run.sh

#!/bin/bash

# do skryptów startowych dodać screen -dm bash --rcfile /bms/run.sh

modprobe i2c-bcm2708
modprobe i2c-dev

# i2cdetect -l
BUS_ADDR="bcm2708_i2c.1"

# i2cdetect $BUS_ADDR

cd /bms/

set -o ignoreeof
alias exit="echo NO EXIT FROM THIS SHELL"
alias logout="echo NO EXIT FROM THIS SHELL"


###
### REJESTRY UKŁADU MCP23008
###
IODIR=0x00;   # kierunek transferu
GPINTEN=0x02; # generowanie przerwan
DEFVAL=0x03;  # "normalny" stan wejsc, inna wartosc generuje przerwanie (gy odp. ust INTCON)
INTCON=0x04;  # porownywanie z DEFVAL zamiast stanem poprzednim
IOCON=0x05;   # konfiguracja (tryb pracy wyjścia przerwaniowego, ...)
GPPU=0x06;    # rezystory podciagajace

INTF=0x07;    # piny na ktorych wystapila sytuacja wywolujaca przerwanie
INTCAP=0x08;  # stan GPIO w chwili pierwszego przerwania
GPIO=0x09;    # aktualny stan wejsc i wyjsc


# OBSŁUGA PRZERWANIOWA MCP23008
## konfiguracja - kierunek transferu, generowanie przerwań, rezystory podciągające
## starsze 4 bity jako wejście z przerwaniami, młodsze jako wyjście
#   i2cset -y $BUS_ADDR $DEV_ADDR $IODIR 0xf0
#   i2cset -y $BUS_ADDR $DEV_ADDR $GPINTEN 0xf0
#   i2cset -y $BUS_ADDR $DEV_ADDR $GPPU  0xf0

# ustawienie wartości wyjść
#   i2cset -y $BUS_ADDR $DEV_ADDR $GPIO 0x05

# odczyt wejść
#   i2cget -y $BUS_ADDR $DEV_ADDR $GPIO

# próba obsługi przerwań
#   i2cget -y $BUS_ADDR $DEV_ADDR $INTF; i2cget -y $BUS_ADDR $DEV_ADDR $INTCAP; i2cget -y $BUS_ADDR $DEV_ADDR $GPIO

# Niestety wbrew dokumentacji układ w INTF nie odnotowuje kolejnych pinów,
# które wywołują kolejne przerwanie (w trakcie trwania przerwania).
# Jest tam odnotowany tylko pierwszy pin który wywołał przerwanie
# (po wyczyszczeniu przerwań odczytem GPIO lub INTCAP).
#
# Jest to znaczna niedogodność w zastosowaniach wymagających szybkiego
# wychwytywania krótkich przerwań przy wolnej obsłudze I2C.
# Gdyby układ działał zgodnie z dokumentacją mugłbby robić za bufor przerwań
# dla układów nie mających podtrzymywania wystawionego przerwania,
# ale wymagających przekazania informacji o nim (np. wejścia linii alarmowych)


###
### KONFIGURACJA MODUŁÓW DO STEROWANIA PRZEKAŹNIKAMI
###
for DEV_ADDR in 0x24 0x25 0x26 0x27; do
  # wyjscia w stanie niskim
  i2cset -y $BUS_ADDR $DEV_ADDR $GPIO  0x00
  # output
  i2cset -y $BUS_ADDR $DEV_ADDR $IODIR 0x00
done

# bity związane z kolorami kabli do przekaznikow
przek_get_bit() {
  case $1 in
    "bp") echo 0x80 ;;
    "p")  echo 0x40 ;;
    "bn") echo 0x20 ;;
    "n")  echo 0x10 ;;
    "bz") echo 0x08 ;;
    "z")  echo 0x04 ;;
    "bb") echo 0x02 ;;
    "b")  echo 0x01 ;;
  esac
}

# adresy i2c związane z modułami sterowania przekaźnikami
przek_get_addr() {
  case $1 in
    1) echo 0x25 ;;
    2) echo 0x24 ;;
    3) echo 0x26 ;;
    4) echo 0x27 ;;
  esac
}

# maski bitowe przechowujące stan przekaźników i funkcje na nich operujące
[ "${przek_bitmask[*]}" = "" ] && przek_bitmask=(0 0 0 0 0 0 0 0)

# funkcja ustawiająca stan przekaźnika
przek2() {
  addr=`przek_get_addr $1`
  bit=$2
  if [ $3 -eq 1 ]; then
    przek_bitmask[$1]=$(( ${przek_bitmask[$1]} | $bit ))
  else
    przek_bitmask[$1]=$(( ${przek_bitmask[$1]} & ~ $bit ))
  fi
  i2cset -y $BUS_ADDR $addr $GPIO  ${przek_bitmask[$1]}
}
przek() {
  bit=`przek_get_bit $2`
  przek2 "$1" "$bit" "$3"
}


