GD32F10x USB-Device: E:/USB Libraries/GD32_USB_Device_Library/Class/dfu/src/usbd_dfu_core.c Source File

GD32F103 Firmware

usbd_dfu_core.c
Go to the documentation of this file.
1 
11 /* Includes ------------------------------------------------------------------*/
12 #include "usbd_dfu_core.h"
13 
30 /* DFU Device library callbacks */
31 static uint8_t USBD_DFU_Init (void *pudev, uint8_t ConfigIndex);
32 static uint8_t USBD_DFU_DeInit (void *pudev, uint8_t ConfigIndex);
33 static uint8_t USBD_DFU_GetClassDescriptor (void *pudev, USB_DEVICE_REQ *req);
34 static uint8_t USBD_DFU_ClassReqHandle (void *pudev, USB_DEVICE_REQ *req);
35 static uint8_t USBD_DFU_GetInterface (void *pudev, USB_DEVICE_REQ *req);
36 static uint8_t USBD_DFU_SetInterface (void *pudev, USB_DEVICE_REQ *req);
37 static uint8_t USBD_DFU_EP0_TxSent (void *pudev);
38 static uint8_t USBD_DFU_EP0_RxReady (void *pudev);
39 static uint8_t* USBD_DFU_GetCfgDesc (uint8_t USBSpeed, uint16_t *len);
40 static uint8_t* USBD_DFU_GetUsrStringDesc (uint8_t USBSpeed, uint8_t index, uint16_t *len);
41 
42 /* DFU Requests management functions */
43 static void DFU_Req_DETACH (void *pudev, USB_DEVICE_REQ *req);
44 static void DFU_Req_DNLOAD (void *pudev, USB_DEVICE_REQ *req);
45 static void DFU_Req_UPLOAD (void *pudev, USB_DEVICE_REQ *req);
46 static void DFU_Req_GETSTATUS (void *pudev);
47 static void DFU_Req_CLRSTATUS (void *pudev);
48 static void DFU_Req_GETSTATE (void *pudev);
49 static void DFU_Req_ABORT (void *pudev);
50 static void DFU_LeaveDFUMode (void *pudev);
51 
55 extern const uint8_t* USBD_DFU_StringDesc[];
56 extern uint8_t MAL_Buffer[];
57 
58 /* State machine variables */
59 uint8_t DeviceStatus[6] =
60 {
61  STATUS_OK, /* bStatus: device status is OK */
62  0x00, /* bwPollTimeout: 0ms */
63  0x00,
64  0x00,
65  STATE_dfuIDLE, /* bState: device state is dfuIDLE */
66  0x00 /* iString: index is 0 */
67 };
68 
69 uint8_t Manifest_State = Manifest_complete;
70 
71 /* Data Management variables */
72 static uint16_t BlockNum = 0;
73 static uint16_t Length = 0;
74 static uint32_t BaseAddress = APP_LOADED_ADDR;
75 static __IO uint32_t USBD_DFU_AltSet = 0;
76 
77 /* DFU interface class callbacks structure */
78 USBD_Class_cb_TypeDef USBD_DFU_cb =
79 {
80  USBD_DFU_Init,
81  USBD_DFU_DeInit,
82  USBD_DFU_GetClassDescriptor,
83  USBD_DFU_ClassReqHandle,
84  USBD_DFU_GetInterface,
85  USBD_DFU_SetInterface,
86  USBD_DFU_EP0_TxSent,
87  USBD_DFU_EP0_RxReady,
88  NULL, /* DataIn */
89  NULL, /* DataOut */
90  NULL, /* SOF */
91  USBD_DFU_GetCfgDesc,
92  USBD_DFU_GetUsrStringDesc,
93 };
94 
95 /* USB DFU device Configuration Descriptor */
96 const uint8_t USBD_DFU_CfgDesc[USB_DFU_CONFIG_DESC_SIZE] =
97 {
98  0x09, /* bLength: configuration descriptor size */
99  USB_DESCTYPE_CONFIGURATION, /* bDescriptorType: configuration descriptor type */
100  USB_DFU_CONFIG_DESC_SIZE, /* wTotalLength: configuration descriptor set total length */
101  0x00,
102  0x01, /* bNumInterfaces: 1 interface */
103  0x01, /* bConfigurationValue: configuration value */
104  0x02, /* iConfiguration: index of string descriptor describing the configuration */
105  0x80, /* bmAttributes: bus powered and not supports remote wakeup */
106  0x32, /* MaxPower 100 mA: this current is used for detecting Vbus */
107 
108  /********** Descriptor of DFU interface 0 Alternate setting 0 **************/
109  USBD_DFU_IF_DESC(0), /* This interface is mandatory for all devices */
110 
111 #if (USBD_ITF_MAX_NUM > 1)
112  /********** Descriptor of DFU interface 0 Alternate setting 1 **************/
113  USBD_DFU_IF_DESC(1),
114 #endif
115 
116 #if (USBD_ITF_MAX_NUM > 2)
117  /********** Descriptor of DFU interface 0 Alternate setting 2 **************/
118  USBD_DFU_IF_DESC(2),
119 #endif
120 
121 #if (USBD_ITF_MAX_NUM > 3)
122  /********** Descriptor of DFU interface 0 Alternate setting 3 **************/
123  USBD_DFU_IF_DESC(3),
124 #endif
125 
126 #if (USBD_ITF_MAX_NUM > 4)
127  /********** Descriptor of DFU interface 0 Alternate setting 4 **************/
128  USBD_DFU_IF_DESC(4),
129 #endif
130 
131 #if (USBD_ITF_MAX_NUM > 5)
132  /********** Descriptor of DFU interface 0 Alternate setting 5 **************/
133  USBD_DFU_IF_DESC(5),
134 #endif
135 
136 #if (USBD_ITF_MAX_NUM > 6)
137  #error "ERROR: usbd_dfu_core.c: Modify the file to support more descriptors!"
138 #endif
139 
140  /******************** DFU functional descriptor********************/
141  0x09, /* blength: 9 bytes */
142  DFU_DESC_TYPE, /* bDescriptorType: DFU functional descriptor type */
143  0x0B, /* bmAttributes:
144  bitCanDnload = 1 (bit 0)
145  bitCanUpload = 1 (bit 1)
146  bitManifestationTolerant = 0 (bit 2)
147  bitWillDetach = 1 (bit 3)
148  Reserved (bit4-6)
149  bitAcceleratedST = 0 (bit 7) */
150  0xFF, /* wDetachTimeOut: 255 ms */
151  0x00,
152  LOWBYTE(TRANSFER_SIZE), /* wTransferSize: 1024 bytes */
153  HIGHBYTE(TRANSFER_SIZE),
154  0x1A, /* bcdDFUVersion: DFU specifigcation release(DFU1.1A) */
155  0x01
156  /***********************************************************/
157 };
158 
173 static uint8_t USBD_DFU_Init (void *pudev, uint8_t ConfigIndex)
174 {
175  /* Initialize the MAL(Media Access Layer) */
176  DFU_MAL_Init();
177 
178  return USBD_OK;
179 }
180 
187 static uint8_t USBD_DFU_DeInit (void *pudev, uint8_t ConfigIndex)
188 {
189  /* Restore device default state */
190  DeviceStatus[0] = STATUS_OK;
191  DeviceStatus[4] = STATE_dfuIDLE;
192 
193  BlockNum = 0;
194  Length = 0;
195 
196  /* Deinitilialize the MAL(Media Access Layer) */
197  DFU_MAL_DeInit();
198 
199  return USBD_OK;
200 }
201 
208 static uint8_t USBD_DFU_GetClassDescriptor (void *pudev, USB_DEVICE_REQ *req)
209 {
210  uint16_t len = 0;
211  uint8_t *pbuf = NULL;
212 
213  if((req->wValue >> 8) == DFU_DESC_TYPE)
214  {
215  pbuf = (uint8_t*)USBD_DFU_CfgDesc + 9 + (9 * USBD_ITF_MAX_NUM);
216  len = MIN(USB_DFU_DESC_SIZE, req->wLength);
217  }
218 
219  USB_CtlTx (pudev, pbuf, len);
220 
221  return USBD_OK;
222 }
223 
230 static uint8_t USBD_DFU_ClassReqHandle (void *pudev, USB_DEVICE_REQ *req)
231 {
232  switch (req->bRequest)
233  {
234  case DFU_DNLOAD:
235  DFU_Req_DNLOAD(pudev, req);
236  break;
237 
238  case DFU_UPLOAD:
239  DFU_Req_UPLOAD(pudev, req);
240  break;
241 
242  case DFU_GETSTATUS:
243  DFU_Req_GETSTATUS(pudev);
244  break;
245 
246  case DFU_CLRSTATUS:
247  DFU_Req_CLRSTATUS(pudev);
248  break;
249 
250  case DFU_GETSTATE:
251  DFU_Req_GETSTATE(pudev);
252  break;
253 
254  case DFU_ABORT:
255  DFU_Req_ABORT(pudev);
256  break;
257 
258  case DFU_DETACH:
259  DFU_Req_DETACH(pudev, req);
260  break;
261 
262  default:
263  USBD_EnumError(pudev, req);
264  return USBD_FAIL;
265  }
266 
267  return USBD_OK;
268 }
269 
276 static uint8_t USBD_DFU_GetInterface (void *pudev, USB_DEVICE_REQ *req)
277 {
278  USB_CtlTx (pudev, (uint8_t *)&USBD_DFU_AltSet, 1);
279 
280  return USBD_OK;
281 }
282 
289 static uint8_t USBD_DFU_SetInterface (void *pudev, USB_DEVICE_REQ *req)
290 {
291  if ((uint8_t)(req->wValue) < USBD_ITF_MAX_NUM)
292  {
293  USBD_DFU_AltSet = (uint8_t)(req->wValue);
294  }
295  else
296  {
297  USBD_EnumError (pudev, req);
298  }
299 
300  return USBD_OK;
301 }
302 
308 static uint8_t USBD_DFU_EP0_TxSent (void *pudev)
309 {
310  uint32_t Addr;
311 
312  if (DeviceStatus[4] == STATE_dfuDNBUSY)
313  {
314  /* Decode the special command */
315  if (BlockNum == 0)
316  {
317  if ((MAL_Buffer[0] == GET_COMMANDS) && (Length == 1))
318  {}
319  else if ((MAL_Buffer[0] == SET_ADDRESS_POINTER) && (Length == 5))
320  {
321  BaseAddress = MAL_Buffer[1];
322  BaseAddress |= MAL_Buffer[2] << 8;
323  BaseAddress |= MAL_Buffer[3] << 16;
324  BaseAddress |= MAL_Buffer[4] << 24;
325  }
326  else if ((MAL_Buffer[0] == ERASE) && (Length == 5))
327  {
328  BaseAddress = MAL_Buffer[1];
329  BaseAddress |= MAL_Buffer[2] << 8;
330  BaseAddress |= MAL_Buffer[3] << 16;
331  BaseAddress |= MAL_Buffer[4] << 24;
332  DFU_MAL_Erase(BaseAddress);
333  }
334  else
335  {
336  USBD_EnumError (pudev, NULL);
337  }
338  }
339  /* Regular download command */
340  else if (BlockNum > 1)
341  {
342  /* Decode the required address */
343  Addr = (BlockNum - 2) * TRANSFER_SIZE + BaseAddress;
344 
345  /* Preform the write operation */
346  DFU_MAL_Write(Addr, Length);
347 
348  BlockNum = 0;
349  }
350 
351  Length = 0;
352 
353  /* Update the device state and poll timeout */
354  DeviceStatus[4] = STATE_dfuDNLOAD_SYNC;
355  DeviceStatus[1] = 0;
356  DeviceStatus[2] = 0;
357  DeviceStatus[3] = 0;
358 
359  return USBD_OK;
360  }
361  else if (DeviceStatus[4] == STATE_dfuMANIFEST)/* Manifestation in progress */
362  {
363  /* Start leaving DFU mode */
364  DFU_LeaveDFUMode(pudev);
365  }
366 
367  return USBD_OK;
368 }
369 
375 static uint8_t USBD_DFU_EP0_RxReady (void *pudev)
376 {
377  return USBD_OK;
378 }
379 
386 static void DFU_Req_DETACH(void *pudev, USB_DEVICE_REQ *req)
387 {
388  switch (DeviceStatus[4])
389  {
390  case STATE_dfuIDLE:
391  case STATE_dfuDNLOAD_SYNC:
392  case STATE_dfuDNLOAD_IDLE:
393  case STATE_dfuMANIFEST_SYNC:
394  case STATE_dfuUPLOAD_IDLE:
395  DeviceStatus[0] = STATUS_OK;
396  DeviceStatus[1] = 0;
397  DeviceStatus[2] = 0;
398  DeviceStatus[3] = 0; /* bwPollTimeout = 0ms */
399  DeviceStatus[4] = STATE_dfuIDLE;
400  DeviceStatus[5] = 0; /* iString */
401 
402  BlockNum = 0;
403  Length = 0;
404  break;
405 
406  default:
407  break;
408  }
409 
410  /* Check the detach capability in the DFU functional descriptor */
411  if ((USBD_DFU_CfgDesc[12 + (9 * USBD_ITF_MAX_NUM)]) & DFU_DETACH_MASK)
412  {
413  /* Perform an Attach-Detach operation on USB bus */
414  USBD_Disconnect(pudev);
415  USBD_Connect(pudev);
416  }
417  else
418  {
419  /* Wait for the period of time specified in detach request */
420  USB_HWP_mDelay (req->wValue);
421  }
422 }
423 
430 static void DFU_Req_DNLOAD(void *pudev, USB_DEVICE_REQ *req)
431 {
432  /* Data setup request */
433  if (req->wLength > 0)
434  {
435  if ((DeviceStatus[4] == STATE_dfuIDLE) || (DeviceStatus[4] == STATE_dfuDNLOAD_IDLE))
436  {
437  /* Update the global length and block number */
438  BlockNum = req->wValue;
439  Length = req->wLength;
440 
441  DeviceStatus[4] = STATE_dfuDNLOAD_SYNC;
442 
443  /* Enable EP0 prepare receive the buffer */
444  USB_CtlRx (pudev, (uint8_t*)MAL_Buffer, Length);
445  }
446  /* Unsupported state */
447  else
448  {
449  USBD_EnumError (pudev, req);
450  }
451  }
452  else
453  {
454  /* End of DNLOAD operation*/
455  if ((DeviceStatus[4] == STATE_dfuDNLOAD_IDLE) || (DeviceStatus[4] == STATE_dfuIDLE))
456  {
457  Manifest_State = Manifest_In_Progress;
458  DeviceStatus[1] = 0;
459  DeviceStatus[2] = 0;
460  DeviceStatus[3] = 0;
461  DeviceStatus[4] = STATE_dfuMANIFEST_SYNC;
462  }
463  else
464  {
465  USBD_EnumError (pudev, req);
466  }
467  }
468 }
469 
476 static void DFU_Req_UPLOAD (void *pudev, USB_DEVICE_REQ *req)
477 {
478  uint8_t *Phy_Addr = NULL;
479  uint32_t Addr = 0;
480 
481  /* Data setup request */
482  if (req->wLength > 0)
483  {
484  if ((DeviceStatus[4] == STATE_dfuIDLE) || (DeviceStatus[4] == STATE_dfuUPLOAD_IDLE))
485  {
486  /* Update the global langth and block number */
487  BlockNum = req->wValue;
488  Length = req->wLength;
489 
490  /* Set device poll timeout */
491  DeviceStatus[1] = 0;
492  DeviceStatus[2] = 0;
493  DeviceStatus[3] = 0;
494 
495  /* DFU Get Command */
496  if (BlockNum == 0)
497  {
498  /* Update the state machine */
499  DeviceStatus[4] = (Length > 3) ? STATE_dfuIDLE : STATE_dfuUPLOAD_IDLE;
500 
501  /* Store the values of all supported commands */
502  MAL_Buffer[0] = GET_COMMANDS;
503  MAL_Buffer[1] = SET_ADDRESS_POINTER;
504  MAL_Buffer[2] = ERASE;
505 
506  /* Send the status data over EP0 */
507  USB_CtlTx (pudev, (uint8_t *)(&(MAL_Buffer[0])), 3);
508  }
509  else if (BlockNum > 1)
510  {
511  DeviceStatus[4] = STATE_dfuUPLOAD_IDLE;
512 
513  /* Change is Accelerated */
514  Addr = ((BlockNum - 2) * TRANSFER_SIZE) + BaseAddress;
515 
516  /* Return the physical address where data are stored */
517  Phy_Addr = DFU_MAL_Read(Addr, Length);
518 
519  /* Send the status data over EP0 */
520  USB_CtlTx (pudev, Phy_Addr, Length);
521  }
522  else
523  {
524  DeviceStatus[4] = STATUS_errSTALLEDPKT;
525 
526  USBD_EnumError (pudev, req);
527  }
528  }
529  else
530  {
531  Length = 0;
532  BlockNum = 0;
533 
534  USBD_EnumError (pudev, req);
535  }
536  }
537  else
538  {
539  DeviceStatus[1] = 0;
540  DeviceStatus[2] = 0;
541  DeviceStatus[3] = 0;
542  DeviceStatus[4] = STATE_dfuIDLE;
543  }
544 }
545 
551 static void DFU_Req_GETSTATUS (void *pudev)
552 {
553  switch (DeviceStatus[4])
554  {
555  case STATE_dfuDNLOAD_SYNC:
556  if (Length != 0)
557  {
558  DeviceStatus[4] = STATE_dfuDNBUSY;
559  if (BlockNum == 0)
560  {
561  if(MAL_Buffer[0] == ERASE)
562  {
563  DFU_MAL_GetStatus(BaseAddress, CMD_ERASE, DeviceStatus);
564  }
565  else
566  {
567  DFU_MAL_GetStatus(BaseAddress, CMD_WRITE, DeviceStatus);
568  }
569  }
570  }
571  else
572  {
573  DeviceStatus[4] = STATE_dfuDNLOAD_IDLE;
574  DeviceStatus[1] = 0;
575  DeviceStatus[2] = 0;
576  DeviceStatus[3] = 0;
577  }
578  break;
579 
580  case STATE_dfuMANIFEST_SYNC:
581  if (Manifest_State == Manifest_In_Progress)
582  {
583  DeviceStatus[4] = STATE_dfuMANIFEST;
584  DeviceStatus[1] = 1;
585  DeviceStatus[2] = 0;
586  DeviceStatus[3] = 0; /* bwPollTimeout = 1ms */
587  }
588  else if ((Manifest_State == Manifest_complete) && \
589  ((USBD_DFU_CfgDesc[(11 + (9 * USBD_ITF_MAX_NUM))]) & 0x04))
590  {
591  DeviceStatus[4] = STATE_dfuIDLE;
592  DeviceStatus[1] = 0;
593  DeviceStatus[2] = 0;
594  DeviceStatus[3] = 0;
595  }
596  break;
597 
598  default :
599  break;
600  }
601 
602  /* Send the status data of DFU interface to host over EP0 */
603  USB_CtlTx (pudev, (uint8_t *)(&(DeviceStatus[0])), 6);
604 }
605 
611 static void DFU_Req_CLRSTATUS (void *pudev)
612 {
613  if (DeviceStatus[4] == STATE_dfuERROR)
614  {
615  DeviceStatus[0] = STATUS_OK;
616  DeviceStatus[4] = STATE_dfuIDLE;
617  }
618  else
619  {
620  /* State Error */
621  DeviceStatus[0] = STATUS_errUNKNOWN;
622  DeviceStatus[4] = STATE_dfuERROR;
623  }
624 
625  DeviceStatus[1] = 0;
626  DeviceStatus[2] = 0;
627  DeviceStatus[3] = 0; /* bwPollTimeout = 0ms */
628  DeviceStatus[5] = 0; /* iString: index = 0 */
629 }
630 
636 static void DFU_Req_GETSTATE (void *pudev)
637 {
638  /* Send the current state of the DFU interface to host */
639  USB_CtlTx (pudev, &DeviceStatus[4], 1);
640 }
641 
647 static void DFU_Req_ABORT (void *pudev)
648 {
649  switch (DeviceStatus[4])
650  {
651  case STATE_dfuIDLE:
652  case STATE_dfuDNLOAD_SYNC:
653  case STATE_dfuDNLOAD_IDLE:
654  case STATE_dfuMANIFEST_SYNC:
655  case STATE_dfuUPLOAD_IDLE:
656  DeviceStatus[0] = STATUS_OK;
657  DeviceStatus[1] = 0;
658  DeviceStatus[2] = 0;
659  DeviceStatus[3] = 0; /* bwPollTimeout = 0ms */
660  DeviceStatus[4] = STATE_dfuIDLE;
661  DeviceStatus[5] = 0; /* iString: index = 0 */
662 
663  BlockNum = 0;
664  Length = 0;
665  break;
666 
667  default:
668  break;
669  }
670 }
671 
677 void DFU_LeaveDFUMode (void *pudev)
678 {
679  Manifest_State = Manifest_complete;
680 
681  DeviceStatus[1] = 0;
682  DeviceStatus[2] = 0;
683  DeviceStatus[3] = 0; /* bwPollTimeout = 0ms */
684 
685  if ((USBD_DFU_CfgDesc[(11 + (9 * USBD_ITF_MAX_NUM))]) & 0x04)
686  {
687  DeviceStatus[4] = STATE_dfuMANIFEST_SYNC;
688  }
689  else
690  {
691  DeviceStatus[4] = STATE_dfuMANIFEST_WAIT_RESET;
692 
693  DFU_MAL_DeInit();
694 
695  /* Generate system reset to allow jumping to the user code */
696  NVIC_SystemReset();
697  }
698 }
699 
706 static uint8_t *USBD_DFU_GetCfgDesc (uint8_t USBSpeed, uint16_t *len)
707 {
708  *len = sizeof (USBD_DFU_CfgDesc);
709 
710  return (uint8_t*)USBD_DFU_CfgDesc;
711 }
712 
720 static uint8_t* USBD_DFU_GetUsrStringDesc (uint8_t USBSpeed, uint8_t index, uint16_t *len)
721 {
722  /* Check if the requested interface string descriptor index is supported */
723  if (index <= (USBD_INTERFACE_STR_IDX + USBD_ITF_MAX_NUM))
724  {
725  USBD_GetUnicodeString ((uint8_t *)USBD_DFU_StringDesc[index - USBD_INTERFACE_STR_IDX - 1], USBD_StrDesc, len);
726  return USBD_StrDesc;
727  }
728  else
729  {
730  return NULL;
731  }
732 }
733 
754 /************************ (C) COPYRIGHT 2014 GIGADEVICE *****END OF FILE****/
uint8_t DFU_MAL_Write(uint32_t Addr, uint32_t Len)
Write data to sectors of memory.
Definition: usbd_dfu_mal.c:148
USB device class callback type define.
Definition: usb_core.h:148
void USBD_GetUnicodeString(uint8_t *desc, uint8_t *unicode, uint16_t *len)
Convert normal string into unicode one.
Definition: usbd_enum.c:762
uint8_t DFU_MAL_GetStatus(uint32_t Addr, uint8_t Cmd, uint8_t *buffer)
Get the status of a given memory and store in buffer.
Definition: usbd_dfu_mal.c:216
uint8_t DFU_MAL_DeInit(void)
Deinitialize the memory media on the GD32.
Definition: usbd_dfu_mal.c:92
Header file for the usbd_dfu_core.c file.
uint8_t DFU_MAL_Init(void)
Initialize the memory media on the GD32.
Definition: usbd_dfu_mal.c:70
void USBD_Disconnect(USB_DEVICE_HANDLE *pudev)
Configure usb device to be unconnected.
Definition: usbd_core.c:49
uint8_t DFU_MAL_Erase(uint32_t Addr)
Erase a memory sector.
Definition: usbd_dfu_mal.c:114
uint8_t * DFU_MAL_Read(uint32_t Addr, uint32_t Len)
Read data from sectors of memory.
Definition: usbd_dfu_mal.c:182
uint8_t USB_CtlRx(USB_CORE_HANDLE *pudev, uint8_t *pbuf, uint16_t Len)
Receive data on the control pipe.
Definition: usb_core.c:538
uint8_t USB_CtlTx(USB_CORE_HANDLE *pudev, uint8_t *pbuf, uint16_t Len)
Transmit data on the control pipe.
Definition: usb_core.c:504
void USBD_Connect(USB_DEVICE_HANDLE *pudev)
Configure usb device to be connected.
Definition: usbd_core.c:38
void USBD_EnumError(USB_DEVICE_HANDLE *pudev, USB_DEVICE_REQ *req)
Handle usb enumeration error event.
Definition: usbd_enum.c:749
USB standard device request struct.
Definition: usb_core.h:120
Generated on Fri Feb 6 2015 14:56:35 for GD32F10x USB-Device by   doxygen 1.8.8