; ***************************************************************************
; 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.   *
; ***************************************************************************

; work in progress!
; writing works
; reading works on 1st device
; reading on 2nd device doesn't work


#ifndef AVR_MODULES_COM2W_COM2WI_H
#define AVR_MODULES_COM2W_COM2WI_H


.equ COM2WI_BUFFER_SIZE = NET_BUFFERS_SIZE-1

.equ COM2WI_R_MAX_WAIT_HI_TIME = 100  ; max 1ms
.equ COM2WI_S_MAX_WAIT_HI_TIME = 100  ; max 1ms
.equ COM2WI_S_MAX_WAIT_LO_TIME = 100  ; max 1ms


.equ COM2WI_W_MAX_WAIT_BUSFREE = 100  ; max 1ms

.equ COM2WI_STATETIMER_W_BYTEHOLDCLOCKLOW =  2 ; 20 us
.equ COM2WI_STATETIMER_W_BITHOLDCLOCKLOW  =  2 ; 20 us
.equ COM2WI_STATETIMER_W_BITSETDATA       =  2 ; 20 us
.equ COM2WI_STATETIMER_W_BITHOLDCLOCKHIGH =  2 ; 20 us
.equ COM2WI_STATETIMER_R_WAITFORCLOCKHIGH = 100 ;  1 ms
.equ COM2WI_STATETIMER_R_WAITFORCLOCKLOW  = 100 ;  1 ms
.equ COM2WI_STATETIMER_S_WAITFORCLOCKLOW  = 100 ;  1 ms

.equ COM2WI_STATE_IDLE               = 0

.equ COM2WI_STATE_W_MSGWAITBUSFREE   = 1
.equ COM2WI_STATE_W_BYTEHOLDCLOCKLOW = 2
.equ COM2WI_STATE_W_BITHOLDCLOCKLOW  = 3
.equ COM2WI_STATE_W_BITSETDATA       = 4
.equ COM2WI_STATE_W_BITHOLDCLOCKHIGH = 5
.equ COM2WI_STATE_W_MSGSENT          = 6

.equ COM2WI_STATE_R_WAITFORCLOCKHIGH = 7
.equ COM2WI_STATE_R_WAITFORCLOCKLOW  = 8
.equ COM2WI_STATE_R_MSGRECVD         = 9

.equ COM2WI_STATE_S_WAITFORCLOCKLOW  = 10
.equ COM2WI_STATE_S_WAITFORCLOCKHIGH = 11

.equ COM2WI_STATE_COUNT              = 12



.equ COM2WI_IFACE_OFFS_BEGIN          = NET_IFACE_SIZE
.equ   COM2WI_IFACE_OFFS_STATE        = COM2WI_IFACE_OFFS_BEGIN+0
.equ   COM2WI_IFACE_OFFS_STATETIMER   = COM2WI_IFACE_OFFS_BEGIN+1
.equ   COM2WI_IFACE_OFFS_STATECOUNTER = COM2WI_IFACE_OFFS_BEGIN+2
.equ   COM2WI_IFACE_OFFS_PINMASK_CLK  = COM2WI_IFACE_OFFS_BEGIN+3
.equ   COM2WI_IFACE_OFFS_PINMASK_DATA = COM2WI_IFACE_OFFS_BEGIN+4
.equ   COM2WI_IFACE_OFFS_BITCOUNTER   = COM2WI_IFACE_OFFS_BEGIN+5
.equ   COM2WI_IFACE_OFFS_CURRBYTE     = COM2WI_IFACE_OFFS_BEGIN+6
.equ   COM2WI_IFACE_OFFS_BUFPOS_LOW   = COM2WI_IFACE_OFFS_BEGIN+7
.equ   COM2WI_IFACE_OFFS_BUFPOS_HIGH  = COM2WI_IFACE_OFFS_BEGIN+8
.equ   COM2WI_IFACE_OFFS_BUFUSED      = COM2WI_IFACE_OFFS_BEGIN+9
.equ   COM2WI_IFACE_OFFS_BUFLEFT      = COM2WI_IFACE_OFFS_BEGIN+10
.equ   COM2WI_IFACE_OFFS_BUFFER       = COM2WI_IFACE_OFFS_BEGIN+11
.equ COM2WI_IFACE_SIZE                = COM2WI_IFACE_OFFS_BUFFER+COM2WI_BUFFER_SIZE




; ---------------------------------------------------------------------------
; @macro mCOM2WI_INIT
;
; @param @0 interface number (beginning with 0)

