diff --git a/avr/com.asm b/avr/com.asm index a1263c4..be5b9db 100644 --- a/avr/com.asm +++ b/avr/com.asm @@ -9,8 +9,21 @@ .equ COM_BUFFER_FLAGS_DONE = 0x80 .equ COM_BUFFER_FLAGS_RECEIVED = 0x40 +.equ COM_BUFFER_FLAGS_TOSEND = 0x20 +.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 ; *************************************************************************** @@ -22,11 +35,16 @@ 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 comRingBuffer: .byte RINGBUFFER_OFFS_DATA+COM_RINGBUFFER_SIZE comDataEnd: @@ -45,7 +63,7 @@ comDataEnd: ; IN: ; OUT: ; - CFLAG: set if okay, clear on error -; USED: +; USED: R16, R17, X, Y Com_Init: ; preset SRAM data area @@ -82,7 +100,271 @@ Com_Init: ; --------------------------------------------------------------------------- -; comSendPacket +; 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 comHandleNextPacketInRingbuffer ; nothing more than handling packages in ringbuffer + ret + + + +; --------------------------------------------------------------------------- +; Mark a packet as enqueued. +; +; IN: +; - R18: pos pointer inside ring buffer to read from next +; - R20: priority +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGS: R10, R11, R12, R15, R16, R20 (R3, R21, R22) + +COM_EnqueuePacket: + ldi yl, LOW(comRingBuffer) + ldi yh, HIGH(comRingBuffer) + in r15, SREG + cli + ldd r19, y+RINGBUFFER_OFFS_MAXSIZE + ; read length + rcall RingBuffer_Read ; (R3, R22) + cpi r16, 3 ; at least 3 bytes? + brcs COM_EnqueuePacket_error ; too few bytes + ; read flags + push r18 + rcall RingBuffer_Read + pop r18 + ; write 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 + rcall RingBuffer_Write + brcc COM_EnqueuePacket_error ; too few bytes + out SREG, r15 ; restore IRQ flag + sec + ret +COM_EnqueuePacket_error: + out SREG, r15 ; restore IRQ flag + clc + ret + + + +; --------------------------------------------------------------------------- +; comHandleNextPacketInRingbuffer +; +; Expects global IRQ disabled. +; +; IN: +; - nothing +; OUT: +; - CFLAG: set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry) +; MODIFIED REGS: R1, R16, R17, R18, R19, Y (R1, R3, R16, R17, R18, R19, R22, X) + + +comHandleNextPacketInRingbuffer: + ; read current packet in ringbuffer (read pointer) + ldi yl, LOW(comRingBuffer) + ldi yh, HIGH(comRingBuffer) + ldd r19, y+RINGBUFFER_OFFS_MAXSIZE + ldd r18, y+RINGBUFFER_OFFS_READPOS + rcall RingBuffer_Read ; packet length (R3, R22) + cpi r16, 3 ; at least 3 bytes? + brcs comHandleNextPacketInRingbuffer_retNc + mov r1, r16 + rcall RingBuffer_Read ; read flags from packet + ldd r18, y+RINGBUFFER_OFFS_READPOS ; r18 back to read pointer + mov r17, r16 + andi r17, COM_BUFFER_FLAGS_TOSEND ; check for message to send + brne comHandleNextPacketInRingbuffer_sendPacket + mov r17, r16 ; check for received message + andi r17, COM_BUFFER_FLAGS_RECEIVED + brne comHandleNextPacketInRingbuffer_receivedPacket + +comHandleNextPacketInRingbuffer_sendPacket: + rcall comSendPacketHandleRepeat ; (R1, R3, R16, R17, R18, R19, R22, X) + ret ; use CFLAG from subroutine + +comHandleNextPacketInRingbuffer_receivedPacket: + clr r17 + sts comRepeatCount, r17 ; set comRepeatCount to zero + rcall comHandleReceivedPacket + sec ; always return with set CFLAG + ret + +comHandleNextPacketInRingbuffer_retNc: + clc + ret + + + +; --------------------------------------------------------------------------- +; comHandleReceivedPacket +; +; IN: +; - nothing +; OUT: +; - nothing +; MODIFIED REGS: X, (R3, R22) + + +comHandleReceivedPacket: + ldi yl, LOW(comRingBuffer) + ldi yh, HIGH(comRingBuffer) + ldd r19, y+RINGBUFFER_OFFS_MAXSIZE + ldd r18, y+RINGBUFFER_OFFS_READPOS + 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: + ldi yl, LOW(comRingBuffer) + ldi yh, HIGH(comRingBuffer) + ldd r19, y+RINGBUFFER_OFFS_MAXSIZE + ldd r18, y+RINGBUFFER_OFFS_READPOS + rcall comDeallocReadBufAndIncrCounter ; (r16, r17, r18, r19, r20, r21) + ret + + + +; --------------------------------------------------------------------------- +; comSendPacketHandleRepeat +; +; IN: +; - R18: pos pointer inside ring buffer to read from next +; - R19: maximum size of the ringbuffer (for wrap-around) +; - Y : ringbuffer +; OUT: +; - CFLAG: set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry) +; MODIFIED REGS: R1, R15, R16, R17, R18, R19, X, (R3, R22) + +comSendPacketHandleRepeat: + in r15, SREG + cli + push r18 + rcall RingBuffer_Read ; packet length (R3, R22) + mov r1, r16 ; r1: ringbuffer packet length + rcall RingBuffer_Read ; flags + pop r18 + rcall comSetupRepeat ; setup comRepeatCount if not already done + sbis COM_PIN_ATTN, COM_PINNUM_ATTN ; check ATTN: low? + rjmp comSendPacketHandleRepeat_adjustRepeat ; yes, line is busy, retry later + push r18 + 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 comSendPacketRaw ; (R3, R10, R11, R12, R16, R20 R21, R22) + cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; release ATTN line + pop r18 + brcc comSendPacketHandleRepeat_adjustRepeat + ; packet sent, adjust stats + mov r16, r1 + ldi xl, LOW(comStatsPacketsOut) + ldi xh, HIGH(comStatsPacketsOut) + rcall comDeallocReadBufAndIncrCounter ; (r16, r17, r18) + rjmp comSendPacketHandleRepeat_retC + +comSendPacketHandleRepeat_adjustRepeat: + 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 dismiss counter + mov r16, r1 + 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: pos pointer inside ring buffer to read from next +; - R20: 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: +; - r16: num of bytes to dealloc +; - X : pointer to counter +; - Y : ring buffer +; OUT: +; - nothing +; REGS: r16, r17, r18 (r19, r20, r21) + +comDeallocReadBufAndIncrCounter: + rcall RingBuffer_DeallocRead ; (r17, r18, r19, r20, r21) + clr r18 + ld r16, x+ + ld r17, x + inc r16 + adc r17, r18 + st -x, r17 + st x, r16 + sts comRepeatCount, r18 ; set comRepeatCount to zero + ret + + + +; --------------------------------------------------------------------------- +; comSendPacketRaw ; ; Send a packet. (TODO: input buffer in x, length in r16) ; @@ -92,13 +374,13 @@ Com_Init: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGS: R10, R11, R12, R16, R20 (R3, R21, R22) -comSendPacket: +comSendPacketRaw: ldi yl, LOW(comRingBuffer) ldi yh, HIGH(comRingBuffer) ldd r19, y+RINGBUFFER_OFFS_MAXSIZE rcall RingBuffer_Read ; read entry length from buffer (advances r18) (R3, R22) cpi r16, 3 ; at least 3 bytes? - brcs comSendPacket_error ; too few bytes + brcs comSendPacketRaw_error ; too few bytes mov r10, r16 ; r10: number of bytes at current ringbuffer pos dec r10 dec r10 @@ -110,24 +392,24 @@ comSendPacket: rcall RingBuffer_Read ; read dest address from buffer eor r11, r16 ; calculate checksum rcall comSendByte ; send destination address (R16, R21, R22) - brcc comSendPacket_error + brcc comSendPacketRaw_error mov r16, r10 ; send msg length eor r11, r16 ; calculate checksum rcall comSendByte ; send destination address - brcc comSendPacket_error + brcc comSendPacketRaw_error tst r10 ; payload? - breq comSendPacket_sendCrc ; no payload, go send checksum -comSendPacket_loop: + breq comSendPacketRaw_sendCrc ; no payload, go send checksum +comSendPacketRaw_loop: rcall RingBuffer_Read ; read byte from buffer eor r11, r16 ; calculate checksum rcall comSendByte ; send byte - brcc comSendPacket_error + brcc comSendPacketRaw_error dec r10 - brne comSendPacket_loop -comSendPacket_sendCrc: + brne comSendPacketRaw_loop +comSendPacketRaw_sendCrc: mov r16, r10 ; send checksum rcall comSendByte ; send byte - brcc comSendPacket_error + brcc comSendPacketRaw_error mov r18, r20 ; pos of flags byte in ringbuffer mov r16, r12 ori r16, COM_BUFFER_FLAGS_DONE ; set flag @@ -135,7 +417,7 @@ comSendPacket_sendCrc: sec ret -comSendPacket_error: +comSendPacketRaw_error: clc ret @@ -149,9 +431,9 @@ comSendPacket_error: ; ; Packages are stored in the buffer like this: ; - 1 byte : buffer size -; - 1 byte: flags (e.g. WAN_BUFFER_RECEIVED) +; - 1 byte: flags (e.g. COM_BUFFER_FLAGS_RECEIVED) ; - 1 byte : destination address -; - n bytes: packet (i.e. buffer size -2 bytes) +; - n bytes: packet (i.e. buffer size -3 bytes) ; ; IN: ; - nothing diff --git a/avr/main.asm b/avr/main.asm index b1b9677..d08307d 100644 --- a/avr/main.asm +++ b/avr/main.asm @@ -178,10 +178,14 @@ initModules: runModulesUntilIdle: -runModulesUntilIdle_Timer: ; repeat this block for every run function +runModulesUntilIdle_Timer: ; repeat this block for every module with run function rcall Timer_Run ; brcs runModulesUntilIdle_Timer ; +runModulesUntilIdle_Com: + rcall Com_Run + brcs runModulesUntilIdle_Com + ret @@ -227,5 +231,24 @@ onEverySecond: +; --------------------------------------------------------------------------- +; onPacketReceived: +; +; Called after a packet was received via COM module. Add your routine calls here. +; +; The packet will be removed from buffer in any case after return from this call. +; IN: +; - R18: pos of packet in ringbuffer +; - Y : pointer to ringbuffer +; OUT: +; - CFLAG: set if handled, cleared otherwise +; USED: depending on called routines + +onPacketReceived: + clc ; not handled + ret + + +