; *************************************************************************** ; 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. * ; *************************************************************************** #ifndef AVR_MODULES_COM2W_COM2WN_RECV_H #define AVR_MODULES_COM2W_COM2WN_RECV_H ; WORK IN PROGRESS .cseg ; --------------------------------------------------------------------------- ; @routine com2wnActOnClock @global ; ; @param r16 CLK input (0 or !=0) ; @param r17 DATA input (0 or !=0) ; @param Y pointer to IFACE data ; @clobbers r16 (r17, r18, X) com2wnActOnClock: tst r16 brne com2wnActOnClock_clockHigh ; clock low ldd r18, Y+COM2W_IFACE_OFFS_MODE cpi r18, COM2W_MODE_IDLE breq com2wnActOnClock_startReading cpi r18, COM2W_MODE_SKIPPING breq com2wnActOnClock_skipping rjmp com2wnActOnClock_end com2wnActOnClock_skipping: ; ldd r18, Y+COM2W_IFACE_OFFS_MODECOUNTER ; cpi r18, COM2W_SKIPPING_MAXMODECOUNTER ; brcc com2wnActOnClock_startReading rjmp com2wnActOnClock_end com2wnActOnClock_startReading: rcall com2wnStartReading ; (r16, r17, X) rjmp com2wnActOnClock_end com2wnActOnClock_clockHigh: ldd r18, Y+COM2W_IFACE_OFFS_MODE cpi r18, COM2W_MODE_READING brne com2wnActOnClock_end push r20 push r22 rcall com2wnReadNextBit ; (r16, r17, r18, r20, r22) pop r22 pop r20 com2wnActOnClock_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnReadNextBit @global ; ; @param r17 DATA input (0 or !=0) ; @clobbers r16, r17, r18, r20, r22 com2wnReadNextBit: ; ldi r20, 50 ; wait for up to 250us for clock rise ; rcall com2w0WaitForClockHighMulti5Us ; (R20, R22) ; brcc com2wnReadNextBit_end ; clock is high now, read bit ; reset read timer (for leaving skipping mode) clr r16 std Y+NET_IFACE_OFFS_READTIMER, r16 ; check mode ldd r16, Y+COM2W_IFACE_OFFS_MODE cpi r16, COM2W_MODE_READING brne com2wnReadNextBit_end ; handle received bit ldd r16, Y+COM2W_IFACE_OFFS_CURRBYTE ldd r18, Y+COM2W_IFACE_OFFS_BITCOUNTER tst r17 ; data port input clc breq com2wnReadNextBit_clockData sec com2wnReadNextBit_clockData: ror r16 std Y+COM2W_IFACE_OFFS_CURRBYTE, r16 inc r18 ; bit counter std Y+COM2W_IFACE_OFFS_BITCOUNTER, r18 cpi r18, 8 brne com2wnReadNextBit_end ; write byte into buffer push xl push xh rcall com2wnByteRecvd ; (r16, r17, r18, X) pop xh pop xl ; prepare for next byte clr r16 std Y+COM2W_IFACE_OFFS_BITCOUNTER, r16 std Y+COM2W_IFACE_OFFS_CURRBYTE, r16 com2wnReadNextBit_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnByteRecvd ; ; @param r16 byte received ; @param Y pointer to interface data ; @return CFLAG set if okay, cleared on error ; @clobbers r16, r17, r18, X com2wnByteRecvd: #ifdef MODULES_LED_ACTIVITY push r16 rcall LedActivity_Trigger pop r16 #endif ldd xl, Y+COM2W_IFACE_OFFS_BUFPOS_LOW ldd xh, Y+COM2W_IFACE_OFFS_BUFPOS_HIGH ldd r17, Y+COM2W_IFACE_OFFS_BUFLEFT ldd r18, Y+COM2W_IFACE_OFFS_BUFUSED tst r17 breq com2wnByteRecvd_overflow st X+, r16 std Y+COM2W_IFACE_OFFS_BUFPOS_LOW, xl std Y+COM2W_IFACE_OFFS_BUFPOS_HIGH, xh inc r18 std Y+COM2W_IFACE_OFFS_BUFUSED, r18 dec r17 std Y+COM2W_IFACE_OFFS_BUFLEFT, r17 breq com2wnByteRecvd_msgComplete cpi r18, 2 sec brne com2wnByteRecvd_end ; determine msg size inc r16 ; last byte was payload length, add byte for crc cp r17, r16 ; compare remaining length against remaining space brcs com2wnByteRecvd_eMsgSize std Y+COM2W_IFACE_OFFS_BUFLEFT, r16 tst r16 sec brne com2wnByteRecvd_end com2wnByteRecvd_msgComplete: push r19 ; pushing these registers is now only needed *here* for every push r20 ; message received. Otherwise they would have been pushed push r24 ; on every bit adding much more execution time to the push r25 ; irq service routine push zl push zh rcall com2wnMsgReceived ; (R16, R17, R18, R19, R20, R24, R25, X, Z) pop zh pop zl pop r25 pop r24 pop r20 pop r19 rjmp com2wnByteRecvd_end com2wnByteRecvd_overflow: ldi r16, NET_IFACE_OFFS_ERR_MISSED_LOW rjmp com2wnByteRecvd_error com2wnByteRecvd_eMsgSize: ldi r16, NET_IFACE_OFFS_ERR_MSGSIZE_LOW com2wnByteRecvd_error: push r24 push r25 rcall NET_Interface_IncCounter16 ; (R24, R25) pop r25 pop r24 ldi r16, COM2W_MODE_SKIPPING ; error, enter skipping mode rcall com2wSetMode clc com2wnByteRecvd_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnMsgReceived ; ; @param Y pointer to interface data in SRAM ; @return CFLAG set if okay, cleared on error ; @clobbers R16, R17, R18, X, Z (R19, R20, R24, R25) com2wnMsgReceived: mov xl, yl mov xh, yh adiw xh:xl, COM2W_IFACE_OFFS_BUFFER mov zl, xl ; Z=buffer in IFACE mov zh, xh rcall NETMSG_CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X) brcc com2wnMsgReceived_econtent ; msg valid, alloc buffer rcall NET_Buffer_Alloc ; X=buffer, R16=bufnum (R16, R17, X) brcc com2wnMsgReceived_enobuf mov r18, r16 ; buffer num rcall NET_Interface_SetIfaceNumInBuffer ; (R16, R17) adiw xh:xl, 1 ; skip buffer header ldd r17, Y+COM2W_IFACE_OFFS_BUFUSED ; always is at least 2 here com2wnMsgReceived_copyLoop: ld r16, Z+ st X+, r16 dec r17 brne com2wnMsgReceived_copyLoop mov r16, r18 ; buffer num rcall NET_AddIncomingMsgNum ; (R17, R18, X) brcc com2wnMsgReceived_enoadd ldi r16, NET_IFACE_OFFS_PACKETSIN_LOW rcall NET_Interface_IncCounter16 ; (R24, R25) sec rjmp com2wnMsgReceived_setIdleAndEnd com2wnMsgReceived_enoadd: rcall NET_Buffer_ReleaseByNum rjmp com2wnMsgReceived_enobuf com2wnMsgReceived_enobuf: ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW rjmp com2wnMsgReceived_err com2wnMsgReceived_econtent: ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW com2wnMsgReceived_err: rcall NET_Interface_IncCounter16 ; (R24, R25) clc com2wnMsgReceived_setIdleAndEnd: ldi r16, COM2W_MODE_IDLE rcall com2wSetMode ; (R17, doesn't change CFLAG!) com2wnMsgReceived_end: ret ; @end #endif ; AVR_MODULES_COM2W_COM2WN_RECV_H