963 lines
26 KiB
NASM
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
|
|
|
|
|