; ***************************************************************************
; copyright   : (C) 2025 by Martin Preuss
; email       : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome".                              *
; * Please see toplevel file COPYING of that project for license details.   *
; ***************************************************************************

#ifndef AVR_MODULES_COM2W_COM2W_H
#define AVR_MODULES_COM2W_COM2W_H

; only currently working com2w module!



.macro M_COM2WCLKSETLOW
  sbi COM_CLK_DDR, COM_CLK_PIN          ; set CLK as output
  cbi COM_CLK_OUTPUT, COM_CLK_PIN       ; set CLK low
.endmacro



.macro M_COM2WCLKSETHIGH
  cbi COM_CLK_DDR, COM_CLK_PIN           ; set CLK as input
.ifndef COM_CLK_PUE
  cbi COM_CLK_OUTPUT, COM_CLK_PIN        ; disable pullup on CLK
.endif
.endmacro



.macro M_COM2WDATASETLOW
  sbi COM_DATA_DDR, COM_DATA_PIN          ; set DATA as output
  cbi COM_DATA_OUTPUT, COM_DATA_PIN       ; set DATA low
.endmacro



.macro M_COM2WDATASETHIGH
  cbi COM_DATA_DDR, COM_DATA_PIN           ; set DATA as input
.ifndef COM_DATA_PUE
  cbi COM_DATA_OUTPUT, COM_DATA_PIN        ; disable pullup on DATA
.endif
.endmacro



.macro M_COM2WSETUPINT0
  inr r16, MCUCR
  cbr r16, (1<<ISC01) | (1<<ISC00)
  sbr r16, (1<<ISC01) | (0<<ISC00)        ; falling edge of ATTN
  outr MCUCR, r16
;  sbr r16, (0<<ISC01) | (0<<ISC00)         ; low level triggers
  inr r16, COM_IRQ_ADDR_CLK               ; enable irq for ATTN line
  sbr r16, (1<<COM_IRQ_BIT_CLK)
  outr COM_IRQ_ADDR_CLK, r16
.endmacro



.macro M_COM2WSETUPPCI
  inr r16, COM_IRQ_ADDR_CLK               ; enable pin change irq for CLK line
  ori r16, (1<<COM_IRQ_BIT_CLK)
  outr COM_IRQ_ADDR_CLK, r16
;  sbi COM_IRQ_ADDR_CLK, COM_IRQ_BIT_CLK   ; enable pin change irq for CLK line
  in r16, GIMSK                           ; enable pin change irq PCIE0 or PCIE1
  ori r16, (1<<COM_IRQ_GIMSK_CLK)
  out GIMSK, R16
  ldi r16, (1<<COM_IRQ_GIFR_CLK)          ; clear pending irq by writing 1 to CLK bit
  out GIFR, r16
.endmacro



.macro M_COM2WSETUPPCICR
  inr r16, COM_IRQ_ADDR_CLK               ; enable pin change irq for CLK line
  ori r16, (1<<COM_IRQ_BIT_CLK)
  outr COM_IRQ_ADDR_CLK, r16

  inr r16, COM_IRQ_ICR_ADDR               ; enable pin change irq in PCICR
  ori r16, (1<<COM_IRQ_ICR_BIT)
  outr COM_IRQ_ICR_ADDR, R16
  ldi r16, (1<<COM_IRQ_IFR_BIT)           ; clear pending irq by writing 1 to CLK bit
  out COM_IRQ_IFR_ADDR, r16
.endmacro





.dseg

com2w_iface: .byte COM2W_IFACE_SIZE



.cseg



; ---------------------------------------------------------------------------
; @routine COM2W_Init
;
; @clobbers 

COM2W_Init:
  ldi yl, LOW(com2w_iface)
  ldi yh, HIGH(com2w_iface)
  rcall NET_Interface_Init                 ; (R16, R17, X)

  ; setup CLK line (as input, disable internal pull-up resistor)
  cbi COM_CLK_DDR, COM_CLK_PIN           ; set CLK as input
.ifdef COM_CLK_PUE
  inr r16, COM_CLK_PUE
  cbr r16, (1<<COM_CLK_PIN)               ; disable pullup on CLK
  outr COM_CLK_PUE, r16
.else
  cbi COM_CLK_OUTPUT, COM_CLK_PIN        ; disable pullup on CLK
.endif

  ; setup DATA line (as input, disable internal pull-up resistor)
  cbi COM_DATA_DDR, COM_DATA_PIN         ; set DATA as input
.ifdef COM_DATA_PUE
  inr r16, COM_DATA_PUE
  cbr r16, (1<<COM_DATA_PIN)              ; disable pullup on DATA
  outr COM_DATA_PUE, r16
.else
  cbi COM_DATA_OUTPUT, COM_DATA_PIN      ; disable pullup on DATA
.endif

  ; setup pin-change interrupt for CLK
  rcall com2wEnableClkIrq

  ; enable IRQ
.ifdef COM_IRQ_ICR_ADDR
  M_COM2WSETUPPCICR
.else
  .ifdef INT0
    .if COM_IRQ_BIT_CLK == INT0
      M_COM2WSETUPINT0
    .else
      M_COM2WSETUPPCI
    .endif
  .else
    M_COM2WSETUPPCI
  .endif
.endif


#if 0
  inr r16, COM_IRQ_ADDR_CLK
  sbr r16, (1<<COM_IRQ_BIT_CLK)           ; enable pin change irq for ATTN line
  outr COM_IRQ_ADDR_CLK, r16

  inr r16, GIMSK                           ; enable pin change irq PCIE0 or PCIE1
  sbr r16, (1<<COM_IRQ_GIMSK_CLK)
  outr GIMSK, r16
  ldi r16, (1<<COM_IRQ_GIFR_CLK)          ; clear pending irq by writing 1 to ATTN bit
  outr GIFR, r16
#endif

  ret
; @end



; ---------------------------------------------------------------------------
; @routine COM2W_Every100ms @global
;
; @clobbers R16, Y

COM2W_Every100ms:
  ldi yl, LOW(com2w_iface)
  ldi yh, HIGH(com2w_iface)
  push r15
    in r15, SREG
    cli
    rcall NET_Interface_Periodically         ; (R16)
    out SREG, r15
  pop r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine COM2W_Run @global
;
; @clobbers (R16, R17, R18, R20, R22, R24, R25, X)

COM2W_Run:
  push r15
    in r15, SREG
    cli
    ldi yl, LOW(com2w_iface)
    ldi yh, HIGH(com2w_iface)
    rcall com2wSendNextPkg     ; (R16, R17, R18, R20, R22, R24, R25, X)
    brcs COM2W_Run_ok
  pop r15
  clc
  rjmp COM2W_Run_ret
COM2W_Run_ok:
  pop r15
  sec
COM2W_Run_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wReceiveNextPkg
;
; Receive packet.
;
; @param Y pointer to start of interface data
; @clobbers R16, R17, R18, R19, R20, R22, R24, R25, X

com2wReceiveNextPkg:
  mov xl, yl
  mov xh, yh
  adiw xh:xl, COM2W_IFACE_OFFS_BUFFER
  ldi r19, COM2W_BUFFER_SIZE
  rcall com2wRecvMsg                              ; (r16, r17, r18, r19, r20, r22, r24, r25, X)
  brcc com2wReceiveNextPkg_end
  
  mov xl, yl
  mov xh, yh
  adiw xh:xl, COM2W_IFACE_OFFS_BUFFER
  rcall NETMSG_CheckMessageInBuffer               ; (R16, R17, R18, R19, R20, X)
  brcc com2wReceiveNextPkg_eCrc

#ifndef COM_ACCEPT_ALL_DEST
  ; check destination addr
  mov xl, yl
  mov xh, yh
  adiw xh:xl, COM2W_IFACE_OFFS_BUFFER
  adiw xh:xl, NETMSG_OFFS_DESTADDR
  ld r16, X                                       ; read destination address
  cpi r16, 0xff
  breq com2wReceiveNextPkg_forMe
  ldd r17, Y+NET_IFACE_OFFS_ADDRESS
  cp r16, r17
  breq com2wReceiveNextPkg_forMe
  ; packet not for me, but correctly received, inc counter, but don't light LED
  ldi r16, NET_IFACE_OFFS_PACKETSIN_LOW
  rcall NET_Interface_IncCounter16                ; (R24, R25)
  rjmp com2wReceiveNextPkg_end
com2wReceiveNextPkg_forMe:
#endif

  ; msg received, alloc buffer for it
  rcall NET_Buffer_Alloc                          ; R16=buffer num (R16, R17, X)
  brcs com2wReceiveNextPkg_gotBuffer
  ; out of memory
  ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
  rcall NET_Interface_IncCounter16                ; (R24, R25)
  rjmp com2wReceiveNextPkg_end

  ; copy received message into allocated buffer
