


MODULE_INFO
- descr:
  - one MODULE_INFO for every module
  - can share code (e.g. use multiple MODULE_INFOs for different pins in PinOut module)
- def:
  - name[16]
  - id
  - handlerFunctionAddr()
- code:
  .equ MODULE_INFO_HANDLER_LO = 0
  .equ MODULE_INFO_HANDLER_HI = 1
  .equ MODULE_INFO_ID         = 2
  .equ MODULE_INFO_NAME       = 4
  .equ MODULE_INFO_SIZE       = 12


SIGNAL_TABLE:
- descr:
  - one table for every signal a module can emit
- def:
  - array of SLOT objects (end of array: 0x0000)


SLOT:
- descr:
  - one SLOT for every module which is waiting for this signal
- def:
  - MODULE_INFO *modInfoPtr (16 bit)
  - signalIdForCaller (8 bit)
  - signalIdForCallee (8 bit)




Initial module:
- OS
  - sent signals:
    - init
    - fini
  - receivable signals:
    - sleep
    - hardReset
    - softReset


Other modules:
- Timer
  - sent signals:
    - 1Hz
    - 10Hz
    - 100Hz

- PinOut
  - receivable signals:
    - setValue
    - setOnDuration
    - setOffDuration
  - sent signals:
    - none




Module_EmitSignal:
- params:
  - senderId (8 bit)                                                     R16
  - signalIdForSender (8 bit, unique in the realm of the sender)         R17
  - slotIdForRecipient (8 bit, unique in the realm of the recipient)     R18
  - paramLo  (8 bit) R26 (YL)
  - paramHi  (8 bit) R27 (YH)
  - recipientModule R30 (ZL), R31 (ZH) (16 bit)


Notes:
- R24 und R25: 16 register (supports ADIW and SBIW)
- for RAM access: R26-R31 (X, Y, Z)
- for flash memory access: R0 and Z (R30/31)
- in INT: use R15 for flags
- for everything else: R1-R14
- LDI only for upper 16 regs


Generic signals from OS module:
- init
- fini
- request (REQUEST flag for a module can be set by an interrupt handler to request that the corresponding
           module be called as soon as the event handler loop is reached)


<moduledef name="os" ramSizeNeeded="2"> <!-- 16 bit request mask, maximum 16 modules for now -->
  <signals>
    <signal name="1Hz" />
  </signals>
  
  <interrupts>
    <irq id="EXT_INT0" handler="AQOS_Timer_Int0" />
  </interrupts>
  
</moduledef>




<moduledef name="timer">
  <signals>
    <signal name="100Hz" />
    <signal name="10Hz" />
    <signal name="1Hz" />
  </signals>
  
  <interrupts>
    <irq id="EXT_INT0" handler="AQOS_Timer_Int0" />
  </interrupts>
  
</moduledef>


<moduledef name="togglePort" ramSizeNeeded="2" >
  <depModules>
    <depModule name="timer" />
  </depModules>
  
  
  <signals>
    <signal name="100Hz" />
    <signal name="10Hz" />
    <signal name="1Hz" />
  </signals>

  <slots>
    <slot name="timer10Hz" />
    <slot name="setValue" />
    <slot name="setOnDuration" />
    <slot name="setOffDuration" />
  </slots>
  
  <connections>
    <connect module="timer" signalId=10Hz" slotId="timer10Hz" />
  </connections>
  
</moduledef>


<moduledef name="inputPinChange" ramSizeNeeded="8"> <!-- current state of ports a..d and change masks -->
  <signals>
    <signal name="aPortChanged" />
    <signal name="bPortChanged" />
    <signal name="cPortChanged" />
    <signal name="dPortChanged" />
  </signals>
  
  <interrupts>
    <irq id="PCI0" handler="AQOS_InputPinChange_PCI0" />
    <irq id="PCI1" handler="AQOS_InputPinChange_PCI1" />
  </interrupts>

  <slots>
    <slot name="request" />
  </slots>


irq handler:
  - for every port:
    - is port change mask 0? -> SET new mask, otherwise OR new mask with old mask
      -> gracefully handling overrun (e.g. a new PIN change before the previous one was handled)

