Fix LED oneshot
[gnuk/neug.git] / src / main.c
1 /*
2  * main.c - main routine of neug
3  *
4  * USB-CDC part:
5  * ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,2011 Giovanni Di Sirio.
6  *
7  * Main routine:
8  * Copyright (C) 2011 Free Software Initiative of Japan
9  * Author: NIIBE Yutaka <gniibe@fsij.org>
10  *
11  * This file is a part of NeuG, a Random Number Generator
12  * implementation.
13  *
14  * NeuG is free software: you can redistribute it and/or modify it
15  * under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * Gnuk is distributed in the hope that it will be useful, but WITHOUT
20  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
22  * License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
26  *
27  */
28
29 #include "config.h"
30
31 #include "ch.h"
32 #include "hal.h"
33 #include "board.h"
34 #include "usb_cdc.h"
35 #include "neug.h"
36
37 /*
38  * We are trying to avoid dependency to C library. 
39  * GCC built-in function(s) are declared here.
40  */
41 void *memcpy(void *dest, const void *src, size_t n);
42
43 \f
44 /*
45  * USB CDC stuff taken from ChibiOS/RT's testhal/STM32/USB_CDC/main.c,
46  * and modified for NeuG.
47  */
48
49 /*
50  * USB Driver structure.
51  */
52 static SerialUSBDriver SDU1;
53
54 /*
55  * USB Device Descriptor.
56  */
57 static const uint8_t vcom_device_descriptor_data[18] = {
58   USB_DESC_DEVICE       (0x0200,        /* bcdUSB (2.0).                    */
59                          0x02,          /* bDeviceClass (CDC).              */
60                          0x00,          /* bDeviceSubClass.                 */
61                          0x00,          /* bDeviceProtocol.                 */
62                          0x40,          /* bMaxPacketSize.                  */
63                          0x234b,        /* idVendor (FSIJ).                 */
64                          0x0001,        /* idProduct (NeoG).                */
65                          0x0100,        /* bcdDevice.                       */
66                          1,             /* iManufacturer.                   */
67                          2,             /* iProduct.                        */
68                          3,             /* iSerialNumber.                   */
69                          1)             /* bNumConfigurations.              */
70 };
71
72 /*
73  * Device Descriptor wrapper.
74  */
75 static const USBDescriptor vcom_device_descriptor = {
76   sizeof vcom_device_descriptor_data,
77   vcom_device_descriptor_data
78 };
79
80 /* Configuration Descriptor tree for a CDC.*/
81 static const uint8_t vcom_configuration_descriptor_data[67] = {
82   /* Configuration Descriptor.*/
83   USB_DESC_CONFIGURATION(67,            /* wTotalLength.                    */
84                          0x02,          /* bNumInterfaces.                  */
85                          0x01,          /* bConfigurationValue.             */
86                          0,             /* iConfiguration.                  */
87                          0x80,          /* bmAttributes (bus powered).      */
88                          50),           /* bMaxPower (100mA).               */
89   /* Interface Descriptor.*/
90   USB_DESC_INTERFACE    (0x00,          /* bInterfaceNumber.                */
91                          0x00,          /* bAlternateSetting.               */
92                          0x01,          /* bNumEndpoints.                   */
93                          0x02,          /* bInterfaceClass (Communications
94                                            Interface Class, CDC section
95                                            4.2).                            */
96                          0x02,          /* bInterfaceSubClass (Abstract
97                                          Control Model, CDC section 4.3).   */
98                          0x01,          /* bInterfaceProtocol (AT commands,
99                                            CDC section 4.4).                */
100                          0),            /* iInterface.                      */
101   /* Header Functional Descriptor (CDC section 5.2.3).*/
102   USB_DESC_BYTE         (5),            /* bLength.                         */
103   USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
104   USB_DESC_BYTE         (0x00),         /* bDescriptorSubtype (Header
105                                            Functional Descriptor.           */
106   USB_DESC_BCD          (0x0110),       /* bcdCDC.                          */
107   /* Call Management Functional Descriptor. */
108   USB_DESC_BYTE         (5),            /* bFunctionLength.                 */
109   USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
110   USB_DESC_BYTE         (0x01),         /* bDescriptorSubtype (Call Management
111                                            Functional Descriptor).          */
112   USB_DESC_BYTE         (0x03),         /* bmCapabilities (D0+D1).          */
113   USB_DESC_BYTE         (0x01),         /* bDataInterface.                  */
114   /* ACM Functional Descriptor.*/
115   USB_DESC_BYTE         (4),            /* bFunctionLength.                 */
116   USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
117   USB_DESC_BYTE         (0x02),         /* bDescriptorSubtype (Abstract
118                                            Control Management Descriptor).  */
119   USB_DESC_BYTE         (0x02),         /* bmCapabilities.                  */
120   /* Union Functional Descriptor.*/
121   USB_DESC_BYTE         (5),            /* bFunctionLength.                 */
122   USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
123   USB_DESC_BYTE         (0x06),         /* bDescriptorSubtype (Union
124                                            Functional Descriptor).          */
125   USB_DESC_BYTE         (0x00),         /* bMasterInterface (Communication
126                                            Class Interface).                */
127   USB_DESC_BYTE         (0x01),         /* bSlaveInterface0 (Data Class
128                                            Interface).                      */
129   /* Endpoint 2 Descriptor.*/
130   USB_DESC_ENDPOINT     (INTERRUPT_REQUEST_EP|0x80, /* bEndpointAddress.    */
131                          0x03,          /* bmAttributes (Interrupt).        */
132                          0x0008,        /* wMaxPacketSize.                  */
133                          0xFF),         /* bInterval.                       */
134   /* Interface Descriptor.*/
135   USB_DESC_INTERFACE    (0x01,          /* bInterfaceNumber.                */
136                          0x00,          /* bAlternateSetting.               */
137                          0x02,          /* bNumEndpoints.                   */
138                          0x0A,          /* bInterfaceClass (Data Class
139                                            Interface, CDC section 4.5).     */
140                          0x00,          /* bInterfaceSubClass (CDC section
141                                            4.6).                            */
142                          0x00,          /* bInterfaceProtocol (CDC section
143                                            4.7).                            */
144                          0x00),         /* iInterface.                      */
145   /* Endpoint 3 Descriptor.*/
146   USB_DESC_ENDPOINT     (DATA_AVAILABLE_EP,         /* bEndpointAddress.    */
147                          0x02,          /* bmAttributes (Bulk).             */
148                          0x0040,        /* wMaxPacketSize.                  */
149                          0x00),         /* bInterval.                       */
150   /* Endpoint 1 Descriptor.*/
151   USB_DESC_ENDPOINT     (DATA_REQUEST_EP|0x80,      /* bEndpointAddress.    */
152                          0x02,          /* bmAttributes (Bulk).             */
153                          0x0040,        /* wMaxPacketSize.                  */
154                          0x00)          /* bInterval.                       */
155 };
156
157
158 /*
159  * Configuration Descriptor wrapper.
160  */
161 static const USBDescriptor vcom_configuration_descriptor = {
162   sizeof vcom_configuration_descriptor_data,
163   vcom_configuration_descriptor_data
164 };
165
166 /*
167  * U.S. English language identifier.
168  */
169 static const uint8_t vcom_string0[] = {
170   USB_DESC_BYTE(4),                     /* bLength.                         */
171   USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
172   USB_DESC_WORD(0x0409)                 /* wLANGID (U.S. English).          */
173 };
174
175 /*
176  * Vendor string.
177  */
178 static const uint8_t vcom_string1[] = {
179   USB_DESC_BYTE(68),                    /* bLength.                         */
180   USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
181   /* Manufacturer: "Free Software Initiative of Japan" */
182   'F', 0, 'r', 0, 'e', 0, 'e', 0, ' ', 0, 'S', 0, 'o', 0, 'f', 0,
183   't', 0, 'w', 0, 'a', 0, 'r', 0, 'e', 0, ' ', 0, 'I', 0, 'n', 0,
184   'i', 0, 't', 0, 'i', 0, 'a', 0, 't', 0, 'i', 0, 'v', 0, 'e', 0,
185   ' ', 0, 'o', 0, 'f', 0, ' ', 0, 'J', 0, 'a', 0, 'p', 0, 'a', 0,
186   'n', 0
187 };
188
189 /*
190  * Device Description string.
191  */
192 static const uint8_t vcom_string2[] = {
193   USB_DESC_BYTE(18),                    /* bLength.                         */
194   USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
195   /* Product name: "NeuG RNG" */
196   'N', 0, 'e', 0, 'u', 0, 'G', 0, ' ', 0, 'R', 0, 'N', 0, 'G', 0,
197 };
198
199 /*
200  * Serial Number string.  NOTE: This does not have CONST qualifier.
201  */
202 static uint8_t vcom_string3[] = {
203   USB_DESC_BYTE(28),                    /* bLength.                         */
204   USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
205   '0', 0,  '.', 0,  '0', 0,  '0', 0,    /* Version number of NeuG.          */
206   '-', 0,
207   0, 0, 0, 0, 0, 0, 0, 0,               /* Filled by Unique device ID.      */
208   0, 0, 0, 0, 0, 0, 0, 0,
209 };
210
211 /*
212  * Strings wrappers array.
213  */
214 static const USBDescriptor vcom_strings[] = {
215   {sizeof vcom_string0, vcom_string0},
216   {sizeof vcom_string1, vcom_string1},
217   {sizeof vcom_string2, vcom_string2},
218   {sizeof vcom_string3, vcom_string3}
219 };
220
221 /*
222  * Handles the GET_DESCRIPTOR callback. All required descriptors must be
223  * handled here.
224  */
225 static const USBDescriptor *get_descriptor(USBDriver *usbp,
226                                            uint8_t dtype,
227                                            uint8_t dindex,
228                                            uint16_t lang) {
229
230   (void)usbp;
231   (void)lang;
232   switch (dtype) {
233   case USB_DESCRIPTOR_DEVICE:
234     return &vcom_device_descriptor;
235   case USB_DESCRIPTOR_CONFIGURATION:
236     return &vcom_configuration_descriptor;
237   case USB_DESCRIPTOR_STRING:
238     if (dindex < 4)
239       return &vcom_strings[dindex];
240   }
241   return NULL;
242 }
243
244 /**
245  * @brief   EP1 initialization structure (IN only).
246  */
247 static const USBEndpointConfig ep1config = {
248   USB_EP_MODE_TYPE_BULK | USB_EP_MODE_PACKET,
249   NULL,
250   sduDataTransmitted,
251   NULL,
252   0x0040,
253   0x0000,
254   NULL,
255   NULL
256 };
257
258 /**
259  * @brief   EP2 initialization structure (IN only).
260  */
261 static const USBEndpointConfig ep2config = {
262   USB_EP_MODE_TYPE_INTR | USB_EP_MODE_PACKET,
263   NULL,
264   sduInterruptTransmitted,
265   NULL,
266   0x0010,
267   0x0000,
268   NULL,
269   NULL
270 };
271
272 /**
273  * @brief   EP3 initialization structure (OUT only).
274  */
275 static const USBEndpointConfig ep3config = {
276   USB_EP_MODE_TYPE_BULK | USB_EP_MODE_PACKET,
277   NULL,
278   NULL,
279   sduDataReceived,
280   0x0000,
281   0x0040,
282   NULL,
283   NULL
284 };
285
286 /*
287  * Handles the USB driver global events.
288  */
289 static void usb_event(USBDriver *usbp, usbevent_t event) {
290
291   switch (event) {
292   case USB_EVENT_RESET:
293     return;
294   case USB_EVENT_ADDRESS:
295     return;
296   case USB_EVENT_CONFIGURED:
297     /* Enables the endpoints specified into the configuration.
298        Note, this callback is invoked from an ISR so I-Class functions
299        must be used.*/
300     chSysLockFromIsr();
301     usbInitEndpointI(usbp, DATA_REQUEST_EP, &ep1config);
302     usbInitEndpointI(usbp, INTERRUPT_REQUEST_EP, &ep2config);
303     usbInitEndpointI(usbp, DATA_AVAILABLE_EP, &ep3config);
304     chSysUnlockFromIsr();
305     return;
306   case USB_EVENT_SUSPEND:
307     return;
308   case USB_EVENT_WAKEUP:
309     return;
310   case USB_EVENT_STALLED:
311     return;
312   }
313   return;
314 }
315
316
317 /*
318  * Serial over USB driver configuration.
319  */
320 static const SerialUSBConfig serusbcfg = {
321   &USBD1,
322   {
323     usb_event,
324     get_descriptor,
325     sduRequestsHook,
326     NULL
327   }
328 };
329
330 static void fill_serial_no_by_unique_id (void)
331 {
332   extern const uint8_t * unique_device_id (void);
333   uint8_t *p = &vcom_string3[12];
334   const uint8_t *u = unique_device_id ();
335   int i;
336
337   for (i = 0; i < 4; i++)
338     {
339       uint8_t b = u[i];
340       uint8_t nibble; 
341
342       nibble = (b >> 4);
343       nibble += (nibble >= 10 ? ('A' - 10) : '0');
344       p[i*4] = nibble;
345       nibble = (b & 0x0f);
346       nibble += (nibble >= 10 ? ('A' - 10) : '0');
347       p[i*4+2] = nibble;
348     }
349 }
350 \f
351 static WORKING_AREA(wa_led, 64);
352
353 #define LED_ONESHOT ((eventmask_t)1)
354 static Thread *led_thread;
355
356 /*
357  * LED blinker: When notified, let LED emit for 100ms.
358  */
359 static msg_t led_blinker (void *arg)
360 {
361   (void)arg;
362
363   led_thread = chThdSelf ();
364   set_led (0);
365
366   while (1)
367     {
368       chEvtWaitOne (LED_ONESHOT);
369       set_led (1);
370       chThdSleep (MS2ST (100));
371       set_led (0);
372     }
373
374   return 0;
375 }
376 \f
377 #define RANDOM_BYTES_LENGTH 32
378 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
379
380 /*
381  * Entry point.
382  *
383  * NOTE: the main function is already a thread in the system on entry.
384  */
385 int
386 main (int argc, char **argv)
387 {
388   unsigned int count = 0;
389
390   (void)argc;
391   (void)argv;
392
393   fill_serial_no_by_unique_id ();
394
395   halInit();
396   chSysInit();
397
398   /*
399    * Activates the USB driver and then the USB bus pull-up on D+.
400    */
401   sduObjectInit(&SDU1);
402   sduStart(&SDU1, &serusbcfg);
403   USB_Cable_Config (ENABLE);
404
405   chThdCreateStatic (wa_led, sizeof (wa_led), NORMALPRIO, led_blinker, NULL);
406
407   neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
408
409   while (1)
410     {
411       uint32_t v;
412       const uint8_t *s = (const uint8_t *)&v;
413
414       while (count++ < NEUG_PRE_LOOP
415              || SDU1.config->usbp->state != USB_ACTIVE)
416         {
417           v = neug_get (NEUG_KICK_FILLING);
418           if ((count & 0x000f) == 0)
419             chEvtSignalFlags (led_thread, LED_ONESHOT);
420           chThdSleep (MS2ST (25));
421           count++;
422         }
423
424       count = 0;
425
426       while (1)
427         {
428           count++;
429
430           if (SDU1.config->usbp->state != USB_ACTIVE)
431             break;
432
433           v = neug_get (NEUG_KICK_FILLING);
434
435           if ((count & 0x07ff) == 0)
436             chEvtSignalFlags (led_thread, LED_ONESHOT);
437           /*
438            * Ignore input, just in case /dev/ttyACM0 echos our output
439            */
440           chIQResetI (&(SDU1.iqueue));
441           chIOWriteTimeout (&SDU1, s, sizeof (v), TIME_INFINITE);
442         }
443     }
444
445   return 0;
446 }