USBDevice with Nucleo 32L476RG support

Dependents:   ObCP_ENSMM_V2020_Test_Accelero

Revision:
71:53949e6131f6
diff -r 2c525a50f1b6 -r 53949e6131f6 targets/TARGET_Silicon_Labs/src/em_usbdep.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/TARGET_Silicon_Labs/src/em_usbdep.c	Thu Jul 27 12:14:04 2017 +0100
@@ -0,0 +1,446 @@
+/**************************************************************************//**
+ * @file em_usbdep.c
+ * @brief USB protocol stack library, USB device endpoint handlers.
+ * @version 3.20.14
+ ******************************************************************************
+ * @section License
+ * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
+ *******************************************************************************
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "em_device.h"
+#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
+#include "em_usb.h"
+#if defined( USB_DEVICE )
+
+#include "em_usbtypes.h"
+#include "em_usbhal.h"
+#include "em_usbd.h"
+
+#ifdef USB_USE_PRINTF
+static const char *epStatusStr[] = {
+    "IDLE","TRANS","RECV","IN_S","OUT_S"
+};
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+/*
+ * USBDEP_Ep0Handler() is called each time a packet has been transmitted
+ * or recieved on the default endpoint.
+ * A state machine navigate us through the phases of a control transfer
+ * according to "chapter 9" in the USB spec.
+ */
+#if !defined( USB_DOEP0INT_STUPPKTRCVD )
+void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
+{
+  int status;
+  USBD_Ep_TypeDef *ep;
+  static bool statusIn;
+  static uint32_t xferred;
+  static USB_XferCompleteCb_TypeDef callback;
+
+  ep = &device->ep[ 0 ];
+
+#ifdef __MBED__
+
+  (void)xferred;
+  (void)statusIn;
+  (void)status;
+
+  USB_PRINTF("USBDEP: ep0 %s, rem %ld, z %d\n", epStatusStr[ep->state], ep->remaining, ep->zlp);
+
+  if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
+  {
+    ep->state = D_EP_IDLE;
+
+    if ( ep->xferCompleteCb )
+    {
+      callback = ep->xferCompleteCb;
+      ep->xferCompleteCb = NULL;
+      callback( USB_STATUS_OK, ep->xferred, ep->remaining );
+    }
+
+    USBDHAL_ReenableEp0Setup(device);
+  }
+  else
+  {
+    device->callbacks->setupCmd(device->setup);
+  }
+
+#else /* not __MBED__ */
+
+  switch ( ep->state )
+  {
+    case D_EP_IDLE:
+      ep->remaining = 0;
+      ep->zlp = 0;
+      callback = NULL;
+      statusIn = false;
+
+      status = USBDCH9_SetupCmd( device );
+
+      if ( status == USB_STATUS_REQ_ERR )
+      {
+        ep->in = true;
+        USBDHAL_StallEp( ep );              /* Stall Ep0 IN                 */
+        ep->in = false;                     /* OUT for next SETUP           */
+        USBDHAL_StallEp( ep );              /* Stall Ep0 OUT                */
+        USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP packet*/
+      }
+      else /* ( Status == USB_STATUS_OK ) */
+      {
+        if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
+        {
+          callback = ep->xferCompleteCb;
+        }
+
+        if ( ep->state != D_EP_RECEIVING )
+        {
+          if ( ep->remaining )
+          {
+            /* Data will be sent to host, check if a ZLP must be appended */
+            if ( ( ep->remaining < device->setup->wLength ) &&
+                 ( ep->remaining % ep->packetSize == 0    )    )
+            {
+              ep->zlp = 1;
+            }
+          }
+          else
+          {
+            /* Prepare for next SETUP packet*/
+            USBDHAL_ReenableEp0Setup( device );
+
+            /* No data stage, a ZLP may have been sent. If not, send one */
+
+            xferred = 0;
+            if ( ep->zlp == 0 )
+            {
+              USBD_Write( 0, NULL, 0, NULL );             /* ACK to host */
+              ep->state = D_EP0_IN_STATUS;
+            }
+            else
+            {
+              ep->state = D_EP_IDLE;
+              ep->in = false;                      /* OUT for next SETUP */
+            }
+          }
+        }
+      }
+      break;
+
+    case D_EP_RECEIVING:
+      if ( ep->remaining )
+      {
+        /* There is more data to receive */
+        USBD_ReArmEp0( ep );
+      }
+      else
+      {
+        status = USB_STATUS_OK;
+        if ( callback != NULL )
+        {
+          status = callback( USB_STATUS_OK, ep->xferred, 0 );
+          callback = NULL;
+        }
+
+        if ( status != USB_STATUS_OK )
+        {
+          ep->in = true;
+          USBDHAL_StallEp( ep );              /* Stall Ep0 IN                */
+          ep->in = false;                     /* OUT for next SETUP           */
+          USBDHAL_StallEp( ep );              /* Stall Ep0 OUT                */
+          USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP pkt. */
+          ep->state = D_EP_IDLE;
+        }
+        else /* Everything OK, send a ZLP (ACK) to host */
+        {
+          USBDHAL_ReenableEp0Setup( device );/* Prepare for next SETUP packet*/
+
+          ep->state = D_EP_IDLE;              /* USBD_Write() sets state back*/
+                                              /* to EP_TRANSMITTING          */
+          USBD_Write( 0, NULL, 0, NULL );
+          ep->state = D_EP0_IN_STATUS;
+        }
+      }
+      break;
+
+    case D_EP_TRANSMITTING:
+      if ( ep->remaining )
+      {
+        /* There is more data to transmit */
+        USBD_ReArmEp0( ep );
+      }
+      else
+      {
+        /* All data transferred, is a ZLP packet needed ? */
+        if ( ep->zlp == 1 )
+        {
+          xferred   = ep->xferred;
+          ep->state = D_EP_IDLE;          /* USBD_Write() sets state back */
+                                          /* to EP_TRANSMITTING           */
+          USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP                     */
+          ep->zlp = 2;
+        }
+        else
+        {
+          if ( ep->zlp == 0 )
+          {
+            xferred = ep->xferred;
+          }
+
+          ep->state = D_EP_IDLE;
+          USBD_Read( 0, NULL, 0, NULL );  /* Get ZLP packet (ACK) from host */
+          statusIn = true;
+          ep->state = D_EP0_OUT_STATUS;
+        }
+      }
+      break;
+
+    case D_EP0_IN_STATUS:
+    case D_EP0_OUT_STATUS:
+      if ( statusIn )
+      {
+        USBDHAL_ReenableEp0Setup( device );
+      }
+
+      if ( callback != NULL )
+      {
+        callback( USB_STATUS_OK, xferred, 0 );
+      }
+
+      ep->state = D_EP_IDLE;
+      ep->in = false;                     /* OUT for next SETUP */
+      break;
+
+    default:
+      EFM_ASSERT( false );
+      break;
+  }
+#endif /* __MBED__ */
+}
+#endif
+
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
+{
+  int status;
+  USBD_Ep_TypeDef *ep;
+  static uint32_t xferred;
+  static USB_XferCompleteCb_TypeDef callback;
+
+#ifdef __MBED__
+
+  (void)xferred;
+  (void)status;
+
+  ep = &device->ep[ 0 ];
+
+  if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
+  {
+    ep->state = D_EP_IDLE;
+
+    if ( ep->xferCompleteCb )
+    {
+      callback = ep->xferCompleteCb;
+      ep->xferCompleteCb = NULL;
+      callback( USB_STATUS_OK, ep->xferred, ep->remaining );
+    }
+
+    USBDHAL_StartEp0Setup( dev );
+  }
+  else
+  {
+    device->callbacks->setupCmd(device->setup);
+  }
+
+#else
+
+  ep = &device->ep[ 0 ];
+
+  switch ( ep->state )
+  {
+    case D_EP_IDLE:
+      ep->zlp       = 0;
+      ep->remaining = 0;
+      callback      = NULL;
+
+      status = USBDCH9_SetupCmd( device );
+
+      if ( status == USB_STATUS_REQ_ERR )
+      {
+        ep->in = true;
+        USBDHAL_StallEp( ep );              /* Stall Ep0 IN                 */
+        ep->in = false;                     /* OUT for next SETUP           */
+        USBDHAL_StallEp( ep );              /* Stall Ep0 OUT                */
+        USBDHAL_StartEp0Setup( dev );       /* Prepare for next SETUP packet*/
+      }
+      else /* ( Status == USB_STATUS_OK ) */
+      {
+        if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
+        {
+          callback = ep->xferCompleteCb;
+        }
+
+        if ( ep->state != D_EP_RECEIVING )
+        {
+          if ( ep->remaining )
+          {
+            /* Data will be sent to host, check if a ZLP must be appended */
+            if ( ( ep->remaining < device->setup->wLength ) &&
+                 ( ep->remaining % ep->packetSize == 0    )    )
+            {
+              ep->zlp = 1;
+            }
+          }
+          else
+          {
+            /* No data stage, a ZLP may have been sent. If not, send one */
+            xferred = 0;
+            if ( ep->zlp == 0 )
+            {
+              ep->state = D_EP_IDLE;
+              USBD_Write( 0, NULL, 0, NULL );             /* ACK to host */
+              ep->state = D_EP0_IN_STATUS;
+            }
+          }
+        }
+      }
+      break;
+
+    case D_EP_RECEIVING:
+      if ( ep->remaining )
+      {
+        ep->in = false;
+        USBD_ReArmEp0( ep );
+      }
+      else
+      {
+        status = USB_STATUS_OK;
+        if ( callback != NULL )
+        {
+          status = callback( USB_STATUS_OK, ep->xferred, 0 );
+          callback = NULL;
+        }
+
+        if ( status != USB_STATUS_OK )
+        {
+          ep->in = true;
+          USBDHAL_StallEp( ep );              /* Stall Ep0 IN                */
+          ep->in = false;                     /* OUT for next SETUP          */
+          USBDHAL_StallEp( ep );              /* Stall Ep0 OUT               */
+          USBDHAL_StartEp0Setup( dev );       /* Prepare for next SETUP pkt. */
+          ep->state = D_EP_IDLE;
+        }
+        else
+        {
+
+          USBDHAL_StartEp0Setup( dev );      /* Prepare for next SETUP packet*/
+          ep->state = D_EP_IDLE;             /* USBD_Write() sets state back */
+                                             /* to EP_TRANSMITTING           */
+          USBD_Write( 0, NULL, 0, NULL );
+          ep->state = D_EP0_IN_STATUS;
+        }
+      }
+      break;
+
+    case D_EP_TRANSMITTING:
+      if ( ep->remaining )
+      {
+        ep->in = true;
+        USBD_ReArmEp0( ep );
+      }
+      else
+      {
+        if ( ep->zlp == 1 )
+        {
+          xferred   = ep->xferred;
+          ep->state = D_EP_IDLE;          /* USBD_Write() sets state back */
+                                          /* to EP_TRANSMITTING           */
+          USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP                     */
+          ep->zlp = 2;
+        }
+        else
+        {
+          if ( ep->zlp == 0 )
+          {
+            xferred = ep->xferred;
+          }
+
+          ep->state = D_EP_IDLE;
+          USBD_Read( 0, NULL, 0, NULL );  /* Get ZLP packet (ACK) from host */
+          ep->state = D_EP0_OUT_STATUS;
+        }
+      }
+      break;
+
+    case D_EP0_IN_STATUS:
+      if ( ( USB->DOEP0CTL & USB_DOEP0CTL_EPENA ) == 0 )
+      {
+        /* Prepare for more SETUP Packets */
+        USBDHAL_StartEp0Setup( dev );
+      }
+      if ( callback != NULL )
+      {
+        callback( USB_STATUS_OK, xferred, 0 );
+      }
+      ep->state = D_EP_IDLE;
+      ep->in = false;                     /* OUT for next SETUP */
+      break;
+
+    case D_EP0_OUT_STATUS:
+      USBDHAL_StartEp0Setup( dev );       /* Prepare for more SETUP Packets */
+      if ( callback != NULL )
+      {
+        callback( USB_STATUS_OK, xferred, 0 );
+      }
+      ep->state = D_EP_IDLE;
+      ep->in = false;                     /* OUT for next SETUP */
+      break;
+  }
+#endif /* __MBED__ */
+}
+#endif
+
+/*
+ * USBDEP_EpHandler() is called each time a packet has been transmitted
+ * or recieved on an endpoint other than the default endpoint.
+ */
+void USBDEP_EpHandler( uint8_t epAddr )
+{
+  USB_XferCompleteCb_TypeDef callback;
+  USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+
+  if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
+  {
+    ep->state = D_EP_IDLE;
+    if ( ep->xferCompleteCb )
+    {
+      callback = ep->xferCompleteCb;
+      ep->xferCompleteCb = NULL;
+      callback( USB_STATUS_OK, ep->xferred, ep->remaining );
+    }
+  }
+  else
+  {
+    EFM_ASSERT( false );
+  }
+}
+
+/** @endcond */
+
+#endif /* defined( USB_DEVICE ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */