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


; ***************************************************************************
; defines




; ***************************************************************************
; data

.dseg


netUartIface: .byte UART_HW_IFACE_SIZE



; ***************************************************************************
; code

.cseg


; ---------------------------------------------------------------------------
; @routine ComOnUart0_Init @global
;

NET_Uart_Init:
  ldi yl, LOW(netUartIface)
  ldi yh, HIGH(netUartIface)
  rcall UART_HW_Interface_Init
  rcall UART_Init
  rcall ATTN_Init
  ret
; @end



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

NET_Uart_Every100ms:
  ldi yl, LOW(netUartIface)
  ldi yh, HIGH(netUartIface)
  push r15
    in r15, SREG
    cli
    rcall NET_Interface_Periodically         ; (R16)
    rcall netUartSendNextPkg
    out SREG, r15
  pop r15
  ret
  rjmp NET_Interface_Periodically
; @end



; ---------------------------------------------------------------------------
; @routine netUartSendNextPkg
;
; Check whether there is an outgoing message in interface data
; and send it if possible.
;
; @return CFLAG set if okay, clear on error
; @param Y pointer to start of interface data
; @clobbers R16, R17, R18, R21, R21, R24, R25, X

netUartSendNextPkg:
  rcall NET_Interface_PeekNextOutgoingMsgNum ; (R17, R18, X)
  brcc netUartSendNextPkg_end
  rcall NET_Buffer_Locate                    ; get pointer to buffer (R17)
  brcc netUartSendNextPkg_end
  adiw xh:xl, 1                              ; skip buffer header
  rcall netUartSendPacketWithAttn              ; (R16, R17, R21, R22, X)
  brcc netUartSendNextPkg_error
  rcall NET_Interface_GetNextOutgoingMsgNum  ; remove from stack (R17, R18, X)
  rcall NET_Buffer_ReleaseByNum              ; release buffer (R16, X)
  ldi r16, NET_IFACE_OFFS_PACKETSOUT_LOW
  rcall NET_Interface_IncCounter16           ; (R24, R25)
  sec
  rjmp netUartSendNextPkg_end
netUartSendNextPkg_error:
  rcall NET_Interface_IncCounter16           ; (R24, R25)
  clc
netUartSendNextPkg_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine netUartSendPacket
;
; @param X buffer to send
; @return CFLAG set if okay, cleared on error
; @return R16 error code (if CFLAG cleared)
; @clobbers R16, R17, R22, X

netUartSendPacketWithAttn:
  rcall ATTN_IsHigh
  ldi r16, NET_IFACE_OFFS_ERR_BUSY_LOW
  brcc netUartSendPacketWithAttn_end         ; ATTN low, jmp

  rcall ATTN_SetLowDisableIrq                ; reserve bus (R16)
  Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22  ; wait for one bit duration
  Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22  ; wait for one bit duration
  rcall netUartSendPacket
  rcall ATTN_SetHighEnableIrq                 ; release bus
  sec
netUartSendPacketWithAttn_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine netUartSendPacket
;
; @param X buffer to send
; @clobbers R17 (R16, X)

netUartSendPacket:
  adiw xh:xl, NETMSG_OFFS_MSGLEN
  ld r17, X
  inc r17
  inc r17
  inc r17
  sbiw xh:xl, NETMSG_OFFS_MSGLEN
  rjmp UART_SendBytes              ; (R16, R17, X)
; @end




; ---------------------------------------------------------------------------
; @routine netUartRecvPacket
;
; alloc a buffer, receive message, add message to global list
; @param Y pointer to start of interface data
; @return CFLAG set if okay, cleared on error
; @clobbers R16, R17, R18, R19, R20, R24, R25, X

netUartRecvPacket:
  rcall UART_StartRx                         ; (R16)
  rcall NET_Buffer_Alloc                     ; (R16, R17, X)
  brcs netUartRecvPacket_haveBuf
  rcall UART_StopRx                          ; (R16)
  ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
  rjmp netUartRecvPacket_incCounterRet
netUartRecvPacket_haveBuf:
  push r16
    adiw xh:xl, 1
    ldd r18, Y+NET_IFACE_OFFS_ADDRESS
    ldi r17, NET_BUFFERS_SIZE-1
    rcall netUartRecvPacketIntoX             ; (R16, R17, R18, R19, R20, R24, R25)
  pop r16
  brcc netUartRecvPacket_releaseBufRet
  rcall NET_AddIncomingMsgNum                ; (R17, R18, X)
  brcc netUartRecvPacket_releaseBufRet
  rcall UART_StopRx                          ; (R16)
  sec
  ret
netUartRecvPacket_noAddMsg:
  rcall NET_Buffer_ReleaseByNum              ; (R16, X)
  ldi r16, NET_IFACE_OFFS_ERR_MISSED_LOW
  rjmp netUartRecvPacket_incCounterRet
netUartRecvPacket_releaseBufRet:
  rcall NET_Buffer_ReleaseByNum              ; (R16, X)
  ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
netUartRecvPacket_incCounterRet:
  rcall NET_Interface_IncCounter16           ; (R24, R25)
  rcall UART_StopRx                          ; (R16)
netUartRecvPacket_retNc:
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine netUartRecvPacketIntoX
;
; @param Y pointer to start of interface data
; @param X pointer buffer (in RAM)
; @param r17 maximum number of bytes to receive
; @param r18 network address to listen to
; @return CFLAG set if okay, cleared on error
; @clobbers R16, R17, R18, R19, R20, R24, R25

netUartRecvPacketIntoX:
  push xh
    push xl
      rcall UART_RecvPacket                  ; (r16, r17, X)
    pop xl
  pop xh
  brcc netUartRecvPacketIntoX_handleError
  push xl
    push xh
      rcall NETMSG_CheckMessageInBuffer      ; (R16, R17, R18, R19, R20, X)
    pop xh
  pop xl
  brcc netUartRecvPacketIntoX_contentError
  ldi r16, NET_IFACE_OFFS_PACKETSIN_LOW
  rcall NET_Interface_IncCounter16           ; (R24, R25)
  sec
  ret
netUartRecvPacketIntoX_handleError:
  cpi r16, UART_ERROR_IO
  breq netUartRecvPacketIntoX_ioError
  cpi r16, UART_ERROR_CONTENT
  breq netUartRecvPacketIntoX_contentError
  rjmp netUartRecvPacketIntoX_retNc
netUartRecvPacketIntoX_ioError:
  ldi r16, NET_IFACE_OFFS_ERR_IO_LOW
  rjmp netUartRecvPacketIntoX_incCounterRetNc
netUartRecvPacketIntoX_contentError:
  ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
netUartRecvPacketIntoX_incCounterRetNc:
  rcall NET_Interface_IncCounter16           ; (R24, R25)
netUartRecvPacketIntoX_retNc:
  clc
  ret
; @end




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

NetUart_AttnChangeIsr:
  push r15
    in r15, SREG
    push r16
      push r17
        push r18
          push r19
            push r20
              push r24
                push r25
                  push xl
                    push xh
                      push yl
                        push yh
                          ldi yl, LOW(netUartIface)
                          ldi yh, HIGH(netUartIface)
                          rcall netUartRecvPacket    ; (R16, R17, R18, R19, R20, R24, R25, X)
                        pop yh
                      pop yl
                    pop xh
                  pop xl
                pop r25
              pop r24
            pop r20
          pop r19  
        pop r18
      pop r17
    pop r16
    out SREG, r15
  pop r15
  reti
; @end



