Files
aqhomecontrol/avr/modules/com2w/com2wn_recv.asm
2025-09-01 23:25:02 +02:00

245 lines
6.9 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. *
; ***************************************************************************
#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:
push r16
rcall LedActivity_Trigger
pop r16
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