.macro mCOM2WI_INIT
  ldi yl, LOW(com2wi@0_iface)
  ldi yh, HIGH(com2wi@0_iface)

  mov xl, yl
  mov xh, yh
  ldi r17, COM2WI_IFACE_SIZE
  clr r16
  rcall Utils_FillSram         ; (R17, X)
  
  rcall NET_Interface_Init     ; (R16, R17, X)

  ldi r16, @0 +1
  std Y+NET_IFACE_OFFS_IFACENUM, r16

  ldi r16, COM_MASK_CLK@0
  std Y+COM2WI_IFACE_OFFS_PINMASK_CLK, r16
  ldi r16, COM_MASK_DATA@0
  std Y+COM2WI_IFACE_OFFS_PINMASK_DATA, r16
;  ldi r16, COM_MASK_IRQ@0
;  std Y+COM2WI_IFACE_OFFS_PINMASK_IRQ, r16
  rcall com2wiInit
.endmacro
; @end





.dseg



.if COM_PORTS >0
com2wi0_iface: .byte COM2WI_IFACE_SIZE
.endif

.if COM_PORTS >1
com2wi1_iface: .byte COM2WI_IFACE_SIZE
.endif

.if COM_PORTS >2
com2wi2_iface: .byte COM2WI_IFACE_SIZE
.endif

.if COM_PORTS >3
com2wi3_iface: .byte COM2WI_IFACE_SIZE
.endif

.if COM_PORTS >4
com2wi4_iface: .byte COM2WI_IFACE_SIZE
.endif

.if COM_PORTS >5
com2wi5_iface: .byte COM2WI_IFACE_SIZE
.endif

.if COM_PORTS >6
com2wi6_iface: .byte COM2WI_IFACE_SIZE
.endif

.if COM_PORTS >7
com2wi7_iface: .byte COM2WI_IFACE_SIZE
.endif



.cseg



; ---------------------------------------------------------------------------
; @routine COM2WI_Init

COM2WI_Init:
.if COM_PORTS >0
  mCOM2WI_INIT 0
.endif

.if COM_PORTS >1
  mCOM2WI_INIT 1
.endif

.if COM_PORTS >2
  mCOM2WI_INIT 2
.endif

.if COM_PORTS >3
  mCOM2WI_INIT 3
.endif

.if COM_PORTS >4
  mCOM2WI_INIT 4
.endif

.if COM_PORTS >5
  mCOM2WI_INIT 5
.endif

.if COM_PORTS >6
  mCOM2WI_INIT 6
.endif

.if COM_PORTS >7
  mCOM2WI_INIT 7
.endif

  rcall com2wiSetupTimer1
  ret
; @end




; ---------------------------------------------------------------------------
; @routine COM2WI_Timer1Isr @global @isr
;
; ISR for timer1
;
; @clobbers: none

COM2WI_Timer1Isr:
  push r15
    in r15, SREG
    push r1
      push r2
        inr r1, COM_CLK_INPUT
        inr r2, COM_DATA_INPUT
        push r16
          push r17
            push r18
              push yl
                push yh
                  push zl
                    push zh
                      rcall COM2WI_HandleTimerIrq  ; (r16, r17, r18, Y, Z)
                    pop zh
                  pop zl
                pop yh
              pop yl
            pop r18
          pop r17
        pop r16
      pop r2
    pop r1
    out SREG, r15
  pop r15
  reti
; @end



; ---------------------------------------------------------------------------
; @routine COM2WI_Run

COM2WI_Run:
  ldi yl, LOW(com2wi0_iface)
  ldi yh, HIGH(com2wi0_iface)
  ldi r18, COM_PORTS
  clr r19
COM2WI_Run_loop:
    push r18
      push r19
        rcall com2wiRun
      pop r19
    pop r18
    sbci r19, 0
    ldi r16, COM2WI_IFACE_SIZE
    add yl, r16
    adc yh, r16
    sub yh, r16
    dec r18
  brne COM2WI_Run_loop

  ; check for repeat request
  tst r19
  clc
  breq COM2WI_Run_end
  sec
COM2WI_Run_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine COM2WI_HandleTimerIrq
;
; @param Y pointer to interface data in SRAM
; @clobbers R16, R17, R18, Y, Z

COM2WI_HandleTimerIrq:
  ldi yl, LOW(com2wi0_iface)
  ldi yh, HIGH(com2wi0_iface)
  ldi r18, COM_PORTS
