update credits
[librepilot.git] / flight / pios / stm32f10x / pios_usb_cdc.c
blobebbaedbd1b1158f6a117905adb97a341a94ae19b
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 */
39 /* STM32 USB Library Definitions */
40 #include "usb_lib.h"
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;
69 uint32_t lower_id;
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];
89 uint32_t rx_dropped;
90 uint32_t rx_oversize;
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));
104 if (!usb_cdc_dev) {
105 return NULL;
108 memset(usb_cdc_dev, 0, sizeof(struct pios_usb_cdc_dev));
109 usb_cdc_dev->magic = PIOS_USB_CDC_DEV_MAGIC;
110 return usb_cdc_dev;
112 #else
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) {
120 return NULL;
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;
128 return usb_cdc_dev;
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);
145 PIOS_Assert(cfg);
147 struct pios_usb_cdc_dev *usb_cdc_dev;
149 usb_cdc_dev = (struct pios_usb_cdc_dev *)PIOS_USB_CDC_alloc();
150 if (!usb_cdc_dev) {
151 goto out_fail;
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;
169 return 0;
171 out_fail:
172 return -1;
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);
182 PIOS_Assert(valid);
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);
198 PIOS_Assert(valid);
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);
214 PIOS_Assert(valid);
216 if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) {
217 return;
220 // If endpoint was stalled and there is now space make it valid
221 PIOS_IRQ_Disable();
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);
226 PIOS_IRQ_Enable();
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) {
234 return;
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),
241 NULL,
242 &need_yield);
243 if (bytes_to_tx == 0) {
244 return;
247 UserToPMABufferCopy(usb_cdc_dev->tx_packet_buffer,
248 GetEPTxAddr(usb_cdc_dev->cfg->data_tx_ep),
249 bytes_to_tx);
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)
254 if (need_yield) {
255 vPortYield();
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);
266 PIOS_Assert(valid);
268 if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) {
269 return;
272 if (GetEPTxStatus(usb_cdc_dev->cfg->data_tx_ep) == EP_TX_VALID) {
273 /* Endpoint is already transmitting */
274 return;
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);
286 PIOS_Assert(valid);
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);
297 PIOS_Assert(valid);
299 uint32_t DataLength;
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),
311 DataLength);
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);
316 return;
319 uint16_t headroom;
320 bool need_yield = false;
321 uint16_t rc;
322 rc = (usb_cdc_dev->rx_in_cb)(usb_cdc_dev->rx_in_context,
323 usb_cdc_dev->rx_packet_buffer,
324 DataLength,
325 &headroom,
326 &need_yield);
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);
336 } else {
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)
342 if (need_yield) {
343 vPortYield();
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);
355 if (!valid) {
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;
365 return USB_SUCCESS;
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);
374 PIOS_Assert(valid);
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,
383 .bDataBits = 8,
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);
392 if (!valid) {
393 /* No CDC interface is configured */
394 return NULL;
397 if (Length == 0) {
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);
401 return NULL;
402 } else {
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);
414 if (!valid) {
415 /* No CDC interface is configured */
416 return NULL;
419 if (Length == 0) {
420 pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding);
421 return NULL;
422 } else {
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,
430 .wValue = 0,
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);
442 PIOS_Assert(valid);
444 /* Give back UART State Bitmap */
445 /* UART State Bitmap
446 * 15-7: reserved
447 * 6: bOverRun overrun error
448 * 5: bParity parity error
449 * 4: bFraming framing error
450 * 3: bRingSignal RI
451 * 2: bBreak break reception
452 * 1: bTxCarrier DSR
453 * 0: bRxCarrier DCD
455 uart_state.bmUartState = htousbs(0x0003);
457 UserToPMABufferCopy((uint8_t *)&uart_state,
458 GetEPTxAddr(usb_cdc_dev->cfg->ctrl_tx_ep),
459 sizeof(uart_state));
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);
470 PIOS_Assert(valid);
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);
486 if (!valid) {
487 /* No CDC interface is configured */
488 return;
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);
502 PIOS_Assert(valid);
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);
515 PIOS_Assert(valid);
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 */