xref: /btstack/port/stm32-f4discovery-usb/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c (revision a8f7f3fcbcd51f8d2e92aca076b6a9f812db358c)
1 /**
2   ******************************************************************************
3   * @file    usbh_core.c
4   * @author  MCD Application Team
5   * @brief   This file implements the functions for the core state machine process
6   *          the enumeration and the control transfer process
7   ******************************************************************************
8   * @attention
9   *
10   * <h2><center>&copy; Copyright (c) 2015 STMicroelectronics.
11   * All rights reserved.</center></h2>
12   *
13   * This software component is licensed by ST under Ultimate Liberty license
14   * SLA0044, the "License"; You may not use this file except in compliance with
15   * the License. You may obtain a copy of the License at:
16   *                      www.st.com/SLA0044
17   *
18   ******************************************************************************
19   */
20 
21 /* Includes ------------------------------------------------------------------*/
22 #include "usbh_core.h"
23 
24 
25 /** @addtogroup USBH_LIB
26   * @{
27   */
28 
29 /** @addtogroup USBH_LIB_CORE
30   * @{
31   */
32 
33 /** @defgroup USBH_CORE
34   * @brief This file handles the basic enumeration when a device is connected
35   *          to the host.
36   * @{
37   */
38 
39 
40 /** @defgroup USBH_CORE_Private_Defines
41   * @{
42   */
43 #define USBH_ADDRESS_DEFAULT                     0x00U
44 #define USBH_ADDRESS_ASSIGNED                    0x01U
45 #define USBH_MPS_DEFAULT                         0x40U
46 /**
47   * @}
48   */
49 
50 /** @defgroup USBH_CORE_Private_Macros
51   * @{
52   */
53 /**
54   * @}
55   */
56 
57 
58 /** @defgroup USBH_CORE_Private_Variables
59   * @{
60   */
61 #if (USBH_USE_OS == 1U)
62 #if (osCMSIS >= 0x20000U)
63 osThreadAttr_t USBH_Thread_Atrr;
64 #endif
65 #endif
66 
67 
68 /**
69   * @}
70   */
71 
72 
73 /** @defgroup USBH_CORE_Private_Functions
74   * @{
75   */
76 static USBH_StatusTypeDef USBH_HandleEnum(USBH_HandleTypeDef *phost);
77 static void USBH_HandleSof(USBH_HandleTypeDef *phost);
78 static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost);
79 
80 #if (USBH_USE_OS == 1U)
81 #if (osCMSIS < 0x20000U)
82 static void USBH_Process_OS(void const *argument);
83 #else
84 static void USBH_Process_OS(void *argument);
85 #endif
86 #endif
87 
88 
89 /**
90   * @brief  HCD_Init
91   *         Initialize the HOST Core.
92   * @param  phost: Host Handle
93   * @param  pUsrFunc: User Callback
94   * @retval USBH Status
95   */
USBH_Init(USBH_HandleTypeDef * phost,void (* pUsrFunc)(USBH_HandleTypeDef * phost,uint8_t id),uint8_t id)96 USBH_StatusTypeDef  USBH_Init(USBH_HandleTypeDef *phost,
97                               void (*pUsrFunc)(USBH_HandleTypeDef *phost,
98                               uint8_t id), uint8_t id)
99 {
100   /* Check whether the USB Host handle is valid */
101   if (phost == NULL)
102   {
103     USBH_ErrLog("Invalid Host handle");
104     return USBH_FAIL;
105   }
106 
107   /* Set DRiver ID */
108   phost->id = id;
109 
110   /* Unlink class*/
111   phost->pActiveClass = NULL;
112   phost->ClassNumber = 0U;
113 
114   /* Restore default states and prepare EP0 */
115   DeInitStateMachine(phost);
116 
117   /* Restore default Device connection states */
118   phost->device.PortEnabled = 0U;
119   phost->device.is_connected = 0U;
120   phost->device.is_disconnected = 0U;
121   phost->device.is_ReEnumerated = 0U;
122 
123   /* Assign User process */
124   if (pUsrFunc != NULL)
125   {
126     phost->pUser = pUsrFunc;
127   }
128 
129 #if (USBH_USE_OS == 1U)
130 #if (osCMSIS < 0x20000U)
131 
132   /* Create USB Host Queue */
133   osMessageQDef(USBH_Queue, MSGQUEUE_OBJECTS, uint16_t);
134   phost->os_event = osMessageCreate(osMessageQ(USBH_Queue), NULL);
135 
136   /* Create USB Host Task */
137 #if defined (USBH_PROCESS_STACK_SIZE)
138   osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0U, USBH_PROCESS_STACK_SIZE);
139 #else
140   osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0U, 8U * configMINIMAL_STACK_SIZE);
141 #endif /* defined (USBH_PROCESS_STACK_SIZE) */
142 
143   phost->thread = osThreadCreate(osThread(USBH_Thread), phost);
144 
145 #else
146 
147   /* Create USB Host Queue */
148   phost->os_event = osMessageQueueNew(MSGQUEUE_OBJECTS, sizeof(uint32_t), NULL);
149 
150   /* Create USB Host Task */
151   USBH_Thread_Atrr.name = "USBH_Queue";
152 
153 #if defined (USBH_PROCESS_STACK_SIZE)
154   USBH_Thread_Atrr.stack_size = USBH_PROCESS_STACK_SIZE;
155 #else
156   USBH_Thread_Atrr.stack_size = (8U * configMINIMAL_STACK_SIZE);
157 #endif /* defined (USBH_PROCESS_STACK_SIZE) */
158 
159   USBH_Thread_Atrr.priority = USBH_PROCESS_PRIO;
160   phost->thread = osThreadNew(USBH_Process_OS, phost, &USBH_Thread_Atrr);
161 
162 #endif /* (osCMSIS < 0x20000U) */
163 #endif /* (USBH_USE_OS == 1U) */
164 
165   /* Initialize low level driver */
166   USBH_LL_Init(phost);
167 
168   return USBH_OK;
169 }
170 
171 
172 /**
173   * @brief  HCD_Init
174   *         De-Initialize the Host portion of the driver.
175   * @param  phost: Host Handle
176   * @retval USBH Status
177   */
USBH_DeInit(USBH_HandleTypeDef * phost)178 USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost)
179 {
180   DeInitStateMachine(phost);
181 
182   /* Restore default Device connection states */
183   phost->device.PortEnabled = 0U;
184   phost->device.is_connected = 0U;
185   phost->device.is_disconnected = 0U;
186   phost->device.is_ReEnumerated = 0U;
187   phost->device.RstCnt = 0U;
188   phost->device.EnumCnt = 0U;
189 
190   if (phost->pData != NULL)
191   {
192     USBH_LL_Stop(phost);
193   }
194 
195   return USBH_OK;
196 }
197 
198 
199 /**
200   * @brief  DeInitStateMachine
201   *         De-Initialize the Host state machine.
202   * @param  phost: Host Handle
203   * @retval USBH Status
204   */
DeInitStateMachine(USBH_HandleTypeDef * phost)205 static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost)
206 {
207   uint32_t i = 0U;
208 
209   /* Clear Pipes flags*/
210   for (i = 0U; i < USBH_MAX_PIPES_NBR; i++)
211   {
212     phost->Pipes[i] = 0U;
213   }
214 
215   for (i = 0U; i < USBH_MAX_DATA_BUFFER; i++)
216   {
217     phost->device.Data[i] = 0U;
218   }
219 
220   phost->gState = HOST_IDLE;
221   phost->EnumState = ENUM_IDLE;
222   phost->RequestState = CMD_SEND;
223   phost->Timer = 0U;
224 
225   phost->Control.state = CTRL_SETUP;
226   phost->Control.pipe_size = USBH_MPS_DEFAULT;
227   phost->Control.errorcount = 0U;
228 
229   phost->device.address = USBH_ADDRESS_DEFAULT;
230   phost->device.speed = USBH_SPEED_FULL;
231   phost->device.RstCnt = 0U;
232   phost->device.EnumCnt = 0U;
233 
234   return USBH_OK;
235 }
236 
237 
238 /**
239   * @brief  USBH_RegisterClass
240   *         Link class driver to Host Core.
241   * @param  phost : Host Handle
242   * @param  pclass: Class handle
243   * @retval USBH Status
244   */
USBH_RegisterClass(USBH_HandleTypeDef * phost,USBH_ClassTypeDef * pclass)245 USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass)
246 {
247   USBH_StatusTypeDef status = USBH_OK;
248 
249   if (pclass != NULL)
250   {
251     if (phost->ClassNumber < USBH_MAX_NUM_SUPPORTED_CLASS)
252     {
253       /* link the class to the USB Host handle */
254       phost->pClass[phost->ClassNumber++] = pclass;
255       status = USBH_OK;
256     }
257     else
258     {
259       USBH_ErrLog("Max Class Number reached");
260       status = USBH_FAIL;
261     }
262   }
263   else
264   {
265     USBH_ErrLog("Invalid Class handle");
266     status = USBH_FAIL;
267   }
268 
269   return status;
270 }
271 
272 
273 /**
274   * @brief  USBH_SelectInterface
275   *         Select current interface.
276   * @param  phost: Host Handle
277   * @param  interface: Interface number
278   * @retval USBH Status
279   */
USBH_SelectInterface(USBH_HandleTypeDef * phost,uint8_t interface)280 USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface)
281 {
282   USBH_StatusTypeDef status = USBH_OK;
283 
284   if (interface < phost->device.CfgDesc.bNumInterfaces)
285   {
286     phost->device.current_interface = interface;
287     USBH_UsrLog("Switching to Interface (#%d)", interface);
288     USBH_UsrLog("Class    : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass);
289     USBH_UsrLog("SubClass : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass);
290     USBH_UsrLog("Protocol : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol);
291   }
292   else
293   {
294     USBH_ErrLog("Cannot Select This Interface.");
295     status = USBH_FAIL;
296   }
297 
298   return status;
299 }
300 
301 
302 /**
303   * @brief  USBH_GetActiveClass
304   *         Return Device Class.
305   * @param  phost: Host Handle
306   * @param  interface: Interface index
307   * @retval Class Code
308   */
USBH_GetActiveClass(USBH_HandleTypeDef * phost)309 uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost)
310 {
311   return (phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass);
312 }
313 
314 
315 /**
316   * @brief  USBH_FindInterface
317   *         Find the interface index for a specific class.
318   * @param  phost: Host Handle
319   * @param  Class: Class code
320   * @param  SubClass: SubClass code
321   * @param  Protocol: Protocol code
322   * @retval interface index in the configuration structure
323   * @note : (1)interface index 0xFF means interface index not found
324   */
USBH_FindInterface(USBH_HandleTypeDef * phost,uint8_t Class,uint8_t SubClass,uint8_t Protocol)325 uint8_t  USBH_FindInterface(USBH_HandleTypeDef *phost, uint8_t Class, uint8_t SubClass, uint8_t Protocol)
326 {
327   USBH_InterfaceDescTypeDef *pif;
328   USBH_CfgDescTypeDef *pcfg;
329   uint8_t if_ix = 0U;
330 
331   pif = (USBH_InterfaceDescTypeDef *)0;
332   pcfg = &phost->device.CfgDesc;
333 
334   while (if_ix < USBH_MAX_NUM_INTERFACES)
335   {
336     pif = &pcfg->Itf_Desc[if_ix];
337     if (((pif->bInterfaceClass == Class) || (Class == 0xFFU)) &&
338         ((pif->bInterfaceSubClass == SubClass) || (SubClass == 0xFFU)) &&
339         ((pif->bInterfaceProtocol == Protocol) || (Protocol == 0xFFU)))
340     {
341       return  if_ix;
342     }
343     if_ix++;
344   }
345   return 0xFFU;
346 }
347 
348 
349 /**
350   * @brief  USBH_FindInterfaceIndex
351   *         Find the interface index for a specific class interface and alternate setting number.
352   * @param  phost: Host Handle
353   * @param  interface_number: interface number
354   * @param  alt_settings    : alternate setting number
355   * @retval interface index in the configuration structure
356   * @note : (1)interface index 0xFF means interface index not found
357   */
USBH_FindInterfaceIndex(USBH_HandleTypeDef * phost,uint8_t interface_number,uint8_t alt_settings)358 uint8_t  USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost, uint8_t interface_number, uint8_t alt_settings)
359 {
360   USBH_InterfaceDescTypeDef *pif;
361   USBH_CfgDescTypeDef *pcfg;
362   uint8_t if_ix = 0U;
363 
364   pif = (USBH_InterfaceDescTypeDef *)0;
365   pcfg = &phost->device.CfgDesc;
366 
367   while (if_ix < USBH_MAX_NUM_INTERFACES)
368   {
369     pif = &pcfg->Itf_Desc[if_ix];
370     if ((pif->bInterfaceNumber == interface_number) && (pif->bAlternateSetting == alt_settings))
371     {
372       return  if_ix;
373     }
374     if_ix++;
375   }
376   return 0xFFU;
377 }
378 
379 
380 /**
381   * @brief  USBH_Start
382   *         Start the USB Host Core.
383   * @param  phost: Host Handle
384   * @retval USBH Status
385   */
USBH_Start(USBH_HandleTypeDef * phost)386 USBH_StatusTypeDef  USBH_Start(USBH_HandleTypeDef *phost)
387 {
388   /* Start the low level driver  */
389   USBH_LL_Start(phost);
390 
391   /* Activate VBUS on the port */
392   USBH_LL_DriverVBUS(phost, TRUE);
393 
394   return USBH_OK;
395 }
396 
397 
398 /**
399   * @brief  USBH_Stop
400   *         Stop the USB Host Core.
401   * @param  phost: Host Handle
402   * @retval USBH Status
403   */
USBH_Stop(USBH_HandleTypeDef * phost)404 USBH_StatusTypeDef  USBH_Stop(USBH_HandleTypeDef *phost)
405 {
406   /* DeActivate VBUS on the port */
407   USBH_LL_DriverVBUS(phost, FALSE);
408 
409   /* Stop and cleanup the low level driver  */
410   USBH_LL_Stop(phost);
411 
412   /* Free Control Pipes */
413   USBH_FreePipe(phost, phost->Control.pipe_in);
414   USBH_FreePipe(phost, phost->Control.pipe_out);
415 
416   return USBH_OK;
417 }
418 
419 
420 /**
421   * @brief  HCD_ReEnumerate
422   *         Perform a new Enumeration phase.
423   * @param  phost: Host Handle
424   * @retval USBH Status
425   */
USBH_ReEnumerate(USBH_HandleTypeDef * phost)426 USBH_StatusTypeDef USBH_ReEnumerate(USBH_HandleTypeDef *phost)
427 {
428   if (USBH_IsPortEnabled(phost))
429   {
430     phost->device.is_ReEnumerated = 1U;
431 
432     /* Stop Host */
433     USBH_Stop(phost);
434 
435     phost->device.is_disconnected = 1U;
436   }
437 
438 #if (USBH_USE_OS == 1U)
439   phost->os_msg = (uint32_t)USBH_PORT_EVENT;
440 #if (osCMSIS < 0x20000U)
441   (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
442 #else
443   (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
444 #endif
445 #endif
446 
447   return USBH_OK;
448 }
449 
450 
451 /**
452   * @brief  USBH_Process
453   *         Background process of the USB Core.
454   * @param  phost: Host Handle
455   * @retval USBH Status
456   */
USBH_Process(USBH_HandleTypeDef * phost)457 USBH_StatusTypeDef  USBH_Process(USBH_HandleTypeDef *phost)
458 {
459   __IO USBH_StatusTypeDef status = USBH_FAIL;
460   uint8_t idx = 0U;
461 
462   /* check for Host pending port disconnect event */
463   if (phost->device.is_disconnected == 1U)
464   {
465     phost->gState = HOST_DEV_DISCONNECTED;
466   }
467 
468   switch (phost->gState)
469   {
470     case HOST_IDLE :
471 
472       if (phost->device.is_connected)
473       {
474         USBH_UsrLog("USB Device Connected");
475 
476         /* Wait for 200 ms after connection */
477         phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT;
478         USBH_Delay(200U);
479         USBH_LL_ResetPort(phost);
480 
481         /* Make sure to start with Default address */
482         phost->device.address = USBH_ADDRESS_DEFAULT;
483         phost->Timeout = 0U;
484 
485 #if (USBH_USE_OS == 1U)
486         phost->os_msg = (uint32_t)USBH_PORT_EVENT;
487 #if (osCMSIS < 0x20000U)
488         (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
489 #else
490         (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
491 #endif
492 #endif
493       }
494       break;
495 
496     case HOST_DEV_WAIT_FOR_ATTACHMENT: /* Wait for Port Enabled */
497 
498       if (phost->device.PortEnabled == 1U)
499       {
500         USBH_UsrLog("USB Device Reset Completed");
501         phost->device.RstCnt = 0U;
502         phost->gState = HOST_DEV_ATTACHED;
503       }
504       else
505       {
506         if (phost->Timeout > USBH_DEV_RESET_TIMEOUT)
507         {
508           phost->device.RstCnt++;
509           if (phost->device.RstCnt > 3U)
510           {
511             /* Buggy Device can't complete reset */
512             USBH_UsrLog("USB Reset Failed, Please unplug the Device.");
513             phost->gState = HOST_ABORT_STATE;
514           }
515           else
516           {
517             phost->gState = HOST_IDLE;
518           }
519         }
520         else
521         {
522           phost->Timeout += 10U;
523           USBH_Delay(10U);
524         }
525       }
526 #if (USBH_USE_OS == 1U)
527       phost->os_msg = (uint32_t)USBH_PORT_EVENT;
528 #if (osCMSIS < 0x20000U)
529       (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
530 #else
531       (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
532 #endif
533 #endif
534       break;
535 
536     case HOST_DEV_ATTACHED :
537 
538       if (phost->pUser != NULL)
539       {
540         phost->pUser(phost, HOST_USER_CONNECTION);
541       }
542 
543       /* Wait for 100 ms after Reset */
544       USBH_Delay(100U);
545 
546       phost->device.speed = USBH_LL_GetSpeed(phost);
547 
548       phost->gState = HOST_ENUMERATION;
549 
550       phost->Control.pipe_out = USBH_AllocPipe(phost, 0x00U);
551       phost->Control.pipe_in  = USBH_AllocPipe(phost, 0x80U);
552 
553       /* Open Control pipes */
554       USBH_OpenPipe(phost, phost->Control.pipe_in, 0x80U,
555                     phost->device.address, phost->device.speed,
556                     USBH_EP_CONTROL, (uint16_t)phost->Control.pipe_size);
557 
558       /* Open Control pipes */
559       USBH_OpenPipe(phost, phost->Control.pipe_out, 0x00U,
560                     phost->device.address, phost->device.speed,
561                     USBH_EP_CONTROL, (uint16_t)phost->Control.pipe_size);
562 
563 #if (USBH_USE_OS == 1U)
564       phost->os_msg = (uint32_t)USBH_PORT_EVENT;
565 #if (osCMSIS < 0x20000U)
566       (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
567 #else
568       (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
569 #endif
570 #endif
571       break;
572 
573     case HOST_ENUMERATION:
574       /* Check for enumeration status */
575       status = USBH_HandleEnum(phost);
576       if (status == USBH_OK)
577       {
578         /* The function shall return USBH_OK when full enumeration is complete */
579         USBH_UsrLog("Enumeration done.");
580 
581         phost->device.current_interface = 0U;
582 
583         if (phost->device.DevDesc.bNumConfigurations == 1U)
584         {
585           USBH_UsrLog("This device has only 1 configuration.");
586           phost->gState = HOST_SET_CONFIGURATION;
587         }
588         else
589         {
590           phost->gState = HOST_INPUT;
591         }
592 #if (USBH_USE_OS == 1U)
593         phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
594 #if (osCMSIS < 0x20000U)
595         (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
596 #else
597         (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
598 #endif
599 #endif
600       }
601       break;
602 
603     case HOST_INPUT:
604     {
605       /* user callback for end of device basic enumeration */
606       if (phost->pUser != NULL)
607       {
608         phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION);
609         phost->gState = HOST_SET_CONFIGURATION;
610 
611 #if (USBH_USE_OS == 1U)
612         phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
613 #if (osCMSIS < 0x20000U)
614         (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
615 #else
616         (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
617 #endif
618 #endif
619       }
620     }
621     break;
622 
623     case HOST_SET_CONFIGURATION:
624       /* set configuration */
625       if (USBH_SetCfg(phost, (uint16_t)phost->device.CfgDesc.bConfigurationValue) == USBH_OK)
626       {
627         phost->gState = HOST_SET_WAKEUP_FEATURE;
628         USBH_UsrLog("Default configuration set.");
629       }
630 
631 #if (USBH_USE_OS == 1U)
632       phost->os_msg = (uint32_t)USBH_PORT_EVENT;
633 #if (osCMSIS < 0x20000U)
634       (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
635 #else
636       (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
637 #endif
638 #endif
639       break;
640 
641     case  HOST_SET_WAKEUP_FEATURE:
642 
643       if ((phost->device.CfgDesc.bmAttributes) & (1U << 5))
644       {
645         if (USBH_SetFeature(phost, FEATURE_SELECTOR_REMOTEWAKEUP) == USBH_OK)
646         {
647           USBH_UsrLog("Device remote wakeup enabled");
648           phost->gState = HOST_CHECK_CLASS;
649         }
650       }
651       else
652       {
653         phost->gState = HOST_CHECK_CLASS;
654       }
655 
656 #if (USBH_USE_OS == 1U)
657       phost->os_msg = (uint32_t)USBH_PORT_EVENT;
658 #if (osCMSIS < 0x20000U)
659       (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
660 #else
661       (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
662 #endif
663 #endif
664       break;
665 
666     case HOST_CHECK_CLASS:
667 
668       if (phost->ClassNumber == 0U)
669       {
670         USBH_UsrLog("No Class has been registered.");
671       }
672       else
673       {
674         phost->pActiveClass = NULL;
675 
676         for (idx = 0U; idx < USBH_MAX_NUM_SUPPORTED_CLASS; idx++)
677         {
678           if (phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass)
679           {
680             phost->pActiveClass = phost->pClass[idx];
681             break;
682           }
683         }
684 
685         if (phost->pActiveClass != NULL)
686         {
687           if (phost->pActiveClass->Init(phost) == USBH_OK)
688           {
689             phost->gState = HOST_CLASS_REQUEST;
690             USBH_UsrLog("%s class started.", phost->pActiveClass->Name);
691 
692             /* Inform user that a class has been activated */
693             phost->pUser(phost, HOST_USER_CLASS_SELECTED);
694           }
695           else
696           {
697             phost->gState = HOST_ABORT_STATE;
698             USBH_UsrLog("Device not supporting %s class.", phost->pActiveClass->Name);
699           }
700         }
701         else
702         {
703           phost->gState = HOST_ABORT_STATE;
704           USBH_UsrLog("No registered class for this device.");
705         }
706       }
707 
708 #if (USBH_USE_OS == 1U)
709       phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
710 #if (osCMSIS < 0x20000U)
711       (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
712 #else
713       (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
714 #endif
715 #endif
716       break;
717 
718     case HOST_CLASS_REQUEST:
719       /* process class standard control requests state machine */
720       if (phost->pActiveClass != NULL)
721       {
722         status = phost->pActiveClass->Requests(phost);
723 
724         if (status == USBH_OK)
725         {
726           phost->gState = HOST_CLASS;
727         }
728         else if (status == USBH_FAIL)
729         {
730           phost->gState = HOST_ABORT_STATE;
731           USBH_ErrLog("Device not responding Please Unplug.");
732         }
733         else
734         {
735           /* .. */
736         }
737       }
738       else
739       {
740         phost->gState = HOST_ABORT_STATE;
741         USBH_ErrLog("Invalid Class Driver.");
742       }
743 #if (USBH_USE_OS == 1U)
744       phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
745 #if (osCMSIS < 0x20000U)
746       (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
747 #else
748       (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
749 #endif
750 #endif
751       break;
752 
753     case HOST_CLASS:
754       /* process class state machine */
755       if (phost->pActiveClass != NULL)
756       {
757         phost->pActiveClass->BgndProcess(phost);
758       }
759       break;
760 
761     case HOST_DEV_DISCONNECTED :
762       phost->device.is_disconnected = 0U;
763 
764       DeInitStateMachine(phost);
765 
766       /* Re-Initilaize Host for new Enumeration */
767       if (phost->pActiveClass != NULL)
768       {
769         phost->pActiveClass->DeInit(phost);
770         phost->pActiveClass = NULL;
771       }
772 
773       if (phost->pUser != NULL)
774       {
775         phost->pUser(phost, HOST_USER_DISCONNECTION);
776       }
777       USBH_UsrLog("USB Device disconnected");
778 
779       if (phost->device.is_ReEnumerated == 1U)
780       {
781         phost->device.is_ReEnumerated = 0U;
782 
783         /* Start the host and re-enable Vbus */
784         USBH_Start(phost);
785       }
786       else
787       {
788         /* Device Disconnection Completed, start USB Driver */
789         USBH_LL_Start(phost);
790       }
791 
792 #if (USBH_USE_OS == 1U)
793       phost->os_msg = (uint32_t)USBH_PORT_EVENT;
794 #if (osCMSIS < 0x20000U)
795       (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
796 #else
797       (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
798 #endif
799 #endif
800       break;
801 
802     case HOST_ABORT_STATE:
803     default :
804       break;
805   }
806   return USBH_OK;
807 }
808 
809 
810 /**
811   * @brief  USBH_HandleEnum
812   *         This function includes the complete enumeration process
813   * @param  phost: Host Handle
814   * @retval USBH_Status
815   */
USBH_HandleEnum(USBH_HandleTypeDef * phost)816 static USBH_StatusTypeDef USBH_HandleEnum(USBH_HandleTypeDef *phost)
817 {
818   USBH_StatusTypeDef Status = USBH_BUSY;
819   USBH_StatusTypeDef ReqStatus = USBH_BUSY;
820 
821   switch (phost->EnumState)
822   {
823     case ENUM_IDLE:
824       /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */
825       ReqStatus = USBH_Get_DevDesc(phost, 8U);
826       if (ReqStatus == USBH_OK)
827       {
828         phost->Control.pipe_size = phost->device.DevDesc.bMaxPacketSize;
829 
830         phost->EnumState = ENUM_GET_FULL_DEV_DESC;
831 
832         /* modify control channels configuration for MaxPacket size */
833         USBH_OpenPipe(phost, phost->Control.pipe_in, 0x80U, phost->device.address,
834                       phost->device.speed, USBH_EP_CONTROL,
835                       (uint16_t)phost->Control.pipe_size);
836 
837         /* Open Control pipes */
838         USBH_OpenPipe(phost, phost->Control.pipe_out, 0x00U, phost->device.address,
839                       phost->device.speed, USBH_EP_CONTROL,
840                       (uint16_t)phost->Control.pipe_size);
841       }
842       else if (ReqStatus == USBH_NOT_SUPPORTED)
843       {
844         USBH_ErrLog("Control error: Get Device Descriptor request failed");
845         phost->device.EnumCnt++;
846         if (phost->device.EnumCnt > 3U)
847         {
848           /* Buggy Device can't complete get device desc request */
849           USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
850           phost->gState = HOST_ABORT_STATE;
851         }
852         else
853         {
854           /* free control pipes */
855           USBH_FreePipe(phost, phost->Control.pipe_out);
856           USBH_FreePipe(phost, phost->Control.pipe_in);
857 
858           /* Reset the USB Device */
859           phost->gState = HOST_IDLE;
860         }
861       }
862       else
863       {
864         /* .. */
865       }
866       break;
867 
868     case ENUM_GET_FULL_DEV_DESC:
869       /* Get FULL Device Desc  */
870       ReqStatus = USBH_Get_DevDesc(phost, USB_DEVICE_DESC_SIZE);
871       if (ReqStatus == USBH_OK)
872       {
873         USBH_UsrLog("PID: %xh", phost->device.DevDesc.idProduct);
874         USBH_UsrLog("VID: %xh", phost->device.DevDesc.idVendor);
875 
876         phost->EnumState = ENUM_SET_ADDR;
877       }
878       else if (ReqStatus == USBH_NOT_SUPPORTED)
879       {
880         USBH_ErrLog("Control error: Get Full Device Descriptor request failed");
881         phost->device.EnumCnt++;
882         if (phost->device.EnumCnt > 3U)
883         {
884           /* Buggy Device can't complete get device desc request */
885           USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
886           phost->gState = HOST_ABORT_STATE;
887         }
888         else
889         {
890           /* Free control pipes */
891           USBH_FreePipe(phost, phost->Control.pipe_out);
892           USBH_FreePipe(phost, phost->Control.pipe_in);
893 
894           /* Reset the USB Device */
895           phost->EnumState = ENUM_IDLE;
896           phost->gState = HOST_IDLE;
897         }
898       }
899       else
900       {
901         /* .. */
902       }
903       break;
904 
905     case ENUM_SET_ADDR:
906       /* set address */
907       ReqStatus = USBH_SetAddress(phost, USBH_DEVICE_ADDRESS);
908       if (ReqStatus == USBH_OK)
909       {
910         USBH_Delay(2U);
911         phost->device.address = USBH_DEVICE_ADDRESS;
912 
913         /* user callback for device address assigned */
914         USBH_UsrLog("Address (#%d) assigned.", phost->device.address);
915         phost->EnumState = ENUM_GET_CFG_DESC;
916 
917         /* modify control channels to update device address */
918         USBH_OpenPipe(phost, phost->Control.pipe_in, 0x80U,  phost->device.address,
919                       phost->device.speed, USBH_EP_CONTROL,
920                       (uint16_t)phost->Control.pipe_size);
921 
922         /* Open Control pipes */
923         USBH_OpenPipe(phost, phost->Control.pipe_out, 0x00U, phost->device.address,
924                       phost->device.speed, USBH_EP_CONTROL,
925                       (uint16_t)phost->Control.pipe_size);
926       }
927       else if (ReqStatus == USBH_NOT_SUPPORTED)
928       {
929         USBH_ErrLog("Control error: Device Set Address request failed");
930 
931         /* Buggy Device can't complete get device desc request */
932         USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
933         phost->gState = HOST_ABORT_STATE;
934         phost->EnumState = ENUM_IDLE;
935       }
936       else
937       {
938         /* .. */
939       }
940       break;
941 
942     case ENUM_GET_CFG_DESC:
943       /* get standard configuration descriptor */
944       ReqStatus = USBH_Get_CfgDesc(phost, USB_CONFIGURATION_DESC_SIZE);
945       if (ReqStatus == USBH_OK)
946       {
947         phost->EnumState = ENUM_GET_FULL_CFG_DESC;
948       }
949       else if (ReqStatus == USBH_NOT_SUPPORTED)
950       {
951         USBH_ErrLog("Control error: Get Device configuration descriptor request failed");
952         phost->device.EnumCnt++;
953         if (phost->device.EnumCnt > 3U)
954         {
955           /* Buggy Device can't complete get device desc request */
956           USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
957           phost->gState = HOST_ABORT_STATE;
958         }
959         else
960         {
961           /* Free control pipes */
962           USBH_FreePipe(phost, phost->Control.pipe_out);
963           USBH_FreePipe(phost, phost->Control.pipe_in);
964 
965           /* Reset the USB Device */
966           phost->EnumState = ENUM_IDLE;
967           phost->gState = HOST_IDLE;
968         }
969       }
970       else
971       {
972         /* .. */
973       }
974       break;
975 
976     case ENUM_GET_FULL_CFG_DESC:
977       /* get FULL config descriptor (config, interface, endpoints) */
978       ReqStatus = USBH_Get_CfgDesc(phost, phost->device.CfgDesc.wTotalLength);
979       if (ReqStatus == USBH_OK)
980       {
981         phost->EnumState = ENUM_GET_MFC_STRING_DESC;
982       }
983       else if (ReqStatus == USBH_NOT_SUPPORTED)
984       {
985         USBH_ErrLog("Control error: Get Device configuration descriptor request failed");
986         phost->device.EnumCnt++;
987         if (phost->device.EnumCnt > 3U)
988         {
989           /* Buggy Device can't complete get device desc request */
990           USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
991           phost->gState = HOST_ABORT_STATE;
992         }
993         else
994         {
995           /* Free control pipes */
996           USBH_FreePipe(phost, phost->Control.pipe_out);
997           USBH_FreePipe(phost, phost->Control.pipe_in);
998 
999           /* Reset the USB Device */
1000           phost->EnumState = ENUM_IDLE;
1001           phost->gState = HOST_IDLE;
1002         }
1003       }
1004       else
1005       {
1006         /* .. */
1007       }
1008       break;
1009 
1010     case ENUM_GET_MFC_STRING_DESC:
1011       if (phost->device.DevDesc.iManufacturer != 0U)
1012       {
1013         /* Check that Manufacturer String is available */
1014         ReqStatus = USBH_Get_StringDesc(phost, phost->device.DevDesc.iManufacturer,
1015                                         phost->device.Data, 0xFFU);
1016         if (ReqStatus == USBH_OK)
1017         {
1018           /* User callback for Manufacturing string */
1019           USBH_UsrLog("Manufacturer : %s", (char *)(void *)phost->device.Data);
1020           phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
1021 
1022 #if (USBH_USE_OS == 1U)
1023           phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
1024 #if (osCMSIS < 0x20000U)
1025           (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
1026 #else
1027           (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
1028 #endif
1029 #endif
1030         }
1031         else if (ReqStatus == USBH_NOT_SUPPORTED)
1032         {
1033           USBH_UsrLog("Manufacturer : N/A");
1034           phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
1035 
1036 #if (USBH_USE_OS == 1U)
1037           phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
1038 #if (osCMSIS < 0x20000U)
1039           (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
1040 #else
1041           (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
1042 #endif
1043 #endif
1044         }
1045         else
1046         {
1047           /* .. */
1048         }
1049       }
1050       else
1051       {
1052         USBH_UsrLog("Manufacturer : N/A");
1053         phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
1054 
1055 #if (USBH_USE_OS == 1U)
1056         phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
1057 #if (osCMSIS < 0x20000U)
1058         (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
1059 #else
1060         (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
1061 #endif
1062 #endif
1063       }
1064       break;
1065 
1066     case ENUM_GET_PRODUCT_STRING_DESC:
1067       if (phost->device.DevDesc.iProduct != 0U)
1068       {
1069         /* Check that Product string is available */
1070         ReqStatus = USBH_Get_StringDesc(phost, phost->device.DevDesc.iProduct,
1071                                         phost->device.Data, 0xFFU);
1072         if (ReqStatus == USBH_OK)
1073         {
1074           /* User callback for Product string */
1075           USBH_UsrLog("Product : %s", (char *)(void *)phost->device.Data);
1076           phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
1077         }
1078         else if (ReqStatus == USBH_NOT_SUPPORTED)
1079         {
1080           USBH_UsrLog("Product : N/A");
1081           phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
1082 
1083 #if (USBH_USE_OS == 1U)
1084           phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
1085 #if (osCMSIS < 0x20000U)
1086           (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
1087 #else
1088           (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
1089 #endif
1090 #endif
1091         }
1092         else
1093         {
1094           /* .. */
1095         }
1096       }
1097       else
1098       {
1099         USBH_UsrLog("Product : N/A");
1100         phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
1101 
1102 #if (USBH_USE_OS == 1U)
1103         phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
1104 #if (osCMSIS < 0x20000U)
1105         (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
1106 #else
1107         (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
1108 #endif
1109 #endif
1110       }
1111       break;
1112 
1113     case ENUM_GET_SERIALNUM_STRING_DESC:
1114       if (phost->device.DevDesc.iSerialNumber != 0U)
1115       {
1116         /* Check that Serial number string is available */
1117         ReqStatus = USBH_Get_StringDesc(phost, phost->device.DevDesc.iSerialNumber,
1118                                         phost->device.Data, 0xFFU);
1119         if (ReqStatus == USBH_OK)
1120         {
1121           /* User callback for Serial number string */
1122           USBH_UsrLog("Serial Number : %s", (char *)(void *)phost->device.Data);
1123           Status = USBH_OK;
1124         }
1125         else if (ReqStatus == USBH_NOT_SUPPORTED)
1126         {
1127           USBH_UsrLog("Serial Number : N/A");
1128           Status = USBH_OK;
1129         }
1130         else
1131         {
1132           /* .. */
1133         }
1134       }
1135       else
1136       {
1137         USBH_UsrLog("Serial Number : N/A");
1138         Status = USBH_OK;
1139       }
1140       break;
1141 
1142     default:
1143       break;
1144   }
1145   return Status;
1146 }
1147 
1148 
1149 /**
1150   * @brief  USBH_LL_SetTimer
1151   *         Set the initial Host Timer tick
1152   * @param  phost: Host Handle
1153   * @retval None
1154   */
USBH_LL_SetTimer(USBH_HandleTypeDef * phost,uint32_t time)1155 void  USBH_LL_SetTimer(USBH_HandleTypeDef *phost, uint32_t time)
1156 {
1157   phost->Timer = time;
1158 }
1159 
1160 
1161 /**
1162   * @brief  USBH_LL_IncTimer
1163   *         Increment Host Timer tick
1164   * @param  phost: Host Handle
1165   * @retval None
1166   */
USBH_LL_IncTimer(USBH_HandleTypeDef * phost)1167 void  USBH_LL_IncTimer(USBH_HandleTypeDef *phost)
1168 {
1169   phost->Timer++;
1170   USBH_HandleSof(phost);
1171 }
1172 
1173 
1174 /**
1175   * @brief  USBH_HandleSof
1176   *         Call SOF process
1177   * @param  phost: Host Handle
1178   * @retval None
1179   */
USBH_HandleSof(USBH_HandleTypeDef * phost)1180 static void  USBH_HandleSof(USBH_HandleTypeDef *phost)
1181 {
1182   if ((phost->gState == HOST_CLASS) && (phost->pActiveClass != NULL))
1183   {
1184     phost->pActiveClass->SOFProcess(phost);
1185   }
1186 }
1187 
1188 
1189 /**
1190   * @brief  USBH_PortEnabled
1191   *         Port Enabled
1192   * @param  phost: Host Handle
1193   * @retval None
1194   */
USBH_LL_PortEnabled(USBH_HandleTypeDef * phost)1195 void USBH_LL_PortEnabled(USBH_HandleTypeDef *phost)
1196 {
1197   phost->device.PortEnabled = 1U;
1198 
1199 #if (USBH_USE_OS == 1U)
1200   phost->os_msg = (uint32_t)USBH_PORT_EVENT;
1201 #if (osCMSIS < 0x20000U)
1202   (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
1203 #else
1204   (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
1205 #endif
1206 #endif
1207 
1208   return;
1209 }
1210 
1211 
1212 /**
1213   * @brief  USBH_LL_PortDisabled
1214   *         Port Disabled
1215   * @param  phost: Host Handle
1216   * @retval None
1217   */
USBH_LL_PortDisabled(USBH_HandleTypeDef * phost)1218 void USBH_LL_PortDisabled(USBH_HandleTypeDef *phost)
1219 {
1220   phost->device.PortEnabled = 0U;
1221 
1222   return;
1223 }
1224 
1225 
1226 /**
1227   * @brief  HCD_IsPortEnabled
1228   *         Is Port Enabled
1229   * @param  phost: Host Handle
1230   * @retval None
1231   */
USBH_IsPortEnabled(USBH_HandleTypeDef * phost)1232 uint8_t USBH_IsPortEnabled(USBH_HandleTypeDef *phost)
1233 {
1234   return (phost->device.PortEnabled);
1235 }
1236 
1237 
1238 /**
1239   * @brief  USBH_LL_Connect
1240   *         Handle USB Host connexion event
1241   * @param  phost: Host Handle
1242   * @retval USBH_Status
1243   */
USBH_LL_Connect(USBH_HandleTypeDef * phost)1244 USBH_StatusTypeDef  USBH_LL_Connect(USBH_HandleTypeDef *phost)
1245 {
1246   phost->device.is_connected = 1U;
1247   phost->device.is_disconnected = 0U;
1248   phost->device.is_ReEnumerated = 0U;
1249 
1250 
1251 #if (USBH_USE_OS == 1U)
1252   phost->os_msg = (uint32_t)USBH_PORT_EVENT;
1253 #if (osCMSIS < 0x20000U)
1254   (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
1255 #else
1256   (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
1257 #endif
1258 #endif
1259 
1260   return USBH_OK;
1261 }
1262 
1263 
1264 /**
1265   * @brief  USBH_LL_Disconnect
1266   *         Handle USB Host disconnection event
1267   * @param  phost: Host Handle
1268   * @retval USBH_Status
1269   */
USBH_LL_Disconnect(USBH_HandleTypeDef * phost)1270 USBH_StatusTypeDef  USBH_LL_Disconnect(USBH_HandleTypeDef *phost)
1271 {
1272   /* update device connection states */
1273   phost->device.is_disconnected = 1U;
1274   phost->device.is_connected = 0U;
1275   phost->device.PortEnabled = 0U;
1276 
1277   /* Stop Host */
1278   USBH_LL_Stop(phost);
1279 
1280   /* FRee Control Pipes */
1281   USBH_FreePipe(phost, phost->Control.pipe_in);
1282   USBH_FreePipe(phost, phost->Control.pipe_out);
1283 #if (USBH_USE_OS == 1U)
1284   phost->os_msg = (uint32_t)USBH_PORT_EVENT;
1285 #if (osCMSIS < 0x20000U)
1286   (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
1287 #else
1288   (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
1289 #endif
1290 #endif
1291 
1292   return USBH_OK;
1293 }
1294 
1295 
1296 #if (USBH_USE_OS == 1U)
1297 /**
1298   * @brief  USB Host Thread task
1299   * @param  pvParameters not used
1300   * @retval None
1301   */
1302 
1303 #if (osCMSIS < 0x20000U)
USBH_Process_OS(void const * argument)1304 static void USBH_Process_OS(void const *argument)
1305 {
1306   osEvent event;
1307 
1308   for (;;)
1309   {
1310     event = osMessageGet(((USBH_HandleTypeDef *)argument)->os_event, osWaitForever);
1311     if (event.status == osEventMessage)
1312     {
1313       USBH_Process((USBH_HandleTypeDef *)argument);
1314     }
1315   }
1316 }
1317 #else
USBH_Process_OS(void * argument)1318 static void USBH_Process_OS(void *argument)
1319 {
1320   osStatus_t status;
1321 
1322   for (;;)
1323   {
1324     status = osMessageQueueGet(((USBH_HandleTypeDef *)argument)->os_event,
1325                                &((USBH_HandleTypeDef *)argument)->os_msg, NULL, osWaitForever);
1326     if (status == osOK)
1327     {
1328       USBH_Process((USBH_HandleTypeDef *)argument);
1329     }
1330   }
1331 }
1332 #endif /* (osCMSIS < 0x20000U) */
1333 
1334 
1335 /**
1336 * @brief  USBH_LL_NotifyURBChange
1337 *         Notify URB state Change
1338 * @param  phost: Host handle
1339 * @retval USBH Status
1340 */
USBH_LL_NotifyURBChange(USBH_HandleTypeDef * phost)1341 USBH_StatusTypeDef  USBH_LL_NotifyURBChange(USBH_HandleTypeDef *phost)
1342 {
1343   phost->os_msg = (uint32_t)USBH_PORT_EVENT;
1344 
1345 #if (osCMSIS < 0x20000U)
1346   (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
1347 #else
1348   (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
1349 #endif
1350 
1351   return USBH_OK;
1352 }
1353 #endif
1354 /**
1355   * @}
1356   */
1357 
1358 /**
1359   * @}
1360   */
1361 
1362 /**
1363   * @}
1364   */
1365 
1366 /**
1367   * @}
1368   */
1369 
1370 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
1371