avr: started adding com2wn module (multiple com2w devices in one)

This commit is contained in:
Martin Preuss
2025-08-03 00:55:52 +02:00
parent 6c5dc21f6a
commit 8c13f9fdf7
8 changed files with 1305 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
; ***************************************************************************
; 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_DATA_H
#define AVR_MODULES_COM2W_COM2WN_DATA_H
.dseg
com2wnIoRingBuffer: .byte RINGBUFFERY_SIZE+COM2WN_IO_RINGBUFFER_SIZE
com2wnIoCurrentClockStates: .byte 1
com2wnIoLastClockStates: .byte 1
com2wnIoFlags: .byte 1
.if COM_PORTS >0
com2w0_iface: .byte COM2W_IFACE_SIZE
.endif
.if COM_PORTS >1
com2w1_iface: .byte COM2W_IFACE_SIZE
.endif
.if COM_PORTS >2
com2w2_iface: .byte COM2W_IFACE_SIZE
.endif
.if COM_PORTS >3
com2w3_iface: .byte COM2W_IFACE_SIZE
.endif
.if COM_PORTS >4
com2w4_iface: .byte COM2W_IFACE_SIZE
.endif
.if COM_PORTS >5
com2w5_iface: .byte COM2W_IFACE_SIZE
.endif
.if COM_PORTS >6
com2w6_iface: .byte COM2W_IFACE_SIZE
.endif
.if COM_PORTS >7
com2w7_iface: .byte COM2W_IFACE_SIZE
.endif
#endif ; AVR_MODULES_COM2W_COM2WN_DATA_H

View File

@@ -0,0 +1,112 @@
; ***************************************************************************
; 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_INIT_H
#define AVR_MODULES_COM2W_COM2WN_INIT_H
; WORK IN PROGRESS
; ---------------------------------------------------------------------------
; @macro mCOM2WN_INIT
;
; @param @0 interface number (beginning with 0)
.macro mCOM2WN_INIT
ldi yl, LOW(com2w@0_iface)
ldi yh, HIGH(com2w@0_iface)
rcall com2wnInit
ldi r16, COM_MASK_CLK@0
std Y+COM2W_IFACE_OFFS_PINMASK_CLK, r16
ldi r16, COM_MASK_DATA@0
std Y+COM2W_IFACE_OFFS_PINMASK_DATA, r16
ldi r16, COM_MASK_IRQ@0
std Y+COM2W_IFACE_OFFS_PINMASK_IRQ, r16
.endmacro
; @end
.cseg
; ---------------------------------------------------------------------------
; @routine COM2WN_Init
;
COM2WN_Init:
ldi r16, 0xff ; start with all clock lines hi
sts com2wnIoCurrentClockStates, r16
sts com2wnIoLastClockStates, r16
clr r16
sts com2wnIoFlags, r16
ldi yl, LOW(com2wnIoRingBuffer)
ldi yh, HIGH(com2wnIoRingBuffer)
ldi r16, COM2WN_IO_RINGBUFFER_SIZE
rcall RingBufferY_Init ; (R17)
.if COM_PORTS >0
mCOM2WN_INIT 0
.endif
.if COM_PORTS >1
mCOM2WN_INIT 1
.endif
.if COM_PORTS >2
mCOM2WN_INIT 2
.endif
.if COM_PORTS >3
mCOM2WN_INIT 3
.endif
.if COM_PORTS >4
mCOM2WN_INIT 4
.endif
.if COM_PORTS >5
mCOM2WN_INIT 5
.endif
.if COM_PORTS >6
mCOM2WN_INIT 6
.endif
.if COM_PORTS >7
mCOM2WN_INIT 7
.endif
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wInit
;
com2wnInit:
rcall NET_Interface_Init ; (R16, R17, X)
ldi r16, COM2W_MODE_IDLE
rcall com2wSetMode ; (R17)
rcall com2wSetupLines
rcall com2wSetupIrq
ret
; @end
#endif ; AVR_MODULES_COM2W_COM2WN_INIT_H

View File

