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



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



; ---------------------------------------------------------------------------
; @routine uartBitbang_ReceiveAndCheckMsg
;
; Receive a packet into buffer pointed to by X.
; Expects interrupts to be disabled.
;
; @param R18 COM address to listen to
; @param R19 max buffer size
; @param X   buffer to receive to
; @return CFLAG set if msg received, cleared on error
; @clobbers R16, R19 (R17, R20, R21, R22, R24, R25)

uartBitbang_ReceiveAndCheckMsg:
  push xl
    push xh
      rcall uartBitbang_RawReceiveMsg        ; (R16, R17, R19, R20, R21, R22, R24, R25, X)
    pop xh
  pop xl
  brcs uartBitbang_ReceiveAndCheckMsg_recvd
  ; fall-through, return with CF cleared (from uartBitbang_RawReceiveMsg)
  ret
uartBitbang_ReceiveAndCheckMsg_recvd:
  push xl
    push xh
      rcall NETMSG_CheckMessageInBuffer      ; (R16, R17, R18, R19, R20, X)
    pop xh
  pop xl
  brcs uartBitbang_ReceiveAndCheckMsg_msgOk
  ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
  rcall NET_Interface_IncCounter16          ; (R24, R25)
  clc
  ret
uartBitbang_ReceiveAndCheckMsg_msgOk:
  ldi r16, NET_IFACE_OFFS_PACKETSIN_LOW
  rcall NET_Interface_IncCounter16          ; (R24, R25)
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine uartBitbang_RawReceiveMsg
;
; Receive a packet into buffer pointed to by X.
; Expects interrupts to be disabled.
;
; @param R18 COM address to listen to
; @param R19 max buffer size
; @param X   buffer to receive to
; @return CFLAG set if msg received, cleared on error (see R16)
; @return R16   if CFLAG cleared: 0=message not for this node, otherwise error
; @clobbers R16, R19 (R17, R20, R21, R22, R24, R25, X)

uartBitbang_RawReceiveMsg:
  cpi r19, 3
  brcs uartBitbang_RawReceiveMsg_eBadSize
  ; read destination address
  rcall uartBitbang_ReceiveByte             ; read byte (R16, R17, R20, R21, R22)
  brcc uartBitbang_RawReceiveMsg_eIo
  cp r16, r18
  breq uartBitbang_RawReceiveMsg_forMe
  cpi r16, 0xff
  breq uartBitbang_RawReceiveMsg_forMe
  clr r16                                   ; not for me
  rjmp uartBitbang_RawReceiveMsg_clcRet
uartBitbang_RawReceiveMsg_forMe:
  subi r19, 1
  brcs uartBitbang_RawReceiveMsg_eBadSize
  st X+, r16
  ; read size of msg payload (e.g. number of msg bytes following minus CRC byte)
  rcall uartBitbang_ReceiveByte             ; read byte (R16, R17, R20, R21, R22)
  brcc uartBitbang_RawReceiveMsg_eIo
  subi r19, 1
  brcs uartBitbang_RawReceiveMsg_eBadSize
  st X+, r16                                ; store msg payload size
  inc r16                                   ; account for crc byte
  sub r19, r16                              ; check msg size against remaining buffer size
  brcs uartBitbang_RawReceiveMsg_eBadSize
  mov r19, r16
uartBitbang_RawReceiveMsg_loop:
    rcall uartBitbang_ReceiveByte           ; read byte (R16, R17, R20, R21, R22)
    brcc uartBitbang_RawReceiveMsg_eIo
    st X+, r16                              ; store msg
    dec r19
  brne uartBitbang_RawReceiveMsg_loop
  sec
  rjmp uartBitbang_RawReceiveMsg_end
uartBitbang_RawReceiveMsg_eBadSize:
  ldi r16, NET_IFACE_OFFS_ERR_MSGSIZE_LOW
  rjmp uartBitbang_RawReceiveMsg_incCounterRet
uartBitbang_RawReceiveMsg_eIo:
  ldi r16, NET_IFACE_OFFS_ERR_IO_LOW
uartBitbang_RawReceiveMsg_incCounterRet:
  rcall NET_Interface_IncCounter16          ; (R24, R25)
uartBitbang_RawReceiveMsg_clcRet:
  clc
uartBitbang_RawReceiveMsg_end:
  ret