COM2WI_HandleTimerIrq_loop:
    push r18
      rcall com2wiHandleIrq  ; R16, R17, R18, Z
    pop r18
    ldi r16, COM2WI_IFACE_SIZE
    add yl, r16
    adc yh, r16
    sub yh, r16
    dec r18
  brne COM2WI_HandleTimerIrq_loop
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiInit

com2wiInit:
  rcall com2wiSetupLines

  ldi r16, COM2WI_STATE_IDLE
  std Y+COM2WI_IFACE_OFFS_STATE, r16

  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiSetupLines

com2wiSetupLines:
  ; setup CLK line (as input, disable internal pull-up resistor)
.ifdef COM_CLK_PUE
  ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
  com r16
  inr r17, COM_CLK_PUE
  and r17, r16
  outr COM_CLK_PUE, r17
.endif
  rcall com2wiClkSetHigh

  ; setup DATA line (as input, disable internal pull-up resistor)
.ifdef COM_DATA_PUE
  ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_DATA
  com r16
  inr r17, COM_DATA_PUE
  and r17, r16
  outr COM_DATA_PUE, r17
.endif
  rcall com2wiDataSetHigh

  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiSetupTimer1
;
; setup timer for IRQ every 20us

com2wiSetupTimer1:
  ; CTC mode, no prescaler, OCR1A=100 (every 20us at 20MHz)
  ; WGM13=0, WGM12=1, WGM11=0, WGM10=0
  ldi r16, 0
  outr TCCR1A, r16                  ; WGM11=0, WGM10=0
  ldi r16, (0<<CS12) | (0<<CS11) | (1<<CS10) | (0<<WGM13) | (1<<WGM12)
  outr TCCR1B, r16
  
  clr r17  HIGH(200)
  ldi r16, LOW(200)
  outr OCR1AH, r17
  outr OCR1AL, r16

  ldi r16, (1<<OCF1A)         ; clear pending interrupts
  outr TIFR1, r16

  inr r16, TIMSK1
  sbr r16, (1<<OCIE1A)        ; Timer/Counter1 Output Compare Match A Interrupt Enable
  outr TIMSK1, r16

  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiClkSetHigh
;
; @clobbers none

com2wiClkSetHigh:
  push r16
    push r17
      ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
      ; clear bit in io reg (AND with complement)
      com r16                        
      inr r17, COM_CLK_DDR
      and r17, r16
      outr COM_CLK_DDR, r17          ; make pin input
.ifndef COM_CLK_PUE
      inr r17, COM_CLK_OUTPUT
      and r17, r16                   ; disable pullup
      outr COM_CLK_OUTPUT, r17
.endif
    pop r17
  pop r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiClkSetLow
;
; @clobbers none

com2wiClkSetLow:
  push r16
    push r17
      ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
      ; set bit in io reg
      inr r17, COM_CLK_DDR
      or r17, r16
      outr COM_CLK_DDR, r17     ; make pin output

      com r16
      inr r17, COM_CLK_OUTPUT
      and r17, r16
      outr COM_CLK_OUTPUT, r17  ; set pin low

    pop r17
  pop r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiDataSetHigh
;
; @param Y pointer to interface data in SRAM
; @clobbers none

com2wiDataSetHigh:
  push r16
    push r17
      ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_DATA
      ; clear bit in io reg (AND with complement)
      com r16                        
      inr r17, COM_DATA_DDR
      and r17, r16
      outr COM_DATA_DDR, r17         ; make pin input
.ifndef COM_DATA_PUE
      inr r17, COM_DATA_OUTPUT
      and r17, r16                   ; disable pullup
      outr COM_DATA_OUTPUT, r17
.endif
    pop r17
  pop r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiDataSetLow
;
; @param Y pointer to interface data in SRAM
; @clobbers none

com2wiDataSetLow:
  push r16
    push r17
      ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_DATA
      ; set bit in io reg
      inr r17, COM_DATA_DDR
      or r17, r16
      outr COM_DATA_DDR, r17          ; make pin output

      com r16
      inr r17, COM_DATA_OUTPUT
      and r17, r16
      outr COM_DATA_OUTPUT, r17       ; set pin low

    pop r17
  pop r16
  ret
; @end




; ---------------------------------------------------------------------------
; @routine com2wiHandleIrq
;
; @param Y pointer to interface data in SRAM
; @clobbers R16, R17, R18, Z

com2wiHandleIrq:
  ; dec state timer
  ldd r17, Y+COM2WI_IFACE_OFFS_STATETIMER
  tst r17
  breq com2wiHandleIrq_jmp
  dec r17
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r17
  ; jump
