; ***************************************************************************
; 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.   *
; ***************************************************************************


.equ TTYONUART1_SKIPTIME = 2
.equ TTYONUART1_MSG_INTERVAL = 0


.dseg

ttyOnUart1_iface: .byte UART_HW_IFACE_SIZE



.cseg


; ---------------------------------------------------------------------------
; @routine TtyOnUart1_Init @global
;
; @clobbers Y (R16, R17, X)

TtyOnUart1_Init:
  ldi yl, LOW(ttyOnUart1_iface)
  ldi yh, HIGH(ttyOnUart1_iface)
  rcall UART_HW_Interface_Init       ; (R16, R17, X)
  rcall ttyOnUart1Init               ; (R16, R17, X)
  ldi r16, TTYONUART1_IFACENUM
  std Y+NET_IFACE_OFFS_IFACENUM, r16
  ldi r16, 0xfe
  std Y+NET_IFACE_OFFS_ADDRESS, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine TtyOnUart1_Periodically @global
;
; @clobbers R16, Y

TtyOnUart1_Periodically:
  ldi yl, LOW(ttyOnUart1_iface)
  ldi yh, HIGH(ttyOnUart1_iface)
  
  ldd r16, Y+NET_IFACE_OFFS_READTIMER
  inc r16
  breq TtyOnUart1_Periodically_l1
  std Y+NET_IFACE_OFFS_READTIMER, r16
TtyOnUart1_Periodically_l1:
  ldd r16, Y+NET_IFACE_OFFS_WRITETIMER
  inc r16
  breq TtyOnUart1_Periodically_l2
  std Y+NET_IFACE_OFFS_WRITETIMER, r16
TtyOnUart1_Periodically_l2:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine TtyOnUart1_RxCharIsr @global @isr
;
; @clobbers none

TtyOnUart1_RxCharIsr:
  push r15
    in r15, SREG
    push r16
      push r17
        push r18
          push r24
            push r25
              push xl
                push xh
                  push yl
                    push yh
                      ldi yl, LOW(ttyOnUart1_iface)
                      ldi yh, HIGH(ttyOnUart1_iface)
                      rcall ttyOnUart1RxCharIsr ; (R16, R17, R18, R24, R25, X)
                    pop yh
                  pop yl
                pop xh
              pop xl
            pop r25
          pop r24
        pop r18
      pop r17
    pop r16
    out SREG, r15
  pop r15
  reti
; @end



; ---------------------------------------------------------------------------
; @routine TtyOnUart1_TxUdreIsr @global @isr
;
; @clobbers none

TtyOnUart1_TxUdreIsr:
  push r15
    in r15, SREG
    push r16
      push r17
        push xl
          push xh
            push yl
              push yh
                ldi yl, LOW(ttyOnUart1_iface)
                ldi yh, HIGH(ttyOnUart1_iface)
                rcall ttyOnUart1TxUdreIsr  ; (R16, R17, X)
              pop yh
            pop yl
          pop xh
        pop xl
      pop r17
    pop r16
    out SREG, r15
  pop r15
  reti
; @end



; ---------------------------------------------------------------------------
; @routine TtyOnUart1_TxCharIsr @global @isr
;
; @clobbers none

TtyOnUart1_TxCharIsr:
  push r15
    in r15, SREG
    push r16
      push r17
        push r18
          push xl
            push xh
              push yl
                push yh
                  ldi yl, LOW(ttyOnUart1_iface)
                  ldi yh, HIGH(ttyOnUart1_iface)
                  rcall ttyOnUart1TxCharIsr ; (R16, R17, R18, X)
                pop yh
              pop yl
            pop xh
          pop xl
        pop r18
      pop r17
    pop r16
    out SREG, r15
  pop r15
  reti
; @end



; ---------------------------------------------------------------------------
; @routine TtyOnUart1_SendBuffer @global
;
; @clobbers R16, R17

TtyOnUart1_SendBuffer:
  push r15
    in r15, SREG
    cli
    ldd r17, Y+UART_HW_IFACE_OFFS_WRITEMODE
    cpi r17, UART_HW_WRITEMODE_IDLE
    breq TtyOnUart1_SendBuffer_setBuffer
    out SREG, r15
  pop r15
  clc
  ret
