trailing whitespace removal (#14026)
[betaflight.git] / src / platform / APM32 / usb / vcp / usbd_cdc_vcp.c
blobf7f5468220e9e0af0751384e1afc99e67646a546
1 /**
2 * @file usbd_cdc_vcp.c
4 * @brief usb device CDC class Virtual Com Port handler
6 * @attention
8 * Copyright (C) 2023 Geehy Semiconductor
10 * You may not use this file except in compliance with the
11 * GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
13 * The program is only for reference, which is distributed in the hope
14 * that it will be useful and instructional for customers to develop
15 * their software. Unless required by applicable law or agreed to in
16 * writing, the program is distributed on an "AS IS" BASIS, WITHOUT
17 * ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
19 * and limitations under the License.
22 /* Includes ***************************************************************/
23 #include "usbd_cdc_vcp.h"
25 /* Private includes *******************************************************/
26 #include <stdbool.h>
28 #include "platform.h"
30 #include "build/atomic.h"
32 #include "drivers/nvic.h"
33 #include "drivers/serial_usb_vcp.h"
34 #include "drivers/time.h"
36 /* Private macro **********************************************************/
37 #define APP_RX_DATA_SIZE 2048
38 #define APP_TX_DATA_SIZE 2048
40 #define APP_TX_BLOCK_SIZE 512
42 /* Private variables ******************************************************/
43 volatile uint8_t cdcTxBuffer[APP_RX_DATA_SIZE];
44 volatile uint8_t cdcRxBuffer[APP_TX_DATA_SIZE];
45 uint32_t BuffLength;
46 volatile uint32_t cdcTxBufPtrIn = 0;/* Increment this pointer or roll it back to
47 start address when data are received over USART */
48 volatile uint32_t cdcTxBufPtrOut = 0; /* Increment this pointer or roll it back to
49 start address when data are sent over USB */
51 uint32_t rxAvailable = 0;
52 uint8_t* rxBuffPtr = NULL;
54 /* Private typedef ********************************************************/
56 static USBD_STA_T USBD_CDC_ItfInit(void);
57 static USBD_STA_T USBD_CDC_ItfDeInit(void);
58 static USBD_STA_T USBD_CDC_ItfCtrl(uint8_t command, uint8_t *buffer, uint16_t length);
59 static USBD_STA_T USBD_CDC_ItfSend(uint8_t *buffer, uint16_t length);
60 static USBD_STA_T USBD_CDC_ItfSendEnd(uint8_t epNum, uint8_t *buffer, uint32_t *length);
61 static USBD_STA_T USBD_CDC_ItfReceive(uint8_t *buffer, uint32_t *length);
62 static USBD_STA_T USBD_CDC_ItfSOF(void);
65 /* USB CDC interface handler */
66 USBD_CDC_INTERFACE_T USBD_CDC_INTERFACE =
68 "CDC Interface",
69 USBD_CDC_ItfInit,
70 USBD_CDC_ItfDeInit,
71 USBD_CDC_ItfCtrl,
72 USBD_CDC_ItfSend,
73 USBD_CDC_ItfSendEnd,
74 USBD_CDC_ItfReceive,
75 USBD_CDC_ItfSOF,
78 /* CDC Line Code Information */
79 USBD_CDC_LINE_CODING_T LineCoding =
81 115200, /*!< baud rate */
82 0x00, /*!< stop bits 1 */
83 0x00, /*!< parity none */
84 0x08, /*!< word length 8 bits */
87 /* Private function prototypes ********************************************/
88 static void (*ctrlLineStateCb)(void *context, uint16_t ctrlLineState);
89 static void *ctrlLineStateCbContext;
90 static void (*baudRateCb)(void *context, uint32_t baud);
91 static void *baudRateCbContext;
93 /* External variables *****************************************************/
94 extern USBD_INFO_T gUsbDevice;
96 /* External functions *****************************************************/
98 /**
99 * @brief USB device initializes CDC media handler
101 * @param None
103 * @retval USB device operation status
105 static USBD_STA_T USBD_CDC_ItfInit(void)
107 USBD_STA_T usbStatus = USBD_OK;
109 USBD_CDC_ConfigRxBuffer(&gUsbDevice, (uint8_t *)cdcRxBuffer);
110 USBD_CDC_ConfigTxBuffer(&gUsbDevice, (uint8_t *)cdcTxBuffer, 0);
112 ctrlLineStateCb = NULL;
113 baudRateCb = NULL;
115 return usbStatus;
119 * @brief USB device deinitializes CDC media handler
121 * @param None
123 * @retval USB device operation status
125 static USBD_STA_T USBD_CDC_ItfDeInit(void)
127 USBD_STA_T usbStatus = USBD_OK;
129 return usbStatus;
133 * @brief USB device CDC interface control request handler
135 * @param command: Command code
137 * @param buffer: Command data buffer
139 * @param length: Command data length
141 * @retval USB device operation status
143 static USBD_STA_T USBD_CDC_ItfCtrl(uint8_t command, uint8_t *buffer, uint16_t length)
145 USBD_STA_T usbStatus = USBD_OK;
146 LINE_CODING* plc = (LINE_CODING*)buffer;
148 switch(command)
150 case USBD_CDC_SEND_ENCAPSULATED_COMMAND:
151 break;
153 case USBD_CDC_GET_ENCAPSULATED_RESPONSE:
154 break;
156 case USBD_CDC_SET_COMM_FEATURE:
157 break;
159 case USBD_CDC_GET_COMM_FEATURE:
160 break;
162 case USBD_CDC_CLEAR_COMM_FEATURE:
163 break;
165 /* Line Coding Data Structure
166 * | Offset(Byte) | Field | Length | Desc |
167 * | 0 | dwDTERate | 4 | Data Terminal rate |
168 * | 4 | bCharFormat | 1 | Stop bits |
169 * (0 : 1 Stop bit)
170 * (1 : 1.5 Stop bits)
171 * (2 : 2 Stop bits)
172 * | 5 | bParityType | 1 | Parity |
173 * (0 : None)
174 * (1 : Odd)
175 * (2 : Even)
176 * (3 : Mark)
177 * (4 : Space)
178 * | 6 | bDataBits | 1 | Data bits |
179 * (5 : 5 bits)
180 * (6 : 6 bits)
181 * (7 : 7 bits)
182 * (8 : 8 bits)
183 * (16 : 16 bits)
185 case USBD_CDC_SET_LINE_CODING:
186 if (buffer && (length == sizeof(*plc))) {
187 LineCoding.baudRate = plc->bitrate;
188 LineCoding.format = plc->format;
189 LineCoding.parityType = plc->paritytype;
190 LineCoding.WordLen = plc->datatype;
192 // If a callback is provided, tell the upper driver of changes in baud rate
193 if (baudRateCb) {
194 baudRateCb(baudRateCbContext, LineCoding.baudRate);
197 break;
199 case USBD_CDC_GET_LINE_CODING:
200 if (buffer && (length == sizeof(*plc))) {
201 plc->bitrate = LineCoding.baudRate;
202 plc->format = LineCoding.format;
203 plc->paritytype = LineCoding.parityType;
204 plc->datatype = LineCoding.WordLen;
206 break;
208 case USBD_CDC_SET_CONTROL_LINE_STATE:
209 // If a callback is provided, tell the upper driver of changes in DTR/RTS state
210 if (buffer && (length == sizeof(uint16_t))) {
211 if (ctrlLineStateCb) {
212 ctrlLineStateCb(ctrlLineStateCbContext, *((uint16_t *)buffer));
215 break;
217 case USBD_CDC_SEND_BREAK:
218 break;
220 default:
221 break;
224 return usbStatus;
228 * @brief USB device CDC interface send handler
230 * @param buffer: Command data buffer
232 * @param length: Command data length
234 * @retval USB device operation status
236 static USBD_STA_T USBD_CDC_ItfSend(uint8_t *buffer, uint16_t length)
238 USBD_STA_T usbStatus = USBD_OK;
240 USBD_CDC_INFO_T *usbDevCDC = (USBD_CDC_INFO_T*)gUsbDevice.devClass[gUsbDevice.classID]->classData;
242 if(usbDevCDC->cdcTx.state != USBD_CDC_XFER_IDLE)
244 return USBD_BUSY;
247 USBD_CDC_ConfigTxBuffer(&gUsbDevice, buffer, length);
249 usbStatus = USBD_CDC_TxPacket(&gUsbDevice);
251 return usbStatus;
255 * @brief USB device CDC interface send end event handler
257 * @param epNum: endpoint number
259 * @param buffer: Command data buffer
261 * @param length: Command data length
263 * @retval USB device operation status
265 static USBD_STA_T USBD_CDC_ItfSendEnd(uint8_t epNum, uint8_t *buffer, uint32_t *length)
267 USBD_STA_T usbStatus = USBD_OK;
269 UNUSED(epNum);
270 UNUSED(buffer);
271 UNUSED(length);
273 return usbStatus;
277 * @brief USB device CDC interface receive handler
279 * @param buffer: Command data buffer
281 * @param length: Command data length
283 * @retval USB device operation status
285 static USBD_STA_T USBD_CDC_ItfReceive(uint8_t *buffer, uint32_t *length)
287 USBD_STA_T usbStatus = USBD_OK;
289 // USBD_CDC_ConfigRxBuffer(&gUsbDevice, &buffer[0]);
290 rxAvailable = *length;
291 rxBuffPtr = buffer;
292 if (!rxAvailable) {
293 // Received an empty packet, trigger receiving the next packet.
294 // This will happen after a packet that's exactly 64 bytes is received.
295 // The USB protocol requires that an empty (0 byte) packet immediately follow.
296 USBD_CDC_RxPacket(&gUsbDevice);
299 return usbStatus;
302 static USBD_STA_T USBD_CDC_ItfSOF(void)
304 static uint32_t FrameCount = 0;
306 uint32_t buffsize;
307 static uint32_t lastBuffsize = 0;
309 USBD_CDC_INFO_T *usbDevCDC = (USBD_CDC_INFO_T*)gUsbDevice.devClass[gUsbDevice.classID]->classData;
311 if (FrameCount++ == USBD_CDC_FS_INTERVAL)
313 FrameCount = 0;
315 if (usbDevCDC->cdcTx.state == USBD_CDC_XFER_IDLE) {
316 // endpoint has finished transmitting previous block
317 if (lastBuffsize) {
318 bool needZeroLengthPacket = lastBuffsize % 64 == 0;
320 // move the ring buffer tail based on the previous succesful transmission
321 cdcTxBufPtrOut += lastBuffsize;
322 if (cdcTxBufPtrOut == APP_TX_DATA_SIZE) {
323 cdcTxBufPtrOut = 0;
325 lastBuffsize = 0;
327 if (needZeroLengthPacket) {
328 USBD_CDC_ConfigTxBuffer(&gUsbDevice, (uint8_t*)&cdcTxBuffer[cdcTxBufPtrOut], 0);
329 return USBD_OK;
332 if (cdcTxBufPtrOut != cdcTxBufPtrIn) {
333 if (cdcTxBufPtrOut > cdcTxBufPtrIn) { /* Roll-back */
334 buffsize = APP_TX_DATA_SIZE - cdcTxBufPtrOut;
335 } else {
336 buffsize = cdcTxBufPtrIn - cdcTxBufPtrOut;
338 if (buffsize > APP_TX_BLOCK_SIZE) {
339 buffsize = APP_TX_BLOCK_SIZE;
342 USBD_CDC_ConfigTxBuffer(&gUsbDevice, (uint8_t*)&cdcTxBuffer[cdcTxBufPtrOut], buffsize);
344 if (USBD_CDC_TxPacket(&gUsbDevice) == USBD_OK) {
345 lastBuffsize = buffsize;
351 return USBD_OK;
354 /*******************************************************************************
355 * Function Name : Send DATA .
356 * Description : send the data received from the STM32 to the PC through USB
357 * Input : buffer to send, and the length of the buffer.
358 * Output : None.
359 * Return : None.
360 *******************************************************************************/
361 uint32_t CDC_Send_DATA(const uint8_t *ptrBuffer, uint32_t sendLength)
363 for (uint32_t i = 0; i < sendLength; i++) {
364 while (CDC_Send_FreeBytes() == 0) {
365 // block until there is free space in the ring buffer
366 delay(1);
368 ATOMIC_BLOCK(NVIC_BUILD_PRIORITY(6, 0)) { // Paranoia
369 cdcTxBuffer[cdcTxBufPtrIn] = ptrBuffer[i];
370 cdcTxBufPtrIn = (cdcTxBufPtrIn + 1) % APP_TX_DATA_SIZE;
373 return sendLength;
376 /*******************************************************************************
377 * Function Name : Receive DATA .
378 * Description : receive the data from the PC to STM32 and send it through USB
379 * Input : None.
380 * Output : None.
381 * Return : None.
382 *******************************************************************************/
383 uint32_t CDC_Receive_DATA(uint8_t* recvBuf, uint32_t len)
385 uint32_t count = 0;
386 if ( (rxBuffPtr != NULL))
388 while ((rxAvailable > 0) && count < len)
390 recvBuf[count] = rxBuffPtr[0];
391 rxBuffPtr++;
392 rxAvailable--;
393 count++;
394 if (rxAvailable < 1)
395 USBD_CDC_RxPacket(&gUsbDevice);
398 return count;
401 uint32_t CDC_Receive_BytesAvailable(void)
403 return rxAvailable;
406 uint32_t CDC_Send_FreeBytes(void)
409 return the bytes free in the circular buffer
411 functionally equivalent to:
412 (APP_Rx_ptr_out > APP_Rx_ptr_in ? APP_Rx_ptr_out - APP_Rx_ptr_in : APP_RX_DATA_SIZE - APP_Rx_ptr_in + APP_Rx_ptr_in)
413 but without the impact of the condition check.
415 uint32_t freeBytes;
417 ATOMIC_BLOCK(NVIC_BUILD_PRIORITY(6, 0)) {
418 freeBytes = ((cdcTxBufPtrOut - cdcTxBufPtrIn) + (-((int)(cdcTxBufPtrOut <= cdcTxBufPtrIn)) & APP_TX_DATA_SIZE)) - 1;
421 return freeBytes;
424 /*******************************************************************************
425 * Function Name : usbIsConfigured.
426 * Description : Determines if USB VCP is configured or not
427 * Input : None.
428 * Output : None.
429 * Return : True if configured.
430 *******************************************************************************/
431 uint8_t usbIsConfigured(void)
433 return (gUsbDevice.devState == USBD_DEV_CONFIGURE);
436 /*******************************************************************************
437 * Function Name : usbIsConnected.
438 * Description : Determines if USB VCP is connected ot not
439 * Input : None.
440 * Output : None.
441 * Return : True if connected.
442 *******************************************************************************/
443 uint8_t usbIsConnected(void)
445 return (gUsbDevice.devState != USBD_DEV_DEFAULT);
448 /*******************************************************************************
449 * Function Name : CDC_BaudRate.
450 * Description : Get the current baud rate
451 * Input : None.
452 * Output : None.
453 * Return : Baud rate in bps
454 *******************************************************************************/
455 uint32_t CDC_BaudRate(void)
457 return LineCoding.baudRate;
460 /*******************************************************************************
461 * Function Name : CDC_SetBaudRateCb
462 * Description : Set a callback to call when baud rate changes
463 * Input : callback function and context.
464 * Output : None.
465 * Return : None.
466 *******************************************************************************/
467 void CDC_SetBaudRateCb(void (*cb)(void *context, uint32_t baud), void *context)
469 baudRateCbContext = context;
470 baudRateCb = cb;
473 /*******************************************************************************
474 * Function Name : CDC_SetCtrlLineStateCb
475 * Description : Set a callback to call when control line state changes
476 * Input : callback function and context.
477 * Output : None.
478 * Return : None.
479 *******************************************************************************/
480 void CDC_SetCtrlLineStateCb(void (*cb)(void *context, uint16_t ctrlLineState), void *context)
482 ctrlLineStateCbContext = context;
483 ctrlLineStateCb = cb;