; *************************************************************************** ; copyright : (C) 2025 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. * ; *************************************************************************** #ifndef AVR_MODULES_COM2W_COM2WN_RUN_H #define AVR_MODULES_COM2W_COM2WN_RUN_H ; WORK IN PROGRESS .cseg ; --------------------------------------------------------------------------- ; @routine COM2WN_Run ; ; @return CFLAG set if something done, cleared otherwise ; @clobbers all COM2WN_Run: clr r16 ; first handle lowlevel (e.g. handle all CLK changes and DATA from ringbuffer) COM2WN_Run_loop1: push r16 rcall com2wnLowLevelRun pop r16 brcc COM2WN_Run_handleRunModes rcall com2wnSetR16OnCarrySet rjmp COM2WN_Run_loop1 ; then handle messages etc COM2WN_Run_handleRunModes: ldi r19, COM_PORTS ldi yl, LOW(com2w0_iface) ; first interface ldi yh, HIGH(com2w0_iface) COM2WN_Run_loop2: push r16 push r19 rcall com2wnRunMode ; (clobbers possibly all but Y) pop r19 pop r16 rcall com2wnSetR16OnCarrySet ldi r20, COM2W_IFACE_SIZE add yl, r20 adc yh, r20 sub yh, r20 dec r19 brne COM2WN_Run_loop2 tst r16 clc breq COM2WN_Run_ret sec COM2WN_Run_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnSetR16OnCarrySet ; com2wnSetR16OnCarrySet: brcc com2wnSetR16OnCarrySet_ret ldi r16, 1 com2wnSetR16OnCarrySet_ret: ret ; @end ; --------------------------------------------------------------------------- ; @routine COM2WN_Periodically ; COM2WN_Periodically: ldi r19, COM_PORTS ldi yl, LOW(com2w0_iface) ; first interface ldi yh, HIGH(com2w0_iface) COM2WN_Periodically_loop: ; loop through all interfaces push r19 rcall com2wPeriodically ; (R16) pop r19 ldi r20, COM2W_IFACE_SIZE add yl, r20 adc yh, r20 sub yh, r20 dec r19 brne COM2WN_Periodically_loop ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnLowLevelRun ; com2wnLowLevelRun: .if COM_DATA_INPUT == COM_CLK_INPUT ; begin routine for single port ldi yl, LOW(com2wnIoRingBuffer) ldi yh, HIGH(com2wnIoRingBuffer) rcall RingBufferY_ReadByteGuarded ; (R17, R18, X) brcc com2wnLowLevelRun_ret lds r18, com2wnIoCurrentClockStates eor r18, r16 ; r18: changed bits in clk states sts com2wnIoCurrentClockStates, r16 ; store new state ; r16=clock byte, r17=data byte, r18=clock change byte ldi r19, COM_PORTS ldi yl, LOW(com2w0_iface) ; first interface ldi yh, HIGH(com2w0_iface) com2wnLowLevelRun_loop: ; loop through all interfaces ldd r20, Y+COM2W_IFACE_OFFS_PINMASK_CLK mov r21, r20 and r21, r18 ; CLK for interface changed? breq com2wnLowLevelRun_nextIface push r16 push r18 push r19 mov r17, r16 ; same byte on onePort system rcall com2wnActOnClock ; (r16, r17, r18, X) pop r19 pop r18 pop r16 com2wnLowLevelRun_nextIface: ldi r20, COM2W_IFACE_SIZE add yl, r20 adc yh, r20 sub yh, r20 dec r19 brne com2wnLowLevelRun_loop sec com2wnLowLevelRun_ret: ret ; end routine for single port .else ; begin routine for double port ldi yl, LOW(com2wnIoRingBuffer) ldi yh, HIGH(com2wnIoRingBuffer) push r15 in r15, SREG cli rcall RingBufferY_ReadByte ; (R17, R18, X) brcc com2wnLowLevelRun_popr15Ret push r16 rcall RingBufferY_ReadByte ; (R17, R18, X) mov r17, r16 pop r16 out SREG, r15 pop r15 lds r18, com2wnIoCurrentClockStates eor r18, r16 ; r18: changed bits in clk states sts com2wnIoCurrentClockStates, r16 ; store new state ; r16=clock byte, r17=data byte, r18=clock change byte ldi r19, COM_PORTS ldi yl, LOW(com2w0_iface) ; first interface ldi yh, HIGH(com2w0_iface) com2wnLowLevelRun_loop: ; loop through all interfaces ldd r20, Y+COM2W_IFACE_OFFS_PINMASK_CLK mov r21, r20 and r21, r18 ; CLK for interface changed? breq com2wnLowLevelRun_nextIface push r16 push r18 push r19 rcall com2wnActOnClock ; (r16, r17, r18, X) pop r19 pop r18 pop r16 com2wnLowLevelRun_nextIface: ldi r20, COM2W_IFACE_SIZE add yl, r20 adc yh, r20 sub yh, r20 dec r19 brne com2wnLowLevelRun_loop sec rjmp com2wnLowLevelRun_ret com2wnLowLevelRun_popr15Ret: out SREG, r15 pop r15 clc com2wnLowLevelRun_ret: ret ; end routine for double port .endif ; @end ; --------------------------------------------------------------------------- ; @routine com2wPeriodically @global ; ; @param Y pointer to interface data ; @clobbers R16 com2wPeriodically: push r15 in r15, SREG cli rcall NET_Interface_Periodically ; (R16) ldd r16, Y+COM2W_IFACE_OFFS_MODECOUNTER inc r16 breq com2wPeriodically_end std Y+COM2W_IFACE_OFFS_MODECOUNTER, r16 com2wPeriodically_end: out SREG, r15 pop r15 ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wSetMode ; ; Doesn't change processor status flags! ; ; @param R16 mode ; @clobbers R17 com2wSetMode: push r15 in r15, SREG cli ldd r17, Y+COM2W_IFACE_OFFS_MODE cp r16, r17 breq com2wSetMode_end std Y+COM2W_IFACE_OFFS_MODE, r16 clr r17 std Y+COM2W_IFACE_OFFS_MODECOUNTER, r17 com2wSetMode_end: out SREG, r15 pop r15 ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnStartReading ; ; @param Y pointer to interface data in SRAM ; @clobbers R16, R17, X com2wnStartReading: mov xl, yl mov xh, yh adiw xh:xl, COM2W_IFACE_OFFS_BUFFER std Y+COM2W_IFACE_OFFS_BUFPOS_LOW, xl std Y+COM2W_IFACE_OFFS_BUFPOS_HIGH, xh ldi r16, COM2W_BUFFER_SIZE std Y+COM2W_IFACE_OFFS_BUFLEFT, r16 clr r16 std Y+COM2W_IFACE_OFFS_BUFUSED, r16 ldi r16, COM2W_MODE_READING rcall com2wSetMode ; (R17) ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnRunMode ; ; @param Y pointer to interface data in SRAM ; @clobbers all com2wnRunMode: cpi r16, COM2W_MODE_NUM brcs com2wnRunMode_jump ldi r16, COM2W_MODE_IDLE ; unknown mode, set to idle rcall com2wSetMode ; (R17) sec ret com2wnRunMode_jump: ldi zl, LOW(com2wnModeJumpTable) ldi zh, HIGH(com2wnModeJumpTable) add zl, r16 adc zh, r16 sub zh, r16 ijmp com2wnModeJumpTable: rjmp com2wnRunIdle rjmp com2wnRunReading rjmp com2wnRunSkipping rjmp com2wnRunWriting ; @end ; --------------------------------------------------------------------------- ; @routine com2wnRunIdle ; ; @param Y pointer to interface data in SRAM ; @clobbers R16, R17, R22, R24, R25, X com2wnRunIdle: ;rjmp com2wnRunIdle_end ; DEBUG push r15 in r15, SREG cli ; look for outbound message rcall NET_Interface_PeekNextOutgoingMsgNum ; r16=msgNum brcs com2wnRunIdle_haveMsg out SREG, r15 pop r15 clc rjmp com2wnRunIdle_end com2wnRunIdle_haveMsg: mov r24, r16 ldi r16, COM2W_MODE_WRITING rcall com2wSetMode ; (R17) mov r16, r24 out SREG, r15 pop r15 push r16 rcall NET_Buffer_Locate ; (R17) adiw xh:xl, 1 rcall com2wnSendMsg ; (R16, R17, R22, R24, R25, X) push r15 in r15, SREG ; save SREG (no CLI, we want to save CFLAG only) ldi r16, COM2W_MODE_IDLE rcall com2wSetMode ; (R17) out SREG, r15 ; restore SREG pop r15 pop r16 brcc com2wnRunIdle_end push r15 in r15, SREG cli rcall NET_Interface_GetNextOutgoingMsgNum ; take current msg off the queue rcall NET_Buffer_ReleaseByNum ; (R16, X) out SREG, r15 pop r15 sec com2wnRunIdle_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnRunReading ; ; @param Y pointer to interface data in SRAM ; @clobbers none com2wnRunReading: ; check for timeout (Y+NET_IFACE_OFFS_READTIMER) ldd r16, Y+NET_IFACE_OFFS_READTIMER cpi r16, COM2W_READING_MAXREADCOUNTER brcc com2wnRunReading_goIdle ldd r16, Y+COM2W_IFACE_OFFS_MODECOUNTER cpi r16, COM2W_READING_MAXMODECOUNTER brcc com2wnRunReading_goIdle clc rjmp com2wnRunReading_end com2wnRunReading_goIdle: ldi r16, NET_IFACE_OFFS_ERR_IO_LOW rcall NET_Interface_IncCounter16 ; (R24, R25) ldi r16, COM2W_MODE_IDLE rcall com2wSetMode ; (r17) sec com2wnRunReading_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnRunSkipping ; ; @param Y pointer to interface data in SRAM ; @clobbers r16 (r17) com2wnRunSkipping: ; check for timeout (Y+NET_IFACE_OFFS_READTIMER) ldd r16, Y+NET_IFACE_OFFS_READTIMER cpi r16, COM2W_SKIPPING_MAXREADCOUNTER brcc com2wnRunSkipping_goIdle ldd r16, Y+COM2W_IFACE_OFFS_MODECOUNTER cpi r16, COM2W_SKIPPING_MAXMODECOUNTER brcc com2wnRunSkipping_goIdle clc rjmp com2wnRunSkipping_end com2wnRunSkipping_goIdle: ldi r16, COM2W_MODE_IDLE rcall com2wSetMode ; (r17) sec com2wnRunSkipping_end: ret ; @end ; --------------------------------------------------------------------------- ; @routine com2wnRunWriting ; ; @param Y pointer to interface data in SRAM ; @clobbers none com2wnRunWriting: ; TODO: check for timeout clc ret ; @end #endif ; AVR_MODULES_COM2W_COM2WN_RUN_H