; *************************************************************************** ; 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 ; *************************************************************************** ; data .dseg appHubDataBegin: appHubRangeBegin: .byte 1 appHubRangeEnd: .byte 1 appHubDataEnd: ; *************************************************************************** ; code .cseg ; --------------------------------------------------------------------------- ; @routine AppHub_Init @global AppHub_Init: ldi xh, HIGH(appHubDataBegin) ldi xl, LOW(appHubDataBegin) clr r16 ldi r17, (appHubDataEnd-appHubDataBegin) rcall Utils_FillSram ; set device address and interface number in all interfaces ldi r16, 0xf0 ; hub address ldi r17, 1 ; first interface number rcall appHubAllSetAddrIfaceNumAndRange ; (R17, R19, R20, Y) ; TODO: read ranges from EEPROM ; TODO: send range msg to all interfaces ret ; @end ; --------------------------------------------------------------------------- ; @routine AppHub_Run @global ; ; Read messages from any interface, handle them and probably forward to the other ; interfaces. ; @return CFLAG set if something done, cleared otherwise ; @clobbers all AppHub_Run: rjmp appHubCheckRecvdMsg ; @end ; --------------------------------------------------------------------------- ; @routine appHubGetDeviceByIfaceNum ; ; @param r16 interface number ; @clobbers r17, r19, r20, Y appHubGetDeviceByIfaceNum: ldi r19, COM_PORTS ldi yl, LOW(com2w0_iface) ; first interface ldi yh, HIGH(com2w0_iface) appHubGetDeviceByIfaceNum_loop: ldd r17, Y+NET_IFACE_OFFS_IFACENUM cp r16, r17 sec ; mark "found" breq appHubGetDeviceByIfaceNum_ret ldi r20, COM2W_IFACE_SIZE add yl, r20 adc yh, r20 sub yh, r20 dec r19 brne appHubGetDeviceByIfaceNum_loop clc ; mark "not found" appHubGetDeviceByIfaceNum_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubAllSetAddrIfaceNumAndRange ; ; @clobbers R17, R18, R19, R20, Y appHubAllSetAddrIfaceNumAndRange: ldi r19, COM_PORTS ldi yl, LOW(com2w0_iface) ; first interface ldi yh, HIGH(com2w0_iface) ldi r18, 0x10 appHubAllSetAddrIfaceNumAndRange_loop: ; set address std Y+NET_IFACE_OFFS_ADDRESS, r16 ; set interface number std Y+NET_IFACE_OFFS_IFACENUM, r17 inc r17 ; set default range (step of 16) std Y+NET_IFACE_OFFS_RANGE_BEGIN, r18 subi r18, -15 std Y+NET_IFACE_OFFS_RANGE_END, r18 inc r18 ; next interface ldi r20, COM2W_IFACE_SIZE add yl, r20 adc yh, r20 sub yh, r20 dec r19 brne appHubAllSetAddrIfaceNumAndRange_loop ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubSendRangeMsg ; ; @param R18 msg code ; @param Y pointer to interface data ; @return CFLAG set if message enqueued, cleared on error ; @clobbers (R16, R17, R18, R19, R20, R21, R24, R25, X) appHubSendRangeMsg: bigcall NET_Buffer_Alloc ; (R16, R17, X) brcc appHubSendRangeMsg_end push r16 ldd r20, Y+NET_IFACE_OFFS_RANGE_BEGIN ldd r21, Y+NET_IFACE_OFFS_RANGE_END adiw xh:xl, 1 bigcall NETMSG_Range_Write ; (R16, R17, R18, R19, R20, R21) sbiw xh:xl, 1 pop r16 rcall appHubSendMsg ; (R16, R17, R18, R24, R25, X) appHubSendRangeMsg_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubSendDenyAddrR19 ; ; @param R19 address to send ; @clobbers R16, R17, R18, R19, R20, R21, X, Y appHubSendDenyAddrR19: ldi r18, NETMSG_CMD_DENY_ADDRESS ; deny addr rjmp appHubSendAddrMsg ; (R16, R17, R18, R19, R20, R21, X, Y) ; @end ; --------------------------------------------------------------------------- ; @routine appHubSendAddrMsg ; ; @param R18 command ; @param R19 address to send ; @clobbers R16 (R17, R18, R19, R20, R21, X, Y) appHubSendAddrMsg: bigcall NET_Buffer_Alloc ; (R16, R17, X) brcc appHubSendAddrMsg_end push r16 adiw xh:xl, 1 bigcall NETMSG_Address_Write ; (R16, R17, R18, R19, R20, R21) sbiw xh:xl, 1 pop r16 rcall appHubSendMsg ; (R16, R17, R18, R24, R25, X) appHubSendAddrMsg_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubSendValueResponse ; ; @param R17 value id ; @param R19:R18 value ; @param R21:R20 denom (e.g. 100, meaning value must be divided by 100) ; @param R23 command ; @param R25:R24 ref msg id ; @return CFLAG on success, cleared on error ; @clobbers r22 (r16, r17, r18, r19, r20, r21, r23, r24, r25, X) appHubSendValueResponse: push r17 rcall NET_Buffer_Alloc ; (R16, R17, X) pop r17 brcc appHubSendValueResponse_end ; jmp on error push r16 ; buffer num ldi r16, 0xff ; DEST addr clr r22 ; value type adiw xh:xl, 1 rcall NETMSG_ValueWriteResponse ; (R16, R17, R18, R19, R20, R21, R23, R24, R25) sbiw xh:xl, 1 pop r16 ; buffer num rcall NET_Interface_AddOrReleaseOutMsg ; (R16, R17, R18, X) appHubSendValueResponse_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubSendMsg ; ; @param R16 num of allocated buffer ; @param Y pointer to interface data ; @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 R16 (R17, R18, R24, R25, X) appHubSendMsg: bigcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X) brcs appHubSendMsg_end bigcall NET_Buffer_ReleaseByNum ; (R16, X) ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW rcall NET_Interface_IncCounter16 ; (R24, R25) clc appHubSendMsg_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubAllResetStats ; ; @clobbers r19, r20, Y (r16, r17, X) appHubAllResetStats: ldi r19, COM_PORTS ldi yl, LOW(com2w0_iface) ; first interface ldi yh, HIGH(com2w0_iface) appHubAllResetStats_loop: bigcall NET_Interface_ResetStats ; (R16, R17, X) ldi r20, COM2W_IFACE_SIZE add yl, r20 adc yh, r20 sub yh, r20 dec r19 brne appHubAllResetStats_loop ret ; @end ; --------------------------------------------------------------------------- ; @routine AppHub_EveryDay @global ; ; @clobbers R16, R17, X AppHub_EveryDay: rcall appHubAllResetStats ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubSendMsgToAllOthers ; ; @param R16 buffer number ; @param X buffer pointer ; @clobbers r17, r19, r20, r24, r25 (r16, r18, X) appHubSendMsgToAllOthers: ld r24, X andi r24, 0x0f ; get sender interface num ldi r19, COM_PORTS ; number of ports ldi yl, LOW(com2w0_iface) ; first interface ldi yh, HIGH(com2w0_iface) appHubSendMsgToAllOthers_loop: ldd r25, Y+NET_IFACE_OFFS_IFACENUM cp r24, r25 ; same interface? breq appHubSendMsgToAllOthers_next ; current iface is not source, send and inc ref counter bigcall NET_Interface_AddOutgoingMsgNum ; (R17, R18, X) brcs appHubSendMsgToAllOthers_added ; inc error counter push r24 mov r17, r16 ; save r16 ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW bigcall NET_Interface_IncCounter16 ; (R24, R25) mov r16, r17 ; restore r16 pop r24 rjmp appHubSendMsgToAllOthers_next appHubSendMsgToAllOthers_added: mov r17, r16 ; save r16 bigcall NET_Buffer_IncRef ; (r16) mov r16, r17 ; restore r16 appHubSendMsgToAllOthers_next: ldi r20, COM2W_IFACE_SIZE add yl, r20 adc yh, r20 sub yh, r20 dec r19 brne appHubSendMsgToAllOthers_loop ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubHandleMsgLocally ; ; @param X pointer to received buffer (points to header byte) ; @param Y pointer to IFACE data from which msg was received ; @clobbers all, !X appHubHandleMsgLocally: push xl push xh rcall appHubHandleMsgLocally_savedX pop xh pop xl rjmp appHubHandleMsgLocally_ret appHubHandleMsgLocally_savedX: ; get message type adiw xh:xl, NETMSG_OFFS_CMD+1 ; account for header byte ld r16, X sbiw xh:xl, NETMSG_OFFS_CMD+1 cpi r16, NETMSG_CMD_PING breq appHubHandleMsgLocally_handlePingMsg cpi r16, NETMSG_CMD_REBOOT_REQUEST breq appHubHandleMsgLocally_handleRebootMsg cpi r16, NETMSG_CMD_VALUE_SET breq appHubHandleMsgLocally_handleSetValue rjmp appHubHandleMsgLocally_ret appHubHandleMsgLocally_handlePingMsg: rjmp appHubHandlePingMsg appHubHandleMsgLocally_handleRebootMsg: rjmp appHubHandleRebootMsg appHubHandleMsgLocally_handleSetValue: rjmp appHubHandleSetValueMsg appHubHandleMsgLocally_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubHandlePingMsg ; ; @param X pointer to received message ; @clobbers any, !X, !Y appHubHandlePingMsg: adiw xh:xl, NETMSG_OFFS_DESTADDR+1 ld r17, X sbiw xh:xl, NETMSG_OFFS_DESTADDR+1 ldd r16, Y+NET_IFACE_OFFS_ADDRESS cp r16, r17 breq appHubHandlePingMsg_forMe cpi r17, 0xff breq appHubHandlePingMsg_forMe clc rjmp appHubHandlePingMsg_end appHubHandlePingMsg_forMe: adiw xh:xl, NETMSG_OFFS_SRCADDR+1 ld r17, X sbiw xh:xl, NETMSG_OFFS_SRCADDR+1 push r17 bigcall NET_Buffer_Alloc ; (R16, R17, X) pop r17 brcc appHubHandlePingMsg_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) appHubHandlePingMsg_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubHandleRebootMsg ; ; Doesn't return if reboot msg is valid. ; ; @param X pointer to received message appHubHandleRebootMsg: rcall NETMSG_RebootRequestRead brcc appHubHandleRebootMsg_end ; reboot cli bigjmp BOOTLOADER_ADDR appHubHandleRebootMsg_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubHandleSetValueMsg ; ; @param X pointer to received message ; @param Y pointer to IFACE data from which msg was received ; @clobbers all, !Y appHubHandleSetValueMsg: adiw xh:xl, NETMSG_OFFS_DESTADDR+1 ld r17, X sbiw xh:xl, NETMSG_OFFS_DESTADDR+1 ldd r16, Y+NET_IFACE_OFFS_ADDRESS cp r16, r17 breq appHubHandleSetValueMsg_forMe cpi r17, 0xff breq appHubHandleSetValueMsg_forMe rjmp appHubHandleSetValueMsg_ret appHubHandleSetValueMsg_forMe: rcall NETMSG_ValueRead ; (none) cpi r17, VALUE_ID_HUB_SETRANGE1 brcs appHubHandleSetValueMsg_ret cpi r17, VALUE_ID_HUB_SETRANGE8+1 brcc appHubHandleSetValueMsg_ret appHubHandleSetValueMsg_setRange: push yl push yh subi r17, (VALUE_ID_HUB_SETRANGE1-1) push r18 push r19 ; send ACK back the same interface the request came from push r17 ; interface number ldi r23, NETMSG_CMD_VALUE_SET_ACK rcall appHubSendValueResponse ; r22 (r16, r17, r18, r19, r20, r21, r23, r24, r25, X) pop r16 ; pop interface number to r16 (from r17) rcall appHubGetDeviceByIfaceNum ; Y=interface to modify (r17, r19, r20) pop r19 pop r18 ; modify interface std Y+NET_IFACE_OFFS_RANGE_BEGIN, r18 std Y+NET_IFACE_OFFS_RANGE_END, r19 ; TODO: store new config ; let subnodes of modified interface re-eunumerate ldi r18, NETMSG_CMD_REENUM rcall appHubSendRangeMsg ; (R16, R17, R18, R19, R20, R21, X) pop yh pop yl appHubHandleSetValueMsg_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubHandleRoutingMsg ; ; @param X pointer to received buffer (points to header byte) ; @param Y pointer to IFACE data from which msg was received ; @clobbers all, !X appHubHandleRoutingMsg: push xl push xh rcall appHubHandleRoutingMsg_savedX pop xh pop xl rjmp appHubHandleRoutingMsg_ret appHubHandleRoutingMsg_savedX: ; get message type adiw xh:xl, NETMSG_OFFS_CMD+1 ; account for header byte ld r16, X sbiw xh:xl, NETMSG_OFFS_CMD+1 cpi r16, NETMSG_CMD_NEED_ADDRESS breq appHubHandleRoutingMsg_handleNeedAddress cpi r16, NETMSG_CMD_CLAIM_ADDRESS breq appHubHandleRoutingMsg_handleClaimAddress clc rjmp appHubHandleRoutingMsg_ret appHubHandleRoutingMsg_handleNeedAddress: rcall appHubHandleNeedAddressMsg rjmp appHubHandleRoutingMsg_secRet appHubHandleRoutingMsg_handleClaimAddress: rcall appHubHandleClaimAddressMsg appHubHandleRoutingMsg_secRet: sec appHubHandleRoutingMsg_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubHandleNeedAddressMsg ; ; @param X pointer to received message ; @param Y pointer to IFACE data from which msg was received ; @clobbers all, !Y appHubHandleNeedAddressMsg: ldi r18, NETMSG_CMD_ADDRESS_RANGE rcall appHubSendRangeMsg ; (R16, R17, R18, R19, R20, R21, X) ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubHandleClaimAddressMsg ; ; @param X pointer to received message ; @param Y pointer to IFACE data from which msg was received ; @clobbers all, !Y appHubHandleClaimAddressMsg: rcall NETMSG_Address_Read ; R18=cmd, R19=addr(R18, R19) rcall appHubIsR19InRange brcs appHubHandleClaimAddressMsg_end ; is not in subnet range, deny rcall appHubSendDenyAddrR19 ; (R16, R17, R18, R19, R20, R21, X) appHubHandleClaimAddressMsg_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubIsR19InRange ; ; @param R19 address to check against range ; @param Y pointer to IFACE data ; @clobbers R16 appHubIsR19InRange: ldd r16, Y+NET_IFACE_OFFS_RANGE_BEGIN cp r19, r16 brcs appHubIsR19InRangeClcRet ldd r16, Y+NET_IFACE_OFFS_RANGE_END cp r16, r19 brcs appHubIsR19InRangeClcRet sec rjmp appHubIsR19InRange_end appHubIsR19InRangeClcRet: clc appHubIsR19InRange_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubCheckRecvdMsg ; ; Read messages from any interface and forward to the other ones. ; ; @return CFLAG set if something done, cleared otherwise appHubCheckRecvdMsg: rcall NET_PeekNextIncomingMsgNum ; check read queue (R16=bufNum) brcc appHubCheckRecvdMsg_end ; no msg, jmp rcall NET_Buffer_Locate ; (R17) rcall appHubHandleRecvdMsg ; (all, !X) rcall NET_GetNextIncomingMsgNum ; take off the queue rcall NET_Buffer_ReleaseByNum ; (R16, X) sec ; we had a message, so something was done appHubCheckRecvdMsg_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubHandleRecvdMsg ; ; @param R16 buffer number ; @param X pointer to received message ; @clobbers all, !X appHubHandleRecvdMsg: mov r18, r16 ld r16, X andi r16, 0x0f rcall appHubGetDeviceByIfaceNum ; Y=source iface (r17, r19, r20) brcc appHubHandleRecvdMsg_ret ; filter out routing msgs push yl push yh push r18 rcall appHubHandleRoutingMsg ; (all, !X) pop r18 pop yh pop yl brcs appHubHandleRecvdMsg_ret ; check for PING, SETVALUE etc push r18 push yl push yh rcall appHubHandleMsgLocally ; (all, !X) pop yh pop yl ; let other apps and modules handle message push xl push xh bigcall mainHandleMessages pop xh pop xl pop r18 ; forward message to all other interfaces mov r16, r18 ; buffer number push xl push xh rcall appHubSendMsgToAllOthers ; (r17, r19, r20, r24, r25 (r16, r18, X) pop xh pop xl appHubHandleRecvdMsg_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine appHubWriteConfToEeprom ; ; @clobbers R16, X (R17) appHubWriteConfToEeprom: ; write range begin ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_BEGIN) ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_BEGIN) lds r16, appHubRangeBegin rcall Eeprom_WriteByteIfChanged ; (R17) brcc appHubWriteConfToEeprom_end ; write range end ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_END) ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_END) lds r16, appHubRangeEnd rcall Eeprom_WriteByteIfChanged ; (R17) appHubWriteConfToEeprom_end: ret ; @end #if 0 ; --------------------------------------------------------------------------- ; @routine appHubReadConfFromEeprom ; ; @clobbers R16, X (R17) appHubReadConfFromEeprom: ; read range begin ldi xl, LOW(EEPROM_OFFS_ROUTER_RANGE_BEGIN) ldi xh, HIGH(EEPROM_OFFS_ROUTER_RANGE_BEGIN) rcall Eeprom_ReadByte brcc appHubReadConfFromEeprom_end cpi r16, 0xff breq appHubReadConfFromEeprom_okay ; not set, jmp cpi r16, 2 ; range should at least start at 2 to assign 1 to router brcs appHubReadConfFromEeprom_okay sts appHubRangeBegin, 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 appHubReadConfFromEeprom_end cpi r16, 0xff breq appHubReadConfFromEeprom_okay sts appHubRangeEnd, r16 appHubReadConfFromEeprom_okay: sec appHubReadConfFromEeprom_end: ret ; @end #endif