2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
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
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
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
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_* */
39 #include "usb_core.h" /* USB_OTG_EP_RX_VALID */
41 /* Implement COM layer driver API */
42 static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id
, pios_com_callback tx_out_cb
, uint32_t context
);
43 static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id
, pios_com_callback rx_in_cb
, uint32_t context
);
44 static void PIOS_USB_CDC_RegisterCtrlLineCallback(uint32_t usbcdc_id
, pios_com_callback_ctrl_line ctrl_line_cb
, uint32_t context
);
45 static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id
, pios_com_callback_baud_rate baud_rate_cb
, uint32_t context
);
46 static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id
, pios_com_callback_available baud_rate_cb
, uint32_t context
);
47 static void PIOS_USB_CDC_ChangeConnectionState(bool connected
, uint32_t usbcdc_id
);
48 static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id
, uint16_t tx_bytes_avail
);
49 static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id
, uint16_t rx_bytes_avail
);
50 static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id
);
52 const struct pios_com_driver pios_usb_cdc_com_driver
= {
53 .tx_start
= PIOS_USB_CDC_TxStart
,
54 .rx_start
= PIOS_USB_CDC_RxStart
,
55 .bind_tx_cb
= PIOS_USB_CDC_RegisterTxCallback
,
56 .bind_rx_cb
= PIOS_USB_CDC_RegisterRxCallback
,
57 .bind_ctrl_line_cb
= PIOS_USB_CDC_RegisterCtrlLineCallback
,
58 .bind_baud_rate_cb
= PIOS_USB_CDC_RegisterBaudRateCallback
,
59 .available
= PIOS_USB_CDC_Available
,
60 .bind_available_cb
= PIOS_USB_CDC_RegisterAvailableCallback
,
63 enum pios_usb_cdc_dev_magic
{
64 PIOS_USB_CDC_DEV_MAGIC
= 0xAABBCCDD,
67 struct pios_usb_cdc_dev
{
68 enum pios_usb_cdc_dev_magic magic
;
69 const struct pios_usb_cdc_cfg
*cfg
;
73 pios_com_callback rx_in_cb
;
74 uint32_t rx_in_context
;
75 pios_com_callback tx_out_cb
;
76 uint32_t tx_out_context
;
77 pios_com_callback_ctrl_line ctrl_line_cb
;
78 uint32_t ctrl_line_context
;
79 pios_com_callback_baud_rate baud_rate_cb
;
80 uint32_t baud_rate_context
;
81 pios_com_callback_available available_cb
;
82 uint32_t available_context
;
84 bool usb_ctrl_if_enabled
;
85 bool usb_data_if_enabled
;
87 uint8_t rx_packet_buffer
[PIOS_USB_BOARD_CDC_DATA_LENGTH
] __attribute__((aligned(4)));
90 * NOTE: This is -1 as somewhat of a hack. It ensures that we always send packets
91 * that are strictly < maxPacketSize for this interface which means we never have
92 * to bother with zero length packets (ZLP).
94 uint8_t tx_packet_buffer
[PIOS_USB_BOARD_CDC_DATA_LENGTH
- 1] __attribute__((aligned(4)));
95 volatile bool tx_active
;
96 volatile bool rx_active
;
98 uint8_t ctrl_tx_packet_buffer
[PIOS_USB_BOARD_CDC_MGMT_LENGTH
] __attribute__((aligned(4)));
101 uint32_t rx_oversize
;
104 * Used to hold the current state of the simulated UART. Changes to this
105 * variable may trigger new USB CDC Notification packets to be sent to the host.
107 volatile uint16_t prev_uart_state
;
110 static bool PIOS_USB_CDC_validate(struct pios_usb_cdc_dev
*usb_cdc_dev
)
112 return usb_cdc_dev
&& (usb_cdc_dev
->magic
== PIOS_USB_CDC_DEV_MAGIC
);
115 #if defined(PIOS_INCLUDE_FREERTOS)
116 static struct pios_usb_cdc_dev
*PIOS_USB_CDC_alloc(void)
118 struct pios_usb_cdc_dev
*usb_cdc_dev
;
120 usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_malloc(sizeof(struct pios_usb_cdc_dev
));
125 memset(usb_cdc_dev
, 0, sizeof(struct pios_usb_cdc_dev
));
126 usb_cdc_dev
->magic
= PIOS_USB_CDC_DEV_MAGIC
;
130 static struct pios_usb_cdc_dev pios_usb_cdc_devs
[PIOS_USB_CDC_MAX_DEVS
];
131 static uint8_t pios_usb_cdc_num_devs
;
132 static struct pios_usb_cdc_dev
*PIOS_USB_CDC_alloc(void)
134 struct pios_usb_cdc_dev
*usb_cdc_dev
;
136 if (pios_usb_cdc_num_devs
>= PIOS_USB_CDC_MAX_DEVS
) {
140 usb_cdc_dev
= &pios_usb_cdc_devs
[pios_usb_cdc_num_devs
++];
142 memset(usb_cdc_dev
, 0, sizeof(struct pios_usb_cdc_dev
));
143 usb_cdc_dev
->magic
= PIOS_USB_CDC_DEV_MAGIC
;
147 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
149 /* Implement USB_IFOPS for CDC Control Interface */
150 static void PIOS_USB_CDC_CTRL_IF_Init(uint32_t usb_cdc_id
);
151 static void PIOS_USB_CDC_CTRL_IF_DeInit(uint32_t usb_cdc_id
);
152 static bool PIOS_USB_CDC_CTRL_IF_Setup(uint32_t usb_cdc_id
, struct usb_setup_request
*req
);
153 static void PIOS_USB_CDC_CTRL_IF_CtrlDataOut(uint32_t usb_cdc_id
, const struct usb_setup_request
*req
);
155 static struct pios_usb_ifops usb_cdc_ctrl_ifops
= {
156 .init
= PIOS_USB_CDC_CTRL_IF_Init
,
157 .deinit
= PIOS_USB_CDC_CTRL_IF_DeInit
,
158 .setup
= PIOS_USB_CDC_CTRL_IF_Setup
,
159 .ctrl_data_out
= PIOS_USB_CDC_CTRL_IF_CtrlDataOut
,
162 /* Implement USB_IFOPS for CDC Data Interface */
163 static void PIOS_USB_CDC_DATA_IF_Init(uint32_t usb_cdc_id
);
164 static void PIOS_USB_CDC_DATA_IF_DeInit(uint32_t usb_cdc_id
);
165 static bool PIOS_USB_CDC_DATA_IF_Setup(uint32_t usb_cdc_id
, struct usb_setup_request
*req
);
166 static void PIOS_USB_CDC_DATA_IF_CtrlDataOut(uint32_t usb_cdc_id
, const struct usb_setup_request
*req
);
168 static struct pios_usb_ifops usb_cdc_data_ifops
= {
169 .init
= PIOS_USB_CDC_DATA_IF_Init
,
170 .deinit
= PIOS_USB_CDC_DATA_IF_DeInit
,
171 .setup
= PIOS_USB_CDC_DATA_IF_Setup
,
172 .ctrl_data_out
= PIOS_USB_CDC_DATA_IF_CtrlDataOut
,
175 static uint32_t pios_usb_cdc_id
;
177 int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id
, const struct pios_usb_cdc_cfg
*cfg
, uint32_t lower_id
)
179 PIOS_Assert(usbcdc_id
);
182 struct pios_usb_cdc_dev
*usb_cdc_dev
;
184 usb_cdc_dev
= (struct pios_usb_cdc_dev
*)PIOS_USB_CDC_alloc();
189 /* Bind the configuration to the device instance */
190 usb_cdc_dev
->cfg
= cfg
;
191 usb_cdc_dev
->lower_id
= lower_id
;
193 pios_usb_cdc_id
= (uint32_t)usb_cdc_dev
;
195 /* Tx and Rx are not active yet */
196 usb_cdc_dev
->tx_active
= false;
197 usb_cdc_dev
->rx_active
= false;
200 usb_cdc_dev
->rx_dropped
= 0;
201 usb_cdc_dev
->rx_oversize
= 0;
203 /* Initialize the uart state */
204 usb_cdc_dev
->prev_uart_state
= 0;
206 /* Register class specific interface callbacks with the USBHOOK layer */
207 usb_cdc_dev
->usb_ctrl_if_enabled
= false;
208 PIOS_USBHOOK_RegisterIfOps(cfg
->ctrl_if
, &usb_cdc_ctrl_ifops
, (uint32_t)usb_cdc_dev
);
210 /* Register class specific interface callbacks with the USBHOOK layer */
211 usb_cdc_dev
->usb_data_if_enabled
= false;
212 PIOS_USBHOOK_RegisterIfOps(cfg
->data_if
, &usb_cdc_data_ifops
, (uint32_t)usb_cdc_dev
);
214 PIOS_USB_RegisterConnectionStateCallback(PIOS_USB_CDC_ChangeConnectionState
, (uint32_t)usb_cdc_dev
);
216 *usbcdc_id
= (uint32_t)usb_cdc_dev
;
224 static bool PIOS_USB_CDC_SendData(struct pios_usb_cdc_dev
*usb_cdc_dev
)
226 uint16_t bytes_to_tx
;
228 if (!usb_cdc_dev
->tx_out_cb
) {
232 bool need_yield
= false;
233 bytes_to_tx
= (usb_cdc_dev
->tx_out_cb
)(usb_cdc_dev
->tx_out_context
,
234 usb_cdc_dev
->tx_packet_buffer
,
235 sizeof(usb_cdc_dev
->tx_packet_buffer
),
238 if (bytes_to_tx
== 0) {
243 * Mark this endpoint as being tx active _before_ actually transmitting
244 * to make sure we don't race with the Tx completion interrupt
246 usb_cdc_dev
->tx_active
= true;
248 PIOS_USBHOOK_EndpointTx(usb_cdc_dev
->cfg
->data_tx_ep
,
249 usb_cdc_dev
->tx_packet_buffer
,
252 #if defined(PIOS_INCLUDE_FREERTOS)
256 #endif /* PIOS_INCLUDE_FREERTOS */
261 static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id
, uint16_t rx_bytes_avail
)
263 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
265 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
269 /* Make sure this USB interface has been initialized */
270 if (!usb_cdc_dev
->usb_data_if_enabled
) {
274 if (!PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
)) {
278 // If endpoint was stalled and there is now space make it valid
279 if ((PIOS_USBHOOK_EndpointGetStatus(usb_cdc_dev
->cfg
->data_rx_ep
) != USB_OTG_EP_RX_VALID
)
280 && (rx_bytes_avail
>= PIOS_USB_BOARD_CDC_DATA_LENGTH
)) {
281 PIOS_USBHOOK_EndpointRx(usb_cdc_dev
->cfg
->data_rx_ep
,
282 usb_cdc_dev
->rx_packet_buffer
,
283 sizeof(usb_cdc_dev
->rx_packet_buffer
));
284 usb_cdc_dev
->rx_active
= true;
288 static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id
, __attribute__((unused
)) uint16_t tx_bytes_avail
)
290 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
292 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
296 /* Make sure this USB interface has been initialized */
297 if (!usb_cdc_dev
->usb_data_if_enabled
) {
301 if (!PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
)) {
305 if (!usb_cdc_dev
->tx_active
) {
306 /* Transmitter is not currently active, send a report */
307 PIOS_USB_CDC_SendData(usb_cdc_dev
);
311 static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id
, pios_com_callback rx_in_cb
, uint32_t context
)
313 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
315 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
320 * Order is important in these assignments since ISR uses _cb
321 * field to determine if it's ok to dereference _cb and _context
323 usb_cdc_dev
->rx_in_context
= context
;
324 usb_cdc_dev
->rx_in_cb
= rx_in_cb
;
327 static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id
, pios_com_callback tx_out_cb
, uint32_t context
)
329 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
331 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
336 * Order is important in these assignments since ISR uses _cb
337 * field to determine if it's ok to dereference _cb and _context
339 usb_cdc_dev
->tx_out_context
= context
;
340 usb_cdc_dev
->tx_out_cb
= tx_out_cb
;
343 static void PIOS_USB_CDC_RegisterCtrlLineCallback(uint32_t usbcdc_id
, pios_com_callback_ctrl_line ctrl_line_cb
, uint32_t context
)
345 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
347 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
352 * Order is important in these assignments since ISR uses _cb
353 * field to determine if it's ok to dereference _cb and _context
355 usb_cdc_dev
->ctrl_line_context
= context
;
356 usb_cdc_dev
->ctrl_line_cb
= ctrl_line_cb
;
359 static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id
, pios_com_callback_baud_rate baud_rate_cb
, uint32_t context
)
361 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
363 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
368 * Order is important in these assignments since ISR uses _cb
369 * field to determine if it's ok to dereference _cb and _context
371 usb_cdc_dev
->baud_rate_context
= context
;
372 usb_cdc_dev
->baud_rate_cb
= baud_rate_cb
;
375 static bool PIOS_USB_CDC_CTRL_EP_IN_Callback(uint32_t usb_cdc_id
, uint8_t epnum
, uint16_t len
);
377 static void PIOS_USB_CDC_CTRL_IF_Init(uint32_t usb_cdc_id
)
379 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
381 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
385 /* Register endpoint specific callbacks with the USBHOOK layer */
386 PIOS_USBHOOK_RegisterEpInCallback(usb_cdc_dev
->cfg
->ctrl_tx_ep
,
387 sizeof(usb_cdc_dev
->ctrl_tx_packet_buffer
),
388 PIOS_USB_CDC_CTRL_EP_IN_Callback
,
389 (uint32_t)usb_cdc_dev
);
390 usb_cdc_dev
->usb_ctrl_if_enabled
= true;
393 static void PIOS_USB_CDC_CTRL_IF_DeInit(uint32_t usb_cdc_id
)
395 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
397 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
401 /* DeRegister endpoint specific callbacks with the USBHOOK layer */
402 usb_cdc_dev
->usb_ctrl_if_enabled
= false;
405 static uint8_t cdc_altset
;
406 static struct usb_cdc_line_coding line_coding
= {
407 .dwDTERate
= htousbl(57600),
408 .bCharFormat
= USB_CDC_LINE_CODING_STOP_1
,
409 .bParityType
= USB_CDC_LINE_CODING_PARITY_NONE
,
413 static uint16_t control_line_state
;
415 static bool PIOS_USB_CDC_CTRL_IF_Setup(uint32_t usb_cdc_id
, struct usb_setup_request
*req
)
417 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
419 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
423 /* Make sure this is a request for an interface we know about */
424 uint8_t ifnum
= req
->wIndex
& 0xFF;
425 if (ifnum
!= usb_cdc_dev
->cfg
->ctrl_if
) {
429 switch (req
->bmRequestType
& (USB_REQ_TYPE_MASK
| USB_REQ_RECIPIENT_MASK
)) {
430 case (USB_REQ_TYPE_STANDARD
| USB_REQ_RECIPIENT_INTERFACE
):
431 switch (req
->bRequest
) {
432 case USB_REQ_GET_INTERFACE
:
433 PIOS_USBHOOK_CtrlTx(&cdc_altset
, 1);
435 case USB_REQ_SET_INTERFACE
:
436 cdc_altset
= (uint8_t)(req
->wValue
);
439 /* Unhandled standard request */
445 case (USB_REQ_TYPE_CLASS
| USB_REQ_RECIPIENT_INTERFACE
):
446 switch (req
->bRequest
) {
447 case USB_CDC_REQ_SET_LINE_CODING
:
448 PIOS_USBHOOK_CtrlRx((uint8_t *)&line_coding
, sizeof(line_coding
));
450 case USB_CDC_REQ_GET_LINE_CODING
:
451 PIOS_USBHOOK_CtrlTx((uint8_t *)&line_coding
, sizeof(line_coding
));
453 case USB_CDC_REQ_SET_CONTROL_LINE_STATE
:
454 control_line_state
= req
->wValue
;
455 if (usb_cdc_dev
->ctrl_line_cb
) {
456 (usb_cdc_dev
->ctrl_line_cb
)(usb_cdc_dev
->ctrl_line_context
,
462 /* Unhandled class request */
469 /* Unhandled request */
476 static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id
)
478 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
480 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
484 return PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
) ? COM_AVAILABLE_RXTX
: COM_AVAILABLE_NONE
;
488 * Called *after* the data has been written to the buffer provided in the setup stage. The
489 * setup request is passed in here again so we know *which* EP0 data out has just completed.
491 static void PIOS_USB_CDC_CTRL_IF_CtrlDataOut(uint32_t usb_cdc_id
, const struct usb_setup_request
*req
)
493 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
495 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
499 /* Make sure this is a request for an interface we know about */
500 uint8_t ifnum
= req
->wIndex
& 0xFF;
501 if (ifnum
!= usb_cdc_dev
->cfg
->ctrl_if
) {
505 switch (req
->bmRequestType
& (USB_REQ_TYPE_MASK
| USB_REQ_RECIPIENT_MASK
)) {
506 case (USB_REQ_TYPE_STANDARD
| USB_REQ_RECIPIENT_INTERFACE
):
507 switch (req
->bRequest
) {
509 /* Unhandled standard request */
515 case (USB_REQ_TYPE_CLASS
| USB_REQ_RECIPIENT_INTERFACE
):
516 switch (req
->bRequest
) {
517 case USB_CDC_REQ_SET_LINE_CODING
:
518 if (usb_cdc_dev
->baud_rate_cb
) {
519 usb_cdc_dev
->baud_rate_cb(usb_cdc_dev
->baud_rate_context
, usbltoh(line_coding
.dwDTERate
));
523 /* Unhandled class request */
530 /* Unhandled request */
535 static struct usb_cdc_serial_state_report uart_state
= {
536 .bmRequestType
= 0xA1,
537 .bNotification
= USB_CDC_NOTIFICATION_SERIAL_STATE
,
539 .wIndex
= htousbs(1),
540 .wLength
= htousbs(2),
541 .bmUartState
= htousbs(0),
544 static bool PIOS_USB_CDC_CTRL_EP_IN_Callback(
545 __attribute__((unused
)) uint32_t usb_cdc_id
,
546 __attribute__((unused
)) uint8_t epnum
,
547 __attribute__((unused
)) uint16_t len
)
549 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
551 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
555 /* Give back UART State Bitmap */
558 * 6: bOverRun overrun error
559 * 5: bParity parity error
560 * 4: bFraming framing error
562 * 2: bBreak break reception
567 /* Currently, we only handle TxCarrier and RxCarrier reporting */
568 uint16_t new_uart_state
= 0;
569 if (usb_cdc_dev
->tx_out_cb
) {
570 /* Someone is going to providing FC->PC data, advertise an RxCarrier to the host */
571 new_uart_state
|= 0x1;
573 if (usb_cdc_dev
->rx_in_cb
) {
574 /* Someone is consuming PC->FC data, advertise a TxCarrier to the host */
575 new_uart_state
|= 0x2;
578 /* Has anything changed since we last sent a notification? */
579 if ((new_uart_state
^ usb_cdc_dev
->prev_uart_state
) & 0x3) {
580 usb_cdc_dev
->prev_uart_state
= new_uart_state
;
582 uart_state
.bmUartState
= htousbs(new_uart_state
);
584 PIOS_USBHOOK_EndpointTx(usb_cdc_dev
->cfg
->ctrl_tx_ep
,
585 (uint8_t *)&uart_state
,
592 static bool PIOS_USB_CDC_DATA_EP_IN_Callback(uint32_t usb_cdc_id
, uint8_t epnum
, uint16_t len
);
593 static bool PIOS_USB_CDC_DATA_EP_OUT_Callback(uint32_t usb_cdc_id
, uint8_t epnum
, uint16_t len
);
595 static void PIOS_USB_CDC_DATA_IF_Init(uint32_t usb_cdc_id
)
597 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
599 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
603 /* Register endpoint specific callbacks with the USBHOOK layer */
604 PIOS_USBHOOK_RegisterEpInCallback(usb_cdc_dev
->cfg
->data_tx_ep
,
605 sizeof(usb_cdc_dev
->tx_packet_buffer
),
606 PIOS_USB_CDC_DATA_EP_IN_Callback
,
607 (uint32_t)usb_cdc_dev
);
608 PIOS_USBHOOK_RegisterEpOutCallback(usb_cdc_dev
->cfg
->data_rx_ep
,
609 sizeof(usb_cdc_dev
->rx_packet_buffer
),
610 PIOS_USB_CDC_DATA_EP_OUT_Callback
,
611 (uint32_t)usb_cdc_dev
);
612 usb_cdc_dev
->usb_data_if_enabled
= true;
613 usb_cdc_dev
->tx_active
= false;
614 /* Check if rx was previously active, if so we need to reactivate */
615 if (usb_cdc_dev
->rx_active
) {
616 PIOS_USBHOOK_EndpointRx(usb_cdc_dev
->cfg
->data_rx_ep
,
617 usb_cdc_dev
->rx_packet_buffer
,
618 sizeof(usb_cdc_dev
->rx_packet_buffer
));
622 static void PIOS_USB_CDC_DATA_IF_DeInit(uint32_t usb_cdc_id
)
624 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
626 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
630 /* DeRegister endpoint specific callbacks with the USBHOOK layer */
631 usb_cdc_dev
->usb_data_if_enabled
= false;
632 PIOS_USBHOOK_DeRegisterEpInCallback(usb_cdc_dev
->cfg
->data_tx_ep
);
633 PIOS_USBHOOK_DeRegisterEpOutCallback(usb_cdc_dev
->cfg
->data_rx_ep
);
636 static bool PIOS_USB_CDC_DATA_IF_Setup(
637 __attribute__((unused
)) uint32_t usb_cdc_id
,
638 __attribute__((unused
)) struct usb_setup_request
*req
)
640 /* There are no valid EP0 transactions for CDC DATA interfaces */
647 * Called *after* the data has been written to the buffer provided in the setup stage. The
648 * setup request is passed in here again so we know *which* EP0 data out has just completed.
650 static void PIOS_USB_CDC_DATA_IF_CtrlDataOut(
651 __attribute__((unused
)) uint32_t usb_cdc_id
,
652 __attribute__((unused
)) const struct usb_setup_request
*req
)
654 /* CDC DATA interfaces don't have any OUT data stages on the control endpoint */
659 * @brief Callback used to indicate a transmission from device INto host completed
660 * Checks if any data remains, pads it into HID packet and sends.
662 static bool PIOS_USB_CDC_DATA_EP_IN_Callback(
663 __attribute__((unused
)) uint32_t usb_cdc_id
,
664 __attribute__((unused
)) uint8_t epnum
,
665 __attribute__((unused
)) uint16_t len
)
667 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
669 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
673 bool rc
= PIOS_USB_CDC_SendData(usb_cdc_dev
);
675 /* No additional data was transmitted, note that tx is no longer active */
676 usb_cdc_dev
->tx_active
= false;
682 static bool PIOS_USB_CDC_DATA_EP_OUT_Callback(
683 __attribute__((unused
)) uint32_t usb_cdc_id
,
684 __attribute__((unused
)) uint8_t epnum
,
687 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
689 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
693 if (len
> sizeof(usb_cdc_dev
->rx_packet_buffer
)) {
694 len
= sizeof(usb_cdc_dev
->rx_packet_buffer
);
697 if (!usb_cdc_dev
->rx_in_cb
) {
698 /* No Rx call back registered, disable the receiver */
703 bool need_yield
= false;
705 bytes_rxed
= (usb_cdc_dev
->rx_in_cb
)(usb_cdc_dev
->rx_in_context
,
706 usb_cdc_dev
->rx_packet_buffer
,
711 if (bytes_rxed
< len
) {
712 /* Lost bytes on rx */
713 usb_cdc_dev
->rx_dropped
+= (len
- bytes_rxed
);
717 if (headroom
>= sizeof(usb_cdc_dev
->rx_packet_buffer
)) {
718 /* We have room for a maximum length message */
719 PIOS_USBHOOK_EndpointRx(usb_cdc_dev
->cfg
->data_rx_ep
,
720 usb_cdc_dev
->rx_packet_buffer
,
721 sizeof(usb_cdc_dev
->rx_packet_buffer
));
723 usb_cdc_dev
->rx_active
= true;
725 /* Not enough room left for a message, apply backpressure */
727 usb_cdc_dev
->rx_active
= false;
730 #if defined(PIOS_INCLUDE_FREERTOS)
734 #endif /* PIOS_INCLUDE_FREERTOS */
739 static void PIOS_USB_CDC_ChangeConnectionState(__attribute__((unused
)) bool connected
, uint32_t usbcdc_id
)
741 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
743 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
747 if (usb_cdc_dev
->available_cb
) {
748 (usb_cdc_dev
->available_cb
)(usb_cdc_dev
->available_context
, PIOS_USB_CDC_Available(usbcdc_id
));
753 static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id
, pios_com_callback_available available_cb
, uint32_t context
)
755 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
757 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
762 * Order is important in these assignments since ISR uses _cb
763 * field to determine if it's ok to dereference _cb and _context
765 usb_cdc_dev
->available_context
= context
;
766 usb_cdc_dev
->available_cb
= available_cb
;
769 #endif /* PIOS_INCLUDE_USB_CDC */