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



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

.dseg

flashDataBegin:
  flashUid:         .byte 4
  flashSendBuffer:  .byte 32
  flashRecvBuffer:  .byte FLASH_RECVBUFFER_MAXLEN
flashDataEnd:



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

.cseg


; ---------------------------------------------------------------------------
; @routine checkFlash
;
; Send a FLASH_READY message and wait for about 10s for incoming FLASH_START
; which is then handled (i.e. FLASH_RESPONSE send).
;
; @return CFLAG set if incoming flash request received, cleared otherwise
; @return R16 message type received (if CFLAG set)
; @clobbers r16, r20, X, (r17, r18, r19, r22, y, z)

checkFlash:
  rcall flashReadUidIntoSdram          ; R16, X, Y
  rcall ioRawInit                      ; (R16, R17)

  ldi xl, LOW(flashSendBuffer)
  ldi xh, HIGH(flashSendBuffer)
  rcall flashProcessWriteFlashReady    ; (R16, R17, R18, R19, R20, Y, Z)
  rcall ioRawSendMsg                   ; (r16, r17, X)

  ldi r16, NETMSG_CMD_FLASH_START
  ldi r20, FLASH_WAITFORSTART_TRIES
  rcall ioWaitForGivenMsg              ; (r16, r17, r18, r19, r20, r22, X)
  brcc checkFlash_end
  
  cpi r16, NETMSG_CMD_FLASH_START
  clc
  brne checkFlash_end                  ; no FLASH_START msg received

  ; check flashStart message (for us?)
  ldi xl, LOW(flashRecvBuffer)
  ldi xh, HIGH(flashRecvBuffer)
  rcall flashProcessHandleFlashStart
;  brcc checkFlash_end
;  sec
checkFlash_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine flashProcess
;
; handling receiving FLASH_DATA and FLASH_END messages, flash new firmware
;
; @return CFLAG set if okay, cleared otherwise
; @clobbers r16, r20 (R0, R1, R15, R16, R17, R18, R19, R22, R24, Z)

flashProcess:
  rcall Flash_Init
flashProcess_loop1:
    ; wait up to 10s for incoming FLASH_DATA message
    ldi r16, NETMSG_CMD_FLASH_DATA
    ldi r20, FLASH_WAITFORDATA_TRIES
    rcall ioWaitForGivenMsg            ; (r16, r17, r18, r19, r20, r22, X)
;    brcc flashProcess_end              ; no FLASH_DATA or FLASH_END msg
    brcc flashProcess_loop1end         ; no FLASH_DATA or FLASH_END msg, retry indefinately
    ; either FLASH_DATA or FLASH_END received
    ldi xl, LOW(flashRecvBuffer)
    ldi xh, HIGH(flashRecvBuffer)
    cpi r16, NETMSG_CMD_FLASH_DATA     ; not FLASH_DATA, flashing ended/aborted
    brne flashProcess_endReceived      ; FLASH_END received, done
    rcall flashProcessHandleFlashData  ; (R0, R1, R15, R16, R17, R18, R19, R20, R22, R24, Z)
flashProcess_loop1end:
  rjmp flashProcess_loop1
flashProcess_endReceived:
  rcall flashProcessHandleFlashEnd
  sec
flashProcess_end:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine flashProcessHandleFlashStart
; Handle FLASH START packet.
;
; @return CFLAG set if message is for us, cleared otherwise
; @param X  buffer containing the message
; @clobbers r16, (R15, R17, R18, R19, R20, R21, R22, X)

flashProcessHandleFlashStart:
  rcall flashProcessCheckFlashStart
  brcc flashProcessHandleFlashStart_notMe
  ; okay, flash start message is for us
  rcall flashWaitFor100ms                    ; TODO: Shorten wait time!!
  clr r16
  rcall flashProcessSendFlashResponse        ; (R15, R16, R17, R18, R19, R20, R21, R22, X)

  sec
flashProcessHandleFlashStart_notMe:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine flashProcessCheckFlashStart
;
; Check whether the UID in the given msg matches our UID.
;
; @return CFLAG set if message is for us, cleared otherwise
; @param  X  buffer containing the message
; @clobbers r16, r17, r18, X, Y

flashProcessCheckFlashStart:
  ldi yh, HIGH(flashUid)
  ldi yl, LOW(flashUid)
  adiw xh:xl, FLASH_PACKET_START_OFFS_UID
  ldi r18, 4
flashProcessCheckFlashStart_loop:
    ld r16, X+
    ld r17, Y+
    cp r16, r17
    brne flashProcessCheckFlashStart_notMe
    dec r18
  brne flashProcessCheckFlashStart_loop
  sec
  ret
flashProcessCheckFlashStart_notMe:
  clc
  ret
; @end



; ---------------------------------------------------------------------------
; @routine flashProcessHandleFlashData

; Handle FLASH DATA packet.
;
; @return CFLAG set if okay, cleared otherwise
; @param  X  buffer containing the message
; @clobbers R0, R1, R18, Z (R15, R16, R17, R19, R20, R22, R24)

