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



; ---------------------------------------------------------------------------
; @routine CPRO_ReadValue @global
; Read a REPORT_VALUE/SET_VALUE message.
;
; @param  X       buffer to read from
; @return R17     value id
; @return R19:R18 value
; @return R21:R20 denom (e.g. 100, meaning value must be divided by 100)
; @return R22     source address
; @return R23     command

CPRO_ReadValue:
  adiw xh:xl, 2
  ld r23, X+    ; command
  ld r22, X+    ; src address
  adiw xh:xl, 6 ; skip uid, msg id
  ld r17, X
  adiw xh:xl, 2 ; skip value id, value type
  ld r18, X+
  ld r19, X+
  ld r20, X+
  ld r21, X+
  sbiw xh:xl, 16                                        ; back to msg begin
  ret
; @end



; ---------------------------------------------------------------------------
; @routine CPRO_WriteReportValue @global
; Write a REPORT_VALUE packet.
;
; @return nothing
; @param  R16     destination address
; @param  R17     value id
; @param  R19:R18 value
; @param  R21:R20 denom (e.g. 100, meaning value must be divided by 100)
; @param  R22     value type
; @param  X       buffer to write to
; @clobbers       R16 (R17, R18, R19, R20, R21)

CPRO_WriteReportValue:
  rcall CPRO_PrepareReportValue              ; (R16, R17, R18, R19, R20, R21)

  ; set msg id
  adiw xh:xl, CPRO_PACKET_VALUE_OFFS_MSGID
  rcall COM2_AddNextMsgIdToBuffer            ; (r16, r17, r18)
  sbiw xh:xl, CPRO_PACKET_VALUE_OFFS_MSGID+2 ; go back to begin  of msg
  
  ; calc and add checksum
  rcall com2CalcAndAddChecksumByte           ; (R16, R17, R18, R19, X)
  sbiw xh:xl, 17                             ; go back to beginning of message
  ret
; @end



; ---------------------------------------------------------------------------
; @routine CPRO_PrepareReportValue @global
; Write a REPORT_VALUE packet (except the checksum byte).
;
; @return nothing
; @param  R16     destination address
; @param  R17     value id
; @param  R19:R18 value
; @param  R21:R20 denom (e.g. 100, meaning value must be divided by 100)
; @param  R22     value type
; @param  X       buffer to write to
; @clobbers       R16 (R17, R18, R19, R20, R21)

CPRO_PrepareReportValue:
  st X+, r16     ; dest address
  ldi r16, 14    ; msg code+src address+12 payload bytes
  st X+, r16     ; msg len
  ldi r16, CPRO_CMD_VALUE_REPORT
  st X+, r16     ; msg code
  lds r16, com2Address
  st X+, r16     ; src address
  adiw xh:xl, 6  ; skip uid (4 bytes), msg/ref id (2 bytes)
  st X+, r17     ; value id
  st X+, r22     ; value type
  st X+, r18     ; value (low)
  st X+, r19     ; value (high)
  st X+, r20     ; denom (low)
  st X+, r21     ; denom (high)

  sbiw xh:xl, 12 ; go back to UID (12=16 back, 4 forward)
  rcall COM2_AddUidToBuffer ; (r16, r18, r19, r20, r21)
  clr r16
  st X+, r16     ; msg id (low)
  st X+, r16     ; msg id (high)
  sbiw xh:xl, 10 ; go back to beginning of message
  ret
; @end



; ---------------------------------------------------------------------------
; @routine CPRO_WriteSetValueResponse @global
; Write response to a SET_VALUE request.
;
; @return nothing
; @param  R16     message code (CPRO_CMD_VALUE_SET_ACK or CPRO_CMD_VALUE_SET_NACK)
; @param  X       buffer to write to
; @param  Y       buffer with received setValueRequest message
; @clobbers       R16, R17, R18, R19, (Y)

CPRO_WriteSetValueResponse:
  rcall cproInvertValueMsg         ; (R16, R17, R18, R19, Y)

  ; add checksum byte
  rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
  sbiw xh:xl, 16                   ; go back to beginning of message
  ret
; @end



