Files
aqhomecontrol/avr/apps/router/main.asm
2025-07-19 17:07:52 +02:00

580 lines
16 KiB
NASM

; ***************************************************************************
; 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
appRouterDataBegin:
appRouterRangeBegin: .byte 1
appRouterRangeEnd: .byte 1
appRouterDataEnd:
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine AppRouter_Init @global
AppRouter_Init:
ldi xh, HIGH(appRouterDataBegin)
ldi xl, LOW(appRouterDataBegin)
clr r16
ldi r17, (appRouterDataEnd-appRouterDataBegin)
rcall Utils_FillSram
#ifndef APP_ROUTER_NO_ADDR_MGR
ldi r16, 0xe0 ; default range from 0xe0-0xef (will be changed later)
sts netInterfaceData+NET_IFACE_OFFS_ADDRESS, r16 ; use first address for router itself
sts netInterfaceData2+NET_IFACE_OFFS_ADDRESS, r16 ; use same address for both interfaces to save on addresses
inc r16
sts appRouterRangeBegin, r16 ; range from router+1
ldi r16, 0xef
sts appRouterRangeEnd, r16
rcall appRouterReadConfFromEeprom ; try to read config from EEPROM
#endif
; 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
#ifndef APP_ROUTER_NO_ADDR_MGR
ldi r18, NETMSG_CMD_ADDRESS_RANGE
rcall appRouterSendRangeMsgToDev1
#endif
ret
; @end
; ---------------------------------------------------------------------------
; @routine AppRouter_EveryDay @global
;
; @clobbers R16, R17, X
AppRouter_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 AppRouter_Run @global
;
; Read messages from either interface and forward to the other one.
AppRouter_Run:
rjmp appRouterCheckRecvdMsg
; @end
; ---------------------------------------------------------------------------
; @routine appRouterHandleMsgAnyDev @global
;
; @param X pointer to received message
; @return CFLAG set if msg handled, cleared otherwise
; @clobbers any, !X
appRouterHandleMsgAnyDev:
push xl
push xh
rcall appRouterHandleMsgAnyDev_savedX
pop xh
pop xl
rjmp appRouterHandleMsgAnyDev_end
appRouterHandleMsgAnyDev_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 appRouterHandleMsgAnyDev_handleRebootMsg
cpi r16, NETMSG_CMD_PING
breq appRouterHandleMsgAnyDev_handlePingMsg
cpi r16, NETMSG_CMD_VALUE_SET
breq appRouterHandleMsgAnyDev_handleSetValue
rjmp appRouterHandleMsgAnyDev_clcRet
appRouterHandleMsgAnyDev_handleRebootMsg:
rcall appRouterHandleRebootRequest
ret
appRouterHandleMsgAnyDev_handlePingMsg:
rcall appRouterHandlePingRequest
clc
ret
appRouterHandleMsgAnyDev_handleSetValue:
rcall NETMSG_ValueRead ; (none)
cpi r17, VALUE_ID_ROUTER_SETRANGE
breq appRouterHandleMsgAnyDev_handleSetRange
rjmp appRouterHandleMsgAnyDev_clcRet
appRouterHandleMsgAnyDev_handleSetRange:
#ifndef APP_ROUTER_NO_ADDR_MGR
sts netInterfaceData+NET_IFACE_OFFS_ADDRESS, r18 ; use first address for router itself
sts netInterfaceData2+NET_IFACE_OFFS_ADDRESS, r18 ; use same address for both interfaces to save on addresses
inc r18 ; start range after router
sts appRouterRangeBegin, r18
sts appRouterRangeEnd, r19
; send ACK
ldi r23, NETMSG_CMD_VALUE_SET_ACK
rcall Main_SendValueResponse ; (clobbers all, including Y)
; let subnodes re-eunumerate
ldi r18, NETMSG_CMD_REENUM
rcall appRouterSendRangeMsgToDev1 ; (R16, R17, R18, R19, R20, R21, X, Y)
rcall appRouterWriteConfToEeprom ; (r16, r17, X)
#endif
sec
ret
appRouterHandleMsgAnyDev_clcRet:
clc
appRouterHandleMsgAnyDev_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterHandleDev1Msg @global
;
; Handle messages from controlled subnet.
;
; @param X pointer to received message
; @return CFLAG set if msg handled, cleared otherwise
; @clobbers any, !X
appRouterHandleDev1Msg:
#ifndef APP_ROUTER_NO_ADDR_MGR
push xl
push xh
rcall appRouterHandleDev1Msg_savedX
pop xh
pop xl
rjmp appRouterHandleDev1Msg_end
appRouterHandleDev1Msg_savedX:
adiw xh:xl, NETMSG_OFFS_CMD
ld r16, X
sbiw xh:xl, NETMSG_OFFS_CMD
cpi r16, NETMSG_CMD_NEED_ADDRESS
breq appRouterHandleDev1Msg_handleNeedAddr
cpi r16, NETMSG_CMD_CLAIM_ADDRESS
breq appRouterHandleDev1Msg_handleClaimAddr
; add more here
ldi r16, 0
rjmp appRouterHandleDev1Msg_clcRet
appRouterHandleDev1Msg_handleNeedAddr:
ldi r18, NETMSG_CMD_ADDRESS_RANGE
rcall appRouterSendRangeMsgToDev1 ; (R16, R17, R18, R19, R20, R21, X, Y)
sec
rjmp appRouterHandleDev1Msg_end
appRouterHandleDev1Msg_handleClaimAddr:
rcall NETMSG_Address_Read ; R18=cmd, R19=addr(R18, R19)
rcall appRouterIsR19InRange
brcs appRouterHandleDev1Msg_end
; is not in subnet range, deny
rcall appRouterSendDenyAddrR19ToDev1 ; (R16, R17, R18, R19, R20, R21, X, Y)
sec
rjmp appRouterHandleDev1Msg_end
#endif
appRouterHandleDev1Msg_clcRet:
clc
appRouterHandleDev1Msg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterIsR19InRange
;
; @param R19 address to check against range
; @clobbers R16
appRouterIsR19InRange:
lds r16, appRouterRangeBegin
cp r19, r16
brcs appRouterIsR19InRangeClcRet
lds r16, appRouterRangeEnd
cp r16, r19
brcs appRouterIsR19InRangeClcRet
sec
rjmp appRouterIsR19InRange_end
appRouterIsR19InRangeClcRet:
clc
appRouterIsR19InRange_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterSendDenyAddrR19ToDev1
;
; @param R19 address to send
; @clobbers R16, R17, R18, R19, R20, R21, X, Y
appRouterSendDenyAddrR19ToDev1:
ldi r18, NETMSG_CMD_DENY_ADDRESS ; deny addr
rjmp appRouterSendAddrMsgToDev1 ; (R16, R17, R18, R19, R20, R21, X, Y)
; @end
; ---------------------------------------------------------------------------
; @routine appRouterSendAddrMsgToDev1
;
; @param R18 command
; @param R19 address to send
; @clobbers R16 (R17, R18, R19, R20, R21, X, Y)
appRouterSendAddrMsgToDev1:
bigcall NET_Buffer_Alloc ; (R16, R17, X)
brcc appRouterSendAddrMsgToDev1_end
push r16
adiw xh:xl, 1
bigcall NETMSG_Address_Write ; (R16, R17, R18, R19, R20, R21)
sbiw xh:xl, 1
pop r16
rcall appRouterSendMsgToDev1 ; (R16, R17, R18, R24, R25, X, Y)
appRouterSendAddrMsgToDev1_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterSendRangeMsgToDev1
;
; @param R18 msg code
; @return CFLAG set if message enqueued, cleared on error
; @clobbers (R16, R17, R18, R19, R20, R21, R24, R25, X, Y)
appRouterSendRangeMsgToDev1:
bigcall NET_Buffer_Alloc ; (R16, R17, X)
brcc appRouterSendRangeMsgToDev1_end
push r16
lds r20, appRouterRangeBegin
lds r21, appRouterRangeEnd
adiw xh:xl, 1
bigcall NETMSG_Range_Write ; (R16, R17, R18, R19, R20, R21)
sbiw xh:xl, 1
pop r16
rcall appRouterSendMsgToDev1 ; (R16, R17, R18, R24, R25, X, Y)
appRouterSendRangeMsgToDev1_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterSendMsgToDev1
;
; @param R16 num of allocated buffer
; @param X msg to send (points to start of allocated buffer, e.g. buffer header)
; @return CFLAG set if message enqueued, cleared on error
; @clobbers Y (R16, R17, R18, R24, R25, X)
appRouterSendMsgToDev1:
ldi yl, LOW(netInterfaceData2)
ldi yh, HIGH(netInterfaceData2)
bigcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X)
brcs appRouterSendMsgToDev1_end
bigcall NET_Buffer_ReleaseByNum ; (R16, X)
ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
rcall NET_Interface_IncCounter16 ; (R24, R25)
clc
appRouterSendMsgToDev1_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterHandleRebootRequest
;
; Doesn't return if reboot msg is valid.
;
; @param X pointer to received message
appRouterHandleRebootRequest:
rcall NETMSG_RebootRequestRead
brcc appRouterHandleRebootRequest_end
; reboot
cli
bigjmp BOOTLOADER_ADDR
appRouterHandleRebootRequest_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterHandlePingRequest
;
; @param X pointer to received message
appRouterHandlePingRequest:
ld r17, X
lds r16, (netInterfaceData+NET_IFACE_OFFS_ADDRESS)
cp r16, r17
breq appRouterHandlePingRequest_forMe
cpi r17, 0xff
breq appRouterHandlePingRequest_forMe
clc
rjmp appRouterHandlePingRequest_end
appRouterHandlePingRequest_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 appRouterHandlePingRequest_end ; jmp on error
push r16 ; buffer num
mov r16, r17 ; DEST addr
adiw xh:xl, 1
ldi yl, LOW(netInterfaceData)
ldi yh, HIGH(netInterfaceData)
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)
appRouterHandlePingRequest_end:
ret
; ---------------------------------------------------------------------------
; @routine appRouterCheckRecvdMsg
;
; Read messages from either interface and forward to the other one.
;
; @return CFLAG set if something done, cleared otherwise
appRouterCheckRecvdMsg:
rcall NET_PeekNextIncomingMsgNum ; check read queue (bufNum->r16)
brcc appRouterCheckRecvdMsg_end ; no msg, jmp
rcall NET_Buffer_Locate ; (R17)
rcall appRouterHandleRouterMsgWithHdr ; filter out router msgs
brcs appRouterCheckRecvdMsg_removeMsg ; handled by router code, don't forward
; let system handle incoming messages
adiw xh:xl, 1
rcall appRouterLetSysHandleMsg
sbiw xh:xl, 1
; forward to other interface
ld r17, X
andi r17, (1<<NET_IFACE_BUFFER_IFACENUM1_BIT) | (1<<NET_IFACE_BUFFER_IFACENUM0_BIT)
rcall appRouterReverseInterfaceNum ; (R16, R17)
rcall appRouterAddMsgToInterface
brcc appRouterCheckRecvdMsg_end ; could not add, jmp
rcall NET_GetNextIncomingMsgNum ; take off the queue
sec
ret
appRouterCheckRecvdMsg_removeMsg:
rcall NET_GetNextIncomingMsgNum ; take off the queue
rcall NET_Buffer_ReleaseByNum ; (R16, X)
sec
appRouterCheckRecvdMsg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterHandleRouterMsgWithHdr
;
; @param X pointer to msg
; @return CFLAG set if msg handled, cleared otherwise
appRouterHandleRouterMsgWithHdr:
ld r17, X
adiw xh:xl, 1
andi r17, (1<<NET_IFACE_BUFFER_IFACENUM1_BIT) | (1<<NET_IFACE_BUFFER_IFACENUM0_BIT)
cpi r17, NETDEV1_IFACENUM
brne appRouterHandleRouterMsgWithHdr_any
#ifndef APP_ROUTER_NO_ADDR_MGR
rcall appRouterHandleDev1Msg ; handle messages from controlled subnet
brcs appRouterHandleRouterMsgWithHdr_msgHandled
#endif
appRouterHandleRouterMsgWithHdr_any:
rcall appRouterHandleMsgAnyDev ; handle any msg
brcs appRouterHandleRouterMsgWithHdr_msgHandled
sbiw xh:xl, 1 ; CFLAG cleared
rjmp appRouterHandleRouterMsgWithHdr_end
appRouterHandleRouterMsgWithHdr_msgHandled:
sbiw xh:xl, 1
sec
appRouterHandleRouterMsgWithHdr_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterLetSysHandleMsg
;
; @param X pointer to msg to handle (point behind the buffer header!)
; @clobbers any, !X
appRouterLetSysHandleMsg:
ld r16, X
cpi r16, 0xff
breq appRouterLetSysHandleMsg_forMe
lds r17, netInterfaceData+NET_IFACE_OFFS_ADDRESS
cp r16, r17
brne appRouterLetSysHandleMsg_end
appRouterLetSysHandleMsg_forMe:
push xl
push xh
rcall onMessageReceived
pop xh
pop xl
push xl
push xh
rcall mainModulesOnPacketReceived
pop xh
pop xl
push xl
push xh
rcall mainAppsOnPacketReceived
pop xh
pop xl
appRouterLetSysHandleMsg_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterReverseInterfaceNum
;
; @param r17 buffer num
; @return r17 reversed interface number
; @clobbers r16, r17
appRouterReverseInterfaceNum:
ldi r16, (1<<NET_IFACE_BUFFER_IFACENUM1_BIT) | (1<<NET_IFACE_BUFFER_IFACENUM0_BIT)
eor r17, r16
and r17, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterAddMsgToInterface
; @param r16 buffer num
; @param r17 interface num
appRouterAddMsgToInterface:
cpi r17, NETDEV0_IFACENUM
brne appRouterAddMsgToInterface_notNetDev0
ldi yl, LOW(netInterfaceData)
ldi yh, HIGH(netInterfaceData)
rjmp NET_Interface_AddOutgoingMsgNum ; try to add msg to interface
appRouterAddMsgToInterface_notNetDev0:
ldi yl, LOW(netInterfaceData2)
ldi yh, HIGH(netInterfaceData2)
rjmp NET_Interface_AddOutgoingMsgNum ; try to add msg to interface
appRouterAddMsgToInterface_end:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterWriteConfToEeprom
;
; @clobbers R16, X (R17)
appRouterWriteConfToEeprom:
; write range begin
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
lds r16, appRouterRangeBegin
rcall Eeprom_WriteByteIfChanged ; (R17)
brcc appRouterWriteConfToEeprom_end
; write range end
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_END)
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_END)
lds r16, appRouterRangeEnd
rcall Eeprom_WriteByteIfChanged ; (R17)
appRouterWriteConfToEeprom_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine appRouterReadConfFromEeprom
;
; @clobbers R16, X (R17)
appRouterReadConfFromEeprom:
; read range begin
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_BEGIN)
rcall Eeprom_ReadByte
brcc appRouterReadConfFromEeprom_end
cpi r16, 0xff
breq appRouterReadConfFromEeprom_okay ; not set, jmp
cpi r16, 2 ; range should at least start at 2 to assign 1 to router
brcs appRouterReadConfFromEeprom_okay
sts appRouterRangeBegin, r16
dec r16
sts netInterfaceData+NET_IFACE_OFFS_ADDRESS, r16 ; use addr rangeBegin-1 for router itself
sts netInterfaceData2+NET_IFACE_OFFS_ADDRESS, r16 ; use same address for both interfaces to save on addresses
; read range end
ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_END)
ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_END)
rcall Eeprom_ReadByte
brcc appRouterReadConfFromEeprom_end
cpi r16, 0xff
breq appRouterReadConfFromEeprom_okay
sts appRouterRangeEnd, r16
appRouterReadConfFromEeprom_okay:
sec
appRouterReadConfFromEeprom_end:
ret
; @end