; ***************************************************************************
; copyright   : (C) 2024 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.   *
; ***************************************************************************



; ---------------------------------------------------------------------------
; @routine uartBitbang_ReceivePacketIntoBuffer
;
; Receive a packet into buffer pointed to by X.
; Expects interrupts to be disabled.
;
; @param R16 COM address to listen to
; @param R17 maximum value for accepted msg data (i.e. buffersize minus 3)
; @param X   buffer to receive to
; @return CFLAG set if okay (packet received), cleared on error
; @return R16 error code if CFLAG is cleared (COM2_ERROR_NOTFORME, COM2_ERROR_IOERROR, COM2_ERROR_DATAERROR)
; @clobbers: r16, r17, r18, X (r19, r20, r21, r22)

uartBitbang_ReceivePacketIntoBuffer:
  mov r18, r17
  push r16
    ; read destination address
    rcall uartBitbang_ReceiveByte             ; read byte (R16, R17, R20, R21, R22)
  pop r17                                     ; pop from R16 to R17
  brcc uartBitbang_ReceivePacketIntoBuffer_ioError
#ifndef COM_ACCEPT_ALL_DEST                    ; accept every destination address
  ; compare destination address (accept "FF" and own address)
  cp r16, r17
  breq uartBitbang_ReceivePacketIntoBuffer_acceptAddr
  cpi r16, 0xff
  breq uartBitbang_ReceivePacketIntoBuffer_acceptAddr
  ldi r16, COM2_ERROR_NOTFORME
  rjmp uartBitbang_ReceivePacketIntoBuffer_error        ; clc/ret
#endif
uartBitbang_ReceivePacketIntoBuffer_acceptAddr:
  st X+, r16                                  ; store dest address, lock buffer
  ; read msg length
  rcall uartBitbang_ReceiveByte               ; read packet length (R16, R17, R20, R21, R22)
  brcc uartBitbang_ReceivePacketIntoBuffer_ioError
  st X+, r16
  cp r16, r18                                 ; (COM2_BUFFER_SIZE-3)
  brcc uartBitbang_ReceivePacketIntoBuffer_contentError ; packet too long
  inc r16                                     ; account for checksum byte
  mov r17, r16
uartBitbang_ReceivePacketIntoBuffer_loop:
    push r17
      rcall uartBitbang_ReceiveByte           ; read byte (R16, R17, R20, R21, R22)
    pop r17
    brcc uartBitbang_ReceivePacketIntoBuffer_ioError
    st X+, r16
    dec r17
  brne uartBitbang_ReceivePacketIntoBuffer_loop
  sec
  ret
uartBitbang_ReceivePacketIntoBuffer_ioError:
  ldi r16, COM2_ERROR_IOERROR
  rjmp uartBitbang_ReceivePacketIntoBuffer_error
uartBitbang_ReceivePacketIntoBuffer_contentError:
  ldi r16, COM2_ERROR_DATAERROR
uartBitbang_ReceivePacketIntoBuffer_error:
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine uartBitbang_SendPacket
;
; Send packet over wire, handle ATTN line.
;
; @param  X ptr to buffer to send
; @return CFLAGS set if okay, cleared otherwise (errorcode in R16)
; @clobbers R16, R22 (R17, R21, X)

uartBitbang_SendPacket:
  rcall uartBitbang_AcquireBus
  brcc uartBitbang_SendPacket_lineBusyError
  
  rcall uartBitbang_WaitForOneBitLength          ; wait for one bit duration (R22)
  rcall uartBitbang_WaitForOneBitLength          ; wait for one bit duration (R22)

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

uartBitbang_SendPacket_loop:
    ld r16, X+
    rcall uartBitbang_SendByte                   ; send byte (R16, R21, R22)
    brcc uartBitbang_SendPacket_releaseBusRet
    dec r17
  brne uartBitbang_SendPacket_loop
  sec
uartBitbang_SendPacket_releaseBusRet:
  cbi COM_ATTN_DDR, COM_ATTN_PIN                 ; release ATTN line (by setting direction to IN)
  brcc uartBitbang_SendPacket_ioError
  ; packet successfully sent
  ret
uartBitbang_SendPacket_ioError:
  ldi r16,COM2_ERROR_COLLISION
  ret
uartBitbang_SendPacket_lineBusyError:
  ldi r16,COM2_ERROR_BUSY
  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



; ---------------------------------------------------------------------------
; @routine uartBitbang_WaitForOneBitLength
;
; wait for one bit length (minus cycles for call and ret).
;
; @clobbers r22

uartBitbang_WaitForOneBitLength:
  Utils_WaitNanoSecs COM_BIT_LENGTH, 7, r22       ; wait for one bit duration (minus RCALL/RET)
  ret
; @end


