text: // Copyright 2019 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef SRC_CONNECTIVITY_OPENTHREAD_DRIVERS_OT_RADIO_OT_RADIO_BOOTLOADER_H_
  #define SRC_CONNECTIVITY_OPENTHREAD_DRIVERS_OT_RADIO_OT_RADIO_BOOTLOADER_H_
  
  #include "ot_radio.h"
  #include "ot_radio_bootloader_spi_packets.h"
  
  namespace ot {
  
  enum OtRadioBlResult {
    BL_RET_SUCCESS,
  
    // spi transmit failure when sending any of the spi commands.
    // Check bl_zx_status for reason
    BL_ERR_SPI_TRANSMIT_FAILED = -1,
  
    // Final verification of bytes by sending a crc failed
    BL_ERR_VERIFICATION_FAILED = -2,
  
    // Syscall for reading fw bytes failed. Check bl_zx_status
    BL_ERR_GET_FW_BYTES_FAILED = -3,
  
    // Check bl_zx_status for exact reason of failure
    BL_ERR_PUT_RCP_BLMODE_FAIL = -4,
  
    // Check bl_zx_status for exact reason of failure
    BL_ERR_RESET_FAILED = -5,
  
    // Write cmd sent to bootloader returned with a valid response but non-zero
    // status. It can happen if we don't have permission to write to that region
    BL_ERR_WR_CMD_FAILED = -6,
  
    // Bootloader Response received doesn't match cmd field of the cmd sent
    BL_ERR_RESP_CMD_MISMATCH = -7,
  
    // Bootloader response received has incorrect crc
    BL_ERR_RESP_CRC_MISMATCH = -8,
  
    // Bootloader response received doesn't have expected length
    BL_ERR_RESP_LENGTH_MISMATCH = -9,
  
    // Port wait timed out when waiting for response
    BL_ERR_PORT_WAIT_TIMED_OUT = -10,
  
    // Port wait when waiting for response failed for some reason. Check
    // bl_zx_status
    BL_ERR_PORT_WAIT_FAILED = -11,
  
    // port wait received a packet with key EXIT_THREAD
    BL_ERR_PORT_KEY_EXIT_THREAD = -12,
  
    // Firmware is invalid, doesn't have proper version string
    BL_ERR_INVALID_FW_VERSION = -13
  };
  
  class OtRadioDeviceBootloader {
   public:
    OtRadioBlResult UpdateRadioFirmware();
    OtRadioBlResult GetBootloaderVersion(std::string& bl_version);
    zx_status_t PutRcpInBootloader();
    OtRadioDeviceBootloader(OtRadioDevice* dev) : dev_handle_(dev) {}
    zx_status_t GetLastZxStatus();
  
   private:
    OtRadioDevice* dev_handle_;
    zx_status_t GetFirmwareBytes(std::vector<uint8_t>* fw_bytes);
    OtRadioBlResult SendSpiCmdAndGetResponse(uint8_t* cmd, size_t cmd_size, size_t exp_resp_size);
    void PrintSpiCommand(int cmd, void* cmd_ptr, size_t cmd_size);
    OtRadioBlResult SendFlashEraseCmd(uint32_t address, uint32_t length);
    OtRadioBlResult UploadFirmware(const std::vector<uint8_t>& fw_bytes);
    OtRadioBlResult VerifyUpload(const std::vector<uint8_t>& fw_bytes);
    OtRadioBlResult UploadAndCheckFirmware(const std::vector<uint8_t>& fw_bytes);
    bool FirmwareAlreadyUpToDateCRC(const std::vector<uint8_t>& fw_bytes);
    uint32_t BlModeCrc32(uint32_t crc, const void* b, size_t len);
    void BlPrepareCmd(NlSpiBlBasicCmd* cmdp, uint16_t length, uint16_t cmd);
  
    // Address at which firmware is flashed
    static constexpr uint32_t kFwStartAddr = 0x5000;
  
    // A syscall may fail, resulting in some fuction failing. The failing
    // functions return type may not be zx_status_t. Store the last syscall
    // status in this variable which can be inspected by calling function
    // in case of failure
    zx_status_t bl_zx_status = ZX_OK;
  };
  }  // namespace ot
  
  #endif  // SRC_CONNECTIVITY_OPENTHREAD_DRIVERS_OT_RADIO_OT_RADIO_BOOTLOADER_H_
  