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



; ***************************************************************************
; defines

; ---------------------------------------------------------------------------
; network interfaces

.equ NETDEV0_IFACENUM = 1
.equ NETDEV1_IFACENUM = 2



; ***************************************************************************
; data

.dseg

; nothing so far



; ***************************************************************************
; code

.cseg

; ---------------------------------------------------------------------------
; @routine AppForwarder_Init @global

AppForwarder_Init:
  ; set interface number for NETDEV0
  ldi r16, NETDEV0_IFACENUM
  sts netInterfaceData+NET_IFACE_OFFS_IFACENUM, r16
  ; set interface number for NETDEV1
  ldi r16, NETDEV1_IFACENUM
  sts netInterfaceData2+NET_IFACE_OFFS_IFACENUM, r16
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine AppForwarder_EveryDay @global
;
; @clobbers R16, R17, X

AppForwarder_EveryDay:
  ldi yl, LOW(netInterfaceData)
  ldi yh, HIGH(netInterfaceData)
  bigcall NET_Interface_ResetStats ; (R16, R17, X)

  ldi yl, LOW(netInterfaceData2)
  ldi yh, HIGH(netInterfaceData2)
  bigcall NET_Interface_ResetStats ; (R16, R17, X)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine AppForwarder_Run @global
;
; Read messages from either interface and forward to the other one.

AppForwarder_Run:
  rjmp appForwarderCheckRecvdMsg
; @end



; ---------------------------------------------------------------------------
; @routine appForwarderCheckRecvdMsg
;
; Read messages from either interface and forward to the other one.
; @return CFLAG set if something done, cleared otherwise
; @clobbers any

appForwarderCheckRecvdMsg:
  rcall NET_PeekNextIncomingMsgNum             ; check read queue (bufNum->r16)
  brcc appForwarderCheckRecvdMsg_ret           ; no msg, jmp
  rcall NET_Buffer_Locate                      ; (R17)
  push r16
    ld r16, X                                  ; read buffer header
    andi r16, 0x0f                             ; keep interface number (in low nibble)
    rcall appForwarderGetDeviceByIfaceNum      ; Y=src interface (R17)
  pop r16
  brcc appForwarderCheckRecvdMsg_ret           ; interface not found
  adiw xh:xl, 1                                ; point to message begin

  push r16
    rcall appForwarderHandleMsgAnyDev          ; check for message we should handle (ping etc)
  pop r16

  ; let system handle incoming messages
  push r16
    rcall appForwarderLetSysHandleMsg
  pop r16

  ; forward to other interface
  ldd r17, Y+NET_IFACE_OFFS_IFACENUM
  rcall appForwarderSendToOtherDev
  brcc appForwarderCheckRecvdMsg_ret           ; could not add, jmp
  rcall NET_GetNextIncomingMsgNum              ; take off the queue
  sec
appForwarderCheckRecvdMsg_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine appForwarderHandleMsgAnyDev @global
;
; @param Y pointer to source interface for the message
; @param X pointer to received message
; @return CFLAG set if msg handled, cleared otherwise
; @clobbers any, !X

appForwarderHandleMsgAnyDev:
  push xl
    push xh
      rcall appForwarderHandleMsgAnyDev_savedX
    pop xh
  pop xl
  rjmp appForwarderHandleMsgAnyDev_end
appForwarderHandleMsgAnyDev_savedX:
  adiw xh:xl, NETMSG_OFFS_CMD                       ; maybe move ping/reboot handling to all/main.asm?
  ld r16, X
  sbiw xh:xl, NETMSG_OFFS_CMD
  cpi r16, NETMSG_CMD_REBOOT_REQUEST
  breq appForwarderHandleMsgAnyDev_handleRebootMsg
  cpi r16, NETMSG_CMD_PING
  breq appForwarderHandleMsgAnyDev_handlePingMsg
  cpi r16, NETMSG_CMD_CLAIM_ADDRESS
  breq appForwarderHandleMsgAnyDev_handleClaimAddr
  rjmp appForwarderHandleMsgAnyDev_clcRet
appForwarderHandleMsgAnyDev_handleRebootMsg:
  rcall appForwarderHandleRebootRequest
  ret
appForwarderHandleMsgAnyDev_handlePingMsg:
  rcall appForwarderHandlePingRequest
  clc
  ret
appForwarderHandleMsgAnyDev_handleClaimAddr:
  rcall appForwarderHandleClaimAddrRequest
  clc
  ret
appForwarderHandleMsgAnyDev_clcRet:
  clc
appForwarderHandleMsgAnyDev_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine appForwarderHandleClaimAddrRequest
;
; @param X pointer to received message
; @param Y pointer to source interface for the message
; @clobbers

appForwarderHandleClaimAddrRequest:
  rcall NETMSG_Address_Read                        ; R18=cmd, R19=addr(R18, R19)
  lds r16, netInterfaceData+NET_IFACE_OFFS_ADDRESS
  cp r19, r16
  brne appForwarderHandleClaimAddrRequest_ret
  ldi r18, NETMSG_CMD_DENY_ADDRESS                 ; deny addr
  rcall appForwarderSendAddrMsg                    ; (R16, R17, R18, R19, R20, R21, X, Y)
