Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
23cbdbf0eThis file is pinned to the selected release. Download the original to open it in your design tool.
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
*/
#ifndef SRC_DFU_HPP_
#define SRC_DFU_HPP_
#include <libusb.h>
#include <map>
#include <string>
#include <vector>
#include "dfuFileParser.hpp"
class DFU {
public:
/*!
* \brief contructor
* \param[in] filename: bitstream
* \param[in] vid: vendor id
* \param[in] pid: product id
* \param[in] altsetting: device altsetting to use
* \param[in] verbose_lvl: verbose level 0 normal, -1 quiet, 1 verbose
*/
DFU(const std::string &filename, bool bypass_bitstream,
uint16_t vid, uint16_t pid,
int16_t altsetting, int verbose_lvl);
~DFU();
/*!
* \brief enumerate all USB peripherals configuration to detect DFU devices
* \return EXIT_FAILURE when something is wrong, EXIT_SUCCESS otherwise
*/
int searchDFUDevices();
/*!
* \brief display details about all DFU compatible devices found
*/
void displayDFU();
/*!
* \brief download file content
* \param[in] filename: filename to download
*/
int download();
private:
/**
* \brief dfu descriptor structure (not provided by libusb
*/
struct dfu_desc {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bmAttributes;
uint16_t wDetachTimeOut;
uint16_t wTransferSize;
uint16_t bcdDFUVersion;
} __attribute__((__packed__));
struct dfu_dev {
uint16_t vid;
uint16_t pid;
uint8_t bus;
uint8_t interface;
uint16_t altsettings;
uint8_t device;
uint8_t path[8];
uint8_t iProduct[128];
uint8_t iInterface[128];
uint32_t bMaxPacketSize0;
struct dfu_desc dfu_desc;
};
/* USB Device firmware Upgrade Specification, Revision 1.1 6.1.2 */
/* p.20 */
struct dfu_status {
uint8_t bStatus;
uint32_t bwPollTimeout;
uint8_t bState;
uint8_t iString;
};
/* USB Device firmware Upgrade Specification, Revision 1.1 6.1.2 */
/* p.21 */
enum dfu_dev_status {
STATUS_OK = 0x00,
STATUS_errTARGET = 0x01,
STATUS_errFILE = 0x02,
STATUS_errWRITE = 0x03,
STATUS_errERASE = 0x04,
STATUS_errCHECK_ERASED = 0x05,
STATUS_errPROG = 0x06,
STATUS_errVERIFY = 0x07,
STATUS_errADDRESS = 0x08,
STATUS_errNOTDONE = 0x09,
STATUS_errFIRMWARE = 0x0A,
STATUS_errVENDOR = 0x0B,
STATUS_errUSBR = 0x0C,
STATUS_errPOR = 0x0D,
STATUS_errUNKNOWN = 0x0E,
STATUS_errSTALLEDPKT = 0x0F
};
std::map<uint8_t, std::string> dfu_dev_status_val = {
{STATUS_OK, "STATUS_OK"},
{STATUS_errTARGET, "STATUS_errTARGET"},
{STATUS_errFILE, "STATUS_errFILE"},
{STATUS_errWRITE, "STATUS_errWRITE"},
{STATUS_errERASE, "STATUS_errERASE"},
{STATUS_errCHECK_ERASED, "STATUS_errCHECK_ERASED"},
{STATUS_errPROG, "STATUS_errPROG"},
{STATUS_errVERIFY, "STATUS_errVERIFY"},
{STATUS_errADDRESS, "STATUS_errADDRESS"},
{STATUS_errNOTDONE, "STATUS_errNOTDONE"},
{STATUS_errFIRMWARE, "STATUS_errFIRMWARE"},
{STATUS_errVENDOR, "STATUS_errVENDOR"},
{STATUS_errUSBR, "STATUS_errUSBR"},
{STATUS_errPOR, "STATUS_errPOR"},
{STATUS_errUNKNOWN, "STATUS_errUNKNOWN"},
{STATUS_errSTALLEDPKT, "STATUS_errSTALLEDPKT"}
};
/* p.22 */
enum dfu_dev_state {
STATE_appIDLE = 0,
STATE_appDETACH = 1,
STATE_dfuIDLE = 2,
STATE_dfuDNLOAD_SYNC = 3,
STATE_dfuDNBUSY = 4,
STATE_dfuDNLOAD_IDLE = 5,
STATE_dfuMANIFEST_SYNC = 6,
STATE_dfuMANIFEST = 7,
STATE_dfuMANIFEST_WAIT_RESET = 8,
STATE_dfuUPLOAD_IDLE = 9,
STATE_dfuERROR = 10
};
std::map <uint8_t, std::string> dfu_dev_state_val = {
{STATE_appIDLE, "STATE_appIDLE"},
{STATE_appDETACH, "STATE_appDETACH"},
{STATE_dfuIDLE, "STATE_dfuIDLE"},
{STATE_dfuDNLOAD_SYNC, "STATE_dfuDNLOAD-SYNC"},
{STATE_dfuDNBUSY, "STATE_dfuDNBUSY"},
{STATE_dfuDNLOAD_IDLE, "STATE_dfuDNLOAD-IDLE"},
{STATE_dfuMANIFEST_SYNC, "STATE_dfuMANIFEST-SYNC"},
{STATE_dfuMANIFEST, "STATE_dfuMANIFEST"},
{STATE_dfuMANIFEST_WAIT_RESET, "STATE_dfuMANIFEST-WAIT-RESET"},
{STATE_dfuUPLOAD_IDLE, "STATE_dfuUPLOAD-IDLE"},
{STATE_dfuERROR, "STATE_dfuERROR"}
};
/*!
* \brief take control to the DFU device
* \param[in] index: device index in dfu_dev list
* \return EXIT_FAILURE when open device fails, EXIT_SUCCESS otherwise
*/
int open_DFU(int index);
/*!
* \brief release control to the DFU device
* \return EXIT_FAILURE when close fails, EXIT_SUCCESS otherwise
*/
int close_DFU();
/*!
* \brief send detach command
* return EXIT_FAILURE when transaction fails, EXIT_SUCCESS otherwise
*/
int dfu_detach();
/*!
* \brief read device status
* \param[out] status: struct dfu_status device payload
* return error/return code from libusb or number of bytes read/write
*/
int get_status(struct dfu_status *status);
/*!
* \brief move through DFU state from current state to newState
* \param[in] newState: targeted state
* \return -1 when something fail, 0 otherwise
*/
int set_state(char newState);
/*!
* \brief get current state without changing DFU state (6.1.5)
* \return -1 when USB transaction fail, state otherwise
*/
char get_state();
/*!
* \brief poll status until device is in state mode
* \param[in] targeted state
* \return value < 0 when transaction fails, new state otherwise
*/
int poll_state(uint8_t state);
/*!
* \brief verify if DFU device always exist
* \return false if lost, true if present
*/
bool checkDevicePresent();
/*!
* \brief send an IN/OUT request
*/
int send(bool out, uint8_t brequest, uint16_t wvalue,
const uint8_t *data, uint16_t length);
/*!
* \brief fill specific DFU structure with extra descriptor
* \param[in] intf: interface descriptor with extra area
* \param[out] dfu_desc: DFU descriptor
* \param[in] dfu_desc_size: DFU descriptor structure size
* \return false if extra len is too small, true otherwise
* */
bool parseDFUDescriptor(const struct libusb_interface_descriptor *intf,
uint8_t *dfu_desc, int dfu_desc_size);
/*!
* \brief try to open device specified by vid and pid. If found
* search for compatible interface
* \param[in] vid: USB VID
* \param[in] pid: USB PID
* \return false when no device, unable to connect, or no DFU interface.
*/
bool searchWithVIDPID(uint16_t vid, uint16_t pid);
/*!
* \brief search, for the specified device, if it has a DFU interface
* \param[in] dev: USB device
* \param[in] desc: USB device descriptor
* \return 1 when can't read config, 0 otherwise
*/
int searchIfDFU(struct libusb_device_handle *handle,
struct libusb_device *dev,
struct libusb_device_descriptor *desc);
bool _verbose; /**< display more message */
bool _debug; /**< display debug message */
bool _quiet; /**< don't use progressBar */
std::vector<struct dfu_dev> dfu_dev; /**< available dfu devices */
int dev_idx; /**< device index in dfu_dev */
uint16_t _vid; /**< device Vendor ID */
uint16_t _pid; /**< device Product ID */
int16_t _altsetting; /**< device altsetting */
struct libusb_context *usb_ctx; /**< usb context */
libusb_device_handle * dev_handle; /**< current device handle */
int curr_intf; /**< device interface to use */
int transaction; /**< download transaction ID */
DFUFileParser *_bit; /**< dfu file to load */
};
#endif // SRC_DFU_HPP_