; ---------------------------------------------------------------------------
; @routine CPRO_WriteGetValueResponse @global
; Write response to a SET_VALUE request.
;
; @return nothing
; @param  R16     message code (CPRO_CMD_VALUE_SET_ACK or CPRO_CMD_VALUE_SET_NACK)
; @param  R19:R18 value
; @param  R21:R20 denom (e.g. 100, meaning value must be divided by 100, 0=don't change)
; @param  X       buffer to write to
; @param  Y       buffer with received setValueRequest message
; @clobbers       R16, R17, R18, R19, (R20, R21, Y)

CPRO_WriteGetValueResponse:
  push r18
    push r19
      rcall cproInvertValueMsg         ; (R16, R17, R18, R19, Y)
    pop r19
  pop r18

  ; replace values
  adiw xh:xl, CPRO_PACKET_VALUE_OFFS_VALUE
  st X+, r18 ; value (low)
  st X+, r19 ; value (high)
  st X+, r20 ; denom (low)
  st X+, r21 ; denom (high)
  sbiw xh:xl, CPRO_PACKET_VALUE_OFFS_VALUE+4

  ; add checksum byte
  rcall com2CalcAndAddChecksumByte ; (R16, R17, R18, R19, X)
  sbiw xh:xl, 13                   ; go back to beginning of message
  ret
; @end



; ---------------------------------------------------------------------------
; @routine cproInvertValueMsg
; Write response to a SET_VALUE request.
;
; @return nothing
; @param  R16     message code (CPRO_CMD_VALUE_SET_ACK or CPRO_CMD_VALUE_SET_NACK)
; @param  X       buffer to write to
; @param  Y       buffer with received setValueRequest message
; @clobbers       R16, R17, R18, R19, (Y)

cproInvertValueMsg:
  ; copy received message into new message
  mov r19, r16
  ldi r18, 16            ; message size without checksum byte
  rcall Utils_Copy_SDRAM ; (R17, R18, X, Y)
  sbiw xh:xl, 16         ; go back to beginning of message

  ; exchange src and dest address
  adiw xh:xl, 3          ; src address
  ld r16, X
  lds r17, com2Address
  st X, r17              ; set our src address
  sbiw xh:xl, 3
  st X, r16              ; set old src address as destination address
  
  ; replace msg code
  adiw xh:xl, 2          ; msg code
  st X, r19
  sbiw xh:xl, 2

  ; replace UID
  adiw xh:xl, CPRO_PACKET_VALUE_OFFS_UID
  rcall COM2_AddUidToBuffer                ; (r16, r18, r19, r20, r21)
  sbiw xh:xl, CPRO_PACKET_VALUE_OFFS_UID+4 ; go back to beginning of message

  ret
; @end



; ---------------------------------------------------------------------------
; @routine CPRO_SendSetValueResponse @global
; Write response to a SET_VALUE request.
;
; @return CFLAG set if okay, cleared on error
; @param R16  message code (CPRO_CMD_VALUE_SET_ACK or CPRO_CMD_VALUE_SET_NACK)
; @param X    buffer to write to
; @param Y    buffer with received setValueRequest message
; @clobbers   Y, (R16, R17, R18, R19, R22)

CPRO_SendSetValueResponse:
  push xh
    push xl
      mov yh, xh
      mov yl, xl
      ldi xl, LOW(com2SendBuffer)
      ldi xh, HIGH(com2SendBuffer)
      rcall CPRO_WriteSetValueResponse ; (R16, R17, R18, R19, Y)
      rcall COM2_SendPacket            ; (r18, r19, r22, X)
    pop xl
  pop xh
  ret
; @end



; ---------------------------------------------------------------------------
; @routine CPRO_SendGetValueResponse @global
; Write response to a GET_VALUE request.
;
; @return CFLAG set if okay, cleared on error
; @param  R16  message code (CPRO_CMD_VALUE_SET_ACK or CPRO_CMD_VALUE_SET_NACK)
; @param  R19:R18 value
; @param  R21:R20 denom (e.g. 100, meaning value must be divided by 100, 0=don't change)
; @param  X       buffer to write to
; @param  Y       buffer with received getValueRequest message
; @clobbers  Y, (R16, R17, R18, R19, R22)

CPRO_SendGetValueResponse:
  push xh
    push xl
      mov yh, xh
      mov yl, xl
      ldi xl, LOW(com2SendBuffer)
      ldi xh, HIGH(com2SendBuffer)
      rcall CPRO_WriteGetValueResponse ; (R16, R17, R18, R19, Y)
      rcall COM2_SendPacket            ; (r18, r19, r22, X)
    pop xl
  pop xh
  ret
; @end