TtyOnUart1_SendBuffer_setBuffer:
    rcall UART_HW_Interface_SetWriteBuffer    ; (R17)
    ldi r17, UART_HW_WRITEMODE_WRITING
    std Y+UART_HW_IFACE_OFFS_WRITEMODE, r17
    rcall ttyOnUart1StartTx               ; (R16)
  pop r15
  out SREG, r15
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine TtyOnUart1_Run @global
;
; @clobbers all

TtyOnUart1_Run:
  push r15
    in r15, SREG
    cli
    ldi yl, LOW(ttyOnUart1_iface)
    ldi yh, HIGH(ttyOnUart1_iface)
  
    rcall ttyOnUart1RunWriteModes
    rcall ttyOnUart1RunReadModes
  pop r15
  out SREG, r15
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunWriteModes
;
; @clobbers all, !Y

ttyOnUart1RunWriteModes:
  ldd r16, Y+UART_HW_IFACE_OFFS_WRITEMODE   ; handle write functions
  cpi r16, UART_HW_WRITEMODE_IDLE
  breq ttyOnUart1RunWriteIdle
  cpi r16, UART_HW_WRITEMODE_WRITING
  breq ttyOnUart1RunWriting
  cpi r16, UART_HW_WRITEMODE_WAITBUFFEREMPTY
  breq ttyOnUart1RunWaitBufferEmpty
  cpi r16, UART_HW_WRITEMODE_WRITEBUFFEREMPTY
  breq ttyOnUart1RunWriteBufferEmpty
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunWriteIdle
;
; @clobbers

ttyOnUart1RunWriteIdle:
  ldd r16, Y+NET_IFACE_OFFS_WRITETIMER
  cpi r16, TTYONUART1_MSG_INTERVAL          ; wait a bit between messages
  brcs ttyOnUart1RunWriteIdle_end
  rcall NET_Interface_GetNextOutgoingMsgNum ; (R17, R18, X)
  brcc ttyOnUart1RunWriteIdle_end
  rcall NET_Buffer_Locate                   ; (R17)
  rcall TtyOnUart1_SendBuffer               ; (R16, R17)
ttyOnUart1RunWriteIdle_end:
  ret


; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunWriting
;
; @clobbers

ttyOnUart1RunWriting:
  ; TODO: check for timeout etc.
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunWaitBufferEmpty
;
; @clobbers none

ttyOnUart1RunWaitBufferEmpty:
  ldd r16, Y+UART_HW_IFACE_OFFS_WRITEBUFNUM
  ldi r17, 0xff
  cp r16, r17
  breq ttyOnUart1RunWaitBufferEmpty_checkHardware
  std Y+UART_HW_IFACE_OFFS_WRITEBUFNUM, r17
  rcall NET_Buffer_ReleaseByNum               ; (R16, X)

ttyOnUart1RunWaitBufferEmpty_checkHardware:
  lds r16, UCSR1A
  sbrs r16,TXC1
    rjmp ttyOnUart1RunWaitBufferEmpty_checkTimer ; bit still clear, go check timer
  ldi r16, UART_HW_WRITEMODE_WRITEBUFFEREMPTY    ; bit is set, change mode to WRITEBUFFEREMPTY
  std Y+UART_HW_IFACE_OFFS_WRITEMODE, r16
  rjmp ttyOnUart1RunWaitBufferEmpty_end
ttyOnUart1RunWaitBufferEmpty_checkTimer:
  ldd r16, Y+NET_IFACE_OFFS_WRITETIMER
  cpi r16, 10
  brcs ttyOnUart1RunWaitBufferEmpty_end
  rcall ttyOnUart1StopTx                  ; disable transceiver and interrupts (R16)
  ldi r16, NET_IFACE_OFFS_ERR_COLLISIONS_LOW
  rcall NET_Interface_IncCounter16            ; (R24, R25)
ttyOnUart1RunWaitBufferEmpty_enterIdle:
  ldi r16, UART_HW_WRITEMODE_IDLE
  std Y+UART_HW_IFACE_OFFS_WRITEMODE, r16
ttyOnUart1RunWaitBufferEmpty_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunWriteBufferEmpty
;
; @clobbers R16, R17, X (R24, R25)

