'(

 **************************************************************
 * Dieters SmartHome: Alarmanlage                             *
 * V 1.1 (C) Juni 2021 by DiLi-Soft, www.liebl-net.de         *
 * (compiliert unter BASCOM 2.0.8.3 von 2020)                 *
 *                                                            *
 * Dieses Programm ist urheberrechtlich geschützt und darf    *
 * ausschließlich für nichtkommerzielle Zwecke verwendet      *
 * werden.                                                    *
 *                                                            *
 * Gewerbliche Nutzung ist ausgeschlossen!!                   *
 *                                                            *
 * Weitergabe des Quelltextes ist erwünscht - aber nur        *
 * komplett, unverändert und mit diesen Copyright-Anmerkungen *
 *                                                            *
 **************************************************************
 *                                                            *
 *  Externer Quarz von 3,6864 Mhz für den ATMega664           *
 *                                   (oder 164 oder 324)      *
 *  Compare1A-Interrupt: 3686400 / 64 / 5760 = 10Hz = 100ms   *
 *                                                            *
 **************************************************************
 *                                                            *
 *  Ausstattung:                                              *
 *  8 Fensterkontakte (Reed), 8 Motorjalousien,               *
 *  2 Bewegungssensoren, 1 Schlüsselschalter mit              *
 *  3 Schaltstellungen: 1 - 0 - 1 , Bedeutung:                *
 *  nur 1 Beweg.-Melder aktiv - AUS - komplett EIN            *
 *  Besonderheit: Bewegungsmelder 1 befindet sich IM Raum     *
 *  von Reed 3, Bewegungsmelder 2 befindet sich NEBEN dem     *
 *  Schlüsselschalter gegenüber der Eingangstür (!).          *
 *  Zum Schlüsselschalter gehören 2 LEDs:                     *
 *  Grün und Rot  (Bereitschaft - Alarm)                      *
 *                                                            *
 *  Mögliche Blinkfolgen:                                     *
 *  1. langsam grün blinkend (Vorbereitungszeit, direkt nach  *
 *     dem Einschalten)                                       *
 *                                                            *
 *  2. 1 - 8 mal kurz rot blinkend, ewig wiederholend (Reed-  *
 *     Kontakt X ist geöffnet -> Warnung dass Fenster auf!)   *
 *                                                            *
 *  3. Dauer-Grün (Schalterstellung "Alle", Anlage SCHARF!)   *
 *                                                            *
 *  4. Dauer-Rot (ALARM! Sirene ertönt 3 Minuten, Jalousie X  *
 *     fährt herunter, wenn Reed-X-ALARM)                     *
 *                                                            *
 *  5. Dauer-Rot mit Unterbrechung (wie 4. , Wiederholung)    *
 *                                                            *
 *  6. schnell rot blinkend (Beweg.-Melder Flur meldet, 15    *
 *     Sekunden Zeit zum Abschalten, sonst ALARM              *
 *                                                            *
 *  7. rot-grün langsam im Wechsel blinkend (bei Schalter-    *
 *     stellung "WoZi", Überwachung ausschließlich mit        *
 *     Beweg.-Sensor im Wohnzimmer - "Lüftungskontrolle")     *
 *                                                            *
 *  8. alle LEDs aus (Anlage ausgeschaltet)                   *
 *                                                            *
 *  Nach einem Stromausfall aktiviert sich die Anlage bei     *
 *  Wiederkehr des Stromes automatisch, überspringt dabei     *
 *  aber die Fenster-Auf-Prüfung !                            *
 *  War vorher ein Fenster-Alarm aktiv, wird das betroffene   *
 *  Fenster gegen Wiederhochfahren auf Dauer geschützt !      *
 *                                                            *
 **************************************************************

')


' ***** PROGRAMMER-Option: "Upload Code and Data" aktivieren - wg. EEPROM-Vorbesetzung *****


'$PROG &HFF,&HFF,&HD1,&HFF      ' = Lockbit + Fusebits für !! Mega644 !!
                                ' damit sind JTAG (!) und DIV8 deaktiviert
                                ' ext. Quarz aktiviert und EEPROM vor dem Löschen geschützt

$regfile = "m644def.dat"        ' für ATMEGA644 / für ATMEGA164 auf "m164def.dat" setzen
$crystal = 3686400
$baud = 38400                   ' später für "TOKEN-RING"
$hwstack = 10
$swstack = 10
$framesize = 40                 ' geringe Anforderungen an den Stack



' PINs konfigurieren und Ausgänge voreinstellen:
'                 Bits:    |      7      |      6      |      5      |    4    |     3     |     2     |     1     |     0     |
ddra = 255               ' | Jal. SchlZi | Jal. Balkon | Jal. Kueche | Jal. WC | Jal. WoZi | Jal. Terr | Jal. FeZi | Jal. EsZi |  (Ausgänge f. Jalousien-abwärts)

PORTA = 0                ' alles ausschalten

DDRC = 0                 ' | Reed SchlZi | Reed Balkon | Reed Kueche | Reed WC | Reed WoZi | Reed Terr | Reed FeZi | Reed EsZi |  (Eingänge von Reed)

'                 Bits:    |    7    |   6   |   5   |     4    |    3   |   2  |    1     |    0    |
ddrb = &B10011011        ' |  eeLED  | frei  | frei  | Netzakt. | Sirene |(INT2)| LED Grün | LED Rot |
                         '                                                          nicht!    nicht!

Portb= &B00000011        ' ausschalten

'                 Bits:    |           7         |           6         |        5        |         4       |   3  |   2  |  1  |  0  |
DDRD = &B00000010        ' | Schl.-Schalter Alle | Schl.-Schalter WoZi | Beweg-Sens Flur | Beweg-Sens WoZi |(INT1)|(INT0)|(TxD)|(RxD)|



' Port-Aliase:
jalAlle alias porta
reedAlle alias PINC
LedRotNot alias portb.0
LedGrnNot alias Portb.1
Sirene alias Portb.3
Netzakt alias portb.4
eeLED alias portb.7

BewSensorWoZi alias pind.4
BewSensorFlur alias pind.5
SchalterWoZi alias pind.6
SchalterAlle alias pind.7


' TIMER1 konfigurieren:
TCCR1B.CS10=1
TCCR1B.CS11=1            ' Prescaler = 64 für Timer 1
tccr1b.wgm12=1           ' CTC einschalten für Timer 1A
compare1a=5760           ' für Interr. nach 100ms
TIMSK1.OCIE1A=1          ' OnCompare-Interrupt einschalten


' PCINT2 konfigurieren (Reed 1-8) :
pcmsk2 = &B11111111      ' alle relevant (Pins PC0-7)
pcicr.pcie2=1            ' PCINT2 einschalten


' PCINT3 konfigurieren (Schalter "Alle" - Schalter "WoZi" - BewSensor Flur - BewSensor "Wozi" - 0 - 0 - 0 - 0) :
pcmsk3 = &B11110000      ' nur Pins PD4-7
pcicr.pcie3=1            ' PCINT3 einschalten


' Interrupt-Serviceroutinen setzen:
on OC1A onOC1A           ' TIMER-Int. alle 100ms; daraus leiten sich die 4 Zeitmesser ab
on PCINT2 onPCINT2       ' Pins PC0-7 -> PCInt16-23 = Reed-Kontakte 1-8
on PCINT3 onPCINT3       ' Pins PD4-7 -> PCInt28-31 = BewSensor "WoZi" + "Alle", Schalter "WoZi" + "Alle"


' LED-Blinkfolgen:
const blinkOff = 0       ' Blinken Rot/Grün ausschalten !!!
const blinkRotFast = 1
const blinkRotInterrupt = 2
const blinkRotXmal = 3
const blinkAlternate = 4
const blinkGrnSlow = 5


' Timer_Presets:      zum Testen:
const 15Sek = 150     '  50           1/10 Seks
const 1Min  = 450     '  50
const 3Min = 1800     ' 100


' Timer-Vars:
dim 15SekTimer as byte   ' schnelles Blinken: Beweg.-Melder Flur bis Ausschalten
dim 1MinTimer as word    ' Vorbereitungszeit bis scharf
dim 3MinTimer as word    ' max. Sirenenlaufzeit


' diverse Vars:
$eeprom
data 0                                   ' mit Null vorbesetzt:
$data                                    ' landet in der .eep-Datei für den Brenner
dim eeJalAlle as eram byte               ' bei Reed-Alarm die betr. Jalousie(n) merken
                                         ' nach Stromausfall werden Letztere unten gehalten !!!
dim status as byte
status=0                 ' alles auf Anfang!

dim bitTest, jalTest as byte

dim old_reedAlle as byte
old_reedAlle=reedAlle                               ' zum Erkennen von Reed-Veränderungen

dim bewSensorSumme, old_bewSensorSumme as byte
old_bewSensorSumme=bewSensorFlur + bewSensorWoZi    ' zum Erkennen von Beweg.-Sensor-Änderungen

dim schalterSumme, old_schalterSumme as byte
old_schalterSumme=schalterAlle + schalterWoZi       ' zum Erkennen von Schlüsselschalteränderungen


' Subs():
declare sub jalAbwaerts()
declare sub setBlink(byval blinkMode as byte, byval xMal as byte)


' --------------------- main() -----------------------

SREG.=1                                ' alle Interrupts freigeben

' ----------------------------------------- Hauptschleife: ------------------------------------------
'                                                                                  Einstiege:
'                                                                                 ------------
do
   select case status
      case  0:                           ' alles auf RESET                         *** 0 ***
               15SekTimer=0              ' alle Timer resetten
               1MinTimer=0
               3MinTimer=0
               call setBlink(blinkOff,0) ' evtl. Blinken aus
               ledRotNot=1               ' LEDs aus
               ledGrnNot=1
               Sirene=0                  ' Sirene aus
               Netzakt=0                 ' Netzaktivierung aus
               jalAlle=0                 ' alle Jalousien-Ausgänge aus
               eeLED=0                   ' EEPROM-Inhalt-LED aus
               status=1

               jalTest=eeJalAlle         ' ggf. gemerkte offene Reed-Kontakte nach Alarm
               if jalTest>then
                  if schalterAlle=then ' Schalter auf "Alle"
                     jalAlle=jalTest     ' gemerkte Fenster (dauerhaft !!) auf abwärts setzen
                     eeLED=1
                  else
                     jalTest=0
                     eeJalAlle=jalTest   ' löschen
                  end if
               end if

               if schalterAlle=then    ' nach Stromausfall autom. aktivieren
                  status=4               ' Reed-Prüfung (Fenster auf) überspringen
               end if

               if schalterWoZi=then    ' nach Stromausfall autom. aktivieren
                  status=31              ' nur WoZi Beweg.-Sensor
               end if

      case  1:                           ' warten auf Einschalten

      ' ----------------------------------------------------------------------

      case  2: if reedAlle=then        ' kein Reed-Kontakt geöffnet              *** 1 ***
                  status=4
               else                      ' Fenster x ist auf !
                  for bitTest=to 7
                     if reedAlle.bitTest =then
                        incr bitTest     ' =x
                        call setBlink(blinkRotXmal,bitTest)   ' x mal blinken
                        status=3         ' warten auf Godot...
                        exit for         ' nicht weitersuchen
                     end if
                  next
               end if

      case  3:                           ' STOPP! Warten auf Ausschalten und neu Einschalten !!

      ' ----------------------------------------------------------------------
      ' ----------------------------------------------------------------------

      case  4: 1MinTimer=1Min
               call setBlink(blinkGrnSlow,0)
               status=5

      case  5:                           ' auf Ablauf der 1 Minute warten

      case  6: call setBlink(blinkOff,0) ' Minute abgelaufen: blinken aus

               if jalTest>then         ' bei Stromausfall und vorherigem Reed-Alarm
                  ledGrnNot=1
                  ledRotNot=0            ' Dauer-Rot an
                  status=11              ' Wiederholungs-SCHARF
               else
                  ledGrnNot=0            ' Dauer-Grün an
                  status=7               ' SCHARF !!!
               end if

      case  7:                           ' warten auf Alarm ...

      ' ----------------------------------------------------------------------

      case  8: 3MinTimer=3Min            ' ALARM !!!                               *** 2 ***
               Sirene=1                  ' 3 Minuten lang Sirene an
               call setBlink(blinkOff,0)
               LedRotNot=0               ' rote LED Dauer-ein
               LedGrnNot=1               ' grüne LED aus
               call jalAbwaerts          ' ggf. Jalousie des betroffenen Reeds herunterfahren
               status=9

      case  9:                           ' warten auf Ablauf 3 Min-Alarm

      case 10: Sirene=0                  ' Alarm abgelaufen
               status=11

      case 11:                           ' warten auf Wiederholung

      ' ----------------------------------------------------------------------

      case 12: 3MinTimer=3Min            ' Wiederholungs-ALARM !!!                 *** 3 ***
               Sirene=1
               call setBlink(blinkRotInterrupt,0)
               call jalAbwaerts          ' ggf. Jalousie herunterfahren !
               status=9

      ' ----------------------------------------------------------------------

      case 15: 15SekTimer=15Sek          ' Beweg.-Sensor-Flur-ALARM !!!            *** 4 ***
               call setBlink(blinkRotFast,0)  ' schnell rot Blinken
               LedGrnNot=1               ' Grün aus
               status=16

      case 16:                           ' warten auf Ablauf 15 Sek.

      case 17: status=8                  ' abgelaufen: weiter wie normal

      case 18: 15SekTimer=15Sek          ' Wiederholung Flur-Alarm                 *** 5 ***
               call setBlink(blinkRotFast,0)  ' schnell rot Blinken
               LedGrnNot=1               ' Grün ist aus
               status=19

      case 19:                           ' warten Ablauf 15 Sek

      case 20: status=12                 ' abgelaufen: weiter wie normal Wiederhg.

      ' ----------------------------------------------------------------------
      ' ----------------------------------------------------------------------

      case 31: 1MinTimer=1Min            ' WoZi-Beweg.-Sensor-Alarm aktivieren      *** 6 ***
               call setBlink(blinkGrnSlow,0)  ' langsam grün blinken
               status=32
      case 32:                           ' auf Ablauf der 1 Minute warten

      case 33: call setBlink(blinkAlternate,0)  ' rot - gün im Wechsel blinkend
               status=34

      case 34:                           ' warten auf WoZi-Alarm

      case 35: 3MinTimer=3Min            ' ALARM
               Sirene=1                  ' 3 Minuten Sirene
               call setBlink(blinkOff,0)
               LedRotNot=0               ' rote LED Dauer-ein
               LedGrnNot=1               ' grüne LED aus
               status=36

      case 36:                           ' warten auf Ablauf 3 Min-Alarm

      case 37: Sirene=0                  ' Alarm abgelaufen
               status=33
   end select

loop


end                                      ' main()




sub jalAbwaerts()                   ' testet Reed-Kontakte und fährt ggf. zugehörige Jalousie herunter
   if reedAlle=then               ' kein Reed-Alarm -> keine Aktion nötig !
      return
   end if

   for bitTest=to 7
      if reedAlle.bitTest =then   ' offenen Reed-Kontakt x gefunden
                                    ' ansonsten:
         Netzakt =1                 ' Netzaktivierungs-Impuls
         waitms 200
         Netzakt =0
         jalAlle.bitTest=1          ' 200ms später Jalousie x abwärts fahren
       end if
   next                             ' wiederholen, so werden auch 2. und weitere Reed-Alarme berücksichtigt!

   if jalAlle >then
      eeJalAlle=jalAlle             ' bei Alarm die betroffene(n) durch Alarm heruntergefahrene(n) Jalousie(n) im EEPROM merken
   end if
end sub



' "private" Vars fürs Blinken:
dim blinkType, blinkXMal as byte
dim blinkCount, blinkLength as byte : blinkCount=0: blinkLength=0
dim modtemp as byte

sub setBlink(byval blinkMode as byte, byval xMal as byte)
   blinkType=blinkMode

   if blinkType=blinkOff then
       blinkLength=0                ' sauber für neuen Start
   end if

   if blinkType=blinkRotXmal then
      blinkXMal=xMal
      blinkCount=xMal
      shift blinkCount, LEFT, 2     ' *4 wg. |~~|__ = 400 ms
   end if
end sub



' ----------------------------- ISR (Interrupt-Service-Routinen: -----------------------------------


' ----------------------------- TIMER1A: -----------------------------------
onOC1A:
   ' ------------------ Blinken (rote und grüne LEDs): ---------------------
   if blinkType=blinkRotFast then
      incr blinkLength
      if blinkLength>then       ' schnelles Blinken Rot
         blinkLength=0
         LedRotNot=not LedRotNot
      end if
   end if

   if blinkType=blinkRotInterrupt then
       incr blinkLength
       if blinkLength>14 then
          blinkLength=0
          LedRotNot=1             ' Dauer-Rot, nur kurz (1/15-tel) unterbrochen
       else
          LedRotNot=0             ' einschalten
       end if
   end if

   if blinkType=blinkRotXmal then

      if blinkLength <10 then     ' Vorlauf 0...9: aus
         LedRotNot=1
         incr blinkLength
      end if

      if blinkLength =10 then     ' Mittelteil: blinkXMal blinken
         decr blinkCount
         modtemp= blinkCount mod 2
         if modtemp=then        ' nur jedes zweite mal, dann aber doppelt so lange!
            LedRotNot= not LedRotNot
         end if
         if blinkCount =then
            blinkCount=blinkXMal
            shift blinkCount, LEFT, 2 ' *4 wg. |~~|__ = 400 ms
            blinkLength=11
         end if
      end if

      if blinkLength >10 then     ' Nachlauf 11...20: aus
         LedRotNot=1
         incr blinkLength
      end if

      if blinkLength >20 then     ' und von Vorne again
         blinkLength=0
      end if
   end if

   if blinkType=blinkAlternate then
      incr blinkLength
      if blinkLength>then       ' langsam im Wechsel blinken
         blinkLength=0
         LedGrnNot=not LedGrnNot
         LedRotNot= not LedGrnNot
      end if
   end if

   if blinkType=blinkGrnSlow then
      incr blinkLength
      if blinkLength>then       ' nur Grün langsam blinken
         blinkLength=0
         LedGrnNot=not LedGrnNot
      end if
   end if

  ' ------------------ 15 Sek-TIMER (Alarm-Verzög. für Beweg.-Sensor Flur): ----------------
  if 15SekTimer >then
     decr 15SekTimer
     if 15SekTimer=then         ' abgelaufen!
        if status=16 then         ' wenn Beweg.-Sensor-Flur-Alarm
           status=17
        end if

        if status=19 then         ' wenn Beweg.-Sensor-Flur-Alarm-Wiederholung
           status=20
        end if
     end if
  end if

  ' ------------------- 1 Min-TIMER (Vorbereitungszeit bis SCHARF): ------------------------
  if 1MinTimer >then
     decr 1MinTimer
     if 1MinTimer=then          ' abgelaufen!
        if status=then          ' von "1 Min warten" nach "1 Min abgelaufen"
           status=6
        end if

        if status=32 then
           status=33
        end if

     end if
  end if

  ' ------------------- 3 Min-TIMER (Dauer Sirenen-Alarm): ---------------------------------
  if 3MinTimer >then
     decr 3MinTimer
     if 3MinTimer=then          ' abgelaufen!
         if status=then         ' normaler Alarm
            status=10             ' Sirene aus!
         end if

         if status=36 then        ' nur WoZi-Alarm
            status=37             ' Sirene aus!
         end if

     end if
  end if

return



' ---------------------------- Reed-Kontakte (PC0-7): ---------------------------
onPCINT2:
   if reedAlle>old_reedAlle then  ' es kam etwas hinzu -> steigende Flanke!
      old_reedAlle=reedAlle       ' letzte Änderung merken
                                  ' irgend eine Reed-Schleife wurde geöffnet
      if status=then
         status=8                 ' ALARM !!!   *** 2 ***
      end if

      if status=then            ' Wiederholung, während der vorige Alarm noch läuft
         status=12
      end if

      if status=11 then
         status=12                ' Wiederholungs-Alarm nach Ablauf der Sirenenzeit   *** 3 ***
      end if

   else
      old_reedAlle=reedAlle       ' kleiner -> fallende Flanke: Alarm-Wegfall ignorieren
   end if

   PCIFR.PCIF2=1                  ' evtl. aufgelaufende INTs (Preller) löschen
return



' ---------------- Beweg.-Sensoren und Schlüsselschalter(PD4-7): ----------------
onPCINT3:
   ' ---------------- Beweg.-Sensoren: ----------------
   bewSensorSumme=bewSensorFlur + bewSensorWoZi
   if bewSensorSumme>old_bewSensorSumme then ' es kam etwas hinzu -> steigende Flanke
      old_bewSensorSumme=bewSensorSumme      ' letzte Änderung merken

      if bewSensorFlur=then     ' Beweg.-Sensor Flur hat gemeldet

         if status=then
            status=15             ' ALARM mit Verzögerung !!!   *** 4 ***
         end if

         if status=11 then
            status=18             ' Wiederholungs-Alarm mit Verzögerung !!!   *** 5 ***
         end if

      end if

      if bewSensorWoZi=then     ' Beweg-Sensor WoZi hat gemeldet

         if status=then
            status=8              ' ALARM !!!
         end if

         if status=11 then
            status=12             ' Wiederholungs-Alarm
         end if

         if status=34 then
            status=35             ' nur WoZi-Alarm !!!
         end if

      end if

   else                           ' fallende Flanke ignorieren
      old_bewSensorSumme=bewSensorSumme
   end if

   ' --------------Schlüsselschalter: -----------------

   schalterSumme=schalterAlle + schalterWoZi
   if schalterSumme <> old_SchalterSumme then
      old_schalterSumme=schalterSumme' letzte Änderung merken

      if schalterSumme>then

      ' ------------------ einschalten: ------------------

         if schalterAlle=then   ' "Alle" eingeschaltet
            status=2              ' Start mit Test: Fenster auf?   *** 1 ***
         end if

         if schalterWoZi=then   ' "WoZi" eingeschaltet
            status=31             ' nur "WoZi" scharf   *** 6 ***
         end if

      else

      ' ------------------ ausschalten: ------------------
         status=0                 ' ausgeschaltet: alles aus und warten auf Einschalten   *** 0 ***

      end if
   end if

   PCIFR.PCIF3=1                  ' evtl. aufgelaufende INTs (Preller) löschen
return