Paparazzi UAS  v4.2.2_stable-4-gcc32f65
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros 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 #define INT_IN_EP 0x81
66 #define BULK_OUT_EP 0x05
67 #define BULK_IN_EP 0x82
68 
69 #define MAX_PACKET_SIZE 64
70 
71 #define LE_WORD(x) ((x)&0xFF),((x)>>8)
72 
73 // CDC definitions
74 #define CS_INTERFACE 0x24
75 #define CS_ENDPOINT 0x25
76 
77 #define SET_LINE_CODING 0x20
78 #define GET_LINE_CODING 0x21
79 #define SET_CONTROL_LINE_STATE 0x22
80 
81 #define VCOM_FIFO_SIZE 128
82 
83 #define EOF (-1)
84 #define ASSERT(x)
85 
86 typedef struct {
87  int head;
88  int tail;
90 } fifo_t;
91 
92 // data structure for GET_LINE_CODING / SET_LINE_CODING class requests
93 typedef struct {
98 } TLineCoding;
99 
101  /* this settings are virtual unless you enable line coding */
102 static TLineCoding LineCoding = {115200, 0, 0, 8};
103 static uint8_t abBulkBuf[64];
105 
108 
109 static fifo_t txfifo;
110 static fifo_t rxfifo;
111 
112 static bool BulkOut_is_blocked = false;
113 
114 // forward declaration of interrupt handler
115 static void USBIntHandler(void) __attribute__ ((interrupt("IRQ")));
116 
117 static void BulkOut(U8 bEP, U8 bEPStatus);
118 
119 #ifdef USE_USB_LINE_CODING
120 void set_linecoding(TLineCoding linecoding);
121 #endif
122 
123 void fifo_init(fifo_t *fifo, U8 *buf);
124 BOOL fifo_put(fifo_t *fifo, U8 c);
125 BOOL fifo_get(fifo_t *fifo, U8 *pc);
126 int fifo_avail(fifo_t *fifo);
127 int fifo_free(fifo_t *fifo);
128 
129 static const uint8_t abDescriptors[] = {
130 
131 // device descriptor
132  0x12,
133  DESC_DEVICE,
134  LE_WORD(0x0101), // bcdUSB
135  0x02, // bDeviceClass
136  0x00, // bDeviceSubClass
137  0x00, // bDeviceProtocol
138  MAX_PACKET_SIZE0, // bMaxPacketSize
139  LE_WORD(0x7070), // idVendor
140  LE_WORD(0x1235), // idProduct
141  LE_WORD(0x0100), // bcdDevice
142  0x01, // iManufacturer
143  0x02, // iProduct
144  0x03, // iSerialNumber
145  0x01, // bNumConfigurations
146 
147 // configuration descriptor
148  0x09,
149  DESC_CONFIGURATION,
150  LE_WORD(67), // wTotalLength
151  0x02, // bNumInterfaces
152  0x01, // bConfigurationValue
153  0x00, // iConfiguration
154  0xC0, // bmAttributes
155  0x32, // bMaxPower
156 // control class interface
157  0x09,
158  DESC_INTERFACE,
159  0x00, // bInterfaceNumber
160  0x00, // bAlternateSetting
161  0x01, // bNumEndPoints
162  0x02, // bInterfaceClass
163  0x02, // bInterfaceSubClass
164  0x01, // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module
165  0x00, // iInterface
166 // header functional descriptor
167  0x05,
168  CS_INTERFACE,
169  0x00,
170  LE_WORD(0x0110),
171 // call management functional descriptor
172  0x05,
173  CS_INTERFACE,
174  0x01,
175  0x01, // bmCapabilities = device handles call management
176  0x01, // bDataInterface
177 // ACM functional descriptor
178  0x04,
179  CS_INTERFACE,
180  0x02,
181  0x02, // bmCapabilities
182 // union functional descriptor
183  0x05,
184  CS_INTERFACE,
185  0x06,
186  0x00, // bMasterInterface
187  0x01, // bSlaveInterface0
188 // notification EP
189  0x07,
190  DESC_ENDPOINT,
191  INT_IN_EP, // bEndpointAddress
192  0x03, // bmAttributes = intr
193  LE_WORD(8), // wMaxPacketSize
194  0xFE, // bInterval
195 // data class interface descriptor
196  0x09,
197  DESC_INTERFACE,
198  0x01, // bInterfaceNumber
199  0x00, // bAlternateSetting
200  0x02, // bNumEndPoints
201  0x0A, // bInterfaceClass = data
202  0x00, // bInterfaceSubClass
203  0x00, // bInterfaceProtocol
204  0x00, // iInterface
205 // data EP OUT
206  0x07,
207  DESC_ENDPOINT,
208  BULK_OUT_EP, // bEndpointAddress
209  0x02, // bmAttributes = bulk
210  LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
211  0x00, // bInterval
212 // data EP in
213  0x07,
214  DESC_ENDPOINT,
215  BULK_IN_EP, // bEndpointAddress
216  0x02, // bmAttributes = bulk
217  LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
218  0x00, // bInterval
219 
220  // string descriptors
221  0x04,
222  DESC_STRING,
223  LE_WORD(0x0409),
224 
225  0x0E,
226  DESC_STRING,
227  'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
228 
229  0x14,
230  DESC_STRING,
231  'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,
232 
233  0x12,
234  DESC_STRING,
235  '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0,
236 
237 // terminating zero
238  0
239 };
240 
241 
242 #ifdef USE_USB_SERIAL
243 
244 void fifo_init(fifo_t *fifo, U8 *buf)
245 {
246  fifo->head = 0;
247  fifo->tail = 0;
248  fifo->buf = buf;
249 }
250 
251 BOOL fifo_put(fifo_t *fifo, U8 c)
252 {
253  int next;
254 
255  // check if FIFO has room
256  next = (fifo->head + 1) % VCOM_FIFO_SIZE;
257  if (next == fifo->tail) {
258  // full
259  return FALSE;
260  }
261 
262  fifo->buf[fifo->head] = c;
263  fifo->head = next;
264 
265  return TRUE;
266 }
267 
268 BOOL fifo_get(fifo_t *fifo, U8 *pc)
269 {
270  int next;
271 
272  // check if FIFO has data
273  if (fifo->head == fifo->tail) {
274  return FALSE;
275  }
276 
277  next = (fifo->tail + 1) % VCOM_FIFO_SIZE;
278 
279  *pc = fifo->buf[fifo->tail];
280  fifo->tail = next;
281 
282  return TRUE;
283 }
284 
285 int fifo_avail(fifo_t *fifo)
286 {
287  return (VCOM_FIFO_SIZE + fifo->head - fifo->tail) % VCOM_FIFO_SIZE;
288 }
289 
290 int fifo_free(fifo_t *fifo)
291 {
292  return (VCOM_FIFO_SIZE - 1 - fifo_avail(fifo));
293 }
294 
295 #ifdef USE_USB_LINE_CODING
296 void set_linecoding(TLineCoding linecoding)
297 {
298  uint16_t baud;
299  uint8_t mode;
300 
301  // set the baudrate
302  baud = (uint16_t)((PCLK / ((linecoding.dwDTERate) * 16.0)) + 0.5);
303 
304  // set the number of characters and other
305  // user specified operating parameters
306  switch (linecoding.bCharFormat)
307  {
308  case 0: /* 1 stop bit */
309  mode = ULCR_STOP_1;
310  break;
311  case 1: /* 1.5 stop bit (only with 5 bit character) */
312  case 2: /* 2 stop bit */
313  mode = ULCR_STOP_2;
314  break;
315  default:
316  mode = ULCR_STOP_1;
317  break;
318  }
319  switch (linecoding.bParityType)
320  {
321  case 0: mode += ULCR_PAR_NO;
322  break;
323  case 1: mode += ULCR_PAR_ODD;
324  break;
325  case 2: mode += ULCR_PAR_EVEN;
326  break;
327  case 3: mode += ULCR_PAR_MARK;
328  break;
329  case 4: mode += ULCR_PAR_SPACE;
330  break;
331  default: mode += ULCR_PAR_NO;
332  break;
333  }
334  switch (linecoding.bDataBits)
335  {
336  case 5: mode += ULCR_CHAR_5;
337  break;
338  case 6: mode += ULCR_CHAR_6;
339  break;
340  case 7: mode += ULCR_CHAR_7;
341  break;
342  case 8: mode += ULCR_CHAR_8;
343  break;
344  case 16:
345  default: mode += ULCR_CHAR_8;
346  break;
347  }
348 
349 #ifdef USE_UART0
350  U0LCR = ULCR_DLAB_ENABLE; // select divisor latches
351  U0DLL = (uint8_t)baud; // set for baud low byte
352  U0DLM = (uint8_t)(baud >> 8); // set for baud high byte
353  U0LCR = (mode & ~ULCR_DLAB_ENABLE);
354 #endif
355 #ifdef USE_UART1
356  U1LCR = ULCR_DLAB_ENABLE; // select divisor latches
357  U1DLL = (uint8_t)baud; // set for baud low byte
358  U1DLM = (uint8_t)(baud >> 8); // set for baud high byte
359  U1LCR = (mode & ~ULCR_DLAB_ENABLE);
360 #endif
361 }
362 #endif
363 
364 #ifdef USE_USB_LINE_CODING
366 {
367  allow_line_coding = mode;
368 }
369 #endif
370 
377 int VCOM_putchar(int c)
378 {
379  return fifo_put(&txfifo, c) ? c : EOF;
380 }
381 
387 int VCOM_getchar(void)
388 {
389  int result;
390  U8 c;
391 
392  result = fifo_get(&rxfifo, &c) ? c : EOF;
393 
394  if (BulkOut_is_blocked && fifo_free(&rxfifo) >= MAX_PACKET_SIZE) {
395  disableIRQ();
396  // get more data from usb bus
397  BulkOut(BULK_OUT_EP, 0);
398  BulkOut_is_blocked = false;
399  enableIRQ();
400  }
401 
402  return result;
403 }
404 
410 bool_t VCOM_check_free_space(uint8_t len)
411 {
412  return (fifo_free(&txfifo) >= len ? TRUE : FALSE);
413 }
414 
415 
421 int VCOM_check_available(void)
422 {
423  return (fifo_avail(&rxfifo));
424 }
425 
426 
433 static void BulkOut(U8 bEP, U8 bEPStatus)
434 {
435  int i, iLen;
436 
437  if (fifo_free(&rxfifo) < MAX_PACKET_SIZE) {
438  // may not fit into fifo
439  BulkOut_is_blocked = true;
440  return;
441  }
442 
443  // get data from USB into intermediate buffer
444  iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf));
445  for (i = 0; i < iLen; i++) {
446  // put into FIFO
447  if (!fifo_put(&rxfifo, abBulkBuf[i])) {
448  // overflow... :(
449  ASSERT(FALSE);
450  break;
451  }
452  }
453 }
454 
455 
462 static void BulkIn(U8 bEP, U8 bEPStatus)
463 {
464  int i, iLen;
465 
466  if (fifo_avail(&txfifo) == 0) {
467  // no more data, disable further NAK interrupts until next USB frame
468  USBHwNakIntEnable(0);
469  return;
470  }
471 
472  // get bytes from transmit FIFO into intermediate buffer
473  for (i = 0; i < MAX_PACKET_SIZE; i++) {
474  if (!fifo_get(&txfifo, &abBulkBuf[i])) {
475  break;
476  }
477  }
478  iLen = i;
479 
480  // send over USB
481  if (iLen > 0) {
482  USBHwEPWrite(bEP, abBulkBuf, iLen);
483  }
484 }
485 
486 
494 static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
495 {
496  switch (pSetup->bRequest) {
497 
498  // set line coding
499  case SET_LINE_CODING:
500  memcpy((U8 *)&LineCoding, *ppbData, 7);
501  *piLen = 7;
502 #ifdef USE_USB_LINE_CODING
503  if (allow_line_coding)
504  {
505  set_linecoding(LineCoding);
506  }
507 #endif
508  break;
509 
510  // get line coding
511  case GET_LINE_CODING:
512  *ppbData = (U8 *)&LineCoding;
513  *piLen = 7;
514  break;
515 
516  // set control line state
518  // bit0 = DTR, bit1 = RTS
519  break;
520 
521  default:
522  return FALSE;
523  }
524  return TRUE;
525 }
526 
527 
533 static void USBIntHandler(void)
534 {
535  USBHwISR();
536  VICVectAddr = 0x00; // dummy write to VIC to signal end of ISR
537 }
538 
539 
540 static void USBFrameHandler(U16 wFrame)
541 {
542  if (fifo_avail(&txfifo) > 0) {
543  // data available, enable NAK interrupt on bulk in
544  USBHwNakIntEnable(INACK_BI);
545  }
546 }
547 
548 
549 void VCOM_init(void) {
550  // initialise stack
551  USBInit();
552 #ifdef USE_USB_LINE_CODING
553  // set default line coding
554  set_linecoding(LineCoding);
555 #endif
556 
557  // register descriptors
558  USBRegisterDescriptors(abDescriptors);
559 
560  // register class request handler
561  USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);
562 
563  // register endpoint handlers
564  USBHwRegisterEPIntHandler(INT_IN_EP, NULL);
565  USBHwRegisterEPIntHandler(BULK_IN_EP, BulkIn);
566  USBHwRegisterEPIntHandler(BULK_OUT_EP, BulkOut);
567 
568  // register frame handler
569  USBHwRegisterFrameHandler(USBFrameHandler);
570 
571  // enable bulk-in interrupts on NAKs
572  USBHwNakIntEnable(INACK_BI);
573 
574  // initialise fifos
575  fifo_init(&txfifo, txdata);
576  fifo_init(&rxfifo, rxdata);
577 
578  // set up USB interrupt
579  VICIntSelect &= ~VIC_BIT(VIC_USB); // select IRQ for USB
581 
584 
585  // connect to bus
586  USBHwConnect(TRUE);
587 }
588 
589 
590 #endif /* USE_USB_SERIAL */
#define VICIntSelect
Definition: LPC21xx.h:398
unsigned short uint16_t
Definition: types.h:16
bool_t VCOM_check_free_space(uint8_t len)
#define VICVectCntl10
Definition: LPC21xx.h:432
static fifo_t rxfifo
Definition: usb_ser_hw.c:110
#define ULCR_CHAR_6
Definition: lpcUART.h:83
#define ULCR_STOP_2
Definition: lpcUART.h:87
int VCOM_check_available(void)
static void USBIntHandler(void)
Definition: usb_ser_hw.c:115
#define PCLK
Definition: booz_1.0.h:18
int allow_line_coding
Definition: usb_ser_hw.c:100
#define VCOM_FIFO_SIZE
Definition: usb_ser_hw.c:81
uint8_t bDataBits
Definition: usb_ser_hw.c:97
#define BULK_OUT_EP
Definition: usb_ser_hw.c:66
static uint8_t rxdata[VCOM_FIFO_SIZE]
Definition: usb_ser_hw.c:107
#define ULCR_PAR_SPACE
Definition: lpcUART.h:92
#define U1DLL
Definition: LPC21xx.h:149
static const U8 abDescriptors[]
Definition: usb_msc_hw.c:84
#define VIC_USB
Definition: lpcVIC.h:92
static TLineCoding LineCoding
Definition: usb_ser_hw.c:102
#define GET_LINE_CODING
Definition: usb_ser_hw.c:78
#define FALSE
Definition: imu_chimu.h:141
uint8_t * buf
Definition: usb_ser_hw.c:89
#define ULCR_CHAR_7
Definition: lpcUART.h:84
#define U0DLM
Definition: LPC21xx.h:128
uint8_t bParityType
Definition: usb_ser_hw.c:96
unsigned enableIRQ(void)
Definition: armVIC.c:51
#define MAX_PACKET_SIZE
Definition: usb_ser_hw.c:69
static uint8_t abClassReqData[8]
Definition: usb_ser_hw.c:104
int VCOM_putchar(int c)
void VCOM_init(void)
#define VICVectAddr
Definition: LPC21xx.h:404
unsigned long uint32_t
Definition: types.h:18
#define SET_CONTROL_LINE_STATE
Definition: usb_ser_hw.c:79
int head
Definition: usb_ser_hw.c:87
int tail
Definition: usb_ser_hw.c:88
#define SET_LINE_CODING
Definition: usb_ser_hw.c:77
static fifo_t txfifo
Definition: usb_ser_hw.c:109
#define VIC_BIT(chan)
Definition: lpcVIC.h:105
#define TRUE
Definition: imu_chimu.h:144
#define EOF
Definition: usb_ser_hw.c:83
static bool BulkOut_is_blocked
Definition: usb_ser_hw.c:112
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
#define VICIntEnable
Definition: LPC21xx.h:399
#define ULCR_PAR_EVEN
Definition: lpcUART.h:90
#define CS_INTERFACE
Definition: usb_ser_hw.c:74
#define ASSERT(x)
Definition: usb_ser_hw.c:84
#define ULCR_PAR_NO
Definition: lpcUART.h:88
#define ULCR_PAR_ODD
Definition: lpcUART.h:89
#define VICVectAddr10
Definition: LPC21xx.h:416
static uint8_t abBulkBuf[64]
Definition: usb_ser_hw.c:103
#define ULCR_CHAR_5
Definition: lpcUART.h:82
uint8_t bCharFormat
Definition: usb_ser_hw.c:95
uint32_t dwDTERate
Definition: usb_ser_hw.c:94
static struct point c
Definition: discsurvey.c:13
int VCOM_getchar(void)
#define LE_WORD(x)
Definition: usb_ser_hw.c:71
static uint8_t txdata[VCOM_FIFO_SIZE]
Definition: usb_ser_hw.c:106
#define ULCR_CHAR_8
Definition: lpcUART.h:85
#define U1DLM
Definition: LPC21xx.h:150
#define INT_IN_EP
Definition: usb_ser_hw.c:65
__attribute__((always_inline))
Definition: i2c_arch.c:35
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:67