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


.include "modules/com2/buffer.asm"



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

.dseg


com2DataBegin:
  com2Address:             .byte 1

  com2Interrupts:          .byte 2
  com2LastMsgId:           .byte 2

com2RecvStatsBegin:        ; 12 bytes
  com2StatsPacketsIn:      .byte 2
  com2StatsContentError:   .byte 2
  com2StatsIoError:        .byte 2
  com2StatsNoBufferError:  .byte 2
  com2StatsHandled:        .byte 2
  com2StatsMissed:         .byte 2   ; currently not used
com2RecvStatsEnd:

com2SendStatsBegin:        ; 6 bytes
  com2StatsPacketsOut:     .byte 2
  com2StatsCollisions:     .byte 2
  com2StatsBusyError:      .byte 2
com2SendStatsEnd:

  com2StatsNotForMe:       .byte 2
  com2StatsIgnored:        .byte 2
  
  com2MaxSendBuffersUsed:  .byte 1
  com2MaxRecvBuffersUsed:  .byte 1

  com2SendBuffer:          .byte COM2_BUFFER_SIZE
com2DataEnd:



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

.cseg

COM2_BEGIN:




; ---------------------------------------------------------------------------
; @routine Com2_Init @global
;
; @return CFLAG set if okay, clear on error
; @clobbers R16, R17, X, Y

Com2_Init:
  ; preset SRAM data area
  ldi xh, HIGH(com2DataBegin)
  ldi xl, LOW(com2DataBegin)
  clr r16
  ldi r17, (com2DataEnd-com2DataBegin)
  rcall Utils_FillSram

  ; set address to 0 (will be updated later)
  clr r16
  sts com2Address, r16

  rjmp COMIO_Init
; @end



; ---------------------------------------------------------------------------
; @routine Com2_Run @global
;
; @return CFLAG set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry)
; @clobbers (R1, R3, R16, R17, R18, R19, R22, X)

COM2_Run:
  rcall COMIO_Run
  brcs COM2_Run_carrySet
  rjmp com2HandleNextPacketInQueue  ; return CFLAG from com2HandleNextPacketInQueue
COM2_Run_carrySet:
  rcall com2HandleNextPacketInQueue
  sec                               ; return CFLAG set regardless of com2HandleNextPacketInQueue
  ret
; @end



; ---------------------------------------------------------------------------
; @routine com2HandleNextPacketInQueue
;
; Get next received packet, call onPacketReceived on it and release it
; @return CFLAG set if something done
; @clobbers any

com2HandleNextPacketInQueue:
  rcall COMIO_GetNextReceivedPacket
  brcc com2HandleNextPacketInQueue_retNc
  push xl
    push xh
      rcall com2CheckMessageInBuffer
    pop xh
  pop xl
  brcs com2HandleNextPacketInQueue_crcOk
  ldi xl, LOW(com2StatsContentError)
  ldi xh, HIGH(com2StatsContentError)
  rjmp com2HandleNextPacketInQueue_incCounterDeallocBuffer
com2HandleNextPacketInQueue_crcOk:
  rcall onPacketReceived
  brcs com2HandleNextPacketInQueue_handled
  ldi xl, LOW(com2StatsIgnored)
  ldi xh, HIGH(com2StatsIgnored)
  rjmp com2HandleNextPacketInQueue_incCounterDeallocBuffer
com2HandleNextPacketInQueue_handled:
  ldi xl, LOW(com2StatsHandled)
  ldi xh, HIGH(com2StatsHandled)
com2HandleNextPacketInQueue_incCounterDeallocBuffer:
  rcall Utils_IncrementCounter16                      ; (r18, r19, r22)
  rcall COMIO_ReleaseReceivedPacket
  sec
  ret
com2HandleNextPacketInQueue_retNc:
  clc
  ret
; @end





; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Preparing messages
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



; ---------------------------------------------------------------------------
; @routine COM2_WriteMsgWithCmdAndSrcAddr @global
;
; Write a simple packet into the given buffer with payload being only CMD and source address.
;
; IN:
; @param R16 destination address
; @param R18 command (e.g. CPRO_CMD_PING or CPRO_CMD_PONG)
; @param X   pointer to buffer to write to
; @return CFLAG set if okay, clear otherwise
; @clobbers R16, R17, X, Y (R3, R4, R15, R16, R17, R18, R19, R20, R21)

COM2_WriteMsgWithCmdAndSrcAddr:
  ldi r17, COM2_PAYLOAD_FLAGS_SECONDS
  push xh
    push xl
      rcall COM2_BeginMsgWithVariablePayload    ; (R3, R4, R16, R17, R18, R19, R20, R21, X)
    pop xl
  pop xh
  rcall com2CalcAndAddChecksumByte              ; (R16, R17, R18, R19, X)
  sec
  ret