flashProcessHandleFlashData:
  mov yl, xl
  mov yh, xh
  ldd r17, Y+FLASH_MSG_OFFS_MSGLEN           ; msg length
  subi r17, 6                                ; remaining length (sub cmd(1), src(1), addr(4))
  brcs flashProcessHandleFlashData_badData   ; too few payload bytes
  breq flashProcessHandleFlashData_badData   ; no payload bytes
  ldd zl, Y+FLASH_PACKET_DATA_OFFS_ADDR      ; only read lower two address bytes
  ldd zh, Y+(FLASH_PACKET_DATA_OFFS_ADDR+1)
  adiw yh:yl, FLASH_PACKET_DATA_OFFS_ADDR+4
  rcall Flash_WriteData                      ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
  clr r16
  rjmp flashProcessHandleFlashData_sendResponse
flashProcessHandleFlashData_badData:
  ldi r16, FLASH_ERROR_MSGERROR
flashProcessHandleFlashData_sendResponse:
#if 0
  push r16
    ; send flash message back (debugging)
;    ldi r24, 2
;    rcall flashWaitForMillisecs                ; (R22, R24)
    ldi xl, LOW(flashRecvBuffer)
    ldi xh, HIGH(flashRecvBuffer)
    rcall ioRawSendPacket                      ; (r16, r17, X)
  pop r16
#endif

;  ldi r24, 2
;  rcall flashWaitForMillisecs                ; (R22, R24)
  rcall flashProcessSendFlashResponse        ; (R16, R17, R18, R19, R20, X)
  sbi LED_PIN, LED_PINNUM                    ; toggle
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine flashProcessHandleFlashEnd
;
; Handle FLASH END packet.
;
; @return CFLAG set if okay, cleared otherwise
; @param  X  buffer containing the message
; @clobbers r16, X (R17, R18, R19, R20)

flashProcessHandleFlashEnd:
  rcall Flash_Fini                       ; flash pending data
  rcall flashWaitFor100ms
  clr r16
  rcall flashProcessSendFlashResponse    ; (R16, R17, R18, R19, R20, X)
  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine flashProcessSendFlashResponse
; Create and send a FLASH RESPONSE packet
;
; @param R16  response code to send
; @clobbers X (R16, R17, R18, R19, R20)

flashProcessSendFlashResponse:
  ; send flash response message
  ldi xl, LOW(flashSendBuffer)
  ldi xh, HIGH(flashSendBuffer)
  rcall flashProcessWriteFlashRsp  ; (R16, R17, R18, R19, R20, X)
  rjmp ioRawSendMsg                ; (R16, R17, X)
; @end



; ---------------------------------------------------------------------------
; @routine flashProcessWriteFlashRsp
; Write a FLASH_RESPONSE packet.
;
; @param  R16 response code (0 if ok, error code otherwise)
; @param  X   buffer to write to
; @clobbers R18 (R16, R17, R19, R20, X)

flashProcessWriteFlashRsp:
  clr r18
  st X+, r18  ; dest address (unused)
  ldi r18, 3  ; msg code+src address+one payload byte
  st X+, r18  ; msg len
  ldi r17, NETMSG_CMD_FLASH_RSP
  st X+, r17  ; msg code
  clr r17
  st X+, r17  ; src address (not used)
  st X+, r16  ; payload byte
  sbiw xh:xl, 5
  rcall NETMSG_CalcAndAddChecksumByte ; (R16, R17, R18, R19, R20, X)
  sbiw xh:xl, 6
  ret
; @end



; ---------------------------------------------------------------------------
; Write a FLASH_READY packet.
;
; @param X  buffer to write to
; @clobbers R16, R18, Y, Z (R17, R19, R20)

flashProcessWriteFlashReady:
  ldi r16, 0xff
  st X+, r16                          ; dest address (unused)
  ldi r16, 20                         ; msg code+src address+18 payload bytes
  st X+, r16                          ; msg len
  ldi r16, NETMSG_CMD_FLASH_READY
  st X+, r16                          ; msg code
  ldi r16, NET_MAINTENANCE_ADDR
  st X+, r16                          ; src address

  ; payload
  ldi yh, HIGH(flashUid)              ; 4 bytes
  ldi yl, LOW(flashUid)
  ldi r18, 4
  rcall Utils_Copy_SDRAM              ; (R17, R18, X, Y)

  ldi zl, LOW(devInfoBlock*2)         ; 12 bytes
  ldi zh, HIGH(devInfoBlock*2)
  ldi r18, 12
  rcall Utils_CopyFromFlash           ; (R16, R18, X, Z)

  ldi r16, LOW(PAGESIZE*2)            ; 2 bytes
  st X+, r16
  ldi r16, HIGH(PAGESIZE*2)
  st X+, r16

  sbiw xh:xl, 22                      ; go back to beginning of message
  rcall NETMSG_CalcAndAddChecksumByte ; (R16, R17, R18, R19, R20, X)
  sbiw xh:xl, 23                      ; go back to beginning of message
  ret
; @end





