; ***************************************************************************
; 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_COM2WN_RECV_H
#define AVR_MODULES_COM2W_COM2WN_RECV_H


; WORK IN PROGRESS



.cseg




; ---------------------------------------------------------------------------
; @routine com2wnActOnClock @global
;
; @param r16 CLK input (0 or !=0)
; @param r17 DATA input (0 or !=0)
; @param Y   pointer to IFACE data
; @clobbers r16 (r17, r18, X)

com2wnActOnClock:
  tst r16
  brne com2wnActOnClock_clockHigh
  ; clock low
  ldd r18, Y+COM2W_IFACE_OFFS_MODE
  cpi r18, COM2W_MODE_IDLE
  breq com2wnActOnClock_startReading
  cpi r18, COM2W_MODE_SKIPPING
  breq com2wnActOnClock_skipping
  rjmp com2wnActOnClock_end
com2wnActOnClock_skipping:
;  ldd r18, Y+COM2W_IFACE_OFFS_MODECOUNTER
;  cpi r18, COM2W_SKIPPING_MAXMODECOUNTER
;  brcc com2wnActOnClock_startReading
  rjmp com2wnActOnClock_end
com2wnActOnClock_startReading:
  rcall com2wnStartReading               ; (r16, r17, X)
  rjmp com2wnActOnClock_end
com2wnActOnClock_clockHigh:
  ldd r18, Y+COM2W_IFACE_OFFS_MODE
  cpi r18, COM2W_MODE_READING
  brne com2wnActOnClock_end

  push r20
    push r22
      rcall com2wnReadNextBit            ; (r16, r17, r18, r20, r22)
    pop r22
  pop r20

com2wnActOnClock_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wnReadNextBit @global
;
; @param r17 DATA input (0 or !=0)
; @clobbers r16, r17, r18, r20, r22

com2wnReadNextBit:
;  ldi r20, 50                           ; wait for up to 250us for clock rise
;  rcall com2w0WaitForClockHighMulti5Us  ; (R20, R22)
;  brcc com2wnReadNextBit_end
  ; clock is high now, read bit
  ; reset read timer (for leaving skipping mode)
  clr r16
  std Y+NET_IFACE_OFFS_READTIMER, r16
  ; check mode
  ldd r16, Y+COM2W_IFACE_OFFS_MODE
  cpi r16, COM2W_MODE_READING
  brne com2wnReadNextBit_end
  ; handle received bit
  ldd r16, Y+COM2W_IFACE_OFFS_CURRBYTE
  ldd r18, Y+COM2W_IFACE_OFFS_BITCOUNTER
  tst r17                                ; data port input
  clc
  breq com2wnReadNextBit_clockData
  sec
com2wnReadNextBit_clockData:
  ror r16
  std Y+COM2W_IFACE_OFFS_CURRBYTE, r16
  inc r18                                ; bit counter
  std Y+COM2W_IFACE_OFFS_BITCOUNTER, r18
  cpi r18, 8
  brne com2wnReadNextBit_end
  ; write byte into buffer
  push xl
    push xh
      rcall com2wnByteRecvd               ; (r16, r17, r18, X)
    pop xh
  pop xl
  ; prepare for next byte
  clr r16
  std Y+COM2W_IFACE_OFFS_BITCOUNTER, r16
  std Y+COM2W_IFACE_OFFS_CURRBYTE, r16
com2wnReadNextBit_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wnByteRecvd
;
; @param r16 byte received
; @param Y   pointer to interface data
; @return CFLAG set if okay, cleared on error
; @clobbers r16, r17, r18, X

com2wnByteRecvd:
#ifdef LED1_NETWORK_ACTIVITY
  push r16
    bigcall LED1_SetActivityTiming  ; (r18-r20)
  pop r16