com2wiHandleIrq_jmp:
  ldi zl, LOW(com2wiIrqJumpTable)
  ldi zh, HIGH(com2wiIrqJumpTable)
  ldd r16, Y+COM2WI_IFACE_OFFS_STATE
  cpi r16, COM2WI_STATE_COUNT
  brcc com2wiHandleIrq_ret
  add zl, r16
  adc zh, r16
  sub zh, r16
  ijmp
com2wiHandleIrq_ret:
  ret
com2wiIrqJumpTable:
  rjmp com2wiIrqStateIdle              ;  0: COM2WI_STATE_IDLE                (r16, r18)
  rjmp com2wiIrqStateWMsgWaitBusFree   ;  1: COM2WI_STATE_W_MSGWAITBUSFREE    (r16, r18)
  rjmp com2wiIrqStateWByteHoldClockLow ;  2: COM2WI_STATE_W_BYTEHOLDCLOCKLOW  (r16)
  rjmp com2wiIrqStateWBitHoldClockLow  ;  3: COM2WI_STATE_W_BITHOLDCLOCKLOW   (r16)
  rjmp com2wiIrqStateWBitSetData       ;  4: COM2WI_STATE_W_BITSETDATA        (r16)
  rjmp com2wiIrqStateWBitHoldClockHigh ;  5: COM2WI_STATE_W_BITHOLDCLOCKHIGH  (r16)
  ret                                  ;  6: COM2WI_STATE_W_MSGSENT
  rjmp com2wiIrqStateRWaitForClockHigh ;  7: COM2WI_STATE_R_WAITFORCLOCKHIGH
  rjmp com2wiIrqStateRWaitForClockLow  ;  8: COM2WI_STATE_R_WAITFORCLOCKLOW
  ret                                  ;  9: COM2WI_STATE_R_MSGRECVD
  rjmp com2wiIrqStateSWaitForClockLow  ; 10: COM2WI_STATE_S_WAITFORCLOCKLOW
  rjmp com2wiIrqStateSWaitForClockHigh ; 11: COM2WI_STATE_S_WAITFORCLOCKHIGH
; @end




; ---------------------------------------------------------------------------
; @routine com2wiIrqStateIdle
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16, r18

com2wiIrqStateIdle:
  mov r16, r1
;  inr r16, COM_CLK_INPUT
  ldd r18, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
  and r16, r18
  brne com2wiIrqStateIdle_ret
  ; CLK is low, start receiving
  push xl
    push xh
      mov xh, yh
      mov xl, yl
      adiw xh:xl, COM2WI_IFACE_OFFS_BUFFER
      std Y+COM2WI_IFACE_OFFS_BUFPOS_LOW, xl
      std Y+COM2WI_IFACE_OFFS_BUFPOS_HIGH, xh
      ldi r16, COM2WI_BUFFER_SIZE
      std Y+COM2WI_IFACE_OFFS_BUFLEFT, r16
      clr r16
      std Y+COM2WI_IFACE_OFFS_BUFUSED, r16
      std Y+COM2WI_IFACE_OFFS_BITCOUNTER, r16
    pop xh
  pop xl
  rjmp com2wiEnterStateRWaitForClockHigh
com2wiIrqStateIdle_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiIrqStateWMsgWaitBusFree
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16, r18

com2wiIrqStateWMsgWaitBusFree:
  inr r16, COM_CLK_INPUT
  ldd r18, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
  and r16, r18
  brne com2wiIrqStateWMsgWaitBusFree_isHi
  ; CLK line is low, restart wait counter
  ldi r16, COM2WI_W_MAX_WAIT_BUSFREE
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ret
com2wiIrqStateWMsgWaitBusFree_isHi:
  tst r17
  brne com2wiIrqStateWMsgWaitBusFree_ret
  ; CLK still high, time's up, start transmitting
  rjmp com2wiEnterStateWByteHoldClockLow
com2wiIrqStateWMsgWaitBusFree_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiIrqStateWMsgWaitBusFree
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16

com2wiIrqStateWByteHoldClockLow:
  tst r17
  brne com2wiIrqStateWByteHoldClockLow_ret
  rjmp com2wiEnterStateWBitHoldClockLow     ; (r16)
com2wiIrqStateWByteHoldClockLow_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiIrqStateWMsgWaitBusFree
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16

com2wiIrqStateWBitHoldClockLow:
  tst r17
  brne com2wiIrqStateWBitHoldClockLow_ret
  rjmp com2wiEnterStateWBitSetData          ; (r16)
com2wiIrqStateWBitHoldClockLow_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiIrqStateWBitSetData
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16