req handler:
  - for every port:
    - is port change mask 0? -> emit aPortChanged(currentPortValue, portChangeMask), clear mask

</moduledef>




File format:

IRQ-Table

.include "os/rqhandlers.inc"
.include "timer/irqhandlers.inc"
.include "toggleport/irqhandlers.inc"


.equ MODULE_ID_OS         = 0
.equ MODULE_ID_TIMER      = 1
.equ MODULE_ID_TOGGLEPORT = 2


.equ TIMER_USE_100Hz      = 1
.equ TIMER_USE_10Hz       = 1
.equ TIMER_USE_10z        = 1

; in file timer/modinfo.inc

; timer module
modInfoTimer:
  .db "TIMER  ", 0         ; name
  .db MODULE_ID_TIMER, 0   ; id, reserved byte (0)
  .dw timerSignalHandler   ; handler

.equ TIMER_SIG_1HZ = 1

.equ TIMER_SLOT_INIT = 0
.equ TIMER_SLOT_FINI = 1



; in file toggleport/module.inc

; toggleport module
.equ TOGGLEPORT_SLOT_OS_INIT   = 0
.equ TOGGLEPORT_SLOT_OS_FINI   = 1
.equ TOGGLEPORT_SLOT_TIMER_1HZ = 2




; in main source file

; signal table for timer
timerSignalTable:
  .db TIMER_SIG_1HZ, TOGGLEPORT_SLOT_TIMER_1HZ, LOW(modInfoTogglePort), HIGH(modInfoTogglePort)
  .db 0, 0, 0, 0 ; last entry





Assembler:
- generate automatic list of modified registers


.object test1 {
  .sram {
    Testdata:
      .bytes 16
  }
  
  .eprom {
  }
  
  .code {
  }
}



function test1 {
  ld r16, 10
l1:
    dec r16
  brne l1
  ret
}





Hardware:

AtTiny 84
=========
                                                       ----------
                                                   VCC + 1   14 +   GND
              (PCINT8,  XTAL1, CLKI)               PB0 + 2   13 +   PA0 (ADC0, AREF,           PCINT0)   IN/OUT
              (PCINT9,  XTAL2)                     PB1 + 3   12 +   PA1 (ADC1, AIN0,           PCINT1)   WAN-DATA
              (PCINT11, RESET, dW)                 PB3 + 4   11 +   PA2 (ADC2, AIN1,           PCINT2)   IN/OUT   [LED (red)]
KEY->IRQ_PCI1 (PCINT10, INT0, OC0A, CKOUT)         PB2 + 5   10 +   PA3 (ADC3, T0,             PCINT3)   LED (green)
WAN-ATTN(PCI0)(PCINT7,  ICP1, OC0B, ADC7)          PA7 + 6    9 +   PA4 (ADC4, USCK, SCL, T1,  PCINT4)   I2C, SPI
     I2C, SPI (PCINT6,  OC1A, SDA, MOSI, DI, ADC6) PA6 + 7    8 +   PA5 (ADC5, DO, MISO, OC1B, PCINT5)   SPI
                                                       ----------


AtTiny 85
=========
                                                       ----------
              (PCINT5, /RESET, ADC0, dW)           PB5 + 1    8 +   VCC
WAN-ATTN      (PCINT3, XTAL1, CLKI, /OC1B, ADC3)   PB3 + 2    7 +   PB2 (SCK, USCK, SCL, ADC1, T0, INT0, PCINT2)
WAN-DATA      (PCINT4, XTAL2, CLKO, OC1B, ADC2)    PB4 + 3    6 +   PB1 (MISO, DO, AIN1, OC0B, OC1A, PCINT1)
                                                   GND + 4    5 +   PB0 (MOSI, DI, SDA, AIN0, OC0A, /OC1A, AREF, PCINT0)
                                                       ----------



