Files
aqhomecontrol/avr/modules/valuemgr/src.asm
Martin Preuss dfad168875 avr: started working on value manager
will probably not use this since this takes many bytes in flash.
2024-10-31 18:50:08 +01:00

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