com2wiIrqStateWBitSetData:
  tst r17
  brne com2wiIrqStateWBitSetData_ret
  rjmp com2wiEnterStateWBitHoldClockHigh
com2wiIrqStateWBitSetData_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiIrqStateWBitHoldClockHigh
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16

com2wiIrqStateWBitHoldClockHigh:
  tst r17
  brne com2wiIrqStateWBitHoldClockHigh_ret

  ldd r16, Y+COM2WI_IFACE_OFFS_BITCOUNTER
  cpi r16, 8
  breq com2wiIrqStateWBitHoldClockHigh_byteFull
  rjmp com2wiEnterStateWBitHoldClockLow          ; (r16)
com2wiIrqStateWBitHoldClockHigh_byteFull:
  ldd r16, Y+COM2WI_IFACE_OFFS_BUFLEFT
  tst r16
  brne com2wiIrqStateWBitHoldClockHigh_nextByte
  rjmp com2wiEnterStateWMsgSent                  ; (r16)
com2wiIrqStateWBitHoldClockHigh_nextByte:
  rjmp com2wiEnterStateWByteHoldClockLow
com2wiIrqStateWBitHoldClockHigh_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiIrqStateRWaitForClockHigh
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16

com2wiIrqStateRWaitForClockHigh:
  mov r16, r1
;  inr r16, COM_CLK_INPUT
  ldd r18, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
  and r16, r18
  brne com2wiIrqStateRWaitForClockHigh_isHi
  tst r17
  brne com2wiIrqStateRWaitForClockHigh_ret
  ; time's up, enter skipping mode
  rjmp com2wiEnterStateSWaitForClockHigh
com2wiIrqStateRWaitForClockHigh_isHi:
  mov r16, r2
;  inr r16, COM_DATA_INPUT
  ldd r18, Y+COM2WI_IFACE_OFFS_PINMASK_DATA
  and r16, r18
  clc
  breq com2wiIrqStateRWaitForClockHigh_shiftIn
  sec
com2wiIrqStateRWaitForClockHigh_shiftIn:
  ldd r16, Y+COM2WI_IFACE_OFFS_CURRBYTE
  ror r16
  std Y+COM2WI_IFACE_OFFS_CURRBYTE, r16
  ldd r17, Y+COM2WI_IFACE_OFFS_BITCOUNTER
  inc r17
  std Y+COM2WI_IFACE_OFFS_BITCOUNTER, r17
  cpi r17, 8
  brne com2wiIrqStateRWaitForClockHigh_waitForLo
  ; byte complete, store
  ldd r17, Y+COM2WI_IFACE_OFFS_BUFLEFT
  dec r17
  std Y+COM2WI_IFACE_OFFS_BUFLEFT, r17
  clr r18
  std Y+COM2WI_IFACE_OFFS_BITCOUNTER, r18
  ldd r18, Y+COM2WI_IFACE_OFFS_BUFUSED
  inc r18
  std Y+COM2WI_IFACE_OFFS_BUFUSED, r18
  push xl
    push xh
      ldd xl, Y+COM2WI_IFACE_OFFS_BUFPOS_LOW
      ldd xh, Y+COM2WI_IFACE_OFFS_BUFPOS_HIGH
      st X+, r16
      std Y+COM2WI_IFACE_OFFS_BUFPOS_LOW, xl
      std Y+COM2WI_IFACE_OFFS_BUFPOS_HIGH, xh
    pop xh
  pop xl
  tst r17
  breq com2wiIrqStateRWaitForClockHigh_msgRecvd
  ; check size
  cpi r18, 2
  brne com2wiIrqStateRWaitForClockHigh_waitForLo
  inc r16                                        ; last byte=remainder of msg, add CRC byte
  cp r17, r16
  brcs com2wiIrqStateRWaitForClockHigh_badMsgSize
  std Y+COM2WI_IFACE_OFFS_BUFLEFT, r16
  tst r16
  breq com2wiIrqStateRWaitForClockHigh_msgRecvd  ; jmp if message complete
com2wiIrqStateRWaitForClockHigh_waitForLo:
  rjmp com2wiEnterStateRWaitForClockLow
com2wiIrqStateRWaitForClockHigh_badMsgSize:
  ldi r16, NET_IFACE_OFFS_ERR_MSGSIZE_LOW
  push r24
    push r25
      rcall NET_Interface_IncCounter16
    pop r25
  pop r24
  rjmp com2wiEnterStateSWaitForClockHigh