ttyOnUart1RunWriteBufferEmpty:
  rcall ttyOnUart1StopTx                  ; disable transceiver and interrupts (R16)
  ldi r16, UART_HW_WRITEMODE_IDLE
  std Y+UART_HW_IFACE_OFFS_WRITEMODE, r16
  ldi r16, NET_IFACE_OFFS_PACKETSOUT_LOW      ; increment packets counter
  rcall NET_Interface_IncCounter16            ; (R24, R25)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunReadModes
;
; @clobbers all, !Y

ttyOnUart1RunReadModes:
  ldd r16, Y+UART_HW_IFACE_OFFS_READMODE   ; handle read functions
  cpi r16, UART_HW_READMODE_IDLE
  breq ttyOnUart1RunReadIdle               ; (R16, R17, R24, R25, X)
  cpi r16, UART_HW_READMODE_READING
  breq ttyOnUart1RunReading                ; (none)
  cpi r16, UART_HW_READMODE_SKIPPING
  breq ttyOnUart1RunSkipping               ; (R16)
  cpi r16, UART_HW_READMODE_MSGRECEIVED
  breq ttyOnUart1RunMsgReceived            ; (R16, R17, R18, R24, R25)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunReadIdle
;
; @clobbers R16 (R17, R24, R25, X)

ttyOnUart1RunReadIdle:
  rcall UART_HW_Interface_EnsureReadBuffer      ; (R16, R17, R24, R25, X)
  brcc ttyOnUart1RunReadIdle_noBuf
  ldi r16, UART_HW_READMODE_READING
  std Y+UART_HW_IFACE_OFFS_READMODE, r16
  rcall ttyOnUart1StartRx                       ; R16
  ret
ttyOnUart1RunReadIdle_noBuf:
  ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
  rcall NET_Interface_IncCounter16              ; (R24, R25)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunReading
;
; @clobbers none

ttyOnUart1RunReading:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunSkipping
;
; @clobbers R16

ttyOnUart1RunSkipping:
  ldi r17, 0xff
  ldd r16, Y+UART_HW_IFACE_OFFS_READBUFNUM
  std Y+UART_HW_IFACE_OFFS_READBUFNUM, r17
  cp r16, r17
  breq ttyOnUart1RunSkipping_checkTimer
  rcall NET_Buffer_ReleaseByNum                 ; (R16, X)

ttyOnUart1RunSkipping_checkTimer:
  ldd r16, Y+NET_IFACE_OFFS_READTIMER
  cpi r16, TTYONUART1_SKIPTIME
  brcs ttyOnUart1RunSkipping_end
; leave skip mode (enter idle)
  ldi r16, UART_HW_READMODE_IDLE
  std Y+UART_HW_IFACE_OFFS_READMODE, r16
ttyOnUart1RunSkipping_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RunMsgReceived
;
; @clobbers R16 (R17, R18, R24, R25)

ttyOnUart1RunMsgReceived:
  rjmp UART_HW_Interface_HandleMsgReceived
; @end








; ---------------------------------------------------------------------------
; @routine ttyOnUart1Init @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16, R17, X

ttyOnUart1Init:
  M_UART_HW_Uart_Init 1
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1StartRx @global
;
; @clobbers R16

ttyOnUart1StartRx:
  M_UART_HW_Uart_StartRx 1
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1StopRx @global
;
; @clobbers R16

ttyOnUart1StopRx:
  M_UART_HW_Uart_StopRx 1
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1StartTx @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16

ttyOnUart1StartTx:
  M_UART_HW_Uart_StartTx 1
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1StopTx @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_STATE)
; @clobbers R16

ttyOnUart1StopTx:
  M_UART_HW_Uart_StopTx 1
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1RxCharIsr @global
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_MODE)
; @clobbers R16 (R17, R18, R24, R25, X)

ttyOnUart1RxCharIsr:
  M_UART_HW_Uart_RxCharFullDuplexIsr 1
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1TxUdreIsr @global
;
; Handler for UDRE1 interrupt called when TX data register is empty.
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_MODE)
; @clobbers R16, R17, X

ttyOnUart1TxUdreIsr:
  M_UART_HW_Uart_TxUdreIsr 1
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ttyOnUart1TxCharIsr @global
;
; Handler for TXC1 interrupt called when a last byte has been completely sent and
; the data register is empty.
;
; @param Y pointer to interface data in SRAM (see @ref UART_HW_IFACE_OFFS_MODE)
; @clobbers R16

ttyOnUart1TxCharIsr:
  M_UART_HW_Uart_TxCharIsr 1
  ret
; @end



