From 839e030cca349a1ac0a4314080ac4670cdc26f86 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Sun, 20 Jan 2019 16:30:19 +0300 Subject: [PATCH 01/12] [USB] Fixed PMA buffers distribution for non USB OTG Signed-off-by: Alexey Makarenya --- cores/arduino/stm32/usb/usbd_conf.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cores/arduino/stm32/usb/usbd_conf.c b/cores/arduino/stm32/usb/usbd_conf.c index e6f8379a94..5fae55bf0b 100644 --- a/cores/arduino/stm32/usb/usbd_conf.c +++ b/cores/arduino/stm32/usb/usbd_conf.c @@ -483,10 +483,16 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) HAL_PCDEx_SetTxFiFo(&g_hpcd, 1, 0x40); HAL_PCDEx_SetTxFiFo(&g_hpcd, 2, 0x40); #else - HAL_PCDEx_PMAConfig(&g_hpcd, 0x00 , PCD_SNG_BUF, 0x18); - HAL_PCDEx_PMAConfig(&g_hpcd, 0x80 , PCD_SNG_BUF, 0x58); - HAL_PCDEx_PMAConfig(&g_hpcd, 0x81 , PCD_SNG_BUF, 0x100); - HAL_PCDEx_PMAConfig(&g_hpcd, 0x82 , PCD_SNG_BUF, 0x100); + uint32_t pma_addr = 8 * 3; /* 3 endpoints, 8 bytes for each in PMA BTABLE */ + HAL_PCDEx_PMAConfig(&g_hpcd, 0x00, PCD_SNG_BUF, pma_addr); + pma_addr += USB_MAX_EP0_SIZE; + HAL_PCDEx_PMAConfig(&g_hpcd, 0x80, PCD_SNG_BUF, pma_addr); + pma_addr += USB_MAX_EP0_SIZE; + HAL_PCDEx_PMAConfig(&g_hpcd, 0x81, PCD_SNG_BUF, pma_addr); + pma_addr += USB_FS_MAX_PACKET_SIZE; + HAL_PCDEx_PMAConfig(&g_hpcd, 0x01, PCD_SNG_BUF, pma_addr); + pma_addr += USB_FS_MAX_PACKET_SIZE; + HAL_PCDEx_PMAConfig(&g_hpcd, 0x82, PCD_SNG_BUF, pma_addr); #endif #endif /* USE_USB_HS */ return USBD_OK; From cca49a19f42ffac70093b28b8b84992444ee30ae Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Thu, 27 Dec 2018 17:30:23 +0300 Subject: [PATCH 02/12] [USB CDC] Add queue implementation Signed-off-by: Alexey Makarenya --- cores/arduino/stm32/usb/cdc/cdc_queue.c | 143 ++++++++++++++++++++++++ cores/arduino/stm32/usb/cdc/cdc_queue.h | 88 +++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 cores/arduino/stm32/usb/cdc/cdc_queue.c create mode 100644 cores/arduino/stm32/usb/cdc/cdc_queue.h diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c new file mode 100644 index 0000000000..44e0b1c2bf --- /dev/null +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -0,0 +1,143 @@ +/** + ****************************************************************************** + * @file cdc_queue.c + * @author makarenya + * @version V1.0.0 + * @date 23-December-2018 + * @brief Provides methods to manipulate with CDC cyclic buffers + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#ifdef USBCON +#ifdef USBD_USE_CDC + +#include "cdc_queue.h" + +// Initialize read and write position of queue +void CDC_TransmitQueue_Init(CDC_TransmitQueue_TypeDef *queue) { + queue->read = 0; + queue->write = 0; +} + +// Determine size, available for write in queue +int CDC_TransmitQueue_WriteSize(CDC_TransmitQueue_TypeDef *queue) { + return (queue->read + CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->write - 1) + % CDC_TRANSMIT_QUEUE_BUFFER_SIZE; +} + +// Determine size of data, stored in queue +int CDC_TransmitQueue_ReadSize(CDC_TransmitQueue_TypeDef *queue) { + return (queue->write + CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->read) + % CDC_TRANSMIT_QUEUE_BUFFER_SIZE; +} + +// Write provided data into queue. +void CDC_TransmitQueue_Enqueue(CDC_TransmitQueue_TypeDef *queue, const uint8_t *buffer, + uint32_t size) { + uint32_t sizeToEnd = CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->write; + if (sizeToEnd > size) { + memcpy(&queue->buffer[queue->write], &buffer[0], size); + } else { + memcpy(&queue->buffer[queue->write], &buffer[0], sizeToEnd); + memcpy(&queue->buffer[0], &buffer[sizeToEnd], size - sizeToEnd); + } + queue->write = (uint16_t)((queue->write + size) % CDC_TRANSMIT_QUEUE_BUFFER_SIZE); +} + +// Read flat block from queue (biggest as possible, but max CDC_QUEUE_MAX_PACKET_SIZE). +uint8_t *CDC_TransmitQueue_ReadBlock(CDC_TransmitQueue_TypeDef *queue, uint16_t *size) { + uint16_t readPos = queue->read; + if (queue->write >= queue->read) { + *size = queue->write - queue->read; + queue->read = queue->write; + } else if ((uint16_t)(CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->read) > CDC_QUEUE_MAX_PACKET_SIZE) { + // limit to max packet size + *size = CDC_QUEUE_MAX_PACKET_SIZE; + queue->read += CDC_QUEUE_MAX_PACKET_SIZE; + } else { + *size = CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->read; + queue->read = 0; + } + return &queue->buffer[readPos]; +} + +// Initialize read and write position of queue. +void CDC_ReceiveQueue_Init(CDC_ReceiveQueue_TypeDef *queue) { + queue->read = 0; + queue->write = 0; + queue->length = CDC_RECEIVE_QUEUE_BUFFER_SIZE; +} + +// Reserve block in queue and return pointer to it. +uint8_t *CDC_ReceiveQueue_ReserveBlock(CDC_ReceiveQueue_TypeDef *queue) { + if ((uint16_t)(CDC_RECEIVE_QUEUE_BUFFER_SIZE - queue->write) >= CDC_QUEUE_MAX_PACKET_SIZE) { + // have enough space on the rest of buffer to store full-length packet + return &queue->buffer[queue->write]; + } else if (queue->read >= CDC_QUEUE_MAX_PACKET_SIZE) { + // have enough space on the beginning of buffer to store full-length packet + queue->length = queue->write; + queue->write = 0; + return &queue->buffer[queue->write]; + } else { + // have no space to store full-length packet + return 0; + } +} + +// Commits block in queue and make it available for reading +void CDC_ReceiveQueue_CommitBlock(CDC_ReceiveQueue_TypeDef *queue, uint16_t size) { + queue->write += size; +} + +// Determine size, available for read +int CDC_ReceiveQueue_ReadSize(CDC_ReceiveQueue_TypeDef *queue) { + if (queue->write >= queue->read) { + return queue->write - queue->read; + } else { + return queue->length - queue->read; + } +} + +// Read one byte from queue. +uint8_t CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef *queue) { + uint8_t ch = queue->buffer[queue->read++]; + if (queue->read >= queue->length) { + queue->read = 0; + } + return ch; +} + +// Peek byte from queue. +uint8_t CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef *queue) { + return queue->buffer[queue->read]; +} + +#endif /* USBD_USE_CDC */ +#endif /* USBCON */ diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.h b/cores/arduino/stm32/usb/cdc/cdc_queue.h new file mode 100644 index 0000000000..f2a87e9fcb --- /dev/null +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -0,0 +1,88 @@ +/** + ****************************************************************************** + * @file cdc_queue.h + * @author makarenya + * @version V1.0.0 + * @date 23-December-2018 + * @brief Header for cdc_queue.c module + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __CDC_QUEUE_H +#define __CDC_QUEUE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#if USE_USB_HS +#define CDC_QUEUE_MAX_PACKET_SIZE USB_HS_MAX_PACKET_SIZE +#else +#define CDC_QUEUE_MAX_PACKET_SIZE USB_FS_MAX_PACKET_SIZE +#endif +#define CDC_TRANSMIT_QUEUE_BUFFER_SIZE ((uint16_t)(CDC_QUEUE_MAX_PACKET_SIZE)) +#define CDC_RECEIVE_QUEUE_BUFFER_SIZE ((uint16_t)(CDC_QUEUE_MAX_PACKET_SIZE * 2)) + +typedef struct { + uint8_t buffer[CDC_TRANSMIT_QUEUE_BUFFER_SIZE]; + volatile uint16_t write; + volatile uint16_t read; +} CDC_TransmitQueue_TypeDef; + +typedef struct { + uint8_t buffer[CDC_RECEIVE_QUEUE_BUFFER_SIZE]; + volatile uint16_t write; + volatile uint16_t read; + volatile uint16_t length; +} CDC_ReceiveQueue_TypeDef; + +void CDC_TransmitQueue_Init(CDC_TransmitQueue_TypeDef* queue); +int CDC_TransmitQueue_WriteSize(CDC_TransmitQueue_TypeDef* queue); +int CDC_TransmitQueue_ReadSize(CDC_TransmitQueue_TypeDef* queue); +void CDC_TransmitQueue_Enqueue(CDC_TransmitQueue_TypeDef* queue, const uint8_t* buffer, uint32_t size); +uint8_t* CDC_TransmitQueue_ReadBlock(CDC_TransmitQueue_TypeDef* queue, uint16_t* size); + +void CDC_ReceiveQueue_Init(CDC_ReceiveQueue_TypeDef* queue); +int CDC_ReceiveQueue_ReadSize(CDC_ReceiveQueue_TypeDef* queue); +uint8_t CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef* queue); +uint8_t CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef* queue); +uint8_t* CDC_ReceiveQueue_ReserveBlock(CDC_ReceiveQueue_TypeDef* queue); +void CDC_ReceiveQueue_CommitBlock(CDC_ReceiveQueue_TypeDef* queue, uint16_t size); + +#ifdef __cplusplus +} +#endif + +#endif // __CDC_QUEUE_H \ No newline at end of file From 1c91d5adeaf5ee4b37237bb80c28f1c59bb6d5d3 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Fri, 18 Jan 2019 14:53:37 +0100 Subject: [PATCH 03/12] [USB CDC] Remove timer and buffer usage Signed-off-by: Alexey Makarenya --- cores/arduino/USBSerial.cpp | 126 +++++------ cores/arduino/USBSerial.h | 6 +- cores/arduino/stm32/usb/cdc/usbd_cdc.c | 5 + cores/arduino/stm32/usb/cdc/usbd_cdc.h | 1 + cores/arduino/stm32/usb/cdc/usbd_cdc_if.c | 241 +++++++--------------- cores/arduino/stm32/usb/cdc/usbd_cdc_if.h | 33 +-- cores/arduino/stm32/usbd_interface.c | 18 -- 7 files changed, 138 insertions(+), 292 deletions(-) diff --git a/cores/arduino/USBSerial.cpp b/cores/arduino/USBSerial.cpp index 7df1d48e42..51eda7f76c 100644 --- a/cores/arduino/USBSerial.cpp +++ b/cores/arduino/USBSerial.cpp @@ -27,123 +27,97 @@ #define USB_TIMEOUT 50 /* USB Device Core handle declaration */ extern USBD_HandleTypeDef hUSBD_Device_CDC; -extern __IO uint32_t device_connection_status; extern __IO uint32_t lineState; -extern __IO uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; -extern __IO uint8_t UserRxBuffer[APP_RX_DATA_SIZE]; -extern __IO uint32_t UserTxBufPtrIn; -extern __IO uint32_t UserTxBufPtrOut; -extern __IO uint32_t UserRxBufPtrIn; -extern __IO uint32_t UserRxBufPtrOut; USBSerial SerialUSB; void serialEventUSB() __attribute__((weak)); +void USBSerial::begin(void) { + CDC_init(); +} + void USBSerial::begin(uint32_t /* baud_count */) { // uart config is ignored in USB-CDC + begin(); } void USBSerial::begin(uint32_t /* baud_count */, uint8_t /* config */) { // uart config is ignored in USB-CDC + begin(); } -void USBSerial::end(void) { - - USBD_LL_DeInit(&hUSBD_Device_CDC); +void USBSerial::end() { + CDC_deInit(); } -int USBSerial::availableForWrite(void) +int USBSerial::availableForWrite() { - int ret_val; - - /* UserTxBufPtrOut can be modified by TIM ISR, so in order to be sure that the */ - /* value that we read is correct, we need to disable TIM Interrupt. */ - CDC_disable_TIM_Interrupt(); - - if (UserTxBufPtrIn >= UserTxBufPtrOut) { - ret_val = (APP_TX_DATA_SIZE - 1 - UserTxBufPtrIn + UserTxBufPtrOut); - } else { - ret_val = (UserTxBufPtrOut - UserTxBufPtrIn - 1); - } - - CDC_enable_TIM_Interrupt(); - - return ret_val; + // Just transmit queue size, available for write + return static_cast(CDC_TransmitQueue_WriteSize(&TransmitQueue)); } size_t USBSerial::write(uint8_t ch) { - - /* UserTxBufPtrOut can be modified by TIM ISR, so in order to be sure that the */ - /* value that we read is correct, we need to disable TIM Interrupt. */ - CDC_disable_TIM_Interrupt(); - - if (((UserTxBufPtrIn + 1) % APP_TX_DATA_SIZE) == UserTxBufPtrOut) { - // Buffer full!!! Force a flush to not loose data and go on - CDC_flush(); - } - UserTxBuffer[UserTxBufPtrIn] = ch; - UserTxBufPtrIn = ((UserTxBufPtrIn + 1) % APP_TX_DATA_SIZE); - - CDC_enable_TIM_Interrupt(); - - return 1; + // Just write single-byte buffer. + return write(&ch, 1); } size_t USBSerial::write(const uint8_t *buffer, size_t size){ - size_t i = 0; - for (i=0; i < size; i++) { - if (write(buffer[i]) != 1) { - break; - } + size_t rest = size; + while(rest > 0) { + // Determine buffer size available for write + auto portion = (size_t)CDC_TransmitQueue_WriteSize(&TransmitQueue); + // Truncate it to content size (if rest is greater) + if (rest < portion) { + portion = rest; + } + if (portion > 0) { + // Only if some space in the buffer exists. + // TS: Only main thread calls write and writeSize methods, + // it's thread-safe since IRQ does not affects + // TransmitQueue write position + CDC_TransmitQueue_Enqueue(&TransmitQueue, buffer, portion); + rest -= portion; + buffer += portion; + // After storing data, start transmitting process + CDC_continue_transmit(); + } } - return i; + return size; } int USBSerial::available(void) { - return ((APP_RX_DATA_SIZE + (UserRxBufPtrIn - UserRxBufPtrOut)) % APP_RX_DATA_SIZE); + // Just ReceiveQueue size, available for reading + return static_cast(CDC_ReceiveQueue_ReadSize(&ReceiveQueue)); } int USBSerial::read(void) { - if (UserRxBufPtrOut == UserRxBufPtrIn) { + // Empty ReceiveQueue - nothing to return + if (CDC_ReceiveQueue_ReadSize(&ReceiveQueue) <= 0) { return -1; - } else { - unsigned char c = UserRxBuffer[UserRxBufPtrOut]; - UserRxBufPtrOut = ((UserRxBufPtrOut + 1) % APP_RX_DATA_SIZE); - CDC_resume_receive(); - return c; } + // Dequeue only one char from queue + // TS: it safe, because only main thread affects ReceiveQueue->read pos + char ch = CDC_ReceiveQueue_Dequeue(&ReceiveQueue); + // Resume receive process, if possible + CDC_resume_receive(); + return ch; } int USBSerial::peek(void) { - if (UserRxBufPtrOut == UserRxBufPtrIn) { + // Empty ReceiveQueue - nothing to return + if (CDC_ReceiveQueue_ReadSize(&ReceiveQueue) <= 0) { return -1; - } else { - unsigned char c = UserRxBuffer[UserRxBufPtrOut]; - return c; } + // Peek one symbol, it can't change receive avaiablity + return CDC_ReceiveQueue_Peek(&ReceiveQueue); } void USBSerial::flush(void) { - /* UserTxBufPtrOut can be modified by TIM ISR, so in order to be sure that the */ - /* value that we read is correct, we need to disable TIM Interrupt. */ - CDC_disable_TIM_Interrupt(); - CDC_flush(); - CDC_enable_TIM_Interrupt(); -} - -uint8_t USBSerial::pending(void) { - return 0; -} - -uint8_t USBSerial::isConnected(void) { - - if (device_connection_status == 1) { - return 1; - } else { - return 0; - } + // Wait for TransmitQueue read size becomes zero + // TS: safe, because it not be stopped while receive 0 + while(CDC_TransmitQueue_ReadSize(&TransmitQueue) > 0) {} } uint32_t USBSerial::baud() { diff --git a/cores/arduino/USBSerial.h b/cores/arduino/USBSerial.h index 10b28f996d..331e65340f 100644 --- a/cores/arduino/USBSerial.h +++ b/cores/arduino/USBSerial.h @@ -27,8 +27,7 @@ // Serial over CDC class USBSerial : public Stream { public: - USBSerial(void) {}; - + void begin(void); void begin(uint32_t); void begin(uint32_t, uint8_t); void end(void); @@ -64,9 +63,6 @@ class USBSerial : public Stream { MARK_PARITY = 3, SPACE_PARITY = 4, }; - - uint8_t isConnected(); - uint8_t pending(); }; extern USBSerial SerialUSB; diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc.c b/cores/arduino/stm32/usb/cdc/usbd_cdc.c index 1674333598..7c8b5a997b 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc.c @@ -678,6 +678,7 @@ static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) { USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)pdev->pClassData; PCD_HandleTypeDef *hpcd = pdev->pData; + USBD_CDC_ItfTypeDef* ctrl = (USBD_CDC_ItfTypeDef *)pdev->pUserData; if(pdev->pClassData != NULL) { @@ -692,6 +693,10 @@ static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) else { hcdc->TxState = 0U; + if (ctrl->Transferred) + { + ctrl->Transferred(); + } } return USBD_OK; } diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc.h b/cores/arduino/stm32/usb/cdc/usbd_cdc.h index 1cddfeaf8b..556ac47ef7 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc.h +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc.h @@ -104,6 +104,7 @@ typedef struct _USBD_CDC_Itf int8_t (* DeInit) (void); int8_t (* Control) (uint8_t cmd, uint8_t* pbuf, uint16_t length); int8_t (* Receive) (uint8_t* Buf, uint32_t *Len); + int8_t (* Transferred) (void); }USBD_CDC_ItfTypeDef; diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c index 76b3b54690..e34a7b0b49 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c @@ -21,6 +21,7 @@ #ifdef USBD_USE_CDC /* Includes ------------------------------------------------------------------*/ +#include "usbd_desc.h" #include "usbd_cdc_if.h" #ifdef USE_USB_HS @@ -32,33 +33,15 @@ #endif /* USBD_CDC Private Variables */ +/* USB Device Core CDC handle declaration */ +USBD_HandleTypeDef hUSBD_Device_CDC; -/* Create buffer for reception and transmission */ -/* It's up to user to redefine and/or remove those define */ -extern USBD_HandleTypeDef hUSBD_Device_CDC; /* Received Data over USB are stored in this buffer */ -__IO uint8_t UserRxBuffer[APP_RX_DATA_SIZE]; -__IO uint8_t StackRxBuffer[CDC_MAX_PACKET_SIZE]; - -/* Send Data over USB CDC are stored in this buffer */ -__IO uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; -__IO uint8_t StackTxBuffer[APP_TX_DATA_SIZE]; - -__IO uint32_t UserTxBufPtrIn = 0; /* Increment this pointer or roll it back to - start address when data are received over write call */ -__IO uint32_t UserTxBufPtrOut = 0; /* Increment this pointer or roll it back to - start address when data are sent over USB */ - -__IO uint32_t UserRxBufPtrIn = 0; /* Increment this pointer or roll it back to - start address when data are received over USB */ -__IO uint32_t UserRxBufPtrOut = 0; /* Increment this pointer or roll it back to - start address when data are sent over read call */ - +CDC_TransmitQueue_TypeDef TransmitQueue; +CDC_ReceiveQueue_TypeDef ReceiveQueue; __IO uint32_t lineState = 0; -__IO bool receiveSuspended = false; -__IO bool sendZLP = false; +__IO bool receivePended = false; -stimer_t CDC_TimHandle; /** USBD_CDC Private Function Prototypes */ @@ -66,15 +49,15 @@ static int8_t USBD_CDC_Init (void); static int8_t USBD_CDC_DeInit (void); static int8_t USBD_CDC_Control (uint8_t cmd, uint8_t* pbuf, uint16_t length); static int8_t USBD_CDC_Receive (uint8_t* pbuf, uint32_t *Len); -static void CDC_TIM_Config(void); -void CDC_TIM_PeriodElapsedCallback(stimer_t *htim); +static int8_t USBD_CDC_Transferred (void); USBD_CDC_ItfTypeDef USBD_CDC_fops = { USBD_CDC_Init, USBD_CDC_DeInit, USBD_CDC_Control, - USBD_CDC_Receive + USBD_CDC_Receive, + USBD_CDC_Transferred }; USBD_CDC_LineCodingTypeDef linecoding = @@ -95,12 +78,11 @@ USBD_CDC_LineCodingTypeDef linecoding = */ static int8_t USBD_CDC_Init(void) { - /* Configure and start the TIM Base generation */ - CDC_TIM_Config(); - /* Set Application Buffers */ - USBD_CDC_SetTxBuffer(&hUSBD_Device_CDC, (uint8_t *)UserTxBuffer, 1); - USBD_CDC_SetRxBuffer(&hUSBD_Device_CDC, (uint8_t *)StackRxBuffer); + CDC_TransmitQueue_Init(&TransmitQueue); + CDC_ReceiveQueue_Init(&ReceiveQueue); + receivePended = true; + USBD_CDC_SetRxBuffer(&hUSBD_Device_CDC, CDC_ReceiveQueue_ReserveBlock(&ReceiveQueue)); return (USBD_OK); } @@ -217,155 +199,80 @@ static int8_t USBD_CDC_Control (uint8_t cmd, uint8_t* pbuf, uint16_t length) * @param Len: Number of data received (in bytes) * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL */ -static int8_t USBD_CDC_Receive (uint8_t* Buf, uint32_t *Len) -{ - uint32_t packetSize = *Len; - - if (packetSize > 0) { - if (UserRxBufPtrIn + packetSize > APP_RX_DATA_SIZE) { - memcpy(((uint8_t *)UserRxBuffer + UserRxBufPtrIn), &Buf[0], - (APP_RX_DATA_SIZE - UserRxBufPtrIn)); - memcpy((uint8_t *)UserRxBuffer, - &Buf[(APP_RX_DATA_SIZE - UserRxBufPtrIn)], - (packetSize - (APP_RX_DATA_SIZE - UserRxBufPtrIn))); - UserRxBufPtrIn = ((UserRxBufPtrIn + packetSize) % APP_RX_DATA_SIZE); - } else { - memcpy(((uint8_t *)UserRxBuffer + UserRxBufPtrIn), Buf, packetSize); - UserRxBufPtrIn = ((UserRxBufPtrIn + packetSize) % APP_RX_DATA_SIZE); - } - } - - if ((UserRxBufPtrOut + APP_RX_DATA_SIZE - UserRxBufPtrIn - 1) % - APP_RX_DATA_SIZE + 1 >= CDC_MAX_PACKET_SIZE) { - USBD_CDC_ReceivePacket( - &hUSBD_Device_CDC); // Initiate next USB packet transfer once a packet - // is received and there is enouch space in the - // buffer - } else { - receiveSuspended = true; - } - return (USBD_OK); +static int8_t USBD_CDC_Receive (uint8_t* Buf, uint32_t *Len) { + UNUSED(Buf); + /* It always contains required amount of free space for writing */ + CDC_ReceiveQueue_CommitBlock(&ReceiveQueue, (uint16_t)(*Len)); + receivePended = false; + /* If enough space in the queue for a full buffer then continue receive */ + CDC_resume_receive(); + return USBD_OK; } -void CDC_flush(void) -{ - uint8_t status; - - if(UserTxBufPtrOut != UserTxBufPtrIn) - { - if(UserTxBufPtrOut > UserTxBufPtrIn) /* Roll-back */ - { - memcpy((uint8_t *)&StackTxBuffer[0], - (uint8_t *)&UserTxBuffer[UserTxBufPtrOut], - (APP_TX_DATA_SIZE - UserTxBufPtrOut)); - memcpy((uint8_t *)&StackTxBuffer[APP_TX_DATA_SIZE - UserTxBufPtrOut], - (uint8_t *)&UserTxBuffer[0], UserTxBufPtrIn); - - USBD_CDC_SetTxBuffer( - &hUSBD_Device_CDC, (uint8_t *)&StackTxBuffer[0], - (APP_TX_DATA_SIZE - UserTxBufPtrOut + UserTxBufPtrIn)); - } else { - USBD_CDC_SetTxBuffer(&hUSBD_Device_CDC, - (uint8_t *)&UserTxBuffer[UserTxBufPtrOut], - (UserTxBufPtrIn - UserTxBufPtrOut)); - } - - do { - if (lineState == 0) { // Device disconnected - status = USBD_OK; - } else { - status = USBD_CDC_TransmitPacket(&hUSBD_Device_CDC); - } - } while (status == USBD_BUSY); - if (status == USBD_OK) { - UserTxBufPtrOut = UserTxBufPtrIn; - } - } +static int8_t USBD_CDC_Transferred (void) { + CDC_continue_transmit(); + return (USBD_OK); } -void CDC_resume_receive(void) { - if (receiveSuspended) { - if ((UserRxBufPtrOut + APP_RX_DATA_SIZE - UserRxBufPtrIn - 1) % - APP_RX_DATA_SIZE + 1 >= CDC_MAX_PACKET_SIZE) { - USBD_CDC_ReceivePacket( - &hUSBD_Device_CDC); // Initiate next USB packet transfer once a packet - // is received and there is enouch space in the - // buffer - receiveSuspended = false; +void CDC_init(void) { + /* Init Device Library */ + if (USBD_Init(&hUSBD_Device_CDC, &CDC_Desc, 0) == USBD_OK) { + /* Add Supported Class */ + if (USBD_RegisterClass(&hUSBD_Device_CDC, USBD_CDC_CLASS) == USBD_OK) { + /* Add CDC Interface Class */ + if (USBD_CDC_RegisterInterface(&hUSBD_Device_CDC, &USBD_CDC_fops) == USBD_OK) { + /* Start Device Process */ + USBD_Start(&hUSBD_Device_CDC); + } } } } -void CDC_disable_TIM_Interrupt(void) -{ - HAL_NVIC_DisableIRQ(CDC_TIM_IRQn); -} - -void CDC_enable_TIM_Interrupt(void) -{ - HAL_NVIC_EnableIRQ(CDC_TIM_IRQn); +void CDC_deInit(void) { + USBD_Stop(&hUSBD_Device_CDC); + USBD_CDC_DeInit(); + USBD_DeInit(&hUSBD_Device_CDC); } -static void CDC_TIM_Config(void) -{ - /* Set TIMx instance */ - CDC_TimHandle.timer = CDC_TIM; - /* Initialize CDC_TIM peripheral as follow: - + Period = 10000 - 1 - + Prescaler = ((SystemCoreClock/2)/10000) - 1 - + ClockDivision = 0 - + Counter direction = Up - */ - TimerHandleInit(&CDC_TimHandle, (uint16_t)((CDC_POLLING_INTERVAL*1000) - 1), ((uint32_t)(getTimerClkFreq(CDC_TIM) / (1000000)) - 1)); - HAL_NVIC_SetPriority(CDC_TIM_IRQn, 6, 0); - - attachIntHandle(&CDC_TimHandle, CDC_TIM_PeriodElapsedCallback); -} - -void CDC_TIM_PeriodElapsedCallback(stimer_t *htim) -{ - UNUSED(htim); - if (UserTxBufPtrOut == UserTxBufPtrIn && - sendZLP == false) // Nothing to do, return immediately - return; - - uint8_t status; - uint16_t packetLength; - - if (UserTxBufPtrOut > UserTxBufPtrIn) { /* Roll-back */ - memcpy((uint8_t *)&StackTxBuffer[0], - (uint8_t *)&UserTxBuffer[UserTxBufPtrOut], - (APP_TX_DATA_SIZE - UserTxBufPtrOut)); - memcpy((uint8_t *)&StackTxBuffer[APP_TX_DATA_SIZE - UserTxBufPtrOut], - (uint8_t *)&UserTxBuffer[0], UserTxBufPtrIn); - - packetLength = (APP_TX_DATA_SIZE - UserTxBufPtrOut + UserTxBufPtrIn); - - USBD_CDC_SetTxBuffer(&hUSBD_Device_CDC, (uint8_t *)&StackTxBuffer[0], - packetLength); - } else if (UserTxBufPtrOut != UserTxBufPtrIn) { - packetLength = (UserTxBufPtrIn - UserTxBufPtrOut); - - USBD_CDC_SetTxBuffer(&hUSBD_Device_CDC, - (uint8_t *)&UserTxBuffer[UserTxBufPtrOut], - packetLength); - } else { - packetLength = 0; - - USBD_CDC_SetTxBuffer(&hUSBD_Device_CDC, NULL, 0); // Send Zero Length Packet - } - - if (lineState == 0) { // Device disconnected - status = USBD_OK; - } else { - status = USBD_CDC_TransmitPacket(&hUSBD_Device_CDC); +void CDC_continue_transmit(void) { + uint16_t size; + uint8_t *buffer; + USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *) hUSBD_Device_CDC.pClassData; + /* + * TS: This method can be called both in the main thread + * (via USBSerial::write) and in the IRQ stream (via USBD_CDC_Transferred), + * BUT the main thread cannot pass this condition while waiting for a IRQ! + * This is not possible because TxState is not zero while waiting for data + * transfer ending! The IRQ thread is uninterrupted, since its priority + * is higher than that of the main thread. So this method is thread safe. + */ + if (hcdc->TxState == 0U) { + buffer = CDC_TransmitQueue_ReadBlock(&TransmitQueue, &size); + if (size > 0) { + USBD_CDC_SetTxBuffer(&hUSBD_Device_CDC, buffer, size); + /* + * size never exceed PMA buffer and USBD_CDC_TransmitPacket make full + * copy of block in PMA, so no need to worry about buffer damage + */ + USBD_CDC_TransmitPacket(&hUSBD_Device_CDC); + } } +} - if (status == USBD_OK) { - UserTxBufPtrOut = UserTxBufPtrIn; - - sendZLP = packetLength % CDC_MAX_PACKET_SIZE == 0; +void CDC_resume_receive(void) { + /* + * TS: main and IRQ threads can't pass it at same time, because + * IRQ may occur only if receivePended is true. So it is thread-safe! + */ + if (!receivePended) { + uint8_t* block = CDC_ReceiveQueue_ReserveBlock(&ReceiveQueue); + if (block != NULL) { + receivePended = true; + /* Set new buffer */ + USBD_CDC_SetRxBuffer(&hUSBD_Device_CDC, block); + USBD_CDC_ReceivePacket(&hUSBD_Device_CDC); + } } } diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h index 9956d42e97..4dfcd6601b 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h @@ -30,29 +30,7 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_cdc.h" -#include "timer.h" - -#ifndef APP_RX_DATA_SIZE -#define APP_RX_DATA_SIZE 2048 -#endif -#ifndef APP_TX_DATA_SIZE -#define APP_TX_DATA_SIZE 2048 -#endif - -#ifndef CDC_TIM -#ifdef TIM6 -#define CDC_TIM TIM6 -#else -#define CDC_TIM TIM4 -#endif -#endif -#ifndef CDC_TIM_IRQn -#ifdef TIM6 -#define CDC_TIM_IRQn TIM6_IRQn -#else -#define CDC_TIM_IRQn TIM4_IRQn -#endif -#endif +#include "cdc_queue.h" /* Periodically, the state of the buffer "UserTxBuffer" is checked. The period depends on CDC_POLLING_INTERVAL */ @@ -62,13 +40,16 @@ /* Exported constants --------------------------------------------------------*/ extern USBD_CDC_ItfTypeDef USBD_CDC_fops; +extern CDC_TransmitQueue_TypeDef TransmitQueue; +extern CDC_ReceiveQueue_TypeDef ReceiveQueue; + /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ -void CDC_disable_TIM_Interrupt(void); -void CDC_enable_TIM_Interrupt(void); -void CDC_flush(void); +void CDC_continue_transmit(void); void CDC_resume_receive(void); +void CDC_init(void); +void CDC_deInit(void); #ifdef __cplusplus } diff --git a/cores/arduino/stm32/usbd_interface.c b/cores/arduino/stm32/usbd_interface.c index 57ae34b4f9..78003e197e 100644 --- a/cores/arduino/stm32/usbd_interface.c +++ b/cores/arduino/stm32/usbd_interface.c @@ -50,9 +50,6 @@ #ifdef USBD_USE_HID_COMPOSITE USBD_HandleTypeDef hUSBD_Device_HID; #endif /* USBD_USE_HID_COMPOSITE*/ -#ifdef USBD_USE_CDC -USBD_HandleTypeDef hUSBD_Device_CDC; -#endif /* USBD_USE_CDC */ /** * @brief initialize USB devices @@ -72,21 +69,6 @@ void usbd_interface_init(void) /* Start Device Process */ USBD_Start(&hUSBD_Device_HID); #endif /* USBD_USE_HID_COMPOSITE */ -#ifdef USBD_USE_CDC - /* Init Device Library */ - if (USBD_Init(&hUSBD_Device_CDC, &CDC_Desc, 0) == USBD_OK) { - - /* Add Supported Class */ - if (USBD_RegisterClass(&hUSBD_Device_CDC, USBD_CDC_CLASS) == USBD_OK) { - - /* Add CDC Interface Class */ - if (USBD_CDC_RegisterInterface(&hUSBD_Device_CDC, &USBD_CDC_fops) == USBD_OK) { - /* Start Device Process */ - USBD_Start(&hUSBD_Device_CDC); - } - } - } -#endif /* USBD_USE_CDC */ } #ifdef USBD_USE_HID_COMPOSITE From ef97030a49d5eab3532ac4e1a50623af8a3b159e Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Fri, 18 Jan 2019 15:23:53 +0100 Subject: [PATCH 04/12] [USB HID] Clean HID composite interface Signed-off-by: Frederic.Pillon --- cores/arduino/board.h | 1 - cores/arduino/main.cpp | 4 -- .../hid/usbd_hid_composite_if.c} | 45 ++++++++++--------- .../hid/usbd_hid_composite_if.h} | 25 +++++------ libraries/Keyboard/library.properties | 2 +- libraries/Keyboard/src/Keyboard.cpp | 5 ++- libraries/Mouse/library.properties | 2 +- libraries/Mouse/src/Mouse.cpp | 5 ++- 8 files changed, 46 insertions(+), 43 deletions(-) rename cores/arduino/stm32/{usbd_interface.c => usb/hid/usbd_hid_composite_if.c} (82%) rename cores/arduino/stm32/{usbd_interface.h => usb/hid/usbd_hid_composite_if.h} (77%) diff --git a/cores/arduino/board.h b/cores/arduino/board.h index e88a237543..4bccf613c1 100644 --- a/cores/arduino/board.h +++ b/cores/arduino/board.h @@ -20,7 +20,6 @@ extern "C"{ #include "timer.h" #include "twi.h" #include "uart.h" -#include "usbd_interface.h" void init( void ) ; #ifdef __cplusplus diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index 741f041d0a..b67ac74b2c 100644 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -54,10 +54,6 @@ int main( void ) { initVariant(); -#if defined(USBCON) - usbd_interface_init(); -#endif - setup(); for (;;) diff --git a/cores/arduino/stm32/usbd_interface.c b/cores/arduino/stm32/usb/hid/usbd_hid_composite_if.c similarity index 82% rename from cores/arduino/stm32/usbd_interface.c rename to cores/arduino/stm32/usb/hid/usbd_hid_composite_if.c index 78003e197e..a87317325b 100644 --- a/cores/arduino/stm32/usbd_interface.c +++ b/cores/arduino/stm32/usb/hid/usbd_hid_composite_if.c @@ -1,7 +1,7 @@ /** ****************************************************************************** - * @file usbd_interface.c - * @brief Provide the USB device interface + * @file usbd_hid_composite_if.c + * @brief Provide the USB HID composite interface * ****************************************************************************** * @attention @@ -33,33 +33,26 @@ ****************************************************************************** */ #ifdef USBCON -#include "usbd_desc.h" -#include "usbd_interface.h" #ifdef USBD_USE_HID_COMPOSITE + +#include "usbd_desc.h" +#include "usbd_hid_composite_if.h" #include "usbd_hid_composite.h" -#endif -#ifdef USBD_USE_CDC -#include "usbd_cdc_if.h" -#endif #ifdef __cplusplus extern "C" { #endif -/* USB Device Core handle declaration */ -#ifdef USBD_USE_HID_COMPOSITE +/* USB Device Core HID composite handle declaration */ USBD_HandleTypeDef hUSBD_Device_HID; -#endif /* USBD_USE_HID_COMPOSITE*/ /** - * @brief initialize USB devices + * @brief Initialize USB devices * @param none * @retval none */ -__attribute__((weak)) -void usbd_interface_init(void) +void HID_Composite_Init(void) { -#ifdef USBD_USE_HID_COMPOSITE /* Init Device Library */ USBD_Init(&hUSBD_Device_HID, &HID_Desc, 0); @@ -68,17 +61,29 @@ void usbd_interface_init(void) /* Start Device Process */ USBD_Start(&hUSBD_Device_HID); -#endif /* USBD_USE_HID_COMPOSITE */ } -#ifdef USBD_USE_HID_COMPOSITE +/** + * @brief DeInitialize USB devices + * @param none + * @retval none + */ +void HID_Composite_DeInit(void) +{ + /* Stop Device Process */ + USBD_Stop(&hUSBD_Device_HID); + + /* DeInit Device Library */ + USBD_DeInit(&hUSBD_Device_HID); +} + /** * @brief Send HID mouse Report * @param report pointer to report * @param len report lenght * @retval none */ -void usbd_interface_mouse_sendReport(uint8_t *report, uint16_t len) +void HID_Composite_mouse_sendReport(uint8_t *report, uint16_t len) { USBD_HID_MOUSE_SendReport(&hUSBD_Device_HID, report, len); } @@ -89,14 +94,14 @@ void usbd_interface_mouse_sendReport(uint8_t *report, uint16_t len) * @param len report lenght * @retval none */ -void usbd_interface_keyboard_sendReport(uint8_t *report, uint16_t len) +void HID_Composite_keyboard_sendReport(uint8_t *report, uint16_t len) { USBD_HID_KEYBOARD_SendReport(&hUSBD_Device_HID, report, len); } -#endif /* USBD_USE_HID_COMPOSITE */ #ifdef __cplusplus } #endif +#endif /* USBD_USE_HID_COMPOSITE */ #endif /* USBCON */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/cores/arduino/stm32/usbd_interface.h b/cores/arduino/stm32/usb/hid/usbd_hid_composite_if.h similarity index 77% rename from cores/arduino/stm32/usbd_interface.h rename to cores/arduino/stm32/usb/hid/usbd_hid_composite_if.h index f32f184938..5c61b12bc5 100644 --- a/cores/arduino/stm32/usbd_interface.h +++ b/cores/arduino/stm32/usb/hid/usbd_hid_composite_if.h @@ -1,7 +1,7 @@ /** ****************************************************************************** - * @file usbd_interface.h - * @brief Header for USB device interface + * @file usbd_hid_composite_if.h + * @brief Header for USB HID composite interface ****************************************************************************** * @attention * @@ -33,32 +33,29 @@ */ /* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USBD_INTERFACE_H -#define __USBD_INTERFACE_H +#ifndef __USBD_HID_COMPOSITE_IF_H +#define __USBD_HID_COMPOSITE_IF_H #ifdef USBCON +#ifdef USBD_USE_HID_COMPOSITE /* Includes ------------------------------------------------------------------*/ #ifdef __cplusplus extern "C" { #endif -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported variables --------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ -void usbd_interface_init(void); +void HID_Composite_Init(void); +void HID_Composite_DeInit(void); -#ifdef USBD_USE_HID_COMPOSITE -void usbd_interface_mouse_sendReport(uint8_t *report, uint16_t len); -void usbd_interface_keyboard_sendReport(uint8_t *report, uint16_t len); -#endif +void HID_Composite_mouse_sendReport(uint8_t *report, uint16_t len); +void HID_Composite_keyboard_sendReport(uint8_t *report, uint16_t len); #ifdef __cplusplus } #endif +#endif /* USBD_USE_HID_COMPOSITE */ #endif /* USBCON */ -#endif /* __USBD_INTERFACE_H */ +#endif /* __USBD_HID_COMPOSITE_IF_H */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/Keyboard/library.properties b/libraries/Keyboard/library.properties index e220811d16..64a98c432a 100644 --- a/libraries/Keyboard/library.properties +++ b/libraries/Keyboard/library.properties @@ -1,5 +1,5 @@ name=Keyboard -version=1.0.1 +version=1.1.0 author=Arduino maintainer=Arduino sentence=Allows an Arduino/Genuino board with USB capabilites to act as a Keyboard. diff --git a/libraries/Keyboard/src/Keyboard.cpp b/libraries/Keyboard/src/Keyboard.cpp index a8d8ca6a41..dab08a39c3 100644 --- a/libraries/Keyboard/src/Keyboard.cpp +++ b/libraries/Keyboard/src/Keyboard.cpp @@ -22,6 +22,7 @@ #include "Keyboard.h" #if defined(USBCON) +#include "usbd_hid_composite_if.h" //================================================================================ //================================================================================ @@ -33,10 +34,12 @@ Keyboard_::Keyboard_(void) void Keyboard_::begin(void) { + HID_Composite_Init(); } void Keyboard_::end(void) { + HID_Composite_DeInit(); } void Keyboard_::sendReport(KeyReport* keys) @@ -44,7 +47,7 @@ void Keyboard_::sendReport(KeyReport* keys) uint8_t buf[8] = {keys->modifiers, keys->reserved, keys->keys[0], keys->keys[1], keys->keys[2], keys->keys[3], keys->keys[4], keys->keys[5]}; - usbd_interface_keyboard_sendReport(buf, 8); + HID_Composite_keyboard_sendReport(buf, 8); //delay required to prevent persistent key when call print delay(20); diff --git a/libraries/Mouse/library.properties b/libraries/Mouse/library.properties index c4a095caa5..8c48029eb0 100644 --- a/libraries/Mouse/library.properties +++ b/libraries/Mouse/library.properties @@ -1,5 +1,5 @@ name=Mouse -version=1.0.0 +version=1.1.0 author=Arduino maintainer=Arduino sentence=Allows an Arduino board with USB capabilites to act as a Mouse. For Leonardo/Micro only diff --git a/libraries/Mouse/src/Mouse.cpp b/libraries/Mouse/src/Mouse.cpp index a6b4cdd633..a6529b053e 100644 --- a/libraries/Mouse/src/Mouse.cpp +++ b/libraries/Mouse/src/Mouse.cpp @@ -22,6 +22,7 @@ #include "Mouse.h" #if defined(USBCON) +#include "usbd_hid_composite_if.h" //================================================================================ //================================================================================ @@ -33,10 +34,12 @@ Mouse_::Mouse_(void) : _buttons(0) void Mouse_::begin(void) { + HID_Composite_Init(); } void Mouse_::end(void) { + HID_Composite_DeInit(); } void Mouse_::click(uint8_t b) @@ -55,7 +58,7 @@ void Mouse_::move(signed char x, signed char y, signed char wheel) m[2] = y; m[3] = wheel; - usbd_interface_mouse_sendReport(m, 4); + HID_Composite_mouse_sendReport(m, 4); } void Mouse_::buttons(uint8_t b) From fb65a1e195854fc0dfbc3957b1d331345357073c Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Sun, 27 Jan 2019 01:41:55 +0300 Subject: [PATCH 05/12] [USB CDC] Fixed receiving data error. --- cores/arduino/stm32/usb/cdc/cdc_queue.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c index 44e0b1c2bf..12a97ea4e0 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -97,10 +97,11 @@ void CDC_ReceiveQueue_Init(CDC_ReceiveQueue_TypeDef *queue) { // Reserve block in queue and return pointer to it. uint8_t *CDC_ReceiveQueue_ReserveBlock(CDC_ReceiveQueue_TypeDef *queue) { - if ((uint16_t)(CDC_RECEIVE_QUEUE_BUFFER_SIZE - queue->write) >= CDC_QUEUE_MAX_PACKET_SIZE) { + if ((uint16_t)(CDC_RECEIVE_QUEUE_BUFFER_SIZE - queue->write) >= CDC_QUEUE_MAX_PACKET_SIZE && + (queue->read <= queue->write || (uint16_t)(queue->read - queue->write) >= CDC_QUEUE_MAX_PACKET_SIZE)) { // have enough space on the rest of buffer to store full-length packet return &queue->buffer[queue->write]; - } else if (queue->read >= CDC_QUEUE_MAX_PACKET_SIZE) { + } else if (queue->read >= CDC_QUEUE_MAX_PACKET_SIZE && queue->read <= queue->write) { // have enough space on the beginning of buffer to store full-length packet queue->length = queue->write; queue->write = 0; @@ -114,6 +115,9 @@ uint8_t *CDC_ReceiveQueue_ReserveBlock(CDC_ReceiveQueue_TypeDef *queue) { // Commits block in queue and make it available for reading void CDC_ReceiveQueue_CommitBlock(CDC_ReceiveQueue_TypeDef *queue, uint16_t size) { queue->write += size; + if (queue->write >= queue->length) { + queue->length = CDC_RECEIVE_QUEUE_BUFFER_SIZE; + } } // Determine size, available for read @@ -121,7 +125,7 @@ int CDC_ReceiveQueue_ReadSize(CDC_ReceiveQueue_TypeDef *queue) { if (queue->write >= queue->read) { return queue->write - queue->read; } else { - return queue->length - queue->read; + return queue->length + queue->write - queue->read; } } From 28bf4ac3500aaf1cc8b0e09f6e8dd3d3eccc6c53 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Sun, 27 Jan 2019 13:44:14 +0300 Subject: [PATCH 06/12] [USB CDC] Fixed possible transmitting error --- cores/arduino/stm32/usb/cdc/cdc_queue.c | 14 ++++++-------- cores/arduino/stm32/usb/cdc/cdc_queue.h | 4 +++- cores/arduino/stm32/usb/cdc/usbd_cdc_if.c | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c index 12a97ea4e0..b0f1112a41 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -73,19 +73,17 @@ void CDC_TransmitQueue_Enqueue(CDC_TransmitQueue_TypeDef *queue, const uint8_t * // Read flat block from queue (biggest as possible, but max CDC_QUEUE_MAX_PACKET_SIZE). uint8_t *CDC_TransmitQueue_ReadBlock(CDC_TransmitQueue_TypeDef *queue, uint16_t *size) { - uint16_t readPos = queue->read; if (queue->write >= queue->read) { *size = queue->write - queue->read; - queue->read = queue->write; - } else if ((uint16_t)(CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->read) > CDC_QUEUE_MAX_PACKET_SIZE) { - // limit to max packet size - *size = CDC_QUEUE_MAX_PACKET_SIZE; - queue->read += CDC_QUEUE_MAX_PACKET_SIZE; } else { *size = CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->read; - queue->read = 0; } - return &queue->buffer[readPos]; + queue->reserved = *size; + return &queue->buffer[queue->read]; +} + +void CDC_TransmitQueue_CommitRead(CDC_TransmitQueue_TypeDef *queue) { + queue->read = (queue->read + queue->reserved) % CDC_TRANSMIT_QUEUE_BUFFER_SIZE; } // Initialize read and write position of queue. diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.h b/cores/arduino/stm32/usb/cdc/cdc_queue.h index f2a87e9fcb..d0d2f21f3c 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.h +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -52,13 +52,14 @@ #else #define CDC_QUEUE_MAX_PACKET_SIZE USB_FS_MAX_PACKET_SIZE #endif -#define CDC_TRANSMIT_QUEUE_BUFFER_SIZE ((uint16_t)(CDC_QUEUE_MAX_PACKET_SIZE)) +#define CDC_TRANSMIT_QUEUE_BUFFER_SIZE ((uint16_t)(CDC_QUEUE_MAX_PACKET_SIZE * 2)) #define CDC_RECEIVE_QUEUE_BUFFER_SIZE ((uint16_t)(CDC_QUEUE_MAX_PACKET_SIZE * 2)) typedef struct { uint8_t buffer[CDC_TRANSMIT_QUEUE_BUFFER_SIZE]; volatile uint16_t write; volatile uint16_t read; + volatile uint16_t reserved; } CDC_TransmitQueue_TypeDef; typedef struct { @@ -73,6 +74,7 @@ int CDC_TransmitQueue_WriteSize(CDC_TransmitQueue_TypeDef* queue); int CDC_TransmitQueue_ReadSize(CDC_TransmitQueue_TypeDef* queue); void CDC_TransmitQueue_Enqueue(CDC_TransmitQueue_TypeDef* queue, const uint8_t* buffer, uint32_t size); uint8_t* CDC_TransmitQueue_ReadBlock(CDC_TransmitQueue_TypeDef* queue, uint16_t* size); +void CDC_TransmitQueue_CommitRead(CDC_TransmitQueue_TypeDef *queue); void CDC_ReceiveQueue_Init(CDC_ReceiveQueue_TypeDef* queue); int CDC_ReceiveQueue_ReadSize(CDC_ReceiveQueue_TypeDef* queue); diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c index e34a7b0b49..c5749a8bc1 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c @@ -211,6 +211,7 @@ static int8_t USBD_CDC_Receive (uint8_t* Buf, uint32_t *Len) { static int8_t USBD_CDC_Transferred (void) { + CDC_TransmitQueue_CommitRead(&TransmitQueue); CDC_continue_transmit(); return (USBD_OK); } From fded1e40b4f1164edc695b1a5105d47ce70d6969 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Tue, 29 Jan 2019 15:55:43 +0300 Subject: [PATCH 07/12] [USB CDC] Some speed improvements Added bulk read method readBytes and improved read and peek methods. --- cores/arduino/Stream.h | 2 +- cores/arduino/USBSerial.cpp | 21 +++++++++++---------- cores/arduino/USBSerial.h | 1 + cores/arduino/stm32/usb/cdc/cdc_queue.c | 21 +++++++++++++++++++-- cores/arduino/stm32/usb/cdc/cdc_queue.h | 5 +++-- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/cores/arduino/Stream.h b/cores/arduino/Stream.h index bd5311b84a..cc554bbd68 100644 --- a/cores/arduino/Stream.h +++ b/cores/arduino/Stream.h @@ -94,7 +94,7 @@ class Stream : public Print float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); // float version of parseInt - size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer + virtual size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } // terminates if length characters have been read or timeout (see setTimeout) // returns the number of characters placed in the buffer (0 means no valid data found) diff --git a/cores/arduino/USBSerial.cpp b/cores/arduino/USBSerial.cpp index 51eda7f76c..2f7bdfb561 100644 --- a/cores/arduino/USBSerial.cpp +++ b/cores/arduino/USBSerial.cpp @@ -24,7 +24,6 @@ #include "usbd_desc.h" #include "wiring.h" -#define USB_TIMEOUT 50 /* USB Device Core handle declaration */ extern USBD_HandleTypeDef hUSBD_Device_CDC; extern __IO uint32_t lineState; @@ -91,24 +90,26 @@ int USBSerial::available(void) { } int USBSerial::read(void) { - // Empty ReceiveQueue - nothing to return - if (CDC_ReceiveQueue_ReadSize(&ReceiveQueue) <= 0) { - return -1; - } // Dequeue only one char from queue // TS: it safe, because only main thread affects ReceiveQueue->read pos - char ch = CDC_ReceiveQueue_Dequeue(&ReceiveQueue); + auto ch = CDC_ReceiveQueue_Dequeue(&ReceiveQueue); // Resume receive process, if possible CDC_resume_receive(); return ch; } +size_t USBSerial::readBytes(char *buffer, size_t length) { + auto rest = static_cast(length); + _startMillis = millis(); + do { + rest -= CDC_ReceiveQueue_Read(&ReceiveQueue, reinterpret_cast(buffer), rest); + if (rest == 0) return length; + } while(millis() - _startMillis < _timeout); + return length - rest; +} + int USBSerial::peek(void) { - // Empty ReceiveQueue - nothing to return - if (CDC_ReceiveQueue_ReadSize(&ReceiveQueue) <= 0) { - return -1; - } // Peek one symbol, it can't change receive avaiablity return CDC_ReceiveQueue_Peek(&ReceiveQueue); } diff --git a/cores/arduino/USBSerial.h b/cores/arduino/USBSerial.h index 331e65340f..76440d7841 100644 --- a/cores/arduino/USBSerial.h +++ b/cores/arduino/USBSerial.h @@ -36,6 +36,7 @@ class USBSerial : public Stream { virtual int availableForWrite(void); virtual int peek(void); virtual int read(void); + virtual size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer virtual void flush(void); virtual size_t write(uint8_t); virtual size_t write(const uint8_t *buffer, size_t size); diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c index b0f1112a41..4abefe43e0 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -128,7 +128,8 @@ int CDC_ReceiveQueue_ReadSize(CDC_ReceiveQueue_TypeDef *queue) { } // Read one byte from queue. -uint8_t CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef *queue) { +int CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef *queue) { + if (queue->write == queue->read) return -1; uint8_t ch = queue->buffer[queue->read++]; if (queue->read >= queue->length) { queue->read = 0; @@ -137,9 +138,25 @@ uint8_t CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef *queue) { } // Peek byte from queue. -uint8_t CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef *queue) { +int CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef *queue) { + if (queue->write == queue->read) return -1; return queue->buffer[queue->read]; } +uint16_t CDC_ReceiveQueue_Read(CDC_ReceiveQueue_TypeDef *queue, uint8_t *buffer, uint16_t size) { + volatile uint16_t write = queue->write; + uint16_t available; + if (write >= queue->read) { + available = write - queue->read; + } else { + available = CDC_RECEIVE_QUEUE_BUFFER_SIZE - queue->read; + } + if (available < size) { + size = available; + } + memcpy(buffer, &queue->buffer[queue->read], size); + queue->read = (queue->read + size) % CDC_RECEIVE_QUEUE_BUFFER_SIZE; + return size; +} #endif /* USBD_USE_CDC */ #endif /* USBCON */ diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.h b/cores/arduino/stm32/usb/cdc/cdc_queue.h index d0d2f21f3c..262ade9112 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.h +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -78,8 +78,9 @@ void CDC_TransmitQueue_CommitRead(CDC_TransmitQueue_TypeDef *queue); void CDC_ReceiveQueue_Init(CDC_ReceiveQueue_TypeDef* queue); int CDC_ReceiveQueue_ReadSize(CDC_ReceiveQueue_TypeDef* queue); -uint8_t CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef* queue); -uint8_t CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef* queue); +int CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef* queue); +int CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef* queue); +uint16_t CDC_ReceiveQueue_Read(CDC_ReceiveQueue_TypeDef* queue, uint8_t* buffer, uint16_t size); uint8_t* CDC_ReceiveQueue_ReserveBlock(CDC_ReceiveQueue_TypeDef* queue); void CDC_ReceiveQueue_CommitBlock(CDC_ReceiveQueue_TypeDef* queue, uint16_t size); From 24a701912bf77538225704238967596d1a33f22e Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Tue, 29 Jan 2019 23:46:12 +0300 Subject: [PATCH 08/12] [USB CDC] Bulk read fixed, added bulk read until --- cores/arduino/Stream.h | 2 +- cores/arduino/USBSerial.cpp | 26 +++++++++- cores/arduino/USBSerial.h | 1 + cores/arduino/stm32/usb/cdc/cdc_queue.c | 59 ++++++++++++++++++++++- cores/arduino/stm32/usb/cdc/cdc_queue.h | 2 + cores/arduino/stm32/usb/cdc/usbd_cdc_if.c | 2 +- 6 files changed, 87 insertions(+), 5 deletions(-) diff --git a/cores/arduino/Stream.h b/cores/arduino/Stream.h index cc554bbd68..db3dbe48d7 100644 --- a/cores/arduino/Stream.h +++ b/cores/arduino/Stream.h @@ -99,7 +99,7 @@ class Stream : public Print // terminates if length characters have been read or timeout (see setTimeout) // returns the number of characters placed in the buffer (0 means no valid data found) - size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character + virtual size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character size_t readBytesUntil( char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); } // terminates if length characters have been read, timeout, or if the terminator character detected // returns the number of characters placed in the buffer (0 means no valid data found) diff --git a/cores/arduino/USBSerial.cpp b/cores/arduino/USBSerial.cpp index 2f7bdfb561..091a29879d 100644 --- a/cores/arduino/USBSerial.cpp +++ b/cores/arduino/USBSerial.cpp @@ -99,15 +99,39 @@ int USBSerial::read(void) { } size_t USBSerial::readBytes(char *buffer, size_t length) { + uint16_t read; auto rest = static_cast(length); _startMillis = millis(); do { - rest -= CDC_ReceiveQueue_Read(&ReceiveQueue, reinterpret_cast(buffer), rest); + read = CDC_ReceiveQueue_Read(&ReceiveQueue, reinterpret_cast(buffer), rest); + CDC_resume_receive(); + rest -= read; + buffer += read; if (rest == 0) return length; } while(millis() - _startMillis < _timeout); return length - rest; } +size_t USBSerial::readBytesUntil(char terminator, char *buffer, size_t length) { + uint16_t read; + auto rest = static_cast(length); + _startMillis = millis(); + do { + bool found = CDC_ReceiveQueue_ReadUntil(&ReceiveQueue, static_cast(terminator), + reinterpret_cast(buffer), rest, &read); + CDC_resume_receive(); + rest -= read; + buffer += read; + if (found) { + return length - rest; + } + if (rest == 0) { + return length; + } + } while(millis() - _startMillis < _timeout); + return length - rest; +} + int USBSerial::peek(void) { // Peek one symbol, it can't change receive avaiablity diff --git a/cores/arduino/USBSerial.h b/cores/arduino/USBSerial.h index 76440d7841..0667c3a294 100644 --- a/cores/arduino/USBSerial.h +++ b/cores/arduino/USBSerial.h @@ -37,6 +37,7 @@ class USBSerial : public Stream { virtual int peek(void); virtual int read(void); virtual size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer + virtual size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character virtual void flush(void); virtual size_t write(uint8_t); virtual size_t write(const uint8_t *buffer, size_t size); diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c index 4abefe43e0..42c2b62c1a 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -116,6 +116,9 @@ void CDC_ReceiveQueue_CommitBlock(CDC_ReceiveQueue_TypeDef *queue, uint16_t size if (queue->write >= queue->length) { queue->length = CDC_RECEIVE_QUEUE_BUFFER_SIZE; } + if (queue->write >= CDC_RECEIVE_QUEUE_BUFFER_SIZE) { + queue->write = 0; + } } // Determine size, available for read @@ -145,18 +148,70 @@ int CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef *queue) { uint16_t CDC_ReceiveQueue_Read(CDC_ReceiveQueue_TypeDef *queue, uint8_t *buffer, uint16_t size) { volatile uint16_t write = queue->write; + volatile uint16_t length = queue->length; uint16_t available; + while(write != queue->write || length != queue->length) { + write = queue->write; + length = queue->length; + } + if (write >= queue->read) { available = write - queue->read; } else { - available = CDC_RECEIVE_QUEUE_BUFFER_SIZE - queue->read; + available = length - queue->read; } if (available < size) { size = available; } + memcpy(buffer, &queue->buffer[queue->read], size); - queue->read = (queue->read + size) % CDC_RECEIVE_QUEUE_BUFFER_SIZE; + queue->read = queue->read + size; + if (queue->read >= length) { + queue->read = 0; + } return size; } + +bool CDC_ReceiveQueue_ReadUntil(CDC_ReceiveQueue_TypeDef *queue, uint8_t terminator, uint8_t *buffer, + uint16_t size, uint16_t* fetched) { + volatile uint16_t write = queue->write; + volatile uint16_t length = queue->length; + uint16_t available; + while(write != queue->write || length != queue->length) { + write = queue->write; + length = queue->length; + } + + if (write >= queue->read) { + available = write - queue->read; + } else { + available = length - queue->read; + } + if (available < size) { + size = available; + } + + uint8_t* start = &queue->buffer[queue->read]; + for(uint16_t i = 0; i < size; i++) { + uint8_t ch = start[i]; + if (ch == terminator) { + queue->read += (uint16_t)(i + 1); + if (queue->read >= length) { + queue->read = 0; + } + *fetched = i; + return true; + } else { + buffer[i] = ch; + } + } + + *fetched = size; + queue->read += size; + if (queue->read >= length) { + queue->read = 0; + } + return false; +} #endif /* USBD_USE_CDC */ #endif /* USBCON */ diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.h b/cores/arduino/stm32/usb/cdc/cdc_queue.h index 262ade9112..d680c00b89 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.h +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -81,6 +81,8 @@ int CDC_ReceiveQueue_ReadSize(CDC_ReceiveQueue_TypeDef* queue); int CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef* queue); int CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef* queue); uint16_t CDC_ReceiveQueue_Read(CDC_ReceiveQueue_TypeDef* queue, uint8_t* buffer, uint16_t size); +bool CDC_ReceiveQueue_ReadUntil(CDC_ReceiveQueue_TypeDef* queue, uint8_t terminator, uint8_t* buffer, + uint16_t size, uint16_t* fetched); uint8_t* CDC_ReceiveQueue_ReserveBlock(CDC_ReceiveQueue_TypeDef* queue); void CDC_ReceiveQueue_CommitBlock(CDC_ReceiveQueue_TypeDef* queue, uint16_t size); diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c index c5749a8bc1..a1c1ab0f0f 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c @@ -40,7 +40,7 @@ USBD_HandleTypeDef hUSBD_Device_CDC; CDC_TransmitQueue_TypeDef TransmitQueue; CDC_ReceiveQueue_TypeDef ReceiveQueue; __IO uint32_t lineState = 0; -__IO bool receivePended = false; +__IO bool receivePended = true; /** USBD_CDC Private Function Prototypes */ From a81910e32e2e5b3b3124dac8445febe4dda5ccbc Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Wed, 30 Jan 2019 23:23:36 +0300 Subject: [PATCH 09/12] [USB CDC] Set of fixes for queue --- cores/arduino/stm32/usb/cdc/cdc_queue.c | 91 +++++++++++++++---------- cores/arduino/stm32/usb/cdc/cdc_queue.h | 2 +- 2 files changed, 55 insertions(+), 38 deletions(-) diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c index 42c2b62c1a..15de13735a 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -59,8 +59,8 @@ int CDC_TransmitQueue_ReadSize(CDC_TransmitQueue_TypeDef *queue) { } // Write provided data into queue. -void CDC_TransmitQueue_Enqueue(CDC_TransmitQueue_TypeDef *queue, const uint8_t *buffer, - uint32_t size) { +void CDC_TransmitQueue_Enqueue(CDC_TransmitQueue_TypeDef *queue, + const uint8_t *buffer, uint32_t size) { uint32_t sizeToEnd = CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->write; if (sizeToEnd > size) { memcpy(&queue->buffer[queue->write], &buffer[0], size); @@ -68,11 +68,13 @@ void CDC_TransmitQueue_Enqueue(CDC_TransmitQueue_TypeDef *queue, const uint8_t * memcpy(&queue->buffer[queue->write], &buffer[0], sizeToEnd); memcpy(&queue->buffer[0], &buffer[sizeToEnd], size - sizeToEnd); } - queue->write = (uint16_t)((queue->write + size) % CDC_TRANSMIT_QUEUE_BUFFER_SIZE); + queue->write = (uint16_t)((queue->write + size) % + CDC_TRANSMIT_QUEUE_BUFFER_SIZE); } -// Read flat block from queue (biggest as possible, but max CDC_QUEUE_MAX_PACKET_SIZE). -uint8_t *CDC_TransmitQueue_ReadBlock(CDC_TransmitQueue_TypeDef *queue, uint16_t *size) { +// Read flat block from queue biggest as possible, but max QUEUE_MAX_PACKET_SIZE +uint8_t *CDC_TransmitQueue_ReadBlock(CDC_TransmitQueue_TypeDef *queue, + uint16_t *size) { if (queue->write >= queue->read) { *size = queue->write - queue->read; } else { @@ -83,7 +85,8 @@ uint8_t *CDC_TransmitQueue_ReadBlock(CDC_TransmitQueue_TypeDef *queue, uint16_t } void CDC_TransmitQueue_CommitRead(CDC_TransmitQueue_TypeDef *queue) { - queue->read = (queue->read + queue->reserved) % CDC_TRANSMIT_QUEUE_BUFFER_SIZE; + queue->read = (queue->read + queue->reserved) % + CDC_TRANSMIT_QUEUE_BUFFER_SIZE; } // Initialize read and write position of queue. @@ -95,23 +98,33 @@ void CDC_ReceiveQueue_Init(CDC_ReceiveQueue_TypeDef *queue) { // Reserve block in queue and return pointer to it. uint8_t *CDC_ReceiveQueue_ReserveBlock(CDC_ReceiveQueue_TypeDef *queue) { - if ((uint16_t)(CDC_RECEIVE_QUEUE_BUFFER_SIZE - queue->write) >= CDC_QUEUE_MAX_PACKET_SIZE && - (queue->read <= queue->write || (uint16_t)(queue->read - queue->write) >= CDC_QUEUE_MAX_PACKET_SIZE)) { - // have enough space on the rest of buffer to store full-length packet - return &queue->buffer[queue->write]; - } else if (queue->read >= CDC_QUEUE_MAX_PACKET_SIZE && queue->read <= queue->write) { - // have enough space on the beginning of buffer to store full-length packet - queue->length = queue->write; - queue->write = 0; - return &queue->buffer[queue->write]; - } else { - // have no space to store full-length packet - return 0; + const uint16_t limit = + CDC_RECEIVE_QUEUE_BUFFER_SIZE - CDC_QUEUE_MAX_PACKET_SIZE; + volatile uint16_t read = queue->read; + + if (read <= queue->write) { + // if write is limited only by buffer size. + if (queue->write < limit || (queue->write == limit && read > 0)) { + // if size in the rest of buffer is enough for full packet plus 1 byte + // or if it tight enough and write position can be set to 0 + return queue->buffer + queue->write; + } else if (read > CDC_QUEUE_MAX_PACKET_SIZE) { + // if size in the rest is not enough, but enough size in head + queue->length = queue->write; + queue->write = 0; + return queue->buffer + queue->write; + } + } else if (queue->write + CDC_QUEUE_MAX_PACKET_SIZE < read) { + // write position must be less than read position + // after reading largest possible packet + return queue->buffer + queue->write; } + return 0; } // Commits block in queue and make it available for reading -void CDC_ReceiveQueue_CommitBlock(CDC_ReceiveQueue_TypeDef *queue, uint16_t size) { +void CDC_ReceiveQueue_CommitBlock(CDC_ReceiveQueue_TypeDef *queue, + uint16_t size) { queue->write += size; if (queue->write >= queue->length) { queue->length = CDC_RECEIVE_QUEUE_BUFFER_SIZE; @@ -123,18 +136,24 @@ void CDC_ReceiveQueue_CommitBlock(CDC_ReceiveQueue_TypeDef *queue, uint16_t size // Determine size, available for read int CDC_ReceiveQueue_ReadSize(CDC_ReceiveQueue_TypeDef *queue) { - if (queue->write >= queue->read) { - return queue->write - queue->read; - } else { - return queue->length + queue->write - queue->read; + // reading length after write make guarantee, that length >= write + // and determined reading size will be smaller or equal than real one. + volatile uint16_t write = queue->write; + volatile uint16_t length = queue->length; + if (write >= queue->read) { + return write - queue->read; } + return length + write - queue->read; } // Read one byte from queue. int CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef *queue) { - if (queue->write == queue->read) return -1; + volatile uint16_t write = queue->write; + volatile uint16_t length = queue->length; + if (queue->read == length) queue->read = 0; + if (write == queue->read) return -1; uint8_t ch = queue->buffer[queue->read++]; - if (queue->read >= queue->length) { + if (queue->read >= length) { queue->read = 0; } return ch; @@ -142,19 +161,20 @@ int CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef *queue) { // Peek byte from queue. int CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef *queue) { - if (queue->write == queue->read) return -1; + volatile uint16_t write = queue->write; + volatile uint16_t length = queue->length; + if (queue->read >= length) queue->read = 0; + if (write == queue->read) return -1; return queue->buffer[queue->read]; } -uint16_t CDC_ReceiveQueue_Read(CDC_ReceiveQueue_TypeDef *queue, uint8_t *buffer, uint16_t size) { +uint16_t CDC_ReceiveQueue_Read(CDC_ReceiveQueue_TypeDef *queue, + uint8_t *buffer, uint16_t size) { volatile uint16_t write = queue->write; volatile uint16_t length = queue->length; uint16_t available; - while(write != queue->write || length != queue->length) { - write = queue->write; - length = queue->length; - } + if (queue->read >= length) queue->read = 0; if (write >= queue->read) { available = write - queue->read; } else { @@ -172,16 +192,13 @@ uint16_t CDC_ReceiveQueue_Read(CDC_ReceiveQueue_TypeDef *queue, uint8_t *buffer, return size; } -bool CDC_ReceiveQueue_ReadUntil(CDC_ReceiveQueue_TypeDef *queue, uint8_t terminator, uint8_t *buffer, - uint16_t size, uint16_t* fetched) { +bool CDC_ReceiveQueue_ReadUntil(CDC_ReceiveQueue_TypeDef *queue, + uint8_t terminator, uint8_t *buffer, uint16_t size, uint16_t* fetched) { volatile uint16_t write = queue->write; volatile uint16_t length = queue->length; uint16_t available; - while(write != queue->write || length != queue->length) { - write = queue->write; - length = queue->length; - } + if (queue->read >= length) queue->read = 0; if (write >= queue->read) { available = write - queue->read; } else { diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.h b/cores/arduino/stm32/usb/cdc/cdc_queue.h index d680c00b89..827f0aa889 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.h +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -53,7 +53,7 @@ #define CDC_QUEUE_MAX_PACKET_SIZE USB_FS_MAX_PACKET_SIZE #endif #define CDC_TRANSMIT_QUEUE_BUFFER_SIZE ((uint16_t)(CDC_QUEUE_MAX_PACKET_SIZE * 2)) -#define CDC_RECEIVE_QUEUE_BUFFER_SIZE ((uint16_t)(CDC_QUEUE_MAX_PACKET_SIZE * 2)) +#define CDC_RECEIVE_QUEUE_BUFFER_SIZE ((uint16_t)(CDC_QUEUE_MAX_PACKET_SIZE * 3)) typedef struct { uint8_t buffer[CDC_TRANSMIT_QUEUE_BUFFER_SIZE]; From 6cde061810b4c2de89ea6f4a12c8c7e36304d176 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Thu, 31 Jan 2019 09:23:32 +0300 Subject: [PATCH 10/12] [USB] PMA Addresses correction --- cores/arduino/stm32/usb/usbd_conf.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/cores/arduino/stm32/usb/usbd_conf.c b/cores/arduino/stm32/usb/usbd_conf.c index 5fae55bf0b..2f2c7063f0 100644 --- a/cores/arduino/stm32/usb/usbd_conf.c +++ b/cores/arduino/stm32/usb/usbd_conf.c @@ -27,6 +27,12 @@ #else /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ +/* Size in words, byte size divided by 2 */ +#define PMA_EP0_OUT_ADDR (8 * 4) +#define PMA_EP0_IN_ADDR (PMA_EP0_OUT_ADDR + USB_MAX_EP0_SIZE / 2) +#define PMA_CDC_OUT_ADDR (PMA_EP0_IN_ADDR + USB_MAX_EP0_SIZE / 2) +#define PMA_CDC_IN_ADDR (PMA_CDC_OUT_ADDR + USB_FS_MAX_PACKET_SIZE / 2) +#define PMA_CDC_CMD_ADDR (PMA_CDC_IN_ADDR + USB_FS_MAX_PACKET_SIZE / 2) /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ PCD_HandleTypeDef g_hpcd; @@ -483,16 +489,11 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) HAL_PCDEx_SetTxFiFo(&g_hpcd, 1, 0x40); HAL_PCDEx_SetTxFiFo(&g_hpcd, 2, 0x40); #else - uint32_t pma_addr = 8 * 3; /* 3 endpoints, 8 bytes for each in PMA BTABLE */ - HAL_PCDEx_PMAConfig(&g_hpcd, 0x00, PCD_SNG_BUF, pma_addr); - pma_addr += USB_MAX_EP0_SIZE; - HAL_PCDEx_PMAConfig(&g_hpcd, 0x80, PCD_SNG_BUF, pma_addr); - pma_addr += USB_MAX_EP0_SIZE; - HAL_PCDEx_PMAConfig(&g_hpcd, 0x81, PCD_SNG_BUF, pma_addr); - pma_addr += USB_FS_MAX_PACKET_SIZE; - HAL_PCDEx_PMAConfig(&g_hpcd, 0x01, PCD_SNG_BUF, pma_addr); - pma_addr += USB_FS_MAX_PACKET_SIZE; - HAL_PCDEx_PMAConfig(&g_hpcd, 0x82, PCD_SNG_BUF, pma_addr); + HAL_PCDEx_PMAConfig(&g_hpcd, 0x00, PCD_SNG_BUF, PMA_EP0_OUT_ADDR); + HAL_PCDEx_PMAConfig(&g_hpcd, 0x80, PCD_SNG_BUF, PMA_EP0_IN_ADDR); + HAL_PCDEx_PMAConfig(&g_hpcd, 0x01, PCD_SNG_BUF, PMA_CDC_OUT_ADDR); + HAL_PCDEx_PMAConfig(&g_hpcd, 0x81, PCD_SNG_BUF, PMA_CDC_IN_ADDR); + HAL_PCDEx_PMAConfig(&g_hpcd, 0x82, PCD_SNG_BUF, PMA_CDC_CMD_ADDR); #endif #endif /* USE_USB_HS */ return USBD_OK; From 1e059c6f4ade923cdc9e6a3ff7867ac4c05873bd Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 12 Feb 2019 18:04:29 +0100 Subject: [PATCH 11/12] Remove useless declaration Signed-off-by: Frederic Pillon --- cores/arduino/USBSerial.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/cores/arduino/USBSerial.cpp b/cores/arduino/USBSerial.cpp index 091a29879d..571bdb4e78 100644 --- a/cores/arduino/USBSerial.cpp +++ b/cores/arduino/USBSerial.cpp @@ -24,8 +24,6 @@ #include "usbd_desc.h" #include "wiring.h" -/* USB Device Core handle declaration */ -extern USBD_HandleTypeDef hUSBD_Device_CDC; extern __IO uint32_t lineState; USBSerial SerialUSB; From 55b8f817dd85733539120b69a26570bc496d34a0 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 12 Feb 2019 18:41:49 +0100 Subject: [PATCH 12/12] [USB CDC] Init interface as soon as possible Signed-off-by: Frederic Pillon --- cores/arduino/stm32/hw_config.c | 5 ++++ cores/arduino/stm32/usb/cdc/usbd_cdc_if.c | 30 ++++++++++++++--------- cores/arduino/stm32/usb/usbd_if.c | 8 ++++++ cores/arduino/stm32/usb/usbd_if.h | 4 ++- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/cores/arduino/stm32/hw_config.c b/cores/arduino/stm32/hw_config.c index f5e9fc6d20..bf9e26da25 100644 --- a/cores/arduino/stm32/hw_config.c +++ b/cores/arduino/stm32/hw_config.c @@ -37,6 +37,7 @@ */ #include "stm32_def.h" #include "hw_config.h" +#include "usbd_if.h" #ifdef __cplusplus extern "C" { @@ -54,6 +55,10 @@ void hw_config_init(void) // Configure the system clock SystemClock_Config(); + +#if defined (USBCON) && defined(USBD_USE_CDC) + USBD_CDC_init(); +#endif } #ifdef __cplusplus } diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c index a1c1ab0f0f..b292a94192 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c @@ -36,6 +36,8 @@ /* USB Device Core CDC handle declaration */ USBD_HandleTypeDef hUSBD_Device_CDC; +static bool CDC_initialized = false; + /* Received Data over USB are stored in this buffer */ CDC_TransmitQueue_TypeDef TransmitQueue; CDC_ReceiveQueue_TypeDef ReceiveQueue; @@ -217,23 +219,29 @@ static int8_t USBD_CDC_Transferred (void) { } void CDC_init(void) { - /* Init Device Library */ - if (USBD_Init(&hUSBD_Device_CDC, &CDC_Desc, 0) == USBD_OK) { - /* Add Supported Class */ - if (USBD_RegisterClass(&hUSBD_Device_CDC, USBD_CDC_CLASS) == USBD_OK) { - /* Add CDC Interface Class */ - if (USBD_CDC_RegisterInterface(&hUSBD_Device_CDC, &USBD_CDC_fops) == USBD_OK) { - /* Start Device Process */ - USBD_Start(&hUSBD_Device_CDC); + if (!CDC_initialized) { + /* Init Device Library */ + if (USBD_Init(&hUSBD_Device_CDC, &CDC_Desc, 0) == USBD_OK) { + /* Add Supported Class */ + if (USBD_RegisterClass(&hUSBD_Device_CDC, USBD_CDC_CLASS) == USBD_OK) { + /* Add CDC Interface Class */ + if (USBD_CDC_RegisterInterface(&hUSBD_Device_CDC, &USBD_CDC_fops) == USBD_OK) { + /* Start Device Process */ + USBD_Start(&hUSBD_Device_CDC); + CDC_initialized = true; + } } } } } void CDC_deInit(void) { - USBD_Stop(&hUSBD_Device_CDC); - USBD_CDC_DeInit(); - USBD_DeInit(&hUSBD_Device_CDC); + if (CDC_initialized) { + USBD_Stop(&hUSBD_Device_CDC); + USBD_CDC_DeInit(); + USBD_DeInit(&hUSBD_Device_CDC); + CDC_initialized = false; + } } void CDC_continue_transmit(void) { diff --git a/cores/arduino/stm32/usb/usbd_if.c b/cores/arduino/stm32/usb/usbd_if.c index 74397f206b..a3f110a4af 100644 --- a/cores/arduino/stm32/usb/usbd_if.c +++ b/cores/arduino/stm32/usb/usbd_if.c @@ -8,6 +8,8 @@ #ifdef USBCON #include "usbd_if.h" +#include "usbd_cdc_if.h" + /** * @brief Force to re-enumerate USB * @param None @@ -38,4 +40,10 @@ void USBD_reenumerate(void) #endif /* USBD_REENUM_DISABLED */ } +#ifdef USBD_USE_CDC +void USBD_CDC_init(void) +{ + CDC_init(); +} +#endif /* USBD_USE_CDC */ #endif /* USBCON */ diff --git a/cores/arduino/stm32/usb/usbd_if.h b/cores/arduino/stm32/usb/usbd_if.h index befa37a9a6..13c6e6e892 100644 --- a/cores/arduino/stm32/usb/usbd_if.h +++ b/cores/arduino/stm32/usb/usbd_if.h @@ -24,7 +24,9 @@ #endif void USBD_reenumerate(void); - +#ifdef USBD_USE_CDC +void USBD_CDC_init(void); +#endif #ifdef __cplusplus } #endif