Paparazzi UAS  v5.8.2_stable-0-g6260b7c
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
usb_ser_hw.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Michal Podhradsky,
3  * based on example from libopencm3
4  *
5  * This file is part of paparazzi.
6  *
7  * paparazzi is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * paparazzi is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with paparazzi; see the file COPYING. If not, write to
19  * the Free Software Foundation, 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  */
23 
29 /* This version derived from libopencm3 example */
30 #include <stdlib.h>
31 #include <libopencm3/stm32/rcc.h>
32 #include <libopencm3/stm32/gpio.h>
33 #include <libopencm3/cm3/nvic.h>
34 #include <libopencm3/cm3/systick.h>
35 #include <libopencm3/usb/usbd.h>
36 #include <libopencm3/usb/cdc.h>
37 #include <libopencm3/cm3/scb.h>
38 #include <libopencm3/stm32/desig.h>
39 
40 #include "mcu_periph/usb_serial.h"
41 
42 
43 /* Max packet size for USB transfer */
44 #define MAX_PACKET_SIZE 64
45 /* Max fifo size for storing data */
46 #define VCOM_FIFO_SIZE 128
47 
48 typedef struct {
49  int head;
50  int tail;
51  uint8_t *buf;
52 } fifo_t;
53 
56 
57 static fifo_t txfifo;
58 static fifo_t rxfifo;
59 
60 void fifo_init(fifo_t *fifo, uint8_t *buf);
61 bool_t fifo_put(fifo_t *fifo, uint8_t c);
62 bool_t fifo_get(fifo_t *fifo, uint8_t *pc);
63 int fifo_avail(fifo_t *fifo);
64 int fifo_free(fifo_t *fifo);
65 
66 
67 usbd_device *my_usbd_dev;
68 
69 static const struct usb_device_descriptor dev = {
70  .bLength = USB_DT_DEVICE_SIZE,
71  .bDescriptorType = USB_DT_DEVICE,
72  .bcdUSB = 0x0200,
73  .bDeviceClass = USB_CLASS_CDC,
74  .bDeviceSubClass = 0,
75  .bDeviceProtocol = 0,
76  .bMaxPacketSize0 = MAX_PACKET_SIZE,
77  .idVendor = 0x1d50, // OpenMoko, Inc.
78  .idProduct = 0x603d, // Paparazzi LPC(STM32)USB Serial
79  .bcdDevice = 0x0200,
80  .iManufacturer = 1,
81  .iProduct = 2,
82  .iSerialNumber = 3,
83  .bNumConfigurations = 1,
84 };
85 
86 /*
87  * This notification endpoint isn't implemented. According to CDC spec it's
88  * optional, but its absence causes a NULL pointer dereference in the
89  * Linux cdc_acm driver.
90  */
91 static const struct usb_endpoint_descriptor comm_endp[] = {{
92  .bLength = USB_DT_ENDPOINT_SIZE,
93  .bDescriptorType = USB_DT_ENDPOINT,
94  .bEndpointAddress = 0x83,
95  .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
96  .wMaxPacketSize = 16,
97  .bInterval = 255,
98  }
99 };
100 
101 static const struct usb_endpoint_descriptor data_endp[] = {{
102  .bLength = USB_DT_ENDPOINT_SIZE,
103  .bDescriptorType = USB_DT_ENDPOINT,
104  .bEndpointAddress = 0x01,
105  .bmAttributes = USB_ENDPOINT_ATTR_BULK,
106  .wMaxPacketSize = MAX_PACKET_SIZE,
107  .bInterval = 1,
108  }, {
109  .bLength = USB_DT_ENDPOINT_SIZE,
110  .bDescriptorType = USB_DT_ENDPOINT,
111  .bEndpointAddress = 0x82,
112  .bmAttributes = USB_ENDPOINT_ATTR_BULK,
113  .wMaxPacketSize = MAX_PACKET_SIZE,
114  .bInterval = 1,
115  }
116 };
117 
118 static const struct {
119  struct usb_cdc_header_descriptor header;
120  struct usb_cdc_call_management_descriptor call_mgmt;
121  struct usb_cdc_acm_descriptor acm;
122  struct usb_cdc_union_descriptor cdc_union;
123 } __attribute__((packed)) cdcacm_functional_descriptors = {
124  .header = {
125  .bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
126  .bDescriptorType = CS_INTERFACE,
127  .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
128  .bcdCDC = 0x0110,
129  },
130  .call_mgmt = {
131  .bFunctionLength =
132  sizeof(struct usb_cdc_call_management_descriptor),
133  .bDescriptorType = CS_INTERFACE,
134  .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
135  .bmCapabilities = 0,
136  .bDataInterface = 1,
137  },
138  .acm = {
139  .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
140  .bDescriptorType = CS_INTERFACE,
141  .bDescriptorSubtype = USB_CDC_TYPE_ACM,
142  .bmCapabilities = 0,
143  },
144  .cdc_union = {
145  .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
146  .bDescriptorType = CS_INTERFACE,
147  .bDescriptorSubtype = USB_CDC_TYPE_UNION,
148  .bControlInterface = 0,
149  .bSubordinateInterface0 = 1,
150  }
151 };
152 
153 static const struct usb_interface_descriptor comm_iface[] = {{
154  .bLength = USB_DT_INTERFACE_SIZE,
155  .bDescriptorType = USB_DT_INTERFACE,
156  .bInterfaceNumber = 0,
157  .bAlternateSetting = 0,
158  .bNumEndpoints = 1,
159  .bInterfaceClass = USB_CLASS_CDC,
160  .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
161  .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
162  .iInterface = 0,
163 
164  .endpoint = comm_endp,
165 
167  .extralen = sizeof(cdcacm_functional_descriptors)
168  }
169 };
170 
171 static const struct usb_interface_descriptor data_iface[] = {{
172  .bLength = USB_DT_INTERFACE_SIZE,
173  .bDescriptorType = USB_DT_INTERFACE,
174  .bInterfaceNumber = 1,
175  .bAlternateSetting = 0,
176  .bNumEndpoints = 2,
177  .bInterfaceClass = USB_CLASS_DATA,
178  .bInterfaceSubClass = 0,
179  .bInterfaceProtocol = 0,
180  .iInterface = 0,
181 
182  .endpoint = data_endp,
183  }
184 };
185 
186 static const struct usb_interface ifaces[] = {{
187  .num_altsetting = 1,
188  .altsetting = comm_iface,
189  }, {
190  .num_altsetting = 1,
191  .altsetting = data_iface,
192  }
193 };
194 
195 static const struct usb_config_descriptor config = {
196  .bLength = USB_DT_CONFIGURATION_SIZE,
197  .bDescriptorType = USB_DT_CONFIGURATION,
198  .wTotalLength = 0,
199  .bNumInterfaces = 2,
200  .bConfigurationValue = 1,
201  .iConfiguration = 0,
202  .bmAttributes = 0x80,
203  .bMaxPower = 0x32,
204 
205  .interface = ifaces,
206 };
207 
208 static char serial_no[25];
209 
210 /* Description of the device as it appears after enumeration */
211 static const char *usb_strings[] = {
212  "Paparazzi UAV",
213  "CDC Serial STM32",
214  serial_no,
215 };
216 
217 
218 /*
219  * Buffer to be used for control requests.
220  * (from libopencm3 examples)
221  */
223 
228 static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
229  uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
230 {
231  (void)complete;
232  (void)buf;
233  (void)usbd_dev;
234 
235  switch (req->bRequest) {
236  case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
237  /*
238  * This Linux cdc_acm driver requires this to be implemented
239  * even though it's optional in the CDC spec, and we don't
240  * advertise it in the ACM functional descriptor.
241  */
242  char local_buf[10];
243  struct usb_cdc_notification *notif = (void *)local_buf;
244 
245  /* We echo signals back to host as notification. */
246  notif->bmRequestType = 0xA1;
247  notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
248  notif->wValue = 0;
249  notif->wIndex = 0;
250  notif->wLength = 2;
251  local_buf[8] = req->wValue & 3;
252  local_buf[9] = 0;
253  usbd_ep_write_packet(usbd_dev, 0x83, local_buf, 10);
254  return 1;
255  }
256  case USB_CDC_REQ_SET_LINE_CODING:
257  if (*len < sizeof(struct usb_cdc_line_coding)) {
258  return 0;
259  }
260 
261  return 1;
262  default:
263  return 0;
264  }
265 }
266 
271 static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
272 {
273  (void)ep;
275  static int len = 0;
276  // read packet
277  len = usbd_ep_read_packet(usbd_dev, 0x01, buf, MAX_PACKET_SIZE);
278 
279  // write to fifo
280  for (int i = 0; i < len; i++) {
281  fifo_put(&rxfifo, buf[i]);
282  }
283 }
284 
285 // store USB connection status
286 static bool_t usb_connected;
287 
288 // use suspend callback to detect disconnect
289 static void suspend_cb(void)
290 {
291  usb_connected = FALSE;
292 }
293 
298 static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
299 {
300  (void)wValue;
301 
302  usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, MAX_PACKET_SIZE, cdcacm_data_rx_cb);
303  usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, MAX_PACKET_SIZE, NULL);
304  usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
305 
306  usbd_register_control_callback(usbd_dev,
307  USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
308  USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
310 
311  // use config and suspend callback to detect connect
312  usb_connected = TRUE;
313  usbd_register_suspend_callback(usbd_dev, suspend_cb);
314 }
315 
316 
317 void fifo_init(fifo_t *fifo, uint8_t *buf)
318 {
319  fifo->head = 0;
320  fifo->tail = 0;
321  fifo->buf = buf;
322 }
323 
324 
325 
326 bool_t fifo_put(fifo_t *fifo, uint8_t c)
327 {
328  int next;
329 
330  // check if FIFO has room
331  next = (fifo->head + 1) % VCOM_FIFO_SIZE;
332  if (next == fifo->tail) {
333  // full
334  return FALSE;
335  }
336 
337  fifo->buf[fifo->head] = c;
338  fifo->head = next;
339 
340  return TRUE;
341 }
342 
343 
344 bool_t fifo_get(fifo_t *fifo, uint8_t *pc)
345 {
346  int next;
347 
348  // check if FIFO has data
349  if (fifo->head == fifo->tail) {
350  return FALSE;
351  }
352 
353  next = (fifo->tail + 1) % VCOM_FIFO_SIZE;
354 
355  *pc = fifo->buf[fifo->tail];
356  fifo->tail = next;
357 
358  return TRUE;
359 }
360 
361 
362 int fifo_avail(fifo_t *fifo)
363 {
364  return (VCOM_FIFO_SIZE + fifo->head - fifo->tail) % VCOM_FIFO_SIZE;
365 }
366 
367 
368 int fifo_free(fifo_t *fifo)
369 {
370  return (VCOM_FIFO_SIZE - 1 - fifo_avail(fifo));
371 }
372 
373 
383 int VCOM_putchar(int c)
384 {
385  if (usb_connected) {
386  // check if there are at least two more bytes left in queue
387  if (VCOM_check_free_space(2)) {
388  // if yes, add char
389  fifo_put(&txfifo, c);
390  } else {
391  // less than 2 bytes available, add byte and send data now
392  fifo_put(&txfifo, c);
394  }
395  return c;
396  }
397  return -1;
398 }
399 
404 int VCOM_getchar(void)
405 {
406  static int result = 0;
407  uint8_t c;
408  result = fifo_get(&rxfifo, &c) ? c : -1;
409  return result;
410 }
411 
417 {
418  return (fifo_free(&txfifo) >= len ? TRUE : FALSE);
419 }
420 
426 {
427  return (fifo_avail(&rxfifo));
428 }
429 
434 void VCOM_event(void)
435 {
436  usbd_poll(my_usbd_dev);
437 }
438 
444 {
445  if (usb_connected) {
447  uint8_t i;
448  for (i = 0; i < MAX_PACKET_SIZE; i++) {
449  if (!fifo_get(&txfifo, &buf[i])) {
450  break;
451  }
452  }
453  usbd_ep_write_packet(my_usbd_dev, 0x82, buf, i);
454  }
455 }
456 
457 
458 /*
459  * USE_USB_LINE_CODING is not used in case of example1, example2 and telemetry
460  */
461 #ifdef USE_USB_LINE_CODING
462 void VCOM_allow_linecoding(uint8_t mode __attribute__((unused))) {}
463 void VCOM_set_linecoding(uint8_t mode __attribute__((unused))) {}
464 #endif
465 
466 /*
467  * For USB telemetry & generic device API
468  */
469 // Periph with generic device API
471 
472 // Functions for the generic device API
473 static int usb_serial_check_free_space(struct usb_serial_periph *p __attribute__((unused)),
474  uint8_t len)
475 {
476  return (int)VCOM_check_free_space(len);
477 }
478 
479 static void usb_serial_transmit(struct usb_serial_periph *p __attribute__((unused)), uint8_t byte)
480 {
481  VCOM_putchar(byte);
482 }
483 
484 static void usb_serial_send(struct usb_serial_periph *p __attribute__((unused)))
485 {
487 }
488 
489 static int usb_serial_char_available(struct usb_serial_periph *p __attribute__((unused)))
490 {
491  return VCOM_check_available();
492 }
493 
494 static uint8_t usb_serial_getch(struct usb_serial_periph *p __attribute__((unused)))
495 {
496  return (uint8_t)(VCOM_getchar());
497 }
498 
499 void VCOM_init(void)
500 {
501  // initialise fifos
502  fifo_init(&txfifo, txdata);
503  fifo_init(&rxfifo, rxdata);
504 
505  /* set up GPIO pins */
506 #if defined STM32F4
507  gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
508  GPIO11 | GPIO12);
509  gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
510 #endif
511 
512  /* USB clock */
513  rcc_periph_clock_enable(RCC_OTGFS);
514 
515  /* Get serial number */
516  desig_get_unique_id_as_string(serial_no, 25);
517 
518  /* usb driver init*/
519  my_usbd_dev = usbd_init(&otgfs_usb_driver, &dev, &config,
520  usb_strings, 3,
521  usbd_control_buffer, sizeof(usbd_control_buffer));
522 
523  usbd_register_set_config_callback(my_usbd_dev, cdcacm_set_config);
524 
525  // disconnected by default
526  usb_connected = FALSE;
527 
528  // Configure generic device
529  usb_serial.device.periph = (void *)(&usb_serial);
535 }
unsigned short uint16_t
Definition: types.h:16
static const struct usb_interface_descriptor comm_iface[]
Definition: usb_ser_hw.c:153
#define GPIOA
Definition: gpio_arch.h:34
static int usb_serial_check_free_space(struct usb_serial_periph *p, uint8_t len)
Definition: usb_ser_hw.c:473
static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
Set configuration and control callbacks for CDC device (from libopencm3 examples) ...
Definition: usb_ser_hw.c:298
#define MAX_PACKET_SIZE
Definition: usb_ser_hw.c:44
static uint8_t usb_serial_getch(struct usb_serial_periph *p)
Definition: usb_ser_hw.c:494
static void suspend_cb(void)
Definition: usb_ser_hw.c:289
static char serial_no[25]
Definition: usb_ser_hw.c:208
static uint8_t rxdata[VCOM_FIFO_SIZE]
Definition: usb_ser_hw.c:55
static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
RX callback for CDC device (from libopencm3 examples)
Definition: usb_ser_hw.c:271
void VCOM_send_message(void)
Definition: usb_ser_hw.c:566
void VCOM_event(void)
Definition: usb_ser_hw.c:563
struct usb_serial_periph usb_serial
Definition: usb_ser_hw.c:547
#define CS_INTERFACE
Definition: usb_ser_hw.c:78
int head
Definition: usb_ser_hw.c:91
uint8_t usbd_control_buffer[128]
Definition: usb_ser_hw.c:222
static const struct usb_endpoint_descriptor data_endp[]
Definition: usb_ser_hw.c:101
int fifo_free(fifo_t *fifo)
Definition: usb_ser_hw.c:292
#define FALSE
Definition: std.h:5
void fifo_init(fifo_t *fifo, U8 *buf)
Definition: usb_ser_hw.c:246
#define TRUE
Definition: std.h:4
struct link_device device
Generic device interface.
Definition: usb_serial.h:37
#define GPIO11
Definition: gpio_arch.h:48
static bool_t usb_connected
Definition: usb_ser_hw.c:286
int VCOM_getchar(void)
Reads one character from VCOM port.
Definition: usb_ser_hw.c:386
static const char * usb_strings[]
Definition: usb_ser_hw.c:211
int tail
Definition: usb_ser_hw.c:92
#define VCOM_FIFO_SIZE
Definition: usb_ser_hw.c:46
static void usb_serial_transmit(struct usb_serial_periph *p, uint8_t byte)
Definition: usb_ser_hw.c:479
static fifo_t txfifo
Definition: usb_ser_hw.c:57
#define GPIO12
Definition: gpio_arch.h:49
static const struct @10 cdcacm_functional_descriptors
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:69
static void usb_serial_send(struct usb_serial_periph *p)
Definition: usb_ser_hw.c:484
struct adc_buf * buf
Definition: adc_arch.c:587
unsigned char uint8_t
Definition: types.h:14
usbd_device * my_usbd_dev
Definition: usb_ser_hw.c:67
BOOL fifo_put(fifo_t *fifo, U8 c)
Definition: usb_ser_hw.c:253
static const struct usb_config_descriptor config
Definition: usb_ser_hw.c:195
static const struct usb_endpoint_descriptor comm_endp[]
Definition: usb_ser_hw.c:91
void VCOM_set_linecoding(uint8_t mode)
struct mavlink_msg_req req
Definition: px4flow.c:46
static float p[2][2]
int VCOM_putchar(int c)
Writes one character to VCOM port.
Definition: usb_ser_hw.c:376
static const struct usb_interface ifaces[]
Definition: usb_ser_hw.c:186
static fifo_t rxfifo
Definition: usb_ser_hw.c:58
uint8_t * buf
Definition: usb_ser_hw.c:93
static int usb_serial_char_available(struct usb_serial_periph *p)
Definition: usb_ser_hw.c:489
bool_t VCOM_check_free_space(uint8_t len)
Checks if buffer free in VCOM buffer.
Definition: usb_ser_hw.c:409
static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, void(**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
CDC device control request (from libopencm3 examples)
Definition: usb_ser_hw.c:228
int fifo_avail(fifo_t *fifo)
Definition: usb_ser_hw.c:287
BOOL fifo_get(fifo_t *fifo, U8 *pc)
Definition: usb_ser_hw.c:270
void VCOM_allow_linecoding(uint8_t mode)
static uint8_t txdata[VCOM_FIFO_SIZE]
Definition: usb_ser_hw.c:54
int VCOM_check_available(void)
Checks if data available in VCOM buffer.
Definition: usb_ser_hw.c:420
void VCOM_init(void)
Definition: usb_ser_hw.c:578
arch independent USB API
static const struct usb_interface_descriptor data_iface[]
Definition: usb_ser_hw.c:171