com2wReceiveNextPkg_gotBuffer:
  mov r19, r16                               ; save buffer num
  rcall NET_Interface_SetIfaceNumInBuffer    ; (R16, R17)
  mov r16, r19                               ; restore buffer num
  push zl
    push zh
      mov zl, yl
      mov zh, yh
      adiw zh:zl, COM2W_IFACE_OFFS_BUFFER    ; Z=SRC
      adiw xh:xl, 1                          ; X=DEST
      ldd r18, Z+NETMSG_OFFS_MSGLEN
      inc r18
      inc r18
      inc r18
com2wReceiveNextPkg_copyLoop:
        ld r17, Z+
        st X+, r17
        dec r18
      brne com2wReceiveNextPkg_copyLoop
    pop zh
  pop zl

  ; add to incoming msg pool
  rcall NET_AddIncomingMsgNum                     ; (R17, R18, X)
  brcc com2wReceiveNextPkg_eMissed
  ldi r16, NET_IFACE_OFFS_PACKETSIN_LOW
  rcall NET_Interface_IncCounter16                ; (R24, R25)
#ifdef LED1_NETWORK_ACTIVITY
  bigcall LED1_SetActivityTiming
#endif
  rjmp com2wReceiveNextPkg_end
com2wReceiveNextPkg_eCrc:
  ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
  rcall NET_Interface_IncCounter16                ; (R24, R25)
  rjmp com2wReceiveNextPkg_end
com2wReceiveNextPkg_eMissed:
  push r16
    ldi r16, NET_IFACE_OFFS_ERR_MISSED_LOW
    rcall NET_Interface_IncCounter16              ; (R24, R25)
  pop r16
  ; fall-through to release buffer
com2wReceiveNextPkg_relBuffer:
  rcall NET_Buffer_ReleaseByNum                   ; (R16, X)
com2wReceiveNextPkg_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wSendNextPkg @global
;
; Check whether there is an outgoing message in interface data
; and send it if possible.
;
; @return CFLAG set if okay, clear on error
; @param Y pointer to start of interface data
; @clobbers (R16, R17, R18, R20, R22, R24, R25, X)

com2wSendNextPkg:
  rcall NET_Interface_PeekNextOutgoingMsgNum ; (R17, R18, X)
  brcc com2wSendNextPkg_end
  rcall NET_Buffer_Locate                    ; get pointer to buffer (R17)
  brcc com2wSendNextPkg_end
  adiw xh:xl, 1                              ; skip buffer header
  rcall com2wSendMsg                         ; (R16, R18, R20, R22, R24, R25, X)
  brcc com2wSendNextPkg_end
  rcall NET_Interface_GetNextOutgoingMsgNum  ; remove from stack (R17, R18, X)
  rcall NET_Buffer_ReleaseByNum              ; release buffer (R16, X)
  sec
com2wSendNextPkg_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wSendMsg
;
; @param X pointer to bytes to send
; @param Y pointer to interface data in SRAM
; @return CFLAG set if message sent, cleared otherwise
; @clobbers R16, R18 (R20, R22, R24, R25, X)

com2wSendMsg:
  ldi r20, 6                           ; wait for about 60us for clock low
  rcall com2wWaitForClockLowMulti10Us  ; (R16, R20, R22)
  brcs com2wSendMsg_busy               ; CLK got low while waiting, so line is busy
  push r15
    in r15, SREG
    cli                                 ; atomic disable irq and set CLK low
    rcall com2wDisableClkIrq            ; (none)
    rcall com2wClkSetLow                ; reserve bus (none)
    out SREG, r15
  pop r15
  adiw xh:xl, NETMSG_OFFS_MSGLEN
  ld r18, X
  sbiw xh:xl, NETMSG_OFFS_MSGLEN
  inc r18                               ; adjust for DESTADDR
  inc r18                               ; adjust for MSGLEN
  inc r18                               ; adjust for CRCBYTE
  rcall com2wWaitTime1                  ; longer wait period (R22)
  rcall com2wSendBytes                  ; (r16, r17, r18, r22, X)
  rcall com2wClkSetHigh                 ; make sure bus is released
  rcall com2wDataSetHigh

  rcall com2wEnableClkIrq               ; (none)
  ldi r16, NET_IFACE_OFFS_PACKETSOUT_LOW
  rcall NET_Interface_IncCounter16       ; (R24, R25)
  sec
  ret
