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

.cseg

COM_SEND_BEGIN:



; ---------------------------------------------------------------------------
; comSendPacketHandleRepeat
;
; IN:
; - Y: pointer to current buffer (pointed to by comRecvBuffersReadPos)
; OUT:
; - CFLAG: set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry)
; MODIFIED REGS: R15, R17, R22, X (R16, R17, R18, R21, R22)

comSendPacketHandleRepeat:
  in r15, SREG
  cli
    cbi COM_PORT_ATTN, COM_PINNUM_ATTN             ; disable pullup on ATTN
    cbi COM_DDR_ATTN, COM_PINNUM_ATTN              ; set ATTN as input
    nop                                            ; needed to sample current input
    sbis COM_PIN_ATTN, COM_PINNUM_ATTN             ; ATTN low?
      rjmp comSendPacketHandleRepeat_adjustRepeat  ; jump if it is
    ldd r16, y+COM_BUFFER_OFFS_FLAGS
    rcall comSetupRepeat                           ; setup comRepeatCount if not already done (R16, R17)
    cbi COM_PORT_ATTN, COM_PINNUM_ATTN             ; set ATTN low
    sbi COM_DDR_ATTN, COM_PINNUM_ATTN              ; set ATTN as output
    Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22      ; wait for one bit duration
    rcall comSendPacketHandleBuffer                ; (R16, R17, R21, R22)
    cbi COM_DDR_ATTN, COM_PINNUM_ATTN              ; release ATTN line (by setting direction to IN)
    brcc comSendPacketHandleRepeat_collision
    ; packet sent, adjust stats, release buffer
    ldi xl, LOW(comStatsPacketsOut)
    ldi xh, HIGH(comStatsPacketsOut)
    rcall comDeallocReadBufAndIncrCounter          ; (r16, r17, r18)
    rjmp comSendPacketHandleRepeat_retC
comSendPacketHandleRepeat_collision:
    ; increment collisions counter
    ldi xl, LOW(comStatsCollisions)
    ldi xh, HIGH(comStatsCollisions)
    rcall Utils_IncrementCounter16                ; (r18, r19, 22)
comSendPacketHandleRepeat_adjustRepeat:
    ; decrement repeat counter (except for vital messages)
    lds r17, comRepeatCount
    cpi r17, COM_REPEAT_VITAL
    breq comSendPacketHandleRepeat_retNC           ; vital message, repeat forever
    dec r17
    sts comRepeatCount, r17
    brne comSendPacketHandleRepeat_retNC
    ; dealloc buffer, inc abort counter
    ldi xl, LOW(comStatsAborted)
    ldi xh, HIGH(comStatsAborted)
    rcall comDeallocReadBufAndIncrCounter
    rjmp comSendPacketHandleRepeat_retC

comSendPacketHandleRepeat_retNC:
  out SREG, r15
  clc
  ret

comSendPacketHandleRepeat_retC:
  out SREG, r15
  sec
  ret



; ---------------------------------------------------------------------------
; comSetupRepeat
;
; IN:
; - R16: priority
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17

comSetupRepeat:
  lds r17, comRepeatCount
  tst r17
  brne comSetupRepeat_l99          ; comRepeatCount already setup
  ; set comRepeatCount according to priority
  andi r16, (COM_BUFFER_FLAGS_PRIO1 | COM_BUFFER_FLAGS_PRIO0)  ; r16: flags
  cpi r16, COM_REPEAT_INFO
  brne comSetupRepeat_l1
  ldi r17, COM_REPEAT_INFO
  rjmp comSetupRepeat_l98
comSetupRepeat_l1:
  cpi r16, COM_REPEAT_NORMAL
  brne comSetupRepeat_l2
  ldi r17, COM_REPEAT_NORMAL
  rjmp comSetupRepeat_l98
comSetupRepeat_l2:
  cpi r16, COM_REPEAT_IMPORTANT
  brne comSetupRepeat_l3
  ldi r17, COM_REPEAT_IMPORTANT
  rjmp comSetupRepeat_l98
comSetupRepeat_l3:
  ldi r17, COM_REPEAT_VITAL
comSetupRepeat_l98:
  sts comRepeatCount, r17
comSetupRepeat_l99:
  ret



; ---------------------------------------------------------------------------
; comSendPacketHandleBuffer
;
; Send a packet from the current read buffer (pointed to by comRecvBuffersReadPos).
; On success the flag COM_BUFFER_FLAGS_DONE is set in the buffer.
; The buffer is not released.
;
; CAVE: Expects interrupts to be disabled!
;
; IN:
; - Y  : pointer to current read buffer
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17 (R21, R22)

comSendPacketHandleBuffer:
  mov xl, yl
  mov xh, yh
  ldi r16, COM_BUFFER_OFFS_DATA
  clr r17
  add xl, r16
  adc xh, r17
  ldd r16, y+(COM_BUFFER_OFFS_DATA+COM_MSG_OFFS_MSGLEN) ; get msg payload length
  ldi r17, 3
  add r16, r17                                          ; add dest addr, msg len and XOR byte
  rcall comSendPacketFromSram                           ; send all that
  brcc comSendPacketHandleBuffer_error
  ldd r16, y+COM_BUFFER_OFFS_FLAGS
  ori r16, COM_BUFFER_FLAGS_DONE
  std y+COM_BUFFER_OFFS_FLAGS, r16
  sec
  ret
comSendPacketHandleBuffer_error:
  clc
  ret


; ---------------------------------------------------------------------------
; comSendPacketFromSram
;
; Send a packet from SRAM
;
; IN:
; - R16: number of bytes to send
; - X:   pointer to buffer to read from
; OUT:
; - CFLAG: set if okay, clear otherwise
; MODIFIED REGS: R16, R17 (R21, R22)

comSendPacketFromSram:
  mov r17, r16
comSendPacketFromSram_loop:
    ld r16, X+
    rcall comSendByte                 ; send byte (R16, R21, R22)
    brcc comSendPacketFromSram_error
    dec r17
  brne comSendPacketFromSram_loop
  sec
  ret

comSendPacketFromSram_error:
  clc
  ret



; ---------------------------------------------------------------------------
; comDeallocReadBufAndIncrCounter
;
; IN:
; - X  : pointer to counter
; OUT:
; - nothing
; REGS: r16, r17, r21

comDeallocReadBufAndIncrCounter:
  rcall COM_BufferDeallocFront                    ; (r16, r17, r21)
  ldi r21, 1
  ld r16, x+
  ld r17, x
  add r16, r21
  dec r21
  adc r17, r21
  st x, r17
  st -x, r16
  sts comRepeatCount, r21                         ; set comRepeatCount to zero
  ret



COM_SEND_END:
.equ MODULE_SIZE_COM_SEND = COM_SEND_END-COM_SEND_BEGIN


