Paparazzi UAS  v5.10_stable-5-g83a0da5-dirty
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 #include <libopencm3/stm32/otg_fs.h>
40 
41 #include "mcu_periph/usb_serial.h"
42 
43 #include "mcu_periph/sys_time_arch.h"
44 
45 /* Max packet size for USB transfer */
46 #define MAX_PACKET_SIZE 64
47 /* Max fifo size for storing data */
48 #define VCOM_FIFO_SIZE 256
49 
50 #define TX_TIMEOUT_CNT 20 //TODO, make dynamic with event period
51 
52 typedef struct {
53  int head;
54  int tail;
55  uint8_t *buf;
56 } fifo_t;
57 
60 
61 static fifo_t txfifo;
62 static fifo_t rxfifo;
63 
64 void fifo_init(fifo_t *fifo, uint8_t *buf);
65 bool fifo_put(fifo_t *fifo, uint8_t c);
66 bool fifo_get(fifo_t *fifo, uint8_t *pc);
67 int fifo_avail(fifo_t *fifo);
68 int fifo_free(fifo_t *fifo);
69 int tx_timeout; // tmp work around for usbd_ep_stall_get from, this function does not always seem to work
70 
71 usbd_device *my_usbd_dev;
72 
73 static const struct usb_device_descriptor dev = {
74  .bLength = USB_DT_DEVICE_SIZE,
75  .bDescriptorType = USB_DT_DEVICE,
76  .bcdUSB = 0x0200,
77  .bDeviceClass = USB_CLASS_CDC,
78  .bDeviceSubClass = 0,
79  .bDeviceProtocol = 0,
80  .bMaxPacketSize0 = MAX_PACKET_SIZE,
81  .idVendor = 0x1d50, // OpenMoko, Inc.
82  .idProduct = 0x603d, // Paparazzi LPC(STM32)USB Serial
83  .bcdDevice = 0x0200,
84  .iManufacturer = 1,
85  .iProduct = 2,
86  .iSerialNumber = 3,
87  .bNumConfigurations = 1,
88 };
89 
90 /*
91  * This notification endpoint isn't implemented. According to CDC spec it's
92  * optional, but its absence causes a NULL pointer dereference in the
93  * Linux cdc_acm driver.
94  */
95 static const struct usb_endpoint_descriptor comm_endp[] = {{
96  .bLength = USB_DT_ENDPOINT_SIZE,
97  .bDescriptorType = USB_DT_ENDPOINT,
98  .bEndpointAddress = 0x83,
99  .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
100  .wMaxPacketSize = 16,
101  .bInterval = 255,
102  }
103 };
104 
105 static const struct usb_endpoint_descriptor data_endp[] = {{
106  .bLength = USB_DT_ENDPOINT_SIZE,
107  .bDescriptorType = USB_DT_ENDPOINT,
108  .bEndpointAddress = 0x01,
109  .bmAttributes = USB_ENDPOINT_ATTR_BULK,
110  .wMaxPacketSize = MAX_PACKET_SIZE,
111  .bInterval = 1,
112  }, {
113  .bLength = USB_DT_ENDPOINT_SIZE,
114  .bDescriptorType = USB_DT_ENDPOINT,
115  .bEndpointAddress = 0x82,
116  .bmAttributes = USB_ENDPOINT_ATTR_BULK,
117  .wMaxPacketSize = MAX_PACKET_SIZE,
118  .bInterval = 1,
119  }
120 };
121 
122 static const struct {
123  struct usb_cdc_header_descriptor header;
124  struct usb_cdc_call_management_descriptor call_mgmt;
125  struct usb_cdc_acm_descriptor acm;
126  struct usb_cdc_union_descriptor cdc_union;
127 } __attribute__((packed)) cdcacm_functional_descriptors = {
128  .header = {
129  .bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
130  .bDescriptorType = CS_INTERFACE,
131  .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
132  .bcdCDC = 0x0110,
133  },
134  .call_mgmt = {
135  .bFunctionLength =
136  sizeof(struct usb_cdc_call_management_descriptor),
137  .bDescriptorType = CS_INTERFACE,
138  .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
139  .bmCapabilities = 0,
140  .bDataInterface = 1,
141  },
142  .acm = {
143  .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
144  .bDescriptorType = CS_INTERFACE,
145  .bDescriptorSubtype = USB_CDC_TYPE_ACM,
146  .bmCapabilities = 0,
147  },
148  .cdc_union = {
149  .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
150  .bDescriptorType = CS_INTERFACE,
151  .bDescriptorSubtype = USB_CDC_TYPE_UNION,
152  .bControlInterface = 0,
153  .bSubordinateInterface0 = 1,
154  }
155 };
156 
157 static const struct usb_interface_descriptor comm_iface[] = {{
158  .bLength = USB_DT_INTERFACE_SIZE,
159  .bDescriptorType = USB_DT_INTERFACE,
160  .bInterfaceNumber = 0,
161  .bAlternateSetting = 0,
162  .bNumEndpoints = 1,
163  .bInterfaceClass = USB_CLASS_CDC,
164  .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
165  .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
166  .iInterface = 0,
167 
168  .endpoint = comm_endp,
169 
171  .extralen = sizeof(cdcacm_functional_descriptors)
172  }
173 };
174 
175 static const struct usb_interface_descriptor data_iface[] = {{
176  .bLength = USB_DT_INTERFACE_SIZE,
177  .bDescriptorType = USB_DT_INTERFACE,
178  .bInterfaceNumber = 1,
179  .bAlternateSetting = 0,
180  .bNumEndpoints = 2,
181  .bInterfaceClass = USB_CLASS_DATA,
182  .bInterfaceSubClass = 0,
183  .bInterfaceProtocol = 0,
184  .iInterface = 0,
185 
186  .endpoint = data_endp,
187  }
188 };
189 
190 static const struct usb_interface ifaces[] = {{
191  .num_altsetting = 1,
192  .altsetting = comm_iface,
193  }, {
194  .num_altsetting = 1,
195  .altsetting = data_iface,
196  }
197 };
198 
199 static const struct usb_config_descriptor config = {
200  .bLength = USB_DT_CONFIGURATION_SIZE,
201  .bDescriptorType = USB_DT_CONFIGURATION,
202  .wTotalLength = 0,
203  .bNumInterfaces = 2,
204  .bConfigurationValue = 1,
205  .iConfiguration = 0,
206  .bmAttributes = 0x80,
207  .bMaxPower = 0x32,
208 
209  .interface = ifaces,
210 };
211 
212 static char serial_no[25];
213 
214 /* Description of the device as it appears after enumeration */
215 static const char *usb_strings[] = {
216  "Paparazzi UAV",
217  "CDC Serial STM32",
218  serial_no,
219 };
220 
221 
222 /*
223  * Buffer to be used for control requests.
224  * (from libopencm3 examples)
225  */
227 
232 static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
233  uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
234 {
235  (void)complete;
236  (void)buf;
237  (void)usbd_dev;
238 
239  switch (req->bRequest) {
240  case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
241  /*
242  * This Linux cdc_acm driver requires this to be implemented
243  * even though it's optional in the CDC spec, and we don't
244  * advertise it in the ACM functional descriptor.
245  */
246  char local_buf[10];
247  struct usb_cdc_notification *notif = (void *)local_buf;
248 
249  /* We echo signals back to host as notification. */
250  notif->bmRequestType = 0xA1;
251  notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
252  notif->wValue = 0;
253  notif->wIndex = 0;
254  notif->wLength = 2;
255  local_buf[8] = req->wValue & 3;
256  local_buf[9] = 0;
257  usbd_ep_write_packet(usbd_dev, 0x83, local_buf, 10);
258  return 1;
259  }
260  case USB_CDC_REQ_SET_LINE_CODING:
261  if (*len < sizeof(struct usb_cdc_line_coding)) {
262  return 0;
263  }
264 
265  return 1;
266  default:
267  return 0;
268  }
269 }
270 
275 static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
276 {
277  (void)ep;
279  static int len = 0;
280  // read packet
281  len = usbd_ep_read_packet(usbd_dev, 0x01, buf, MAX_PACKET_SIZE);
282 
283  // write to fifo
284  for (int i = 0; i < len; i++) {
285  fifo_put(&rxfifo, buf[i]);
286  }
287 }
288 
289 // store USB connection status
290 static bool usb_connected;
291 
292 // use suspend callback to detect disconnect
293 static void suspend_cb(void)
294 {
295  usb_connected = false;
296 }
297 
302 static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
303 {
304  (void)wValue;
305 
306  usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, MAX_PACKET_SIZE, cdcacm_data_rx_cb);
307  usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, MAX_PACKET_SIZE, NULL);
308  usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
309 
310  usbd_register_control_callback(usbd_dev,
311  USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
312  USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
314 
315  // use config and suspend callback to detect connect
316  usb_connected = true;
317  usbd_register_suspend_callback(usbd_dev, suspend_cb);
318 }
319 
320 
321 void fifo_init(fifo_t *fifo, uint8_t *buf)
322 {
323  fifo->head = 0;
324  fifo->tail = 0;
325  fifo->buf = buf;
326 }
327 
328 
329 
330 bool fifo_put(fifo_t *fifo, uint8_t c)
331 {
332  int next;
333 
334  // check if FIFO has room
335  next = (fifo->head + 1) % VCOM_FIFO_SIZE;
336  if (next == fifo->tail) {
337  // full
338  return false;
339  }
340 
341  fifo->buf[fifo->head] = c;
342  fifo->head = next;
343 
344  return true;
345 }
346 
347 
348 bool fifo_get(fifo_t *fifo, uint8_t *pc)
349 {
350  int next;
351 
352  // check if FIFO has data
353  if (fifo->head == fifo->tail) {
354  return false;
355  }
356 
357  next = (fifo->tail + 1) % VCOM_FIFO_SIZE;
358 
359  *pc = fifo->buf[fifo->tail];
360  fifo->tail = next;
361 
362  return true;
363 }
364 
365 
366 int fifo_avail(fifo_t *fifo)
367 {
368  return (VCOM_FIFO_SIZE + fifo->head - fifo->tail) % VCOM_FIFO_SIZE;
369 }
370 
371 
372 int fifo_free(fifo_t *fifo)
373 {
374  return (VCOM_FIFO_SIZE - 1 - fifo_avail(fifo));
375 }
376 
377 
387 int VCOM_putchar(int c)
388 {
389  if (usb_connected) {
390  // check if there are at least two more bytes left in queue
391  if (VCOM_check_free_space(2)) {
392  // if yes, add char
393  fifo_put(&txfifo, c);
394  /*c is not send until VCOM_send_message is called. This only happens in three cases:
395  * i) after a timeout (giving the chance to add more data to the fifo before sending)
396  * ii) if the fifo is filled, at which point the data is send immidiately
397  * iii) VCOM_send_message is called externally
398  */
399  tx_timeout = TX_TIMEOUT_CNT; // set timeout
400  } else {
401  // less than 2 bytes available, add byte and send data now
402  fifo_put(&txfifo, c);
403  sys_time_usleep(10); //far from optimal, increase fifo size to prevent this problem
405  }
406  return c;
407  }
408  return -1;
409 }
410 
415 int VCOM_getchar(void)
416 {
417  static int result = 0;
418  uint8_t c;
419  result = fifo_get(&rxfifo, &c) ? c : -1;
420  return result;
421 }
422 
428 {
429  return (fifo_free(&txfifo) >= len ? TRUE : FALSE);
430 }
431 
437 {
438  return (fifo_avail(&rxfifo));
439 }
440 
445 void VCOM_event(void)
446 {
447  if (tx_timeout == 1) { // send any remaining bytes that still hang arround in the tx fifo, after a timeout
448  if (fifo_avail(&txfifo)) {
450  }
451  }
452  if (tx_timeout > 0) {
453  tx_timeout--;
454  }
455 
456  usbd_poll(my_usbd_dev);
457 
458 }
459 
465 {
466  if (usb_connected) {
467 
469  uint8_t i;
470  for (i = 0; i < MAX_PACKET_SIZE; i++) {
471  if (!fifo_get(&txfifo, &buf[i])) {
472  break;
473  }
474  }
475 
476  // wait until the line is free to write
477  // this however seems buggy, sometimes data gets lost even for the stall to clear
478  // so do not call this function continously without additional safe guards
479  while (usbd_ep_stall_get(my_usbd_dev, 0x82)) {};
480 
481  // send the data over usb
482  usbd_ep_write_packet(my_usbd_dev, 0x82, buf, i);
483 
484  }
485 }
486 
487 
488 /*
489  * USE_USB_LINE_CODING is not used in case of example1, example2 and telemetry
490  */
491 #ifdef USE_USB_LINE_CODING
492 void VCOM_allow_linecoding(uint8_t mode __attribute__((unused))) {}
493 void VCOM_set_linecoding(uint8_t mode __attribute__((unused))) {}
494 #endif
495 
496 /*
497  * For USB telemetry & generic device API
498  */
499 // Periph with generic device API
501 
502 // Functions for the generic device API
503 static int usb_serial_check_free_space(struct usb_serial_periph *p __attribute__((unused)),
504  long *fd __attribute__((unused)),
505  uint16_t len)
506 {
507  return (int)VCOM_check_free_space(len);
508 }
509 
510 static void usb_serial_transmit(struct usb_serial_periph *p __attribute__((unused)),
511  long fd __attribute__((unused)),
512  uint8_t byte)
513 {
514  VCOM_putchar(byte);
515 }
516 
517 static void usb_serial_transmit_buffer(struct usb_serial_periph *p __attribute__((unused)),
518  long fd __attribute__((unused)),
519  uint8_t *data, uint16_t len)
520 {
521  int i;
522  for (i = 0; i < len; i++) {
523  VCOM_putchar(data[i]);
524  }
525 }
526 
527 static void usb_serial_send(struct usb_serial_periph *p __attribute__((unused)), long fd __attribute__((unused)))
528 {
530 }
531 
532 static int usb_serial_char_available(struct usb_serial_periph *p __attribute__((unused)))
533 {
534  return VCOM_check_available();
535 }
536 
537 static uint8_t usb_serial_getch(struct usb_serial_periph *p __attribute__((unused)))
538 {
539  return (uint8_t)(VCOM_getchar());
540 }
541 
542 void VCOM_init(void)
543 {
544  // initialise fifos
545  fifo_init(&txfifo, txdata);
546  fifo_init(&rxfifo, rxdata);
547 
548  /* set up GPIO pins */
549 #if defined STM32F4
550  gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
551  GPIO11 | GPIO12);
552  gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
553 #endif
554 
555  /* USB clock */
556  rcc_periph_clock_enable(RCC_OTGFS);
557 
558  /* Get serial number */
559  desig_get_unique_id_as_string(serial_no, 25);
560 
561  /* usb driver init*/
562  my_usbd_dev = usbd_init(&otgfs_usb_driver, &dev, &config,
563  usb_strings, 3,
564  usbd_control_buffer, sizeof(usbd_control_buffer));
565 
566  usbd_register_set_config_callback(my_usbd_dev, cdcacm_set_config);
567 
568  // disable VBUS monitoring
569  OTG_FS_GCCFG = 0;
570  OTG_FS_GCCFG |= OTG_GCCFG_NOVBUSSENS | OTG_GCCFG_PWRDWN;
571 
572  // disconnected by default
573  usb_connected = false;
574 
575  // Configure generic device
576  usb_serial.device.periph = (void *)(&usb_serial);
577  usb_serial.device.check_free_space = (check_free_space_t) usb_serial_check_free_space;
578  usb_serial.device.put_byte = (put_byte_t) usb_serial_transmit;
579  usb_serial.device.put_buffer = (put_buffer_t) usb_serial_transmit_buffer;
580  usb_serial.device.send_message = (send_message_t) usb_serial_send;
581  usb_serial.device.char_available = (char_available_t) usb_serial_char_available;
582  usb_serial.device.get_byte = (get_byte_t) usb_serial_getch;
583 
584  tx_timeout = 0;
585 }
586 
unsigned short uint16_t
Definition: types.h:16
static bool usb_connected
Definition: usb_ser_hw.c:290
static const struct usb_interface_descriptor comm_iface[]
Definition: usb_ser_hw.c:157
#define GPIOA
Definition: gpio_arch.h:34
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:302
#define MAX_PACKET_SIZE
Definition: usb_ser_hw.c:46
static uint8_t usb_serial_getch(struct usb_serial_periph *p)
Definition: usb_ser_hw.c:537
static void suspend_cb(void)
Definition: usb_ser_hw.c:293
#define TX_TIMEOUT_CNT
Definition: usb_ser_hw.c:50
static char serial_no[25]
Definition: usb_ser_hw.c:212
static uint8_t rxdata[VCOM_FIFO_SIZE]
Definition: usb_ser_hw.c:59
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:275
void VCOM_send_message(void)
Definition: usb_ser_hw.c:574
void VCOM_event(void)
Definition: usb_ser_hw.c:571
struct usb_serial_periph usb_serial
Definition: usb_ser_hw.c:547
static void usb_serial_transmit_buffer(struct usb_serial_periph *p, long fd, uint8_t *data, uint16_t len)
Definition: usb_ser_hw.c:517
static int usb_serial_check_free_space(struct usb_serial_periph *p, long *fd, uint16_t len)
Definition: usb_ser_hw.c:503
#define CS_INTERFACE
Definition: usb_ser_hw.c:78
static const struct @11 cdcacm_functional_descriptors
int head
Definition: usb_ser_hw.c:91
uint8_t usbd_control_buffer[128]
Definition: usb_ser_hw.c:226
static const struct usb_endpoint_descriptor data_endp[]
Definition: usb_ser_hw.c:105
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
void sys_time_usleep(uint32_t us)
sys_time_usleep(uint32_t us)
Definition: sys_time_arch.c:95
#define TRUE
Definition: std.h:4
static void usb_serial_send(struct usb_serial_periph *p, long fd)
Definition: usb_ser_hw.c:527
struct link_device device
Generic device interface.
Definition: usb_serial.h:37
bool VCOM_check_free_space(uint16_t len)
Checks if buffer free in VCOM buffer.
Definition: usb_ser_hw.c:409
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:215
int tail
Definition: usb_ser_hw.c:92
#define VCOM_FIFO_SIZE
Definition: usb_ser_hw.c:48
#define GPIO_AF10
Definition: gpio_def.h:74
static fifo_t txfifo
Definition: usb_ser_hw.c:61
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:73
int tx_timeout
Definition: usb_ser_hw.c:69
unsigned char uint8_t
Definition: types.h:14
usbd_device * my_usbd_dev
Definition: usb_ser_hw.c:71
#define byte
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:199
static void usb_serial_transmit(struct usb_serial_periph *p, long fd, uint8_t byte)
Definition: usb_ser_hw.c:510
int fd
Definition: serial.c:26
static const struct usb_endpoint_descriptor comm_endp[]
Definition: usb_ser_hw.c:95
void VCOM_set_linecoding(uint8_t mode)
struct mavlink_msg_req req
Definition: px4flow.c:46
static float p[2][2]
#define GPIO11
Definition: gpio_def.h:42
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:190
static fifo_t rxfifo
Definition: usb_ser_hw.c:62
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:532
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:232
#define GPIO12
Definition: gpio_def.h:43
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:58
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:586
arch independent USB API
static const struct usb_interface_descriptor data_iface[]
Definition: usb_ser_hw.c:175