Files
aqhomecontrol/avr/com.asm
2023-04-05 23:39:45 +02:00

963 lines
26 KiB
NASM

; ***************************************************************************
; defines
.equ COM_MAXWAIT = 200 ; maximum loop count when waiting for rising/falling clock (TODO: Make frequency-dependant)
.equ COM_MAINTENANCE_ADDR = 0xf1
.equ COM_BUFFER_FLAGS_DONE = 0x80
.equ COM_BUFFER_FLAGS_RECEIVED = 0x40
.equ COM_BUFFER_FLAGS_TOSEND = 0x20
.equ COM_BUFFER_FLAGS_RELEASED = 0x10
.equ COM_BUFFER_FLAGS_PRIO1 = 0x08
.equ COM_BUFFER_FLAGS_PRIO0 = 0x04
.equ COM_BUFFER_FLAGS_IFACE1 = 0x02
.equ COM_BUFFER_FLAGS_IFACE0 = 0x01
.equ COM_BUFFER_PRIO_INFO = 0
.equ COM_BUFFER_PRIO_NORMAL = COM_BUFFER_FLAGS_PRIO0
.equ COM_BUFFER_PRIO_IMPORTANT = COM_BUFFER_FLAGS_PRIO1
.equ COM_BUFFER_PRIO_VITAL = (COM_BUFFER_FLAGS_PRIO0 | COM_BUFFER_FLAGS_PRIO1)
.equ COM_REPEAT_INFO = 3
.equ COM_REPEAT_NORMAL = 32
.equ COM_REPEAT_IMPORTANT = 64
.equ COM_REPEAT_VITAL = 255
.equ COM_BUFFER_NUM = 6
.equ COM_BUFFER_SIZE = 24 ; CAVE: Need to change routine COM_BufferPosToY when changing this value!!
.equ COM_BUFFER_OFFS_FLAGS = 0 ; first byte in buffer is flags byte
.equ COM_BUFFER_OFFS_DATA = 1
.equ COM_MSG_OFFS_DESTADDR = 0
.equ COM_MSG_OFFS_MSGLEN = 1
.equ COM_MSG_OFFS_MSGDATA = 2
.equ COM_MSG_OFFS_CMD = 2 ; first at COM_MSG_OFFS_MSGDATA
.equ COM_MSG_OFFS_SRCADDR = 3
.equ COM_MSG_OFFS_PAYLOAD = 4 ; payload for the cmd follows here
.equ COM_ERR_NOTFORME = 1
.equ COM_ERR_CHECKSUM = 2
.equ COM_ERR_IO = 3
; ***************************************************************************
; data
.dseg
comDataBegin:
comFlags: .byte 1
comAddress: .byte 1
comRepeatCount: .byte 1
comReserved1: .byte 1
comStatsPacketsIn: .byte 2
comStatsPacketsOut: .byte 2
comStatsRecvErrs: .byte 2
comStatsCollisions: .byte 2
comStatsMissed: .byte 2
comStatsAborted: .byte 2
comStatsIgnored: .byte 2
comStatsHandled: .byte 2
comRecvBuffersReadPos: .byte 1
comRecvBuffersWritePos: .byte 1
comRecvBuffersUsed: .byte 1
comRecvBuffers: .byte (COM_BUFFER_SIZE*COM_BUFFER_NUM)
comDataEnd:
; ***************************************************************************
; code
.cseg
comIsrPcint0:
push r15
in r15, SREG
sbic COM_PIN_ATTN, COM_PINNUM_ATTN
rjmp comIsrPcint0_end
; low, read packet
push r1
push r16
push r17
push r18
push r19
push r20
push r21
push r22
push xh
push xl
push yh
push yl
rcall comReceivePacketHandleBuffer ; (R1, R16, R17, R18, R19, R20, R21, R22, X, Y
pop yl
pop yh
pop xl
pop xh
pop r22
pop r21
pop r20
pop r19
pop r18
pop r17
pop r16
pop r1
comIsrPcint0_end:
pop r15
reti
; ---------------------------------------------------------------------------
; Com_Init
;
; IN:
; OUT:
; - CFLAG: set if okay, clear on error
; USED: R16, R17, X, Y
Com_Init:
; preset SRAM data area
ldi xh, HIGH(comDataBegin)
ldi xl, LOW(comDataBegin)
clr r16
ldi r17, (comDataEnd-comDataBegin)
rcall Utils_FillSram
; set address to 0 (will be updated later)
clr r16
sts comAddress, r16
; setup pins and interrupts
cbi COM_PORT_DATA, COM_PINNUM_DATA ; disable internal pullup for DATA
cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input
cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable internal pullup for ATTN
cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN port as input
sbi COM_IRQ_ADDR_ATTN, COM_IRQ_BIT_ATTN ; enable pin change irq for ATTN line
in r16, GIMSK ; enable pin change irq PCIE0 or PCIE1
ori r16, (1<<COM_IRQ_GIMSK_ATTN)
out GIMSK, R16
in r16, GIFR ; clear pending irq
andi r16, ~(1<<COM_IRQ_GIFR_ATTN)
out GIFR, r16
sec
ret
; ---------------------------------------------------------------------------
; Com_Run
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry)
; REGS: (R1, R3, R16, R17, R18, R19, R22, X)
Com_Run:
rcall comHandleNextPacketInQueue ; nothing more than handling packages in ringbuffer
; clc
ret
; ---------------------------------------------------------------------------
; Mark a packet as enqueued.
;
; IN:
; - Y: pointer to buffer containing the enqueued packet
; - R20: priority
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R15, R16
COM_EnqueuePacket:
in r15, SREG
cli
ldd r16, y+COM_BUFFER_OFFS_FLAGS
andi r16, (~(COM_BUFFER_FLAGS_PRIO1 | COM_BUFFER_FLAGS_PRIO0 | COM_BUFFER_FLAGS_RECEIVED | COM_BUFFER_FLAGS_DONE)) & 0xff
or r16, r20 ; add priority
ori r16, COM_BUFFER_FLAGS_TOSEND
std y+COM_BUFFER_OFFS_FLAGS, r16
out SREG, r15 ; restore IRQ flag
sec
ret
; ---------------------------------------------------------------------------
; COM_AllocBufferAndGetXY
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; - Y: pointer to buffer
; - X: pointer to data portion of the buffer
; MODIFIED REGS: R16, R17 (R21)
COM_AllocBufferAndGetXY:
rcall COM_BufferAlloc ; (r16, r17, r21)
brcc COM_AllocBufferAndGetXY_error
mov xl, yl
mov xh, yh
ldi r16, COM_BUFFER_OFFS_DATA
clr r17
add xl, r16
adc xh, r17
sec
ret
COM_AllocBufferAndGetXY_error:
clc
ret
; ---------------------------------------------------------------------------
; comHandleNextPacketInQueue
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry)
; MODIFIED REGS: R16, R17, Y (R15, R18, R21, R22, X)
comHandleNextPacketInQueue:
lds r16, comRecvBuffersUsed
tst r16
breq comHandleNextPacketInQueue_retNc ; no buffers in use
lds r16, comRecvBuffersReadPos
rcall COM_BufferPosToY ; get current read buffer to Y (R16, R17)
ldd r16, y+COM_BUFFER_OFFS_FLAGS ; get flags
; check for released buffer (dealloc)
mov r17, r16
andi r17, COM_BUFFER_FLAGS_RELEASED ; check for buffer released
brne comHandleNextPacketInQueue_releaseBuffer
; check for received packet
mov r17, r16
andi r17, COM_BUFFER_FLAGS_RECEIVED
brne comHandleNextPacketInQueue_receivedPacket
; check for buffer to send
mov r17, r16
andi r17, COM_BUFFER_FLAGS_TOSEND ; check for message to send
brne comHandleNextPacketInQueue_sendPacket
; nothing to do (e.g. buffer not ready to be sent)
rjmp comHandleNextPacketInQueue_retNc
comHandleNextPacketInQueue_sendPacket:
rcall comSendPacketHandleRepeat ; (R15, R16, R17, R18, R21, R22, X)
ret ; use CFLAG from subroutine
comHandleNextPacketInQueue_receivedPacket:
clr r17
sts comRepeatCount, r17 ; set comRepeatCount to zero
rcall comHandleReceivedPacket ; (r16, r17, r21, X)
sec ; always return with set CFLAG
ret
comHandleNextPacketInQueue_releaseBuffer:
rcall COM_BufferDeallocFront
sec ; always return with set CFLAG
ret
comHandleNextPacketInQueue_retNc:
clc
ret
; ---------------------------------------------------------------------------
; comHandleReceivedPacket
;
; IN:
; - Y: pointer to current buffer (pointed to by comRecvBuffersReadPos)
; OUT:
; - nothing
; MODIFIED REGS: X (r16, r17, r21)
comHandleReceivedPacket:
rcall onPacketReceived
brcs comHandleReceivedPacket_l1
ldi xl, LOW(comStatsIgnored)
ldi xh, HIGH(comStatsIgnored)
rjmp comHandleReceivedPacket_l2
comHandleReceivedPacket_l1:
ldi xl, LOW(comStatsHandled)
ldi xh, HIGH(comStatsHandled)
comHandleReceivedPacket_l2:
rcall comDeallocReadBufAndIncrCounter ; (r16, r17, r21)
ret
; ---------------------------------------------------------------------------
; comSendPacketHandleRepeat
;
; IN:
; - Y: pointer to current buffer (pointed to by comRecvBuffersReadPos)
; OUT:
; - CFLAG: set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry)
; MODIFIED REGS: R15, R17, R22, X (R16, R17, R18, R21, R22)
comSendPacketHandleRepeat:
in r15, SREG
cli
cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable pullup on ATTN
cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as input
nop ; needed to sample current input
sbis COM_PIN_ATTN, COM_PINNUM_ATTN ; ATTN low?
rjmp comSendPacketHandleRepeat_adjustRepeat ; jump if it is
ldd r16, y+COM_BUFFER_OFFS_FLAGS
rcall comSetupRepeat ; setup comRepeatCount if not already done (R16, R17)
cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; set ATTN low
sbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as output
Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration
rcall comSendPacketHandleBuffer ; (R16, R17, R21, R22)
cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; release ATTN line (by setting direction to IN)
brcc comSendPacketHandleRepeat_collision
; packet sent, adjust stats, release buffer
ldi xl, LOW(comStatsPacketsOut)
ldi xh, HIGH(comStatsPacketsOut)
rcall comDeallocReadBufAndIncrCounter ; (r16, r17, r18)
rjmp comSendPacketHandleRepeat_retC
comSendPacketHandleRepeat_collision:
; increment collisions counter
ldi xl, LOW(comStatsCollisions)
ldi xh, HIGH(comStatsCollisions)
ldi r22, 1
ld r16, x+
ld r17, x
add r16, r22
dec r22
adc r17, r22
st x, r17
st -x, r16
comSendPacketHandleRepeat_adjustRepeat:
; decrement repeat counter (except for vital messages)
lds r17, comRepeatCount
cpi r17, COM_REPEAT_VITAL
breq comSendPacketHandleRepeat_retNC ; vital message, repeat forever
dec r17
sts comRepeatCount, r17
brne comSendPacketHandleRepeat_retNC
; dealloc buffer, inc abort counter
ldi xl, LOW(comStatsAborted)
ldi xh, HIGH(comStatsAborted)
rcall comDeallocReadBufAndIncrCounter
rjmp comSendPacketHandleRepeat_retC
comSendPacketHandleRepeat_retNC:
out SREG, r15
clc
ret
comSendPacketHandleRepeat_retC:
out SREG, r15
sec
ret
; ---------------------------------------------------------------------------
; comSetupRepeat
;
; IN:
; - R16: priority
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17
comSetupRepeat:
lds r17, comRepeatCount
tst r17
brne comSetupRepeat_l99 ; comRepeatCount already setup
; set comRepeatCount according to priority
andi r16, (COM_BUFFER_FLAGS_PRIO1 | COM_BUFFER_FLAGS_PRIO0) ; r16: flags
cpi r16, COM_REPEAT_INFO
brne comSetupRepeat_l1
ldi r17, COM_REPEAT_INFO
rjmp comSetupRepeat_l98
comSetupRepeat_l1:
cpi r16, COM_REPEAT_NORMAL
brne comSetupRepeat_l2
ldi r17, COM_REPEAT_NORMAL
rjmp comSetupRepeat_l98
comSetupRepeat_l2:
cpi r16, COM_REPEAT_IMPORTANT
brne comSetupRepeat_l3
ldi r17, COM_REPEAT_IMPORTANT
rjmp comSetupRepeat_l98
comSetupRepeat_l3:
ldi r17, COM_REPEAT_VITAL
comSetupRepeat_l98:
sts comRepeatCount, r17
comSetupRepeat_l99:
ret
; ---------------------------------------------------------------------------
; comDeallocReadBufAndIncrCounter
;
; IN:
; - X : pointer to counter
; OUT:
; - nothing
; REGS: r16, r17, r21
comDeallocReadBufAndIncrCounter:
rcall COM_BufferDeallocFront ; (r16, r17, r21)
ldi r21, 1
ld r16, x+
ld r17, x
add r16, r21
dec r21
adc r17, r21
st x, r17
st -x, r16
sts comRepeatCount, r21 ; set comRepeatCount to zero
ret
; ---------------------------------------------------------------------------
; comSendPacketHandleBuffer
;
; Send a packet from the current read buffer (pointed to by comRecvBuffersReadPos).
; On success the flag COM_BUFFER_FLAGS_DONE is set in the buffer.
; The buffer is not released.
;
; CAVE: Expects interrupts to be disabled!
;
; IN:
; - Y : pointer to current read buffer
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17 (R21, R22)
comSendPacketHandleBuffer:
mov xl, yl
mov xh, yh
ldi r16, COM_BUFFER_OFFS_DATA
clr r17
add xl, r16
adc xh, r17
ldd r16, y+(COM_BUFFER_OFFS_DATA+COM_MSG_OFFS_MSGLEN) ; get msg payload length
ldi r17, 3
add r16, r17 ; add dest addr, msg len and XOR byte
rcall comSendPacketFromSram ; send all that
brcc comSendPacketHandleBuffer_error
ldd r16, y+COM_BUFFER_OFFS_FLAGS
ori r16, COM_BUFFER_FLAGS_DONE
std y+COM_BUFFER_OFFS_FLAGS, r16
sec
ret
comSendPacketHandleBuffer_error:
clc
ret
; ---------------------------------------------------------------------------
; comSendPacketFromSram
;
; Send a packet from SRAM
;
; IN:
; - R16: number of bytes to send
; - X: pointer to buffer to read from
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17 (R21, R22)
comSendPacketFromSram:
mov r17, r16
comSendPacketFromSram_loop:
ld r16, X+
rcall comSendByte ; send byte (R16, R21, R22)
brcc comSendPacketFromSram_error
dec r17
brne comSendPacketFromSram_loop
sec
ret
comSendPacketFromSram_error:
clc
ret
; ---------------------------------------------------------------------------
; comReceivePacketHandleBuffer
;
; Allocate a buffer and receive a packet into it.
; On success the buffer flags will have COM_BUFFER_FLAGS_RECEIVED set.
; On error the buffer will be deallocated.
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, cleared otherwise
; MODIFIED REGISTERS: R16, R17, X, Y (R1, R18, R19, R20, R21, R22)
comReceivePacketHandleBuffer:
rcall COM_BufferAlloc
brcc comReceivePacketHandleBuffer_error
; get pos of data portion for the allocated buffer
mov xl, yl
mov xh, yh
ldi r16, COM_BUFFER_OFFS_DATA
clr r17
add xl, r16
adc xh, r17
rcall comReceivePacketToSram ; (r1, r16, r17, R20, R21, R22, X)
brcc comReceivePacketHandleBuffer_dealloc
; handle buffer flags
ldi r16, COM_BUFFER_FLAGS_RECEIVED
std y+COM_BUFFER_OFFS_FLAGS, r16
ldi xl, LOW(comStatsPacketsIn)
ldi xh, HIGH(comStatsPacketsIn)
rcall Utils_IncrementCounter16 ; (r18, r19, 22)
sec
ret
comReceivePacketHandleBuffer_dealloc:
push r16
rcall COM_BufferDeallocBack ; (r16, r17, r21)
pop r16
cpi r16, COM_ERR_NOTFORME ; packet just not for me?
breq comReceivePacketHandleBuffer_notforme ; correct, don't count as error
ldi xl, LOW(comStatsRecvErrs)
ldi xh, HIGH(comStatsRecvErrs)
rcall Utils_IncrementCounter16 ; (r18, r19, 22)
comReceivePacketHandleBuffer_error:
clc
ret
comReceivePacketHandleBuffer_notforme: ; TODO: may count packets not for me?
clc
ret
; ---------------------------------------------------------------------------
; comReceivePacketToSram
;
; Receive a packet to the given SRAM position.
; IN:
; - X: pointer to start of buffer to receive bytes
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r1, r16, r17, X (R20, R21, R22)
comReceivePacketToSram:
clr r1 ; r1: checksum
; read destination address
rcall comReceiveByte ; read byte (R16, R17, R20, R21, R22)
brcc comReceivePacketToSram_error
eor r1, r16
; compare destination address (accept "0" and own address)
tst r16
breq comReceivePacketToSram_acceptAddr
cpi r16, 0xff
breq comReceivePacketToSram_acceptAddr
lds r17, comAddress
cp r16, r17
breq comReceivePacketToSram_acceptAddr
ldi r16, COM_ERR_NOTFORME
clc ; not for me
ret
comReceivePacketToSram_acceptAddr:
st X+, r16
; read msg length
rcall comReceiveByte ; read packet length (R16, R17, R20, R21, R22)
brcc comReceivePacketToSram_error
eor r1, r16
st X+, r16
cpi r16, (COM_BUFFER_SIZE-3-COM_BUFFER_OFFS_DATA)+1
brcc comReceivePacketToSram_error ; packet too long (TODO: count overruns)
tst r16
breq comReceivePacketToSram_readXOR
mov r17, r16
comReceivePacketToSram_loop:
push r17
rcall comReceiveByte ; read byte (R16, R17, R20, R21, R22)
pop r17
brcc comReceivePacketToSram_error
st X+, r16
eor r1, r16
dec r17
brne comReceivePacketToSram_loop
comReceivePacketToSram_readXOR:
rcall comReceiveByte ; XOR byte (R16, R17, R20, R21, R22)
brcc comReceivePacketToSram_error
st X+, r16
eor r1, r16
brne comReceivePacketToSram_error
sec
ret
comReceivePacketToSram_crcError:
ldi r16, COM_ERR_CHECKSUM
clc
ret
comReceivePacketToSram_error:
ldi r16, COM_ERR_IO
clc
ret
; ***************************************************************************
; lowlevel pin functions
; ---------------------------------------------------------------------------
; comSendByte
;
; Send a byte.
; We only set the data pin to low at the beginning for the startbit. After that
; we only change the pin direction (e.g. input vs output):
; - for 0 bit: set DDR to output, forcing the data line low
; - for 1 bit: set DDR to input, letting the external pullup R pull the data line to HIGH
; since the output pin is still set to 0 the internal pullup is disabled
; IN:
; - R16: byte to send
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R21, R22
comSendByte:
ldi r21, 8 ; +1 bits left
; send startbit
cbi COM_PORT_DATA, COM_PINNUM_DATA ; +2 set DATA low
sbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as output
Utils_WaitNanoSecs COM_BIT_LENGTH, 5, r22 ; wait for one bit duration
; send data bits
comSendByte_loop: ; 9 for low bit
lsr r16 ; 1+ bit to send -> CARRY
brcs comSendByte_setHigh ; HI: +2, LO: +1
comSendByte_setLow:
sbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as output
Utils_WaitNanoSecs COM_BIT_LENGTH, 9, r22
rjmp comSendByte_loopEnd ; +2
comSendByte_setHigh:
cbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as input, pullup R makes it ONE
nop ; +1 (to make pin change available)
Utils_WaitNanoSecs COM_BIT_LENGTH/2, 11, r22 ; wait for half a bit length for line to safely settle
sbis COM_PIN_DATA, COM_PINNUM_DATA ; +1 if no skip, +2 if skipped
rjmp comSendByte_error ; +2 if error (collision: we wanted line to be high but it is low)
Utils_WaitNanoSecs COM_BIT_LENGTH/2, 0, r22
comSendByte_loopEnd:
dec r21 ; +1
brne comSendByte_loop ; +2, sum per loop: 10 cycles
; send stopbit
cbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as input, pullup R makes it ONE
Utils_WaitNanoSecs COM_BIT_LENGTH, 4, r22 ; wait for one bit length
sec
ret
comSendByte_error:
clc
ret
; ---------------------------------------------------------------------------
; comReceiveByte
;
; Receive a byte.
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; - R16: byte read (if CFLAG set)
; MODIFIED REGS: R16, R20, R21, R22 (R17)
comReceiveByte:
cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input
cbi COM_PORT_DATA, COM_PINNUM_DATA ; disable internal pullup for DATA
ldi r21, 8 ; bits left
clr r20 ; byte currently receiving
; wait for startbit
rcall comWaitForDataLow ; (R17)
brcc comReceiveByte_error
Utils_WaitNanoSecs COM_BIT_LENGTH/2, 5, r22 ; goto middle of startbit to maximize sync stability
comReceiveByte_loop:
Utils_WaitNanoSecs COM_BIT_LENGTH, 8, r22 ; 8 cycles used in the complete loop between waits
sec ; +1
sbic COM_PIN_DATA, COM_PINNUM_DATA ; LOW: +2, HIGH: +1
rjmp comReceiveByte_shiftIn ; HIGH: +2, rjmp, use set CFLAG
clc ; LOW: +1
comReceiveByte_shiftIn:
ror r20 ; +1
dec r21 ; +1
brne comReceiveByte_loop ; +2, sum per loop: 8 cycles
rcall comWaitForDataHigh ; wait for start of stopbit
brcc comReceiveByte_error
mov r16, r20
sec
ret
comReceiveByte_error:
clc
ret
; ---------------------------------------------------------------------------
; comWaitForDataLow
;
; Waits up to COM_MAXWAIT loops for low data line
; IN:
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r17, r22
comWaitForDataLow:
ldi r17, COM_MAXWAIT
comWaitForDataLow_loop:
sbis COM_PIN_DATA, COM_PINNUM_DATA
rjmp comWaitForDataLow_done
Utils_WaitNanoSecs 100, 0, r22 ; wait for 100 nanosecs
dec r17
brne comWaitForDataLow_loop
clc ; timeout
ret
comWaitForDataLow_done:
sec ; ok
ret
; ---------------------------------------------------------------------------
; comWaitForDataHigh
;
; Waits up to COM_MAXWAIT loops for high data line
; IN:
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r17, r22, X
comWaitForDataHigh:
ldi r17, COM_MAXWAIT
comWaitForDataHigh_loop:
sbic COM_PIN_DATA, COM_PINNUM_DATA
rjmp comWaitForDataHigh_done
Utils_WaitNanoSecs 100, 0, r22 ; wait for 100 nanosecs
dec r17
brne comWaitForDataHigh_loop
clc ; timeout
ret
comWaitForDataHigh_done:
sec ; ok
ret
; ---------------------------------------------------------------------------
; comWaitForAttnHigh
;
; Waits up to COM_MAXWAIT loops for high ATTN line
; IN:
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r17, r22, X
comWaitForAttnHigh:
ldi r17, COM_MAXWAIT
comWaitForAttnHigh_loop:
sbic COM_PIN_ATTN, COM_PINNUM_ATTN
rjmp comWaitForAttnHigh_done
Utils_WaitNanoSecs 100, 0, r22 ; wait for 100 nanosecs
dec r17
brne comWaitForAttnHigh_loop
clc ; timeout
ret
comWaitForAttnHigh_done:
sec ; ok
ret
; ***************************************************************************
; buffer functions
; ---------------------------------------------------------------------------
; COM_BufferAlloc
;
; Allocate a transfer buffer.
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; - Y: pointer to allocated buffer in SRAM
; MODIFIED REGISTERS: r16, r17, r21
COM_BufferAlloc:
in r21, SREG ; save global interrupt enable bit from SREG
cli
lds r17, comRecvBuffersUsed
cpi r17, COM_BUFFER_NUM
brcc COM_AllocBuffer_error ; no buffer available
inc r17 ; increment number of buffers used
sts comRecvBuffersUsed, r17 ; store new value
lds r16, comRecvBuffersWritePos ; get current write pos
mov r17, r16 ; increment for next call
inc r17
cpi r17, COM_BUFFER_NUM ; CF set if COM_BUFFER_NUM > R17
brcs COM_AllocBuffer_l1
clr r17 ; wraparound
COM_AllocBuffer_l1:
sts comRecvBuffersWritePos, r17 ; store new writepos for next caller
rcall COM_BufferPosToY ; (R16, R17)
clr r17
std y+COM_BUFFER_OFFS_FLAGS, r17 ; preset flags
out SREG, r21 ; restore global interrupt enable bit in SREG
sec
ret
COM_AllocBuffer_error:
out SREG, r21
clc
ret
; ---------------------------------------------------------------------------
; COM_BufferDeallocBack
;
; Release a transfer buffer at the end of the list by decreasing the write pos.
; This releases the last allocated buffer!
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r16, r17, r21
COM_BufferDeallocBack:
in r21, SREG ; save global interrupt enable bit from SREG
cli
lds r17, comRecvBuffersUsed
tst r17
breq COM_BufferDeallocBack_error ; no buffer allocated, nothing to release
dec r17
sts comRecvBuffersUsed, r17 ; store new value
lds r17, comRecvBuffersWritePos
tst r17 ; 0?
brne COM_BufferDeallocBack_l1 ; nope go directly decrement r17
ldi r17, COM_BUFFER_NUM ; wrap-around
COM_BufferDeallocBack_l1:
dec r17
sts comRecvBuffersWritePos, r17
out SREG, r21
sec
ret
COM_BufferDeallocBack_error:
out SREG, r21
clc
ret
; ---------------------------------------------------------------------------
; COM_BufferDeallocFront
;
; Release a transfer buffer by increasing the read pos.
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGISTERS: r16, r17, r21
COM_BufferDeallocFront:
in r21, SREG ; save global interrupt enable bit from SREG
cli
lds r17, comRecvBuffersUsed
tst r17
breq COM_BufferDeallocFront_error ; no buffer allocated, nothing to release
dec r17
sts comRecvBuffersUsed, r17 ; store new value
lds r17, comRecvBuffersReadPos
inc r17
cpi r17, COM_BUFFER_NUM
brcs COM_BufferDeallocFront_l1
clr r17 ; wrap-around
COM_BufferDeallocFront_l1:
sts comRecvBuffersReadPos, r17
out SREG, r21
sec
ret
COM_BufferDeallocFront_error:
out SREG, r21
clc
ret
; ---------------------------------------------------------------------------
; COM_BufferPosToY
;
; Get a pointer to the SRAM position of the given buffer.
; CAVE: Code must correspond to COM_BUFFER_SIZE!!
; IN:
; - R16: buffer number (starting with 0)
; OUT:
; - Y: pointer to buffer in SRAM
; MODIFIED REGISTERS: R16, R17
COM_BufferPosToY:
; calculate offset
clr r17
mov yl, r16
clr yh
lsl yl
rol yh ; *2
add yl, r16
adc yh, r17 ; *3
lsl yl
rol yh ; *6
lsl yl
rol yh ; *12
lsl yl
rol yh ; *24
; add base position of buffers
ldi r16, LOW(comRecvBuffers)
ldi r17, HIGH(comRecvBuffers)
add yl, r16
adc yh, r17
ret