###
### KONFIGURACJA MODUŁU 1WIRE
###
DEV_ADDR=0x20
i2cset -y $BUS_ADDR $DEV_ADDR $IODIR 0xa8 # 0-2: OUT (wybor linii), 4,6: OUT, 3,5,7: IN
i2cset -y $BUS_ADDR $DEV_ADDR $GPIO  0x00
i2cset -y $BUS_ADDR $DEV_ADDR $GPPU  0xa8 # all input with pull-up

onewire_line=0
set_onewire() {
  if [ $1 -ge 0 -a $1 -lt 8 ]; then
    onewire_line=$1
    i2cset -y $BUS_ADDR 0x20 $GPIO $(( $onewire_line | $sygn_orange_line ))
  fi
}


###
### KONFIGURACJA MODUŁÓW ATMEGA
###
for DEV_ADDR in 0x10 0x11; do
  # port D as output (DDRD=0xff)
  i2cset -y $BUS_ADDR $DEV_ADDR 0x97 0xff
  # wyjscia w stanie niskim
  i2cset -y $BUS_ADDR $DEV_ADDR 0x93 0x00

  # port C jako input z pull-up
  i2cset -y $BUS_ADDR $DEV_ADDR 0x96 0x00
  i2cset -y $BUS_ADDR $DEV_ADDR 0x92 0xff
done
  # port B jako input z pull-up
  i2cset -y $BUS_ADDR 0x10 0x95 0x40
  i2cset -y $BUS_ADDR 0x10 0x91 0xbf
  i2cset -y $BUS_ADDR 0x11 0x95 0x00
  i2cset -y $BUS_ADDR 0x11 0x91 0x3e


# maska bitowa przechowujące stan LEDów
led_val=0

# funkcje ustawiające stan LEDów oraz realizujące miganie
led2() {
  if [ $2 -eq 1 ]; then
    led_val=$(( $led_val | $1 ))
  else
    led_val=$(( $led_val & ~ $1 ))
  fi
  i2cset -y $BUS_ADDR 0x11 0x93 $led_val
}
led() {
  bit=`led_get_bit $1`
  led2 $bit $2
}
led_blink() {
  # usage: led_blink led_bits time count
  led_val_on=$(( $led_val | $1 ))
  led_val_off=$(( $led_val & ~ $1 ))
  
  for i in `seq 1 $3`; do
    i2cset -y $BUS_ADDR 0x11 0x93 $led_val_on
    sleep $2
    i2cset -y $BUS_ADDR 0x11 0x93 $led_val_off
    [ $i -eq $3 ] || sleep $2
  done
}

### ODCZYT DI

# inicjalizacja na  stany normalne (bez wcisnietych przyciskow itp)
DI_A=0x28; DI_B=0xba; DI_C=0x3e;

# obliczmy maske stanu normalnego
DI_normal_mask=$(( ($DI_A & 0xa8) << 13 | $DI_B << 8 | $DI_C ))
DI_bistable_mask=$(( 0x2 | 0x4 | 0x40000 | 0x100000 ))

DI_status=0; DI_cnt=0; DI_bistable_diff=0; DI_bistable_cnt=0;
DI_read() {
  # zapamietujemy poprzedni status wejść jako DI_status_old
  DI_status_old=$DI_status
  
  # odczytujemy wszystkiewejscia cyfrowe (gdy błąd odczytu to uznajemy że brak zmiany)
  t=`i2cget -y $BUS_ADDR 0x20 $GPIO 2>/dev/null` && DI_A=$t
  t=`i2cget -y $BUS_ADDR 0x10 0x99  2>/dev/null` && DI_B=$t
  t=`i2cget -y $BUS_ADDR 0x11 0x99  2>/dev/null` && DI_C=$t
  
  # wyliczamy status oparty na wszystkich wejściach (w normalnym stanie = 0)
  t=$(( ($DI_A & 0xa8) << 13 | ($DI_B & 0xbf) << 8 | $DI_C ))
  DI_status=$(( $t ^ $DI_normal_mask ))
  
  # obliczamy zmianę
  DI_diff=$(( $DI_status ^ $DI_status_old ))
  
  
  if [ $DI_bistable_cnt -eq 1 -a $DI_bistable_diff -ne 0 -a \
       $(( ($DI_status ^ $DI_status_old) & $DI_bistable_mask )) -eq 0 ]; then
    # jeżeli w poprzednim cyklu była zmiana na bistabilnych i się utrzymała to zaznaczamy do realizacji
    DI_bistable_cnt=2
  else
    # jak nie to sprawdzamy czy w obecnym cyklu jest zmiana na bistabilnych
    DI_bistable_diff=$(( $DI_diff & $DI_bistable_mask ))
    
    if [ $DI_bistable_diff -ne 0 ]; then
      DI_bistable_cnt=1
    else
      DI_bistable_cnt=0
    fi
  fi
  
  
  t=$(( $DI_status & ~ $DI_bistable_mask ))
  if [ $t -ne 0 ]; then
    # jeżeli jest wciśnięty któryś z monostabilnych
    if [ $DI_check -eq 0 ]; then
      # jeżeli pierwsza rejestracja wciśnięcia - zapamiętaj który to przycisk
      DI_check=$t
    fi
    
    # jeżeli ten który zapamiętaliśmy pozostaje wciśnięty to zwiększ licznik
    if [ $(( $t & $DI_check )) -ne 0 ]; then
      let DI_cnt++;
    fi
  else
    # gdy nie ma wciśniętego monostabilnego wyzeruj liczniki i zapamiętany przycisk
    DI_cnt_old=$DI_cnt
    DI_cnt=0
    DI_check=0
  fi
}

