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 */
39 /* STM32 USB Library Definitions */
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_RegisterBaudRateCallback(uint32_t usbcdc_id
, pios_com_callback_baud_rate baud_rate_cb
, uint32_t context
);
45 static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id
, pios_com_callback_available baud_rate_cb
, uint32_t context
);
46 static void PIOS_USB_CDC_ChangeConnectionState(bool connected
, uint32_t usbcdc_id
);
47 static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id
, uint16_t tx_bytes_avail
);
48 static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id
, uint16_t rx_bytes_avail
);
49 static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id
);
51 const struct pios_com_driver pios_usb_cdc_com_driver
= {
52 .tx_start
= PIOS_USB_CDC_TxStart
,
53 .rx_start
= PIOS_USB_CDC_RxStart
,
54 .bind_tx_cb
= PIOS_USB_CDC_RegisterTxCallback
,
55 .bind_rx_cb
= PIOS_USB_CDC_RegisterRxCallback
,
56 .bind_baud_rate_cb
= PIOS_USB_CDC_RegisterBaudRateCallback
,
57 .available
= PIOS_USB_CDC_Available
,
58 .bind_available_cb
= PIOS_USB_CDC_RegisterAvailableCallback
,
61 enum pios_usb_cdc_dev_magic
{
62 PIOS_USB_CDC_DEV_MAGIC
= 0xAABBCCDD,
65 struct pios_usb_cdc_dev
{
66 enum pios_usb_cdc_dev_magic magic
;
67 const struct pios_usb_cdc_cfg
*cfg
;
71 pios_com_callback rx_in_cb
;
72 uint32_t rx_in_context
;
73 pios_com_callback tx_out_cb
;
74 uint32_t tx_out_context
;
76 pios_com_callback_baud_rate baud_rate_cb
;
77 uint32_t baud_rate_context
;
78 pios_com_callback_available available_cb
;
79 uint32_t available_context
;
81 uint8_t rx_packet_buffer
[PIOS_USB_BOARD_CDC_DATA_LENGTH
];
83 * NOTE: This is -1 as somewhat of a hack. It ensures that we always send packets
84 * that are strictly < maxPacketSize for this interface which means we never have
85 * to bother with zero length packets (ZLP).
87 uint8_t tx_packet_buffer
[PIOS_USB_BOARD_CDC_DATA_LENGTH
- 1];
93 static bool PIOS_USB_CDC_validate(struct pios_usb_cdc_dev
*usb_cdc_dev
)
95 return usb_cdc_dev
->magic
== PIOS_USB_CDC_DEV_MAGIC
;
98 #if defined(PIOS_INCLUDE_FREERTOS)
99 static struct pios_usb_cdc_dev
*PIOS_USB_CDC_alloc(void)
101 struct pios_usb_cdc_dev
*usb_cdc_dev
;
103 usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_malloc(sizeof(struct pios_usb_cdc_dev
));
108 memset(usb_cdc_dev
, 0, sizeof(struct pios_usb_cdc_dev
));
109 usb_cdc_dev
->magic
= PIOS_USB_CDC_DEV_MAGIC
;
113 static struct pios_usb_cdc_dev pios_usb_cdc_devs
[PIOS_USB_CDC_MAX_DEVS
];
114 static uint8_t pios_usb_cdc_num_devs
;
115 static struct pios_usb_cdc_dev
*PIOS_USB_CDC_alloc(void)
117 struct pios_usb_cdc_dev
*usb_cdc_dev
;
119 if (pios_usb_cdc_num_devs
>= PIOS_USB_CDC_MAX_DEVS
) {
123 usb_cdc_dev
= &pios_usb_cdc_devs
[pios_usb_cdc_num_devs
++];
125 memset(usb_cdc_dev
, 0, sizeof(struct pios_usb_cdc_dev
));
126 usb_cdc_dev
->magic
= PIOS_USB_CDC_DEV_MAGIC
;
130 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
132 static void PIOS_USB_CDC_DATA_EP_IN_Callback(void);
133 static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void);
134 static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void);
136 static uint32_t pios_usb_cdc_id
;
138 /* Need a better way to pull these in */
139 extern void(*pEpInt_IN
[7]) (void);
140 extern void(*pEpInt_OUT
[7]) (void);
142 int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id
, const struct pios_usb_cdc_cfg
*cfg
, uint32_t lower_id
)
144 PIOS_Assert(usbcdc_id
);
147 struct pios_usb_cdc_dev
*usb_cdc_dev
;
149 usb_cdc_dev
= (struct pios_usb_cdc_dev
*)PIOS_USB_CDC_alloc();
154 /* Bind the configuration to the device instance */
155 usb_cdc_dev
->cfg
= cfg
;
156 usb_cdc_dev
->lower_id
= lower_id
;
158 pios_usb_cdc_id
= (uint32_t)usb_cdc_dev
;
160 /* Bind lower level callbacks into the USB infrastructure */
161 pEpInt_OUT
[cfg
->ctrl_tx_ep
- 1] = PIOS_USB_CDC_CTRL_EP_IN_Callback
;
162 pEpInt_IN
[cfg
->data_tx_ep
- 1] = PIOS_USB_CDC_DATA_EP_IN_Callback
;
163 pEpInt_OUT
[cfg
->data_rx_ep
- 1] = PIOS_USB_CDC_DATA_EP_OUT_Callback
;
165 PIOS_USB_RegisterConnectionStateCallback(PIOS_USB_CDC_ChangeConnectionState
, (uint32_t)usb_cdc_dev
);
167 *usbcdc_id
= (uint32_t)usb_cdc_dev
;
176 static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id
, pios_com_callback rx_in_cb
, uint32_t context
)
178 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
180 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
185 * Order is important in these assignments since ISR uses _cb
186 * field to determine if it's ok to dereference _cb and _context
188 usb_cdc_dev
->rx_in_context
= context
;
189 usb_cdc_dev
->rx_in_cb
= rx_in_cb
;
192 static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id
, pios_com_callback tx_out_cb
, uint32_t context
)
194 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
196 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
201 * Order is important in these assignments since ISR uses _cb
202 * field to determine if it's ok to dereference _cb and _context
204 usb_cdc_dev
->tx_out_context
= context
;
205 usb_cdc_dev
->tx_out_cb
= tx_out_cb
;
208 static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id
, uint16_t rx_bytes_avail
)
210 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
212 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
216 if (!PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
)) {
220 // If endpoint was stalled and there is now space make it valid
222 if ((GetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
) != EP_RX_VALID
) &&
223 (rx_bytes_avail
>= sizeof(usb_cdc_dev
->rx_packet_buffer
))) {
224 SetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
, EP_RX_VALID
);
229 static void PIOS_USB_CDC_SendData(struct pios_usb_cdc_dev
*usb_cdc_dev
)
231 uint16_t bytes_to_tx
;
233 if (!usb_cdc_dev
->tx_out_cb
) {
237 bool need_yield
= false;
238 bytes_to_tx
= (usb_cdc_dev
->tx_out_cb
)(usb_cdc_dev
->tx_out_context
,
239 usb_cdc_dev
->tx_packet_buffer
,
240 sizeof(usb_cdc_dev
->tx_packet_buffer
),
243 if (bytes_to_tx
== 0) {
247 UserToPMABufferCopy(usb_cdc_dev
->tx_packet_buffer
,
248 GetEPTxAddr(usb_cdc_dev
->cfg
->data_tx_ep
),
250 SetEPTxCount(usb_cdc_dev
->cfg
->data_tx_ep
, bytes_to_tx
);
251 SetEPTxValid(usb_cdc_dev
->cfg
->data_tx_ep
);
253 #if defined(PIOS_INCLUDE_FREERTOS)
257 #endif /* PIOS_INCLUDE_FREERTOS */
260 static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id
, __attribute__((unused
)) uint16_t tx_bytes_avail
)
262 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
264 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
268 if (!PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
)) {
272 if (GetEPTxStatus(usb_cdc_dev
->cfg
->data_tx_ep
) == EP_TX_VALID
) {
273 /* Endpoint is already transmitting */
277 PIOS_USB_CDC_SendData(usb_cdc_dev
);
280 static void PIOS_USB_CDC_DATA_EP_IN_Callback(void)
282 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
284 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
288 PIOS_USB_CDC_SendData(usb_cdc_dev
);
291 static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void)
293 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
295 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
301 /* Get the number of received data on the selected Endpoint */
302 DataLength
= GetEPRxCount(usb_cdc_dev
->cfg
->data_rx_ep
);
303 if (DataLength
> sizeof(usb_cdc_dev
->rx_packet_buffer
)) {
304 usb_cdc_dev
->rx_oversize
++;
305 DataLength
= sizeof(usb_cdc_dev
->rx_packet_buffer
);
308 /* Use the memory interface function to read from the selected endpoint */
309 PMAToUserBufferCopy((uint8_t *)usb_cdc_dev
->rx_packet_buffer
,
310 GetEPRxAddr(usb_cdc_dev
->cfg
->data_rx_ep
),
313 if (!usb_cdc_dev
->rx_in_cb
) {
314 /* No Rx call back registered, disable the receiver */
315 SetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
, EP_RX_NAK
);
320 bool need_yield
= false;
322 rc
= (usb_cdc_dev
->rx_in_cb
)(usb_cdc_dev
->rx_in_context
,
323 usb_cdc_dev
->rx_packet_buffer
,
328 if (rc
< DataLength
) {
329 /* Lost bytes on rx */
330 usb_cdc_dev
->rx_dropped
+= (DataLength
- rc
);
333 if (headroom
>= sizeof(usb_cdc_dev
->rx_packet_buffer
)) {
334 /* We have room for a maximum length message */
335 SetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
, EP_RX_VALID
);
337 /* Not enough room left for a message, apply backpressure */
338 SetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
, EP_RX_NAK
);
341 #if defined(PIOS_INCLUDE_FREERTOS)
345 #endif /* PIOS_INCLUDE_FREERTOS */
348 static uint16_t control_line_state
;
349 RESULT
PIOS_USB_CDC_SetControlLineState(void)
351 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
353 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
356 /* No CDC interface is configured */
357 return USB_UNSUPPORT
;
360 uint8_t wValue0
= pInformation
->USBwValue0
;
361 uint8_t wValue1
= pInformation
->USBwValue1
;
363 control_line_state
= wValue1
<< 8 | wValue0
;
368 static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id
)
370 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
372 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
376 return PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
) ? COM_AVAILABLE_RXTX
: COM_AVAILABLE_NONE
;
379 static struct usb_cdc_line_coding line_coding
= {
380 .dwDTERate
= htousbl(57600),
381 .bCharFormat
= USB_CDC_LINE_CODING_STOP_1
,
382 .bParityType
= USB_CDC_LINE_CODING_PARITY_NONE
,
386 uint8_t *PIOS_USB_CDC_SetLineCoding(uint16_t Length
)
388 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
390 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
393 /* No CDC interface is configured */
398 /* Report the number of bytes we're prepared to consume */
399 pInformation
->Ctrl_Info
.Usb_wLength
= sizeof(line_coding
);
400 pInformation
->Ctrl_Info
.Usb_rLength
= sizeof(line_coding
);
403 /* Give out a pointer to the data struct */
404 return (uint8_t *)&line_coding
;
408 const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length
)
410 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
412 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
415 /* No CDC interface is configured */
420 pInformation
->Ctrl_Info
.Usb_wLength
= sizeof(line_coding
);
423 return (uint8_t *)&line_coding
;
427 struct usb_cdc_serial_state_report uart_state
= {
428 .bmRequestType
= 0xA1,
429 .bNotification
= USB_CDC_NOTIFICATION_SERIAL_STATE
,
431 .wIndex
= htousbs(1),
432 .wLength
= htousbs(2),
433 .bmUartState
= htousbs(0),
436 static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void)
438 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
440 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
444 /* Give back UART State Bitmap */
447 * 6: bOverRun overrun error
448 * 5: bParity parity error
449 * 4: bFraming framing error
451 * 2: bBreak break reception
455 uart_state
.bmUartState
= htousbs(0x0003);
457 UserToPMABufferCopy((uint8_t *)&uart_state
,
458 GetEPTxAddr(usb_cdc_dev
->cfg
->ctrl_tx_ep
),
460 SetEPTxCount(usb_cdc_dev
->cfg
->ctrl_tx_ep
, PIOS_USB_BOARD_CDC_MGMT_LENGTH
);
461 SetEPTxValid(usb_cdc_dev
->cfg
->ctrl_tx_ep
);
464 static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id
, pios_com_callback_baud_rate baud_rate_cb
, uint32_t context
)
466 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
468 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
473 * Order is important in these assignments since ISR uses _cb
474 * field to determine if it's ok to dereference _cb and _context
476 usb_cdc_dev
->baud_rate_context
= context
;
477 usb_cdc_dev
->baud_rate_cb
= baud_rate_cb
;
480 void PIOS_USB_CDC_SetLineCoding_Completed()
482 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
484 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
487 /* No CDC interface is configured */
491 if (usb_cdc_dev
->baud_rate_cb
) {
492 usb_cdc_dev
->baud_rate_cb(usb_cdc_dev
->baud_rate_context
, usbltoh(line_coding
.dwDTERate
));
496 static void PIOS_USB_CDC_ChangeConnectionState(__attribute__((unused
)) bool connected
, uint32_t usbcdc_id
)
498 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
500 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
504 if (usb_cdc_dev
->available_cb
) {
505 (usb_cdc_dev
->available_cb
)(usb_cdc_dev
->available_context
, PIOS_USB_CDC_Available(usbcdc_id
));
509 static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id
, pios_com_callback_available available_cb
, uint32_t context
)
511 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
513 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
518 * Order is important in these assignments since ISR uses _cb
519 * field to determine if it's ok to dereference _cb and _context
521 usb_cdc_dev
->available_context
= context
;
522 usb_cdc_dev
->available_cb
= available_cb
;
525 #endif /* PIOS_INCLUDE_USB_CDC */