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