ADC   = ADC Input Channel
AREF  = External Analog Reference
PCINT = Pin Change Interrupt
AIN   = Analog Comparator Input (0=positive, 1=negative input)
T0    = Timer/Counter0 Clock Source
T1    = Timer/Counter1 Clock Source
USCK  = USI Clock (Three Wire Mode)
SCL   = USI Clock (I2C Mode=
DO    = USI Data Output (Three Wire Mode)
MISO  = SPI Master Data Input / Slave Data Output (Three Wire Mode)
OC0A  = Timer/Counter0 Compare Match A Output
OC0B  = Timer/Counter0 Compare Match B Output
OC1A  = Timer/Counter1 Compare Match A Output
OC1B  = Timer/Counter1 Compare Match B Output
SDA   = USI Data Input (I2C Mode)
MOSI  = SPI Data Master Output/Slave Data Input (Three Wire Mode)
ICP1  = Timer/Counter1 Input Capture Pin



WAN-ATTN -> irq PCI0
KEY      -> irq PCI1
PA0 -> in/out1
PA2 -> in/out2
PA3 -> LED
PA4-6: I2C, SPI



WAN-Communication:

WAN-Protocol (UART 9600bps 8N1)


104us pro bit bei 9600bps, about 1040us per byte, about 8.3ms per 8 bytes

               52us  104us    104us    104us    104us    104us    104us    104us    104us    104us    104us
            INACTIVE START    0        1        2        3        4        5        6        7        STOP        INACTIVE
- DATA     ~11111111 00000000 00000000 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111    11111111 11~
- /ACTIVE  ~11100000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000    11111111 11~
                     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (repeat for every byte)



Sensors:
- Erd-Feuchtigkeitssensor: 
  https://www.mouser.de/ProductDetail/M5Stack/U019?qs=sGAEpiMZZMu2rInN%2FZRmFkkq%2FqtywxsmOLlgBBfclSVLB6YzCank4Q%3D%3D


- rename WAN -> inc (inter-node-communication)
- INC messages:
  - 1 byte : dest address                                                      [not saved]
  - 1 byte : msg length (not including dest address, msg length and xor byte)  [not saved]
  - n bytes: data
  - 1 byte : XOR checksum                                                      [not saved]

Packet in buffer:
- 1 byte: buffer length
- 1 byte: flags
- 1 byte: dest address
- 1 byte: msg data


- receivePacket:
  - recv dest address
    - matches?
      - no: finished
  - recv msg size
    - too big?
      - yes: ABORT
    - alloc buffer (msg size +1)
      - error?
        - yes: ABORT
    - write to buffer: size+0x80 (0x80: READ)
  - for every msg size byte: receive byte
  - receive XOR byte
  - check XOR checksum
    - 0?
      - no: ABORT, DeallocBufferBack




Infrastructure, what's next
===========================

- build PC module to read and write control messages
- make WAN code in AVR stable
- implement command to write debug messages to PC via WAN

- node
  - unit (e.g. environment, presence, door, power)    [defines per unit type, use uint8_t values]
    - value (e.g. temp, humidity, pressure, light)

- addresses:
  - 8-bits total, but:
    - bit 7=0: bit 0-6 contains a node address (i.e. max 127 node devices)
    - bit 7=1, bit 6=0: bits 0-5 contain id of a group:
      - nodes with window/door status
      - nodes with alarm output (e.g. horn, bell or or sms)
      - nodes with environmental readouts (temp, humidity etc.)
    - 240+: special ids
      - 252: timekeeper node
      - 253: id of database node
      - 254: id of a router node to upper layers (e.g. room -> appartement -> floor -> house)
      - 255: broadcast (every node)
    - 0: only unassigned nodes (used when assigning an address)

- nodes:
  - database node
    - contains a list of known nodes and their modules and addresses on a bus
  - router node
    - forwards upwards in the hierarchy (e.g. from room to appartement level)

- commands:
  - ping
  - announce device
    - used to assign a 8-bit device id on a bus
    - needs a 8-byte serial number for the device
  - assign device id
    - response from a database node to "announce device"
  - announce module
    - make information about a module on a node available to a central node (or other interested nodes)
  - announce value
    - make info about data available
  - value data
    - announce changes in a given module
  - RQ: set value
    - allow to change a value
  - RSP: set value (response to set value request)
  - request value info
    - make the node send the current value of a given module
  - time (date, time, day/night flag)


Bauteile fuer Platine:
- Widerstaende:
  - 1K fuer LEDs
  - 1K fuer Pull-up (UART lines)
  - 100 Ohm serial inline (UART lines)
  - 4K7/10K fuer Pull-up (I2C lines)
- Kondensatoren:
  - 10 microF (fuer Spannungsregler)
  - 100nF (Abblockkondensatoren fuer Chips)
- Chips:
  - HT7333 (3V3 Spannungsregler
  - 74LS21: Dual 4-Port AND Gate (OpenCollector Outputs)
  - 74LS03, 74LS04: Interface for usbserial (OpenCollector Outputs)



Memory Layout:
- 0x0000-0x003f: Reset and IRQ vectors
- 0x0020-0x04ff: base system  (1248 words, starting with irq table)
- 0x0500-end   : main system starting with IRQ table (2816 words)


Interrupt-Vektoren:
- bei aktivem base system:
  - rjmp PC+0x020 (0xc01f)
- bei aktivem main system:
  - rjmp PC+0x500 (0xc4ff)







; with temp1
;                                 AtTiny84
;                                 --------
;                            VCC  1     14  GND
;                            PB0  2     13  PA0
;                            PB1  3     12  PA1  COM-DATA
;                  /RESET    PB3  4     11  PA2
;                  KEY1      PB2  5     10  PA3  LED
;                  COM_ATTN  PA7  6      9  PA4  TWI-SCL
;                  TWI-SDA   PA6  7      8  PA5
;                                 --------



; with temp2
;                                 AtTiny84
;                                 --------
;                            VCC  1     14  GND
;                            PB0  2     13  PA0
;                            PB1  3     12  PA1  COM-DATA
;                  /RESET    PB3  4     11  PA2  OWI
;                  KEY1      PB2  5     10  PA3  LED
;                  COM_ATTN  PA7  6      9  PA4
;                            PA6  7      8  PA5
;                                 --------



; with pwm
;                                 AtTiny84
;                                 --------
;                            VCC  1     14  GND
;                            PB0  2     13  PA0
;                  FAN1-IN   PB1  3     12  PA1  COM-DATA
;                  /RESET    PB3  4     11  PA2  OWI
;                  KEY1      PB2  5     10  PA3  LED
;                  COM_ATTN  PA7  6      9  PA4  FAN2-IN
;                  PWM1-OUT  PA6  7      8  PA5  PWM2-OUT
;                                 --------



; with optic door/window sensors
;                                 AtTiny84
;                                 --------
;                            VCC  1     14  GND
;                            PB0  2     13  PA0  DOOR-ADC1
;                  DOOR-ADC2 PB1  3     12  PA1  COM-DATA
;                  /RESET    PB3  4     11  PA2
;                  KEY1      PB2  5     10  PA3  LED
;                  COM_ATTN  PA7  6      9  PA4  TWI-SCL
;                  TWI-SDA   PA6  7      8  PA5
;                                 --------



; generic node 5
;                                 AtTiny84
;                                 --------
;                            VCC  1     14  GND
;                            PB0  2     13  PA0
;                  DOOR-ADC1 PB1  3     12  PA1  COM-DATA
;                  /RESET    PB3  4     11  PA2
;                            PB2  5     10  PA3  LED
;                  COM_ATTN  PA7  6      9  PA4  TWI-SCL
;                  TWI-SDA   PA6  7      8  PA5  DOOR-ADC0 (CNY70 Collector)
;                                 --------



;                                 AtTiny85
;                                 --------
;                  /RESET    PB5  1      8  VCC
;                  COM-ATTN  PB3  2      7  PB2  TWI-SCL
;                  COM-DATA  PB4  3      6  PB1  LED
;                            GND  4      5  PB0  TWI-SDA
;                                 --------















format of an intel hex file:

:02 0000 02 0000 FC
 |  |    |  |    |
 |  |    |  |    checksum = -(len + addrlow+addrHigh+every_data_byte)
 |  addr |  data
 length  record type (02=extended segment address record)



:10  0000  00  34 C8 18 95 7E C1 18 95 18 95 18 95 18 95 18 95  A7
:10  0100  00  02 E0 09 BF 08 95 08 95 FF B6 F8 94 00 27 10 91  02


see https://developer.arm.com/documentation/ka003292/latest

record types:
    00  data record;
    01  End of file record. Usually, it is 00000001FF
    02  Extended Segment address record. This indicates segment base address when 16 bits is not enough for addressing memory;
[    03  Start segment address record. Indicates initial segment base address.]
    04  Extended Linear Address Record  allows 32 bit addressing.
    05  Start Linear Address Record. 

for record type 2:
- should be 0 for attiny
- real address is segment address from record type 2 left-shifted by 4 bits + address in data segments, e.g.:
    adress from data record: 2462
    type 2 address:         1200  <- shift left by 4
    resulting address:   00014462

for type 4 (start address of appication):
- data part contains full 32-bit address


int writehex( FILE *fp, ulong adr, uchar *data, int len )

{

  if( len ){

    int pruef;

    fprintf( fp, ":%02X%04lX00", len, adr );

    pruef = len + (adr & 0xFF) + (adr >> 8);

    for(; len--; data++){

      fprintf( fp, "%02X", *data );

      pruef += *data;

    }

    fprintf( fp, "%02X\r\n", -pruef & 0xFF );

    return 1;

  }

  fputs( ":00000001FF\r\n", fp );

  return 1;

}


Das Attiny-Projekt O Der Bootloader 4
  ldi temp, LOW(RAMEND) ; Stackpointer auf RAMEND setzen
  out SPL, temp
GuckObStarten:
  sbis pinD, DTR ; DTR = 0 bzw. Taster Ta1 geschlossen -> BOOTLOADER,
; sonst Anwender-Programm
  rjmp Start
  rjmp $079F ; Sprung zum Anwender-Programm
Start:
  sbi ddrd, LED ; fr Anzeige LED
  sbi portD, LED ; Anzeige: LED an D.5 an, wenn Bootloading
  sbis pinD, DTR ; warten bis DTR = 1 bzw. Ta1 offen
  rjmp Start

; UART initialisieren:
  sbi UCSRB, 4 ; UCR=UCSRB=0x0B RXEN=Bit4 RX aktivieren
  sbi UCSRB, 3 ; UCR=UCSRB=0x0B UDRE=Bit3 TX aktiv
  ldi uartparam, 4000000/(9600*16)-1 ;Baudrate 9600 einstellen
  out UBRRL, uartparam
  rcall rdcom ; warten auf Startbyte
  cbi portd, LED ; LED an D.5 aus, wenn Startbyte erhalten
  ldi param, 105 ; ACK senden
  rcall wrcom
MainSchlaufe:
  rcall rdcom
  mov command, param
B201: ; Block (Page) schreiben
  cpi command, 201
  brne B203
  rcall Schreib_Block
  ldi param, 1 ; ACK Block_Schreiben
  rcall wrcom
B203: ; Anwender-Programm starten
  cpi command, 203
  brne zurueck ; Wenn keine Zahl zutrifft zum Anfang
  ldi param, 11 ; ACK Ende des Uploads
  rcall wrcom
  rcall warte1ms ; 1 ms warten
  cbi UCSRB, 4 ; RX deaktivieren
  cbi UCSRB, 3 ; TX deaktivieren
  rjmp $03AF
zurueck:
  rjmp MainSchlaufe



Schreib_Block:
  ldi r23, PageSize4313
  rcall rdcom                  ; Block-Adresse vom Master
  mov ZH, r16
  rcall rdcom
  mov ZL, r16
Loeschen:                      ; Block loeschen
  ldi r22, 3
  out spmcsr, r22
  spm
Puffer_Schreib_Schleife:       ; alle Woerter des Blocks einzeln in den Puffer
                               ; r1:r0 uebertragen
    rcall rdcom
    mov r0, r16
    rcall rdcom
    mov r1, r16
    ldi r22, 1                   ; Puffer schreiben
    out spmcsr, r22
    spm

    adiw ZL, 2                   ; Flash-Adresse um 1 Word erhoehen
    mov r16, r0                  ; ACK fuer die Uebernahme erhoehen
    rcall wrcom
    mov r16, r1
    rcall wrcom
    dec r23
  brne Puffer_Schreib_Schleife ; Ende der Puffer_Schreib_Schleife
  subi ZL, PageSize4313        ; Startwert fuer Page in Z-Register restaurieren, um...
  subi ZL, PageSize4313
  ldi r22, 5                   ; ... gesamten Puffer in FLASH schreiben
  out spmcsr, r22
  spm
  ret




; temp1, temp2, looplo, loophi, spmcrval
; in: Z=address in FLASH (byte address like for LPM!)
;     Y=address in RAM

.equ PAGESIZEB = PAGESIZE*2 ; PAGESIZEB is page size in BYTES, not words

write_page:
  ; page erase
  ldi r20, (1<<PGERS) + (1<<SPMEN)
  call do_spm

  ;transfer data from RAM to Flash page buffer
  ldi r18, low(PAGESIZEB) ;init loop variable
  ldi r19, high(PAGESIZEB) ;not required for PAGESIZEB<=256

wrloop: ld r0, Y+
    ld r1, Y+
    ldi r20, (1<<SPMEN)
    call do_spm
    adiw ZH:ZL, 2
    sbiw r19:r18, 2 ;use subi for PAGESIZEB<=256
  brne wrloop

  ;execute page write
  subi ZL, low(PAGESIZEB)  ;restore pointer
  sbci ZH, high(PAGESIZEB) ;not required for PAGESIZEB<=256
  ldi r20, (1<<PGWRT) + (1<<SPMEN)
  call do_spm
  
  ;read back and check, optional
  ldi r18, low(PAGESIZEB)  ; init loop variable
  ldi r19, high(PAGESIZEB) ; not required for PAGESIZEB<=256
  subi YL, low(PAGESIZEB)  ;restore pointer
  sbci YH, high(PAGESIZEB)

rdloop: 
    lpm r0, Z+
    ld r1, Y+
    cpse r0, r1
     jmp error      ; skipped if equal
    sbiw r19:r18, 2 ;use subi for PAGESIZEB<=256
  brne rdloop
  ;return
  ret

do_spm:
  ; input: r20 determines SPM action
  ; disable interrupts if enabled, store status
  in r17, SREG
  cli
  ;check for previous SPM complete
wait: 
    in r16, SPMCR
    sbrc r16, SPMEN
  rjmp wait
  ; SPM timed sequence
  out SPMCR, r20
  spm
  ; restore SREG (to enable interrupts if originally enabled)
  out SREG, r17
  ret




TODO:
- Pseudo random:
  - add some dynamics (otherwise nodes with the exact same firmware will have the same sequence of random numbers)
- read/write FLASH
- Timer_Run TODO:
  - disable interrupts
  - first handle internal counters and sample into internal flags
  - enable interrupts
  - call handlers (every10s etc) according to flags
- Serial TODO:
  - work out how to check for ATTN line before sending data
- add onEveryHour
- add onEveryDay
- choose between systems:
  - write correct command into every vector of the low irq table
    - for calling maintenance system: "C:aaaaaa c04f" (low: 4f, high: c0)



- never flash into the initial irq table (starting at 0!!)
- that table will be set according to currently active system
- writeWord:
  - current address pointer: start of page?
    - yes: 
      startPage
      - Flash_ReadPageIntoPageBuffer
  - Flash_WriteIntoPage (increments Z)
  - current address pointer: start of page (meaning: next page)
    - yes:
      finishPage
      - z=z-(PAGESIZE*2)
      - Flash_ErasePage (previous page!)
      - Flash_WritePage (previous page!)
      - z=z+(PAGESIZE*2)
  - store address (Z)

- setAddress:
  - new address inside current page?
    - yes: only set new address
    - no:
      - finish current page
      - start new page
      - set new address


FlashMsg:
- start flash
- set address
  - msg num (2 bytes)
  - address (2 bytes)
- write bytes
  - msg num (2 bytes)
  - bytes (up to 8)
- end flash



msg size in buffer:
 COM_BUFFER_SIZE-3-COM_BUFFER_OFFS_DATA)
 16             -3-1 ; 12 bytes max
 - 4 bytes header (destaddr, msglen, cmd, srcaddr)
 - 1 byte XOR
 - 1 byte flags in buffer
 ->6 bytes overhead
 -> 10 usable bytes left
    flash data msg:
    - 2 bytes msg num
    - remaining data bytes: 8


Part list N03:
- Resistors
  - R1: 100 Ohm
  - R2: 100 Ohm
  - R3: 10K Ohm
  - R4:  1K Ohm
  - R5: 10K Ohm
  - R6: 10K Ohm
  - R7: 120 Ohm   (restrict current to 27mA at 3.3V)
  - R8: 220K Ohm
- Capacitors
  - C1:   10 uF
  - C2:   10 uF
  - C3:  100 nF


Part list N04, N05, N06:
- Resistors
  - R1:  100 Ohm  serial COM_ATTN
  - R2:  100 Ohm  serial COM_DATA
  - R3:  10K Ohm  pullup reset
  - R4:   1K Ohm  serial LED
  - R5:  10K Ohm  pullup SDA
  - R6:  10K Ohm  pullup SCL
  - R7: 120  Ohm  (restrict CNY70 LED current to 27mA at 3.3V)
  - R8: 220K Ohm  pullup CNY70 photo transistor
- Capacitors
  - C1:   10 uF
  - C2:   10 uF
  - C3:  100 nF



Node header:
- baseFirmwareVersion     (2 bytes)
- mainFirmwareVersion     (2 bytes)
- modules mask:           (2 bytes)

Registered firmware modules:
- 0x01: LED
- 0x02: SI7021
- 0x03: CNY70
- etc.


Next:
- aqhome:
  - add IPC client
  - add IPC command to set accepted msg groups
  - add IPC command to query nodeinfo database
  - add IPC command for sending value change
    - node (UID, addr?)
    - value id
    - value type
    - new value
- avr:
  - add firmware header
  - add msg which sends that header
  - value msg: send uid instead of timestamp
  - maybe use fletcher16? (https://en.wikipedia.org/wiki/Fletcher%27s_checksum)
  - or crc8 (https://stackoverflow.com/questions/51752284/how-to-calculate-crc8-in-c)?  [use this!]

   3 4 2 1
   1 2 3 4     1: GND       x  
   x x x       2: ATTN
        x      3: DATA      x
               4: 5V


Gehaeuse:
- Abstandshalter in Gehaeuse?
- Platine verkehrt herum einbauen, einschrauben (Abstandshuelsen?)
- oder: LED und Schalter auf der Rueckseite einbauen, Platine mit Abstandshuelsen einschrauben
- Deckel an der Wand befestigen
- Kabel innerhalb der Dose verlegen (sauberere Anschluesse)


Kabel:
- ROT    : 5V
- SCHWARZ: GND
- GRUEN  : DATA
- BLAU   : ATTN



Tasmota-Steckdosen melden alle 300s:

  tele/tasmota/plug01/STATE
  {
    "Time":"1970-01-01T09:01:09",
    "Uptime":"0T09:00:41",
    "UptimeSec":32441,
    "Heap":29,
    "SleepMode":"Dynamic",
    "Sleep":50,
    "LoadAvg":19,
    "MqttCount":1,
    "POWER":"ON",
    "Wifi":{
      "AP":1,
      "SSId":"CAMELOT_IOT",
      "BSSId":"74:DA:38:EF:8B:DC",
      "Channel":4,
      "Mode":"11n",
      "RSSI":98,
      "Signal":-51,
      "LinkCount":1,
      "Downtime":"0T00:00:06"
    }
  }
  
  
  
  tele/tasmota/plug01/SENSOR
  {
    "Time":"1970-01-01T09:01:09",
    "ENERGY": {
      "TotalStartTime":"1970-01-01T00:00:00",
      "Total":0.131,
      "Yesterday":0.000,
      "Today":0.131,
      "Period": 4,
      "Power":49,
      "ApparentPower":55,
      "ReactivePower":25,
      "Factor":0.89,
      "Voltage":232,
      "Current":0.235
    }
  }




node 2: no messages received again???

rewrite COM:
- send message:
  - alloc buffer
  - message vorbereiten lassen
  - send message
  - dealloc buffer
  - wenn fehler (z.B. line busy): spaeter alles wiederholen (dann aber durch das anfordernde modul, nicht das COM modul)
- kein fire and forget mehr!
- evtl. einen buffer fuer notfall-meldungen
- reihenfolge aendern bei comInterrupt (counter hinterher erhoehen)


