; ***************************************************************************
; 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_COMMON_H
#define AVR_MODULES_COM2W_COMMON_H



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

com2wPeriodically:
  push r15
    in r15, SREG
    cli
    rcall NET_Interface_Periodically
    ldd r16, Y+COM2W_IFACE_OFFS_MODECOUNTER
    inc r16
    breq com2wPeriodically_end
    std Y+COM2W_IFACE_OFFS_MODECOUNTER, r16
com2wPeriodically_end:
    out SREG, r15
  pop r15
  ret
; @end





; ---------------------------------------------------------------------------
; @routine com2wSetMode
;
; Doesn't change processor status flags!
;
; @param R16 mode
; @clobbers R17

com2wSetMode:
  push r15
    in r15, SREG
    cli
    ldd r17, Y+COM2W_IFACE_OFFS_MODE
    cp r16, r17
    breq com2wSetMode_end
    std Y+COM2W_IFACE_OFFS_MODE, r16
    clr r17
    std Y+COM2W_IFACE_OFFS_MODECOUNTER, r17
com2wSetMode_end:
    out SREG, r15
  pop r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wStartReading
;
; @param Y pointer to interface data in SRAM
; @clobbers R16, R17, X

com2wStartReading:
  mov xl, yl
  mov xh, yh
  adiw xh:xl, COM2W_IFACE_OFFS_BUFFER
  std Y+COM2W_IFACE_OFFS_BUFPOS_LOW, xl
  std Y+COM2W_IFACE_OFFS_BUFPOS_HIGH, xh
  ldi r16, COM2W_BUFFER_SIZE
  std Y+COM2W_IFACE_OFFS_BUFLEFT, r16
  clr r16
  std Y+COM2W_IFACE_OFFS_BUFUSED, r16
  ldi r16, COM2W_MODE_READING
  rcall com2wSetMode                      ; (R17)
  ret
; @end



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

com2wByteRecvd:
  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 com2wByteRecvd_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 com2wByteRecvd_msgComplete
  cpi r18, 2
  sec
  brne com2wByteRecvd_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 com2wByteRecvd_eMsgSize
  std Y+COM2W_IFACE_OFFS_BUFLEFT, r16
  tst r16
  sec
  brne com2wByteRecvd_end
com2wByteRecvd_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 com2wMsgReceived            ; (R16, R17, R18, R19, R20, R24, R25, X, Z)
            pop zh
          pop zl
        pop r25
      pop r24
    pop r20
  pop r19
  rjmp com2wByteRecvd_end
com2wByteRecvd_overflow:
  ldi r16, NET_IFACE_OFFS_ERR_MISSED_LOW
  rjmp com2wByteRecvd_error
com2wByteRecvd_eMsgSize:

  ldi r16, NET_IFACE_OFFS_ERR_MSGSIZE_LOW
com2wByteRecvd_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
com2wByteRecvd_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2wMsgReceived
;
; @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)

com2wMsgReceived:
  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 com2wMsgReceived_econtent
  ; msg valid, alloc buffer
  rcall NET_Buffer_Alloc                     ; X=buffer, R16=bufnum (R16, R17, X)
  brcc com2wMsgReceived_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
com2wMsgReceived_copyLoop:
    ld r16, Z+
    st X+, r16
    dec r17
  brne com2wMsgReceived_copyLoop
  mov r16, r18                               ; buffer num
  rcall NET_AddIncomingMsgNum                ; (R17, R18, X)
  brcc com2wMsgReceived_enoadd
  ldi r16, NET_IFACE_OFFS_PACKETSIN_LOW
  rcall NET_Interface_IncCounter16           ; (R24, R25)
  sec
  rjmp com2wMsgReceived_setIdleAndEnd
com2wMsgReceived_enoadd:
  rcall NET_Buffer_ReleaseByNum
  rjmp com2wMsgReceived_enobuf
com2wMsgReceived_enobuf:
  ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
  rjmp com2wMsgReceived_err
com2wMsgReceived_econtent:
  ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
com2wMsgReceived_err:
  rcall NET_Interface_IncCounter16           ; (R24, R25)
  clc
com2wMsgReceived_setIdleAndEnd:
  ldi r16, COM2W_MODE_IDLE
  rcall com2wSetMode                         ; (R17, doesn't change CFLAG!)
com2wMsgReceived_end:
  ret
; @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




#endif ; AVR_MODULES_COM2W_COMMON_H

