Files
aqhomecontrol/avr/com.asm
2023-04-10 23:33:24 +02:00

314 lines
8.8 KiB
NASM

; ***************************************************************************
; copyright : (C) 2023 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. *
; ***************************************************************************
; ***************************************************************************
; defines
.equ COM_MAXWAIT_US = 100 ; maximum wait time in microseconds when waiting for rising/falling clock
.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
comInterrupts: .byte 2
comStatsPacketsIn: .byte 2
comStatsPacketsOut: .byte 2
comStatsRecvErrs: .byte 2
comStatsRecvCrcErrs: .byte 2
comStatsMissed: .byte 2
comStatsIgnored: .byte 2
comStatsHandled: .byte 2
comStatsCollisions: .byte 2
comStatsAborted: .byte 2
comStatsSendNoBuffer: .byte 2
comStatsRecvNoBuffer: .byte 2
comRecvBuffersReadPos: .byte 1
comRecvBuffersWritePos: .byte 1
comRecvBuffersUsed: .byte 1
comMaxBuffersUsed: .byte 1
comRecvBuffers: .byte (COM_BUFFER_SIZE*COM_BUFFER_NUM)
comDataEnd:
; ***************************************************************************
; code
.cseg
COM_BEGIN:
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
lds xl, comInterrupts
lds xh, comInterrupts+1
adiw xh:xl, 1
sts comInterrupts, xl
sts comInterrupts+1, xh
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
ldi r16, (1<<COM_IRQ_GIFR_ATTN) ; clear pending irq by writing 1 to ATTN bit
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
; ---------------------------------------------------------------------------
; 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
.include "com_lowlevel.asm"
.include "com_buffer.asm"
.include "com_crc.asm"
.include "com_send.asm"
.include "com_recv.asm"
COM_END:
.equ MODULE_SIZE_COM = COM_END-COM_BEGIN