forked from trabucayre/openFPGALoader
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdfu.hpp
247 lines (227 loc) · 7.8 KB
/
dfu.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (c) 2021 Gwenhael Goavec-Merou <[email protected]>
*/
#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_