; *************************************************************************** ; copyright : (C) 2024 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. * ; *************************************************************************** ; *************************************************************************** ; defs .equ VALMGR_VAR_OFFS_VALUEID = 0 ; 1 byte .equ VALMGR_VAR_OFFS_PRIORITY = 1 ; 1 byte (1=lowest, reset to 0 when done with msg) .equ VALMGR_VAR_OFFS_CURRVAL = 2 ; 4 bytes .equ VALMGR_VAR_OFFS_TIMERSEND = 6 ; 1 byte .equ VALMGR_VAR_OFFS_COUNTERRESEND = 7 ; 1 byte .equ VALMGR_VAR_OFFS_MSGID = 8 ; 2 bytes .equ VALMGR_VAR_OFFS_TIMERACK = 10 ; 1 byte .equ VALMGR_VAR_OFFS_VALUETYPE = 11 ; 1 byte .equ VALMGR_VAR_SIZE = 12 .equ VALMGR_SRCLINK_OFFS_VALUEID = 0 ; 1 byte .equ VALMGR_SRCLINK_OFFS_PEERADDR = 1 ; 1 byte .equ VALMGR_SRCLINK_SIZE = 2 ; *************************************************************************** ; data .dseg valMgrSrcDataBegin: valMgrSrcLinks: .byte VALMGR_SRC_MAX_LINKS*VALMGR_SRCLINK_SIZE valMgrSrcNoSendErrors: .byte 1 valMgrSrcOverflowErrors: .byte 1 valMgrSrcNoAckErrors: .byte 1 valMgrSrcDataEnd: ; *************************************************************************** ; code .cseg VALMGR_SRC_BEGIN: ; --------------------------------------------------------------------------- ; @routine VALMGR_Src_Init VALMGR_Src_Init: ; preset SRAM data area ldi xh, HIGH(valMgrSrcDataBegin) ldi xl, LOW(valMgrSrcDataBegin) clr r16 ldi r17, (valMgrSrcDataEnd-valMgrSrcDataBegin) rcall Utils_FillSram sec ret ; @end ; --------------------------------------------------------------------------- ; @routine VALMGR_Src_Fini VALMGR_Src_Fini: ret ; @end ; --------------------------------------------------------------------------- ; @routine VALMGR_Src_ValueInit ; ; @param R16 value id ; @param R17 value type ; @param Y pointer to VALMGR_VAR object ; @clobbers R16 VALMGR_Src_ValueInit: std Y+VALMGR_VAR_OFFS_VALUEID, r16 std Y+VALMGR_VAR_OFFS_VALUETYPE, r17 rjmp valMgrSrcResetValue ; (R16) ; @end ; --------------------------------------------------------------------------- ; @routine VALMGR_Src_AddSrcLink @global ; ; @return CFLAG set if link found and deleted, cleared otherwise ; @param R16 value id ; @param R17 peer address ; @clobbers (R18, R19, X) VALMGR_Src_AddSrcLink: rcall valMgrSrcFindLink ; (R18, R19, X) brcs VALMGR_Src_AddSrcLink_retnc ; exists, jmp rcall valMgrSrcFindFreeLink ; (R18, R19, X) brcc VALMGR_Src_AddSrcLink_retnc ; no free link st X+, r16 ; value id st X+, r17 ; peer address sec ret VALMGR_Src_AddSrcLink_retnc: clc ret ; @end ; --------------------------------------------------------------------------- ; @routine VALMGR_Src_DelSrcLink @global ; ; @return CFLAG set if link found and deleted, cleared otherwise ; @param R16 value id ; @param R17 peer address ; @clobbers R18 (R19, X) VALMGR_Src_DelSrcLink: rcall valMgrSrcFindLink ; (R18, R19, X) brcs VALMGR_Src_DelSrcLink_retnc ; exists, jmp clr r18 st X+, r18 ; value id st X+, r18 ; peer address sec ret VALMGR_Src_DelSrcLink_retnc: clc ret ; @end ; --------------------------------------------------------------------------- ; @routine VALMGR_Src_ValueSend @global ; Handle sending a REPORT_VALUE packet. ; ; @return CFLAG set if enqueued, cleared on error ; @param R19:R18 value ; @param R21:R20 denom (e.g. 100, meaning value must be divided by 100) ; @param R22 priority ; @param Y pointer to VALMGR_VAR object ; @clobbers any, -Y VALMGR_Src_ValueSend: ldd r16, Y+VALMGR_VAR_OFFS_PRIORITY tst r16 ; prio==0 (inactive)? breq VALMGR_Src_ValueSend_setnew ; yes, free to go cp r22, r16 ; old prio higher? brcc VALMGR_Src_ValueSend_setnew ; overflow (buffer still in use with higher priority msg) lds r16, valMgrSrcOverflowErrors inc r16 breq VALMGR_Src_ValueSend_dontCountUp sts valMgrSrcOverflowErrors, r16 VALMGR_Src_ValueSend_dontCountUp: clc ret VALMGR_Src_ValueSend_setnew: std Y+VALMGR_VAR_OFFS_PRIORITY, r22 std Y+VALMGR_VAR_OFFS_CURRVAL, r18 std Y+VALMGR_VAR_OFFS_CURRVAL+1, r19 std Y+VALMGR_VAR_OFFS_CURRVAL+2, r20 std Y+VALMGR_VAR_OFFS_CURRVAL+3, r21 ldi r16, VALMGR_SRC_TIMEOUT_SENDVALUE std Y+VALMGR_VAR_OFFS_TIMERSEND, r16 ldi r16, VALMGR_SRC_MAX_RESEND std Y+VALMGR_VAR_OFFS_COUNTERRESEND, r16 clr r16 std Y+VALMGR_VAR_OFFS_TIMERACK, r16 std Y+VALMGR_VAR_OFFS_MSGID, r16 std Y+VALMGR_VAR_OFFS_MSGID+1, r16 ldd r16, Y+VALMGR_VAR_OFFS_VALUEID rcall valMgrSrcMarkLinks rcall valMgrSrcSendValue VALMGR_Src_ValueSend_end: sec ret ; @end ; --------------------------------------------------------------------------- ; @routine VALMGR_Src_ValueHandleResponse @global ; Handle sending a REPORT_VALUE packet. ; ; @return CFLAG set if handled, cleared otherwise ; @param R17 peer address (sender of the response) ; @param R19:R18 msg id ; @param Y pointer to VALMGR_VAR object ; @clobbers R16 (R18, R19, X) VALMGR_Src_ValueHandleResponse: ldd r16, Y+VALMGR_VAR_OFFS_MSGID cp r16, r18 brne VALMGR_Src_ValueHandleResponse_retnc ldd r16, Y+VALMGR_VAR_OFFS_MSGID+1 cp r16, r19 brne VALMGR_Src_ValueHandleResponse_retnc ldd r16, Y+VALMGR_VAR_OFFS_VALUEID rcall valMgrSrcUnmarkLink ; (R18, R19, X) rcall valMgrSrcHasMarkedLinks brcc VALMGR_Src_ValueHandleResponse_retc rcall valMgrSrcResetValue ; (R16) VALMGR_Src_ValueHandleResponse_retc: sec ret VALMGR_Src_ValueHandleResponse_retnc: clc ret ; @end ; --------------------------------------------------------------------------- ; @routine VALMGR_Src_ValueEvery100ms ; ; @param Y pointer to VALMGR_VAR object ; @clobbers R16 VALMGR_Src_ValueEvery100ms: ldd r16, Y+VALMGR_VAR_OFFS_PRIORITY tst r16 brne VALMGR_Src_ValueEvery100ms_active ret VALMGR_Src_ValueEvery100ms_active: rcall valMgrSrcCheckSendTimer rcall valMgrSrcCheckAckTimer ret ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcCheckSendTimer ; ; Set MSB in value id of all matching link entries ; @param R16 valueId to activate ; @clobbers any, -Y valMgrSrcCheckSendTimer: ldd r16, Y+VALMGR_VAR_OFFS_TIMERSEND tst r16 brne valMgrSrcCheckSendTimer_dec ret valMgrSrcCheckSendTimer_dec: dec r16 std Y+VALMGR_VAR_OFFS_TIMERSEND, r16 breq valMgrSrcCheckSendTimer_timeout rjmp valMgrSrcSendValue ; (any except Y) valMgrSrcCheckSendTimer_timeout: lds r16, valMgrSrcNoSendErrors inc r16 breq valMgrSrcCheckSendTimer_dontCountUp sts valMgrSrcNoSendErrors, r16 valMgrSrcCheckSendTimer_dontCountUp: rjmp valMgrSrcResetValue ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcCheckAckTimer ; ; Set MSB in value id of all matching link entries ; @param R16 valueId to activate ; @clobbers any, -Y valMgrSrcCheckAckTimer: ldd r16, Y+VALMGR_VAR_OFFS_TIMERACK tst r16 brne valMgrSrcCheckAckTimer_dec ret valMgrSrcCheckAckTimer_dec: dec r16 std Y+VALMGR_VAR_OFFS_TIMERACK, r16 breq valMgrSrcCheckAckTimer_timeout ret valMgrSrcCheckAckTimer_timeout: lds r16, valMgrSrcNoAckErrors ; inc error counter inc r16 breq valMgrSrcCheckAckTimer_tryresend sts valMgrSrcNoAckErrors, r16 valMgrSrcCheckAckTimer_tryresend: ldd r16, Y+VALMGR_VAR_OFFS_COUNTERRESEND dec r16 brne valMgrSrcCheckAckTimer_resend ; resend counter reached zero, abort ldd r16, Y+VALMGR_VAR_OFFS_VALUEID rcall valMgrSrcUnmarkLinks ; (R17, R18, X) rjmp valMgrSrcResetValue ; (R16) valMgrSrcCheckAckTimer_resend: std Y+VALMGR_VAR_OFFS_COUNTERRESEND, r16 ldi r16, VALMGR_SRC_TIMEOUT_SENDVALUE std Y+VALMGR_VAR_OFFS_TIMERSEND, r16 rjmp valMgrSrcSendValue ; (any except Y) ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcMarkLinks ; ; Set MSB in value id of all matching link entries ; @param R16 valueId to activate ; @clobbers R17, R18, X valMgrSrcMarkLinks: ldi xl, LOW(valMgrSrcLinks) ldi xh, HIGH(valMgrSrcLinks) ldi r17, VALMGR_SRC_MAX_LINKS valMgrSrcMarkLinks_loop: ld r18, X andi r18, 0x7f cp r18, r16 brne valMgrSrcMarkLinks_next ori r18, 0x80 st X, r18 valMgrSrcMarkLinks_next: adiw xh:xl, VALMGR_SRCLINK_SIZE dec r17 brne valMgrSrcMarkLinks_loop ret ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcUnmarkLink ; ; Find matching link entry and unmark it (i.e. clear MSB) ; @param R16 valueId to find ; @param R17 source address to find ; @clobbers R18, R19, X valMgrSrcUnmarkLink: rcall valMgrSrcFindLink ; (R18, R19, X) brcc valMgrMarkSrcLink_end st X, r16 valMgrMarkSrcLink_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcFindLink ; ; Find matching link entries ; @return CFLAG set if found, cleared otherwise ; @return X points to link ; @param R16 valueId to find ; @param R17 source address to find ; @clobbers R18, R19, X valMgrSrcFindLink: ldi xl, LOW(valMgrSrcLinks) ldi xh, HIGH(valMgrSrcLinks) ldi r19, VALMGR_SRC_MAX_LINKS valMgrSrcFindLink_loop: ld r18, X+ andi r18, 0x7f cp r18, r16 brne valMgrSrcFindLink_next1 ld r18, X+ cp r18, r17 brne valMgrSrcFindLink_next2 sbiw xh:xl, 2 sec ret valMgrSrcFindLink_next1: adiw xh:xl, VALMGR_SRCLINK_SIZE-1 valMgrSrcFindLink_next2: dec r19 brne valMgrSrcFindLink_loop clc ret ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcFindFreeLink ; ; Find matching link entries ; @return CFLAG set if found, cleared otherwise ; @return X points to link ; @clobbers R18, R19, X valMgrSrcFindFreeLink: ldi xl, LOW(valMgrSrcLinks) ldi xh, HIGH(valMgrSrcLinks) ldi r19, VALMGR_SRC_MAX_LINKS valMgrSrcFindFreeLink_loop: ld r18, X andi r18, 0x7f brne valMgrSrcFindFreeLink_next sec ret valMgrSrcFindFreeLink_next: adiw xh:xl, VALMGR_SRCLINK_SIZE dec r19 brne valMgrSrcFindFreeLink_loop clc ret ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcUnmarkLinks ; ; Clear MSB in value id of all matching link entries ; @param R16 valueId to activate ; @clobbers R17, R18, X valMgrSrcUnmarkLinks: ldi xl, LOW(valMgrSrcLinks) ldi xh, HIGH(valMgrSrcLinks) ldi r17, VALMGR_SRC_MAX_LINKS valMgrSrcUnmarkLinks_loop: ld r18, X andi r18, 0x7f cp r18, r16 brne valMgrSrcUnmarkLinks_next st X, r18 valMgrSrcUnmarkLinks_next: adiw xh:xl, VALMGR_SRCLINK_SIZE dec r17 brne valMgrSrcUnmarkLinks_loop ret ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcHasMarkedLinks ; ; Set MSB in value id of all matching link entries ; @param R16 valueId to activate ; @clobbers R17, R18, X valMgrSrcHasMarkedLinks: ldi xl, LOW(valMgrSrcLinks) ldi xh, HIGH(valMgrSrcLinks) ldi r17, VALMGR_SRC_MAX_LINKS valMgrSrcHasMarkedLinks_loop: ld r18, X andi r18, 0x7f cp r18, r16 brne valMgrSrcHasMarkedLinks_next sec ret valMgrSrcHasMarkedLinks_next: adiw xh:xl, VALMGR_SRCLINK_SIZE dec r17 brne valMgrSrcHasMarkedLinks_loop clc ret ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcSendValue ; ; Try to send a value ; ; @return CFLAG set if message sent, cleared otherwise ; @param Y pointer to VALMGR_VAR object ; @clobbers any, -Y valMgrSrcSendValue: ldi xl, LOW(com2SendBuffer) ldi xh, HIGH(com2SendBuffer) ldi r16, 0xff ; broadcast ldd r17, Y+VALMGR_VAR_OFFS_VALUEID ldd r18, Y+VALMGR_VAR_OFFS_CURRVAL ldd r19, Y+VALMGR_VAR_OFFS_CURRVAL+1 ldd r20, Y+VALMGR_VAR_OFFS_CURRVAL+2 ldd r21, Y+VALMGR_VAR_OFFS_CURRVAL+3 ldd r22, Y+VALMGR_VAR_OFFS_VALUETYPE rcall CPRO_WriteReportValue ; (R16, R17, R18, R19, R20, R21) rcall COM2_SendPacket ; (any) brcc valMgrSrcSendValue_end ; could not send ; successfully sent, check for active links for this var ldd r16, Y+VALMGR_VAR_OFFS_VALUEID rcall valMgrSrcHasMarkedLinks brcs valMgrSrcSendValue_prepareWaitForAck rcall valMgrSrcResetValue sec ret valMgrSrcSendValue_prepareWaitForAck: clr r16 ; clear timer std Y+VALMGR_VAR_OFFS_TIMERSEND, r16 lds r16, com2LastMsgId ; copy last used msg id (we will wait for ACK on this msg) std Y+VALMGR_VAR_OFFS_MSGID, r16 lds r16, com2LastMsgId+1 std Y+VALMGR_VAR_OFFS_MSGID+1, r16 ldi r16, VALMGR_SRC_TIMEOUT_RECVACK ; start ACK timer std Y+VALMGR_VAR_OFFS_TIMERACK, r16 sec valMgrSrcSendValue_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine valMgrSrcResetValue ; ; Reset value data (e.g. set timers, msgid and priority to 0) ; ; @return CFLAG set if message sent, cleared otherwise ; @param Y pointer to VALMGR_VAR object ; @clobbers r16 valMgrSrcResetValue: clr r16 std Y+VALMGR_VAR_OFFS_PRIORITY, r16 std Y+VALMGR_VAR_OFFS_TIMERSEND, r16 std Y+VALMGR_VAR_OFFS_COUNTERRESEND, r16 std Y+VALMGR_VAR_OFFS_MSGID, r16 std Y+VALMGR_VAR_OFFS_MSGID+1, r16 ret ; @end VALMGR_SRC_END: .equ MODULE_SIZE_VALMGR_SRC = VALMGR_SRC_END-VALMGR_SRC_BEGIN