@@ -0,0 +1,165 @@
; ***************************************************************************
; 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_IO_H
#define AVR_MODULES_COM2W_COM2WN_IO_H
; WORK IN PROGRESS
.cseg
; ---------------------------------------------------------------------------
; @routine com2wSetupLines
com2wSetupLines:
; setup CLK line (as input, disable internal pull-up resistor)
rcall com2wClkSetHigh
.ifdef COM_CLK_PUE
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_CLK
com r16
inr r17, COM_CLK_PUE
and r17, r16
outr COM_CLK_PUE, r17
.endif
; setup DATA line (as input, disable internal pull-up resistor)
rcall com2wDataSetHigh
.ifdef COM_DATA_PUE
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_DATA
com r16
inr r17, COM_DATA_PUE
and r17, r16
outr COM_DATA_PUE, r17
.endif
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wClkSetHigh
;
; @clobbers none
com2wClkSetHigh:
push r16
push r17
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_CLK
; clear bit in io reg (AND with complement)
com r16
inr r17, COM_CLK_DDR
and r17, r16
outr COM_CLK_DDR, r17 ; make pin input
.ifndef COM_CLK_PUE
inr r17, COM_CLK_OUTPUT
and r17, r16 ; disable pullup
outr COM_CLK_OUTPUT, r17
.endif
pop r17
pop r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wClkSetLow
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wClkSetLow:
push r16
push r17
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_CLK
; set bit in io reg
inr r17, COM_CLK_DDR
or r17, r16
outr COM_CLK_DDR, r17 ; make pin output
com r16
inr r17, COM_CLK_OUTPUT
and r17, r16
outr COM_CLK_OUTPUT, r17 ; set pin low
pop r17
pop r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wDataSetHigh
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wDataSetHigh:
push r16
push r17
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_DATA
; clear bit in io reg (AND with complement)
com r16
inr r17, COM_DATA_DDR
and r17, r16
outr COM_DATA_DDR, r17 ; make pin input
.ifndef COM_DATA_PUE
inr r17, COM_DATA_OUTPUT
and r17, r16 ; disable pullup
outr COM_DATA_OUTPUT, r17
.endif
pop r17
pop r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wDataSetLow
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wDataSetLow:
push r16
push r17
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_DATA
; set bit in io reg
inr r17, COM_DATA_DDR
or r17, r16
outr COM_DATA_DDR, r17 ; make pin output
com r16
inr r17, COM_DATA_OUTPUT
and r17, r16
outr COM_DATA_OUTPUT, r17 ; set pin low
pop r17
pop r16
ret
; @end
#endif ; AVR_MODULES_COM2W_COM2WN_IO_H

View File

@@ -0,0 +1,165 @@
; ***************************************************************************
; 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_IRQ_H
#define AVR_MODULES_COM2W_COM2WN_IRQ_H
.cseg
; ---------------------------------------------------------------------------
; @routine com2wnSetupIrq
;
com2wnSetupIrq:
; setup pin-change interrupt for CLK
rcall com2wnEnableClkIrq
; enable and clear PCIE0/1 (@TODO put later into general setup)
inr r16, GIMSK ; enable pin change irq PCIE0 or PCIE1
sbr r16, (1<<COM_IRQ_GIMSK_CLK)
outr GIMSK, r16
ldi r16, (1<<COM_IRQ_GIFR_CLK) ; clear pending irq by writing 1 to GIFR bit
outr GIFR, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnEnableClkIrq
;
; @clobbers
com2wnEnableClkIrq:
push r16
push r17
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_IRQ
inr r17, COM_IRQ_ADDR_CLK
or r17, r16
outr COM_IRQ_ADDR_CLK, r17
pop r17
pop r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnDisableClkIrq
;
; @clobbers none
com2wnDisableClkIrq:
push r16
push r17
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_IRQ
com r16
inr r17, COM_IRQ_ADDR_CLK
and r17, r16 ; clear bit for clock line
outr COM_IRQ_ADDR_CLK, r17
pop r17
pop r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine COM2WN_ClkChangeOnePortIsr @global @isr
;
; Interrupt service routine for single port (i.e. one port contains all
; CLOCK and DATA bits like in node R05).
;
; @clobbers none
COM2WN_ClkChangeOnePortIsr:
push r15
in r15, SREG
push r16
inr r16, COM_CLK_INPUT ; read clk state early
push r17
push r18
push xl
push xh
push yl
push yh
ldi yl, LOW(com2wnIoRingBuffer)
ldi yh, HIGH(com2wnIoRingBuffer)
rcall RingBufferY_WriteByte ; (R17, R18, X)
brcs COM2WN_ClkChangeOnePortIsr_popRet
lds r16, com2wnIoFlags
ori r16, (1<<COM2W_IO_FLAGS_BIT_OVR)
sts com2wnIoFlags, r16
COM2WN_ClkChangeOnePortIsr_popRet:
pop yh
pop yl
pop xh
pop xl
pop r18
pop r17
pop r16
out SREG, r15
pop r15
reti
; @end
; ---------------------------------------------------------------------------
; @routine COM2WN_ClkChangeTwoPortIsr @global @isr
;
; Interrupt service routine for single port (i.e. one port contains all
; CLOCK and DATA bits like in node R05).
;
; @clobbers none
COM2WN_ClkChangeTwoPortIsr:
push r15
in r15, SREG
push r16
push r17
inr r16, COM_CLK_INPUT ; read clk state early
inr r17, COM_DATA_INPUT ; read data state early
push r18
push xl
push xh
push yl
push yh
ldi yl, LOW(com2wnIoRingBuffer)
ldi yh, HIGH(com2wnIoRingBuffer)
push r17
rcall RingBufferY_WriteByte ; push clk state (R17, R18, X)
pop r16 ; pop DATA input into r16 (from r17)
brcc COM2WN_ClkChangeTwoPortIsr_ovr
rcall RingBufferY_WriteByte ; push data state (R17, R18, X)
brcs COM2WN_ClkChangeTwoPortIsr_popRet
COM2WN_ClkChangeTwoPortIsr_ovr:
lds r16, com2wnIoFlags
ori r16, (1<<COM2W_IO_FLAGS_BIT_OVR)
sts com2wnIoFlags, r16
COM2WN_ClkChangeTwoPortIsr_popRet:
pop yh
pop yl
pop xh
pop xl
pop r18
pop r17
pop r16
out SREG, r15
pop r15
reti
; @end
#endif ; AVR_MODULES_COM2W_COM2WN_IRQ_H

