Files
aqhomecontrol/avr/modules/com2w/com2wn_run.asm
Martin Preuss d9e7d4df81 com2w*: allow for higher frequencies than 8MHz
to be used with node S03, which is run at 20MHz.
2025-08-18 18:04:30 +02:00

428 lines
10 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_RUN_H
#define AVR_MODULES_COM2W_COM2WN_RUN_H
; WORK IN PROGRESS
.cseg
; ---------------------------------------------------------------------------
; @routine COM2WN_Run
;
; @return CFLAG set if something done, cleared otherwise
; @clobbers all
COM2WN_Run:
clr r16
; first handle lowlevel (e.g. handle all CLK changes and DATA from ringbuffer)
COM2WN_Run_loop1:
push r16
rcall com2wnLowLevelRun
pop r16
brcc COM2WN_Run_handleRunModes
rcall com2wnSetR16OnCarrySet
rjmp COM2WN_Run_loop1
; then handle messages etc
COM2WN_Run_handleRunModes:
ldi r19, COM_PORTS
ldi yl, LOW(com2w0_iface) ; first interface
ldi yh, HIGH(com2w0_iface)
COM2WN_Run_loop2:
push r16
push r19
rcall com2wnRunMode ; (clobbers possibly all but Y)
pop r19
pop r16
rcall com2wnSetR16OnCarrySet
ldi r20, COM2W_IFACE_SIZE
add yl, r20
adc yh, r20
sub yh, r20
dec r19
brne COM2WN_Run_loop2
tst r16
clc
breq COM2WN_Run_ret
sec
COM2WN_Run_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnSetR16OnCarrySet
;
com2wnSetR16OnCarrySet:
brcc com2wnSetR16OnCarrySet_ret
ldi r16, 1
com2wnSetR16OnCarrySet_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine COM2WN_Periodically
;
COM2WN_Periodically:
ldi r19, COM_PORTS
ldi yl, LOW(com2w0_iface) ; first interface
ldi yh, HIGH(com2w0_iface)
COM2WN_Periodically_loop: ; loop through all interfaces
push r19
rcall com2wPeriodically ; (R16)
pop r19
ldi r20, COM2W_IFACE_SIZE
add yl, r20
adc yh, r20
sub yh, r20
dec r19
brne COM2WN_Periodically_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnLowLevelRun
;
com2wnLowLevelRun:
.if COM_DATA_INPUT == COM_CLK_INPUT
; begin routine for single port
ldi yl, LOW(com2wnIoRingBuffer)
ldi yh, HIGH(com2wnIoRingBuffer)
rcall RingBufferY_ReadByteGuarded ; (R17, R18, X)
brcc com2wnLowLevelRun_ret
lds r18, com2wnIoCurrentClockStates
eor r18, r16 ; r18: changed bits in clk states
sts com2wnIoCurrentClockStates, r16 ; store new state
; r16=clock byte, r17=data byte, r18=clock change byte
ldi r19, COM_PORTS
ldi yl, LOW(com2w0_iface) ; first interface
ldi yh, HIGH(com2w0_iface)
com2wnLowLevelRun_loop: ; loop through all interfaces
ldd r20, Y+COM2W_IFACE_OFFS_PINMASK_CLK
mov r21, r20
and r21, r18 ; CLK for interface changed?
breq com2wnLowLevelRun_nextIface
push r16
push r18
push r19
mov r17, r16 ; same byte on onePort system
rcall com2wnActOnClock ; (r16, r17, r18, X)
pop r19
pop r18
pop r16
com2wnLowLevelRun_nextIface:
ldi r20, COM2W_IFACE_SIZE
add yl, r20
adc yh, r20
sub yh, r20
dec r19
brne com2wnLowLevelRun_loop
sec
com2wnLowLevelRun_ret:
ret
; end routine for single port
.else
; begin routine for double port
ldi yl, LOW(com2wnIoRingBuffer)
ldi yh, HIGH(com2wnIoRingBuffer)
push r15
in r15, SREG
cli
rcall RingBufferY_ReadByte ; (R17, R18, X)
brcc com2wnLowLevelRun_popr15Ret
push r16
rcall RingBufferY_ReadByte ; (R17, R18, X)
mov r17, r16
pop r16
out SREG, r15
pop r15
lds r18, com2wnIoCurrentClockStates
eor r18, r16 ; r18: changed bits in clk states
sts com2wnIoCurrentClockStates, r16 ; store new state
; r16=clock byte, r17=data byte, r18=clock change byte
ldi r19, COM_PORTS
ldi yl, LOW(com2w0_iface) ; first interface
ldi yh, HIGH(com2w0_iface)
com2wnLowLevelRun_loop: ; loop through all interfaces
ldd r20, Y+COM2W_IFACE_OFFS_PINMASK_CLK
mov r21, r20
and r21, r18 ; CLK for interface changed?
breq com2wnLowLevelRun_nextIface
push r16
push r18
push r19
rcall com2wnActOnClock ; (r16, r17, r18, X)
pop r19
pop r18
pop r16
com2wnLowLevelRun_nextIface:
ldi r20, COM2W_IFACE_SIZE
add yl, r20
adc yh, r20
sub yh, r20
dec r19
brne com2wnLowLevelRun_loop
sec
rjmp com2wnLowLevelRun_ret
com2wnLowLevelRun_popr15Ret:
out SREG, r15
pop r15
clc
com2wnLowLevelRun_ret:
ret
; end routine for double port
.endif
; @end
; ---------------------------------------------------------------------------
; @routine com2wPeriodically @global
;
; @param Y pointer to interface data
; @clobbers R16
com2wPeriodically:
push r15
in r15, SREG
cli
rcall NET_Interface_Periodically ; (R16)
ldd r16, Y+COM2W_IFACE_OFFS_MODECOUNTER
inc r16
breq com2wPeriodically_end
std Y+COM2W_IFACE_OFFS_MODECOUNTER, r16
com2wPeriodically_end:
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wSetMode
;
; Doesn't change processor status flags!
;
; @param R16 mode
; @clobbers R17
com2wSetMode:
push r15
in r15, SREG
cli
ldd r17, Y+COM2W_IFACE_OFFS_MODE
cp r16, r17
breq com2wSetMode_end
std Y+COM2W_IFACE_OFFS_MODE, r16
clr r17
std Y+COM2W_IFACE_OFFS_MODECOUNTER, r17
com2wSetMode_end:
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnStartReading
;
; @param Y pointer to interface data in SRAM
; @clobbers R16, R17, X
com2wnStartReading:
mov xl, yl
mov xh, yh
adiw xh:xl, COM2W_IFACE_OFFS_BUFFER
std Y+COM2W_IFACE_OFFS_BUFPOS_LOW, xl
std Y+COM2W_IFACE_OFFS_BUFPOS_HIGH, xh
ldi r16, COM2W_BUFFER_SIZE
std Y+COM2W_IFACE_OFFS_BUFLEFT, r16
clr r16
std Y+COM2W_IFACE_OFFS_BUFUSED, r16
ldi r16, COM2W_MODE_READING
rcall com2wSetMode ; (R17)
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnRunMode
;
; @param Y pointer to interface data in SRAM
; @clobbers all
com2wnRunMode:
cpi r16, COM2W_MODE_NUM
brcs com2wnRunMode_jump
ldi r16, COM2W_MODE_IDLE ; unknown mode, set to idle
rcall com2wSetMode ; (R17)
sec
ret
com2wnRunMode_jump:
ldi zl, LOW(com2wnModeJumpTable)
ldi zh, HIGH(com2wnModeJumpTable)
add zl, r16
adc zh, r16
sub zh, r16
ijmp
com2wnModeJumpTable:
rjmp com2wnRunIdle
rjmp com2wnRunReading
rjmp com2wnRunSkipping
rjmp com2wnRunWriting
; @end
; ---------------------------------------------------------------------------
; @routine com2wnRunIdle
;
; @param Y pointer to interface data in SRAM
; @clobbers R16, R17, R22, R24, R25, X
com2wnRunIdle:
;rjmp com2wnRunIdle_end ; DEBUG
push r15
in r15, SREG
cli
; look for outbound message
rcall NET_Interface_PeekNextOutgoingMsgNum ; r16=msgNum
brcs com2wnRunIdle_haveMsg
out SREG, r15
pop r15
clc
rjmp com2wnRunIdle_end
com2wnRunIdle_haveMsg:
mov r24, r16
ldi r16, COM2W_MODE_WRITING
rcall com2wSetMode ; (R17)
mov r16, r24
out SREG, r15
pop r15
push r16
rcall NET_Buffer_Locate ; (R17)
adiw xh:xl, 1
rcall com2wnSendMsg ; (R16, R17, R22, R24, R25, X)
push r15
in r15, SREG ; save SREG (no CLI, we want to save CFLAG only)
ldi r16, COM2W_MODE_IDLE
rcall com2wSetMode ; (R17)
out SREG, r15 ; restore SREG
pop r15
pop r16
brcc com2wnRunIdle_end
push r15
in r15, SREG
cli
rcall NET_Interface_GetNextOutgoingMsgNum ; take current msg off the queue
rcall NET_Buffer_ReleaseByNum ; (R16, X)
out SREG, r15
pop r15
sec
com2wnRunIdle_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnRunReading
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wnRunReading:
; check for timeout (Y+NET_IFACE_OFFS_READTIMER)
ldd r16, Y+NET_IFACE_OFFS_READTIMER
cpi r16, COM2W_READING_MAXREADCOUNTER
brcc com2wnRunReading_goIdle
ldd r16, Y+COM2W_IFACE_OFFS_MODECOUNTER
cpi r16, COM2W_READING_MAXMODECOUNTER
brcc com2wnRunReading_goIdle
clc
rjmp com2wnRunReading_end
com2wnRunReading_goIdle:
ldi r16, NET_IFACE_OFFS_ERR_IO_LOW
rcall NET_Interface_IncCounter16 ; (R24, R25)
ldi r16, COM2W_MODE_IDLE
rcall com2wSetMode ; (r17)
sec
com2wnRunReading_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnRunSkipping
;
; @param Y pointer to interface data in SRAM
; @clobbers r16 (r17)
com2wnRunSkipping:
; check for timeout (Y+NET_IFACE_OFFS_READTIMER)
ldd r16, Y+NET_IFACE_OFFS_READTIMER
cpi r16, COM2W_SKIPPING_MAXREADCOUNTER
brcc com2wnRunSkipping_goIdle
ldd r16, Y+COM2W_IFACE_OFFS_MODECOUNTER
cpi r16, COM2W_SKIPPING_MAXMODECOUNTER
brcc com2wnRunSkipping_goIdle
clc
rjmp com2wnRunSkipping_end
com2wnRunSkipping_goIdle:
ldi r16, COM2W_MODE_IDLE
rcall com2wSetMode ; (r17)
sec
com2wnRunSkipping_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnRunWriting
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wnRunWriting:
; TODO: check for timeout
clc
ret
; @end
#endif ; AVR_MODULES_COM2W_COM2WN_RUN_H