1 /*!
2 \file dfu_core.c
3 \brief USB DFU device class core functions
4
5 \version 2020-08-04, V1.1.0, firmware for GD32VF103
6 \version 2020-12-11, V1.1.1, firmware for GD32VF103
7 */
8
9 /*
10 Copyright (c) 2020, GigaDevice Semiconductor Inc.
11
12 Redistribution and use in source and binary forms, with or without modification,
13 are permitted provided that the following conditions are met:
14
15 1. Redistributions of source code must retain the above copyright notice, this
16 list of conditions and the following disclaimer.
17 2. Redistributions in binary form must reproduce the above copyright notice,
18 this list of conditions and the following disclaimer in the documentation
19 and/or other materials provided with the distribution.
20 3. Neither the name of the copyright holder nor the names of its contributors
21 may be used to endorse or promote products derived from this software without
22 specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 OF SUCH DAMAGE.
34 */
35
36 #include "dfu_core.h"
37 #include "drv_usb_hw.h"
38 #include "dfu_mal.h"
39 #include "flash_if.h"
40 #include <string.h>
41
42 #define USBD_VID 0x28E9U
43 #define USBD_PID 0x0189U
44
45 /* local function prototypes ('static') */
46 static uint8_t dfu_init(usb_dev *udev, uint8_t config_index);
47 static uint8_t dfu_deinit(usb_dev *udev, uint8_t config_index);
48 static uint8_t dfu_req_handler(usb_dev *udev, usb_req *req);
49 static uint8_t dfu_ctlx_in(usb_dev *udev);
50 static void dfu_detach(usb_dev *udev, usb_req *req);
51 static void dfu_dnload(usb_dev *udev, usb_req *req);
52 static void dfu_upload(usb_dev *udev, usb_req *req);
53 static void dfu_getstatus(usb_dev *udev, usb_req *req);
54 static void dfu_clrstatus(usb_dev *udev, usb_req *req);
55 static void dfu_getstate(usb_dev *udev, usb_req *req);
56 static void dfu_abort(usb_dev *udev, usb_req *req);
57 static void dfu_mode_leave(usb_dev *udev);
58 static uint8_t dfu_getstatus_complete (usb_dev *udev);
59
60 static void (*dfu_request_process[])(usb_dev *udev, usb_req *req) =
61 {
62 [DFU_DETACH] = dfu_detach,
63 [DFU_DNLOAD] = dfu_dnload,
64 [DFU_UPLOAD] = dfu_upload,
65 [DFU_GETSTATUS] = dfu_getstatus,
66 [DFU_CLRSTATUS] = dfu_clrstatus,
67 [DFU_GETSTATE] = dfu_getstate,
68 [DFU_ABORT] = dfu_abort
69 };
70
71 /* note:it should use the c99 standard when compiling the below codes */
72 /* USB standard device descriptor */
73 const usb_desc_dev dfu_dev_desc =
74 {
75 .header =
76 {
77 .bLength = USB_DEV_DESC_LEN,
78 .bDescriptorType = USB_DESCTYPE_DEV
79 },
80 .bcdUSB = 0x0200U,
81 .bDeviceClass = 0x00U,
82 .bDeviceSubClass = 0x00U,
83 .bDeviceProtocol = 0x00U,
84 .bMaxPacketSize0 = USB_FS_EP0_MAX_LEN,
85 .idVendor = USBD_VID,
86 .idProduct = USBD_PID,
87 .bcdDevice = 0x0100U,
88 .iManufacturer = STR_IDX_MFC,
89 .iProduct = STR_IDX_PRODUCT,
90 .iSerialNumber = STR_IDX_SERIAL,
91 .bNumberConfigurations = USBD_CFG_MAX_NUM
92 };
93
94 /* USB device configuration descriptor */
95 const usb_dfu_desc_config_set dfu_config_desc =
96 {
97 .config =
98 {
99 .header =
100 {
101 .bLength = sizeof(usb_desc_config),
102 .bDescriptorType = USB_DESCTYPE_CONFIG
103 },
104 .wTotalLength = USB_DFU_CONFIG_DESC_SIZE,
105 .bNumInterfaces = 0x01U,
106 .bConfigurationValue = 0x01U,
107 .iConfiguration = 0x04U,
108 .bmAttributes = 0x80U,
109 .bMaxPower = 0x32U
110 },
111
112 .dfu_itf =
113 {
114 .header =
115 {
116 .bLength = sizeof(usb_desc_itf),
117 .bDescriptorType = USB_DESCTYPE_ITF
118 },
119 .bInterfaceNumber = 0x00U,
120 .bAlternateSetting = 0x00U,
121 .bNumEndpoints = 0x00U,
122 .bInterfaceClass = USB_DFU_CLASS,
123 .bInterfaceSubClass = USB_DFU_SUBCLASS_UPGRADE,
124 .bInterfaceProtocol = USB_DFU_PROTOCL_DFU,
125 .iInterface = 0x05U
126 },
127
128 .dfu_func =
129 {
130 .header =
131 {
132 .bLength = sizeof(usb_desc_dfu_func),
133 .bDescriptorType = DFU_DESC_TYPE
134 },
135 .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD | USB_DFU_WILL_DETACH,
136 .wDetachTimeOut = 0x00FFU,
137 .wTransferSize = TRANSFER_SIZE,
138 .bcdDFUVersion = 0x011AU,
139 },
140 };
141
142 /* USB language ID Descriptor */
143 static const usb_desc_LANGID usbd_language_id_desc =
144 {
145 .header = {
146 .bLength = sizeof(usb_desc_LANGID),
147 .bDescriptorType = USB_DESCTYPE_STR
148 },
149 .wLANGID = ENG_LANGID
150 };
151
152 /* USB manufacture string */
153 static const usb_desc_str manufacturer_string =
154 {
155 .header =
156 {
157 .bLength = USB_STRING_LEN(10U),
158 .bDescriptorType = USB_DESCTYPE_STR,
159 },
160 .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
161 };
162
163 /* USB product string */
164 static const usb_desc_str product_string =
165 {
166 .header =
167 {
168 .bLength = USB_STRING_LEN(12U),
169 .bDescriptorType = USB_DESCTYPE_STR,
170 },
171 .unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'D', 'F', 'U'}
172 };
173
174 /* USBD serial string */
175 static usb_desc_str serial_string =
176 {
177 .header =
178 {
179 .bLength = USB_STRING_LEN(2U),
180 .bDescriptorType = USB_DESCTYPE_STR,
181 }
182 };
183
184 /* USB configure string */
185 static const usb_desc_str config_string =
186 {
187 .header =
188 {
189 .bLength = USB_STRING_LEN(15U),
190 .bDescriptorType = USB_DESCTYPE_STR,
191 },
192 .unicode_string = {'G', 'D', '3', '2', ' ', 'U', 'S', 'B', ' ', 'C', 'O', 'N', 'F', 'I', 'G'}
193 };
194
195 static const usb_desc_str interface_string =
196 {
197 .header =
198 {
199 .bLength = USB_STRING_LEN(44U),
200 .bDescriptorType = USB_DESCTYPE_STR,
201 },
202 .unicode_string = {'@', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'F', 'l', 'a', 's', 'h', ' ', '/', '0', 'x', '0', '8', '0', '0',
203 '0', '0', '0', '0', '/', '1', '6', '*', '0', '0', '1', 'K', 'a', ',', '4', '8', '*', '0', '0', '1', 'K', 'g'}
204 };
205
206 void *const usbd_dfu_strings[] =
207 {
208 [STR_IDX_LANGID] = (uint8_t *)&usbd_language_id_desc,
209 [STR_IDX_MFC] = (uint8_t *)&manufacturer_string,
210 [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
211 [STR_IDX_SERIAL] = (uint8_t *)&serial_string,
212 [STR_IDX_CONFIG] = (uint8_t *)&config_string,
213 [STR_IDX_ITF] = (uint8_t *)&interface_string
214 };
215
216 usb_desc dfu_desc = {
217 .dev_desc = (uint8_t *)&dfu_dev_desc,
218 .config_desc = (uint8_t *)&dfu_config_desc,
219 .strings = usbd_dfu_strings
220 };
221
222 usb_class_core dfu_class = {
223 .init = dfu_init,
224 .deinit = dfu_deinit,
225 .req_proc = dfu_req_handler,
226 .ctlx_in = dfu_ctlx_in
227 };
228
229 /*!
230 \brief initialize the DFU device
231 \param[in] udev: pointer to USB device instance
232 \param[in] config_index: configuration index
233 \param[out] none
234 \retval USB device operation status
235 */
dfu_init(usb_dev * udev,uint8_t config_index)236 static uint8_t dfu_init (usb_dev *udev, uint8_t config_index)
237 {
238 static usbd_dfu_handler dfu_handler;
239
240 /* unlock the internal flash */
241 dfu_mal_init();
242
243 memset((void *)&dfu_handler, 0, sizeof(usbd_dfu_handler));
244
245 dfu_handler.base_addr = APP_LOADED_ADDR;
246 dfu_handler.manifest_state = MANIFEST_COMPLETE;
247 dfu_handler.bState = STATE_DFU_IDLE;
248 dfu_handler.bStatus = STATUS_OK;
249
250 udev->dev.class_data[USBD_DFU_INTERFACE] = (void *)&dfu_handler;
251
252 return USBD_OK;
253 }
254
255 /*!
256 \brief de-initialize the DFU device
257 \param[in] udev: pointer to USB device instance
258 \param[in] config_index: configuration index
259 \param[out] none
260 \retval USB device operation status
261 */
dfu_deinit(usb_dev * udev,uint8_t config_index)262 static uint8_t dfu_deinit (usb_dev *udev, uint8_t config_index)
263 {
264 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
265
266 /* restore device default state */
267 memset(udev->dev.class_data[USBD_DFU_INTERFACE], 0, sizeof(usbd_dfu_handler));
268
269 dfu->bState = STATE_DFU_IDLE;
270 dfu->bStatus = STATUS_OK;
271
272 /* lock the internal flash */
273 dfu_mal_deinit();
274
275 return USBD_OK;
276 }
277
278 /*!
279 \brief handle the DFU class-specific requests
280 \param[in] udev: pointer to USB device instance
281 \param[in] req: device class-specific request
282 \param[out] none
283 \retval USB device operation status
284 */
dfu_req_handler(usb_dev * udev,usb_req * req)285 static uint8_t dfu_req_handler (usb_dev *udev, usb_req *req)
286 {
287 if (req->bRequest < DFU_REQ_MAX) {
288 dfu_request_process[req->bRequest](udev, req);
289 } else {
290 return USBD_FAIL;
291 }
292
293 return USBD_OK;
294 }
295
296 /*!
297 \brief handle data Stage
298 \param[in] udev: pointer to USB device instance
299 \param[in] ep_num: the endpoint number
300 \param[out] none
301 \retval USB device operation status
302 */
dfu_ctlx_in(usb_dev * udev)303 static uint8_t dfu_ctlx_in (usb_dev *udev)
304 {
305 dfu_getstatus_complete(udev);
306
307 return USBD_OK;
308 }
309
310 /*!
311 \brief leave DFU mode and reset device to jump to user loaded code
312 \param[in] udev: pointer to USB device instance
313 \param[out] none
314 \retval none
315 */
dfu_mode_leave(usb_dev * udev)316 static void dfu_mode_leave (usb_dev *udev)
317 {
318 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
319
320 dfu->manifest_state = MANIFEST_COMPLETE;
321
322 if (dfu_config_desc.dfu_func.bmAttributes & 0x04U) {
323 dfu->bState = STATE_DFU_MANIFEST_SYNC;
324 } else {
325 dfu->bState = STATE_DFU_MANIFEST_WAIT_RESET;
326
327 /* lock the internal flash */
328 dfu_mal_deinit();
329
330 /* generate system reset to allow jumping to the user code */
331 eclic_system_reset();
332 }
333 }
334
335 /*!
336 \brief handle data IN stage in control endpoint 0
337 \param[in] udev: pointer to usb device instance
338 \param[out] none
339 \retval usb device operation status
340 */
dfu_getstatus_complete(usb_dev * udev)341 static uint8_t dfu_getstatus_complete (usb_dev *udev)
342 {
343 uint32_t addr;
344
345 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
346
347 if (STATE_DFU_DNBUSY == dfu->bState) {
348 /* decode the special command */
349 if (0U == dfu->block_num) {
350 if (1U == dfu->data_len){
351 if (GET_COMMANDS == dfu->buf[0]) {
352 /* no operation */
353 }
354 } else if (5U == dfu->data_len) {
355 if (SET_ADDRESS_POINTER == dfu->buf[0]) {
356 /* set flash operation address */
357 dfu->base_addr = *(uint32_t *)(dfu->buf + 1U);
358 } else if (ERASE == dfu->buf[0]) {
359 dfu->base_addr = *(uint32_t *)(dfu->buf + 1U);
360
361 dfu_mal_erase(dfu->base_addr);
362 } else {
363 /* no operation */
364 }
365 } else {
366 /* no operation */
367 }
368 } else if (dfu->block_num > 1U) { /* regular download command */
369 /* decode the required address */
370 addr = (dfu->block_num - 2U) * TRANSFER_SIZE + dfu->base_addr;
371
372 dfu_mal_write (dfu->buf, addr, dfu->data_len);
373
374 dfu->block_num = 0U;
375 } else {
376 /* no operation */
377 }
378
379 dfu->data_len = 0U;
380
381 /* update the device state and poll timeout */
382 dfu->bState = STATE_DFU_DNLOAD_SYNC;
383
384 return USBD_OK;
385 } else if (dfu->bState == STATE_DFU_MANIFEST) { /* manifestation in progress */
386 /* start leaving DFU mode */
387 dfu_mode_leave(udev);
388 } else {
389 /* no operation */
390 }
391
392 return USBD_OK;
393 }
394
395 /*!
396 \brief handle the DFU_DETACH request
397 \param[in] udev: pointer to usb device instance
398 \param[in] req: DFU class request
399 \param[out] none
400 \retval none.
401 */
dfu_detach(usb_dev * udev,usb_req * req)402 static void dfu_detach(usb_dev *udev, usb_req *req)
403 {
404 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
405
406 switch (dfu->bState) {
407 case STATE_DFU_IDLE:
408 case STATE_DFU_DNLOAD_SYNC:
409 case STATE_DFU_DNLOAD_IDLE:
410 case STATE_DFU_MANIFEST_SYNC:
411 case STATE_DFU_UPLOAD_IDLE:
412 dfu->bStatus = STATUS_OK;
413 dfu->bState = STATE_DFU_IDLE;
414 dfu->iString = 0U; /* iString */
415
416 dfu->block_num = 0U;
417 dfu->data_len = 0U;
418 break;
419
420 default:
421 break;
422 }
423
424 /* check the detach capability in the DFU functional descriptor */
425 if (dfu_config_desc.dfu_func.wDetachTimeOut & DFU_DETACH_MASK) {
426 usbd_disconnect (udev);
427
428 usbd_connect (udev);
429 } else {
430 /* wait for the period of time specified in detach request */
431 usb_mdelay (4U);
432 }
433 }
434
435 /*!
436 \brief handle the DFU_DNLOAD request
437 \param[in] udev: pointer to usb device instance
438 \param[in] req: DFU class request
439 \param[out] none
440 \retval none
441 */
dfu_dnload(usb_dev * udev,usb_req * req)442 static void dfu_dnload(usb_dev *udev, usb_req *req)
443 {
444 usb_transc *transc = &udev->dev.transc_out[0];
445 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
446
447 switch (dfu->bState) {
448 case STATE_DFU_IDLE:
449 case STATE_DFU_DNLOAD_IDLE:
450 if (req->wLength > 0U) {
451 /* update the global length and block number */
452 dfu->block_num = req->wValue;
453 dfu->data_len = req->wLength;
454
455 dfu->bState = STATE_DFU_DNLOAD_SYNC;
456
457 transc->remain_len = dfu->data_len;
458 transc->xfer_buf = dfu->buf;
459 } else {
460 dfu->manifest_state = MANIFEST_IN_PROGRESS;
461 dfu->bState = STATE_DFU_MANIFEST_SYNC;
462 }
463 break;
464
465 default:
466 break;
467 }
468 }
469
470 /*!
471 \brief handles the DFU UPLOAD request.
472 \param[in] udev: pointer to usb device instance
473 \param[in] req: DFU class request
474 \param[out] none
475 \retval none
476 */
dfu_upload(usb_dev * udev,usb_req * req)477 static void dfu_upload (usb_dev *udev, usb_req *req)
478 {
479 uint8_t *phy_addr = NULL;
480 uint32_t addr = 0U;
481 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
482
483 usb_transc *transc = &udev->dev.transc_in[0];
484
485 if(req->wLength <= 0U) {
486 dfu->bState = STATE_DFU_IDLE;
487 return;
488 }
489
490 switch (dfu->bState) {
491 case STATE_DFU_IDLE:
492 case STATE_DFU_UPLOAD_IDLE:
493 /* update the global length and block number */
494 dfu->block_num = req->wValue;
495 dfu->data_len = req->wLength;
496
497 /* DFU get command */
498 if (0U == dfu->block_num) {
499 /* update the state machine */
500 dfu->bState = (dfu->data_len > 3U) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE;
501
502 /* store the values of all supported commands */
503 dfu->buf[0] = GET_COMMANDS;
504 dfu->buf[1] = SET_ADDRESS_POINTER;
505 dfu->buf[2] = ERASE;
506
507 /* send the status data over EP0 */
508 transc->xfer_buf = &(dfu->buf[0]);
509 transc->remain_len = 3U;
510 } else if (dfu->block_num > 1U) {
511 dfu->bState = STATE_DFU_UPLOAD_IDLE;
512
513 /* change is accelerated */
514 addr = (dfu->block_num - 2U) * TRANSFER_SIZE + dfu->base_addr;
515
516 /* return the physical address where data are stored */
517 phy_addr = dfu_mal_read (dfu->buf, addr, dfu->data_len);
518
519 /* send the status data over EP0 */
520 transc->xfer_buf = phy_addr;
521 transc->remain_len = dfu->data_len;
522 } else {
523 dfu->bState = STATUS_ERR_STALLEDPKT;
524 }
525 break;
526
527 default:
528 dfu->data_len = 0U;
529 dfu->block_num = 0U;
530 break;
531 }
532 }
533
534 /*!
535 \brief handle the DFU_GETSTATUS request
536 \param[in] udev: pointer to usb device instance
537 \param[in] req: DFU class request
538 \param[out] none
539 \retval none
540 */
dfu_getstatus(usb_dev * udev,usb_req * req)541 static void dfu_getstatus (usb_dev *udev, usb_req *req)
542 {
543 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
544
545 usb_transc *transc = &udev->dev.transc_in[0];
546
547 switch (dfu->bState) {
548 case STATE_DFU_DNLOAD_SYNC:
549 if (0U != dfu->data_len) {
550 dfu->bState = STATE_DFU_DNBUSY;
551
552 if (0U == dfu->block_num) {
553 if (ERASE == dfu->buf[0]) {
554 dfu_mal_getstatus (dfu->base_addr, CMD_ERASE, (uint8_t *)&dfu->bwPollTimeout0);
555 } else {
556 dfu_mal_getstatus (dfu->base_addr, CMD_WRITE, (uint8_t *)&dfu->bwPollTimeout0);
557 }
558 }
559 } else {
560 dfu->bState = STATE_DFU_DNLOAD_IDLE;
561 }
562 break;
563
564 case STATE_DFU_MANIFEST_SYNC:
565 if (MANIFEST_IN_PROGRESS == dfu->manifest_state) {
566 dfu->bState = STATE_DFU_MANIFEST;
567 dfu->bwPollTimeout0 = 1U;
568 } else if ((MANIFEST_COMPLETE == dfu->manifest_state) && \
569 (dfu_config_desc.dfu_func.bmAttributes & 0x04U)){
570 dfu->bState = STATE_DFU_IDLE;
571 dfu->bwPollTimeout0 = 0U;
572 } else {
573 /* no operation */
574 }
575 break;
576
577 default:
578 break;
579 }
580
581 /* send the status data of DFU interface to host over EP0 */
582 transc->xfer_buf = (uint8_t *)&(dfu->bStatus);
583 transc->remain_len = 6U;
584 }
585
586 /*!
587 \brief handle the DFU_CLRSTATUS request
588 \param udev: pointer to usb device instance
589 \param[out] none
590 \retval none
591 */
dfu_clrstatus(usb_dev * udev,usb_req * req)592 static void dfu_clrstatus (usb_dev *udev, usb_req *req)
593 {
594 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
595
596 if (STATE_DFU_ERROR == dfu->bState) {
597 dfu->bStatus = STATUS_OK;
598 dfu->bState = STATE_DFU_IDLE;
599 } else {
600 /* state error */
601 dfu->bStatus = STATUS_ERR_UNKNOWN;
602 dfu->bState = STATE_DFU_ERROR;
603 }
604
605 dfu->iString = 0U; /* iString: index = 0 */
606 }
607
608 /*!
609 \brief handle the DFU_GETSTATE request
610 \param[in] udev: pointer to usb device instance
611 \param[out] none
612 \retval none
613 */
dfu_getstate(usb_dev * udev,usb_req * req)614 static void dfu_getstate (usb_dev *udev, usb_req *req)
615 {
616 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
617
618 usb_transc *transc = &udev->dev.transc_in[0];
619
620 /* send the current state of the DFU interface to host */
621 transc->xfer_buf = &(dfu->bState);
622 transc->remain_len = 1U;
623 }
624
625 /*!
626 \brief handle the DFU_ABORT request
627 \param[in] udev: pointer to usb device instance
628 \param[out] none
629 \retval none
630 */
dfu_abort(usb_dev * udev,usb_req * req)631 static void dfu_abort (usb_dev *udev, usb_req *req)
632 {
633 usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
634
635 switch (dfu->bState){
636 case STATE_DFU_IDLE:
637 case STATE_DFU_DNLOAD_SYNC:
638 case STATE_DFU_DNLOAD_IDLE:
639 case STATE_DFU_MANIFEST_SYNC:
640 case STATE_DFU_UPLOAD_IDLE:
641 dfu->bStatus = STATUS_OK;
642 dfu->bState = STATE_DFU_IDLE;
643 dfu->iString = 0U; /* iString: index = 0 */
644
645 dfu->block_num = 0U;
646 dfu->data_len = 0U;
647 break;
648
649 default:
650 break;
651 }
652 }
653