diff --git a/hal/src/core/usb_settings.h b/hal/src/core/usb_settings.h
new file mode 100644
index 0000000000..093565a691
--- /dev/null
+++ b/hal/src/core/usb_settings.h
@@ -0,0 +1,26 @@
+/**
+ Copyright (c) 2016 Particle Industries, Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation, either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see .
+ ******************************************************************************
+ */
+
+#ifndef USB_SETTINGS_H_
+#define USB_SETTINGS_H_
+
+#define USB_RX_BUFFER_SIZE 256
+
+//#define USB_SERIAL_USERSPACE_BUFFERS 0
+
+#endif /* USB_SETTINGS_H_ */
\ No newline at end of file
diff --git a/hal/src/stm32f2xx/usb_hal.c b/hal/src/stm32f2xx/usb_hal.c
index 131b87d9c1..2918e11d80 100644
--- a/hal/src/stm32f2xx/usb_hal.c
+++ b/hal/src/stm32f2xx/usb_hal.c
@@ -28,12 +28,15 @@
/* Includes ------------------------------------------------------------------*/
#include "usb_hal.h"
-#include "usbd_cdc_core.h"
+#include "usb_settings.h"
+#include "usbd_mcdc.h"
#include "usbd_usr.h"
#include "usb_conf.h"
#include "usbd_desc.h"
#include "delay_hal.h"
#include "interrupts_hal.h"
+#include "ringbuf_helper.h"
+#include
/* Private typedef -----------------------------------------------------------*/
@@ -52,18 +55,10 @@ extern uint32_t USBD_OTG_EP1OUT_ISR_Handler(USB_OTG_CORE_HANDLE *pdev);
/* Extern variables ----------------------------------------------------------*/
#ifdef USB_CDC_ENABLE
-extern volatile LINE_CODING linecoding;
-extern volatile uint8_t USB_DEVICE_CONFIGURED;
-extern volatile uint8_t USB_Rx_Buffer[];
-extern volatile uint32_t USB_Rx_Buffer_head;
-extern volatile uint32_t USB_Rx_Buffer_tail;
-extern volatile uint32_t USB_Rx_Buffer_length;
-extern volatile uint8_t USB_Tx_Buffer[];
-extern volatile uint32_t USB_Tx_Buffer_head;
-extern volatile uint32_t USB_Tx_Buffer_tail;
-extern volatile uint8_t USB_Tx_State;
-extern volatile uint8_t USB_Rx_State;
-extern volatile uint8_t USB_Serial_Open;
+static void (*LineCoding_BitRate_Handler)(uint32_t bitRate) = NULL;
+USBD_MCDC_Instance_Data USBD_MCDC = {{0}};
+__ALIGN_BEGIN static uint8_t USBD_MCDC_Rx_Buffer[USB_RX_BUFFER_SIZE];
+__ALIGN_BEGIN static uint8_t USBD_MCDC_Tx_Buffer[USB_TX_BUFFER_SIZE];
#endif
#if defined (USB_CDC_ENABLE) || defined (USB_HID_ENABLE)
@@ -82,7 +77,7 @@ void SPARK_USB_Setup(void)
USB_OTG_HS_CORE_ID,
#endif
&USR_desc,
- &USBD_CDC_cb,
+ &USBD_MCDC_cb,
NULL);
}
@@ -100,6 +95,18 @@ void Get_SerialNum(void)
#endif
#ifdef USB_CDC_ENABLE
+
+uint16_t USB_USART_Request_Handler(/*USBD_Composite_Class_Data* cls, */uint32_t cmd, uint8_t* buf, uint32_t len) {
+ if (cmd == SET_LINE_CODING && LineCoding_BitRate_Handler) {
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+ if (priv)
+ LineCoding_BitRate_Handler(priv->linecoding.bitrate);
+ }
+
+ return 0;
+}
+
/*******************************************************************************
* Function Name : USB_USART_Init
* Description : Start USB-USART protocol.
@@ -108,9 +115,9 @@ void Get_SerialNum(void)
*******************************************************************************/
void USB_USART_Init(uint32_t baudRate)
{
- if (linecoding.bitrate != baudRate)
+ if (USBD_MCDC.linecoding.bitrate != baudRate)
{
- if (!baudRate && linecoding.bitrate > 0)
+ if (!baudRate && USBD_MCDC.linecoding.bitrate > 0)
{
// Deconfigure CDC class endpoints
USBD_ClrCfg(&USB_OTG_dev, 0);
@@ -130,8 +137,18 @@ void USB_USART_Init(uint32_t baudRate)
// Soft reattach
// USB_OTG_dev.regs.DREGS->DCTL |= 0x02;
}
- else if (!linecoding.bitrate)
+ else if (!USBD_MCDC.linecoding.bitrate)
{
+ memset((void*)&USBD_MCDC, 0, sizeof(USBD_MCDC));
+ USBD_MCDC.ep_in_data = CDC_IN_EP;
+ USBD_MCDC.ep_in_int = CDC_CMD_EP;
+ USBD_MCDC.ep_out_data = CDC_OUT_EP;
+ USBD_MCDC.rx_buffer = USBD_MCDC_Rx_Buffer;
+ USBD_MCDC.tx_buffer = USBD_MCDC_Tx_Buffer;
+ USBD_MCDC.rx_buffer_size = USB_RX_BUFFER_SIZE;
+ USBD_MCDC.tx_buffer_size = USB_TX_BUFFER_SIZE;
+ USBD_MCDC.name = "Serial";
+ USBD_MCDC.req_handler = USB_USART_Request_Handler;
//Initialize USB device
SPARK_USB_Setup();
@@ -143,26 +160,41 @@ void USB_USART_Init(uint32_t baudRate)
// USB_OTG_dev.regs.DREGS->DCTL |= 0x02;
}
//linecoding.bitrate will be overwritten by USB Host
- linecoding.bitrate = baudRate;
+ USBD_MCDC.linecoding.bitrate = baudRate;
}
}
unsigned USB_USART_Baud_Rate(void)
{
- return linecoding.bitrate;
+ return USBD_MCDC.linecoding.bitrate;
+}
+
+static bool USB_WillPreempt()
+{
+ if (HAL_IsISR()) {
+#ifdef USE_USB_OTG_FS
+ int32_t irq = OTG_FS_IRQn;
+#else
+ int32_t irq = OTG_HS_IRQn;
+#endif
+ if (!HAL_WillPreempt(irq, HAL_ServicedIRQn()))
+ return false;
+ }
+
+ return true;
}
+
void USB_USART_LineCoding_BitRate_Handler(void (*handler)(uint32_t bitRate))
{
//Init USB Serial first before calling the linecoding handler
USB_USART_Init(9600);
- //Set the system defined custom handler
- SetLineCodingBitRateHandler(handler);
+ LineCoding_BitRate_Handler = handler;
}
static inline bool USB_USART_Connected() {
- return linecoding.bitrate > 0 && USB_OTG_dev.dev.device_status == USB_OTG_CONFIGURED && USB_Serial_Open;
+ return USBD_MCDC.linecoding.bitrate > 0 && USB_OTG_dev.dev.device_status == USB_OTG_CONFIGURED && USBD_MCDC.serial_open;
}
/*******************************************************************************
@@ -175,10 +207,9 @@ uint8_t USB_USART_Available_Data(void)
{
int32_t available = 0;
int state = HAL_disable_irq();
- if (USB_Rx_Buffer_head >= USB_Rx_Buffer_tail)
- available = USB_Rx_Buffer_head - USB_Rx_Buffer_tail;
- else
- available = USB_Rx_Buffer_length + USB_Rx_Buffer_head - USB_Rx_Buffer_tail;
+ available = ring_data_avail(USBD_MCDC.rx_buffer_length,
+ USBD_MCDC.rx_buffer_head,
+ USBD_MCDC.rx_buffer_tail);
HAL_enable_irq(state);
return available;
}
@@ -194,11 +225,9 @@ int32_t USB_USART_Receive_Data(uint8_t peek)
if (USB_USART_Available_Data() > 0)
{
int state = HAL_disable_irq();
- uint8_t data = USB_Rx_Buffer[USB_Rx_Buffer_tail];
+ uint8_t data = USBD_MCDC.rx_buffer[USBD_MCDC.rx_buffer_tail];
if (!peek) {
- USB_Rx_Buffer_tail++;
- if (USB_Rx_Buffer_tail == USB_Rx_Buffer_length)
- USB_Rx_Buffer_tail = 0;
+ USBD_MCDC.rx_buffer_tail = ring_wrap(USBD_MCDC.rx_buffer_length, USBD_MCDC.rx_buffer_tail + 1);
}
HAL_enable_irq(state);
return data;
@@ -217,9 +246,11 @@ int32_t USB_USART_Available_Data_For_Write(void)
{
if (USB_USART_Connected())
{
- uint32_t tail = USB_Tx_Buffer_tail;
- int32_t available = USB_TX_BUFFER_SIZE - (USB_Tx_Buffer_head >= tail ?
- USB_Tx_Buffer_head - tail : USB_TX_BUFFER_SIZE + USB_Tx_Buffer_head - tail) - 1;
+ int state = HAL_disable_irq();
+ int32_t available = ring_space_avail(USBD_MCDC.tx_buffer_size,
+ USBD_MCDC.tx_buffer_head,
+ USBD_MCDC.tx_buffer_tail);
+ HAL_enable_irq(state);
return available;
}
@@ -232,22 +263,26 @@ int32_t USB_USART_Available_Data_For_Write(void)
* Input : Data.
* Return : None.
*******************************************************************************/
-void USB_USART_Send_Data(uint8_t Data)
+void USB_USART_Send_Data(uint8_t data)
{
+ int32_t ret = -1;
int32_t available = 0;
do {
available = USB_USART_Available_Data_For_Write();
}
- while (available < 1 && available != -1);
+ while (available < 1 && available != -1 && USB_WillPreempt());
// Confirm once again that the Host is connected
- if (USB_USART_Connected())
+ int32_t state = HAL_disable_irq();
+ if (USB_USART_Connected() && available > 0)
{
- uint32_t head = USB_Tx_Buffer_head;
-
- USB_Tx_Buffer[head] = Data;
-
- USB_Tx_Buffer_head = ++head % USB_TX_BUFFER_SIZE;
+ USBD_MCDC.tx_buffer[USBD_MCDC.tx_buffer_head] = data;
+ USBD_MCDC.tx_buffer_head = ring_wrap(USBD_MCDC.tx_buffer_size, USBD_MCDC.tx_buffer_head + 1);
+ ret = 1;
}
+ HAL_enable_irq(state);
+
+ //return ret;
+ (void)ret;
}
/*******************************************************************************
@@ -258,9 +293,9 @@ void USB_USART_Send_Data(uint8_t Data)
*******************************************************************************/
void USB_USART_Flush_Data(void)
{
- while(USB_USART_Connected() && USB_USART_Available_Data_For_Write() != (USB_TX_BUFFER_SIZE - 1));
+ while(USB_USART_Connected() && USB_USART_Available_Data_For_Write() != (USBD_MCDC.tx_buffer_size - 1) && USB_WillPreempt());
// We should also wait for USB_Tx_State to become 0, as hardware might still be busy transmitting data
- while(USB_Tx_State == 1);
+ while(USBD_MCDC.tx_state == 1);
}
#endif
diff --git a/hal/src/stm32f2xx/usb_settings.h b/hal/src/stm32f2xx/usb_settings.h
new file mode 100644
index 0000000000..6f3049f31f
--- /dev/null
+++ b/hal/src/stm32f2xx/usb_settings.h
@@ -0,0 +1,28 @@
+/**
+ Copyright (c) 2016 Particle Industries, Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation, either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see .
+ ******************************************************************************
+ */
+
+#ifndef USB_SETTINGS_H_
+#define USB_SETTINGS_H_
+
+#define USB_TX_BUFFER_SIZE 129 /* Total size of IN buffer:
+ APP_RX_DATA_SIZE*8/MAX_BAUDARATE*1000 should be > CDC_IN_FRAME_INTERVAL */
+#define USB_RX_BUFFER_SIZE 256
+
+//#define USB_SERIAL_USERSPACE_BUFFERS 1
+
+#endif /* USB_SETTINGS_H_ */
\ No newline at end of file
diff --git a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/usbd_conf.h b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/usbd_conf.h
index a6ed06686f..27c7b6f7f9 100644
--- a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/usbd_conf.h
+++ b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/usbd_conf.h
@@ -86,9 +86,9 @@
#define CDC_CMD_PACKET_SZE 8 /* Control Endpoint Packet size */
#define CDC_IN_FRAME_INTERVAL 1 /* Number of micro-frames between IN transfers */
-#define USB_TX_BUFFER_SIZE 128 /* Total size of IN buffer:
- APP_RX_DATA_SIZE*8/MAX_BAUDARATE*1000 should be > CDC_IN_FRAME_INTERVAL */
-#define USB_RX_BUFFER_SIZE 256
+// #define USB_TX_BUFFER_SIZE 128 /* Total size of IN buffer:
+// APP_RX_DATA_SIZE*8/MAX_BAUDARATE*1000 should be > CDC_IN_FRAME_INTERVAL */
+// #define USB_RX_BUFFER_SIZE 256
#define APP_FOPS APP_fops
diff --git a/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc/usbd_mcdc.h b/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc/usbd_mcdc.h
new file mode 100644
index 0000000000..410c1dca8f
--- /dev/null
+++ b/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc/usbd_mcdc.h
@@ -0,0 +1,101 @@
+#ifndef USBD_MCDC_H_
+#define USBD_MCDC_H_
+
+#include
+#include "usbd_ioreq.h"
+
+#define USBD_MCDC_CONFIG_DESC_SIZE (67)
+#define USBD_MCDC_DESC_SIZE (USBD_MCDC_CONFIG_DESC_SIZE - 9)
+
+#define CDC_DESCRIPTOR_TYPE 0x21
+
+#define DEVICE_CLASS_CDC 0x02
+#define DEVICE_SUBCLASS_CDC 0x00
+
+#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
+#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
+#define USB_STRING_DESCRIPTOR_TYPE 0x03
+#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
+#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
+
+#define STANDARD_ENDPOINT_DESC_SIZE 0x09
+
+#define CDC_DATA_IN_PACKET_SIZE CDC_DATA_MAX_PACKET_SIZE
+
+#define CDC_DATA_OUT_PACKET_SIZE CDC_DATA_MAX_PACKET_SIZE
+
+/*---------------------------------------------------------------------*/
+/* CDC definitions */
+/*---------------------------------------------------------------------*/
+
+/**************************************************/
+/* CDC Requests */
+/**************************************************/
+#define SEND_ENCAPSULATED_COMMAND 0x00
+#define GET_ENCAPSULATED_RESPONSE 0x01
+#define SET_COMM_FEATURE 0x02
+#define GET_COMM_FEATURE 0x03
+#define CLEAR_COMM_FEATURE 0x04
+#define SET_LINE_CODING 0x20
+#define GET_LINE_CODING 0x21
+#define SET_CONTROL_LINE_STATE 0x22
+#define SEND_BREAK 0x23
+#define NO_CMD 0xFF
+#define ACM_SERIAL_STATE 0x20
+
+#define CDC_DTR 0x01
+#define CDC_RTS 0x02
+
+typedef struct USBD_MCDC_Instance_Data {
+ // // Back-reference to USBD_Composite_Class_Data
+ // void* cls;
+
+ LINE_CODING linecoding;
+ uint8_t ep_in_data;
+ uint8_t ep_out_data;
+ uint8_t ep_in_int;
+
+ __ALIGN_BEGIN volatile uint32_t alt_set __ALIGN_END;
+
+ uint8_t* rx_buffer;
+ uint16_t rx_buffer_size;
+ volatile uint32_t rx_buffer_head;
+ volatile uint32_t rx_buffer_tail;
+ volatile uint32_t rx_buffer_length;
+
+ uint8_t* tx_buffer;
+ uint16_t tx_buffer_size;
+ volatile uint32_t tx_buffer_head;
+ volatile uint32_t tx_buffer_tail;
+ volatile uint32_t tx_failed_counter;
+ volatile uint32_t tx_buffer_last;
+
+ __ALIGN_BEGIN uint8_t cmd_buffer[CDC_CMD_PACKET_SZE] __ALIGN_END;
+
+ volatile uint8_t rx_state;
+ volatile uint8_t tx_state;
+ volatile uint8_t serial_open;
+
+ uint8_t configured;
+
+ uint32_t cmd;
+ uint32_t cmd_len;
+
+ uint32_t frame_count;
+
+ uint8_t ctrl_line;
+
+ uint16_t (*req_handler) (/*USBD_Composite_Class_Data* cls, */uint32_t cmd, uint8_t* buf, uint32_t len);
+
+ const char* name;
+
+ #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+ // Temporary aligned buffer
+ __ALIGN_BEGIN uint8_t descriptor[USBD_MCDC_CONFIG_DESC_SIZE] __ALIGN_END;
+ #endif
+} USBD_MCDC_Instance_Data;
+
+// extern USBD_Multi_Instance_cb_Typedef USBD_MCDC_cb;
+extern USBD_Class_cb_TypeDef USBD_MCDC_cb;
+
+#endif /* USBD_MCDC_H_ */
diff --git a/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/src/sources.mk b/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/src/sources.mk
index 69ae6b2593..41756b3025 100644
--- a/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/src/sources.mk
+++ b/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/src/sources.mk
@@ -30,8 +30,7 @@ CSRC += $(TARGET_USB_FS_SRC_PATH)/usbd_sflash_if.c
endif
# cdc/usbserial specific files
-CSRC += $(TARGET_USB_FS_SRC_PATH)/usbd_cdc_core.c
-CSRC += $(TARGET_USB_FS_SRC_PATH)/usbd_cdc_if.c
+CSRC += $(TARGET_USB_FS_SRC_PATH)/usbd_mcdc.c
# C++ source files included in this build.
CPPSRC +=
diff --git a/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/src/usbd_mcdc.c b/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/src/usbd_mcdc.c
new file mode 100644
index 0000000000..f2dac9701a
--- /dev/null
+++ b/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/src/usbd_mcdc.c
@@ -0,0 +1,664 @@
+#include
+#include "usbd_mcdc.h"
+#include "usbd_desc.h"
+#include "usbd_req.h"
+#include "debug.h"
+#include "ringbuf_helper.h"
+
+// LOG_SOURCE_CATEGORY("usb.mcdc")
+
+#define USBD_MCDC_USRSTR_BASE 10
+
+#ifndef MIN
+#define MIN(a, b) (a) < (b) ? (a) : (b)
+#endif
+#ifndef MAX
+#define MAX(a, b) (a) > (b) ? (a) : (b)
+#endif
+
+static uint8_t USBD_MCDC_Init (void* pdev/*, USBD_Composite_Class_Data* cls*/, uint8_t cfgidx);
+static uint8_t USBD_MCDC_DeInit (void* pdev/*, USBD_Composite_Class_Data* cls*/, uint8_t cfgidx);
+static uint8_t USBD_MCDC_Setup (void* pdev/*, USBD_Composite_Class_Data* cls*/, USB_SETUP_REQ *req);
+static uint8_t USBD_MCDC_EP0_RxReady (void* pdev/*, USBD_Composite_Class_Data* cls*/);
+static uint8_t USBD_MCDC_DataIn (void* pdev/*, USBD_Composite_Class_Data* cls*/, uint8_t epnum);
+static uint8_t USBD_MCDC_DataOut (void* pdev/*, USBD_Composite_Class_Data* cls*/, uint8_t epnum);
+static uint8_t USBD_MCDC_SOF (void* pdev/*, USBD_Composite_Class_Data* cls*/);
+
+static uint8_t* USBD_MCDC_GetCfgDesc (uint8_t speed/*, USBD_Composite_Class_Data* cls*/, uint16_t *length);
+static uint8_t* USBD_MCDC_GetUsrStrDescriptor(uint8_t speed/*, USBD_Composite_Class_Data* cls*/, uint8_t index, uint16_t* length);
+
+static uint16_t USBD_MCDC_Request_Handler(void* pdev/*, USBD_Composite_Class_Data* cls*/, uint32_t cmd, uint8_t* buf, uint32_t len);
+static int USBD_MCDC_Start_Rx(void *pdev, USBD_MCDC_Instance_Data* priv);
+static void USBD_MCDC_Schedule_Out(void *pdev, USBD_MCDC_Instance_Data* priv);
+
+static const uint8_t USBD_MCDC_CfgDesc[USBD_MCDC_CONFIG_DESC_SIZE] __ALIGN_END;
+
+#ifdef CDC_CMD_EP_SHARED
+static uint8_t USBD_MCDC_Cmd_Ep_Refcount = 0;
+#endif
+
+extern USBD_MCDC_Instance_Data USBD_MCDC;
+
+/* CDC interface class callbacks structure */
+USBD_Class_cb_TypeDef USBD_MCDC_cb =
+{
+ USBD_MCDC_Init,
+ USBD_MCDC_DeInit,
+ USBD_MCDC_Setup,
+ NULL, /* EP0_TxSent, */
+ USBD_MCDC_EP0_RxReady,
+ USBD_MCDC_DataIn,
+ USBD_MCDC_DataOut,
+ USBD_MCDC_SOF,
+ NULL,
+ NULL,
+ USBD_MCDC_GetCfgDesc,
+#ifdef USE_USB_OTG_HS
+ USBD_MCDC_GetCfgDesc, /* use same cobfig as per FS */
+#endif /* USE_USB_OTG_HS */
+ USBD_MCDC_GetUsrStrDescriptor,
+};
+// USBD_Multi_Instance_cb_Typedef USBD_MCDC_cb =
+// {
+// USBD_MCDC_Init,
+// USBD_MCDC_DeInit,
+// USBD_MCDC_Setup,
+// NULL, /* EP0_TxSent, */
+// USBD_MCDC_EP0_RxReady,
+// USBD_MCDC_DataIn,
+// USBD_MCDC_DataOut,
+// USBD_MCDC_SOF,
+// NULL,
+// NULL,
+// USBD_MCDC_GetCfgDesc,
+// #ifdef USE_USB_OTG_HS
+// USBD_MCDC_GetCfgDesc, /* use same cobfig as per FS */
+// #endif /* USE_USB_OTG_HS */
+// USBD_MCDC_GetUsrStrDescriptor,
+
+// };
+
+static const uint8_t USBD_MCDC_CfgDesc[USBD_MCDC_CONFIG_DESC_SIZE] __ALIGN_END =
+{
+ /*Configuration Descriptor*/
+ 0x09, /* bLength: Configuration Descriptor size */
+ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
+ USBD_MCDC_CONFIG_DESC_SIZE, /* wTotalLength:no of returned bytes */
+ 0x00,
+ 0x02, /* bNumInterfaces: 2 interface */
+ 0x01, /* bConfigurationValue: Configuration value */
+ 0x00, /* iConfiguration: Index of string descriptor describing the configuration */
+ 0xC0, /* bmAttributes: self powered */
+ 0x32, /* MaxPower 100 mA */
+
+ /*---------------------------------------------------------------------------*/
+
+ /*Interface Descriptor */
+ 0x09, /* bLength: Interface Descriptor size */
+ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
+ /* Interface descriptor type */
+ 0x00, /* bInterfaceNumber: Number of Interface */
+ 0x00, /* bAlternateSetting: Alternate setting */
+ 0x01, /* bNumEndpoints: One endpoints used */
+ 0x02, /* bInterfaceClass: Communication Interface Class */
+ 0x02, /* bInterfaceSubClass: Abstract Control Model */
+ 0x01, /* bInterfaceProtocol: Common AT commands */
+ 0x00, /* iInterface: */
+
+ /*Header Functional Descriptor*/
+ 0x05, /* bLength: Endpoint Descriptor size */
+ 0x24, /* bDescriptorType: CS_INTERFACE */
+ 0x00, /* bDescriptorSubtype: Header Func Desc */
+ 0x10, /* bcdCDC: spec release number */
+ 0x01,
+
+ /*Call Management Functional Descriptor*/
+ 0x05, /* bFunctionLength */
+ 0x24, /* bDescriptorType: CS_INTERFACE */
+ 0x01, /* bDescriptorSubtype: Call Management Func Desc */
+ 0x00, /* bmCapabilities: D0+D1 */
+ 0x01, /* bDataInterface: 1 */
+
+ /*ACM Functional Descriptor*/
+ 0x04, /* bFunctionLength */
+ 0x24, /* bDescriptorType: CS_INTERFACE */
+ 0x02, /* bDescriptorSubtype: Abstract Control Management desc */
+ 0x02, /* bmCapabilities */
+
+ /*Union Functional Descriptor*/
+ 0x05, /* bFunctionLength */
+ 0x24, /* bDescriptorType: CS_INTERFACE */
+ 0x06, /* bDescriptorSubtype: Union func desc */
+ 0x00, /* bMasterInterface: Communication class interface */
+ 0x01, /* bSlaveInterface0: Data Class Interface */
+
+ /*Endpoint 2 Descriptor*/
+ 0x07, /* bLength: Endpoint Descriptor size */
+ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
+ CDC_CMD_EP, /* bEndpointAddress */
+ 0x03, /* bmAttributes: Interrupt */
+ LOBYTE(CDC_CMD_PACKET_SZE), /* wMaxPacketSize: */
+ HIBYTE(CDC_CMD_PACKET_SZE),
+#ifdef USE_USB_OTG_HS
+ 0x10, /* bInterval: */
+#else
+ 0xFF, /* bInterval: */
+#endif /* USE_USB_OTG_HS */
+
+ /*---------------------------------------------------------------------------*/
+
+ /*Data class interface descriptor*/
+ 0x09, /* bLength: Endpoint Descriptor size */
+ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
+ 0x01, /* bInterfaceNumber: Number of Interface */
+ 0x00, /* bAlternateSetting: Alternate setting */
+ 0x02, /* bNumEndpoints: Two endpoints used */
+ 0x0A, /* bInterfaceClass: CDC */
+ 0x00, /* bInterfaceSubClass: */
+ 0x00, /* bInterfaceProtocol: */
+ 0x00, /* iInterface: */
+
+ /*Endpoint OUT Descriptor*/
+ 0x07, /* bLength: Endpoint Descriptor size */
+ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
+ CDC_OUT_EP, /* bEndpointAddress */
+ 0x02, /* bmAttributes: Bulk */
+ LOBYTE(CDC_DATA_MAX_PACKET_SIZE), /* wMaxPacketSize: */
+ HIBYTE(CDC_DATA_MAX_PACKET_SIZE),
+ 0x00, /* bInterval: ignore for Bulk transfer */
+
+ /*Endpoint IN Descriptor*/
+ 0x07, /* bLength: Endpoint Descriptor size */
+ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
+ CDC_IN_EP, /* bEndpointAddress */
+ 0x02, /* bmAttributes: Bulk */
+ LOBYTE(CDC_DATA_MAX_PACKET_SIZE), /* wMaxPacketSize: */
+ HIBYTE(CDC_DATA_MAX_PACKET_SIZE),
+ 0x00 /* bInterval: ignore for Bulk transfer */
+};
+
+static void USBD_MCDC_Change_Open_State(void* pdev, USBD_MCDC_Instance_Data* priv, uint8_t state) {
+ if (state != priv->serial_open) {
+ // USBD_Composite_Class_Data* cls = (USBD_Composite_Class_Data*)priv->cls;
+ // (void)cls;
+ //LOG_DEBUG(TRACE, "[%s] USB Serial state: %d", priv->name, state);
+ if (state) {
+ priv->tx_failed_counter = 0;
+ // Also flush everything in TX buffer
+ priv->tx_buffer_head = priv->tx_buffer_tail = priv->tx_buffer_last = 0;
+
+ priv->tx_state = 0;
+ USBD_MCDC_Schedule_Out(pdev, priv);
+ }
+ priv->serial_open = state;
+ }
+}
+
+static uint8_t USBD_MCDC_Init(void* pdev/*, USBD_Composite_Class_Data* cls*/, uint8_t cfgidx)
+{
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+ USBD_MCDC_DeInit(pdev, /*cls,*/ cfgidx);
+
+#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+ memcpy(priv->descriptor, /*cls->cfg,*/ USBD_MCDC_CfgDesc, USBD_MCDC_DESC_SIZE);
+#endif
+
+ /* Open EP IN */
+ DCD_EP_Open(pdev,
+ priv->ep_in_data,
+ CDC_DATA_IN_PACKET_SIZE,
+ USB_OTG_EP_BULK);
+
+ /* Open EP OUT */
+ DCD_EP_Open(pdev,
+ priv->ep_out_data,
+ CDC_DATA_OUT_PACKET_SIZE,
+ USB_OTG_EP_BULK);
+
+#ifdef CDC_CMD_EP_SHARED
+ if (USBD_MCDC_Cmd_Ep_Refcount++ == 0) {
+#endif
+ if (priv->ep_in_int != priv->ep_in_data) {
+ /* Open Command IN EP */
+ DCD_EP_Open(pdev,
+ priv->ep_in_int,
+ CDC_CMD_PACKET_SZE,
+ USB_OTG_EP_INT);
+ }
+#ifdef CDC_CMD_EP_SHARED
+ }
+#endif
+ priv->configured = 1;
+ priv->rx_state = 1;
+
+ USBD_MCDC_Start_Rx(pdev, priv);
+
+ return USBD_OK;
+}
+
+static uint8_t USBD_MCDC_DeInit(void* pdev/*, USBD_Composite_Class_Data* cls*/, uint8_t cfgidx)
+{
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+ USBD_MCDC_Change_Open_State(pdev, priv, 0);
+
+ if (priv->configured) {
+ if (priv->tx_state) {
+ DCD_EP_Flush(pdev, priv->ep_in_data);
+ }
+
+ /* Close EP IN */
+ DCD_EP_Close(pdev,
+ priv->ep_in_data);
+
+ /* Close EP OUT */
+ DCD_EP_Close(pdev,
+ priv->ep_out_data);
+#ifdef CDC_CMD_EP_SHARED
+ if (--USBD_MCDC_Cmd_Ep_Refcount == 0) {
+#endif
+ if (priv->ep_in_int != priv->ep_in_data) {
+ /* Close Command IN EP */
+ DCD_EP_Close(pdev,
+ priv->ep_in_int);
+ }
+#ifdef CDC_CMD_EP_SHARED
+ }
+#endif
+ }
+
+ USBD_MCDC_Change_Open_State(pdev, priv, 0);
+
+ priv->configured = 0;
+ priv->tx_state = 0;
+ priv->rx_state = 0;
+ priv->rx_buffer_head = 0;
+ priv->rx_buffer_tail = 0;
+ priv->rx_buffer_length = priv->rx_buffer_size;
+ priv->tx_buffer_head = 0;
+ priv->tx_buffer_tail = 0;
+ priv->tx_buffer_last = 0;
+ priv->frame_count = 0;
+ priv->cmd = NO_CMD;
+ priv->ctrl_line = 0x00;
+
+ return USBD_OK;
+}
+
+static uint8_t USBD_MCDC_Setup(void* pdev/*, USBD_Composite_Class_Data* cls*/, USB_SETUP_REQ *req)
+{
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+ uint16_t len = 0;
+ uint8_t* pbuf = NULL;
+
+ switch (req->bmRequest & USB_REQ_TYPE_MASK)
+ {
+ /* CDC Class Requests -------------------------------*/
+ case USB_REQ_TYPE_CLASS :
+ /* Check if the request is a data setup packet */
+ if (req->wLength)
+ {
+ /* Check if the request is Device-to-Host */
+ if (req->bmRequest & 0x80)
+ {
+ /* Get the data to be sent to Host from interface layer */
+ USBD_MCDC_Request_Handler(pdev, /*cls,*/ req->bRequest, priv->cmd_buffer, req->wLength);
+
+ /* Send the data to the host */
+ USBD_CtlSendData (pdev,
+ priv->cmd_buffer,
+ req->wLength);
+ }
+ else /* Host-to-Device requeset */
+ {
+ /* Set the value of the current command to be processed */
+ priv->cmd = req->bRequest;
+ priv->cmd_len = req->wLength;
+
+ /* Prepare the reception of the buffer over EP0
+ Next step: the received data will be managed in usbd_cdc_EP0_TxSent()
+ function. */
+ USBD_CtlPrepareRx (pdev,
+ priv->cmd_buffer,
+ req->wLength);
+ }
+ }
+ else /* No Data request */
+ {
+ /* Transfer the command to the interface layer */
+ USBD_MCDC_Request_Handler(pdev, /*cls,*/ req->bRequest, (uint8_t*)&req->wValue, sizeof(req->wValue));
+ }
+
+ return USBD_OK;
+
+ /* Standard Requests -------------------------------*/
+ case USB_REQ_TYPE_STANDARD: {
+ switch (req->bRequest)
+ {
+ case USB_REQ_GET_DESCRIPTOR:
+ if( (req->wValue >> 8) == CDC_DESCRIPTOR_TYPE)
+ {
+ // For CDC this request should never arrive probably
+ #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+ pbuf = priv->descriptor;
+ #else
+ // pbuf = cls->cfg;
+ pbuf = (uint8_t*)USBD_MCDC_CfgDesc + 9;
+ #endif
+ len = MIN(USBD_MCDC_DESC_SIZE , req->wLength);
+ }
+
+ USBD_CtlSendData (pdev,
+ pbuf,
+ len);
+ break;
+
+ case USB_REQ_GET_INTERFACE :
+ USBD_CtlSendData (pdev,
+ (uint8_t *)&priv->alt_set,
+ 1);
+ break;
+
+ case USB_REQ_SET_INTERFACE :
+ if ((uint8_t)(req->wValue) < USBD_ITF_MAX_NUM)
+ {
+ priv->alt_set = (uint8_t)(req->wValue);
+ }
+ else
+ {
+ /* Call the error management function (command will be nacked */
+ USBD_CtlError (pdev, req);
+ }
+ break;
+ default:
+ USBD_CtlError(pdev, req);
+ return USBD_OK;
+ }
+ break;
+ }
+
+ default:
+ USBD_CtlError (pdev, req);
+ return USBD_FAIL;
+ }
+ return USBD_OK;
+}
+
+static uint8_t USBD_MCDC_EP0_RxReady(void* pdev/*, USBD_Composite_Class_Data* cls*/)
+{
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+
+ if (priv->cmd != NO_CMD)
+ {
+ // USBD_MCDC_Change_Open_State(priv, 1);
+ /* Process the data */
+ USBD_MCDC_Request_Handler(pdev, /*cls,*/ priv->cmd, priv->cmd_buffer, priv->cmd_len);
+
+ /* Reset the command variable to default value */
+ priv->cmd = NO_CMD;
+ }
+
+ return USBD_OK;
+}
+
+static inline uint32_t USBD_Last_Tx_Packet_size(void *pdev, uint8_t epnum)
+{
+ return ((USB_OTG_CORE_HANDLE*)pdev)->dev.in_ep[epnum].xfer_len;
+}
+
+static inline uint32_t USBD_Last_Rx_Packet_size(void *pdev, uint8_t epnum)
+{
+ return ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count;
+}
+
+static uint8_t USBD_MCDC_DataIn(void* pdev/*, USBD_Composite_Class_Data* cls*/, uint8_t epnum)
+{
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+ uint32_t USB_Tx_length;
+
+ if ((epnum | 0x80) != (priv->ep_in_data) && (epnum | 0x80) != (priv->ep_in_int)) {
+ return USBD_FAIL;
+ }
+
+ USBD_MCDC_Change_Open_State(pdev, priv, 1);
+
+ if (!priv->tx_state)
+ return USBD_OK;
+
+ priv->tx_failed_counter = 0;
+ priv->tx_buffer_tail = ring_wrap(priv->tx_buffer_size, priv->tx_buffer_tail + priv->tx_buffer_last);
+ priv->tx_buffer_last = 0;
+
+ USB_Tx_length = ring_data_contig(priv->tx_buffer_size, priv->tx_buffer_head, priv->tx_buffer_tail);
+
+ if (USB_Tx_length) {
+ USB_Tx_length = MIN(USB_Tx_length, CDC_DATA_IN_PACKET_SIZE);
+ } else if (USBD_Last_Tx_Packet_size(pdev, epnum) != CDC_DATA_IN_PACKET_SIZE) {
+ priv->tx_state = 0;
+ return USBD_OK;
+ }
+
+ priv->tx_buffer_last = USB_Tx_length;
+
+ /* Prepare the available data buffer to be sent on IN endpoint */
+ DCD_EP_Tx (pdev,
+ priv->ep_in_data,
+ (uint8_t*)&priv->tx_buffer[priv->tx_buffer_tail],
+ USB_Tx_length);
+
+ return USBD_OK;
+}
+
+int USBD_MCDC_Start_Rx(void *pdev, USBD_MCDC_Instance_Data* priv)
+{
+
+ /* USB_Rx_Buffer_length is used here to keep track of
+ * available _contiguous_ buffer space in USB_Rx_Buffer.
+ */
+ uint32_t USB_Rx_length;
+ if (priv->rx_buffer_head >= priv->rx_buffer_tail)
+ priv->rx_buffer_length = priv->rx_buffer_size;
+
+ USB_Rx_length = ring_space_contig(priv->rx_buffer_length, priv->rx_buffer_head, priv->rx_buffer_tail);
+
+ if (USB_Rx_length < CDC_DATA_OUT_PACKET_SIZE) {
+ USB_Rx_length = ring_space_wrapped(priv->rx_buffer_length, priv->rx_buffer_head, priv->rx_buffer_tail);
+ if (USB_Rx_length < CDC_DATA_OUT_PACKET_SIZE) {
+ if (priv->rx_state) {
+ priv->rx_state = 0;
+ DCD_SetEPStatus(pdev, priv->ep_out_data, USB_OTG_EP_RX_NAK);
+ }
+ return 0;
+ }
+ priv->rx_buffer_length = priv->rx_buffer_head;
+ priv->rx_buffer_head = 0;
+ if (priv->rx_buffer_tail == priv->rx_buffer_length)
+ priv->rx_buffer_tail = 0;
+ }
+ if (!priv->rx_state) {
+ priv->rx_state = 1;
+ DCD_SetEPStatus(pdev, priv->ep_out_data, USB_OTG_EP_RX_VALID);
+ }
+
+ DCD_EP_PrepareRx(pdev,
+ priv->ep_out_data,
+ priv->rx_buffer + priv->rx_buffer_head,
+ CDC_DATA_OUT_PACKET_SIZE);
+ return 1;
+}
+
+static uint8_t USBD_MCDC_DataOut(void* pdev/*, USBD_Composite_Class_Data* cls*/, uint8_t epnum)
+{
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+ if (epnum != (priv->ep_out_data)) {
+ return USBD_FAIL;
+ }
+
+ uint32_t USB_Rx_Count = USBD_Last_Rx_Packet_size(pdev, epnum);
+ priv->rx_buffer_head = ring_wrap(priv->rx_buffer_length, priv->rx_buffer_head + USB_Rx_Count);
+
+ // Serial port is definitely open
+ USBD_MCDC_Change_Open_State(pdev, priv, 1);
+
+ USBD_MCDC_Start_Rx(pdev, priv);
+
+ return USBD_OK;
+}
+
+void USBD_MCDC_Schedule_Out(void *pdev, USBD_MCDC_Instance_Data* priv)
+{
+ if (!priv->rx_state)
+ USBD_MCDC_Start_Rx(pdev, priv);
+}
+
+static void USBD_MCDC_Schedule_In(void *pdev, USBD_MCDC_Instance_Data* priv)
+{
+ uint32_t USB_Tx_length;
+
+ if (priv->tx_state) {
+ if (priv->serial_open) {
+ priv->tx_failed_counter++;
+ if (priv->tx_failed_counter >= 1000) {
+ USBD_MCDC_Change_Open_State(pdev, priv, 0);
+ }
+ }
+
+ if (!priv->serial_open) {
+ // Completely flush TX buffer
+ DCD_EP_Flush(pdev, priv->ep_in_data);
+ // Send ZLP
+ DCD_EP_Tx(pdev, priv->ep_in_data, NULL, 0);
+ priv->tx_buffer_head = 0;
+ priv->tx_buffer_tail = 0;
+ priv->tx_buffer_last = 0;
+ USB_Tx_length = 0;
+
+ priv->tx_state = 0;
+ }
+ return;
+ }
+
+ priv->tx_buffer_tail = ring_wrap(priv->tx_buffer_size, priv->tx_buffer_tail + priv->tx_buffer_last);
+ priv->tx_buffer_last = 0;
+
+ USB_Tx_length = ring_data_contig(priv->tx_buffer_size, priv->tx_buffer_head, priv->tx_buffer_tail);
+
+ if (!USB_Tx_length)
+ return;
+
+ priv->tx_state = 1;
+ priv->tx_failed_counter = 0;
+
+ USB_Tx_length = MIN(USB_Tx_length, CDC_DATA_IN_PACKET_SIZE);
+ priv->tx_buffer_last = USB_Tx_length;
+
+ DCD_EP_Tx (pdev,
+ priv->ep_in_data,
+ (uint8_t*)&priv->tx_buffer[priv->tx_buffer_tail],
+ USB_Tx_length);
+}
+
+static uint8_t USBD_MCDC_SOF(void* pdev/*, USBD_Composite_Class_Data* cls*/)
+{
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+
+ if (priv->configured) {
+ USBD_MCDC_Schedule_In(pdev, priv);
+ USBD_MCDC_Schedule_Out(pdev, priv);
+ }
+
+ return USBD_OK;
+}
+
+static uint8_t* USBD_MCDC_GetCfgDesc(uint8_t speed/*, USBD_Composite_Class_Data* cls, uint8_t* buf*/, uint16_t *length)
+{
+ *length = sizeof(USBD_MCDC_CfgDesc);
+ return (uint8_t*)USBD_MCDC_CfgDesc;
+}
+
+static uint16_t USBD_MCDC_Request_Handler(void* pdev/*, USBD_Composite_Class_Data* cls*/, uint32_t cmd, uint8_t* buf, uint32_t len) {
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+ switch (cmd)
+ {
+ case SEND_ENCAPSULATED_COMMAND:
+ /* Not needed for this driver */
+ break;
+
+ case GET_ENCAPSULATED_RESPONSE:
+ /* Not needed for this driver */
+ break;
+
+ case SET_COMM_FEATURE:
+ /* Not needed for this driver */
+ break;
+
+ case GET_COMM_FEATURE:
+ /* Not needed for this driver */
+ break;
+
+ case CLEAR_COMM_FEATURE:
+ /* Not needed for this driver */
+ break;
+
+ case SET_LINE_CODING:
+ priv->linecoding.bitrate = (uint32_t)(buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24));
+ priv->linecoding.format = buf[4];
+ priv->linecoding.paritytype = buf[5];
+ priv->linecoding.datatype = buf[6];
+ // LOG_DEBUG(TRACE, "[%s] SET_LINE_CODING %d", priv->name, priv->linecoding.bitrate);
+ break;
+
+ case GET_LINE_CODING:
+ buf[0] = (uint8_t)(priv->linecoding.bitrate);
+ buf[1] = (uint8_t)(priv->linecoding.bitrate >> 8);
+ buf[2] = (uint8_t)(priv->linecoding.bitrate >> 16);
+ buf[3] = (uint8_t)(priv->linecoding.bitrate >> 24);
+ buf[4] = priv->linecoding.format;
+ buf[5] = priv->linecoding.paritytype;
+ buf[6] = priv->linecoding.datatype;
+ break;
+
+ case SET_CONTROL_LINE_STATE:
+ priv->ctrl_line = buf[0];
+ if (priv->ctrl_line & CDC_DTR) {
+ USBD_MCDC_Change_Open_State(pdev, priv, 1);
+ } else if ((priv->ctrl_line & CDC_DTR) == 0x00) {
+ USBD_MCDC_Change_Open_State(pdev, priv, 0);
+ }
+ // LOG_DEBUG(TRACE, "[%s] SET_CONTROL_LINE_STATE DTR=%d RTS=%d", priv->name, priv->ctrl_line & CDC_DTR ? 1 : 0, priv->ctrl_line & CDC_RTS ? 1 : 0);
+ break;
+
+ case SEND_BREAK:
+ /* Not needed for this driver */
+ break;
+
+ default:
+ break;
+ }
+
+ if (priv->req_handler) {
+ priv->req_handler(/*cls, */cmd, buf, len);
+ }
+
+ return USBD_OK;
+}
+
+uint8_t* USBD_MCDC_GetUsrStrDescriptor(uint8_t speed/*, USBD_Composite_Class_Data* cls*/, uint8_t index, uint16_t* length) {
+ // USBD_MCDC_Instance_Data* priv = (USBD_MCDC_Instance_Data*)cls->priv;
+ USBD_MCDC_Instance_Data* priv = &USBD_MCDC;
+
+ if (index == (USBD_MCDC_USRSTR_BASE/* + cls->firstInterface*/)) {
+ USBD_GetString((uint8_t*)priv->name, USBD_StrDesc, length);
+ return USBD_StrDesc;
+ }
+
+ *length = 0;
+ return NULL;
+}
diff --git a/services/inc/ringbuf_helper.h b/services/inc/ringbuf_helper.h
new file mode 100644
index 0000000000..f00a1525f5
--- /dev/null
+++ b/services/inc/ringbuf_helper.h
@@ -0,0 +1,60 @@
+#ifndef RINGBUF_HELPER_H_
+#define RINGBUF_HELPER_H_
+
+#include
+
+/* Wrap up buffer index */
+static inline uint32_t ring_wrap(uint32_t size, uint32_t idx)
+{
+ return idx >= size ? idx - size : idx;
+}
+
+/* Returns the number of bytes available in buffer */
+static inline uint32_t ring_data_avail(uint32_t size, uint32_t head, uint32_t tail)
+{
+ if (head >= tail)
+ return head - tail;
+ else
+ return size + head - tail;
+}
+
+/* Returns the amount of free space available in buffer */
+static inline uint32_t ring_space_avail(uint32_t size, uint32_t head, uint32_t tail)
+{
+ if (size == 0)
+ return 0;
+ return size - ring_data_avail(size, head, tail) - 1;
+}
+
+/* Returns the number of contiguous data bytes available in buffer */
+static inline uint32_t ring_data_contig(uint32_t size, uint32_t head, uint32_t tail)
+{
+ if (head >= tail)
+ return head - tail;
+ else
+ return size - tail;
+}
+
+/* Returns the amount of contiguous space available in buffer */
+static inline uint32_t ring_space_contig(uint32_t size, uint32_t head, uint32_t tail)
+{
+ if (size == 0)
+ return 0;
+ if (head >= tail)
+ return (tail ? size : size - 1) - head;
+ else
+ return tail - head - 1;
+}
+
+/* Returns the amount of free space available after wrapping up the head */
+static inline uint32_t ring_space_wrapped(uint32_t size, uint32_t head, uint32_t tail)
+{
+ if (size == 0)
+ return 0;
+ if (head < tail || !tail)
+ return 0;
+ else
+ return tail - 1;
+}
+
+#endif // RINGBUF_HELPER_H_
diff --git a/user/tests/wiring/usbserial/application.cpp b/user/tests/wiring/usbserial/application.cpp
new file mode 100644
index 0000000000..f0199953d6
--- /dev/null
+++ b/user/tests/wiring/usbserial/application.cpp
@@ -0,0 +1,6 @@
+#include "application.h"
+#include "unit-test/unit-test.h"
+
+UNIT_TEST_APP();
+
+SYSTEM_MODE(SEMI_AUTOMATIC);
diff --git a/user/tests/wiring/usbserial/usbserial.cpp b/user/tests/wiring/usbserial/usbserial.cpp
new file mode 100644
index 0000000000..a3eff08d65
--- /dev/null
+++ b/user/tests/wiring/usbserial/usbserial.cpp
@@ -0,0 +1,231 @@
+#include "application.h"
+#include "unit-test/unit-test.h"
+#include "usb_settings.h"
+#include "ringbuf_helper.h"
+
+int randomString(char *buf, int len) {
+ for (int i = 0; i < len; i++) {
+ uint8_t d = random(0, 15);
+ char c = d + 48;
+ if (57 < c)
+ c += 7;
+ buf[i] = c;
+ }
+
+ return len;
+}
+
+void consume(Stream& serial)
+{
+ while (serial.available() > 0) {
+ (void)serial.read();
+ }
+}
+
+test(0_USBSERIAL_RingBufferHelperIsSane) {
+ uint32_t size = 129;
+ uint32_t head = 0;
+ uint32_t tail = 0;
+
+ head = 0;
+ tail = 0;
+ assertEqual(0, ring_data_avail(size, head, tail));
+ assertEqual(128, ring_space_avail(size, head, tail));
+ assertEqual(0, ring_data_contig(size, head, tail));
+ assertEqual(128, ring_space_contig(size, head, tail));
+ assertEqual(0, ring_space_wrapped(size, head, tail));
+
+ head = 63;
+ tail = 0;
+ assertEqual(63, ring_data_avail(size, head, tail));
+ assertEqual(65, ring_space_avail(size, head, tail));
+ assertEqual(63, ring_data_contig(size, head, tail));
+ assertEqual(65, ring_space_contig(size, head, tail));
+ assertEqual(0, ring_space_wrapped(size, head, tail));
+
+ head = 63;
+ tail = 32;
+ assertEqual(31, ring_data_avail(size, head, tail));
+ assertEqual(97, ring_space_avail(size, head, tail));
+ assertEqual(31, ring_data_contig(size, head, tail));
+ assertEqual(66, ring_space_contig(size, head, tail));
+ assertEqual(31, ring_space_wrapped(size, head, tail));
+
+ head = 63;
+ tail = 63;
+ assertEqual(0, ring_data_avail(size, head, tail));
+ assertEqual(128, ring_space_avail(size, head, tail));
+ assertEqual(0, ring_data_contig(size, head, tail));
+ assertEqual(66, ring_space_contig(size, head, tail));
+ assertEqual(62, ring_space_wrapped(size, head, tail));
+
+ head = 128;
+ tail = 63;
+ assertEqual(65, ring_data_avail(size, head, tail));
+ assertEqual(63, ring_space_avail(size, head, tail));
+ assertEqual(65, ring_data_contig(size, head, tail));
+ assertEqual(1, ring_space_contig(size, head, tail));
+ assertEqual(62, ring_space_wrapped(size, head, tail));
+
+ head = 128;
+ tail = 128;
+ assertEqual(0, ring_data_avail(size, head, tail));
+ assertEqual(128, ring_space_avail(size, head, tail));
+ assertEqual(0, ring_data_contig(size, head, tail));
+ assertEqual(1, ring_space_contig(size, head, tail));
+ assertEqual(127, ring_space_wrapped(size, head, tail));
+
+ head = 0;
+ tail = 63;
+ assertEqual(66, ring_data_avail(size, head, tail));
+ assertEqual(62, ring_space_avail(size, head, tail));
+ assertEqual(66, ring_data_contig(size, head, tail));
+ assertEqual(62, ring_space_contig(size, head, tail));
+ assertEqual(0, ring_space_wrapped(size, head, tail));
+
+ head = 32;
+ tail = 63;
+ assertEqual(98, ring_data_avail(size, head, tail));
+ assertEqual(30, ring_space_avail(size, head, tail));
+ assertEqual(66, ring_data_contig(size, head, tail));
+ assertEqual(30, ring_space_contig(size, head, tail));
+ assertEqual(0, ring_space_wrapped(size, head, tail));
+
+ head = 0;
+ tail = 128;
+ assertEqual(1, ring_data_avail(size, head, tail));
+ assertEqual(127, ring_space_avail(size, head, tail));
+ assertEqual(1, ring_data_contig(size, head, tail));
+ assertEqual(127, ring_space_contig(size, head, tail));
+ assertEqual(0, ring_space_wrapped(size, head, tail));
+
+ head = 128;
+ tail = 0;
+ assertEqual(128, ring_data_avail(size, head, tail));
+ assertEqual(0, ring_space_avail(size, head, tail));
+ assertEqual(128, ring_data_contig(size, head, tail));
+ assertEqual(0, ring_space_contig(size, head, tail));
+ assertEqual(0, ring_space_wrapped(size, head, tail));
+}
+
+test(1_USBSERIAL_ReadWrite) {
+ //The following code will test all the important USB Serial routines
+ char test[] = "hello";
+ char message[10];
+ // when
+ consume(Serial);
+ Serial.print("Type the following message and press Enter: ");
+ Serial.println(test);
+ serialReadLine(&Serial, message, 9, 10000);//10 sec timeout
+ Serial.println("");
+ // then
+ assertTrue(strncmp(test, message, 5)==0);
+}
+
+test(2_USBSERIAL_isConnectedWorksCorrectly) {
+ Serial.println("Please close the USB Serial port and open it again within 60 seconds");
+
+ uint32_t mil = millis();
+ // Wait for 60 seconds maximum for the host to close the USB Serial port
+ while(Serial.isConnected()) {
+ assertTrue((millis() - mil) < 60000);
+ }
+ // Wait for 60 seconds maximum for the host to open the USB Serial port again
+ while(!Serial.isConnected()) {
+ assertTrue((millis() - mil) < 60000);
+ }
+
+ delay(10);
+ Serial.println("Glad too see you back!");
+
+ char test[] = "hello";
+ char message[10];
+ // when
+ consume(Serial);
+ Serial.print("Type the following message and press Enter: ");
+ Serial.println(test);
+ serialReadLine(&Serial, message, 9, 10000);//10 sec timeout
+ Serial.println("");
+ // then
+ assertTrue(strncmp(test, message, 5)==0);
+}
+
+test(3_USBSERIAL_RxBufferFillsCompletely) {
+ Serial.println("We will now test USB Serial RX buffer");
+ Serial.println("Please close the USB Serial port and open it again once the device reattaches");
+
+ uint32_t mil = millis();
+ // Wait for 60 seconds maximum for the host to close the USB Serial port
+ while(Serial.isConnected()) {
+ assertTrue((millis() - mil) < 60000);
+ }
+
+ Serial.end();
+ assertEqual(Serial.isEnabled(), false);
+ Serial.begin();
+ assertEqual(Serial.isEnabled(), true);
+
+ // Wait for 60 seconds maximum for the host to open the USB Serial port again
+ while(!Serial.isConnected()) {
+ assertTrue((millis() - mil) < 60000);
+ }
+
+ assertEqual(Serial.available(), 0);
+
+ delay(10);
+ Serial.println("Glad too see you back!");
+
+ for (int attmpt = 0; attmpt < 3; attmpt++) {
+ char randStr[USB_RX_BUFFER_SIZE + 2];
+ char rStr[USB_RX_BUFFER_SIZE + 2];
+ memset(randStr, 0, USB_RX_BUFFER_SIZE + 2);
+ memset(rStr, 0, USB_RX_BUFFER_SIZE + 2);
+ srand(millis());
+ randomString(randStr, USB_RX_BUFFER_SIZE - 1);
+
+ Serial.println("Please copy and paste the following string:");
+ Serial.println(randStr);
+
+ int32_t avail = 0;
+ mil = millis();
+ uint32_t milsame = 0;
+ while(Serial.available() != (USB_RX_BUFFER_SIZE - 1)) {
+ if (avail == Serial.available() && avail != 0) {
+ if (milsame == 0) {
+ milsame = millis();
+ } else {
+ if ((millis() - milsame) >= 5000) {
+ // Depending on the host driver, we might have received (USB_RX_BUFFER_SIZE - 64)
+ break;
+ }
+ }
+ } else {
+ avail = Serial.available();
+ milsame = 0;
+ }
+ assertTrue((millis() - mil) < 120000);
+ }
+ avail = Serial.available();
+ Serial.printf("OK. Read back %d bytes\r\n", avail);
+
+ assertTrue((avail == (USB_RX_BUFFER_SIZE - 1)) ||
+ (avail >= ((USB_RX_BUFFER_SIZE - 1) / 64 * 64)));
+ for (int i = 0; i < avail; i++) {
+ rStr[i] = Serial.read();
+ }
+
+ Serial.printf("Data: %s\r\n\r\n", rStr);
+
+ assertTrue(!strncmp(randStr, rStr, avail));
+
+ delay(500);
+ while(Serial.available()) {
+ (void)Serial.read();
+ }
+
+ if (!((avail == (USB_RX_BUFFER_SIZE - 1)) || (avail == ((USB_RX_BUFFER_SIZE - 1) / 64 * 64)))) {
+ // Continue only if we received data in 64-byte blocks
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/wiring/inc/spark_wiring_usbserial.h b/wiring/inc/spark_wiring_usbserial.h
index 0719b7f1ce..4b5d7cb5c9 100644
--- a/wiring/inc/spark_wiring_usbserial.h
+++ b/wiring/inc/spark_wiring_usbserial.h
@@ -31,17 +31,19 @@
#include "usb_hal.h"
#include "system_task.h"
+
class USBSerial : public Stream
{
public:
// public methods
USBSerial();
- unsigned int baud() { return USB_USART_Baud_Rate(); }
-
- operator bool() { return baud()!=0; }
+ unsigned int baud() { return USB_USART_Baud_Rate(); }
+ operator bool() { return isEnabled(); }
+ bool isConnected();
+ bool isEnabled() { return baud()!=0; }
- void begin(long speed);
+ void begin(long speed=9600);
void end();
int peek();
diff --git a/wiring/src/spark_wiring_usbserial.cpp b/wiring/src/spark_wiring_usbserial.cpp
index 3ea7469d33..c7826f217a 100644
--- a/wiring/src/spark_wiring_usbserial.cpp
+++ b/wiring/src/spark_wiring_usbserial.cpp
@@ -31,7 +31,7 @@
//
USBSerial::USBSerial()
{
- _blocking = true;
+ _blocking = true;
}
//
@@ -48,6 +48,11 @@ void USBSerial::end()
USB_USART_Init(0);
}
+bool USBSerial::isConnected()
+{
+ return USB_USART_Available_Data_For_Write() >= 0;
+}
+
// Read data from buffer
int USBSerial::read()