Support relocatable reGNUal
[gnuk/neug.git] / src / main.c
1 /*
2  * main.c - main routine of neug
3  *
4  * Main routine:
5  * Copyright (C) 2011, 2012, 2013 Free Software Initiative of Japan
6  * Author: NIIBE Yutaka <gniibe@fsij.org>
7  *
8  * This file is a part of NeuG, a True 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, '5', 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
183 #define NUM_INTERFACES 2
184
185 uint32_t bDeviceState = UNCONNECTED; /* USB device status */
186
187 void
188 usb_cb_device_reset (void)
189 {
190   /* Set DEVICE as not configured */
191   usb_lld_set_configuration (0);
192
193   /* Current Feature initialization */
194   usb_lld_set_feature (vcom_configuration_desc[7]);
195
196   usb_lld_reset ();
197
198   /* Initialize Endpoint 0 */
199   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
200 }
201
202 extern uint8_t _regnual_start, __heap_end__;
203
204 static const uint8_t *const mem_info[] = { &_regnual_start,  &__heap_end__, };
205
206 /* USB vendor requests to control pipe */
207 #define USB_FSIJ_MEMINFO          0
208 #define USB_FSIJ_DOWNLOAD         1
209 #define USB_FSIJ_EXEC             2
210 #define USB_NEUG_GET_INFO       254
211 #define USB_NEUG_EXIT           255 /* Ask to exit and to receive reGNUal */
212
213 enum {
214   FSIJ_DEVICE_RUNNING = 0,
215   FSIJ_DEVICE_EXITED,
216   FSIJ_DEVICE_EXEC_REQUESTED,
217   /**/
218   FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255
219 }; 
220
221 static uint8_t fsij_device_state = FSIJ_DEVICE_RUNNING;
222
223 static uint32_t rbit (uint32_t v)
224 {
225   uint32_t r;
226
227   asm ("rbit    %0, %1" : "=r" (r) : "r" (v));
228   return r;
229 }
230
231 /* After calling this function, CRC module remain enabled.  */
232 static int download_check_crc32 (const uint32_t *end_p)
233 {
234   uint32_t crc32 = *end_p;
235   const uint32_t *p;
236
237   RCC->AHBENR |= RCC_AHBENR_CRCEN;
238   CRC->CR = CRC_CR_RESET;
239
240   for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
241     CRC->DR = rbit (*p);
242
243   if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
244     return USB_SUCCESS;
245
246   return USB_UNSUPPORT;
247 }
248
249 void
250 usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
251                           uint16_t index, uint16_t len)
252 {
253   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
254
255   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
256       && USB_SETUP_SET (req) && len == 0)
257     {
258       if (req_no == USB_FSIJ_EXEC)
259         {
260           if (fsij_device_state != FSIJ_DEVICE_EXITED)
261             return;
262
263           (void)value; (void)index;
264           usb_lld_prepare_shutdown (); /* No further USB communication */
265           fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED;
266         }
267       else if (req_no == USB_NEUG_EXIT)
268         {
269           chSysLockFromIsr ();
270           if (main_thread->p_state == THD_STATE_SUSPENDED
271               || main_thread->p_state == THD_STATE_SLEEPING)
272             {
273               main_thread->p_u.rdymsg = RDY_OK;
274               chSchReadyI (main_thread);
275             }
276           chSysUnlockFromIsr ();
277         }
278     }
279 }
280
281 struct line_coding
282 {
283   uint32_t bitrate;
284   uint8_t format;
285   uint8_t paritytype;
286   uint8_t datatype;
287 };
288
289 static struct line_coding line_coding = {
290   115200, /* baud rate: 115200    */
291   0x00,   /* stop bits: 1         */
292   0x00,   /* parity:    none      */
293   0x08    /* bits:      8         */
294 };
295
296 static uint8_t connected;
297
298 static int
299 vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value)
300 {
301   if (USB_SETUP_GET (req))
302     {
303       if (req_no == USB_CDC_REQ_GET_LINE_CODING)
304         {
305           usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
306           return USB_SUCCESS;
307         }
308     }
309   else  /* USB_SETUP_SET (req) */
310     {
311       if (req_no == USB_CDC_REQ_SET_LINE_CODING)
312         {
313           usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
314           return USB_SUCCESS;
315         }
316       else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
317         {
318           uint8_t connected_saved = connected;
319
320           if (value != 0)
321             {
322               if (connected == 0)
323                 /* It's Open call */
324                 connected++;
325             }
326           else
327             {
328               if (connected)
329                 /* Close call */
330                 connected = 0;
331             }
332
333           if (connected != connected_saved)
334             {
335               chSysLockFromIsr ();
336               if (main_thread->p_state == THD_STATE_SUSPENDED
337                   || main_thread->p_state == THD_STATE_SLEEPING)
338                 {
339                   main_thread->p_u.rdymsg = RDY_OK;
340                   chSchReadyI (main_thread);
341                 }
342               chSysUnlockFromIsr ();
343             }
344
345           return USB_SUCCESS;
346         }
347     }
348
349   return USB_UNSUPPORT;
350 }
351
352 int
353 usb_cb_setup (uint8_t req, uint8_t req_no,
354                uint16_t value, uint16_t index, uint16_t len)
355 {
356   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
357
358   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
359     {
360       if (USB_SETUP_GET (req))
361         {
362           if (req_no == USB_FSIJ_MEMINFO)
363             {
364               usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
365               return USB_SUCCESS;
366             }
367           else if (req_no == USB_NEUG_GET_INFO)
368             {
369               if (index == 0)
370                 usb_lld_set_data_to_send (&neug_mode, sizeof (uint8_t));
371               else if (index == 1)
372                 usb_lld_set_data_to_send (&neug_err_cnt, sizeof (uint16_t));
373               else if (index == 2)
374                 usb_lld_set_data_to_send (&neug_err_cnt_rc, sizeof (uint16_t));
375               else if (index == 3)
376                 usb_lld_set_data_to_send (&neug_err_cnt_p64, sizeof (uint16_t));
377               else if (index == 4)
378                 usb_lld_set_data_to_send (&neug_err_cnt_p4k, sizeof (uint16_t));
379               else if (index == 5)
380                 usb_lld_set_data_to_send (&neug_rc_max, sizeof (uint16_t));
381               else if (index == 6)
382                 usb_lld_set_data_to_send (&neug_p64_max, sizeof (uint16_t));
383               else if (index == 7)
384                 usb_lld_set_data_to_send (&neug_p4k_max, sizeof (uint16_t));
385               else
386                 return USB_UNSUPPORT;
387
388               return USB_SUCCESS;
389             }
390         }
391       else /* SETUP_SET */
392         {
393           uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
394
395           if (req_no == USB_FSIJ_DOWNLOAD)
396             {
397               if (fsij_device_state != FSIJ_DEVICE_EXITED)
398                 return USB_UNSUPPORT;
399
400               if (addr < &_regnual_start || addr + len > &__heap_end__)
401                 return USB_UNSUPPORT;
402
403               if (index + len < 256)
404                 memset (addr + index + len, 0, 256 - (index + len));
405
406               usb_lld_set_data_to_recv (addr, len);
407               return USB_SUCCESS;
408             }
409           else if (req_no == USB_FSIJ_EXEC && len == 0)
410             {
411               if (fsij_device_state != FSIJ_DEVICE_EXITED)
412                 return USB_UNSUPPORT;
413
414               if (((uint32_t)addr & 0x03))
415                 return USB_UNSUPPORT;
416
417               return download_check_crc32 ((uint32_t *)addr);
418             }
419           else if (req_no == USB_NEUG_EXIT && len == 0)
420             {
421               if (fsij_device_state != FSIJ_DEVICE_RUNNING)
422                 return USB_UNSUPPORT;
423
424               fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
425               return USB_SUCCESS;
426             }
427         }
428     }
429   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
430     if (index == 0)
431       return vcom_port_data_setup (req, req_no, value);
432
433   return USB_UNSUPPORT;
434 }
435
436 int
437 usb_cb_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
438 {
439   (void)index;
440   if (desc_type == DEVICE_DESCRIPTOR)
441     {
442       usb_lld_set_data_to_send (vcom_device_desc, sizeof (vcom_device_desc));
443       return USB_SUCCESS;
444     }
445   else if (desc_type == CONFIG_DESCRIPTOR)
446     {
447       usb_lld_set_data_to_send (vcom_configuration_desc,
448                                 sizeof (vcom_configuration_desc));
449       return USB_SUCCESS;
450     }
451   else if (desc_type == STRING_DESCRIPTOR)
452     {
453       uint8_t desc_index = value & 0xff;
454       const uint8_t *str;
455       int size;
456
457       switch (desc_index)
458         {
459         case 0:
460           str = vcom_string0;
461           size = sizeof (vcom_string0);
462           break;
463         case 1:
464           str = neug_string_vendor;
465           size = sizeof (neug_string_vendor);
466           break;
467         case 2:
468           str = neug_string_product;
469           size = sizeof (neug_string_product);
470           break;
471         case 3:
472           str = vcom_string3;
473           size = sizeof (vcom_string3);
474           break;
475         case 4:
476           str = neug_revision_detail;
477           size = sizeof (neug_revision_detail);
478           break;
479         case 5:
480           str = neug_config_options;
481           size = sizeof (neug_config_options);
482           break;
483         case 6:
484           str = sys_version;
485           size = sizeof (sys_version);
486           break;
487         default:
488           return USB_UNSUPPORT;
489         }
490
491       usb_lld_set_data_to_send (str, size);
492       return USB_SUCCESS;
493     }
494
495   return USB_UNSUPPORT;
496 }
497
498 static void
499 neug_setup_endpoints_for_interface (uint16_t interface, int stop)
500 {
501   if (interface == 0)
502     {
503       if (!stop)
504         usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
505       else
506         usb_lld_stall_tx (ENDP2);
507     }
508   else if (interface == 1)
509     {
510       if (!stop)
511         {
512           usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
513           usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
514         }
515       else
516         {
517           usb_lld_stall_tx (ENDP1);
518           usb_lld_stall_rx (ENDP3);
519         }
520     }
521 }
522
523 int usb_cb_handle_event (uint8_t event_type, uint16_t value)
524 {
525   int i;
526   uint8_t current_conf;
527
528   switch (event_type)
529     {
530     case USB_EVENT_ADDRESS:
531       bDeviceState = ADDRESSED;
532       return USB_SUCCESS;
533     case USB_EVENT_CONFIG:
534       current_conf = usb_lld_current_configuration ();
535       if (current_conf == 0)
536         {
537           if (value != 1)
538             return USB_UNSUPPORT;
539
540           usb_lld_set_configuration (1);
541           for (i = 0; i < NUM_INTERFACES; i++)
542             neug_setup_endpoints_for_interface (i, 0);
543           bDeviceState = CONFIGURED;
544         }
545       else if (current_conf != value)
546         {
547           if (value != 0)
548             return USB_UNSUPPORT;
549
550           usb_lld_set_configuration (0);
551           for (i = 0; i < NUM_INTERFACES; i++)
552             neug_setup_endpoints_for_interface (i, 1);
553           bDeviceState = ADDRESSED;
554         }
555       /* Do nothing when current_conf == value */
556       return USB_SUCCESS;
557
558       return USB_SUCCESS;
559     default:
560       break;
561     }
562
563   return USB_UNSUPPORT;
564 }
565
566
567 int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
568 {
569   static uint8_t zero = 0;
570
571   if (interface >= NUM_INTERFACES)
572     return USB_UNSUPPORT;
573
574   switch (cmd)
575     {
576     case USB_SET_INTERFACE:
577       if (alt != 0)
578         return USB_UNSUPPORT;
579       else
580         {
581           neug_setup_endpoints_for_interface (interface, 0);
582           return USB_SUCCESS;
583         }
584
585     case USB_GET_INTERFACE:
586       usb_lld_set_data_to_send (&zero, 1);
587       return USB_SUCCESS;
588
589     default:
590     case USB_QUERY_INTERFACE:
591       return USB_SUCCESS;
592     }
593 }
594
595
596 static void fill_serial_no_by_unique_id (void)
597 {
598   extern const uint8_t * unique_device_id (void);
599   uint8_t *p = &vcom_string3[12];
600   const uint8_t *u = unique_device_id ();
601   int i;
602
603   for (i = 0; i < 4; i++)
604     {
605       uint8_t b = u[i];
606       uint8_t nibble; 
607
608       nibble = (b >> 4);
609       nibble += (nibble >= 10 ? ('A' - 10) : '0');
610       p[i*4] = nibble;
611       nibble = (b & 0x0f);
612       nibble += (nibble >= 10 ? ('A' - 10) : '0');
613       p[i*4+2] = nibble;
614     }
615 }
616 \f
617 CH_IRQ_HANDLER (Vector90)
618 {
619   CH_IRQ_PROLOGUE();
620   usb_interrupt_handler ();
621   CH_IRQ_EPILOGUE();
622 }
623
624 void
625 EP1_IN_Callback (void)
626 {
627   chSysLockFromIsr ();
628   if (main_thread->p_state == THD_STATE_SUSPENDED)
629     {
630       main_thread->p_u.rdymsg = RDY_OK;
631       chSchReadyI (main_thread);
632     }
633   chSysUnlockFromIsr ();
634 }
635
636 void
637 EP2_IN_Callback (void)
638 {
639 }
640
641 void
642 EP3_OUT_Callback (void)
643 {
644   usb_lld_rx_enable (ENDP3);
645 }
646 \f
647 static WORKING_AREA(wa_led, 64);
648
649 #define LED_ONESHOT_SHORT       ((eventmask_t)1)
650 #define LED_TWOSHOTS            ((eventmask_t)2)
651 #define LED_ONESHOT_LONG        ((eventmask_t)4)
652 static Thread *led_thread;
653
654 /*
655  * LED blinker: When notified, let LED emit for 100ms.
656  */
657 static msg_t led_blinker (void *arg)
658 {
659   (void)arg;
660
661   led_thread = chThdSelf ();
662   set_led (0);
663
664   while (1)
665     {
666       eventmask_t m;
667
668       m = chEvtWaitOne (ALL_EVENTS);
669       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
670         break;
671
672       set_led (1);
673       if (m == LED_ONESHOT_SHORT)
674         chThdSleepMilliseconds (100);
675       else if (m == LED_TWOSHOTS)
676         {
677           chThdSleepMilliseconds (50);
678           set_led (0);
679           chThdSleepMilliseconds (50);
680           set_led (1);
681           chThdSleepMilliseconds (50);
682         }
683       else
684         chThdSleepMilliseconds (250);
685       set_led (0);
686     }
687
688   return 0;
689 }
690 \f
691 #define RANDOM_BYTES_LENGTH 64
692 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
693
694 static void copy_to_tx (uint32_t v, int i)
695 {
696   usb_lld_txcpy (&v, ENDP1, i * 4, 4);
697 }
698
699 /*
700  * In Gnuk 1.0.[12], reGNUal was not relocatable.
701  * Now, it's relocatable, but we need to calculate its entry address
702  * based on it's pre-defined address.
703  */
704 #define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
705 static uint32_t
706 calculate_regnual_entry_address (const uint8_t *addr)
707 {
708   const uint8_t *p = addr + 4;
709   uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
710
711   v -= REGNUAL_START_ADDRESS_COMPATIBLE;
712   v += (uint32_t)addr;
713   return v;
714 }
715
716
717 /*
718  * Entry point.
719  *
720  * NOTE: the main function is already a thread in the system on entry.
721  */
722 int
723 main (int argc, char **argv)
724 {
725   uint32_t entry;
726
727   (void)argc;
728   (void)argv;
729
730   fill_serial_no_by_unique_id ();
731
732   halInit ();
733   adc_init ();
734   chSysInit ();
735
736   main_thread = chThdSelf ();
737
738   chThdCreateStatic (wa_led, sizeof (wa_led), NORMALPRIO, led_blinker, NULL);
739
740   neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
741
742   usb_lld_init (vcom_configuration_desc[7]);
743
744   while (1)
745     {
746       unsigned int count = 0;
747       int last_was_fullsizepacket = 0;
748
749       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
750         break;
751
752       while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
753         {
754           if (fsij_device_state != FSIJ_DEVICE_RUNNING)
755             break;
756
757           neug_wait_full ();
758           neug_flush ();
759
760           if ((count & 0x0007) == 0)
761             chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
762           chThdSleepMilliseconds (25);
763           count++;
764         }
765
766     waiting_connection:
767       while (connected == 0)
768         {
769           if (fsij_device_state != FSIJ_DEVICE_RUNNING)
770             break;
771
772           neug_flush ();
773           chEvtSignalFlags (led_thread, LED_TWOSHOTS);
774           chThdSleepMilliseconds (5000);
775         }
776
777       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
778         break;
779
780       /* The connection opened.  */
781       count = 0;
782       /*
783        * No parity is standard.  It means to provide conditioned output.
784        * When parity enabled, it means to provide raw output.
785        */
786       neug_mode_select (line_coding.paritytype); /* 0: None, 1: Odd, 2: Even */
787
788       while (1)
789         {
790           int i;
791
792           if (fsij_device_state != FSIJ_DEVICE_RUNNING)
793             break;
794
795           if (bDeviceState != CONFIGURED)
796             break;
797
798           if ((count & 0x03ff) == 0)
799             chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
800
801           i = neug_consume_random (copy_to_tx);
802
803           if (i == 0 && !last_was_fullsizepacket)
804             {    /* Only send ZLP when the last packet was fullsize.  */
805               neug_wait_full ();
806               continue;
807             }
808
809           if (i == 64/4)
810             last_was_fullsizepacket = 1;
811           else
812             last_was_fullsizepacket = 0;
813
814           chSysLock ();
815           if (connected == 0)
816             {
817               chSysUnlock();
818               goto waiting_connection;
819             }
820           else
821             {
822               usb_lld_tx_enable (ENDP1, i * 4);
823               chSchGoSleepS (THD_STATE_SUSPENDED);
824             }
825           chSysUnlock ();
826
827           count++;
828         }
829     }
830
831   chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
832   chThdWait (led_thread);
833
834   /*
835    * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED.
836    */
837   neug_fini ();
838
839   fsij_device_state = FSIJ_DEVICE_EXITED;
840
841   while (fsij_device_state == FSIJ_DEVICE_EXITED)
842     chThdSleepMilliseconds (500);
843
844   flash_unlock ();              /* Flash unlock should be done here */
845   set_led (1);
846   usb_lld_shutdown ();
847   /* Disable SysTick */
848   SysTick->CTRL = 0;
849   /* Disable all interrupts */
850   port_disable ();
851   /* Set vector */
852   SCB->VTOR = (uint32_t)&_regnual_start;
853   entry = calculate_regnual_entry_address (&_regnual_start);
854 #ifdef DFU_SUPPORT
855 #define FLASH_SYS_START_ADDR 0x08000000
856 #define FLASH_SYS_END_ADDR (0x08000000+0x1000)
857   {
858     extern uint8_t _sys;
859     uint32_t addr;
860     handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
861     void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[10];
862
863     /* Kill DFU */
864     for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
865          addr += FLASH_PAGE_SIZE)
866       flash_erase_page (addr);
867
868     /* copy system service routines */
869     flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
870
871     /* Leave NeuG to exec reGNUal */
872     (*func) ((void (*)(void))entry);
873     for (;;);
874   }
875 #else
876   /* Leave NeuG to exec reGNUal */
877   flash_erase_all_and_exec ((void (*)(void))entry);
878 #endif
879
880   /* Never reached */
881   return 0;
882 }