Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
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/usb/dwc/otg_fs.h>
40
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
52typedef struct {
53 int head;
54 int tail;
56} fifo_t;
57
60
63
64void fifo_init(fifo_t *fifo, uint8_t *buf);
65bool fifo_put(fifo_t *fifo, uint8_t c);
70int tx_timeout; // tmp work around for usbd_ep_stall_get from, this function does not always seem to work
71
73
74static const struct usb_device_descriptor dev = {
75 .bLength = USB_DT_DEVICE_SIZE,
76 .bDescriptorType = USB_DT_DEVICE,
77 .bcdUSB = 0x0200,
78 .bDeviceClass = USB_CLASS_CDC,
79 .bDeviceSubClass = 0,
80 .bDeviceProtocol = 0,
81 .bMaxPacketSize0 = MAX_PACKET_SIZE,
82 .idVendor = 0x1d50, // OpenMoko, Inc.
83 .idProduct = 0x603d, // Paparazzi LPC(STM32)USB Serial
84 .bcdDevice = 0x0200,
85 .iManufacturer = 1,
86 .iProduct = 2,
87 .iSerialNumber = 3,
88 .bNumConfigurations = 1,
89};
90
91/*
92 * This notification endpoint isn't implemented. According to CDC spec it's
93 * optional, but its absence causes a NULL pointer dereference in the
94 * Linux cdc_acm driver.
95 */
96static const struct usb_endpoint_descriptor comm_endp[] = {{
97 .bLength = USB_DT_ENDPOINT_SIZE,
98 .bDescriptorType = USB_DT_ENDPOINT,
99 .bEndpointAddress = 0x83,
100 .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
101 .wMaxPacketSize = 16,
102 .bInterval = 255,
103 }
104};
105
106static const struct usb_endpoint_descriptor data_endp[] = {{
107 .bLength = USB_DT_ENDPOINT_SIZE,
108 .bDescriptorType = USB_DT_ENDPOINT,
109 .bEndpointAddress = 0x01,
110 .bmAttributes = USB_ENDPOINT_ATTR_BULK,
111 .wMaxPacketSize = MAX_PACKET_SIZE,
112 .bInterval = 1,
113 }, {
114 .bLength = USB_DT_ENDPOINT_SIZE,
115 .bDescriptorType = USB_DT_ENDPOINT,
116 .bEndpointAddress = 0x82,
117 .bmAttributes = USB_ENDPOINT_ATTR_BULK,
118 .wMaxPacketSize = MAX_PACKET_SIZE,
119 .bInterval = 1,
120 }
121};
122
123static const struct {
124 struct usb_cdc_header_descriptor header;
125 struct usb_cdc_call_management_descriptor call_mgmt;
126 struct usb_cdc_acm_descriptor acm;
127 struct usb_cdc_union_descriptor cdc_union;
129 .header = {
130 .bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
132 .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
133 .bcdCDC = 0x0110,
134 },
135 .call_mgmt = {
136 .bFunctionLength =
139 .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
140 .bmCapabilities = 0,
141 .bDataInterface = 1,
142 },
143 .acm = {
144 .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
146 .bDescriptorSubtype = USB_CDC_TYPE_ACM,
147 .bmCapabilities = 0,
148 },
149 .cdc_union = {
150 .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
152 .bDescriptorSubtype = USB_CDC_TYPE_UNION,
153 .bControlInterface = 0,
154 .bSubordinateInterface0 = 1,
155 }
157
158static const struct usb_interface_descriptor comm_iface[] = {{
159 .bLength = USB_DT_INTERFACE_SIZE,
160 .bDescriptorType = USB_DT_INTERFACE,
161 .bInterfaceNumber = 0,
162 .bAlternateSetting = 0,
163 .bNumEndpoints = 1,
164 .bInterfaceClass = USB_CLASS_CDC,
165 .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
166 .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
167 .iInterface = 0,
168
169 .endpoint = comm_endp,
170
172 .extralen = sizeof(cdcacm_functional_descriptors)
173 }
174};
175
176static const struct usb_interface_descriptor data_iface[] = {{
177 .bLength = USB_DT_INTERFACE_SIZE,
178 .bDescriptorType = USB_DT_INTERFACE,
179 .bInterfaceNumber = 1,
180 .bAlternateSetting = 0,
181 .bNumEndpoints = 2,
182 .bInterfaceClass = USB_CLASS_DATA,
183 .bInterfaceSubClass = 0,
184 .bInterfaceProtocol = 0,
185 .iInterface = 0,
186
187 .endpoint = data_endp,
188 }
189};
190
191static const struct usb_interface ifaces[] = {{
192 .num_altsetting = 1,
193 .altsetting = comm_iface,
194 }, {
195 .num_altsetting = 1,
196 .altsetting = data_iface,
197 }
198};
199
200static const struct usb_config_descriptor config = {
201 .bLength = USB_DT_CONFIGURATION_SIZE,
202 .bDescriptorType = USB_DT_CONFIGURATION,
203 .wTotalLength = 0,
204 .bNumInterfaces = 2,
205 .bConfigurationValue = 1,
206 .iConfiguration = 0,
207 .bmAttributes = 0x80,
208 .bMaxPower = 0x32,
209
210 .interface = ifaces,
211};
212
213static char serial_no[25];
214
215/* Description of the device as it appears after enumeration */
216static const char *usb_strings[] = {
217 "Paparazzi UAV",
218 "CDC Serial STM32",
219 serial_no,
220};
221
222
223/*
224 * Buffer to be used for control requests.
225 * (from libopencm3 examples)
226 */
228
234 uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
235{
236 (void)complete;
237 (void)buf;
238 (void)usbd_dev;
239
240 switch (req->bRequest) {
242 /*
243 * This Linux cdc_acm driver requires this to be implemented
244 * even though it's optional in the CDC spec, and we don't
245 * advertise it in the ACM functional descriptor.
246 */
247 char local_buf[10];
248 struct usb_cdc_notification *notif = (void *)local_buf;
249
250 /* We echo signals back to host as notification. */
251 notif->bmRequestType = 0xA1;
252 notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
253 notif->wValue = 0;
254 notif->wIndex = 0;
255 notif->wLength = 2;
256 local_buf[8] = req->wValue & 3;
257 local_buf[9] = 0;
259 return USBD_REQ_HANDLED;
260 }
262 if (*len < sizeof(struct usb_cdc_line_coding)) {
263 return USBD_REQ_NOTSUPP;
264 }
265
266 return USBD_REQ_HANDLED;
267 default:
268 return USBD_REQ_NOTSUPP;
269 }
270}
271
277{
278 (void)ep;
280 static int len = 0;
281 // read packet
283
284 // write to fifo
285 for (int i = 0; i < len; i++) {
286 fifo_put(&rxfifo, buf[i]);
287 }
288}
289
290// store USB connection status
291static bool usb_connected;
292
293// use suspend callback to detect disconnect
294static void suspend_cb(void)
295{
296 usb_connected = false;
297}
298
320
321
323{
324 fifo->head = 0;
325 fifo->tail = 0;
326 fifo->buf = buf;
327}
328
329
330
332{
333 int next;
334
335 // check if FIFO has room
336 next = (fifo->head + 1) % VCOM_FIFO_SIZE;
337 if (next == fifo->tail) {
338 // full
339 return false;
340 }
341
342 fifo->buf[fifo->head] = c;
343 fifo->head = next;
344
345 return true;
346}
347
348
350{
351 int next;
352
353 // check if FIFO has data
354 if (fifo->head == fifo->tail) {
355 return false;
356 }
357
358 next = (fifo->tail + 1) % VCOM_FIFO_SIZE;
359
360 *pc = fifo->buf[fifo->tail];
361 fifo->tail = next;
362
363 return true;
364}
365
366
368{
369 return (VCOM_FIFO_SIZE + fifo->head - fifo->tail) % VCOM_FIFO_SIZE;
370}
371
372
374{
375 return (VCOM_FIFO_SIZE - 1 - fifo_avail(fifo));
376}
377
379 if (fifo_avail(fifo) < ofs + 1) {
380 return false;
381 }
382 int index = (fifo->tail + ofs) % VCOM_FIFO_SIZE;
383 *pc = fifo->buf[index];
384 return true;
385}
386
387
397int VCOM_putchar(int c)
398{
399 if (usb_connected) {
400 // check if there are at least two more bytes left in queue
401 if (VCOM_check_free_space(2)) {
402 // if yes, add char
403 fifo_put(&txfifo, c);
404 /*c is not send until VCOM_send_message is called. This only happens in three cases:
405 * i) after a timeout (giving the chance to add more data to the fifo before sending)
406 * ii) if the fifo is filled, at which point the data is send immidiately
407 * iii) VCOM_send_message is called externally
408 */
409 tx_timeout = TX_TIMEOUT_CNT; // set timeout
410 } else {
411 // less than 2 bytes available, add byte and send data now
412 fifo_put(&txfifo, c);
413 sys_time_usleep(10); //far from optimal, increase fifo size to prevent this problem
415 }
416 return c;
417 }
418 return -1;
419}
420
426{
427 static int result = 0;
428 uint8_t c;
429 result = fifo_get(&rxfifo, &c) ? c : -1;
430 return result;
431}
432
439{
440 static int result = 0;
441 uint8_t c;
442 result = fifo_peek(&rxfifo, &c, ofs) ? c : -1;
443 return result;
444}
445
451{
452 return (fifo_free(&txfifo) >= len ? TRUE : FALSE);
453}
454
460{
461 return (fifo_avail(&rxfifo));
462}
463
468void VCOM_event(void)
469{
470 if (tx_timeout == 1) { // send any remaining bytes that still hang arround in the tx fifo, after a timeout
471 if (fifo_avail(&txfifo)) {
473 }
474 }
475 if (tx_timeout > 0) {
476 tx_timeout--;
477 }
478
480
481}
482
488{
489 if (usb_connected) {
490
492 uint8_t i;
493 for (i = 0; i < MAX_PACKET_SIZE; i++) {
494 if (!fifo_get(&txfifo, &buf[i])) {
495 break;
496 }
497 }
498
499 // wait until the line is free to write
500 // this however seems buggy, sometimes data gets lost even for the stall to clear
501 // so do not call this function continously without additional safe guards
502 while (usbd_ep_stall_get(my_usbd_dev, 0x82)) {};
503
504 // send the data over usb
505 usbd_ep_write_packet(my_usbd_dev, 0x82, buf, i);
506
507 }
508}
509
510
511/*
512 * USE_USB_LINE_CODING is not used in case of example1, example2 and telemetry
513 */
514#ifdef USE_USB_LINE_CODING
517#endif
518
519/*
520 * For USB telemetry & generic device API
521 */
522// Periph with generic device API
524
525// Functions for the generic device API
527 long *fd __attribute__((unused)),
528 uint16_t len)
529{
530 return (int)VCOM_check_free_space(len);
531}
532
534 long fd __attribute__((unused)),
535 uint8_t byte)
536{
537 VCOM_putchar(byte);
538}
539
541 long fd __attribute__((unused)),
542 uint8_t *data, uint16_t len)
543{
544 int i;
545 for (i = 0; i < len; i++) {
546 VCOM_putchar(data[i]);
547 }
548}
549
550static void usb_serial_send(struct usb_serial_periph *p __attribute__((unused)), long fd __attribute__((unused)))
551{
553}
554
556{
557 return VCOM_check_available();
558}
559
561{
562 return (uint8_t)(VCOM_getchar());
563}
564
565void VCOM_init(void)
566{
567 // initialise fifos
570
571 /* set up GPIO pins */
572#if defined STM32F4
575 GPIO11 | GPIO12);
577#endif
578
579 /* USB clock */
581
582 /* Get serial number */
584
585 /* usb driver init*/
587 usb_strings, 3,
589
591
592 // disable VBUS monitoring
593 OTG_FS_GCCFG = 0;
595
596 // disconnected by default
597 usb_connected = false;
598
599 // Configure generic device
600 usb_serial.device.periph = (void *)(&usb_serial);
607
608 tx_timeout = 0;
609}
610
void sys_time_usleep(uint32_t us)
sys_time_usleep(uint32_t us)
int tail
Definition usb_ser_hw.c:54
int head
Definition usb_ser_hw.c:53
uint8_t * buf
Definition usb_ser_hw.c:55
#define GPIO12
Definition gpio_def.h:43
#define GPIO_AF10
Definition gpio_def.h:74
#define GPIO11
Definition gpio_def.h:42
static float p[2][2]
uint16_t foo
Definition main_demo5.c:58
int fd
Definition serial.c:26
#define GPIOA
Definition gpio_arch.h:34
static uint8_t mode
mode holds the current sonar mode mode = 0 used at high altitude, uses 16 wave patterns mode = 1 used...
Definition sonar_bebop.c:65
#define TRUE
Definition std.h:4
#define FALSE
Definition std.h:5
static const struct usb_interface ifaces[]
Definition usb_ser_hw.c:191
bool fifo_peek(fifo_t *fifo, uint8_t *pc, uint8_t ofs)
Definition usb_ser_hw.c:378
int tx_timeout
Definition usb_ser_hw.c:70
static fifo_t txfifo
Definition usb_ser_hw.c:61
void fifo_init(fifo_t *fifo, uint8_t *buf)
Definition usb_ser_hw.c:322
void VCOM_event(void)
Poll usb (required by libopencm3).
Definition usb_ser_hw.c:468
int VCOM_getchar(void)
Reads one character from VCOM port.
Definition usb_ser_hw.c:425
int fifo_free(fifo_t *fifo)
Definition usb_ser_hw.c:373
int VCOM_putchar(int c)
Writes one character to VCOM port fifo.
Definition usb_ser_hw.c:397
static const struct @12 cdcacm_functional_descriptors
static int usb_serial_check_free_space(struct usb_serial_periph *p, long *fd, uint16_t len)
Definition usb_ser_hw.c:526
static void usb_serial_transmit_buffer(struct usb_serial_periph *p, long fd, uint8_t *data, uint16_t len)
Definition usb_ser_hw.c:540
static void usb_serial_transmit(struct usb_serial_periph *p, long fd, uint8_t byte)
Definition usb_ser_hw.c:533
static void suspend_cb(void)
Definition usb_ser_hw.c:294
usbd_device * my_usbd_dev
Definition usb_ser_hw.c:72
uint8_t usbd_control_buffer[128]
Definition usb_ser_hw.c:227
static char serial_no[25]
Definition usb_ser_hw.c:213
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:459
static enum usbd_request_return_codes 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:233
static const struct usb_endpoint_descriptor data_endp[]
Definition usb_ser_hw.c:106
int VCOM_peekchar(int ofs)
Reads one character from VCOM port without removing it from the queue.
Definition usb_ser_hw.c:438
static fifo_t rxfifo
Definition usb_ser_hw.c:62
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:303
static const struct usb_interface_descriptor data_iface[]
Definition usb_ser_hw.c:176
static const struct usb_config_descriptor config
Definition usb_ser_hw.c:200
int fifo_avail(fifo_t *fifo)
Definition usb_ser_hw.c:367
#define MAX_PACKET_SIZE
Definition usb_ser_hw.c:46
#define VCOM_FIFO_SIZE
Definition usb_ser_hw.c:48
static const struct usb_endpoint_descriptor comm_endp[]
Definition usb_ser_hw.c:96
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:276
void VCOM_init(void)
Definition usb_ser_hw.c:565
void VCOM_send_message(void)
Send data from fifo right now.
Definition usb_ser_hw.c:487
struct usb_serial_periph usb_serial
Definition usb_ser_hw.c:523
static uint8_t usb_serial_getch(struct usb_serial_periph *p)
Definition usb_ser_hw.c:560
static void usb_serial_send(struct usb_serial_periph *p, long fd)
Definition usb_ser_hw.c:550
static int usb_serial_char_available(struct usb_serial_periph *p)
Definition usb_ser_hw.c:555
bool fifo_put(fifo_t *fifo, uint8_t c)
Definition usb_ser_hw.c:331
bool VCOM_check_free_space(uint16_t len)
Checks if buffer free in VCOM buffer.
Definition usb_ser_hw.c:450
#define TX_TIMEOUT_CNT
Definition usb_ser_hw.c:50
static const struct usb_device_descriptor dev
Definition usb_ser_hw.c:74
static const char * usb_strings[]
Definition usb_ser_hw.c:216
static const struct usb_interface_descriptor comm_iface[]
Definition usb_ser_hw.c:158
static bool usb_connected
Definition usb_ser_hw.c:291
bool fifo_get(fifo_t *fifo, uint8_t *pc)
Definition usb_ser_hw.c:349
arch independent USB API
void VCOM_set_linecoding(uint8_t mode)
struct link_device device
Generic device interface.
Definition usb_serial.h:59
void VCOM_allow_linecoding(uint8_t mode)
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.