]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LPC1768_IAR/LPCUSB/USB_CDC.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / CORTEX_LPC1768_IAR / LPCUSB / USB_CDC.c
1 /*\r
2         LPCUSB, an USB device driver for LPC microcontrollers   \r
3         Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)\r
4 \r
5         Redistribution and use in source and binary forms, with or without\r
6         modification, are permitted provided that the following conditions are met:\r
7 \r
8         1. Redistributions of source code must retain the above copyright\r
9            notice, this list of conditions and the following disclaimer.\r
10         2. Redistributions in binary form must reproduce the above copyright\r
11            notice, this list of conditions and the following disclaimer in the\r
12            documentation and/or other materials provided with the distribution.\r
13         3. The name of the author may not be used to endorse or promote products\r
14            derived from this software without specific prior written permission.\r
15 \r
16         THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
17         IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
18         OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
19         IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
20         INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
21         NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
22         DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
23         THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
24         (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
25         THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
26 */\r
27 \r
28 /*\r
29         Minimal implementation of a USB serial port, using the CDC class.\r
30         This example application simply echoes everything it receives right back\r
31         to the host.\r
32 \r
33         Windows:\r
34         Extract the usbser.sys file from .cab file in C:\WINDOWS\Driver Cache\i386\r
35         and store it somewhere (C:\temp is a good place) along with the usbser.inf\r
36         file. Then plug in the LPC176x and direct windows to the usbser driver.\r
37         Windows then creates an extra COMx port that you can open in a terminal\r
38         program, like hyperterminal. [Note for FreeRTOS users - the required .inf\r
39         file is included in the project directory.]\r
40 \r
41         Linux:\r
42         The device should be recognised automatically by the cdc_acm driver,\r
43         which creates a /dev/ttyACMx device file that acts just like a regular\r
44         serial port.\r
45 \r
46 */\r
47 \r
48 #include "FreeRTOS.h"\r
49 #include "task.h"\r
50 #include "queue.h"\r
51 \r
52 #include <stdio.h>\r
53 #include <string.h>\r
54 \r
55 #include "usbapi.h"\r
56 #include "usbdebug.h"\r
57 #include "usbstruct.h"\r
58 \r
59 #include "LPC17xx.h"\r
60 \r
61 #define usbMAX_SEND_BLOCK               ( 20 / portTICK_RATE_MS )\r
62 #define usbBUFFER_LEN                   ( 20 )\r
63 \r
64 #define INCREMENT_ECHO_BY 1\r
65 #define BAUD_RATE       115200\r
66 \r
67 #define INT_IN_EP               0x81\r
68 #define BULK_OUT_EP             0x05\r
69 #define BULK_IN_EP              0x82\r
70 \r
71 #define MAX_PACKET_SIZE 64\r
72 \r
73 #define LE_WORD(x)              ((x)&0xFF),((x)>>8)\r
74 \r
75 // CDC definitions\r
76 #define CS_INTERFACE                    0x24\r
77 #define CS_ENDPOINT                             0x25\r
78 \r
79 #define SET_LINE_CODING                 0x20\r
80 #define GET_LINE_CODING                 0x21\r
81 #define SET_CONTROL_LINE_STATE  0x22\r
82 \r
83 // data structure for GET_LINE_CODING / SET_LINE_CODING class requests\r
84 typedef struct {\r
85         unsigned long           dwDTERate;\r
86         unsigned char           bCharFormat;\r
87         unsigned char           bParityType;\r
88         unsigned char           bDataBits;\r
89 } TLineCoding;\r
90 \r
91 static TLineCoding LineCoding = {115200, 0, 0, 8};\r
92 static unsigned char abBulkBuf[64];\r
93 static unsigned char abClassReqData[8];\r
94 \r
95 static xQueueHandle xRxedChars = NULL, xCharsForTx = NULL;\r
96 \r
97 // forward declaration of interrupt handler\r
98 void USBIntHandler(void);\r
99 \r
100 static const unsigned char abDescriptors[] = {\r
101 \r
102 // device descriptor\r
103         0x12,\r
104         DESC_DEVICE,\r
105         LE_WORD(0x0101),                        // bcdUSB\r
106         0x02,                                           // bDeviceClass\r
107         0x00,                                           // bDeviceSubClass\r
108         0x00,                                           // bDeviceProtocol\r
109         MAX_PACKET_SIZE0,                       // bMaxPacketSize\r
110         LE_WORD(0xFFFF),                        // idVendor\r
111         LE_WORD(0x0005),                        // idProduct\r
112         LE_WORD(0x0100),                        // bcdDevice\r
113         0x01,                                           // iManufacturer\r
114         0x02,                                           // iProduct\r
115         0x03,                                           // iSerialNumber\r
116         0x01,                                           // bNumConfigurations\r
117 \r
118 // configuration descriptor\r
119         0x09,\r
120         DESC_CONFIGURATION,\r
121         LE_WORD(67),                            // wTotalLength\r
122         0x02,                                           // bNumInterfaces\r
123         0x01,                                           // bConfigurationValue\r
124         0x00,                                           // iConfiguration\r
125         0xC0,                                           // bmAttributes\r
126         0x32,                                           // bMaxPower\r
127 // control class interface\r
128         0x09,\r
129         DESC_INTERFACE,\r
130         0x00,                                           // bInterfaceNumber\r
131         0x00,                                           // bAlternateSetting\r
132         0x01,                                           // bNumEndPoints\r
133         0x02,                                           // bInterfaceClass\r
134         0x02,                                           // bInterfaceSubClass\r
135         0x01,                                           // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module\r
136         0x00,                                           // iInterface\r
137 // header functional descriptor\r
138         0x05,\r
139         CS_INTERFACE,\r
140         0x00,\r
141         LE_WORD(0x0110),\r
142 // call management functional descriptor\r
143         0x05,\r
144         CS_INTERFACE,\r
145         0x01,\r
146         0x01,                                           // bmCapabilities = device handles call management\r
147         0x01,                                           // bDataInterface\r
148 // ACM functional descriptor\r
149         0x04,\r
150         CS_INTERFACE,\r
151         0x02,\r
152         0x02,                                           // bmCapabilities\r
153 // union functional descriptor\r
154         0x05,\r
155         CS_INTERFACE,\r
156         0x06,\r
157         0x00,                                           // bMasterInterface\r
158         0x01,                                           // bSlaveInterface0\r
159 // notification EP\r
160         0x07,\r
161         DESC_ENDPOINT,\r
162         INT_IN_EP,                                      // bEndpointAddress\r
163         0x03,                                           // bmAttributes = intr\r
164         LE_WORD(8),                                     // wMaxPacketSize\r
165         0x0A,                                           // bInterval\r
166 // data class interface descriptor\r
167         0x09,\r
168         DESC_INTERFACE,\r
169         0x01,                                           // bInterfaceNumber\r
170         0x00,                                           // bAlternateSetting\r
171         0x02,                                           // bNumEndPoints\r
172         0x0A,                                           // bInterfaceClass = data\r
173         0x00,                                           // bInterfaceSubClass\r
174         0x00,                                           // bInterfaceProtocol\r
175         0x00,                                           // iInterface\r
176 // data EP OUT\r
177         0x07,\r
178         DESC_ENDPOINT,\r
179         BULK_OUT_EP,                            // bEndpointAddress\r
180         0x02,                                           // bmAttributes = bulk\r
181         LE_WORD(MAX_PACKET_SIZE),       // wMaxPacketSize\r
182         0x00,                                           // bInterval\r
183 // data EP in\r
184         0x07,\r
185         DESC_ENDPOINT,\r
186         BULK_IN_EP,                                     // bEndpointAddress\r
187         0x02,                                           // bmAttributes = bulk\r
188         LE_WORD(MAX_PACKET_SIZE),       // wMaxPacketSize\r
189         0x00,                                           // bInterval\r
190         \r
191         // string descriptors\r
192         0x04,\r
193         DESC_STRING,\r
194         LE_WORD(0x0409),\r
195 \r
196         0x0E,\r
197         DESC_STRING,\r
198         'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,\r
199 \r
200         0x14,\r
201         DESC_STRING,\r
202         'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,\r
203 \r
204         0x12,\r
205         DESC_STRING,\r
206         'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,\r
207 \r
208 // terminating zero\r
209         0\r
210 };\r
211 \r
212 \r
213 /**\r
214         Local function to handle incoming bulk data\r
215                 \r
216         @param [in] bEP\r
217         @param [in] bEPStatus\r
218  */\r
219 static void BulkOut(unsigned char bEP, unsigned char bEPStatus)\r
220 {\r
221         int i, iLen;\r
222         long lHigherPriorityTaskWoken = pdFALSE;\r
223 \r
224         ( void ) bEPStatus;\r
225         \r
226         // get data from USB into intermediate buffer\r
227         iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf));\r
228         for (i = 0; i < iLen; i++) {\r
229                 // put into queue\r
230                 xQueueSendFromISR( xRxedChars, &( abBulkBuf[ i ] ), &lHigherPriorityTaskWoken );\r
231         }\r
232         \r
233         portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
234 }\r
235 \r
236 \r
237 /**\r
238         Local function to handle outgoing bulk data\r
239                 \r
240         @param [in] bEP\r
241         @param [in] bEPStatus\r
242  */\r
243 static void BulkIn(unsigned char bEP, unsigned char bEPStatus)\r
244 {\r
245         int i, iLen;\r
246         long lHigherPriorityTaskWoken = pdFALSE;\r
247 \r
248         ( void ) bEPStatus;\r
249         \r
250         if (uxQueueMessagesWaitingFromISR( xCharsForTx ) == 0) {\r
251                 // no more data, disable further NAK interrupts until next USB frame\r
252                 USBHwNakIntEnable(0);\r
253                 return;\r
254         }\r
255 \r
256         // get bytes from transmit FIFO into intermediate buffer\r
257         for (i = 0; i < MAX_PACKET_SIZE; i++) {\r
258                 if( xQueueReceiveFromISR( xCharsForTx, ( &abBulkBuf[i] ), &lHigherPriorityTaskWoken ) != pdPASS )\r
259                 {\r
260                         break;\r
261                 }\r
262         }\r
263         iLen = i;\r
264         \r
265         // send over USB\r
266         if (iLen > 0) {\r
267                 USBHwEPWrite(bEP, abBulkBuf, iLen);\r
268         }\r
269         \r
270         portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
271 }\r
272 \r
273 \r
274 /**\r
275         Local function to handle the USB-CDC class requests\r
276                 \r
277         @param [in] pSetup\r
278         @param [out] piLen\r
279         @param [out] ppbData\r
280  */\r
281 static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData)\r
282 {\r
283         switch (pSetup->bRequest) {\r
284 \r
285         // set line coding\r
286         case SET_LINE_CODING:\r
287 DBG("SET_LINE_CODING\n");\r
288                 memcpy((unsigned char *)&LineCoding, *ppbData, 7);\r
289                 *piLen = 7;\r
290 DBG("dwDTERate=%u, bCharFormat=%u, bParityType=%u, bDataBits=%u\n",\r
291         LineCoding.dwDTERate,\r
292         LineCoding.bCharFormat,\r
293         LineCoding.bParityType,\r
294         LineCoding.bDataBits);\r
295                 break;\r
296 \r
297         // get line coding\r
298         case GET_LINE_CODING:\r
299 DBG("GET_LINE_CODING\n");\r
300                 *ppbData = (unsigned char *)&LineCoding;\r
301                 *piLen = 7;\r
302                 break;\r
303 \r
304         // set control line state\r
305         case SET_CONTROL_LINE_STATE:\r
306                 // bit0 = DTR, bit = RTS\r
307 DBG("SET_CONTROL_LINE_STATE %X\n", pSetup->wValue);\r
308                 break;\r
309 \r
310         default:\r
311                 return FALSE;\r
312         }\r
313         return TRUE;\r
314 }\r
315 \r
316 \r
317 /**\r
318         Writes one character to VCOM port\r
319         \r
320         @param [in] c character to write\r
321         @returns character written, or EOF if character could not be written\r
322  */\r
323 int VCOM_putchar(int c)\r
324 {\r
325 char cc = ( char ) c;\r
326 \r
327         if( xQueueSend( xCharsForTx, &cc, usbMAX_SEND_BLOCK ) == pdPASS )\r
328         {\r
329                 return c;\r
330         }\r
331         else\r
332         {\r
333                 return EOF;\r
334         }\r
335 }\r
336 \r
337 \r
338 /**\r
339         Reads one character from VCOM port\r
340         \r
341         @returns character read, or EOF if character could not be read\r
342  */\r
343 int VCOM_getchar(void)\r
344 {\r
345         unsigned char c;\r
346         \r
347         /* Block the task until a character is available. */\r
348         xQueueReceive( xRxedChars, &c, portMAX_DELAY );\r
349         return c;\r
350 }\r
351 \r
352 \r
353 /**\r
354         Interrupt handler\r
355         \r
356         Simply calls the USB ISR\r
357  */\r
358 //void USBIntHandler(void)\r
359 void USB_IRQHandler(void)\r
360 {\r
361         USBHwISR();\r
362 }\r
363 \r
364 \r
365 static void USBFrameHandler(unsigned short wFrame)\r
366 {\r
367         ( void ) wFrame;\r
368         \r
369         if( uxQueueMessagesWaitingFromISR( xCharsForTx ) > 0 )\r
370         {\r
371                 // data available, enable NAK interrupt on bulk in\r
372                 USBHwNakIntEnable(INACK_BI);\r
373         }\r
374 }\r
375 \r
376 void vUSBTask( void *pvParameters )\r
377 {\r
378         int c;\r
379         \r
380         /* Just to prevent compiler warnings about the unused parameter. */\r
381         ( void ) pvParameters;\r
382         DBG("Initialising USB stack\n");\r
383 \r
384         xRxedChars = xQueueCreate( usbBUFFER_LEN, sizeof( char ) );\r
385         xCharsForTx = xQueueCreate( usbBUFFER_LEN, sizeof( char ) );\r
386 \r
387         if( ( xRxedChars == NULL ) || ( xCharsForTx == NULL ) )\r
388         {\r
389                 /* Not enough heap available to create the buffer queues, can't do\r
390                 anything so just delete ourselves. */\r
391                 vTaskDelete( NULL );\r
392         }\r
393         \r
394         \r
395         // initialise stack\r
396         USBInit();\r
397 \r
398         // register descriptors\r
399         USBRegisterDescriptors(abDescriptors);\r
400 \r
401         // register class request handler\r
402         USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);\r
403 \r
404         // register endpoint handlers\r
405         USBHwRegisterEPIntHandler(INT_IN_EP, NULL);\r
406         USBHwRegisterEPIntHandler(BULK_IN_EP, BulkIn);\r
407         USBHwRegisterEPIntHandler(BULK_OUT_EP, BulkOut);\r
408         \r
409         // register frame handler\r
410         USBHwRegisterFrameHandler(USBFrameHandler);\r
411 \r
412         // enable bulk-in interrupts on NAKs\r
413         USBHwNakIntEnable(INACK_BI);\r
414 \r
415         DBG("Starting USB communication\n");\r
416 \r
417         NVIC_SetPriority( USB_IRQn, configUSB_INTERRUPT_PRIORITY );\r
418         NVIC_EnableIRQ( USB_IRQn );\r
419                 \r
420         // connect to bus\r
421                 \r
422         DBG("Connecting to USB bus\n");\r
423         USBHwConnect(TRUE);\r
424 \r
425         // echo any character received (do USB stuff in interrupt)\r
426         for( ;; )\r
427         {\r
428                 c = VCOM_getchar();\r
429                 if (c != EOF)\r
430                 {\r
431                         // Echo character back with INCREMENT_ECHO_BY offset, so for example if\r
432                         // INCREMENT_ECHO_BY is 1 and 'A' is received, 'B' will be echoed back.\r
433                         VCOM_putchar(c + INCREMENT_ECHO_BY );\r
434                 }\r
435         }\r
436 }\r
437 \r