com2wiIrqStateRWaitForClockHigh_msgRecvd:
  rjmp com2wiEnterStateRMsgRecvd
com2wiIrqStateRWaitForClockHigh_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiIrqStateRWaitForClockLow
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16

com2wiIrqStateRWaitForClockLow:
  mov r16, r1
;  inr r16, COM_CLK_INPUT
  ldd r18, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
  and r16, r18
  breq com2wiIrqStateRWaitForClockLow_isLo
  tst r17
  brne com2wiIrqStateRWaitForClockLow_ret
  ; time's up, enter skipping mode
  rjmp com2wiEnterStateSWaitForClockLow
com2wiIrqStateRWaitForClockLow_isLo:
  rjmp com2wiEnterStateRWaitForClockHigh
com2wiIrqStateRWaitForClockLow_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiIrqStateSWaitForClockHigh
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16

com2wiIrqStateSWaitForClockHigh:
  mov r16, r1
;  inr r16, COM_CLK_INPUT
  ldd r18, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
  and r16, r18
  breq com2wiIrqStateSWaitForClockHigh_ret ; jmp if still low
  rjmp com2wiEnterStateSWaitForClockLow
com2wiIrqStateSWaitForClockHigh_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiIrqStateSWaitForClockLow
;
; @param Y pointer to interface data in SRAM
; @param r17 current state timer
; @clobbers r16, r18

com2wiIrqStateSWaitForClockLow:
  mov r16, r1
;  inr r16, COM_CLK_INPUT
  ldd r18, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
  and r16, r18
  brne com2wiIrqStateSWaitForClockLow_isHi
  ; CLK is low again, restart loop
  rjmp com2wiEnterStateSWaitForClockHigh
com2wiIrqStateSWaitForClockLow_isHi:
  tst r17
  brne com2wiIrqStateSWaitForClockLow_ret
  ; time's up, line still high, leave skipping mode
  rjmp com2wiEnterStateIdle
