Paparazzi UAS  v5.2.2_stable-0-gd6b9f29
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
usb_ser_hw.c
Go to the documentation of this file.
1 /*
2  LPCUSB, an USB device driver for LPC microcontrollers
3  Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
4  adapted to pprz Martin Mueller (martinmm@pfump.org)
5 
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions are met:
8 
9  1. Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  2. Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in the
13  documentation and/or other materials provided with the distribution.
14  3. The name of the author may not be used to endorse or promote products
15  derived from this software without specific prior written permission.
16 
17  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 /*
30  Minimal implementation of a USB serial port, using the CDC class.
31  This example application simply echoes everything it receives right back
32  to the host.
33 
34  Windows:
35  Extract the usbser.sys file from .cab file in C:\WINDOWS\Driver Cache\i386
36  and store it somewhere (C:\temp is a good place) along with the usbser.inf
37  file. Then plug in the LPC214x and direct windows to the usbser driver.
38  Windows then creates an extra COMx port that you can open in a terminal
39  program, like hyperterminal.
40 
41  Linux:
42  The device should be recognised automatically by the cdc_acm driver,
43  which creates a /dev/ttyACMx device file that acts just like a regular
44  serial port.
45 
46 */
47 
48 
49 #include <string.h>
50 #include "std.h"
51 #include <stdbool.h>
52 #include "LPC21xx.h"
53 #include "armVIC.h"
54 #include "mcu_periph/usb_serial.h"
55 #include BOARD_CONFIG
56 
57 #include "lpcusb/usbapi.h"
58 
59 #ifdef USE_USB_SERIAL
60 #if PCLK < 18000000
61 #error PCLK needs to be higher than 18MHz for USB to work properly
62 #endif
63 #endif
64 
65 #ifndef USB_VIC_SLOT
66 #define USB_VIC_SLOT 10
67 #endif
68 
69 #define INT_IN_EP 0x81
70 #define BULK_OUT_EP 0x05
71 #define BULK_IN_EP 0x82
72 
73 #define MAX_PACKET_SIZE 64
74 
75 #define LE_WORD(x) ((x)&0xFF),((x)>>8)
76 
77 // CDC definitions
78 #define CS_INTERFACE 0x24
79 #define CS_ENDPOINT 0x25
80 
81 #define SET_LINE_CODING 0x20
82 #define GET_LINE_CODING 0x21
83 #define SET_CONTROL_LINE_STATE 0x22
84 
85 #define VCOM_FIFO_SIZE 128
86 
87 #define EOF (-1)
88 #define ASSERT(x)
89 
90 typedef struct {
91  int head;
92  int tail;
94 } fifo_t;
95 
96 // data structure for GET_LINE_CODING / SET_LINE_CODING class requests
97 typedef struct {
102 } TLineCoding;
103 
105  /* this settings are virtual unless you enable line coding */
106 static TLineCoding LineCoding = {115200, 0, 0, 8};
107 static uint8_t abBulkBuf[64];
109 
112 
113 static fifo_t txfifo;
114 static fifo_t rxfifo;
115 
116 static bool BulkOut_is_blocked = false;
117 
118 // forward declaration of interrupt handler
119 static void USBIntHandler(void) __attribute__ ((interrupt("IRQ")));
120 
121 static void BulkOut(U8 bEP, U8 bEPStatus);
122 
123 #ifdef USE_USB_LINE_CODING
124 void set_linecoding(TLineCoding linecoding);
125 #endif
126 
127 void fifo_init(fifo_t *fifo, U8 *buf);
128 BOOL fifo_put(fifo_t *fifo, U8 c);
129 BOOL fifo_get(fifo_t *fifo, U8 *pc);
130 int fifo_avail(fifo_t *fifo);
131 int fifo_free(fifo_t *fifo);
132 
133 static const uint8_t abDescriptors[] = {
134 
135 // device descriptor
136  0x12,
137  DESC_DEVICE,
138  LE_WORD(0x0101), // bcdUSB
139  0x02, // bDeviceClass
140  0x00, // bDeviceSubClass
141  0x00, // bDeviceProtocol
142  MAX_PACKET_SIZE0, // bMaxPacketSize
143  LE_WORD(0x7070), // idVendor
144  LE_WORD(0x1235), // idProduct
145  LE_WORD(0x0100), // bcdDevice
146  0x01, // iManufacturer
147  0x02, // iProduct
148  0x03, // iSerialNumber
149  0x01, // bNumConfigurations
150 
151 // configuration descriptor
152  0x09,
153  DESC_CONFIGURATION,
154  LE_WORD(67), // wTotalLength
155  0x02, // bNumInterfaces
156  0x01, // bConfigurationValue
157  0x00, // iConfiguration
158  0xC0, // bmAttributes
159  0x32, // bMaxPower
160 // control class interface
161  0x09,
162  DESC_INTERFACE,
163  0x00, // bInterfaceNumber
164  0x00, // bAlternateSetting
165  0x01, // bNumEndPoints
166  0x02, // bInterfaceClass
167  0x02, // bInterfaceSubClass
168  0x01, // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module
169  0x00, // iInterface
170 // header functional descriptor
171  0x05,
172  CS_INTERFACE,
173  0x00,
174  LE_WORD(0x0110),
175 // call management functional descriptor
176  0x05,
177  CS_INTERFACE,
178  0x01,
179  0x01, // bmCapabilities = device handles call management
180  0x01, // bDataInterface
181 // ACM functional descriptor
182  0x04,
183  CS_INTERFACE,
184  0x02,
185  0x02, // bmCapabilities
186 // union functional descriptor
187  0x05,
188  CS_INTERFACE,
189  0x06,
190  0x00, // bMasterInterface
191  0x01, // bSlaveInterface0
192 // notification EP
193  0x07,
194  DESC_ENDPOINT,
195  INT_IN_EP, // bEndpointAddress
196  0x03, // bmAttributes = intr
197  LE_WORD(8), // wMaxPacketSize
198  0xFE, // bInterval
199 // data class interface descriptor
200  0x09,
201  DESC_INTERFACE,
202  0x01, // bInterfaceNumber
203  0x00, // bAlternateSetting
204  0x02, // bNumEndPoints
205  0x0A, // bInterfaceClass = data
206  0x00, // bInterfaceSubClass
207  0x00, // bInterfaceProtocol
208  0x00, // iInterface
209 // data EP OUT
210  0x07,
211  DESC_ENDPOINT,
212  BULK_OUT_EP, // bEndpointAddress
213  0x02, // bmAttributes = bulk
214  LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
215  0x00, // bInterval
216 // data EP in
217  0x07,
218  DESC_ENDPOINT,
219  BULK_IN_EP, // bEndpointAddress
220  0x02, // bmAttributes = bulk
221  LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
222  0x00, // bInterval
223 
224  // string descriptors
225  0x04,
226  DESC_STRING,
227  LE_WORD(0x0409),
228 
229  0x0E,
230  DESC_STRING,
231  'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
232 
233  0x14,
234  DESC_STRING,
235  'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,
236 
237  0x12,
238  DESC_STRING,
239  '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0,
240 
241 // terminating zero
242  0
243 };
244 
245 
246 #ifdef USE_USB_SERIAL
247 
248 void fifo_init(fifo_t *fifo, U8 *buf)
249 {
250  fifo->head = 0;
251  fifo->tail = 0;
252  fifo->buf = buf;
253 }
254 
255 BOOL fifo_put(fifo_t *fifo, U8 c)
256 {
257  int next;
258 
259  // check if FIFO has room
260  next = (fifo->head + 1) % VCOM_FIFO_SIZE;
261  if (next == fifo->tail) {
262  // full
263  return FALSE;
264  }
265 
266  fifo->buf[fifo->head] = c;
267  fifo->head = next;
268 
269  return TRUE;
270 }
271 
272 BOOL fifo_get(fifo_t *fifo, U8 *pc)
273 {
274  int next;
275 
276  // check if FIFO has data
277  if (fifo->head == fifo->tail) {
278  return FALSE;
279  }
280 
281  next = (fifo->tail + 1) % VCOM_FIFO_SIZE;
282 
283  *pc = fifo->buf[fifo->tail];
284  fifo->tail = next;
285 
286  return TRUE;
287 }
288 
289 int fifo_avail(fifo_t *fifo)
290 {
291  return (VCOM_FIFO_SIZE + fifo->head - fifo->tail) % VCOM_FIFO_SIZE;
292 }
293 
294 int fifo_free(fifo_t *fifo)
295 {
296  return (VCOM_FIFO_SIZE - 1 - fifo_avail(fifo));
297 }
298 
299 #ifdef USE_USB_LINE_CODING
300 void set_linecoding(TLineCoding linecoding)
301 {
302  uint16_t baud;
303  uint8_t mode;
304 
305  // set the baudrate
306  baud = (uint16_t)((PCLK / ((linecoding.dwDTERate) * 16.0)) + 0.5);
307 
308  // set the number of characters and other
309  // user specified operating parameters
310  switch (linecoding.bCharFormat)
311  {
312  case 0: /* 1 stop bit */
313  mode = ULCR_STOP_1;
314  break;
315  case 1: /* 1.5 stop bit (only with 5 bit character) */
316  case 2: /* 2 stop bit */
317  mode = ULCR_STOP_2;
318  break;
319  default:
320  mode = ULCR_STOP_1;
321  break;
322  }
323  switch (linecoding.bParityType)
324  {
325  case 0: mode += ULCR_PAR_NO;
326  break;
327  case 1: mode += ULCR_PAR_ODD;
328  break;
329  case 2: mode += ULCR_PAR_EVEN;
330  break;
331  case 3: mode += ULCR_PAR_MARK;
332  break;
333  case 4: mode += ULCR_PAR_SPACE;
334  break;
335  default: mode += ULCR_PAR_NO;
336  break;
337  }
338  switch (linecoding.bDataBits)
339  {
340  case 5: mode += ULCR_CHAR_5;
341  break;
342  case 6: mode += ULCR_CHAR_6;
343  break;
344  case 7: mode += ULCR_CHAR_7;
345  break;
346  case 8: mode += ULCR_CHAR_8;
347  break;
348  case 16:
349  default: mode += ULCR_CHAR_8;
350  break;
351  }
352 
353 #if USE_UART0
354  U0LCR = ULCR_DLAB_ENABLE; // select divisor latches
355  U0DLL = (uint8_t)baud; // set for baud low byte
356  U0DLM = (uint8_t)(baud >> 8); // set for baud high byte
357  U0LCR = (mode & ~ULCR_DLAB_ENABLE);
358 #endif
359 #if USE_UART1
360  U1LCR = ULCR_DLAB_ENABLE; // select divisor latches
361  U1DLL = (uint8_t)baud; // set for baud low byte
362  U1DLM = (uint8_t)(baud >> 8); // set for baud high byte
363  U1LCR = (mode & ~ULCR_DLAB_ENABLE);
364 #endif
365 }
366 #endif
367 
368 #ifdef USE_USB_LINE_CODING
370 {
371  allow_line_coding = mode;
372 }
373 #endif
374 
381 int VCOM_putchar(int c)
382 {
383  return fifo_put(&txfifo, c) ? c : EOF;
384 }
385 
391 int VCOM_getchar(void)
392 {
393  int result;
394  U8 c;
395 
396  result = fifo_get(&rxfifo, &c) ? c : EOF;
397 
398  if (BulkOut_is_blocked && fifo_free(&rxfifo) >= MAX_PACKET_SIZE) {
399  disableIRQ();
400  // get more data from usb bus
401  BulkOut(BULK_OUT_EP, 0);
402  BulkOut_is_blocked = false;
403  enableIRQ();
404  }
405 
406  return result;
407 }
408 
414 bool_t VCOM_check_free_space(uint8_t len)
415 {
416  return (fifo_free(&txfifo) >= len ? TRUE : FALSE);
417 }
418 
419 
425 int VCOM_check_available(void)
426 {
427  return (fifo_avail(&rxfifo));
428 }
429 
430 
437 static void BulkOut(U8 bEP, U8 bEPStatus)
438 {
439  int i, iLen;
440 
441  if (fifo_free(&rxfifo) < MAX_PACKET_SIZE) {
442  // may not fit into fifo
443  BulkOut_is_blocked = true;
444  return;
445  }
446 
447  // get data from USB into intermediate buffer
448  iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf));
449  for (i = 0; i < iLen; i++) {
450  // put into FIFO
451  if (!fifo_put(&rxfifo, abBulkBuf[i])) {
452  // overflow... :(
453  ASSERT(FALSE);
454  break;
455  }
456  }
457 }
458 
459 
466 static void BulkIn(U8 bEP, U8 bEPStatus)
467 {
468  int i, iLen;
469 
470  if (fifo_avail(&txfifo) == 0) {
471  // no more data, disable further NAK interrupts until next USB frame
472  USBHwNakIntEnable(0);
473  return;
474  }
475 
476  // get bytes from transmit FIFO into intermediate buffer
477  for (i = 0; i < MAX_PACKET_SIZE; i++) {
478  if (!fifo_get(&txfifo, &abBulkBuf[i])) {
479  break;
480  }
481  }
482  iLen = i;
483 
484  // send over USB
485  if (iLen > 0) {
486  USBHwEPWrite(bEP, abBulkBuf, iLen);
487  }
488 }
489 
490 
498 static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
499 {
500  switch (pSetup->bRequest) {
501 
502  // set line coding
503  case SET_LINE_CODING:
504  memcpy((U8 *)&LineCoding, *ppbData, 7);
505  *piLen = 7;
506 #ifdef USE_USB_LINE_CODING
507  if (allow_line_coding)
508  {
509  set_linecoding(LineCoding);
510  }
511 #endif
512  break;
513 
514  // get line coding
515  case GET_LINE_CODING:
516  *ppbData = (U8 *)&LineCoding;
517  *piLen = 7;
518  break;
519 
520  // set control line state
522  // bit0 = DTR, bit1 = RTS
523  break;
524 
525  default:
526  return FALSE;
527  }
528  return TRUE;
529 }
530 
531 
537 static void USBIntHandler(void)
538 {
539  USBHwISR();
540  VICVectAddr = 0x00; // dummy write to VIC to signal end of ISR
541 }
542 
543 
544 static void USBFrameHandler(U16 wFrame)
545 {
546  if (fifo_avail(&txfifo) > 0) {
547  // data available, enable NAK interrupt on bulk in
548  USBHwNakIntEnable(INACK_BI);
549  }
550 }
551 
552 
553 void VCOM_init(void) {
554  // initialise stack
555  USBInit();
556 #ifdef USE_USB_LINE_CODING
557  // set default line coding
558  set_linecoding(LineCoding);
559 #endif
560 
561  // register descriptors
562  USBRegisterDescriptors(abDescriptors);
563 
564  // register class request handler
565  USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);
566 
567  // register endpoint handlers
568  USBHwRegisterEPIntHandler(INT_IN_EP, NULL);
569  USBHwRegisterEPIntHandler(BULK_IN_EP, BulkIn);
570  USBHwRegisterEPIntHandler(BULK_OUT_EP, BulkOut);
571 
572  // register frame handler
573  USBHwRegisterFrameHandler(USBFrameHandler);
574 
575  // enable bulk-in interrupts on NAKs
576  USBHwNakIntEnable(INACK_BI);
577 
578  // initialise fifos
579  fifo_init(&txfifo, txdata);
580  fifo_init(&rxfifo, rxdata);
581 
582  // set up USB interrupt
583  VICIntSelect &= ~VIC_BIT(VIC_USB); // select IRQ for USB
585 
588 
589  // connect to bus
590  USBHwConnect(TRUE);
591 }
592 
593 
594 #endif /* USE_USB_SERIAL */
#define VICIntSelect
Definition: LPC21xx.h:430
unsigned short uint16_t
Definition: types.h:16
bool_t VCOM_check_free_space(uint8_t len)
int fifo_avail(fifo_t *fifo)
BOOL fifo_get(fifo_t *fifo, U8 *pc)
static fifo_t rxfifo
Definition: usb_ser_hw.c:114
#define USB_VIC_SLOT
Definition: usb_ser_hw.c:66
#define _VIC_CNTL(idx)
Definition: armVIC.h:19
#define ULCR_CHAR_6
Definition: lpcUART.h:83
#define ULCR_STOP_2
Definition: lpcUART.h:87
int VCOM_check_available(void)
static const uint8_t abDescriptors[]
Definition: usb_ser_hw.c:133
static void USBIntHandler(void)
#define PCLK
Definition: booz_1.0.h:18
int allow_line_coding
Definition: usb_ser_hw.c:104
#define VCOM_FIFO_SIZE
Definition: usb_ser_hw.c:85
uint8_t bDataBits
Definition: usb_ser_hw.c:101
#define BULK_OUT_EP
Definition: usb_ser_hw.c:70
static uint8_t rxdata[VCOM_FIFO_SIZE]
Definition: usb_ser_hw.c:111
#define ULCR_PAR_SPACE
Definition: lpcUART.h:92
#define U1DLL
Definition: LPC21xx.h:149
#define VIC_USB
Definition: lpcVIC.h:92
static TLineCoding LineCoding
Definition: usb_ser_hw.c:106
#define GET_LINE_CODING
Definition: usb_ser_hw.c:82
#define _VIC_ADDR(idx)
Definition: armVIC.h:20
#define FALSE
Definition: imu_chimu.h:141
uint8_t * buf
Definition: usb_ser_hw.c:93
#define ULCR_CHAR_7
Definition: lpcUART.h:84
#define U0DLM
Definition: LPC21xx.h:128
uint8_t bParityType
Definition: usb_ser_hw.c:100
BOOL fifo_put(fifo_t *fifo, U8 c)
unsigned enableIRQ(void)
Definition: armVIC.c:51
#define MAX_PACKET_SIZE
Definition: usb_ser_hw.c:73
static uint8_t abClassReqData[8]
Definition: usb_ser_hw.c:108
int VCOM_putchar(int c)
void VCOM_init(void)
#define VICVectAddr
Definition: LPC21xx.h:436
unsigned long uint32_t
Definition: types.h:18
#define SET_CONTROL_LINE_STATE
Definition: usb_ser_hw.c:83
int head
Definition: usb_ser_hw.c:91
void fifo_init(fifo_t *fifo, U8 *buf)
int tail
Definition: usb_ser_hw.c:92
#define SET_LINE_CODING
Definition: usb_ser_hw.c:81
static fifo_t txfifo
Definition: usb_ser_hw.c:113
#define VIC_BIT(chan)
Definition: lpcVIC.h:105
#define TRUE
Definition: imu_chimu.h:144
struct adc_buf * buf
Definition: adc_arch.c:586
#define EOF
Definition: usb_ser_hw.c:87
static bool BulkOut_is_blocked
Definition: usb_ser_hw.c:116
unsigned char uint8_t
Definition: types.h:14
#define U0LCR
Definition: LPC21xx.h:124
unsigned disableIRQ(void)
Definition: armVIC.c:33
#define U0DLL
Definition: LPC21xx.h:127
int fifo_free(fifo_t *fifo)
#define VICIntEnable
Definition: LPC21xx.h:431
#define ULCR_PAR_EVEN
Definition: lpcUART.h:90
#define CS_INTERFACE
Definition: usb_ser_hw.c:78
#define ASSERT(x)
Definition: usb_ser_hw.c:88
#define ULCR_PAR_NO
Definition: lpcUART.h:88
#define ULCR_PAR_ODD
Definition: lpcUART.h:89
static uint8_t abBulkBuf[64]
Definition: usb_ser_hw.c:107
#define ULCR_CHAR_5
Definition: lpcUART.h:82
uint8_t bCharFormat
Definition: usb_ser_hw.c:99
uint32_t dwDTERate
Definition: usb_ser_hw.c:98
static void BulkOut(U8 bEP, U8 bEPStatus)
int VCOM_getchar(void)
#define LE_WORD(x)
Definition: usb_ser_hw.c:75
static uint8_t txdata[VCOM_FIFO_SIZE]
Definition: usb_ser_hw.c:110
#define ULCR_CHAR_8
Definition: lpcUART.h:85
#define U1DLM
Definition: LPC21xx.h:150
#define INT_IN_EP
Definition: usb_ser_hw.c:69
void VCOM_allow_linecoding(uint8_t mode)
#define ULCR_PAR_MARK
Definition: lpcUART.h:91
#define VIC_ENABLE
Definition: lpcVIC.h:102
#define ULCR_STOP_1
Definition: lpcUART.h:86
#define U1LCR
Definition: LPC21xx.h:144
arch independent USB API
#define ULCR_DLAB_ENABLE
Definition: lpcUART.h:94
#define BULK_IN_EP
Definition: usb_ser_hw.c:71