No syslockisr
[gnuk/neug.git] / src / main.c
1 /*
2  * main.c - main routine of neug
3  *
4  * Main routine:
5  * Copyright (C) 2011, 2012 Free Software Initiative of Japan
6  * Author: NIIBE Yutaka <gniibe@fsij.org>
7  *
8  * This file is a part of NeuG, a Random Number Generator
9  * implementation.
10  *
11  * NeuG is free software: you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * NeuG is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
19  * License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  */
25
26 #include "config.h"
27 #include "ch.h"
28 #include "hal.h"
29 #include "board.h"
30 #include "neug.h"
31 #include "usb_lld.h"
32 #include "sys.h"
33 #include "adc.h"
34
35 /*
36  * We are trying to avoid dependency to C library. 
37  * GCC built-in function(s) are declared here.
38  */
39 extern void *memcpy(void *dest, const void *src, size_t n);
40 extern void *memset (void *s, int c, size_t n);
41
42 static Thread *main_thread;
43
44 \f
45 #define ENDP0_RXADDR        (0x40)
46 #define ENDP0_TXADDR        (0x80)
47 #define ENDP1_TXADDR        (0xc0)
48 #define ENDP2_TXADDR        (0x100)
49 #define ENDP3_RXADDR        (0x140)
50
51 #define USB_CDC_REQ_SET_LINE_CODING             0x20
52 #define USB_CDC_REQ_GET_LINE_CODING             0x21
53 #define USB_CDC_REQ_SET_CONTROL_LINE_STATE      0x22
54 #define USB_CDC_REQ_SEND_BREAK                  0x23
55
56 /* USB Device Descriptor */
57 static const uint8_t vcom_device_desc[18] = {
58   18,   /* bLength */
59   USB_DEVICE_DESCRIPTOR_TYPE,   /* bDescriptorType */
60   0x10, 0x01,                   /* bcdUSB = 1.1 */
61   0x02,                         /* bDeviceClass (CDC).              */
62   0x00,                         /* bDeviceSubClass.                 */
63   0x00,                         /* bDeviceProtocol.                 */
64   0x40,                         /* bMaxPacketSize.                  */
65 #include "usb-vid-pid-ver.c.inc"
66   1,                            /* iManufacturer.                   */
67   2,                            /* iProduct.                        */
68   3,                            /* iSerialNumber.                   */
69   1                             /* bNumConfigurations.              */
70 };
71
72 /* Configuration Descriptor tree for a CDC.*/
73 static const uint8_t vcom_configuration_desc[67] = {
74   9,
75   USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
76   /* Configuration Descriptor.*/
77   67, 0x00,                     /* wTotalLength.                    */
78   0x02,                         /* bNumInterfaces.                  */
79   0x01,                         /* bConfigurationValue.             */
80   0,                            /* iConfiguration.                  */
81   0x80,                         /* bmAttributes (bus powered).      */
82   50,                           /* bMaxPower (100mA).               */
83   /* Interface Descriptor.*/
84   9,
85   USB_INTERFACE_DESCRIPTOR_TYPE,
86   0x00,            /* bInterfaceNumber.                */
87   0x00,            /* bAlternateSetting.               */
88   0x01,            /* bNumEndpoints.                   */
89   0x02,            /* bInterfaceClass (Communications Interface Class,
90                       CDC section 4.2).  */
91   0x02,            /* bInterfaceSubClass (Abstract Control Model, CDC
92                       section 4.3).  */
93   0x01,            /* bInterfaceProtocol (AT commands, CDC section
94                       4.4).  */
95   0,               /* iInterface.                      */
96   /* Header Functional Descriptor (CDC section 5.2.3).*/
97   5,          /* bLength.                         */
98   0x24,       /* bDescriptorType (CS_INTERFACE).  */
99   0x00,       /* bDescriptorSubtype (Header Functional Descriptor). */
100   0x10, 0x01, /* bcdCDC.                          */
101   /* Call Management Functional Descriptor. */
102   5,            /* bFunctionLength.                 */
103   0x24,         /* bDescriptorType (CS_INTERFACE).  */
104   0x01,         /* bDescriptorSubtype (Call Management Functional
105                    Descriptor). */
106   0x03,         /* bmCapabilities (D0+D1).          */
107   0x01,         /* bDataInterface.                  */
108   /* ACM Functional Descriptor.*/
109   4,            /* bFunctionLength.                 */
110   0x24,         /* bDescriptorType (CS_INTERFACE).  */
111   0x02,         /* bDescriptorSubtype (Abstract Control Management
112                    Descriptor).  */
113   0x02,         /* bmCapabilities.                  */
114   /* Union Functional Descriptor.*/
115   5,            /* bFunctionLength.                 */
116   0x24,         /* bDescriptorType (CS_INTERFACE).  */
117   0x06,         /* bDescriptorSubtype (Union Functional
118                    Descriptor).  */
119   0x00,         /* bMasterInterface (Communication Class
120                    Interface).  */
121   0x01,         /* bSlaveInterface0 (Data Class Interface).  */
122   /* Endpoint 2 Descriptor.*/
123   7,
124   USB_ENDPOINT_DESCRIPTOR_TYPE,
125   ENDP2|0x80,    /* bEndpointAddress.    */
126   0x03,          /* bmAttributes (Interrupt).        */
127   0x08, 0x00,    /* wMaxPacketSize.                  */
128   0xFF,          /* bInterval.                       */
129   /* Interface Descriptor.*/
130   9,
131   USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
132   0x01,          /* bInterfaceNumber.                */
133   0x00,          /* bAlternateSetting.               */
134   0x02,          /* bNumEndpoints.                   */
135   0x0A,          /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
136   0x00,          /* bInterfaceSubClass (CDC section 4.6). */
137   0x00,          /* bInterfaceProtocol (CDC section 4.7). */
138   0x00,          /* iInterface.                      */
139   /* Endpoint 3 Descriptor.*/
140   7,
141   USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
142   ENDP3,    /* bEndpointAddress. */
143   0x02,                         /* bmAttributes (Bulk).             */
144   0x40, 0x00,                   /* wMaxPacketSize.                  */
145   0x00,                         /* bInterval.                       */
146   /* Endpoint 1 Descriptor.*/
147   7,
148   USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
149   ENDP1|0x80,                   /* bEndpointAddress. */
150   0x02,                         /* bmAttributes (Bulk).             */
151   0x40, 0x00,                   /* wMaxPacketSize.                  */
152   0x00                          /* bInterval.                       */
153 };
154
155
156 /*
157  * U.S. English language identifier.
158  */
159 static const uint8_t vcom_string0[4] = {
160   4,                            /* bLength */
161   USB_STRING_DESCRIPTOR_TYPE,
162   0x09, 0x04                    /* LangID = 0x0409: US-English */
163 };
164
165 #define USB_STRINGS_FOR_NEUG 1
166 #include "usb-strings.c.inc"
167
168 /*
169  * Serial Number string.  NOTE: This does not have CONST qualifier.
170  */
171 static uint8_t vcom_string3[28] = {
172   28,                    /* bLength.                         */
173   USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType.                 */
174   '0', 0,  '.', 0,  '0', 0, '2', 0,    /* Version number of NeuG.          */
175   '-', 0,
176   0, 0, 0, 0,   /* Filled by Unique device ID.      */
177   0, 0, 0, 0,
178   0, 0, 0, 0,
179   0, 0, 0, 0,
180 };
181
182 static const struct Descriptor device_desc = {
183   vcom_device_desc,
184   sizeof (vcom_device_desc)
185 };
186
187 static const struct Descriptor config_desc = {
188   vcom_configuration_desc,
189   sizeof (vcom_configuration_desc)
190 };
191
192 static const struct Descriptor string_descs[] = {
193   {vcom_string0, sizeof vcom_string0},
194   {neug_string_vendor, sizeof (neug_string_vendor)},
195   {neug_string_product, sizeof (neug_string_product)},
196   {vcom_string3, sizeof (vcom_string3)},
197   {neug_revision_detail, sizeof (neug_revision_detail)},
198   {neug_config_options, sizeof (neug_config_options)},
199   {sys_version, sizeof (sys_version)},
200 };
201
202 #define NUM_STRING_DESC (sizeof (string_descs)/sizeof (struct Descriptor))
203
204 #define NUM_INTERFACES 2
205
206 uint32_t bDeviceState = UNCONNECTED; /* USB device status */
207
208 #define NEUG_WAIT_FOR_TX_READY 1
209 static uint8_t neug_state;
210
211 static void
212 neug_device_reset (void)
213 {
214   /* Set DEVICE as not configured */
215   usb_lld_set_configuration (0);
216
217   /* Current Feature initialization */
218   usb_lld_set_feature (config_desc.Descriptor[7]);
219
220   usb_lld_reset ();
221
222   /* Initialize Endpoint 0 */
223   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
224 }
225
226 extern uint8_t _regnual_start, __heap_end__;
227
228 static const uint8_t *const mem_info[] = { &_regnual_start,  &__heap_end__, };
229
230 /* USB vendor requests to control pipe */
231 #define USB_FSIJ_MEMINFO          0
232 #define USB_FSIJ_DOWNLOAD         1
233 #define USB_FSIJ_EXEC             2
234 #define USB_NEUG_GET_INFO       254
235 #define USB_NEUG_EXIT           255 /* Ask to exit and to receive reGNUal */
236
237 enum {
238   FSIJ_DEVICE_RUNNING = 0,
239   FSIJ_DEVICE_EXITED,
240   FSIJ_DEVICE_EXEC_REQUESTED,
241   /**/
242   FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255
243 }; 
244
245 static uint8_t fsij_device_state = FSIJ_DEVICE_RUNNING;
246
247 static uint32_t rbit (uint32_t v)
248 {
249   uint32_t r;
250
251   asm ("rbit    %0, %1" : "=r" (r) : "r" (v));
252   return r;
253 }
254
255 /* After calling this function, CRC module remain enabled.  */
256 static int download_check_crc32 (const uint32_t *end_p)
257 {
258   uint32_t crc32 = *end_p;
259   const uint32_t *p;
260
261   RCC->AHBENR |= RCC_AHBENR_CRCEN;
262   CRC->CR = CRC_CR_RESET;
263
264   for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
265     CRC->DR = rbit (*p);
266
267   if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
268     return USB_SUCCESS;
269
270   return USB_UNSUPPORT;
271 }
272
273 static void neug_ctrl_write_finish (uint8_t req, uint8_t req_no,
274                                     uint16_t value, uint16_t index,
275                                     uint16_t len)
276 {
277   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
278
279   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
280       && USB_SETUP_SET (req) && len == 0)
281     {
282       if (req_no == USB_FSIJ_EXEC)
283         {
284           if (fsij_device_state != FSIJ_DEVICE_EXITED)
285             return;
286
287           (void)value; (void)index;
288           usb_lld_prepare_shutdown (); /* No further USB communication */
289           fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED;
290         }
291       else if (req_no == USB_NEUG_EXIT)
292         {
293           chSysLockFromIsr ();
294           if (neug_state == NEUG_WAIT_FOR_TX_READY)
295             {
296               main_thread->p_u.rdymsg = RDY_OK;
297               chSchReadyI (main_thread);
298             }
299           else
300             chEvtSignalFlagsI (main_thread, 1);
301           chSysUnlockFromIsr ();
302         }
303     }
304 }
305
306 struct line_coding
307 {
308   uint32_t bitrate;
309   uint8_t format;
310   uint8_t paritytype;
311   uint8_t datatype;
312 };
313
314 static struct line_coding line_coding = {
315   115200, /* baud rate: 115200    */
316   0x00,   /* stop bits: 1         */
317   0x00,   /* parity:    none      */
318   0x08    /* bits:      8         */
319 };
320
321 static uint8_t connected;
322
323 static int
324 vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value)
325 {
326   if (USB_SETUP_GET (req))
327     {
328       if (req_no == USB_CDC_REQ_GET_LINE_CODING)
329         {
330           usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
331           return USB_SUCCESS;
332         }
333     }
334   else  /* USB_SETUP_SET (req) */
335     {
336       if (req_no == USB_CDC_REQ_SET_LINE_CODING)
337         {
338           usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
339           return USB_SUCCESS;
340         }
341       else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
342         {
343           if (value != 0)
344             {
345               if (connected == 0)
346                 /* It's Open call */
347                 connected++;
348             }
349           else
350             {
351               if (connected)
352                 {
353                   /* Close call */
354                   connected = 0;
355                   chSysLockFromIsr ();
356                   if (neug_state == NEUG_WAIT_FOR_TX_READY)
357                     {
358                       main_thread->p_u.rdymsg = RDY_OK;
359                       chSchReadyI (main_thread);
360                     }
361                   chSysUnlockFromIsr ();
362                 }
363             }
364
365           return USB_SUCCESS;
366         }
367     }
368
369   return USB_UNSUPPORT;
370 }
371
372 static int
373 neug_setup (uint8_t req, uint8_t req_no,
374                uint16_t value, uint16_t index, uint16_t len)
375 {
376   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
377
378   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
379     {
380       if (USB_SETUP_GET (req))
381         {
382           if (req_no == USB_FSIJ_MEMINFO)
383             {
384               usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
385               return USB_SUCCESS;
386             }
387           else if (req_no == USB_NEUG_GET_INFO)
388             {
389               if (index == 0)
390                 usb_lld_set_data_to_send (&neug_mode, sizeof (uint8_t));
391               else if (index == 1)
392                 usb_lld_set_data_to_send (&neug_err_cnt, sizeof (uint16_t));
393               else if (index == 2)
394                 usb_lld_set_data_to_send (&neug_err_cnt_rc, sizeof (uint16_t));
395               else if (index == 3)
396                 usb_lld_set_data_to_send (&neug_err_cnt_p64, sizeof (uint16_t));
397               else if (index == 4)
398                 usb_lld_set_data_to_send (&neug_err_cnt_p4k, sizeof (uint16_t));
399
400               return USB_SUCCESS;
401             }
402         }
403       else /* SETUP_SET */
404         {
405           uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
406
407           if (req_no == USB_FSIJ_DOWNLOAD)
408             {
409               if (fsij_device_state != FSIJ_DEVICE_EXITED)
410                 return USB_UNSUPPORT;
411
412               if (addr < &_regnual_start || addr + len > &__heap_end__)
413                 return USB_UNSUPPORT;
414
415               if (index + len < 256)
416                 memset (addr + index + len, 0, 256 - (index + len));
417
418               usb_lld_set_data_to_recv (addr, len);
419               return USB_SUCCESS;
420             }
421           else if (req_no == USB_FSIJ_EXEC && len == 0)
422             {
423               if (fsij_device_state != FSIJ_DEVICE_EXITED)
424                 return USB_UNSUPPORT;
425
426               if (((uint32_t)addr & 0x03))
427                 return USB_UNSUPPORT;
428
429               return download_check_crc32 ((uint32_t *)addr);
430             }
431           else if (req_no == USB_NEUG_EXIT && len == 0)
432             {
433               if (fsij_device_state != FSIJ_DEVICE_RUNNING)
434                 return USB_UNSUPPORT;
435
436               fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
437               return USB_SUCCESS;
438             }
439         }
440     }
441   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
442     if (index == 0)
443       return vcom_port_data_setup (req, req_no, value);
444
445   return USB_UNSUPPORT;
446 }
447
448 static int
449 neug_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
450 {
451   (void)index;
452   if (desc_type == DEVICE_DESCRIPTOR)
453     {
454       usb_lld_set_data_to_send (device_desc.Descriptor,
455                                 device_desc.Descriptor_Size);
456       return USB_SUCCESS;
457     }
458   else if (desc_type == CONFIG_DESCRIPTOR)
459     {
460       usb_lld_set_data_to_send (config_desc.Descriptor,
461                                 config_desc.Descriptor_Size);
462       return USB_SUCCESS;
463     }
464   else if (desc_type == STRING_DESCRIPTOR)
465     {
466       uint8_t desc_index = value & 0xff;
467
468       if (desc_index < NUM_STRING_DESC)
469         {
470           usb_lld_set_data_to_send (string_descs[desc_index].Descriptor,
471                                     string_descs[desc_index].Descriptor_Size);
472           return USB_SUCCESS;
473         }
474     }
475
476   return USB_UNSUPPORT;
477 }
478
479 static void
480 neug_setup_endpoints_for_interface (uint16_t interface, int stop)
481 {
482   if (interface == 0)
483     {
484       if (!stop)
485         usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
486       else
487         usb_lld_stall_tx (ENDP2);
488     }
489   else if (interface == 1)
490     {
491       if (!stop)
492         {
493           usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
494           usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
495         }
496       else
497         {
498           usb_lld_stall_tx (ENDP1);
499           usb_lld_stall_rx (ENDP3);
500         }
501     }
502 }
503
504 static int neug_usb_event (uint8_t event_type, uint16_t value)
505 {
506   int i;
507   uint8_t current_conf;
508
509   switch (event_type)
510     {
511     case USB_EVENT_ADDRESS:
512       bDeviceState = ADDRESSED;
513       return USB_SUCCESS;
514     case USB_EVENT_CONFIG:
515       current_conf = usb_lld_current_configuration ();
516       if (current_conf == 0)
517         {
518           if (value != 1)
519             return USB_UNSUPPORT;
520
521           usb_lld_set_configuration (1);
522           for (i = 0; i < NUM_INTERFACES; i++)
523             neug_setup_endpoints_for_interface (i, 0);
524           bDeviceState = CONFIGURED;
525         }
526       else if (current_conf != value)
527         {
528           if (value != 0)
529             return USB_UNSUPPORT;
530
531           usb_lld_set_configuration (0);
532           for (i = 0; i < NUM_INTERFACES; i++)
533             neug_setup_endpoints_for_interface (i, 1);
534           bDeviceState = ADDRESSED;
535         }
536       /* Do nothing when current_conf == value */
537       return USB_SUCCESS;
538
539       return USB_SUCCESS;
540     default:
541       break;
542     }
543
544   return USB_UNSUPPORT;
545 }
546
547
548 static int neug_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
549 {
550   static uint8_t zero = 0;
551
552   if (interface >= NUM_INTERFACES)
553     return USB_UNSUPPORT;
554
555   switch (cmd)
556     {
557     case USB_SET_INTERFACE:
558       if (alt != 0)
559         return USB_UNSUPPORT;
560       else
561         {
562           neug_setup_endpoints_for_interface (interface, 0);
563           return USB_SUCCESS;
564         }
565
566     case USB_GET_INTERFACE:
567       usb_lld_set_data_to_send (&zero, 1);
568       return USB_SUCCESS;
569
570     default:
571     case USB_QUERY_INTERFACE:
572       return USB_SUCCESS;
573     }
574 }
575
576 const struct usb_device_method Device_Method = {
577   neug_device_reset,
578   neug_ctrl_write_finish,
579   neug_setup,
580   neug_get_descriptor,
581   neug_usb_event,
582   neug_interface,
583 };
584
585
586
587 static void fill_serial_no_by_unique_id (void)
588 {
589   extern const uint8_t * unique_device_id (void);
590   uint8_t *p = &vcom_string3[12];
591   const uint8_t *u = unique_device_id ();
592   int i;
593
594   for (i = 0; i < 4; i++)
595     {
596       uint8_t b = u[i];
597       uint8_t nibble; 
598
599       nibble = (b >> 4);
600       nibble += (nibble >= 10 ? ('A' - 10) : '0');
601       p[i*4] = nibble;
602       nibble = (b & 0x0f);
603       nibble += (nibble >= 10 ? ('A' - 10) : '0');
604       p[i*4+2] = nibble;
605     }
606 }
607 \f
608 CH_IRQ_HANDLER (Vector90)
609 {
610   CH_IRQ_PROLOGUE();
611   usb_interrupt_handler ();
612   CH_IRQ_EPILOGUE();
613 }
614
615 void
616 EP1_IN_Callback (void)
617 {
618   chSysLockFromIsr ();
619   if (neug_state == NEUG_WAIT_FOR_TX_READY)
620     {
621       main_thread->p_u.rdymsg = RDY_OK;
622       chSchReadyI (main_thread);
623     }
624   chSysUnlockFromIsr ();
625 }
626
627 void
628 EP2_IN_Callback (void)
629 {
630 }
631
632 void
633 EP3_OUT_Callback (void)
634 {
635   usb_lld_rx_enable (ENDP3);
636 }
637 \f
638 static WORKING_AREA(wa_led, 64);
639
640 #define LED_ONESHOT_SHORT       ((eventmask_t)1)
641 #define LED_TWOSHOTS            ((eventmask_t)2)
642 #define LED_ONESHOT_LONG        ((eventmask_t)4)
643 static Thread *led_thread;
644
645 /*
646  * LED blinker: When notified, let LED emit for 100ms.
647  */
648 static msg_t led_blinker (void *arg)
649 {
650   (void)arg;
651
652   led_thread = chThdSelf ();
653   set_led (0);
654
655   while (1)
656     {
657       eventmask_t m;
658
659       m = chEvtWaitOne (ALL_EVENTS);
660       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
661         break;
662
663       set_led (1);
664       if (m == LED_ONESHOT_SHORT)
665         chThdSleep (MS2ST (100));
666       else if (m == LED_TWOSHOTS)
667         {
668           chThdSleep (MS2ST (50));
669           set_led (0);
670           chThdSleep (MS2ST (50));
671           set_led (1);
672           chThdSleep (MS2ST (50));
673         }
674       else
675         chThdSleep (MS2ST (250));
676       set_led (0);
677     }
678
679   return 0;
680 }
681 \f
682 #define RANDOM_BYTES_LENGTH 32
683 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
684
685 /*
686  * Entry point.
687  *
688  * NOTE: the main function is already a thread in the system on entry.
689  */
690 int
691 main (int argc, char **argv)
692 {
693   (void)argc;
694   (void)argv;
695
696   fill_serial_no_by_unique_id ();
697
698   halInit ();
699   adc_init ();
700   chSysInit ();
701
702   main_thread = chThdSelf ();
703
704   chThdCreateStatic (wa_led, sizeof (wa_led), NORMALPRIO, led_blinker, NULL);
705
706   neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
707
708   usb_lld_init (config_desc.Descriptor[7]);
709
710   while (1)
711     {
712       unsigned int count = 0;
713
714       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
715         break;
716
717       while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
718         {
719           if (fsij_device_state != FSIJ_DEVICE_RUNNING)
720             break;
721
722           neug_wait_full ();
723           neug_flush ();
724
725           if ((count & 0x0007) == 0)
726             chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
727           chEvtWaitOneTimeout (ALL_EVENTS, MS2ST (25));
728           count++;
729         }
730
731     waiting_connection:
732       while (connected == 0)
733         {
734           if (fsij_device_state != FSIJ_DEVICE_RUNNING)
735             break;
736
737           neug_flush ();
738           chEvtSignalFlags (led_thread, LED_TWOSHOTS);
739           chEvtWaitOneTimeout (ALL_EVENTS, MS2ST (5000));
740         }
741
742       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
743         break;
744
745       /* The connection opened.  */
746       count = 0;
747       /*
748        * No parity is standard.  It means to provide conditioned output.
749        * When parity enabled, it means to provide raw output.
750        */
751       neug_mode_select (line_coding.paritytype); /* 0: None, 1: Odd, 2: Even */
752
753       while (1)
754         {
755           if (fsij_device_state != FSIJ_DEVICE_RUNNING)
756             break;
757
758           if (bDeviceState != CONFIGURED)
759             break;
760
761           neug_wait_full ();
762
763           if ((count & 0x03ff) == 0)
764             chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
765
766           usb_lld_txcpy (random_word, ENDP1, 0, RANDOM_BYTES_LENGTH);
767           neug_flush ();
768
769           chSysLock ();
770           if (connected == 0)
771             {
772               chSysUnlock();
773               goto waiting_connection;
774             }
775           else
776             {
777               neug_state = NEUG_WAIT_FOR_TX_READY;
778               usb_lld_tx_enable (ENDP1, RANDOM_BYTES_LENGTH);
779               chSchGoSleepS (THD_STATE_SUSPENDED);
780               neug_state = 0;
781             }
782           chSysUnlock ();
783
784           count++;
785         }
786     }
787
788   chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
789   chThdWait (led_thread);
790
791   /*
792    * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED.
793    */
794   neug_fini ();
795
796   fsij_device_state = FSIJ_DEVICE_EXITED;
797
798   while (fsij_device_state == FSIJ_DEVICE_EXITED)
799     chThdSleep (MS2ST (500));
800
801   flash_unlock ();              /* Flash unlock should be done here */
802   set_led (1);
803   usb_lld_shutdown ();
804   /* Disable SysTick */
805   SysTick->CTRL = 0;
806   /* Disable all interrupts */
807   port_disable ();
808   /* Set vector */
809   SCB->VTOR = (uint32_t)&_regnual_start;
810 #ifdef DFU_SUPPORT
811 #define FLASH_SYS_START_ADDR 0x08000000
812 #define FLASH_SYS_END_ADDR (0x08000000+0x1000)
813   {
814     extern uint8_t _sys;
815     uint32_t addr;
816     handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
817     void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[10];
818
819     /* Kill DFU */
820     for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
821          addr += FLASH_PAGE_SIZE)
822       flash_erase_page (addr);
823
824     /* copy system service routines */
825     flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
826
827     /* Leave NeuG to exec reGNUal */
828     (*func) (*((void (**)(void))(&_regnual_start+4)));
829     for (;;);
830   }
831 #else
832   /* Leave NeuG to exec reGNUal */
833   flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4)));
834 #endif
835
836   /* Never reached */
837   return 0;
838 }