com2wiIrqStateSWaitForClockLow_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateIdle
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateIdle:
  ; setup lines (make sure we don't hold the lines low)
  rcall com2wiClkSetHigh                       ; (none)
  rcall com2wiDataSetHigh                      ; (none)

  ; setup state
  clr r16
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_IDLE
  std Y+COM2WI_IFACE_OFFS_STATE, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateWMsgWaitBusFree
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateWMsgWaitBusFree:
  ; setup lines (make sure we don't hold the lines low)
  rcall com2wiClkSetHigh                       ; (none)
  rcall com2wiDataSetHigh                      ; (none)

  ; setup state
  ldi r16, COM2WI_W_MAX_WAIT_BUSFREE
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_W_MSGWAITBUSFREE
  std Y+COM2WI_IFACE_OFFS_STATE, r16

  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateWByteHoldClockLow
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateWByteHoldClockLow:
  ; setup line
  rcall com2wiClkSetLow                          ; (none)

  ; setup state
  ldi r16, COM2WI_STATETIMER_W_BYTEHOLDCLOCKLOW
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_W_BYTEHOLDCLOCKLOW
  std Y+COM2WI_IFACE_OFFS_STATE, r16

  ; setup current byte
  push xl
    push xh
      ldd xl, Y+COM2WI_IFACE_OFFS_BUFPOS_LOW
      ldd xh, Y+COM2WI_IFACE_OFFS_BUFPOS_HIGH
      ld r16, X+
      std Y+COM2WI_IFACE_OFFS_BUFPOS_LOW, xl
      std Y+COM2WI_IFACE_OFFS_BUFPOS_HIGH, xh
    pop xh
  pop xl
  std Y+COM2WI_IFACE_OFFS_CURRBYTE, r16
  clr r16
  std Y+COM2WI_IFACE_OFFS_BITCOUNTER, r16
  ldd r16, Y+COM2WI_IFACE_OFFS_BUFLEFT
  dec r16
  std Y+COM2WI_IFACE_OFFS_BUFLEFT, r16

  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateWBitHoldClockLow
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateWBitHoldClockLow:
  ; setup line
  rcall com2wiClkSetLow                          ; (none)

  ; setup state
  ldi r16, COM2WI_STATETIMER_W_BITHOLDCLOCKLOW
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_W_BITHOLDCLOCKLOW
  std Y+COM2WI_IFACE_OFFS_STATE, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateWBitSetData
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateWBitSetData:
  ; setup state
  ldi r16, COM2WI_STATETIMER_W_BITSETDATA
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_W_BITSETDATA
  std Y+COM2WI_IFACE_OFFS_STATE, r16

  ; setup line
  ldd r16, Y+COM2WI_IFACE_OFFS_BITCOUNTER
  inc r16
  std Y+COM2WI_IFACE_OFFS_BITCOUNTER, r16
  ldd r16, Y+COM2WI_IFACE_OFFS_CURRBYTE
  lsr r16
  std Y+COM2WI_IFACE_OFFS_CURRBYTE, r16
  brcc com2wiEnterStateWBitSetData_set0
  rcall com2wiDataSetHigh
  ret
com2wiEnterStateWBitSetData_set0:
  rcall com2wiDataSetLow
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateWBitHoldClockHigh
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateWBitHoldClockHigh:
  ; setup line
  rcall com2wiClkSetHigh                          ; (none)

  ; setup state
  ldi r16, COM2WI_STATETIMER_W_BITHOLDCLOCKHIGH
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_W_BITHOLDCLOCKHIGH
  std Y+COM2WI_IFACE_OFFS_STATE, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateWMsgSent
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateWMsgSent:
  ; setup lines
  rcall com2wiClkSetHigh                       ; (none)
  rcall com2wiDataSetHigh                      ; (none)
  ; setup state
  clr r16                                      ; wait indefinately
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_W_MSGSENT
  std Y+COM2WI_IFACE_OFFS_STATE, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateRWaitForClockHigh
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateRWaitForClockHigh:
  ldi r16, COM2WI_STATETIMER_R_WAITFORCLOCKHIGH
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_R_WAITFORCLOCKHIGH
  std Y+COM2WI_IFACE_OFFS_STATE, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateRWaitForClockLow
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateRWaitForClockLow:
  ldi r16, COM2WI_STATETIMER_R_WAITFORCLOCKLOW
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_R_WAITFORCLOCKLOW
  std Y+COM2WI_IFACE_OFFS_STATE, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateSWaitForClockHigh
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateSWaitForClockHigh:
  clr r16
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_S_WAITFORCLOCKHIGH
  std Y+COM2WI_IFACE_OFFS_STATE, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wiEnterStateSWaitForClockLow
;
; @param Y pointer to interface data in SRAM
; @clobbers r16

com2wiEnterStateSWaitForClockLow:
  ldi r16, COM2WI_STATETIMER_S_WAITFORCLOCKLOW
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_S_WAITFORCLOCKLOW
  std Y+COM2WI_IFACE_OFFS_STATE, r16
  ret
; @end



com2wiEnterStateRMsgRecvd:
  ; setup state
  clr r16                                      ; wait indefinately
  std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
  ldi r16, COM2WI_STATE_R_MSGRECVD
  std Y+COM2WI_IFACE_OFFS_STATE, r16
  ret
; @end







; ---------------------------------------------------------------------------
; @routine com2wiRun
;
; @param Y pointer to interface data in SRAM
; @clobbers 

com2wiRun:
  ldi zl, LOW(com2wiRunJumpTable)
  ldi zh, HIGH(com2wiRunJumpTable)
  ldd r16, Y+COM2WI_IFACE_OFFS_STATE
  cpi r16, COM2WI_STATE_COUNT
  brcc com2wiRun_ret
  add zl, r16
  adc zh, r16
  sub zh, r16
  ijmp
com2wiRun_ret:
  ret
com2wiRunJumpTable:
  rjmp com2wiRunStateIdle              ;  0: COM2WI_STATE_IDLE
  ret                                  ;  1: COM2WI_STATE_W_MSGWAITBUSFREE
  ret                                  ;  2: COM2WI_STATE_W_BYTEHOLDCLOCKLOW
  ret                                  ;  3: COM2WI_STATE_W_BITHOLDCLOCKLOW
  ret                                  ;  4: COM2WI_STATE_W_BITSETDATA
  ret                                  ;  5: COM2WI_STATE_W_BITHOLDCLOCKHIGH
  rjmp com2wiRunStateWMsgSent          ;  6: COM2WI_STATE_W_MSGSENT
  ret                                  ;  7: COM2WI_STATE_R_WAITFORCLOCKHI
  ret                                  ;  8: COM2WI_STATE_R_WAITFORCLOCKLO
  rjmp com2wiRunStateRMsgRecvd         ;  9: COM2WI_STATE_R_MSGRECVD
  ret                                  ; 10: COM2WI_STATE_S_WAITFORCLOCKLO
  ret                                  ; 11: COM2WI_STATE_S_WAITFORCLOCKHI
; @end



com2wiRunStateIdle:
  ; look for outbound message
  rcall NET_Interface_PeekNextOutgoingMsgNum ; r16=msgNum
  brcc com2wiRunStateIdle_ret
  push r15
    in r15, SREG
    cli
    rcall NET_Buffer_Locate                    ; (R17)
    adiw xh:xl, 1
    std Y+COM2WI_IFACE_OFFS_BUFPOS_LOW, xl
    std Y+COM2WI_IFACE_OFFS_BUFPOS_HIGH, xh
    adiw xh:xl, NETMSG_OFFS_MSGLEN
    ld r16, X
    subi r16, -3
    std Y+COM2WI_IFACE_OFFS_BUFUSED, r16
    std Y+COM2WI_IFACE_OFFS_BUFLEFT, r16
    rcall com2wiEnterStateWMsgWaitBusFree     ; (R16)
    out SREG, r15
  pop r15
com2wiRunStateIdle_ret:
  clc                                       ; no need to re-run in this loop
  ret
; @end



com2wiRunStateWMsgSent:
  rcall NET_Interface_GetNextOutgoingMsgNum  ; take current msg off the queue
  brcc com2wiRunStateWMsgSent_ret
  rcall NET_Buffer_ReleaseByNum              ; (R16, X)
  push r15
    in r15, SREG
    cli
    rcall com2wiEnterStateIdle
    out SREG, r15
  pop r15
  ldi r16, NET_IFACE_OFFS_PACKETSOUT_LOW
  push r24
    push r25
      rcall NET_Interface_IncCounter16
    pop r25
  pop r24
#ifdef LED1_NETWORK_ACTIVITY
  bigcall LED1_SetActivityTiming  ; (r18-r20)
#endif
  sec                                        ; did something
com2wiRunStateWMsgSent_ret:
  ret
; @end



com2wiRunStateRMsgRecvd:
  mov xl, yl
  mov xh, yh
  adiw xh:xl, COM2WI_IFACE_OFFS_BUFFER
  rcall NETMSG_CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X)
  brcc com2wiRunStateRMsgRecvd_crcError
#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 com2wiRunStateRMsgRecvd_forMe
  ldd r17, Y+NET_IFACE_OFFS_ADDRESS
  cp r16, r17
  breq com2wiRunStateRMsgRecvd_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 com2wiRunStateRMsgRecvd_goIdle
com2wiRunStateRMsgRecvd_forMe:
#endif

  ; msg received, alloc buffer for it
  rcall NET_Buffer_Alloc                          ; R16=buffer num (R16, R17, X)
  brcc com2wiRunStateRMsgRecvd_noBuf

  ; set interface number in msg header
  mov r19, r16                               ; save buffer num
  rcall NET_Interface_SetIfaceNumInBuffer    ; (R16, R17)
  mov r16, r19                               ; restore buffer num
  ; copy into allocated buffer
  push zl
    push zh
      mov zl, yl
      mov zh, yh
      adiw zh:zl, COM2WI_IFACE_OFFS_BUFFER   ; Z=SRC
      adiw xh:xl, 1                          ; X=DEST
      ldd r18, Z+NETMSG_OFFS_MSGLEN
      inc r18
      inc r18
      inc r18
com2wiRunStateRMsgRecvd_copyLoop:
        ld r17, Z+
        st X+, r17
        dec r18
      brne com2wiRunStateRMsgRecvd_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  ; (r18-r20)
#endif
  ; fall-through to enter idle state
com2wiRunStateRMsgRecvd_goIdle:
  push r15
    in r15, SREG
    cli
    rcall com2wiEnterStateIdle
    out SREG, r15
  pop r15
  sec
  rjmp com2wiRunStateRMsgRecvd_ret
com2wiRunStateRMsgRecvd_noBuf:
  ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
  rcall NET_Interface_IncCounter16                ; (R24, R25)
  rjmp com2wiRunStateRMsgRecvd_goIdle
com2wiRunStateRMsgRecvd_crcError:
  ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
  rcall NET_Interface_IncCounter16                ; (R24, R25)
  rjmp com2wiRunStateRMsgRecvd_goIdle
com2wReceiveNextPkg_eMissed:
  rcall NET_Buffer_ReleaseByNum                   ; (R16, X)
  ldi r16, NET_IFACE_OFFS_ERR_MISSED_LOW
  rcall NET_Interface_IncCounter16                ; (R24, R25)
  rjmp com2wiRunStateRMsgRecvd_goIdle
com2wiRunStateRMsgRecvd_ret:
  ret
; @end




#endif