com2wSendMsg_busy:
  ldi r16, NET_IFACE_OFFS_ERR_BUSY_LOW
  rcall NET_Interface_IncCounter16       ; (R24, R25)
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wSendBytes
;
; @param  R18 number of bytes to send
; @param X pointer to bytes to send
; @param Y pointer to interface data in SRAM
; @clobbers: r16, r18, X (r17, r22)

com2wSendBytes:
com2wSendBytes_loop:
    rcall com2wClkSetLow                     ; (none)
    rcall com2wWaitTime1                      ; longer wait period (R22)
    ld r16, X+
    rcall com2wSendByte                      ; (R16, R17, R22)
    dec r18
  brne com2wSendBytes_loop
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wSendByte
;
; @param  R16 byte to send
; @clobbers: r16, r17 (r22)

com2wSendByte:
  push r15
    in r15, SREG
    ldi r17, 8
com2wSendByte_loop:
      M_COM2WCLKSETLOW
      out SREG, r15                          ; probably enable irqs
      rcall com2wWaitTime1                   ; wait for longer time (R22)
      lsr r16
      brcs com2wSendByte_send1
      M_COM2WDATASETLOW
      rjmp com2wSendByte_sent
com2wSendByte_send1:
      M_COM2WDATASETHIGH
com2wSendByte_sent:
      Utils_WaitNanoSecs 5000, 0, r22        ; wait for very short time to ensure data is stable when clock rises
      cli                                    ; ensure time period by disabling irqs
      M_COM2WCLKSETHIGH
      rcall com2wWaitTime2                   ; wait for shorter time (R22)
      dec r17
    brne com2wSendByte_loop
    out SREG, r15
  pop r15
  rcall com2wWaitTime2                       ; wait for shorter time (R22)
  M_COM2WDATASETHIGH                         ; ensure data line is high
  ret
; @end






; ---------------------------------------------------------------------------
; @routine com2wRecvMsg
;
; Receive a packet into buffer pointed to by X.
; Expects interrupts to be disabled.
;
; @param R19 max buffer size
; @param X   buffer to receive to
; @return CFLAG set if msg received, cleared on error (see R16)
; @return R16   if CFLAG cleared: 0=message not for this node, otherwise error
; @clobbers r16, r17, r18, r19, r20, r22, r24, r25, X

com2wRecvMsg:
  ; check buffer size
  subi r19, 2
  brcs com2wRecvMsg_eBadSize
  ; read destination address
  rcall com2wRecvByte                    ; (r17, r18, r20, r22)
  brcc com2wRecvMsg_eIo
  st X+, r16
  ; read remaining msg size
  rcall com2wRecvByte                    ; (r17, r18, r20, r22)
  brcc com2wRecvMsg_eIo
  st X+, r16
  inc r16                                 ; account for CRC byte
  sub r19, r16
  brcs com2wRecvMsg_eBadSize
  mov r19, r16
com2wRecvMsg_loop:
    rcall com2wRecvByte                  ; (r17, r18, r20, r22)
    brcc com2wRecvMsg_eIo
    st X+, r16
    dec r19
  brne com2wRecvMsg_loop
  sec
  rjmp com2wRecvMsg_end
com2wRecvMsg_eBadSize:
  ldi r16, NET_IFACE_OFFS_ERR_MSGSIZE_LOW
  rjmp com2wRecvMsg_incCounterRet
com2wRecvMsg_eIo:
  ldi r16, NET_IFACE_OFFS_ERR_IO_LOW
com2wRecvMsg_incCounterRet:
  rcall NET_Interface_IncCounter16        ; (R24, R25)
  rcall com2wRecvByteWaitForQuietClk      ; (r18, r20, r22)
com2wRecvMsg_clcRet:
  clc
com2wRecvMsg_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wRecvByteWaitForQuietClk
;
; Wait until the clock line is consistently high for 1ms.
;
; @clobbers r18, r20, r22

com2wRecvByteWaitForQuietClk:
  ldi r18, 200
com2wRecvByteWaitForQuietClk_loop:
      ldi r20, 100                          ; wait up to 1ms for clock high (R20, R22)
      rcall com2wWaitForClockLowMulti10Us
      brcs com2wRecvByteWaitForQuietClk_waitForLow
      dec r18
    brne com2wRecvByteWaitForQuietClk_loop
    rjmp com2wRecvByteWaitForQuietClk_ret