#endif
  ldd xl, Y+COM2W_IFACE_OFFS_BUFPOS_LOW
  ldd xh, Y+COM2W_IFACE_OFFS_BUFPOS_HIGH
  ldd r17, Y+COM2W_IFACE_OFFS_BUFLEFT
  ldd r18, Y+COM2W_IFACE_OFFS_BUFUSED
  tst r17
  breq com2wnByteRecvd_overflow
  st X+, r16
  std Y+COM2W_IFACE_OFFS_BUFPOS_LOW, xl
  std Y+COM2W_IFACE_OFFS_BUFPOS_HIGH, xh
  inc r18
  std Y+COM2W_IFACE_OFFS_BUFUSED, r18
  dec r17
  std Y+COM2W_IFACE_OFFS_BUFLEFT, r17
  breq com2wnByteRecvd_msgComplete
  cpi r18, 2
  sec
  brne com2wnByteRecvd_end

  ; determine msg size
  inc r16                                       ; last byte was payload length, add byte for crc
  cp r17, r16                                   ; compare remaining length against remaining space
  brcs com2wnByteRecvd_eMsgSize
  std Y+COM2W_IFACE_OFFS_BUFLEFT, r16
  tst r16
  sec
  brne com2wnByteRecvd_end
com2wnByteRecvd_msgComplete:
  push r19                                      ; pushing these registers is now only needed *here* for every
    push r20                                    ; message received. Otherwise they would have been pushed
      push r24                                  ; on every bit adding much more execution time to the
        push r25                                ; irq service routine
          push zl
            push zh
              rcall com2wnMsgReceived            ; (R16, R17, R18, R19, R20, R24, R25, X, Z)
            pop zh
          pop zl
        pop r25
      pop r24
    pop r20
  pop r19
  rjmp com2wnByteRecvd_end
com2wnByteRecvd_overflow:
  ldi r16, NET_IFACE_OFFS_ERR_MISSED_LOW
  rjmp com2wnByteRecvd_error
com2wnByteRecvd_eMsgSize:
  ldi r16, NET_IFACE_OFFS_ERR_MSGSIZE_LOW
com2wnByteRecvd_error:
  push r24
    push r25
      rcall NET_Interface_IncCounter16          ; (R24, R25)
    pop r25
  pop r24
  ldi r16, COM2W_MODE_SKIPPING                  ; error, enter skipping mode
  rcall com2wSetMode
  clc
com2wnByteRecvd_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wnMsgReceived
;
; @param Y pointer to interface data in SRAM
; @return CFLAG set if okay, cleared on error
; @clobbers R16, R17, R18, X, Z (R19, R20, R24, R25)

com2wnMsgReceived:
  mov xl, yl
  mov xh, yh
  adiw xh:xl, COM2W_IFACE_OFFS_BUFFER
  mov zl, xl                                 ; Z=buffer in IFACE
  mov zh, xh
  rcall NETMSG_CheckMessageInBuffer          ; (R16, R17, R18, R19, R20, X)
  brcc com2wnMsgReceived_econtent
  ; msg valid, alloc buffer
  rcall NET_Buffer_Alloc                     ; X=buffer, R16=bufnum (R16, R17, X)
  brcc com2wnMsgReceived_enobuf
  mov r18, r16                               ; buffer num
  rcall NET_Interface_SetIfaceNumInBuffer    ; (R16, R17)
  adiw xh:xl, 1                              ; skip buffer header
  ldd r17, Y+COM2W_IFACE_OFFS_BUFUSED        ; always is at least 2 here
com2wnMsgReceived_copyLoop:
    ld r16, Z+
    st X+, r16
    dec r17
  brne com2wnMsgReceived_copyLoop
  mov r16, r18                               ; buffer num
  rcall NET_AddIncomingMsgNum                ; (R17, R18, X)
  brcc com2wnMsgReceived_enoadd
  ldi r16, NET_IFACE_OFFS_PACKETSIN_LOW
  rcall NET_Interface_IncCounter16           ; (R24, R25)
  sec
  rjmp com2wnMsgReceived_setIdleAndEnd
com2wnMsgReceived_enoadd:
  rcall NET_Buffer_ReleaseByNum
  rjmp com2wnMsgReceived_enobuf
com2wnMsgReceived_enobuf:
  ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
  rjmp com2wnMsgReceived_err
com2wnMsgReceived_econtent:
  ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
com2wnMsgReceived_err:
  rcall NET_Interface_IncCounter16           ; (R24, R25)
  clc
com2wnMsgReceived_setIdleAndEnd:
  ldi r16, COM2W_MODE_IDLE
  rcall com2wSetMode                         ; (R17, doesn't change CFLAG!)
com2wnMsgReceived_end:
  ret
; @end





#endif ; AVR_MODULES_COM2W_COM2WN_RECV_H

