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_TxStart(uint32_t usbcdc_id
, uint16_t tx_bytes_avail
);
45 static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id
, uint16_t rx_bytes_avail
);
46 static bool PIOS_USB_CDC_Available(uint32_t usbcdc_id
);
48 const struct pios_com_driver pios_usb_cdc_com_driver
= {
49 .tx_start
= PIOS_USB_CDC_TxStart
,
50 .rx_start
= PIOS_USB_CDC_RxStart
,
51 .bind_tx_cb
= PIOS_USB_CDC_RegisterTxCallback
,
52 .bind_rx_cb
= PIOS_USB_CDC_RegisterRxCallback
,
53 .available
= PIOS_USB_CDC_Available
,
56 enum pios_usb_cdc_dev_magic
{
57 PIOS_USB_CDC_DEV_MAGIC
= 0xAABBCCDD,
60 struct pios_usb_cdc_dev
{
61 enum pios_usb_cdc_dev_magic magic
;
62 const struct pios_usb_cdc_cfg
*cfg
;
66 pios_com_callback rx_in_cb
;
67 uint32_t rx_in_context
;
68 pios_com_callback tx_out_cb
;
69 uint32_t tx_out_context
;
71 uint8_t rx_packet_buffer
[PIOS_USB_BOARD_CDC_DATA_LENGTH
];
73 * NOTE: This is -1 as somewhat of a hack. It ensures that we always send packets
74 * that are strictly < maxPacketSize for this interface which means we never have
75 * to bother with zero length packets (ZLP).
77 uint8_t tx_packet_buffer
[PIOS_USB_BOARD_CDC_DATA_LENGTH
- 1];
83 static bool PIOS_USB_CDC_validate(struct pios_usb_cdc_dev
*usb_cdc_dev
)
85 return usb_cdc_dev
->magic
== PIOS_USB_CDC_DEV_MAGIC
;
88 #if defined(PIOS_INCLUDE_FREERTOS)
89 static struct pios_usb_cdc_dev
*PIOS_USB_CDC_alloc(void)
91 struct pios_usb_cdc_dev
*usb_cdc_dev
;
93 usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_malloc(sizeof(struct pios_usb_cdc_dev
));
98 memset(usb_cdc_dev
, 0, sizeof(struct pios_usb_cdc_dev
));
99 usb_cdc_dev
->magic
= PIOS_USB_CDC_DEV_MAGIC
;
103 static struct pios_usb_cdc_dev pios_usb_cdc_devs
[PIOS_USB_CDC_MAX_DEVS
];
104 static uint8_t pios_usb_cdc_num_devs
;
105 static struct pios_usb_cdc_dev
*PIOS_USB_CDC_alloc(void)
107 struct pios_usb_cdc_dev
*usb_cdc_dev
;
109 if (pios_usb_cdc_num_devs
>= PIOS_USB_CDC_MAX_DEVS
) {
113 usb_cdc_dev
= &pios_usb_cdc_devs
[pios_usb_cdc_num_devs
++];
115 memset(usb_cdc_dev
, 0, sizeof(struct pios_usb_cdc_dev
));
116 usb_cdc_dev
->magic
= PIOS_USB_CDC_DEV_MAGIC
;
120 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
122 static void PIOS_USB_CDC_DATA_EP_IN_Callback(void);
123 static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void);
124 static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void);
126 static uint32_t pios_usb_cdc_id
;
128 /* Need a better way to pull these in */
129 extern void(*pEpInt_IN
[7]) (void);
130 extern void(*pEpInt_OUT
[7]) (void);
132 int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id
, const struct pios_usb_cdc_cfg
*cfg
, uint32_t lower_id
)
134 PIOS_Assert(usbcdc_id
);
137 struct pios_usb_cdc_dev
*usb_cdc_dev
;
139 usb_cdc_dev
= (struct pios_usb_cdc_dev
*)PIOS_USB_CDC_alloc();
144 /* Bind the configuration to the device instance */
145 usb_cdc_dev
->cfg
= cfg
;
146 usb_cdc_dev
->lower_id
= lower_id
;
148 pios_usb_cdc_id
= (uint32_t)usb_cdc_dev
;
150 /* Bind lower level callbacks into the USB infrastructure */
151 pEpInt_OUT
[cfg
->ctrl_tx_ep
- 1] = PIOS_USB_CDC_CTRL_EP_IN_Callback
;
152 pEpInt_IN
[cfg
->data_tx_ep
- 1] = PIOS_USB_CDC_DATA_EP_IN_Callback
;
153 pEpInt_OUT
[cfg
->data_rx_ep
- 1] = PIOS_USB_CDC_DATA_EP_OUT_Callback
;
155 *usbcdc_id
= (uint32_t)usb_cdc_dev
;
164 static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id
, pios_com_callback rx_in_cb
, uint32_t context
)
166 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
168 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
173 * Order is important in these assignments since ISR uses _cb
174 * field to determine if it's ok to dereference _cb and _context
176 usb_cdc_dev
->rx_in_context
= context
;
177 usb_cdc_dev
->rx_in_cb
= rx_in_cb
;
180 static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id
, pios_com_callback tx_out_cb
, uint32_t context
)
182 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
184 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
189 * Order is important in these assignments since ISR uses _cb
190 * field to determine if it's ok to dereference _cb and _context
192 usb_cdc_dev
->tx_out_context
= context
;
193 usb_cdc_dev
->tx_out_cb
= tx_out_cb
;
196 static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id
, uint16_t rx_bytes_avail
)
198 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
200 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
204 if (!PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
)) {
208 // If endpoint was stalled and there is now space make it valid
210 if ((GetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
) != EP_RX_VALID
) &&
211 (rx_bytes_avail
>= sizeof(usb_cdc_dev
->rx_packet_buffer
))) {
212 SetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
, EP_RX_VALID
);
217 static void PIOS_USB_CDC_SendData(struct pios_usb_cdc_dev
*usb_cdc_dev
)
219 uint16_t bytes_to_tx
;
221 if (!usb_cdc_dev
->tx_out_cb
) {
225 bool need_yield
= false;
226 bytes_to_tx
= (usb_cdc_dev
->tx_out_cb
)(usb_cdc_dev
->tx_out_context
,
227 usb_cdc_dev
->tx_packet_buffer
,
228 sizeof(usb_cdc_dev
->tx_packet_buffer
),
231 if (bytes_to_tx
== 0) {
235 UserToPMABufferCopy(usb_cdc_dev
->tx_packet_buffer
,
236 GetEPTxAddr(usb_cdc_dev
->cfg
->data_tx_ep
),
238 SetEPTxCount(usb_cdc_dev
->cfg
->data_tx_ep
, bytes_to_tx
);
239 SetEPTxValid(usb_cdc_dev
->cfg
->data_tx_ep
);
241 #if defined(PIOS_INCLUDE_FREERTOS)
245 #endif /* PIOS_INCLUDE_FREERTOS */
248 static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id
, __attribute__((unused
)) uint16_t tx_bytes_avail
)
250 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)usbcdc_id
;
252 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
256 if (!PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
)) {
260 if (GetEPTxStatus(usb_cdc_dev
->cfg
->data_tx_ep
) == EP_TX_VALID
) {
261 /* Endpoint is already transmitting */
265 PIOS_USB_CDC_SendData(usb_cdc_dev
);
268 static void PIOS_USB_CDC_DATA_EP_IN_Callback(void)
270 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
272 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
276 PIOS_USB_CDC_SendData(usb_cdc_dev
);
279 static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void)
281 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
283 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
289 /* Get the number of received data on the selected Endpoint */
290 DataLength
= GetEPRxCount(usb_cdc_dev
->cfg
->data_rx_ep
);
291 if (DataLength
> sizeof(usb_cdc_dev
->rx_packet_buffer
)) {
292 usb_cdc_dev
->rx_oversize
++;
293 DataLength
= sizeof(usb_cdc_dev
->rx_packet_buffer
);
296 /* Use the memory interface function to read from the selected endpoint */
297 PMAToUserBufferCopy((uint8_t *)usb_cdc_dev
->rx_packet_buffer
,
298 GetEPRxAddr(usb_cdc_dev
->cfg
->data_rx_ep
),
301 if (!usb_cdc_dev
->rx_in_cb
) {
302 /* No Rx call back registered, disable the receiver */
303 SetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
, EP_RX_NAK
);
308 bool need_yield
= false;
310 rc
= (usb_cdc_dev
->rx_in_cb
)(usb_cdc_dev
->rx_in_context
,
311 usb_cdc_dev
->rx_packet_buffer
,
316 if (rc
< DataLength
) {
317 /* Lost bytes on rx */
318 usb_cdc_dev
->rx_dropped
+= (DataLength
- rc
);
321 if (headroom
>= sizeof(usb_cdc_dev
->rx_packet_buffer
)) {
322 /* We have room for a maximum length message */
323 SetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
, EP_RX_VALID
);
325 /* Not enough room left for a message, apply backpressure */
326 SetEPRxStatus(usb_cdc_dev
->cfg
->data_rx_ep
, EP_RX_NAK
);
329 #if defined(PIOS_INCLUDE_FREERTOS)
333 #endif /* PIOS_INCLUDE_FREERTOS */
336 static uint16_t control_line_state
;
337 RESULT
PIOS_USB_CDC_SetControlLineState(void)
339 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
341 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
344 /* No CDC interface is configured */
345 return USB_UNSUPPORT
;
348 uint8_t wValue0
= pInformation
->USBwValue0
;
349 uint8_t wValue1
= pInformation
->USBwValue1
;
351 control_line_state
= wValue1
<< 8 | wValue0
;
356 static bool PIOS_USB_CDC_Available(uint32_t usbcdc_id
)
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
);
364 return PIOS_USB_CheckAvailable(usb_cdc_dev
->lower_id
) &&
365 (control_line_state
& USB_CDC_CONTROL_LINE_STATE_DTE_PRESENT
);
368 static struct usb_cdc_line_coding line_coding
= {
369 .dwDTERate
= htousbl(57600),
370 .bCharFormat
= USB_CDC_LINE_CODING_STOP_1
,
371 .bParityType
= USB_CDC_LINE_CODING_PARITY_NONE
,
375 uint8_t *PIOS_USB_CDC_SetLineCoding(uint16_t Length
)
377 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
379 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
382 /* No CDC interface is configured */
387 /* Report the number of bytes we're prepared to consume */
388 pInformation
->Ctrl_Info
.Usb_wLength
= sizeof(line_coding
);
389 pInformation
->Ctrl_Info
.Usb_rLength
= sizeof(line_coding
);
392 /* Give out a pointer to the data struct */
393 return (uint8_t *)&line_coding
;
397 const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length
)
399 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
401 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
404 /* No CDC interface is configured */
409 pInformation
->Ctrl_Info
.Usb_wLength
= sizeof(line_coding
);
412 return (uint8_t *)&line_coding
;
416 struct usb_cdc_serial_state_report uart_state
= {
417 .bmRequestType
= 0xA1,
418 .bNotification
= USB_CDC_NOTIFICATION_SERIAL_STATE
,
420 .wIndex
= htousbs(1),
421 .wLength
= htousbs(2),
422 .bmUartState
= htousbs(0),
425 static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void)
427 struct pios_usb_cdc_dev
*usb_cdc_dev
= (struct pios_usb_cdc_dev
*)pios_usb_cdc_id
;
429 bool valid
= PIOS_USB_CDC_validate(usb_cdc_dev
);
433 /* Give back UART State Bitmap */
436 * 6: bOverRun overrun error
437 * 5: bParity parity error
438 * 4: bFraming framing error
440 * 2: bBreak break reception
444 uart_state
.bmUartState
= htousbs(0x0003);
446 UserToPMABufferCopy((uint8_t *)&uart_state
,
447 GetEPTxAddr(usb_cdc_dev
->cfg
->ctrl_tx_ep
),
449 SetEPTxCount(usb_cdc_dev
->cfg
->ctrl_tx_ep
, PIOS_USB_BOARD_CDC_MGMT_LENGTH
);
450 SetEPTxValid(usb_cdc_dev
->cfg
->ctrl_tx_ep
);
453 #endif /* PIOS_INCLUDE_USB_CDC */