com2wRecvByteWaitForQuietClk_waitForLow:
    ldi r20, 100                          ; wait up to 1ms for clock low (R20, R22)
    rcall com2wWaitForClockLowMulti10Us
    brcc com2wRecvByteWaitForQuietClk_ret ; not low within 1ms, assume line is quiet
  brne com2wRecvByteWaitForQuietClk_loop
com2wRecvByteWaitForQuietClk_ret:
  ret



; ---------------------------------------------------------------------------
; @routine com2wRecvByte
;
; @return CFLAG set if byte received, cleared on error
; @return r16 byte received
; @clobbers r17, r18, r20, r22

com2wRecvByte:
  ldi r17, 8
  clr r16
com2wRecvByte_loop:
    ldi r20, 100                         ; wait up to 1ms for clock low
    rcall com2wWaitForClockLowMulti10Us  ; (R20, R22)
    brcc com2wRecvByte_end
    ldi r20, 100                         ; wait up to 1ms for clock high
    rcall com2wWaitForClockHighMulti10Us ; (R20, R22)
    brcc com2wRecvByte_end
    ; handle received bit
    inr r18, COM_DATA_INPUT
    andi r18, (1<<COM_DATA_PIN)
    clc
    breq com2wRecvByte_clockData
    sec
com2wRecvByte_clockData:
    ror r16
    dec r17
  brne com2wRecvByte_loop
  sec
com2wRecvByte_end:
  ret
; @end






; ---------------------------------------------------------------------------
; @routine com2wEnableClkIrq
;
; @clobbers 

com2wEnableClkIrq:
  push r16
    inr r16, COM_IRQ_ADDR_CLK
    sbr r16, (1<<COM_IRQ_BIT_CLK)          ; enable pin change irq for CLK line
    outr COM_IRQ_ADDR_CLK, r16
  pop r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wDisableClkIrq
;
; @clobbers none

com2wDisableClkIrq:
  push r16
    inr r16, COM_IRQ_ADDR_CLK
    cbr r16, (1<<COM_IRQ_BIT_CLK)        ; disable pin change irq for CLK line
    outr COM_IRQ_ADDR_CLK, r16
  pop r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wClkSetHigh
;
; @clobbers none

com2wClkSetHigh:
  cbi COM_CLK_DDR, COM_CLK_PIN           ; set CLK as input
.ifdef COM_CLK_PUE
;  cbi COM_CLK_PUE, COM_CLK_PIN           ; disable pullup on CLK
.else
  cbi COM_CLK_OUTPUT, COM_CLK_PIN        ; disable pullup on CLK
.endif
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wClkSetLow
;
; @clobbers none

com2wClkSetLow:
  sbi COM_CLK_DDR, COM_CLK_PIN          ; set CLK as output
  cbi COM_CLK_OUTPUT, COM_CLK_PIN       ; set CLK low
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wDataSetHigh
;
; @clobbers none

com2wDataSetHigh:
  cbi COM_DATA_DDR, COM_DATA_PIN           ; set DATA as input
.ifdef COM_DATA_PUE
;  cbi COM_DATA_PUE, COM_CLK_PIN           ; disable pullup on DATA
.else
  cbi COM_DATA_OUTPUT, COM_DATA_PIN        ; disable pullup on DATA
.endif
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wDataSetLow
;
; @clobbers none

com2wDataSetLow:
  sbi COM_DATA_DDR, COM_DATA_PIN          ; set DATA as output
  cbi COM_DATA_OUTPUT, COM_DATA_PIN       ; set DATA low
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wWaitForClockHighMulti10Us
;
; Wait for high CLK
;
; @param  R20 multiple of 10us to wait (e.g. "2" for "20" us)
; @return CFLAG set if okay (state reached), cleared on error
; @clobbers: r20, r22

com2wWaitForClockHighMulti10Us:
.if clock > 1000000
; begin version for > 1000000 Hz
  ldi r22, clock/1000000
com2wWaitForClockHighMulti10Us_loop0:
    push r20
com2wWaitForClockHighMulti10Us_loop:                      ; 10 cycles per loop
        sbic COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
          rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
        sbic COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
          rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
        sbic COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
          rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
        nop                                               ; +1
        dec r20                                           ; +1
      brne com2wWaitForClockHighMulti10Us_loop            ; +2 if TRUE, +1 if FALSE
    pop r20
    dec r22                                               ; +1
  brne com2wWaitForClockHighMulti10Us_loop0               ; +1 if FALSE, +2 if TRUE
  clc                                                     ; +1
  ret                                                     ; +4
com2wWaitForClockHighMulti10Us_stateReached:
  pop r20
  sec                                                 ; +1
  ret                                                 ; +4
