541 lines
14 KiB
NASM
541 lines
14 KiB
NASM
; ***************************************************************************
|
|
; 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
|
|
|