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
;
97 uint8_t ctrl_tx_packet_buffer
[PIOS_USB_BOARD_CDC_MGMT_LENGTH
] __attribute__((aligned(4)));
100 uint32_t rx_oversize
;
103 * Used to hold the current state of the simulated UART. Changes to this
104 * variable may trigger new USB CDC Notification packets to be sent to the host.
106 volatile uint16_t prev_uart_state
;
109 static bool PIOS_USB_CDC_validate(struct pios_usb_cdc_dev
*usb_cdc_dev
)
111 return usb_cdc_dev
&& (usb_cdc_dev
->magic
== PIOS_USB_CDC_DEV_MAGIC
);
114 #if defined(PIOS_INCLUDE_FREERTOS)
115 static struct pios_usb_cdc_dev
*PIOS_USB_CDC_alloc(void)
117 struct pios_usb_cdc_dev
*usb_cdc_dev
;
119 usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_malloc(sizeof(struct pios_usb_cdc_dev
));
124 memset(usb_cdc_dev
, 0, sizeof(struct pios_usb_cdc_dev
));
125 usb_cdc_dev
->magic
= PIOS_USB_CDC_DEV_MAGIC
;
129 static struct pios_usb_cdc_dev pios_usb_cdc_devs
[PIOS_USB_CDC_MAX_DEVS
];
130 static uint8_t pios_usb_cdc_num_devs
;
131 static struct pios_usb_cdc_dev
*PIOS_USB_CDC_alloc(void)
133 struct pios_usb_cdc_dev
*usb_cdc_dev
;
135 if (pios_usb_cdc_num_devs
>= PIOS_USB_CDC_MAX_DEVS
) {
139 usb_cdc_dev
= &pios_usb_cdc_devs
[pios_usb_cdc_num_devs
++];
141 memset(usb_cdc_dev
, 0, sizeof(struct pios_usb_cdc_dev
));
142 usb_cdc_dev
->magic
= PIOS_USB_CDC_DEV_MAGIC
;
146 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
148 /* Implement USB_IFOPS for CDC Control Interface */
149 static void PIOS_USB_CDC_CTRL_IF_Init(uint32_t usb_cdc_id
);
150 static void PIOS_USB_CDC_CTRL_IF_DeInit(uint32_t usb_cdc_id
);
151 static bool PIOS_USB_CDC_CTRL_IF_Setup(uint32_t usb_cdc_id
, struct usb_setup_request
*req
);
152 static void PIOS_USB_CDC_CTRL_IF_CtrlDataOut(uint32_t usb_cdc_id
, const struct usb_setup_request
*req
);
154 static struct pios_usb_ifops usb_cdc_ctrl_ifops
= {
155 .init
= PIOS_USB_CDC_CTRL_IF_Init
,
156 .deinit
= PIOS_USB_CDC_CTRL_IF_DeInit
,
157 .setup
= PIOS_USB_CDC_CTRL_IF_Setup
,
158 .ctrl_data_out
= PIOS_USB_CDC_CTRL_IF_CtrlDataOut
,
161 /* Implement USB_IFOPS for CDC Data Interface */
162 static void PIOS_USB_CDC_DATA_IF_Init(uint32_t usb_cdc_id
);
163 static void PIOS_USB_CDC_DATA_IF_DeInit(uint32_t usb_cdc_id
);
164 static bool PIOS_USB_CDC_DATA_IF_Setup(uint32_t usb_cdc_id
, struct usb_setup_request
*req
);
165 static void PIOS_USB_CDC_DATA_IF_CtrlDataOut(uint32_t usb_cdc_id
, const struct usb_setup_request
*req
);
167 static struct pios_usb_ifops usb_cdc_data_ifops
= {
168 .init
= PIOS_USB_CDC_DATA_IF_Init
,
169 .deinit
= PIOS_USB_CDC_DATA_IF_DeInit
,
170 .setup
= PIOS_USB_CDC_DATA_IF_Setup
,
171 .ctrl_data_out
= PIOS_USB_CDC_DATA_IF_CtrlDataOut
,
174 static uint32_t pios_usb_cdc_id
;
176 int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id
, const struct pios_usb_cdc_cfg
*cfg
, uint32_t lower_id
)
178 PIOS_Assert(usbcdc_id
);
181 struct pios_usb_cdc_dev
*usb_cdc_dev
;
183 usb_cdc_dev
= (struct pios_usb_cdc_dev
*)PIOS_USB_CDC_alloc();
188 /* Bind the configuration to the device instance */
189 usb_cdc_dev
->cfg
= cfg
;
190 usb_cdc_dev
->lower_id
= lower_id
;
192 pios_usb_cdc_id
= (uint32_t)usb_cdc_dev
;
194 /* Tx is not active yet */
195 usb_cdc_dev
->tx_active
= false;
198 usb_cdc_dev
->rx_dropped
= 0;
199 usb_cdc_dev
->rx_oversize
= 0;
201 /* Initialize the uart state */
202 usb_cdc_dev
->prev_uart_state
= 0;
204 /* Register class specific interface callbacks with the USBHOOK layer */
205 usb_cdc_dev
->usb_ctrl_if_enabled
= false;
206 PIOS_USBHOOK_RegisterIfOps(cfg
->ctrl_if
, &usb_cdc_ctrl_ifops
, (uint32_t)usb_cdc_dev
);
208 /* Register class specific interface callbacks with the USBHOOK layer */
209 usb_cdc_dev
->usb_data_if_enabled
= false;
210 PIOS_USBHOOK_RegisterIfOps(cfg
->data_if
, &usb_cdc_data_ifops
, (uint32_t)usb_cdc_dev
);
212 PIOS_USB_RegisterConnectionStateCallback(PIOS_USB_CDC_ChangeConnectionState
, (uint32_t)usb_cdc_dev
);
214 *usbcdc_id
= (uint32_t)usb_cdc_dev
;
222 static bool PIOS_USB_CDC_SendData(struct pios_usb_cdc_dev
*usb_cdc_dev
)
224 uint16_t bytes_to_tx
;
226 if (!usb_cdc_dev
->tx_out_cb
) {
230 bool need_yield
= false;
231 bytes_to_tx
= (usb_cdc_dev
->tx_out_cb
)(usb_cdc_dev
->tx_out_context
,
232 usb_cdc_dev
->tx_packet_buffer
,
233 sizeof(usb_cdc_dev
->tx_packet_buffer
),
236 if (bytes_to_tx
== 0) {
241 * Mark this endpoint as being tx active _before_ actually transmitting
242 * to make sure we don't race with the Tx completion interrupt
244 usb_cdc_dev
->tx_active
= true;
246 PIOS_USBHOOK_EndpointTx(usb_cdc_dev
->cfg
->data_tx_ep
,
247 usb_cdc_dev
->tx_packet_buffer
,
250 #if defined(PIOS_INCLUDE_FREERTOS)
254 #endif /* PIOS_INCLUDE_FREERTOS */
259 static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id
, uint16_t rx_bytes_avail
)
261 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
263 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
267 /* Make sure this USB interface has been initialized */
268 if (!usb_cdc_dev
->usb_data_if_enabled
) {
272 if (!PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
)) {
276 // If endpoint was stalled and there is now space make it valid
277 if ((PIOS_USBHOOK_EndpointGetStatus(usb_cdc_dev
->cfg
->data_rx_ep
) != USB_OTG_EP_RX_VALID
)
278 && (rx_bytes_avail
>= PIOS_USB_BOARD_CDC_DATA_LENGTH
)) {
279 PIOS_USBHOOK_EndpointRx(usb_cdc_dev
->cfg
->data_rx_ep
,
280 usb_cdc_dev
->rx_packet_buffer
,
281 sizeof(usb_cdc_dev
->rx_packet_buffer
));
285 static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id
, __attribute__((unused
)) uint16_t tx_bytes_avail
)
287 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
289 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
293 /* Make sure this USB interface has been initialized */
294 if (!usb_cdc_dev
->usb_data_if_enabled
) {
298 if (!PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
)) {
302 if (!usb_cdc_dev
->tx_active
) {
303 /* Transmitter is not currently active, send a report */
304 PIOS_USB_CDC_SendData(usb_cdc_dev
);
308 static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id
, pios_com_callback rx_in_cb
, uint32_t context
)
310 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
312 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
317 * Order is important in these assignments since ISR uses _cb
318 * field to determine if it's ok to dereference _cb and _context
320 usb_cdc_dev
->rx_in_context
= context
;
321 usb_cdc_dev
->rx_in_cb
= rx_in_cb
;
324 static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id
, pios_com_callback tx_out_cb
, uint32_t context
)
326 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
328 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
333 * Order is important in these assignments since ISR uses _cb
334 * field to determine if it's ok to dereference _cb and _context
336 usb_cdc_dev
->tx_out_context
= context
;
337 usb_cdc_dev
->tx_out_cb
= tx_out_cb
;
340 static void PIOS_USB_CDC_RegisterCtrlLineCallback(uint32_t usbcdc_id
, pios_com_callback_ctrl_line ctrl_line_cb
, uint32_t context
)
342 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
344 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
349 * Order is important in these assignments since ISR uses _cb
350 * field to determine if it's ok to dereference _cb and _context
352 usb_cdc_dev
->ctrl_line_context
= context
;
353 usb_cdc_dev
->ctrl_line_cb
= ctrl_line_cb
;
356 static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id
, pios_com_callback_baud_rate baud_rate_cb
, uint32_t context
)
358 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
360 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
365 * Order is important in these assignments since ISR uses _cb
366 * field to determine if it's ok to dereference _cb and _context
368 usb_cdc_dev
->baud_rate_context
= context
;
369 usb_cdc_dev
->baud_rate_cb
= baud_rate_cb
;
372 static bool PIOS_USB_CDC_CTRL_EP_IN_Callback(uint32_t usb_cdc_id
, uint8_t epnum
, uint16_t len
);
374 static void PIOS_USB_CDC_CTRL_IF_Init(uint32_t usb_cdc_id
)
376 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
378 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
382 /* Register endpoint specific callbacks with the USBHOOK layer */
383 PIOS_USBHOOK_RegisterEpInCallback(usb_cdc_dev
->cfg
->ctrl_tx_ep
,
384 sizeof(usb_cdc_dev
->ctrl_tx_packet_buffer
),
385 PIOS_USB_CDC_CTRL_EP_IN_Callback
,
386 (uint32_t)usb_cdc_dev
);
387 usb_cdc_dev
->usb_ctrl_if_enabled
= true;
390 static void PIOS_USB_CDC_CTRL_IF_DeInit(uint32_t usb_cdc_id
)
392 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
394 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
398 /* DeRegister endpoint specific callbacks with the USBHOOK layer */
399 usb_cdc_dev
->usb_ctrl_if_enabled
= false;
402 static uint8_t cdc_altset
;
403 static struct usb_cdc_line_coding line_coding
= {
404 .dwDTERate
= htousbl(57600),
405 .bCharFormat
= USB_CDC_LINE_CODING_STOP_1
,
406 .bParityType
= USB_CDC_LINE_CODING_PARITY_NONE
,
410 static uint16_t control_line_state
;
412 static bool PIOS_USB_CDC_CTRL_IF_Setup(uint32_t usb_cdc_id
, struct usb_setup_request
*req
)
414 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
416 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
420 /* Make sure this is a request for an interface we know about */
421 uint8_t ifnum
= req
->wIndex
& 0xFF;
422 if (ifnum
!= usb_cdc_dev
->cfg
->ctrl_if
) {
426 switch (req
->bmRequestType
& (USB_REQ_TYPE_MASK
| USB_REQ_RECIPIENT_MASK
)) {
427 case (USB_REQ_TYPE_STANDARD
| USB_REQ_RECIPIENT_INTERFACE
):
428 switch (req
->bRequest
) {
429 case USB_REQ_GET_INTERFACE
:
430 PIOS_USBHOOK_CtrlTx(&cdc_altset
, 1);
432 case USB_REQ_SET_INTERFACE
:
433 cdc_altset
= (uint8_t)(req
->wValue
);
436 /* Unhandled standard request */
442 case (USB_REQ_TYPE_CLASS
| USB_REQ_RECIPIENT_INTERFACE
):
443 switch (req
->bRequest
) {
444 case USB_CDC_REQ_SET_LINE_CODING
:
445 PIOS_USBHOOK_CtrlRx((uint8_t *)&line_coding
, sizeof(line_coding
));
447 case USB_CDC_REQ_GET_LINE_CODING
:
448 PIOS_USBHOOK_CtrlTx((uint8_t *)&line_coding
, sizeof(line_coding
));
450 case USB_CDC_REQ_SET_CONTROL_LINE_STATE
:
451 control_line_state
= req
->wValue
;
452 if (usb_cdc_dev
->ctrl_line_cb
) {
453 (usb_cdc_dev
->ctrl_line_cb
)(usb_cdc_dev
->ctrl_line_context
,
459 /* Unhandled class request */
466 /* Unhandled request */
473 static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id
)
475 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
477 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
481 return PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
) ? COM_AVAILABLE_RXTX
: COM_AVAILABLE_NONE
;
485 * Called *after* the data has been written to the buffer provided in the setup stage. The
486 * setup request is passed in here again so we know *which* EP0 data out has just completed.
488 static void PIOS_USB_CDC_CTRL_IF_CtrlDataOut(uint32_t usb_cdc_id
, const struct usb_setup_request
*req
)
490 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
492 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
496 /* Make sure this is a request for an interface we know about */
497 uint8_t ifnum
= req
->wIndex
& 0xFF;
498 if (ifnum
!= usb_cdc_dev
->cfg
->ctrl_if
) {
502 switch (req
->bmRequestType
& (USB_REQ_TYPE_MASK
| USB_REQ_RECIPIENT_MASK
)) {
503 case (USB_REQ_TYPE_STANDARD
| USB_REQ_RECIPIENT_INTERFACE
):
504 switch (req
->bRequest
) {
506 /* Unhandled standard request */
512 case (USB_REQ_TYPE_CLASS
| USB_REQ_RECIPIENT_INTERFACE
):
513 switch (req
->bRequest
) {
514 case USB_CDC_REQ_SET_LINE_CODING
:
515 if (usb_cdc_dev
->baud_rate_cb
) {
516 usb_cdc_dev
->baud_rate_cb(usb_cdc_dev
->baud_rate_context
, usbltoh(line_coding
.dwDTERate
));
520 /* Unhandled class request */
527 /* Unhandled request */
532 static struct usb_cdc_serial_state_report uart_state
= {
533 .bmRequestType
= 0xA1,
534 .bNotification
= USB_CDC_NOTIFICATION_SERIAL_STATE
,
536 .wIndex
= htousbs(1),
537 .wLength
= htousbs(2),
538 .bmUartState
= htousbs(0),
541 static bool PIOS_USB_CDC_CTRL_EP_IN_Callback(
542 __attribute__((unused
)) uint32_t usb_cdc_id
,
543 __attribute__((unused
)) uint8_t epnum
,
544 __attribute__((unused
)) uint16_t len
)
546 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
548 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
552 /* Give back UART State Bitmap */
555 * 6: bOverRun overrun error
556 * 5: bParity parity error
557 * 4: bFraming framing error
559 * 2: bBreak break reception
564 /* Currently, we only handle TxCarrier and RxCarrier reporting */
565 uint16_t new_uart_state
= 0;
566 if (usb_cdc_dev
->tx_out_cb
) {
567 /* Someone is going to providing FC->PC data, advertise an RxCarrier to the host */
568 new_uart_state
|= 0x1;
570 if (usb_cdc_dev
->rx_in_cb
) {
571 /* Someone is consuming PC->FC data, advertise a TxCarrier to the host */
572 new_uart_state
|= 0x2;
575 /* Has anything changed since we last sent a notification? */
576 if ((new_uart_state
^ usb_cdc_dev
->prev_uart_state
) & 0x3) {
577 usb_cdc_dev
->prev_uart_state
= new_uart_state
;
579 uart_state
.bmUartState
= htousbs(new_uart_state
);
581 PIOS_USBHOOK_EndpointTx(usb_cdc_dev
->cfg
->ctrl_tx_ep
,
582 (uint8_t *)&uart_state
,
589 static bool PIOS_USB_CDC_DATA_EP_IN_Callback(uint32_t usb_cdc_id
, uint8_t epnum
, uint16_t len
);
590 static bool PIOS_USB_CDC_DATA_EP_OUT_Callback(uint32_t usb_cdc_id
, uint8_t epnum
, uint16_t len
);
592 static void PIOS_USB_CDC_DATA_IF_Init(uint32_t usb_cdc_id
)
594 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
596 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
600 /* Register endpoint specific callbacks with the USBHOOK layer */
601 PIOS_USBHOOK_RegisterEpInCallback(usb_cdc_dev
->cfg
->data_tx_ep
,
602 sizeof(usb_cdc_dev
->tx_packet_buffer
),
603 PIOS_USB_CDC_DATA_EP_IN_Callback
,
604 (uint32_t)usb_cdc_dev
);
605 PIOS_USBHOOK_RegisterEpOutCallback(usb_cdc_dev
->cfg
->data_rx_ep
,
606 sizeof(usb_cdc_dev
->rx_packet_buffer
),
607 PIOS_USB_CDC_DATA_EP_OUT_Callback
,
608 (uint32_t)usb_cdc_dev
);
609 usb_cdc_dev
->usb_data_if_enabled
= true;
610 usb_cdc_dev
->tx_active
= false;
613 static void PIOS_USB_CDC_DATA_IF_DeInit(uint32_t usb_cdc_id
)
615 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usb_cdc_id
;
617 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
621 /* DeRegister endpoint specific callbacks with the USBHOOK layer */
622 usb_cdc_dev
->usb_data_if_enabled
= false;
623 PIOS_USBHOOK_DeRegisterEpInCallback(usb_cdc_dev
->cfg
->data_tx_ep
);
624 PIOS_USBHOOK_DeRegisterEpOutCallback(usb_cdc_dev
->cfg
->data_rx_ep
);
627 static bool PIOS_USB_CDC_DATA_IF_Setup(
628 __attribute__((unused
)) uint32_t usb_cdc_id
,
629 __attribute__((unused
)) struct usb_setup_request
*req
)
631 /* There are no valid EP0 transactions for CDC DATA interfaces */
638 * Called *after* the data has been written to the buffer provided in the setup stage. The
639 * setup request is passed in here again so we know *which* EP0 data out has just completed.
641 static void PIOS_USB_CDC_DATA_IF_CtrlDataOut(
642 __attribute__((unused
)) uint32_t usb_cdc_id
,
643 __attribute__((unused
)) const struct usb_setup_request
*req
)
645 /* CDC DATA interfaces don't have any OUT data stages on the control endpoint */
650 * @brief Callback used to indicate a transmission from device INto host completed
651 * Checks if any data remains, pads it into HID packet and sends.
653 static bool PIOS_USB_CDC_DATA_EP_IN_Callback(
654 __attribute__((unused
)) uint32_t usb_cdc_id
,
655 __attribute__((unused
)) uint8_t epnum
,
656 __attribute__((unused
)) uint16_t len
)
658 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
660 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
664 bool rc
= PIOS_USB_CDC_SendData(usb_cdc_dev
);
666 /* No additional data was transmitted, note that tx is no longer active */
667 usb_cdc_dev
->tx_active
= false;
673 static bool PIOS_USB_CDC_DATA_EP_OUT_Callback(
674 __attribute__((unused
)) uint32_t usb_cdc_id
,
675 __attribute__((unused
)) uint8_t epnum
,
678 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
680 if (!PIOS_USB_CDC_validate(usb_cdc_dev
)) {
684 if (len
> sizeof(usb_cdc_dev
->rx_packet_buffer
)) {
685 len
= sizeof(usb_cdc_dev
->rx_packet_buffer
);
688 if (!usb_cdc_dev
->rx_in_cb
) {
689 /* No Rx call back registered, disable the receiver */
694 bool need_yield
= false;
696 bytes_rxed
= (usb_cdc_dev
->rx_in_cb
)(usb_cdc_dev
->rx_in_context
,
697 usb_cdc_dev
->rx_packet_buffer
,
702 if (bytes_rxed
< len
) {
703 /* Lost bytes on rx */
704 usb_cdc_dev
->rx_dropped
+= (len
- bytes_rxed
);
708 if (headroom
>= sizeof(usb_cdc_dev
->rx_packet_buffer
)) {
709 /* We have room for a maximum length message */
710 PIOS_USBHOOK_EndpointRx(usb_cdc_dev
->cfg
->data_rx_ep
,
711 usb_cdc_dev
->rx_packet_buffer
,
712 sizeof(usb_cdc_dev
->rx_packet_buffer
));
715 /* Not enough room left for a message, apply backpressure */
719 #if defined(PIOS_INCLUDE_FREERTOS)
723 #endif /* PIOS_INCLUDE_FREERTOS */
728 static void PIOS_USB_CDC_ChangeConnectionState(__attribute__((unused
)) bool connected
, uint32_t usbcdc_id
)
730 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
732 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
736 if (usb_cdc_dev
->available_cb
) {
737 (usb_cdc_dev
->available_cb
)(usb_cdc_dev
->available_context
, PIOS_USB_CDC_Available(usbcdc_id
));
742 static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id
, pios_com_callback_available available_cb
, uint32_t context
)
744 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
746 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
751 * Order is important in these assignments since ISR uses _cb
752 * field to determine if it's ok to dereference _cb and _context
754 usb_cdc_dev
->available_context
= context
;
755 usb_cdc_dev
->available_cb
= available_cb
;
758 #endif /* PIOS_INCLUDE_USB_CDC */