View File

@@ -0,0 +1,242 @@
; ***************************************************************************
; 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:
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

View File

@@ -0,0 +1,289 @@
; ***************************************************************************
; 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 com2wnLowLevelRun
;
com2wnLowLevelRunOnePort:
ldi yl, LOW(com2wnIoRingBuffer)
ldi yh, HIGH(com2wnIoRingBuffer)
rcall RingBufferY_ReadByteGuarded ; (R17, R18, X)
brcc com2wnLowLevelRunOnePort_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)
com2wnLowLevelRunOnePort_loop: ; loop through all interfaces
ldd r20, Y+COM2W_IFACE_OFFS_PINMASK_CLK
mov r21, r20
and r21, r18 ; CLK for interface changed?
breq com2wnLowLevelRunOnePort_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
com2wnLowLevelRunOnePort_nextIface:
adiw yh:yl, COM2W_IFACE_SIZE
dec r19
brne com2wnLowLevelRunOnePort_loop
sec
com2wnLowLevelRunOnePort_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wPeriodically @global
;
; @clobbers R16, Y
com2wPeriodically:
push r15
in r15, SREG
cli
rcall NET_Interface_Periodically
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 com2w0SendMsg ; (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

View File

@@ -0,0 +1,154 @@
; ***************************************************************************
; 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_SEND_H
#define AVR_MODULES_COM2W_COM2WN_SEND_H
; WORK IN PROGRESS
.cseg
; ---------------------------------------------------------------------------
; @routine com2wSendMsg
;
; @param X pointer to bytes to send
; @param Y pointer to interface data in SRAM
; @return CFLAG set if message sent, cleared otherwise
; @clobbers R16, R18 (R20, R22, R24, R25, X)
com2wSendMsg:
ldi r20, 6 ; wait for about 60us for clock low
rcall com2wWaitForClockLowMulti10Us ; (R17, R20, R22)
brcs com2wSendMsg_busy ; CLK got low while waiting, so line is busy
push r15
in r15, SREG
cli ; atomic disable irq and set CLK low
rcall com2wDisableClkIrq ; (none)
rcall com2wClkSetLow ; reserve bus (none)
out SREG, r15
pop r15
adiw xh:xl, NETMSG_OFFS_MSGLEN
ld r18, X
sbiw xh:xl, NETMSG_OFFS_MSGLEN
inc r18 ; adjust for DESTADDR
inc r18 ; adjust for MSGLEN
inc r18 ; adjust for CRCBYTE
rcall com2wWaitTime1 ; longer wait period (R22)
rcall com2wSendBytes ; (r16, r17, r18, r22, X)
rcall com2wClkSetHigh ; make sure bus is released
rcall com2wDataSetHigh
rcall com2wEnableClkIrq ; (none)
ldi r16, NET_IFACE_OFFS_PACKETSOUT_LOW
rcall NET_Interface_IncCounter16 ; (R24, R25)
sec
ret
com2wSendMsg_busy:
ldi r16, NET_IFACE_OFFS_ERR_BUSY_LOW
rcall NET_Interface_IncCounter16 ; (R24, R25)
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wSendBytes
;
; @param R18 number of bytes to send
; @param X pointer to bytes to send
; @param Y pointer to interface data in SRAM
; @clobbers: r16, r18, X (r17, r22)
com2wSendBytes:
com2wSendBytes_loop:
rcall com2wClkSetLow ; (none)
rcall com2wWaitTime1 ; longer wait period (R22)
ld r16, X+
rcall com2wSendByte ; (R16, R17, R22)
dec r18
brne com2wSendBytes_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wSendByte
;
; @param R16 byte to send
; @param Y pointer to interface data in SRAM
; @clobbers r16, r17 (r22)
com2wSendByte:
ldi r17, 8
com2wSendByte_loop:
rcall com2wClkSetLow
rcall com2wWaitTime1 ; longer wait period (R22)
lsr r16
brcs com2wSendByte_send1
rcall com2wDataSetLow
rjmp com2wSendByte_sent
com2wSendByte_send1:
rcall com2wDataSetHigh
com2wSendByte_sent:
rcall com2wWaitTime2 ; shorter wait period (R22)
push r15
in r15, SREG
cli ; ensure time period by disabling irqs
rcall com2wClkSetHigh
rcall com2wWaitTime1 ; longer wait period (R22)
out SREG, r15
pop r15
dec r17
brne com2wSendByte_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wWaitTime1
;
; waits for longer period (e.g. 30ns)
;
; @clobbers R22
com2wWaitTime1:
Utils_WaitNanoSecs COM2W_WAITTIME1, 7, r22 ; wait for longer time (minus RCALL and RET)
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wWaitTime2
;
; waits for shorter period (e.g. 10ns)
;
; @clobbers R22
com2wWaitTime2:
Utils_WaitNanoSecs COM2W_WAITTIME2, 7, r22 ; wait for shorter time (minus RCALL and RET)
ret
; @end
#endif ; AVR_MODULES_COM2W_COM2WN_SEND_H

View File

@@ -0,0 +1,119 @@
; ***************************************************************************
; 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_WAIT_H
#define AVR_MODULES_COM2W_COM2WN_WAIT_H
; WORK IN PROGRESS
.cseg
; ---------------------------------------------------------------------------
; @routine com2wWaitForClockHighMulti10Us
;
; Wait for high CLK
;
; @param R20 multiple of 10us to wait (e.g. "2" for "20" us, max: 32)
; @return CFLAG set if okay (state reached), cleared on error
; @clobbers: r16, r20, r22
com2wWaitForClockHighMulti10Us:
.if clock == 8000000
add r20, r20 ; *2
add r20, r20 ; *4
add r20, r20 ; *8
.endif
.elif clock == 1000000
; nothing to do
.else
.error "Unhandled clock speed"
.endif
ldd r22, Y+COM2W_IFACE_OFFS_PINMASK_CLK ; +2
com2wWaitForClockHighMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
brne com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
brne com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
nop ; +1
dec r20 ; +1
brne com2wWaitForClockHighMulti10Us_loop ; +2 if TRUE, +1 if FALSE
clc ; +1
ret ; +4
com2wWaitForClockHighMulti10Us_stateReached:
sec ; +1
ret ; +4
; @end
; ---------------------------------------------------------------------------
; @routine com2wWaitForClockLowMulti10Us
;
; Wait for low CLK
;
; @param R20 multiple of 10us to wait (e.g. "2" for "20" us, max: 32)
; @return CFLAG set if okay (state reached), cleared on error
; @clobbers: r16, r20, r22
com2wWaitForClockLowMulti10Us:
.if clock == 8000000
add r20, r20 ; *2
add r20, r20 ; *4
add r20, r20 ; *8
.endif
.elif clock == 1000000
; nothing to do
.else
.error "Unhandled clock speed"
.endif
ldd r22, Y+COM2W_IFACE_OFFS_PINMASK_CLK ; +2
com2wWaitForClockLowMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockLowMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockLowMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
nop ; +1
dec r20 ; +1
brne com2wWaitForClockLowMulti10Us_loop ; +2 if TRUE, +1 if FALSE
clc ; +1
ret ; +4
com2wWaitForClockLowMulti10Us_stateReached:
sec ; +1
ret ; +4
; @end
#endif ; AVR_MODULES_COM2W_COM2WN_WAIT_H