appForwarderHandleClaimAddrRequest_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine appForwarderSendAddrMsg
;
; @param R18 command
; @param R19 address to send
; @param Y pointer to interface to send to
; @clobbers R16 (R17, R18, R19, R20, R21, X, Y)

appForwarderSendAddrMsg:
  bigcall NET_Buffer_Alloc                 ; (R16, R17, X)
  brcc appForwarderSendAddrMsg_end
  push r16
    adiw xh:xl, 1
    bigcall NETMSG_Address_Write           ; (R16, R17, R18, R19, R20, R21)
    sbiw xh:xl, 1
  pop r16
  bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
appForwarderSendAddrMsg_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine appForwarderHandleRebootRequest
;
; Doesn't return if reboot msg is valid.
;
; @param X pointer to received message

appForwarderHandleRebootRequest:
  rcall NETMSG_RebootRequestRead
  brcc appForwarderHandleRebootRequest_end
  ; reboot
  cli
  bigjmp BOOTLOADER_ADDR
appForwarderHandleRebootRequest_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine appForwarderHandlePingRequest
;
; @param X pointer to received message
; @param Y pointer to source interface for the message

appForwarderHandlePingRequest:
  ld r17, X
  lds r16, (netInterfaceData+NET_IFACE_OFFS_ADDRESS)
  cp r16, r17
  breq appForwarderHandlePingRequest_forMe
  cpi r17, 0xff
  breq appForwarderHandlePingRequest_forMe
  clc
  rjmp appForwarderHandlePingRequest_end
appForwarderHandlePingRequest_forMe:
  adiw xh:xl, NETMSG_OFFS_SRCADDR
  ld r17, X
  sbiw xh:xl, NETMSG_OFFS_SRCADDR
  push r17
    bigcall NET_Buffer_Alloc               ; (R16, R17, X)
  pop r17
  brcc appForwarderHandlePingRequest_end   ; jmp on error
  push r16                                 ; buffer num
    mov r16, r17                           ; DEST addr
    adiw xh:xl, 1
    bigcall NETMSG_Pong_Write              ; (R16, R17, R18, R19, R20, X)
    sbiw xh:xl, 1
  pop r16                                  ; buffer num
  bigcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X)
appForwarderHandlePingRequest_end:
  ret





; ---------------------------------------------------------------------------
; @routine appForwarderLetSysHandleMsg
;
; @param X pointer to msg to handle (point behind the buffer header!)
; @param Y pointer to source interface for the message
; @clobbers any, !X

appForwarderLetSysHandleMsg:
  ld r16, X
  cpi r16, 0xff
  breq appForwarderLetSysHandleMsg_forMe
  lds r17, netInterfaceData+NET_IFACE_OFFS_ADDRESS
  cp r16, r17
  brne appForwarderLetSysHandleMsg_end
appForwarderLetSysHandleMsg_forMe:
  push xl
    push xh
      rcall onMessageReceived
    pop xh
  pop xl
  push xl
    push xh
      rcall modulesOnPacketReceived
    pop xh
  pop xl
  push xl
    push xh
      rcall appsOnPacketReceived
    pop xh
  pop xl
appForwarderLetSysHandleMsg_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine appForwarderSendToOtherDev
; @param r16 buffer num
; @param r17 src interface num

appForwarderSendToOtherDev:
  ldi yl, LOW(netInterfaceData)
  ldi yh, HIGH(netInterfaceData)
  ldd r18, Y+NET_IFACE_OFFS_IFACENUM
  andi r18, 0x0f
  cp r18, r17
  breq appForwarderSendToAllDevsBut_check2
  bigcall NET_Interface_AddOutgoingMsgNum  ; (R17, R18, X)
  rjmp appForwarderSendToOtherDev_ret
appForwarderSendToAllDevsBut_check2:
  ldi yl, LOW(netInterfaceData2)
  ldi yh, HIGH(netInterfaceData2)
  ldd r18, Y+NET_IFACE_OFFS_IFACENUM
  andi r18, 0x0f
  cp r18, r17
  breq appForwarderSendToOtherDev_ret
  bigcall NET_Interface_AddOutgoingMsgNum  ; (R17, R18, X)
appForwarderSendToOtherDev_ret:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine appForwarderGetDeviceByIfaceNum
;
; @param r16 interface number
; @return CFLAG set if interface found (cleared otherwise)
; @return Y pointer to interface with given number
; @clobbers r17

appForwarderGetDeviceByIfaceNum:
  ldi yl, LOW(netInterfaceData)
  ldi yh, HIGH(netInterfaceData)
  ldd r17, Y+NET_IFACE_OFFS_IFACENUM
  cp r16, r17
  breq appForwarderGetDeviceByIfaceNum_secRet
  ldi yl, LOW(netInterfaceData2)
  ldi yh, HIGH(netInterfaceData2)
  ldd r17, Y+NET_IFACE_OFFS_IFACENUM
  cp r16, r17
  breq appForwarderGetDeviceByIfaceNum_secRet
  clc
  rjmp appForwarderGetDeviceByIfaceNum_ret
appForwarderGetDeviceByIfaceNum_secRet:
  sec
appForwarderGetDeviceByIfaceNum_ret:
  ret
; @end




