; *************************************************************************** ; 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