COM2_WriteMsgWithCmdAndSrcAddr_error:
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine COM2_BeginMsgWithVariablePayload @global
;
; begin packet with variable payload.
;
; @param R16 destination address
; @param R17 flags
; @param R18 command (e.g. CPRO_CMD_PING)
; @param X   pointer to packet buffer
; @return X  points to end of packet as it was written so far
; @clobbers R3, R16, R17, R18, R19, R20, R21, X (R4)

COM2_BeginMsgWithVariablePayload:
  ; write header (dest address, msg length)
  st X+, r16                               ; destination address
  mov r16, r17                             ; calculate payload size
  mov r3, r17
  rcall com2CalcPayloadSize                ; (R4, R16, R17)
  inc r16                                  ; add CMD byte
  inc r16                                  ; add source address byte
  st X+, r16
  ; write payload
  st X+, r18                               ; 0: CMD
  lds r16, com2Address                     ; 1: source address
  st X+, r16
  lsr r3                                   ; shift out COM2_PAYLOAD_FLAGS_SECONDS
  brcc COM2_BeginMsgWithVariablePayload_l1
  ; write seconds
  rcall COM2_AddSecsToBuffer
COM2_BeginMsgWithVariablePayload_l1:
  lsr r3                                   ; shift out COM2_PAYLOAD_FLAGS_UID
  brcc COM2_BeginMsgWithVariablePayload_l2
  ; write uid
  rcall COM2_AddUidToBuffer
COM2_BeginMsgWithVariablePayload_l2:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine COM2_AddUidToBuffer @global
;
; Write UID into buffer given by X.
;
; @return X   points to behind written uid
; @param  X   pointer to packet buffer
; @clobbers: r18, r19, r20, r21 (r16)

COM2_AddUidToBuffer:
  push xh
    push xl
      rcall Utils_ReadUid                  ; (R16, X)
    pop xl
  pop xh
  st X+, r18
  st X+, r19
  st X+, r20
  st X+, r21
  ret
; @end



; ---------------------------------------------------------------------------
; @routine COM2_AddSecsToBuffer @global
;
; Write current seconds counter (4 bytes) into buffer given by X, advance X.
;
; @return X   points to behind written seconds
; @param  X   pointer to packet buffer
; @clobbers   r16

COM2_AddSecsToBuffer:
  lds r16, timerModuleCounterSecs          ; add current seconds counter
  st X+, r16
  lds r16, timerModuleCounterSecs+1
  st X+, r16
  lds r16, timerModuleCounterSecs+2
  st X+, r16
  lds r16, timerModuleCounterSecs+3
  st X+, r16
  ret
; @end



; ---------------------------------------------------------------------------
; @routine COM2_AddNextMsgIdToBuffer @global
;
; Write next message id (2 bytes) into buffer given by X, advance X.
;
; @return X   points to behind written message id
; @param  X   pointer to packet buffer
; @clobbers: r16, r17, r18

COM2_AddNextMsgIdToBuffer:
  ldi r18, 1
  lds r16, com2LastMsgId
  lds r17, com2LastMsgId+1
  add r16, r18
  dec r18
  adc r17, r18
  sts com2LastMsgId, r16
  sts com2LastMsgId+1, r17
  st X+, r16
  st X+, r17
  ret
; @end



; ---------------------------------------------------------------------------
; com2CalcPayloadSize
;
; Calculate payload size from given flags
;
; @param    R16 flags
; @return   R16 payload size
; @clobbers R4, R16, R17

com2CalcPayloadSize:
  clr r4
  ldi r17, 4
  lsr r16                       ; shift out COM2_PAYLOAD_FLAGS_SECONDS
  brcc com2CalcPayloadSize_l1
  add r4, r17                   ; add 4 bytes
com2CalcPayloadSize_l1:
  lsr r16                       ; shift out COM2_PAYLOAD_FLAGS_UID
  brcc com2CalcPayloadSize_l2
  add r4, r17                   ; add 4 bytes
com2CalcPayloadSize_l2:
  lsr r16                       ; shift out reserved1, after this R16 contains COM2_PAYLOAD_FLAGS_NUM0-4
  add r16, r4                   ; add previous bytes to R16
  ret
; @end







; ---------------------------------------------------------------------------
; @routine COM2_SendPacket
;
; send packet from sendBuffer, if line free.
;
; @return CFLAG set if okay (packet sent), cleared on error
; @clobbers any (depending on io implementation)

COM2_SendPacket:
  ldi xl, LOW(com2SendBuffer)
  ldi xh, HIGH(com2SendBuffer)
  rjmp COMIO_SendPacket
; @end





.include "modules/com2/crc.asm"



COM2_END:
.equ MODULE_SIZE_COM2 = COM2_END-COM2_BEGIN

