Files
aqhomecontrol/avr/modules/uart_hw/msglevel_recv.asm
2025-01-27 00:20:45 +01:00

281 lines
8.2 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. *
; ***************************************************************************
.cseg
UART_HW_Interface_RunRead:
rcall uartHwReadEnsureBuffer ; (r16, R17, X)
brcc UART_HW_Interface_RunRead_end
rcall uartHwReadEnsureHeader ; (r16, r17, r20, r21, X)
brcc UART_HW_Interface_RunRead_end
rcall uartHwReadEnsureBody ; (r16, r17, r20, r21, x)
brcc UART_HW_Interface_RunRead_end
UART_HW_Interface_RunRead_HaveMsg:
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_USED
cpi r16, 3
brcs UART_HW_Interface_RunRead_badMsg
; check and store msg
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM
rcall UART_HW_AddIncomingMsgNum ; (R17, R18, X)
brcs UART_HW_Interface_RunRead_clearBuf
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM
rcall UART_HW_FixedBuffers_ReleaseByNum ; (R16, X)
UART_HW_Interface_RunRead_clearBuf:
ldi r16, 0xff
std Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM, r16
rjmp UART_HW_Interface_RunRead_end
UART_HW_Interface_RunRead_badMsg:
; reset READ buffer settings, enter skip mode
rcall uartHwResetBufferStartSkipping ; (r16, X)
UART_HW_Interface_RunRead_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartHwEnsureReadBuffer
;
; @param Y pointer to start of interface data
; @clobbers r16 (R17, X)
uartHwReadEnsureBuffer:
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM
cpi r16, 0xff
breq uartHwReadEnsureBuffer_alloc
uartHwReadEnsureBuffer_SecRet:
sec
ret
uartHwReadEnsureBuffer_alloc:
rcall uartHwAllocateReadBuffer ; (r16, R17, X)
brcc uartHwReadEnsureBuffer_error
rcall uartHwReadSetBuffer ; (r16)
rjmp uartHwReadEnsureBuffer_SecRet
uartHwReadEnsureBuffer_error:
; no buffer, set error status, skip msg
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM
rcall UART_HW_FixedBuffers_Locate ; (r16)
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM
rcall uartHwReadResetBuffer ; (r16)
ldd r16, Y+UART_HW_IFACE_OFFS_MODE
ori r16, UART_HW_MODE_SKIPPING
std Y+UART_HW_IFACE_OFFS_MODE, r16
ldd r16, Y+UART_HW_IFACE_OFFS_ERR_OVR
inc r16
breq UART_HW_Interface_RunRead_end
std Y+UART_HW_IFACE_OFFS_ERR_OVR, r16
clc
uartHwReadEnsureBuffer_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartHwReadSetBuffer
;
; @param Y pointer to start of interface data
; @param X pointer to start of buffer
; @param r16 buffer number
; @clobbers r16
uartHwReadSetBuffer:
std Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM, r16 ; set buffer data
adiw xh:xl, 1
std Y+UART_HW_IFACE_OFFS_READMSG_PTR, xl
std Y+UART_HW_IFACE_OFFS_READMSG_PTR+1, xh
sbiw xh:xl, 1
clr r16
std Y+UART_HW_IFACE_OFFS_READMSG_USED, r16
std Y+UART_HW_IFACE_OFFS_READMSG_LEFT, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartHwReadResetBuffer
;
; @param Y pointer to start of interface data
; @clobbers r16, X
uartHwReadResetBuffer:
; reset READ buffer settings, enter skip mode
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM
rcall UART_HW_FixedBuffers_Locate ; (X)
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM
rjmp uartHwReadSetBuffer ; (r16)
; @end
; ---------------------------------------------------------------------------
; @routine uartHwResetBufferStartSkipping
;
; @param Y pointer to start of interface data
; @clobbers r16, X
uartHwResetBufferStartSkipping:
; reset READ buffer settings, enter skip mode
rcall uartHwReadResetBuffer
ldd r16, Y+UART_HW_IFACE_OFFS_MODE
ori r16, UART_HW_MODE_SKIPPING
std Y+UART_HW_IFACE_OFFS_MODE, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartHwReadEnsureHeader
;
; @param Y pointer to start of interface data
; @clobbers r16 (r17, r20, r21, X)
uartHwReadEnsureHeader:
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_LEFT
tst r16
breq uartHwReadEnsureHeader_readHeader
sec
ret
uartHwReadEnsureHeader_readHeader:
; read and validate header (2 bytes)
rcall uartHwReadAndValidateHeader ; (r16, r17, r20, r21, X)
brcc UART_HW_Interface_RunRead_badMsg
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_USED
cpi r16, 2 ; full header in buffer (2 bytes)?
brcs UART_HW_Interface_RunRead_end ; nope, done for this round
uartHwReadEnsureHeader_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartHwReadEnsureBody
;
; @param Y pointer to start of interface data
; @clobbers r20 (r16, r17, r21, x)
uartHwReadEnsureBody:
ldd r20, Y+UART_HW_IFACE_OFFS_READMSG_LEFT
tst r20
sec
breq uartHwReadEnsureBody_end ; no bytes left, message done
rcall uartHwReadUptoNumBytes ; (r16, r17, r20, r21, X)
ldd r20, Y+UART_HW_IFACE_OFFS_READMSG_LEFT
tst r20
sec
breq uartHwReadEnsureBody_end ; no bytes left, message done
clc
uartHwReadEnsureBody_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartHwAllocateReadBuffer
;
; @param Y pointer to start of interface data
; @clobbers r16 (R17, X)
uartHwAllocateReadBuffer:
rcall UART_HW_FixedBuffers_Alloc ; (R16, R17, X)
brcc uartHwAllocateReadBuffer_end
std Y+UART_HW_IFACE_OFFS_READMSG_BUFNUM, r16
adiw xh:xl, 1
std Y+UART_HW_IFACE_OFFS_READMSG_PTR, xl
std Y+UART_HW_IFACE_OFFS_READMSG_PTR+1, xh
clr r16
std Y+UART_HW_IFACE_OFFS_READMSG_USED, r16
std Y+UART_HW_IFACE_OFFS_READMSG_LEFT, r16
sec
uartHwAllocateReadBuffer_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartHwReadAndValidateHeader
;
; @param Y pointer to start of interface data
; @clobbers r16, r20, X (r17, r21)
uartHwReadAndValidateHeader:
; read until we have 2 bytes
ldi r20, 2
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_USED
sub r20, r16
rcall uartHwReadUptoNumBytes ; (r16, r17, r20, r21, X)
; check whether we have 2 bytes
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_USED
cpi r16, 2
brcs uartHwReadAndValidateHeader_ok ; < 2 bytes in buffer, nothing to do
; read and check msg len
ldd xl, Y+UART_HW_IFACE_OFFS_READMSG_PTR
ldd xh, Y+UART_HW_IFACE_OFFS_READMSG_PTR+1
sbiw xh:xl, 1 ; go back one byte, pointing to MSG_LEN
ld r16, X
cpi r16, UART_HW_FIXEDBUFFERS_SIZE-4 ; minus buffer status byte, dest addr, msglen, crc
brcc uartHwReadAndValidateHeader_error ; bad msg length
; set number of bytes left to read
inc r16 ; account for crc byte
std Y+UART_HW_IFACE_OFFS_READMSG_LEFT, r16
uartHwReadAndValidateHeader_ok:
sec
ret
uartHwReadAndValidateHeader_error:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine uartHwReadUptoNumBytes
;
; @param Y pointer to start of interface data
; @param R20 number of bytes to read
; @clobbers r16, r20, r21, X (R17)
uartHwReadUptoNumBytes:
clr r21
ldd xl, Y+UART_HW_IFACE_OFFS_READMSG_PTR
ldd xh, Y+UART_HW_IFACE_OFFS_READMSG_PTR+1
uartHwReadUptoNumBytes_loop:
push xl
push xh
rcall UART_HW_InterfaceReadFromWriteBuffer ; (R17, R18, X)
pop xh
pop xl
brcc uartHwReadUptoNumBytes_done
st X+, r16
inc r21
dec r20
brne uartHwReadUptoNumBytes_loop
uartHwReadUptoNumBytes_done:
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_USED
add r16, r21
std Y+UART_HW_IFACE_OFFS_READMSG_USED, r16
ldd r16, Y+UART_HW_IFACE_OFFS_READMSG_LEFT
sub r16, r21
std Y+UART_HW_IFACE_OFFS_READMSG_LEFT, r16 ; might become negative when reading header
std Y+UART_HW_IFACE_OFFS_READMSG_PTR, xl
std Y+UART_HW_IFACE_OFFS_READMSG_PTR+1, xh
ret
; @end