; @end






; ---------------------------------------------------------------------------
; @routine uartBitbang_SendMsg
;
; Send packet over wire, handle ATTN line.
;
; @param  X ptr to buffer to send
; @return CFLAGS set if okay, cleared otherwise (index of error variable in R16)
; @return R16 index of error variable (if CFLAGS cleared)
; @clobbers R16 (R17, R21, R22, R24, R25, X)

uartBitbang_SendMsg:
  rcall uartBitbang_AcquireBus
  brcc uartBitbang_SendMsg_lineBusyError

  rcall uartBitbang_WaitForOneBitLength          ; wait for one bit duration (R22)
  rcall uartBitbang_WaitForOneBitLength          ; wait for one bit duration (R22)

  rcall uartBitbang_RawSendMsg                   ; (R16, R17, R21, R22, R24, R25, X)
  cbi COM_ATTN_DDR, COM_ATTN_PIN                 ; release ATTN line (by setting direction to IN)
  ret
uartBitbang_SendMsg_lineBusyError:
  ldi r16, NET_IFACE_OFFS_ERR_BUSY_LOW
  rcall NET_Interface_IncCounter16               ; (R24, R25)
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine uartBitbang_RawSendMsg
;
; Send packet over wire.
;
; @param  X ptr to buffer to send
; @return CFLAGS set if okay, cleared otherwise (index of error variable in R16)
; @return R16 index of error variable (if CFLAGS cleared)
; @clobbers R16, R17 (R21, R22, R24, R25, X)

uartBitbang_RawSendMsg:
  adiw xh:xl, NETMSG_OFFS_MSGLEN
  ld r17, X
  sbiw xh:xl, NETMSG_OFFS_MSGLEN
  inc r17                                        ; account for dest addr
  inc r17                                        ; account for msglen byte
  inc r17                                        ; account for crc byte

uartBitbang_RawSendMsg_loop:
    rcall uartBitbang_WaitForOneBitLength        ; wait for one bit duration (R22)

    ld r16, X+
    rcall uartBitbang_SendByte                   ; send byte (R16, R21, R22)
    brcc uartBitbang_RawSendMsg_ioError
    dec r17
  brne uartBitbang_RawSendMsg_loop
  ldi r16, NET_IFACE_OFFS_PACKETSOUT_LOW
  rcall NET_Interface_IncCounter16               ; (R24, R25)
  sec
  ret
uartBitbang_RawSendMsg_ioError:
  ldi r16, NET_IFACE_OFFS_ERR_COLLISIONS_LOW
  rcall NET_Interface_IncCounter16               ; (R24, R25)
  clc
  ret
; @end





; ---------------------------------------------------------------------------
; @routine uartBitbang_WaitForAttnHigh
;
; Wait up to 1ms for data pin to become high
; @return CFLAG set if okay, clear otherwise
; @clobbers R17, R22

uartBitbang_WaitForAttnHigh:
  cbi COM_ATTN_DDR, COM_ATTN_PIN          ; set ATTN port as input
  cbi COM_ATTN_OUTPUT, COM_ATTN_PIN       ; disable internal pullup for ATTN
  UART_BB_M_WAIT_FOR_PIN_HIGH COM_ATTN_INPUT, COM_ATTN_PIN
  ret
; @end




; ---------------------------------------------------------------------------
; @routine uartBitbang_AcquireBus
;
; Reserve bus if free (otherwise return error)
; Expects interrupts to be disabled.
;
; @return CFLAG set if okay (bus acquired), cleared on error
; @clobbers: none

uartBitbang_AcquireBus:
  ; check for ATTN line: busy?
  cbi COM_ATTN_DDR, COM_ATTN_PIN                 ; set ATTN as input
  cbi COM_ATTN_OUTPUT, COM_ATTN_PIN              ; disable pullup on ATTN
  nop                                            ; needed to sample current input
  sbis COM_ATTN_INPUT, COM_ATTN_PIN              ; ATTN low?
    rjmp uartBitbang_AcquireBus_busy             ; jump if it is
  sbi COM_ATTN_DDR, COM_ATTN_PIN                 ; set ATTN as output
  cbi COM_ATTN_OUTPUT, COM_ATTN_PIN              ; set ATTN low
  sec
  ret
uartBitbang_AcquireBus_busy:
  clc
  ret
; @end







