From 87227337bfc475d1883815b75e0e927db44e7f6b Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Sun, 20 Jan 2019 16:30:19 +0300 Subject: [PATCH 1/9] Fixed PMA buffers distribution for SMTF1xx --- 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 c02d8c35cb..cebdccb633 100644 --- a/cores/arduino/stm32/usb/usbd_conf.c +++ b/cores/arduino/stm32/usb/usbd_conf.c @@ -475,10 +475,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 137d727237352884f37805068039c1afc0182d8f Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Sun, 20 Jan 2019 16:33:59 +0300 Subject: [PATCH 2/9] Timers removing, and some other updates. --- cores/arduino/USBSerial.cpp | 139 ++++++------- cores/arduino/USBSerial.h | 6 +- cores/arduino/stm32/usb/cdc/cdc_queue.c | 140 ++++++++++++++ cores/arduino/stm32/usb/cdc/cdc_queue.h | 89 +++++++++ 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 | 226 +++++++--------------- cores/arduino/stm32/usb/cdc/usbd_cdc_if.h | 26 +-- cores/arduino/stm32/usbd_interface.c | 15 -- 9 files changed, 366 insertions(+), 281 deletions(-) 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/USBSerial.cpp b/cores/arduino/USBSerial.cpp index b11d4f5c8d..3203357bce 100644 --- a/cores/arduino/USBSerial.cpp +++ b/cores/arduino/USBSerial.cpp @@ -27,122 +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 USBSerial::begin() { + pinMode(PA12, OUTPUT); + digitalWrite(PA12, LOW); + delay(100); + 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; - } - } - return i; + 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 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) { - return -1; - } else { - unsigned char c = UserRxBuffer[UserRxBufPtrOut]; - UserRxBufPtrOut = ((UserRxBufPtrOut + 1) % APP_RX_DATA_SIZE); + // 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); + // resume receive process, if possible CDC_resume_receive(); - return c; - } + return ch; } int USBSerial::peek(void) { - if (UserRxBufPtrOut == UserRxBufPtrIn) { - return -1; - } else { - unsigned char c = UserRxBuffer[UserRxBufPtrOut]; - return c; - } + // 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); } 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..2613f3978f 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 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/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c new file mode 100644 index 0000000000..d02e5232aa --- /dev/null +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -0,0 +1,140 @@ +/** + ****************************************************************************** + * @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. + * + ****************************************************************************** + */ + + +#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 (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 (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]; +} + + 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..8113870f87 --- /dev/null +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -0,0 +1,89 @@ +/** + ****************************************************************************** + * @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 +#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 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..cf34ab4590 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 #include "usbd_cdc_if.h" #ifdef USE_USB_HS @@ -37,28 +38,13 @@ /* 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 +52,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 +81,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 +202,74 @@ 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) { + // it always contains required amount of free space for writing + CDC_ReceiveQueue_CommitBlock(&ReceiveQueue, (uint16_t)(*Len)); + receivePended = false; + // If there is enough space in the queue for a full buffer, 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)); - } +static int8_t USBD_CDC_Transferred (void) { + CDC_continue_transmit(); +} - do { - if (lineState == 0) { // Device disconnected - status = USBD_OK; - } else { - status = USBD_CDC_TransmitPacket(&hUSBD_Device_CDC); - } - } while (status == USBD_BUSY); +void CDC_init(void) { + /* Init Device Library */ + if (USBD_Init(&hUSBD_Device_CDC, &CDC_Desc, 0) == USBD_OK) { - if (status == USBD_OK) { - UserTxBufPtrOut = UserTxBufPtrIn; - } - } -} + /* Add Supported Class */ + if (USBD_RegisterClass(&hUSBD_Device_CDC, USBD_CDC_CLASS) == 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; + /* 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); -} - -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_deInit(void) { + USBD_Stop(&hUSBD_Device_CDC); + USBD_CDC_DeInit(); + USBD_DeInit(&hUSBD_Device_CDC); } -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 newer 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 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..7408f30d49 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h @@ -30,8 +30,10 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_cdc.h" +#include "cdc_queue.h" #include "timer.h" + #ifndef APP_RX_DATA_SIZE #define APP_RX_DATA_SIZE 2048 #endif @@ -39,21 +41,6 @@ #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 - /* Periodically, the state of the buffer "UserTxBuffer" is checked. The period depends on CDC_POLLING_INTERVAL */ #define CDC_POLLING_INTERVAL 2 /* in ms. The max is 65 and the min is 1 */ @@ -62,13 +49,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..5657223c65 100644 --- a/cores/arduino/stm32/usbd_interface.c +++ b/cores/arduino/stm32/usbd_interface.c @@ -72,21 +72,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 6b697acb0cc0b58861e434679c3918db8192d6c4 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Sun, 27 Jan 2019 01:41:55 +0300 Subject: [PATCH 3/9] Fixed receiving data error. --- cores/arduino/stm32/usb/cdc/cdc_queue.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c index d02e5232aa..cf94ddb20b 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -95,10 +95,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 (CDC_RECEIVE_QUEUE_BUFFER_SIZE - queue->write >= CDC_QUEUE_MAX_PACKET_SIZE) { + if (CDC_RECEIVE_QUEUE_BUFFER_SIZE - queue->write >= CDC_QUEUE_MAX_PACKET_SIZE && + (queue->read <= queue->write || 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; @@ -112,6 +113,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 @@ -119,7 +123,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; } } @@ -136,5 +140,3 @@ uint8_t CDC_ReceiveQueue_Dequeue(CDC_ReceiveQueue_TypeDef *queue) { uint8_t CDC_ReceiveQueue_Peek(CDC_ReceiveQueue_TypeDef *queue) { return queue->buffer[queue->read]; } - - From ca4018cc7afc4c5e8322f49d81c08cdc1de01dea Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Sun, 27 Jan 2019 13:44:14 +0300 Subject: [PATCH 4/9] Fixed 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 cf94ddb20b..215992454e 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -71,19 +71,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 (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 8113870f87..b28e7d7425 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.h +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -53,13 +53,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 { @@ -74,6 +75,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 cf34ab4590..21893502f2 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c @@ -213,6 +213,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(); } From 663859da0062f0852357663fc47752ebb80b8e09 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Tue, 29 Jan 2019 15:55:43 +0300 Subject: [PATCH 5/9] Some speed improvements Added bulk read method readBytes and improved read and peek methods. --- cores/arduino/Stream.h | 2 +- cores/arduino/USBSerial.cpp | 20 +++++++++++--------- cores/arduino/USBSerial.h | 1 + cores/arduino/stm32/usb/cdc/cdc_queue.c | 22 ++++++++++++++++++++-- cores/arduino/stm32/usb/cdc/cdc_queue.h | 5 +++-- 5 files changed, 36 insertions(+), 14 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 3203357bce..702ba29e53 100644 --- a/cores/arduino/USBSerial.cpp +++ b/cores/arduino/USBSerial.cpp @@ -91,24 +91,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 2613f3978f..473405f54d 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 215992454e..743f247256 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -126,7 +126,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; @@ -135,6 +136,23 @@ 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; +} diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.h b/cores/arduino/stm32/usb/cdc/cdc_queue.h index b28e7d7425..c16856a370 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.h +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -79,8 +79,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 07a20822f9598f6313659850ad942dc43f9c0048 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Tue, 29 Jan 2019 15:58:17 +0300 Subject: [PATCH 6/9] Spaces changes, garbage removed. --- cores/arduino/USBSerial.cpp | 79 ++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/cores/arduino/USBSerial.cpp b/cores/arduino/USBSerial.cpp index 702ba29e53..36da3e55e2 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; @@ -52,74 +51,74 @@ void USBSerial::end() { int USBSerial::availableForWrite() { - // just transmit queue size, available for write - return static_cast(CDC_TransmitQueue_WriteSize(&TransmitQueue)); + // just transmit queue size, available for write + return static_cast(CDC_TransmitQueue_WriteSize(&TransmitQueue)); } size_t USBSerial::write(uint8_t ch) { - // just write single-byte buffer. - return write(&ch, 1); + // just write single-byte buffer. + return write(&ch, 1); } size_t USBSerial::write(const uint8_t *buffer, size_t size){ - 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(); - } + 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; } - return size; + 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 size; } int USBSerial::available(void) { - // just ReceiveQueue size, available for reading - return static_cast(CDC_ReceiveQueue_ReadSize(&ReceiveQueue)); + // just ReceiveQueue size, available for reading + return static_cast(CDC_ReceiveQueue_ReadSize(&ReceiveQueue)); } int USBSerial::read(void) { - // Dequeue only one char from queue - // TS: it safe, because only main thread affects ReceiveQueue->read pos - auto ch = CDC_ReceiveQueue_Dequeue(&ReceiveQueue); - // resume receive process, if possible - CDC_resume_receive(); - return ch; + // Dequeue only one char from queue + // TS: it safe, because only main thread affects ReceiveQueue->read pos + 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; + 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) { - // Peek one symbol, it can't change receive avaiablity - return CDC_ReceiveQueue_Peek(&ReceiveQueue); + // Peek one symbol, it can't change receive avaiablity + return CDC_ReceiveQueue_Peek(&ReceiveQueue); } void USBSerial::flush(void) { - // Wait for TransmitQueue read size becomes zero - // TS: safe, because it not be stopped while receive 0 - while(CDC_TransmitQueue_ReadSize(&TransmitQueue) > 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() { From 7f5cceb39406963021913fea68acad5c3ed2a415 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Tue, 29 Jan 2019 23:46:12 +0300 Subject: [PATCH 7/9] Bulk read fixed, added bulk read until --- cores/arduino/Stream.h | 2 +- cores/arduino/USBSerial.cpp | 28 ++++++++++- 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, 88 insertions(+), 6 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 36da3e55e2..f4be38c847 100644 --- a/cores/arduino/USBSerial.cpp +++ b/cores/arduino/USBSerial.cpp @@ -94,20 +94,44 @@ int USBSerial::read(void) { // TS: it safe, because only main thread affects ReceiveQueue->read pos auto ch = CDC_ReceiveQueue_Dequeue(&ReceiveQueue); // resume receive process, if possible - CDC_resume_receive(); + CDC_resume_receive(); return ch; } 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 473405f54d..bf4f07ecfe 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 743f247256..1812734ebc 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -114,6 +114,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 @@ -143,16 +146,68 @@ 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; +} diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.h b/cores/arduino/stm32/usb/cdc/cdc_queue.h index c16856a370..cc7aa0b7df 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.h +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -82,6 +82,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 21893502f2..4c1603a0d3 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c @@ -43,7 +43,7 @@ extern 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 1194ec273018072a516a9e1d168814f3c321ec4b Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Wed, 30 Jan 2019 23:23:36 +0300 Subject: [PATCH 8/9] Set of fixes. --- cores/arduino/stm32/usb/cdc/cdc_queue.c | 90 +++++++++++++++---------- cores/arduino/stm32/usb/cdc/cdc_queue.h | 2 +- 2 files changed, 55 insertions(+), 37 deletions(-) diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c index 1812734ebc..c1c338e160 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.c +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c @@ -57,8 +57,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); @@ -66,11 +66,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 { @@ -81,7 +83,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. @@ -93,23 +96,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 (CDC_RECEIVE_QUEUE_BUFFER_SIZE - queue->write >= CDC_QUEUE_MAX_PACKET_SIZE && - (queue->read <= queue->write || 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; @@ -121,18 +134,25 @@ 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; + // 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; } else { - return queue->length + queue->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; @@ -140,19 +160,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 { @@ -170,16 +191,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 cc7aa0b7df..108cdc1281 100644 --- a/cores/arduino/stm32/usb/cdc/cdc_queue.h +++ b/cores/arduino/stm32/usb/cdc/cdc_queue.h @@ -54,7 +54,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 3f29a79c8b7b1902740ea28effa37795320b85e7 Mon Sep 17 00:00:00 2001 From: Alexey Makarenya Date: Thu, 31 Jan 2019 09:23:32 +0300 Subject: [PATCH 9/9] 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 cebdccb633..2d91232d9a 100644 --- a/cores/arduino/stm32/usb/usbd_conf.c +++ b/cores/arduino/stm32/usb/usbd_conf.c @@ -25,6 +25,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; @@ -475,16 +481,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;