]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_LPC1768_GCC_RedSuite/src/LPCUSB/USB_CDC.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / CORTEX_LPC1768_GCC_RedSuite / src / 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 "queue.h"\r
50 \r
51 #include <stdio.h>\r
52 #include <string.h>\r
53 \r
54 #include "usbapi.h"\r
55 #include "usbdebug.h"\r
56 #include "usbstruct.h"\r
57 \r
58 #include "LPC17xx.h"\r
59 \r
60 #define usbMAX_SEND_BLOCK               ( 20 / portTICK_RATE_MS )\r
61 #define usbBUFFER_LEN                   ( 20 )\r
62 \r
63 #define INCREMENT_ECHO_BY 1\r
64 #define BAUD_RATE       115200\r
65 \r
66 #define INT_IN_EP               0x81\r
67 #define BULK_OUT_EP             0x05\r
68 #define BULK_IN_EP              0x82\r
69 \r
70 #define MAX_PACKET_SIZE 64\r
71 \r
72 #define LE_WORD(x)              ((x)&0xFF),((x)>>8)\r
73 \r
74 // CDC definitions\r
75 #define CS_INTERFACE                    0x24\r
76 #define CS_ENDPOINT                             0x25\r
77 \r
78 #define SET_LINE_CODING                 0x20\r
79 #define GET_LINE_CODING                 0x21\r
80 #define SET_CONTROL_LINE_STATE  0x22\r
81 \r
82 // data structure for GET_LINE_CODING / SET_LINE_CODING class requests\r
83 typedef struct {\r
84         unsigned long           dwDTERate;\r
85         unsigned char           bCharFormat;\r
86         unsigned char           bParityType;\r
87         unsigned char           bDataBits;\r
88 } TLineCoding;\r
89 \r
90 static TLineCoding LineCoding = {115200, 0, 0, 8};\r
91 static unsigned char abBulkBuf[64];\r
92 static unsigned char abClassReqData[8];\r
93 \r
94 static xQueueHandle xRxedChars = NULL, xCharsForTx = NULL;\r
95 \r
96 // forward declaration of interrupt handler\r
97 void USBIntHandler(void);\r
98 \r
99 static const unsigned char abDescriptors[] = {\r
100 \r
101 // device descriptor\r
102         0x12,\r
103         DESC_DEVICE,\r
104         LE_WORD(0x0101),                        // bcdUSB\r
105         0x02,                                           // bDeviceClass\r
106         0x00,                                           // bDeviceSubClass\r
107         0x00,                                           // bDeviceProtocol\r
108         MAX_PACKET_SIZE0,                       // bMaxPacketSize\r
109         LE_WORD(0xFFFF),                        // idVendor\r
110         LE_WORD(0x0005),                        // idProduct\r
111         LE_WORD(0x0100),                        // bcdDevice\r
112         0x01,                                           // iManufacturer\r
113         0x02,                                           // iProduct\r
114         0x03,                                           // iSerialNumber\r
115         0x01,                                           // bNumConfigurations\r
116 \r
117 // configuration descriptor\r
118         0x09,\r
119         DESC_CONFIGURATION,\r
120         LE_WORD(67),                            // wTotalLength\r
121         0x02,                                           // bNumInterfaces\r
122         0x01,                                           // bConfigurationValue\r
123         0x00,                                           // iConfiguration\r
124         0xC0,                                           // bmAttributes\r
125         0x32,                                           // bMaxPower\r
126 // control class interface\r
127         0x09,\r
128         DESC_INTERFACE,\r
129         0x00,                                           // bInterfaceNumber\r
130         0x00,                                           // bAlternateSetting\r
131         0x01,                                           // bNumEndPoints\r
132         0x02,                                           // bInterfaceClass\r
133         0x02,                                           // bInterfaceSubClass\r
134         0x01,                                           // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module\r
135         0x00,                                           // iInterface\r
136 // header functional descriptor\r
137         0x05,\r
138         CS_INTERFACE,\r
139         0x00,\r
140         LE_WORD(0x0110),\r
141 // call management functional descriptor\r
142         0x05,\r
143         CS_INTERFACE,\r
144         0x01,\r
145         0x01,                                           // bmCapabilities = device handles call management\r
146         0x01,                                           // bDataInterface\r
147 // ACM functional descriptor\r
148         0x04,\r
149         CS_INTERFACE,\r
150         0x02,\r
151         0x02,                                           // bmCapabilities\r
152 // union functional descriptor\r
153         0x05,\r
154         CS_INTERFACE,\r
155         0x06,\r
156         0x00,                                           // bMasterInterface\r
157         0x01,                                           // bSlaveInterface0\r
158 // notification EP\r
159         0x07,\r
160         DESC_ENDPOINT,\r
161         INT_IN_EP,                                      // bEndpointAddress\r
162         0x03,                                           // bmAttributes = intr\r
163         LE_WORD(8),                                     // wMaxPacketSize\r
164         0x0A,                                           // bInterval\r
165 // data class interface descriptor\r
166         0x09,\r
167         DESC_INTERFACE,\r
168         0x01,                                           // bInterfaceNumber\r
169         0x00,                                           // bAlternateSetting\r
170         0x02,                                           // bNumEndPoints\r
171         0x0A,                                           // bInterfaceClass = data\r
172         0x00,                                           // bInterfaceSubClass\r
173         0x00,                                           // bInterfaceProtocol\r
174         0x00,                                           // iInterface\r
175 // data EP OUT\r
176         0x07,\r
177         DESC_ENDPOINT,\r
178         BULK_OUT_EP,                            // bEndpointAddress\r
179         0x02,                                           // bmAttributes = bulk\r
180         LE_WORD(MAX_PACKET_SIZE),       // wMaxPacketSize\r
181         0x00,                                           // bInterval\r
182 // data EP in\r
183         0x07,\r
184         DESC_ENDPOINT,\r
185         BULK_IN_EP,                                     // bEndpointAddress\r
186         0x02,                                           // bmAttributes = bulk\r
187         LE_WORD(MAX_PACKET_SIZE),       // wMaxPacketSize\r
188         0x00,                                           // bInterval\r
189         \r
190         // string descriptors\r
191         0x04,\r
192         DESC_STRING,\r
193         LE_WORD(0x0409),\r
194 \r
195         0x0E,\r
196         DESC_STRING,\r
197         'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,\r
198 \r
199         0x14,\r
200         DESC_STRING,\r
201         'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,\r
202 \r
203         0x12,\r
204         DESC_STRING,\r
205         'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,\r
206 \r
207 // terminating zero\r
208         0\r
209 };\r
210 \r
211 \r
212 /**\r
213         Local function to handle incoming bulk data\r
214                 \r
215         @param [in] bEP\r
216         @param [in] bEPStatus\r
217  */\r
218 static void BulkOut(unsigned char bEP, unsigned char bEPStatus)\r
219 {\r
220         int i, iLen;\r
221         long lHigherPriorityTaskWoken = pdFALSE;\r
222 \r
223         ( void ) bEPStatus;\r
224         \r
225         // get data from USB into intermediate buffer\r
226         iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf));\r
227         for (i = 0; i < iLen; i++) {\r
228                 // put into queue\r
229                 xQueueSendFromISR( xRxedChars, &( abBulkBuf[ i ] ), &lHigherPriorityTaskWoken ); \r
230         }\r
231         \r
232         portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
233 }\r
234 \r
235 \r
236 /**\r
237         Local function to handle outgoing bulk data\r
238                 \r
239         @param [in] bEP\r
240         @param [in] bEPStatus\r
241  */\r
242 static void BulkIn(unsigned char bEP, unsigned char bEPStatus)\r
243 {\r
244         int i, iLen;\r
245         long lHigherPriorityTaskWoken = pdFALSE;\r
246 \r
247         ( void ) bEPStatus;\r
248         \r
249         if (uxQueueMessagesWaitingFromISR( xCharsForTx ) == 0) {\r
250                 // no more data, disable further NAK interrupts until next USB frame\r
251                 USBHwNakIntEnable(0);\r
252                 return;\r
253         }\r
254 \r
255         // get bytes from transmit FIFO into intermediate buffer\r
256         for (i = 0; i < MAX_PACKET_SIZE; i++) {\r
257                 if( xQueueReceiveFromISR( xCharsForTx, ( &abBulkBuf[i] ), &lHigherPriorityTaskWoken ) != pdPASS )\r
258                 {\r
259                         break;\r
260                 }\r
261         }\r
262         iLen = i;\r
263         \r
264         // send over USB\r
265         if (iLen > 0) {\r
266                 USBHwEPWrite(bEP, abBulkBuf, iLen);\r
267         }\r
268         \r
269         portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
270 }\r
271 \r
272 \r
273 /**\r
274         Local function to handle the USB-CDC class requests\r
275                 \r
276         @param [in] pSetup\r
277         @param [out] piLen\r
278         @param [out] ppbData\r
279  */\r
280 static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData)\r
281 {\r
282         switch (pSetup->bRequest) {\r
283 \r
284         // set line coding\r
285         case SET_LINE_CODING:\r
286 DBG("SET_LINE_CODING\n");\r
287                 memcpy((unsigned char *)&LineCoding, *ppbData, 7);\r
288                 *piLen = 7;\r
289 DBG("dwDTERate=%u, bCharFormat=%u, bParityType=%u, bDataBits=%u\n",\r
290         LineCoding.dwDTERate,\r
291         LineCoding.bCharFormat,\r
292         LineCoding.bParityType,\r
293         LineCoding.bDataBits);\r
294                 break;\r
295 \r
296         // get line coding\r
297         case GET_LINE_CODING:\r
298 DBG("GET_LINE_CODING\n");\r
299                 *ppbData = (unsigned char *)&LineCoding;\r
300                 *piLen = 7;\r
301                 break;\r
302 \r
303         // set control line state\r
304         case SET_CONTROL_LINE_STATE:\r
305                 // bit0 = DTR, bit = RTS\r
306 DBG("SET_CONTROL_LINE_STATE %X\n", pSetup->wValue);\r
307                 break;\r
308 \r
309         default:\r
310                 return FALSE;\r
311         }\r
312         return TRUE;\r
313 }\r
314 \r
315 \r
316 /**\r
317         Writes one character to VCOM port\r
318         \r
319         @param [in] c character to write\r
320         @returns character written, or EOF if character could not be written\r
321  */\r
322 int VCOM_putchar(int c)\r
323 {\r
324 char cc = ( char ) c;\r
325 \r
326         if( xQueueSend( xCharsForTx, &cc, usbMAX_SEND_BLOCK ) == pdPASS )\r
327         {\r
328                 return c;\r
329         }\r
330         else\r
331         {\r
332                 return EOF;\r
333         }\r
334 }\r
335 \r
336 \r
337 /**\r
338         Reads one character from VCOM port\r
339         \r
340         @returns character read, or EOF if character could not be read\r
341  */\r
342 int VCOM_getchar(void)\r
343 {\r
344         unsigned char c;\r
345         \r
346         /* Block the task until a character is available. */\r
347         xQueueReceive( xRxedChars, &c, portMAX_DELAY );\r
348         return c;\r
349 }\r
350 \r
351 \r
352 /**\r
353         Interrupt handler\r
354         \r
355         Simply calls the USB ISR\r
356  */\r
357 //void USBIntHandler(void)\r
358 void USB_IRQHandler(void)\r
359 {\r
360         USBHwISR();\r
361 }\r
362 \r
363 \r
364 static void USBFrameHandler(unsigned short wFrame)\r
365 {\r
366         ( void ) wFrame;\r
367         \r
368         if( uxQueueMessagesWaitingFromISR( xCharsForTx ) > 0 )\r
369         {\r
370                 // data available, enable NAK interrupt on bulk in\r
371                 USBHwNakIntEnable(INACK_BI);\r
372         }\r
373 }\r
374 \r
375 // CodeRed - added CPUcpsie\r
376 \r
377 unsigned long CPUcpsie(void)\r
378 {\r
379     unsigned long ulRet;\r
380 \r
381     //\r
382     // Read PRIMASK and enable interrupts.\r
383     //\r
384     __asm("    mrs     %0, PRIMASK\n"\r
385           "    cpsie   i\n"\r
386           "    bx      lr\n"\r
387           : "=r" (ulRet));\r
388 \r
389     //\r
390     // The return is handled in the inline assembly, but the compiler will\r
391     // still complain if there is not an explicit return here (despite the fact\r
392     // that this does not result in any code being produced because of the\r
393     // naked attribute).\r
394     //\r
395     return(ulRet);\r
396 }\r
397 \r
398 void vUSBTask( void *pvParameters )\r
399 {\r
400         int c;\r
401         \r
402         /* Just to prevent compiler warnings about the unused parameter. */\r
403         ( void ) pvParameters;\r
404         DBG("Initialising USB stack\n");\r
405 \r
406         xRxedChars = xQueueCreate( usbBUFFER_LEN, sizeof( char ) );\r
407         xCharsForTx = xQueueCreate( usbBUFFER_LEN, sizeof( char ) );\r
408 \r
409         if( ( xRxedChars == NULL ) || ( xCharsForTx == NULL ) )\r
410         {\r
411                 /* Not enough heap available to create the buffer queues, can't do\r
412                 anything so just delete ourselves. */\r
413                 vTaskDelete( NULL );\r
414         }\r
415         \r
416         \r
417         // initialise stack\r
418         USBInit();\r
419 \r
420         // register descriptors\r
421         USBRegisterDescriptors(abDescriptors);\r
422 \r
423         // register class request handler\r
424         USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);\r
425 \r
426         // register endpoint handlers\r
427         USBHwRegisterEPIntHandler(INT_IN_EP, NULL);\r
428         USBHwRegisterEPIntHandler(BULK_IN_EP, BulkIn);\r
429         USBHwRegisterEPIntHandler(BULK_OUT_EP, BulkOut);\r
430         \r
431         // register frame handler\r
432         USBHwRegisterFrameHandler(USBFrameHandler);\r
433 \r
434         // enable bulk-in interrupts on NAKs\r
435         USBHwNakIntEnable(INACK_BI);\r
436 \r
437         DBG("Starting USB communication\n");\r
438 \r
439         NVIC_SetPriority( USB_IRQn, configUSB_INTERRUPT_PRIORITY );\r
440         NVIC_EnableIRQ( USB_IRQn );\r
441                 \r
442         // connect to bus\r
443                 \r
444         DBG("Connecting to USB bus\n");\r
445         USBHwConnect(TRUE);\r
446 \r
447         // echo any character received (do USB stuff in interrupt)\r
448         for( ;; )\r
449         {\r
450                 c = VCOM_getchar();\r
451                 if (c != EOF) \r
452                 {\r
453                         // Echo character back with INCREMENT_ECHO_BY offset, so for example if\r
454                         // INCREMENT_ECHO_BY is 1 and 'A' is received, 'B' will be echoed back.\r
455                         VCOM_putchar(c + INCREMENT_ECHO_BY );\r
456                 }\r
457         }\r
458 }\r
459 \r