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


; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; This file contains packet receiption handlers for the address protocol
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



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

.cseg





; ---------------------------------------------------------------------------
; CPRO_Address_OnPacketReceived:
;
; Try to handle the given packet.
;
; IN:
; - X  : pointer to received buffer
; OUT:
; - CFLAG: set if handled, cleared otherwise
; USED: depending on called routines

CPRO_Address_OnPacketReceived:
  adiw xh:xl, COM2_MSG_OFFS_CMD
  ld r16, x
  sbiw xh:xl, COM2_MSG_OFFS_CMD

  cpi r16, CPRO_CMD_NEED_ADDRESS
  brcs CPRO_Address_OnPacketReceived_nc  ; smaller than 60
  
  cpi r16, (CPRO_CMD_ADDRESS_RANGE+1)
  brcc CPRO_Address_OnPacketReceived_nc

CPRO_Address_OnPacketReceived_debug2:
  ldi r17, (cproPacketTypeTransTableEnd-cproPacketTypeTransTableBegin)*2
  ldi zl, LOW(cproPacketTypeTransTableBegin)
  ldi zh, HIGH(cproPacketTypeTransTableBegin)
  rcall Utils_FindBytePositionInTable
  brcc CPRO_Address_OnPacketReceived_nc

  ldi r17, (cproPacketTypeTransTableEnd-cproPacketTypeTransTableBegin)*2
  ldi zl, LOW(cproPacketTypeHandleTable)
  ldi zh, HIGH(cproPacketTypeHandleTable)
  rcall Utils_TableJump
  sec
  ret
CPRO_Address_OnPacketReceived_nc:
  clc
  ret



cproPacketTypeTransTableBegin:
 .db CPRO_CMD_NEED_ADDRESS, CPRO_CMD_HAVE_ADDRESS, CPRO_CMD_ADDRESS_RANGE, CPRO_CMD_DENY_ADDRESS, CPRO_CMD_CLAIM_ADDRESS, CPRO_CMD_PING
cproPacketTypeTransTableEnd:

; position within table must be in same order as in table above!
cproPacketTypeHandleTable:
  .dw cproHandleNeedAddr, cproHandleHaveAddr, cproHandleAddrRange, cproHandleDenyAddr, cproHandleClaimAddr, cproHandlePing



cproHandleNeedAddr:
  lds r17, cproMode
  cpi r17, CPRO_MODE_NORMAL
  brne cproHandleNeedAddr_done
  ; enter CPRO_MODE_SENDING_HAVE_ADDR mode
  lds r16, com2Address
  tst r16
  breq cproHandleNeedAddr_done          ; we have no address, don't handle
  ldi r24, CPRO_MODE_SENDING_HAVE_ADDR  ; start singleshot timer for sending HAVE_ADDRESS
  sts cproMode, r24
  lds r24, com2Address
  clr r25
  lsl r24                               ; *2
  rol r25
  lsl r24                               ; *4
  rol r25
  lsl r24                               ; *8
  rol r25
  adiw r25:r24, 30                      ; add 3 secs
  mov r18, r24
  mov r19, r25
  rjmp cproAddressSetTimer
cproHandleNeedAddr_done:
  sec
  ret



cproHandleHaveAddr:
  lds r17, cproMode
  cpi r17, CPRO_MODE_GETADDRSTARTED
  brne cproHandleHaveAddr_done
  ; validate address
  adiw xh:xl, CPRO_PACKET_HAVEADDR_OFFS_ADDRESS
  ld r16, x
  sbiw xh:xl, CPRO_PACKET_HAVEADDR_OFFS_ADDRESS
  tst r16
  breq cproHandleHaveAddr_done  ; invalid address, ignore
  cpi r16, 127
  brcc cproHandleHaveAddr_done  ; invalid address, ignore
  ; set bit corresponding to given address in bitfield of used addresses
  dec r16
  rcall cproSetBitInBitfield
cproHandleHaveAddr_done:
  sec
  ret



cproHandleClaimAddr:
  adiw xh:xl, CPRO_PACKET_CLAIMADDR_OFFS_ADDRESS
  ld r16, x
  sbiw xh:xl, CPRO_PACKET_CLAIMADDR_OFFS_ADDRESS
  tst r16                        ; dont handle claim addr 0
  breq cproHandleClaimAddr_done
  cpi r16, 0xff                  ; dont handle claim addr 0
  breq cproHandleClaimAddr_done
  lds r17, com2Address
  tst r17
  breq cproHandleClaimAddr_done  ; we have no address, yet
  cp r16, r17
  brne cproHandleClaimAddr_done  ; not our address
  ldi r16, CPRO_MODE_SEND_DENY_ADDR
  sts cproMode, r16
  rcall cproAddressSetTimer1s
  
cproHandleClaimAddr_done:
  sec
  ret



cproHandleDenyAddr:
  ; check mode
  lds r17, cproMode
  cpi r17, CPRO_MODE_CLAIMING_ADDR1
  brcs cproHandleDenyAddr_notInClaimAddr13Mode
  cpi r17, CPRO_MODE_CLAIMING_ADDR3+1
  brcc cproHandleDenyAddr_notInClaimAddr13Mode
  ; we are in one of the three CLAIM_ADDRESS modes and received a DENY_ADDR, check address
  adiw xh:xl, CPRO_PACKET_DENYADDR_OFFS_ADDRESS
  ld r16, x
  sbiw xh:xl, CPRO_PACKET_DENYADDR_OFFS_ADDRESS
  lds r17, cproAddrRangeBegin
  cp r16, r17
  brne cproHandleDenyAddr_done            ; not our currently claimed address, ignore
  ; someone denied us our claimed address, try next
  rcall cproGetNextFreeAddr
  brcs cproHandleDenyAddr_gotFreeAddr
  ; no free address, abort  TODO: send an error message to bus ("bus full")
  ldi r16, CPRO_MODE_NOADDRESS
  sts cproMode, r16
  ret
cproHandleDenyAddr_gotFreeAddr:          ; claim next address
  ldi r16, CPRO_MODE_SEND_CLAIM_ADDR1
  sts cproMode, r16
  rcall cproAddressSetTimer1s            ; start timer
  rjmp cproHandleDenyAddr_done
cproHandleDenyAddr_notInClaimAddr13Mode: ; reclaim mode?
  lds r17, cproMode
  cpi r17, CPRO_MODE_RECLAIMING_ADDR
  brne cproHandleDenyAddr_done
  ; reclaiming went wrong, go through full address assignment protocol
  rcall CPRO_StartGetAddrProcedure
cproHandleDenyAddr_done:
  sec
  ret