; end version for > 1000000 Hz
.elif clock < 1000000
  .error "Clock speed too low"
.else
; begin version for 1000000 Hz
com2wWaitForClockHighMulti10Us_loop:                  ; 10 cycles per loop
    sbic COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
      rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
    sbic COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
      rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
    sbic COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
      rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
    nop                                               ; +1
    dec r20                                           ; +1
  brne com2wWaitForClockHighMulti10Us_loop             ; +2 if TRUE, +1 if FALSE
  clc                                                 ; +1
  ret                                                 ; +4
com2wWaitForClockHighMulti10Us_stateReached:
  sec                                                 ; +1
  ret                                                 ; +4
; end version for 1000000 Hz
.endif
; @end



; ---------------------------------------------------------------------------
; @routine com2wWaitForClockLowMulti10Us
;
; Wait for low CLK
;
; @param  R20 multiple of 10us to wait (e.g. "2" for "20" us)
; @return CFLAG set if okay (state reached), cleared on error
; @clobbers: r20, r22

com2wWaitForClockLowMulti10Us:
.if clock > 1000000
; begin version for > 1000000 Hz
  ldi r22, clock/1000000
com2wWaitForClockLowMulti10Us_loop0:
    push r20
com2wWaitForClockLowMulti10Us_loop:                   ; 10 cycles per loop
        sbis COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
          rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
        sbis COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
          rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
        sbis COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
          rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
        nop                                             ; +1
        dec r20                                         ; +1
      brne com2wWaitForClockLowMulti10Us_loop           ; +2 if TRUE, +1 if FALSE
    pop r20
    dec r22                                           ; +1
  brne com2wWaitForClockLowMulti10Us_loop0            ; +1 if FALSE, +2 if TRUE
  clc                                                 ; +1
  ret                                                 ; +4
com2wWaitForClockLowMulti10Us_stateReached:
  pop r20
  sec                                                 ; +1
  ret                                                 ; +4
; end version for > 1000000 Hz
.elif clock < 1000000
  .error "Clock speed too low"
.else
; begin version for 1000000 Hz
com2wWaitForClockLowMulti10Us_loop:                   ; 10 cycles per loop
    sbis COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
      rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
    sbis COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
      rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
    sbis COM_CLK_INPUT, COM_CLK_PIN                   ; +2 if skipped, +1 if taken
      rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
    nop                                               ; +1
    dec r20                                           ; +1
  brne com2wWaitForClockLowMulti10Us_loop             ; +2 if TRUE, +1 if FALSE
  clc                                                 ; +1
  ret                                                 ; +4
com2wWaitForClockLowMulti10Us_stateReached:
  sec                                                 ; +1
  ret                                                 ; +4
; end version for 1000000 Hz
.endif
; @end



; ---------------------------------------------------------------------------
; @routine com2wWaitTime1
;
; waits for longer period (e.g. 30ns)
;
; @clobbers R22

com2wWaitTime1:
  Utils_WaitNanoSecs COM2W_WAITTIME1, 7, r22            ; wait for longer time (minus RCALL and RET)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wWaitTime2
;
; waits for shorter period (e.g. 10ns)
;
; @clobbers R22

com2wWaitTime2:
  Utils_WaitNanoSecs COM2W_WAITTIME2, 7, r22            ; wait for shorter time (minus RCALL and RET)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wPcintIsr @global @isr
;
; ISR for PCINT0/1
;
; @clobbers: none

com2wPcintIsr:
  push r15
    in r15, SREG
    sbic COM_CLK_INPUT, COM_CLK_PIN
      rjmp com2wPcintIsr_end
    ; low, read packet
    push r16
      push r17
        push r18
          push r19
            push r20
              push r21
                push r22
                  push r24
                    push r25
                      push xl
                        push xh
                          push yl
                            push yh
                              ldi yl, LOW(com2w_iface)
                              ldi yh, HIGH(com2w_iface)
                              rcall com2wReceiveNextPkg         ; (R16, R17, R18, R19, R20, R21, R22, R24, R25, X)
                            pop yh
                          pop yl
                        pop xh
                      pop xl
                    pop r25
                  pop r24
                pop r22
              pop r21
            pop r20
          pop r19
        pop r18
      pop r17
    pop r16
com2wPcintIsr_end:
    out SREG, r15
  pop r15
  reti
; @end



#endif ; AVR_MODULES_COM2W_COM2W_H

