OP-1516 fixed boundf mistake
[librepilot.git] / flight / pios / stm32f4xx / pios_usb_cdc.c
blob253295d94ca822479d3c24d426214d3804ee3036
1 /**
2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
4 * @{
5 * @addtogroup PIOS_USB_COM USB COM Functions
6 * @brief PIOS USB COM implementation for CDC interfaces
7 * @notes This implements a CDC Serial Port
8 * @{
10 * @file pios_usb_com_cdc.c
11 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
12 * @brief USB COM functions (STM32 dependent code)
13 * @see The GNU Public License (GPL) Version 3
15 *****************************************************************************/
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 * for more details.
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "pios.h"
34 #ifdef PIOS_INCLUDE_USB_CDC
36 #include "pios_usb_cdc_priv.h"
37 #include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */
38 #include "pios_usbhook.h" /* PIOS_USBHOOK_* */
40 /* Implement COM layer driver API */
41 static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context);
42 static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context);
43 static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, uint16_t tx_bytes_avail);
44 static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail);
45 static bool PIOS_USB_CDC_Available(uint32_t usbcdc_id);
47 const struct pios_com_driver pios_usb_cdc_com_driver = {
48 .tx_start = PIOS_USB_CDC_TxStart,
49 .rx_start = PIOS_USB_CDC_RxStart,
50 .bind_tx_cb = PIOS_USB_CDC_RegisterTxCallback,
51 .bind_rx_cb = PIOS_USB_CDC_RegisterRxCallback,
52 .available = PIOS_USB_CDC_Available,
55 enum pios_usb_cdc_dev_magic {
56 PIOS_USB_CDC_DEV_MAGIC = 0xAABBCCDD,
59 struct pios_usb_cdc_dev {
60 enum pios_usb_cdc_dev_magic magic;
61 const struct pios_usb_cdc_cfg *cfg;
63 uint32_t lower_id;
65 pios_com_callback rx_in_cb;
66 uint32_t rx_in_context;
67 pios_com_callback tx_out_cb;
68 uint32_t tx_out_context;
70 bool usb_ctrl_if_enabled;
71 bool usb_data_if_enabled;
73 uint8_t rx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH] __attribute__((aligned(4)));
74 volatile bool rx_active;
77 * NOTE: This is -1 as somewhat of a hack. It ensures that we always send packets
78 * that are strictly < maxPacketSize for this interface which means we never have
79 * to bother with zero length packets (ZLP).
81 uint8_t tx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH - 1] __attribute__((aligned(4)));
82 volatile bool tx_active;
84 uint8_t ctrl_tx_packet_buffer[PIOS_USB_BOARD_CDC_MGMT_LENGTH] __attribute__((aligned(4)));
86 uint32_t rx_dropped;
87 uint32_t rx_oversize;
90 * Used to hold the current state of the simulated UART. Changes to this
91 * variable may trigger new USB CDC Notification packets to be sent to the host.
93 volatile uint16_t prev_uart_state;
96 static bool PIOS_USB_CDC_validate(struct pios_usb_cdc_dev *usb_cdc_dev)
98 return usb_cdc_dev && (usb_cdc_dev->magic == PIOS_USB_CDC_DEV_MAGIC);
101 #if defined(PIOS_INCLUDE_FREERTOS)
102 static struct pios_usb_cdc_dev *PIOS_USB_CDC_alloc(void)
104 struct pios_usb_cdc_dev *usb_cdc_dev;
106 usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_malloc(sizeof(struct pios_usb_cdc_dev));
107 if (!usb_cdc_dev) {
108 return NULL;
111 memset(usb_cdc_dev, 0, sizeof(struct pios_usb_cdc_dev));
112 usb_cdc_dev->magic = PIOS_USB_CDC_DEV_MAGIC;
113 return usb_cdc_dev;
115 #else
116 static struct pios_usb_cdc_dev pios_usb_cdc_devs[PIOS_USB_CDC_MAX_DEVS];
117 static uint8_t pios_usb_cdc_num_devs;
118 static struct pios_usb_cdc_dev *PIOS_USB_CDC_alloc(void)
120 struct pios_usb_cdc_dev *usb_cdc_dev;
122 if (pios_usb_cdc_num_devs >= PIOS_USB_CDC_MAX_DEVS) {
123 return NULL;
126 usb_cdc_dev = &pios_usb_cdc_devs[pios_usb_cdc_num_devs++];
128 memset(usb_cdc_dev, 0, sizeof(struct pios_usb_cdc_dev));
129 usb_cdc_dev->magic = PIOS_USB_CDC_DEV_MAGIC;
131 return usb_cdc_dev;
133 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
135 /* Implement USB_IFOPS for CDC Control Interface */
136 static void PIOS_USB_CDC_CTRL_IF_Init(uint32_t usb_cdc_id);
137 static void PIOS_USB_CDC_CTRL_IF_DeInit(uint32_t usb_cdc_id);
138 static bool PIOS_USB_CDC_CTRL_IF_Setup(uint32_t usb_cdc_id, struct usb_setup_request *req);
139 static void PIOS_USB_CDC_CTRL_IF_CtrlDataOut(uint32_t usb_cdc_id, const struct usb_setup_request *req);
141 static struct pios_usb_ifops usb_cdc_ctrl_ifops = {
142 .init = PIOS_USB_CDC_CTRL_IF_Init,
143 .deinit = PIOS_USB_CDC_CTRL_IF_DeInit,
144 .setup = PIOS_USB_CDC_CTRL_IF_Setup,
145 .ctrl_data_out = PIOS_USB_CDC_CTRL_IF_CtrlDataOut,
148 /* Implement USB_IFOPS for CDC Data Interface */
149 static void PIOS_USB_CDC_DATA_IF_Init(uint32_t usb_cdc_id);
150 static void PIOS_USB_CDC_DATA_IF_DeInit(uint32_t usb_cdc_id);
151 static bool PIOS_USB_CDC_DATA_IF_Setup(uint32_t usb_cdc_id, struct usb_setup_request *req);
152 static void PIOS_USB_CDC_DATA_IF_CtrlDataOut(uint32_t usb_cdc_id, const struct usb_setup_request *req);
154 static struct pios_usb_ifops usb_cdc_data_ifops = {
155 .init = PIOS_USB_CDC_DATA_IF_Init,
156 .deinit = PIOS_USB_CDC_DATA_IF_DeInit,
157 .setup = PIOS_USB_CDC_DATA_IF_Setup,
158 .ctrl_data_out = PIOS_USB_CDC_DATA_IF_CtrlDataOut,
161 static uint32_t pios_usb_cdc_id;
163 int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id, const struct pios_usb_cdc_cfg *cfg, uint32_t lower_id)
165 PIOS_Assert(usbcdc_id);
166 PIOS_Assert(cfg);
168 struct pios_usb_cdc_dev *usb_cdc_dev;
170 usb_cdc_dev = (struct pios_usb_cdc_dev *)PIOS_USB_CDC_alloc();
171 if (!usb_cdc_dev) {
172 goto out_fail;
175 /* Bind the configuration to the device instance */
176 usb_cdc_dev->cfg = cfg;
177 usb_cdc_dev->lower_id = lower_id;
179 pios_usb_cdc_id = (uint32_t)usb_cdc_dev;
181 /* Rx and Tx are not active yet */
182 usb_cdc_dev->rx_active = false;
183 usb_cdc_dev->tx_active = false;
185 /* Clear stats */
186 usb_cdc_dev->rx_dropped = 0;
187 usb_cdc_dev->rx_oversize = 0;
189 /* Initialize the uart state */
190 usb_cdc_dev->prev_uart_state = 0;
192 /* Register class specific interface callbacks with the USBHOOK layer */
193 usb_cdc_dev->usb_ctrl_if_enabled = false;
194 PIOS_USBHOOK_RegisterIfOps(cfg->ctrl_if, &usb_cdc_ctrl_ifops, (uint32_t)usb_cdc_dev);
196 /* Register class specific interface callbacks with the USBHOOK layer */
197 usb_cdc_dev->usb_data_if_enabled = false;
198 PIOS_USBHOOK_RegisterIfOps(cfg->data_if, &usb_cdc_data_ifops, (uint32_t)usb_cdc_dev);
200 *usbcdc_id = (uint32_t)usb_cdc_dev;
202 return 0;
204 out_fail:
205 return -1;
208 static bool PIOS_USB_CDC_SendData(struct pios_usb_cdc_dev *usb_cdc_dev)
210 uint16_t bytes_to_tx;
212 if (!usb_cdc_dev->tx_out_cb) {
213 return false;
216 bool need_yield = false;
217 bytes_to_tx = (usb_cdc_dev->tx_out_cb)(usb_cdc_dev->tx_out_context,
218 usb_cdc_dev->tx_packet_buffer,
219 sizeof(usb_cdc_dev->tx_packet_buffer),
220 NULL,
221 &need_yield);
222 if (bytes_to_tx == 0) {
223 return false;
227 * Mark this endpoint as being tx active _before_ actually transmitting
228 * to make sure we don't race with the Tx completion interrupt
230 usb_cdc_dev->tx_active = true;
232 PIOS_USBHOOK_EndpointTx(usb_cdc_dev->cfg->data_tx_ep,
233 usb_cdc_dev->tx_packet_buffer,
234 bytes_to_tx);
236 #if defined(PIOS_INCLUDE_FREERTOS)
237 if (need_yield) {
238 vPortYield();
240 #endif /* PIOS_INCLUDE_FREERTOS */
242 return true;
245 static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail)
247 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
249 bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
251 PIOS_Assert(valid);
253 /* Make sure this USB interface has been initialized */
254 if (!usb_cdc_dev->usb_data_if_enabled) {
255 return;
258 if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) {
259 return;
262 // If endpoint was stalled and there is now space make it valid
263 if (!usb_cdc_dev->rx_active && (rx_bytes_avail >= PIOS_USB_BOARD_CDC_DATA_LENGTH)) {
264 PIOS_USBHOOK_EndpointRx(usb_cdc_dev->cfg->data_rx_ep,
265 usb_cdc_dev->rx_packet_buffer,
266 sizeof(usb_cdc_dev->rx_packet_buffer));
267 usb_cdc_dev->rx_active = true;
271 static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, __attribute__((unused)) uint16_t tx_bytes_avail)
273 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
275 bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
277 PIOS_Assert(valid);
279 /* Make sure this USB interface has been initialized */
280 if (!usb_cdc_dev->usb_data_if_enabled) {
281 return;
284 if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) {
285 return;
288 if (!usb_cdc_dev->tx_active) {
289 /* Transmitter is not currently active, send a report */
290 PIOS_USB_CDC_SendData(usb_cdc_dev);
294 static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context)
296 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
298 bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
300 PIOS_Assert(valid);
303 * Order is important in these assignments since ISR uses _cb
304 * field to determine if it's ok to dereference _cb and _context
306 usb_cdc_dev->rx_in_context = context;
307 usb_cdc_dev->rx_in_cb = rx_in_cb;
310 static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context)
312 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
314 bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
316 PIOS_Assert(valid);
319 * Order is important in these assignments since ISR uses _cb
320 * field to determine if it's ok to dereference _cb and _context
322 usb_cdc_dev->tx_out_context = context;
323 usb_cdc_dev->tx_out_cb = tx_out_cb;
326 static bool PIOS_USB_CDC_CTRL_EP_IN_Callback(uint32_t usb_cdc_id, uint8_t epnum, uint16_t len);
328 static void PIOS_USB_CDC_CTRL_IF_Init(uint32_t usb_cdc_id)
330 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usb_cdc_id;
332 if (!PIOS_USB_CDC_validate(usb_cdc_dev)) {
333 return;
336 /* Register endpoint specific callbacks with the USBHOOK layer */
337 PIOS_USBHOOK_RegisterEpInCallback(usb_cdc_dev->cfg->ctrl_tx_ep,
338 sizeof(usb_cdc_dev->ctrl_tx_packet_buffer),
339 PIOS_USB_CDC_CTRL_EP_IN_Callback,
340 (uint32_t)usb_cdc_dev);
341 usb_cdc_dev->usb_ctrl_if_enabled = true;
344 static void PIOS_USB_CDC_CTRL_IF_DeInit(uint32_t usb_cdc_id)
346 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usb_cdc_id;
348 if (!PIOS_USB_CDC_validate(usb_cdc_dev)) {
349 return;
352 /* DeRegister endpoint specific callbacks with the USBHOOK layer */
353 usb_cdc_dev->usb_data_if_enabled = false;
356 static uint8_t cdc_altset;
357 static struct usb_cdc_line_coding line_coding = {
358 .dwDTERate = htousbl(57600),
359 .bCharFormat = USB_CDC_LINE_CODING_STOP_1,
360 .bParityType = USB_CDC_LINE_CODING_PARITY_NONE,
361 .bDataBits = 8,
364 static uint16_t control_line_state;
366 static bool PIOS_USB_CDC_CTRL_IF_Setup(uint32_t usb_cdc_id, struct usb_setup_request *req)
368 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usb_cdc_id;
370 if (!PIOS_USB_CDC_validate(usb_cdc_dev)) {
371 return false;
374 /* Make sure this is a request for an interface we know about */
375 uint8_t ifnum = req->wIndex & 0xFF;
376 if (ifnum != usb_cdc_dev->cfg->ctrl_if) {
377 return false;
380 switch (req->bmRequestType & (USB_REQ_TYPE_MASK | USB_REQ_RECIPIENT_MASK)) {
381 case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_INTERFACE):
382 switch (req->bRequest) {
383 case USB_REQ_GET_INTERFACE:
384 PIOS_USBHOOK_CtrlTx(&cdc_altset, 1);
385 break;
386 case USB_REQ_SET_INTERFACE:
387 cdc_altset = (uint8_t)(req->wValue);
388 break;
389 default:
390 /* Unhandled standard request */
391 return false;
393 break;
395 break;
396 case (USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE):
397 switch (req->bRequest) {
398 case USB_CDC_REQ_SET_LINE_CODING:
399 PIOS_USBHOOK_CtrlRx((uint8_t *)&line_coding, sizeof(line_coding));
400 break;
401 case USB_CDC_REQ_GET_LINE_CODING:
402 PIOS_USBHOOK_CtrlTx((uint8_t *)&line_coding, sizeof(line_coding));
403 break;
404 case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
405 control_line_state = req->wValue;
406 break;
407 default:
408 /* Unhandled class request */
409 return false;
411 break;
413 break;
414 default:
415 /* Unhandled request */
416 return false;
419 return true;
422 static bool PIOS_USB_CDC_Available(uint32_t usbcdc_id)
424 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
426 bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
428 PIOS_Assert(valid);
430 return PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id) &&
431 (control_line_state & USB_CDC_CONTROL_LINE_STATE_DTE_PRESENT);
435 * Called *after* the data has been written to the buffer provided in the setup stage. The
436 * setup request is passed in here again so we know *which* EP0 data out has just completed.
438 static void PIOS_USB_CDC_CTRL_IF_CtrlDataOut(uint32_t usb_cdc_id, const struct usb_setup_request *req)
440 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usb_cdc_id;
442 if (!PIOS_USB_CDC_validate(usb_cdc_dev)) {
443 return;
446 /* Make sure this is a request for an interface we know about */
447 uint8_t ifnum = req->wIndex & 0xFF;
448 if (ifnum != usb_cdc_dev->cfg->ctrl_if) {
449 return;
452 switch (req->bmRequestType & (USB_REQ_TYPE_MASK | USB_REQ_RECIPIENT_MASK)) {
453 case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_INTERFACE):
454 switch (req->bRequest) {
455 default:
456 /* Unhandled standard request */
457 return;
459 break;
461 break;
462 case (USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE):
463 switch (req->bRequest) {
464 case USB_CDC_REQ_SET_LINE_CODING:
466 * If we cared to, this is where we would apply the new line coding
467 * that is now stored in the line_coding struct. This could be used
468 * to notify the upper COM layer that the baud rate has changed. This
469 * may be useful in the case of a COM USB bridge where we would
470 * auto-adjust the USART baud rate based on the line coding set here.
472 break;
473 default:
474 /* Unhandled class request */
475 return;
477 break;
479 break;
480 default:
481 /* Unhandled request */
482 return;
486 static struct usb_cdc_serial_state_report uart_state = {
487 .bmRequestType = 0xA1,
488 .bNotification = USB_CDC_NOTIFICATION_SERIAL_STATE,
489 .wValue = 0,
490 .wIndex = htousbs(1),
491 .wLength = htousbs(2),
492 .bmUartState = htousbs(0),
495 static bool PIOS_USB_CDC_CTRL_EP_IN_Callback(
496 __attribute__((unused)) uint32_t usb_cdc_id,
497 __attribute__((unused)) uint8_t epnum,
498 __attribute__((unused)) uint16_t len)
500 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
502 bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
504 PIOS_Assert(valid);
506 /* Give back UART State Bitmap */
507 /* UART State Bitmap
508 * 15-7: reserved
509 * 6: bOverRun overrun error
510 * 5: bParity parity error
511 * 4: bFraming framing error
512 * 3: bRingSignal RI
513 * 2: bBreak break reception
514 * 1: bTxCarrier DSR
515 * 0: bRxCarrier DCD
518 /* Currently, we only handle TxCarrier and RxCarrier reporting */
519 uint16_t new_uart_state = 0;
520 if (usb_cdc_dev->tx_out_cb) {
521 /* Someone is going to providing FC->PC data, advertise an RxCarrier to the host */
522 new_uart_state |= 0x1;
524 if (usb_cdc_dev->rx_in_cb) {
525 /* Someone is consuming PC->FC data, advertise a TxCarrier to the host */
526 new_uart_state |= 0x2;
529 /* Has anything changed since we last sent a notification? */
530 if ((new_uart_state ^ usb_cdc_dev->prev_uart_state) & 0x3) {
531 usb_cdc_dev->prev_uart_state = new_uart_state;
533 uart_state.bmUartState = htousbs(new_uart_state);
535 PIOS_USBHOOK_EndpointTx(usb_cdc_dev->cfg->ctrl_tx_ep,
536 (uint8_t *)&uart_state,
537 sizeof(uart_state));
540 return true;
543 static bool PIOS_USB_CDC_DATA_EP_IN_Callback(uint32_t usb_cdc_id, uint8_t epnum, uint16_t len);
544 static bool PIOS_USB_CDC_DATA_EP_OUT_Callback(uint32_t usb_cdc_id, uint8_t epnum, uint16_t len);
546 static void PIOS_USB_CDC_DATA_IF_Init(uint32_t usb_cdc_id)
548 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usb_cdc_id;
550 if (!PIOS_USB_CDC_validate(usb_cdc_dev)) {
551 return;
554 /* Register endpoint specific callbacks with the USBHOOK layer */
555 PIOS_USBHOOK_RegisterEpInCallback(usb_cdc_dev->cfg->data_tx_ep,
556 sizeof(usb_cdc_dev->tx_packet_buffer),
557 PIOS_USB_CDC_DATA_EP_IN_Callback,
558 (uint32_t)usb_cdc_dev);
559 PIOS_USBHOOK_RegisterEpOutCallback(usb_cdc_dev->cfg->data_rx_ep,
560 sizeof(usb_cdc_dev->rx_packet_buffer),
561 PIOS_USB_CDC_DATA_EP_OUT_Callback,
562 (uint32_t)usb_cdc_dev);
563 usb_cdc_dev->usb_data_if_enabled = true;
566 static void PIOS_USB_CDC_DATA_IF_DeInit(uint32_t usb_cdc_id)
568 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usb_cdc_id;
570 if (!PIOS_USB_CDC_validate(usb_cdc_dev)) {
571 return;
574 /* DeRegister endpoint specific callbacks with the USBHOOK layer */
575 usb_cdc_dev->usb_data_if_enabled = false;
576 PIOS_USBHOOK_DeRegisterEpInCallback(usb_cdc_dev->cfg->data_tx_ep);
577 PIOS_USBHOOK_DeRegisterEpOutCallback(usb_cdc_dev->cfg->data_rx_ep);
580 static bool PIOS_USB_CDC_DATA_IF_Setup(
581 __attribute__((unused)) uint32_t usb_cdc_id,
582 __attribute__((unused)) struct usb_setup_request *req)
584 /* There are no valid EP0 transactions for CDC DATA interfaces */
585 PIOS_Assert(0);
587 return false;
591 * Called *after* the data has been written to the buffer provided in the setup stage. The
592 * setup request is passed in here again so we know *which* EP0 data out has just completed.
594 static void PIOS_USB_CDC_DATA_IF_CtrlDataOut(
595 __attribute__((unused)) uint32_t usb_cdc_id,
596 __attribute__((unused)) const struct usb_setup_request *req)
598 /* CDC DATA interfaces don't have any OUT data stages on the control endpoint */
599 PIOS_Assert(0);
603 * @brief Callback used to indicate a transmission from device INto host completed
604 * Checks if any data remains, pads it into HID packet and sends.
606 static bool PIOS_USB_CDC_DATA_EP_IN_Callback(
607 __attribute__((unused)) uint32_t usb_cdc_id,
608 __attribute__((unused)) uint8_t epnum,
609 __attribute__((unused)) uint16_t len)
611 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
613 bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
615 PIOS_Assert(valid);
617 bool rc = PIOS_USB_CDC_SendData(usb_cdc_dev);
618 if (!rc) {
619 /* No additional data was transmitted, note that tx is no longer active */
620 usb_cdc_dev->tx_active = false;
623 return rc;
626 static bool PIOS_USB_CDC_DATA_EP_OUT_Callback(
627 __attribute__((unused)) uint32_t usb_cdc_id,
628 __attribute__((unused)) uint8_t epnum,
629 uint16_t len)
631 struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
633 if (!PIOS_USB_CDC_validate(usb_cdc_dev)) {
634 return false;
637 if (len > sizeof(usb_cdc_dev->rx_packet_buffer)) {
638 len = sizeof(usb_cdc_dev->rx_packet_buffer);
641 if (!usb_cdc_dev->rx_in_cb) {
642 /* No Rx call back registered, disable the receiver */
643 usb_cdc_dev->rx_active = false;
644 return false;
647 uint16_t headroom;
648 bool need_yield = false;
649 uint16_t bytes_rxed;
650 bytes_rxed = (usb_cdc_dev->rx_in_cb)(usb_cdc_dev->rx_in_context,
651 usb_cdc_dev->rx_packet_buffer,
652 len,
653 &headroom,
654 &need_yield);
656 if (bytes_rxed < len) {
657 /* Lost bytes on rx */
658 usb_cdc_dev->rx_dropped += (len - bytes_rxed);
661 bool rc;
662 if (headroom >= sizeof(usb_cdc_dev->rx_packet_buffer)) {
663 /* We have room for a maximum length message */
664 PIOS_USBHOOK_EndpointRx(usb_cdc_dev->cfg->data_rx_ep,
665 usb_cdc_dev->rx_packet_buffer,
666 sizeof(usb_cdc_dev->rx_packet_buffer));
667 rc = true;
668 } else {
669 /* Not enough room left for a message, apply backpressure */
670 usb_cdc_dev->rx_active = false;
671 rc = false;
674 #if defined(PIOS_INCLUDE_FREERTOS)
675 if (need_yield) {
676 vPortYield();
678 #endif /* PIOS_INCLUDE_FREERTOS */
680 return rc;
683 #endif /* PIOS_INCLUDE_USB_CDC */