DI_read_loop() {
  while true; do
    # odczyt linii DI
    DI_read

    if [ $DI_bistable_cnt -eq 2 ]; then
      # wykryto zmianę stanu przycisku bistabilnego
      led_blink 0xc8 0.15 1
      DI_action0 $DI_bistable_diff $DI_status_old
    elif [ $DI_cnt -eq 0 ]; then
      # wykryto zmianę stanu przycisku monostabilnego
      if [ $DI_cnt_old -ge 20 ]; then
        # bardzo długie naciśnięcie
        DI_action4 $DI_status_old
      elif [ $DI_cnt_old -ge 14 ]; then
        # długie naciśnięcie
        DI_action3 $DI_status_old
      elif [ $DI_cnt_old -ge 8 ]; then
        # średnie naciśnięcie
        DI_action2 $DI_status_old
      elif [ $DI_cnt_old -ge 2 ]; then
        # krótkie nasićnięcie (potwierdzone dwoma odczytami)
        DI_action1 $DI_status_old
      fi
    elif [ $DI_cnt -eq 2 ]; then
      # wykryto nacisniecie przycisku
      led_blink 0xc8 0.15 1
    elif [ $DI_cnt -eq 8 ]; then
      # naciśnięcie przycisku trwa ~1s
      led_blink 0xc8 0.15 2
    elif [ $DI_cnt -eq 14 ]; then
      # naciśnięcie przycisku trwa ~2s
      led_blink 0xc8 0.15 3
    elif [ $DI_cnt -eq 20 ]; then
      # naciśnięcie przycisku trwa ~3s
      led_blink 0xc8 0.15 4
    elif [ $DI_cnt -eq 40 ]; then
      # naciśnięcie przycisku trwa zbyt długo
      DI_action_verbose $DI_status_old
      led_blink 0xc8 0.4 5
      DI_cnt=0
      DI_cnt_old=0
    fi
    sleep 0.05
  done
}


###
### ZAINCLUDOWANIE FUNKCJI REALIZUJĄCYCH STEROWANIE
###
. ./output.sh
. ./input.sh

# don't run in background - we want have variables used by DI_read_loop system in current shell
# eg for `set | egrep '^output_state|^przek_bitmask'`
DI_read_loop

XHTML generated by highlight (http://www.andre-simon.de/) from run.sh



Copyright (c) 1999-2015, Robert Paciorek (http://www.opcode.eu.org/), BSD/MIT-type license


Redystrybucja wersji źródłowych i wynikowych, po lub bez dokonywania modyfikacji JEST DOZWOLONA, pod warunkiem zachowania niniejszej informacji o prawach autorskich. Autor NIE ponosi JAKIEJKOLWIEK odpowiedzialności za skutki użytkowania tego dokumentu/programu oraz za wykorzystanie zawartych tu informacji.

This text/program is free document/software. Redistribution and use in source and binary forms, with or without modification, ARE PERMITTED provided save this copyright notice. This document/program is distributed WITHOUT any warranty, use at YOUR own risk.

Valid XHTML 1.1 Dokument ten (URL: http://www.opcode.eu.org/usage_and_config/smart_home/centralka_alarmowa/run.sh) należy do serwisu OpCode. Autorem tej strony jest Robert Paciorek, wszelkie uwagi proszę kierować na adres e-mail serwisu: webmaster@opcode.eu.org.
Data ostatniej modyfikacji artykulu: '2014-01-07 19:27:43 (UTC)' (data ta może być zafałszowana niemerytorycznymi modyfikacjami artykułu).