Files
aqhomecontrol/avr/com.asm
2023-04-08 18:18:19 +02:00

306 lines
8.5 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
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
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
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