Version 1.0.1a
[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
27 #include <stdint.h>
28 #include <string.h>
29 #include <chopstx.h>
30
31 #include "config.h"
32 #include "neug.h"
33 #include "usb_lld.h"
34 #include "sys.h"
35 #include "stm32f103.h"
36 #include "adc.h"
37
38 enum {
39   FSIJ_DEVICE_RUNNING = 0,
40   FSIJ_DEVICE_EXITED,
41   FSIJ_DEVICE_EXEC_REQUESTED,
42   /**/
43   FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255
44 }; 
45
46 #ifdef FRAUCHEKY_SUPPORT
47 static uint8_t running_neug;
48 #endif
49
50 static chopstx_mutex_t usb_mtx;
51 static chopstx_cond_t cnd_usb;
52 static uint32_t bDeviceState = UNCONNECTED; /* USB device status */
53 static uint8_t fsij_device_state = FSIJ_DEVICE_RUNNING;
54 static uint8_t connected;
55 static uint32_t wait_usb_connection; /* Timer variable.  */
56
57
58 extern uint8_t __process0_stack_end__;
59 static chopstx_t main_thd = (uint32_t)(&__process0_stack_end__ - 60);
60
61 #define ENDP0_RXADDR        (0x40)
62 #define ENDP0_TXADDR        (0x80)
63 #define ENDP1_TXADDR        (0xc0)
64 #define ENDP2_TXADDR        (0x100)
65 #define ENDP3_RXADDR        (0x140)
66
67 #define USB_CDC_REQ_SET_LINE_CODING             0x20
68 #define USB_CDC_REQ_GET_LINE_CODING             0x21
69 #define USB_CDC_REQ_SET_CONTROL_LINE_STATE      0x22
70 #define USB_CDC_REQ_SEND_BREAK                  0x23
71
72 /* USB Device Descriptor */
73 static const uint8_t vcom_device_desc[18] = {
74   18,   /* bLength */
75   USB_DEVICE_DESCRIPTOR_TYPE,   /* bDescriptorType */
76   0x10, 0x01,                   /* bcdUSB = 1.1 */
77   0x02,                         /* bDeviceClass (CDC).              */
78   0x00,                         /* bDeviceSubClass.                 */
79   0x00,                         /* bDeviceProtocol.                 */
80   0x40,                         /* bMaxPacketSize.                  */
81 #include "usb-vid-pid-ver.c.inc"
82   1,                            /* iManufacturer.                   */
83   2,                            /* iProduct.                        */
84   3,                            /* iSerialNumber.                   */
85   1                             /* bNumConfigurations.              */
86 };
87
88 /* Configuration Descriptor tree for a CDC.*/
89 static const uint8_t vcom_configuration_desc[67] = {
90   9,
91   USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
92   /* Configuration Descriptor.*/
93   67, 0x00,                     /* wTotalLength.                    */
94   0x02,                         /* bNumInterfaces.                  */
95   0x01,                         /* bConfigurationValue.             */
96   0,                            /* iConfiguration.                  */
97   0x80,                         /* bmAttributes (bus powered).      */
98   50,                           /* bMaxPower (100mA).               */
99   /* Interface Descriptor.*/
100   9,
101   USB_INTERFACE_DESCRIPTOR_TYPE,
102   0x00,            /* bInterfaceNumber.                */
103   0x00,            /* bAlternateSetting.               */
104   0x01,            /* bNumEndpoints.                   */
105   0x02,            /* bInterfaceClass (Communications Interface Class,
106                       CDC section 4.2).  */
107   0x02,            /* bInterfaceSubClass (Abstract Control Model, CDC
108                       section 4.3).  */
109   0x01,            /* bInterfaceProtocol (AT commands, CDC section
110                       4.4).  */
111   0,               /* iInterface.                      */
112   /* Header Functional Descriptor (CDC section 5.2.3).*/
113   5,          /* bLength.                         */
114   0x24,       /* bDescriptorType (CS_INTERFACE).  */
115   0x00,       /* bDescriptorSubtype (Header Functional Descriptor). */
116   0x10, 0x01, /* bcdCDC.                          */
117   /* Call Management Functional Descriptor. */
118   5,            /* bFunctionLength.                 */
119   0x24,         /* bDescriptorType (CS_INTERFACE).  */
120   0x01,         /* bDescriptorSubtype (Call Management Functional
121                    Descriptor). */
122   0x03,         /* bmCapabilities (D0+D1).          */
123   0x01,         /* bDataInterface.                  */
124   /* ACM Functional Descriptor.*/
125   4,            /* bFunctionLength.                 */
126   0x24,         /* bDescriptorType (CS_INTERFACE).  */
127   0x02,         /* bDescriptorSubtype (Abstract Control Management
128                    Descriptor).  */
129   0x02,         /* bmCapabilities.                  */
130   /* Union Functional Descriptor.*/
131   5,            /* bFunctionLength.                 */
132   0x24,         /* bDescriptorType (CS_INTERFACE).  */
133   0x06,         /* bDescriptorSubtype (Union Functional
134                    Descriptor).  */
135   0x00,         /* bMasterInterface (Communication Class
136                    Interface).  */
137   0x01,         /* bSlaveInterface0 (Data Class Interface).  */
138   /* Endpoint 2 Descriptor.*/
139   7,
140   USB_ENDPOINT_DESCRIPTOR_TYPE,
141   ENDP2|0x80,    /* bEndpointAddress.    */
142   0x03,          /* bmAttributes (Interrupt).        */
143   0x08, 0x00,    /* wMaxPacketSize.                  */
144   0xFF,          /* bInterval.                       */
145   /* Interface Descriptor.*/
146   9,
147   USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
148   0x01,          /* bInterfaceNumber.                */
149   0x00,          /* bAlternateSetting.               */
150   0x02,          /* bNumEndpoints.                   */
151   0x0A,          /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
152   0x00,          /* bInterfaceSubClass (CDC section 4.6). */
153   0x00,          /* bInterfaceProtocol (CDC section 4.7). */
154   0x00,          /* iInterface.                      */
155   /* Endpoint 3 Descriptor.*/
156   7,
157   USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
158   ENDP3,    /* bEndpointAddress. */
159   0x02,                         /* bmAttributes (Bulk).             */
160   0x40, 0x00,                   /* wMaxPacketSize.                  */
161   0x00,                         /* bInterval.                       */
162   /* Endpoint 1 Descriptor.*/
163   7,
164   USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
165   ENDP1|0x80,                   /* bEndpointAddress. */
166   0x02,                         /* bmAttributes (Bulk).             */
167   0x40, 0x00,                   /* wMaxPacketSize.                  */
168   0x00                          /* bInterval.                       */
169 };
170
171
172 /*
173  * U.S. English language identifier.
174  */
175 static const uint8_t vcom_string0[4] = {
176   4,                            /* bLength */
177   USB_STRING_DESCRIPTOR_TYPE,
178   0x09, 0x04                    /* LangID = 0x0409: US-English */
179 };
180
181 #include "usb-strings.c.inc"
182
183 #ifdef FRAUCHEKY_SUPPORT
184 extern int fraucheky_enabled (void);
185 extern void fraucheky_main (void);
186
187 extern void fraucheky_setup_endpoints_for_interface (int stop);
188 extern int fraucheky_setup (uint8_t req, uint8_t req_no, uint16_t value,
189                             uint16_t len);
190 extern int fraucheky_get_descriptor (uint8_t rcp, uint8_t desc_type,
191                                      uint8_t desc_index, uint16_t index);
192 #endif
193
194 #define NUM_INTERFACES 2
195
196 void
197 usb_cb_device_reset (void)
198 {
199   /* Set DEVICE as not configured */
200   usb_lld_set_configuration (0);
201
202   /* Current Feature initialization */
203   usb_lld_set_feature (vcom_configuration_desc[7]);
204
205   usb_lld_reset ();
206
207   /* Initialize Endpoint 0 */
208   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
209 }
210
211 extern uint8_t _regnual_start, __heap_end__;
212
213 static const uint8_t *const mem_info[] = { &_regnual_start,  &__heap_end__, };
214
215 /* USB vendor requests to control pipe */
216 #define USB_FSIJ_MEMINFO          0
217 #define USB_FSIJ_DOWNLOAD         1
218 #define USB_FSIJ_EXEC             2
219 #define USB_NEUG_GET_INFO       254
220 #define USB_NEUG_EXIT           255 /* Ask to exit and to receive reGNUal */
221
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           chopstx_mutex_lock (&usb_mtx);
261           if (fsij_device_state == FSIJ_DEVICE_EXITED)
262             {
263               usb_lld_prepare_shutdown (); /* No further USB communication */
264               fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED;
265             }
266           chopstx_mutex_unlock (&usb_mtx);
267         }
268       else if (req_no == USB_NEUG_EXIT)
269         {
270           /* Force exit from the main loop.  */
271           if (wait_usb_connection)
272             {
273               wait_usb_connection = 0;
274               chopstx_wakeup_usec_wait (main_thd);
275             }
276           else
277             {
278               chopstx_mutex_lock (&usb_mtx);
279               chopstx_cond_signal (&cnd_usb);
280               chopstx_mutex_unlock (&usb_mtx);
281             }
282         }
283     }
284   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
285            && index == 0 && USB_SETUP_SET (req)
286            && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
287     {
288       /* Open/close the connection.  */
289       chopstx_mutex_lock (&usb_mtx);
290       connected = (value != 0)? 1 : 0;
291       if (wait_usb_connection)
292         {                       /* It is waiting a connection.  */
293           if (connected)        /* It's now connected.  */
294             {
295               wait_usb_connection = 0;
296               chopstx_wakeup_usec_wait (main_thd);
297             }
298         }
299       else
300         chopstx_cond_signal (&cnd_usb);
301       chopstx_mutex_unlock (&usb_mtx);
302     }
303 }
304
305 struct line_coding
306 {
307   uint32_t bitrate;
308   uint8_t format;
309   uint8_t paritytype;
310   uint8_t datatype;
311 } __attribute__((packed));
312
313 static struct line_coding line_coding = {
314   115200, /* baud rate: 115200    */
315   0x00,   /* stop bits: 1         */
316   0x00,   /* parity:    none      */
317   0x08    /* bits:      8         */
318 };
319
320
321 static int
322 vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value,
323                       uint16_t len)
324 {
325   (void)value;
326   if (USB_SETUP_GET (req))
327     {
328       if (req_no == USB_CDC_REQ_GET_LINE_CODING
329           && len == sizeof (line_coding))
330         {
331           usb_lld_set_data_to_send (&line_coding, sizeof (line_coding));
332           return USB_SUCCESS;
333         }
334     }
335   else  /* USB_SETUP_SET (req) */
336     {
337       if (req_no == USB_CDC_REQ_SET_LINE_CODING
338           && len == sizeof (line_coding))
339         {
340           usb_lld_set_data_to_recv (&line_coding, sizeof (line_coding));
341           return USB_SUCCESS;
342         }
343       else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
344         return USB_SUCCESS;
345     }
346
347   return USB_UNSUPPORT;
348 }
349
350 int
351 usb_cb_setup (uint8_t req, uint8_t req_no,
352                uint16_t value, uint16_t index, uint16_t len)
353 {
354   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
355
356   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
357     {
358       if (USB_SETUP_GET (req))
359         {
360           if (req_no == USB_FSIJ_MEMINFO)
361             {
362               usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
363               return USB_SUCCESS;
364             }
365           else if (req_no == USB_NEUG_GET_INFO)
366             {
367               if (index == 0)
368                 usb_lld_set_data_to_send (&neug_mode, sizeof (uint8_t));
369               else if (index == 1)
370                 usb_lld_set_data_to_send (&neug_err_cnt, sizeof (uint16_t));
371               else if (index == 2)
372                 usb_lld_set_data_to_send (&neug_err_cnt_rc, sizeof (uint16_t));
373               else if (index == 3)
374                 usb_lld_set_data_to_send (&neug_err_cnt_p64, sizeof (uint16_t));
375               else if (index == 4)
376                 usb_lld_set_data_to_send (&neug_err_cnt_p4k, sizeof (uint16_t));
377               else if (index == 5)
378                 usb_lld_set_data_to_send (&neug_rc_max, sizeof (uint16_t));
379               else if (index == 6)
380                 usb_lld_set_data_to_send (&neug_p64_max, sizeof (uint16_t));
381               else if (index == 7)
382                 usb_lld_set_data_to_send (&neug_p4k_max, sizeof (uint16_t));
383               else
384                 return USB_UNSUPPORT;
385
386               return USB_SUCCESS;
387             }
388         }
389       else /* SETUP_SET */
390         {
391           uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
392
393           if (req_no == USB_FSIJ_DOWNLOAD)
394             {
395               chopstx_mutex_lock (&usb_mtx);
396               if (fsij_device_state != FSIJ_DEVICE_EXITED)
397                 {
398                   chopstx_mutex_unlock (&usb_mtx);
399                   return USB_UNSUPPORT;
400                 }
401               chopstx_mutex_unlock (&usb_mtx);
402
403               if (addr < &_regnual_start || addr + len > &__heap_end__)
404                 return USB_UNSUPPORT;
405
406               if (index + len < 256)
407                 memset (addr + index + len, 0, 256 - (index + len));
408
409               usb_lld_set_data_to_recv (addr, len);
410               return USB_SUCCESS;
411             }
412           else if (req_no == USB_FSIJ_EXEC && len == 0)
413             {
414               chopstx_mutex_lock (&usb_mtx);
415               if (fsij_device_state != FSIJ_DEVICE_EXITED)
416                 {
417                   chopstx_mutex_unlock (&usb_mtx);
418                   return USB_UNSUPPORT;
419                 }
420               chopstx_mutex_unlock (&usb_mtx);
421
422               if (((uint32_t)addr & 0x03))
423                 return USB_UNSUPPORT;
424
425               return download_check_crc32 ((uint32_t *)addr);
426             }
427           else if (req_no == USB_NEUG_EXIT && len == 0)
428             {
429               chopstx_mutex_lock (&usb_mtx);
430               if (fsij_device_state != FSIJ_DEVICE_RUNNING)
431                 {
432                   chopstx_mutex_unlock (&usb_mtx);
433                   return USB_UNSUPPORT;
434                 }
435
436               fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
437               chopstx_wakeup_usec_wait (main_thd);
438               chopstx_cond_signal (&cnd_usb);
439               chopstx_mutex_unlock (&usb_mtx);
440
441               return USB_SUCCESS;
442             }
443         }
444     }
445   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
446     {
447       if (index == 0)
448         {
449 #ifdef FRAUCHEKY_SUPPORT
450           if (running_neug)
451             return vcom_port_data_setup (req, req_no, value, len);
452           else
453             fraucheky_setup (req, req_no, value, len);
454 #else
455           return vcom_port_data_setup (req, req_no, value, len);
456 #endif
457         }
458     }
459
460   return USB_UNSUPPORT;
461 }
462
463 int
464 usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
465                        uint16_t index)
466 {
467 #ifdef FRAUCHEKY_SUPPORT
468   if (!running_neug)
469     return fraucheky_get_descriptor (rcp, desc_type, desc_index, index);
470 #else
471   (void)index;
472 #endif
473
474   if (rcp != DEVICE_RECIPIENT)
475     return USB_UNSUPPORT;
476
477   if (desc_type == DEVICE_DESCRIPTOR)
478     {
479       usb_lld_set_data_to_send (vcom_device_desc, sizeof (vcom_device_desc));
480       return USB_SUCCESS;
481     }
482   else if (desc_type == CONFIG_DESCRIPTOR)
483     {
484       usb_lld_set_data_to_send (vcom_configuration_desc,
485                                 sizeof (vcom_configuration_desc));
486       return USB_SUCCESS;
487     }
488   else if (desc_type == STRING_DESCRIPTOR)
489     {
490       const uint8_t *str;
491       int size;
492
493       switch (desc_index)
494         {
495         case 0:
496           str = vcom_string0;
497           size = sizeof (vcom_string0);
498           break;
499         case 1:
500           str = neug_string_vendor;
501           size = sizeof (neug_string_vendor);
502           break;
503         case 2:
504           str = neug_string_product;
505           size = sizeof (neug_string_product);
506           break;
507         case 3:
508           str = neug_string_serial;
509           size = sizeof (neug_string_serial);
510           break;
511         case 4:
512           str = neug_revision_detail;
513           size = sizeof (neug_revision_detail);
514           break;
515         case 5:
516           str = neug_config_options;
517           size = sizeof (neug_config_options);
518           break;
519         case 6:
520           str = sys_version;
521           size = sizeof (sys_version);
522           break;
523         default:
524           return USB_UNSUPPORT;
525         }
526
527       usb_lld_set_data_to_send (str, size);
528       return USB_SUCCESS;
529     }
530
531   return USB_UNSUPPORT;
532 }
533
534 static void
535 neug_setup_endpoints_for_interface (uint16_t interface, int stop)
536 {
537   if (interface == 0)
538     {
539 #ifdef FRAUCHEKY_SUPPORT
540       if (running_neug)
541         {
542           if (!stop)
543             usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
544           else
545             usb_lld_stall_tx (ENDP2);
546         }
547       else
548         fraucheky_setup_endpoints_for_interface (stop);
549 #else
550       if (!stop)
551         usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
552       else
553         usb_lld_stall_tx (ENDP2);
554 #endif
555     }
556   else if (interface == 1)
557     {
558       if (!stop)
559         {
560           usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
561           usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
562         }
563       else
564         {
565           usb_lld_stall_tx (ENDP1);
566           usb_lld_stall_rx (ENDP3);
567         }
568     }
569 }
570
571 int usb_cb_handle_event (uint8_t event_type, uint16_t value)
572 {
573   int i;
574   uint8_t current_conf;
575
576   switch (event_type)
577     {
578     case USB_EVENT_ADDRESS:
579       chopstx_mutex_lock (&usb_mtx);
580       bDeviceState = ADDRESSED;
581       chopstx_mutex_unlock (&usb_mtx);
582       return USB_SUCCESS;
583     case USB_EVENT_CONFIG:
584       current_conf = usb_lld_current_configuration ();
585       if (current_conf == 0)
586         {
587           if (value != 1)
588             return USB_UNSUPPORT;
589
590           usb_lld_set_configuration (1);
591           for (i = 0; i < NUM_INTERFACES; i++)
592             neug_setup_endpoints_for_interface (i, 0);
593           chopstx_mutex_lock (&usb_mtx);
594           bDeviceState = CONFIGURED;
595           chopstx_mutex_unlock (&usb_mtx);
596         }
597       else if (current_conf != value)
598         {
599           if (value != 0)
600             return USB_UNSUPPORT;
601
602           usb_lld_set_configuration (0);
603           for (i = 0; i < NUM_INTERFACES; i++)
604             neug_setup_endpoints_for_interface (i, 1);
605           chopstx_mutex_lock (&usb_mtx);
606           bDeviceState = ADDRESSED;
607           chopstx_mutex_unlock (&usb_mtx);
608         }
609       /* Do nothing when current_conf == value */
610       return USB_SUCCESS;
611
612       return USB_SUCCESS;
613     default:
614       break;
615     }
616
617   return USB_UNSUPPORT;
618 }
619
620
621 int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
622 {
623   static uint8_t zero = 0;
624
625   if (interface >= NUM_INTERFACES)
626     return USB_UNSUPPORT;
627
628   switch (cmd)
629     {
630     case USB_SET_INTERFACE:
631       if (alt != 0)
632         return USB_UNSUPPORT;
633       else
634         {
635           neug_setup_endpoints_for_interface (interface, 0);
636           return USB_SUCCESS;
637         }
638
639     case USB_GET_INTERFACE:
640       usb_lld_set_data_to_send (&zero, 1);
641       return USB_SUCCESS;
642
643     default:
644     case USB_QUERY_INTERFACE:
645       return USB_SUCCESS;
646     }
647 }
648
649 #define INTR_REQ_USB 20
650 #define PRIO_USB 3
651
652 static void *
653 usb_intr (void *arg)
654 {
655   chopstx_intr_t interrupt;
656
657   (void)arg;
658   usb_lld_init (vcom_configuration_desc[7]);
659   chopstx_claim_irq (&interrupt, INTR_REQ_USB);
660   usb_interrupt_handler ();
661
662   while (1)
663     {
664       chopstx_intr_wait (&interrupt);
665
666       /* Process interrupt. */
667       usb_interrupt_handler ();
668     }
669
670   return NULL;
671 }
672
673 #define ID_OFFSET (2+SERIALNO_STR_LEN*2)
674 static void fill_serial_no_by_unique_id (void)
675 {
676   extern const uint8_t * unique_device_id (void);
677   uint8_t *p = &neug_string_serial[ID_OFFSET];
678   const uint8_t *u = unique_device_id () + 8;
679   int i;
680
681   for (i = 0; i < 4; i++)
682     {
683       uint8_t b = u[3-i];
684       uint8_t nibble; 
685
686       nibble = (b >> 4);
687       nibble += (nibble >= 10 ? ('A' - 10) : '0');
688       p[i*4] = nibble;
689       p[i*4+1] = 0;
690       nibble = (b & 0x0f);
691       nibble += (nibble >= 10 ? ('A' - 10) : '0');
692       p[i*4+2] = nibble;
693       p[i*4+3] = 0;
694     }
695 }
696 \f
697 void
698 EP1_IN_Callback (void)
699 {
700   chopstx_mutex_lock (&usb_mtx);
701   chopstx_cond_signal (&cnd_usb);
702   chopstx_mutex_unlock (&usb_mtx);
703 }
704
705 void
706 EP2_IN_Callback (void)
707 {
708 }
709
710 void
711 EP3_OUT_Callback (void)
712 {
713   usb_lld_rx_enable (ENDP3);
714 }
715 \f
716 typedef uint32_t eventmask_t;
717 #define ALL_EVENTS (~0)
718
719 struct event_flag {
720   chopstx_mutex_t mutex;
721   chopstx_cond_t cond;
722   eventmask_t flag;
723 };
724
725 static void event_flag_init (struct event_flag *ev)
726 {
727   ev->flag = 0;
728   chopstx_mutex_init (&ev->mutex);
729   chopstx_cond_init (&ev->cond);
730 }
731
732
733 static eventmask_t event_flag_waitone (struct event_flag *ev, eventmask_t m)
734 {
735   int n;
736
737   chopstx_mutex_lock (&ev->mutex);
738   while (!(ev->flag & m))
739     chopstx_cond_wait (&ev->cond, &ev->mutex);
740
741   n = __builtin_ffs ((ev->flag & m));
742   ev->flag &= ~(1 << (n - 1));
743   chopstx_mutex_unlock (&ev->mutex);
744
745   return (1 << (n - 1));
746 }
747
748 static void event_flag_signal (struct event_flag *ev, eventmask_t m)
749 {
750   chopstx_mutex_lock (&ev->mutex);
751   ev->flag |= m;
752   chopstx_cond_signal (&ev->cond);
753   chopstx_mutex_unlock (&ev->mutex);
754 }
755
756 extern uint8_t __process1_stack_base__, __process1_stack_size__;
757 extern uint8_t __process3_stack_base__, __process3_stack_size__;
758
759 const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
760 const size_t __stacksize_led = (size_t)&__process1_stack_size__;
761 const uint32_t __stackaddr_usb = (uint32_t)&__process3_stack_base__;
762 const size_t __stacksize_usb = (size_t)&__process3_stack_size__;
763
764
765 #define PRIO_LED 3
766 static struct event_flag led_event;
767
768 #define LED_ONESHOT_SHORT       ((eventmask_t)1)
769 #define LED_TWOSHOTS            ((eventmask_t)2)
770 #define LED_ONESHOT_LONG        ((eventmask_t)4)
771
772 /*
773  * LED blinker: When notified, let LED emit for 100ms.
774  */
775 static void *
776 led_blinker (void *arg)
777 {
778   (void)arg;
779
780   set_led (0);
781
782   while (1)
783     {
784       eventmask_t m;
785
786       m = event_flag_waitone (&led_event, ALL_EVENTS);
787       if (fsij_device_state != FSIJ_DEVICE_RUNNING) /* No usb_mtx lock.  */
788         break;
789
790       set_led (1);
791       if (m == LED_ONESHOT_SHORT)
792         chopstx_usec_wait (100*1000);
793       else if (m == LED_TWOSHOTS)
794         {
795           chopstx_usec_wait (50*1000);
796           set_led (0);
797           chopstx_usec_wait (50*1000);
798           set_led (1);
799           chopstx_usec_wait (50*1000);
800         }
801       else
802         chopstx_usec_wait (250*1000);
803       set_led (0);
804     }
805
806   return NULL;
807 }
808 \f
809 #define RANDOM_BYTES_LENGTH 64
810 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
811
812 static void copy_to_tx (uint32_t v, int i)
813 {
814   usb_lld_txcpy (&v, ENDP1, i * 4, 4);
815 }
816
817 /*
818  * In Gnuk 1.0.[12], reGNUal was not relocatable.
819  * Now, it's relocatable, but we need to calculate its entry address
820  * based on it's pre-defined address.
821  */
822 #define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
823 static uint32_t
824 calculate_regnual_entry_address (const uint8_t *addr)
825 {
826   const uint8_t *p = addr + 4;
827   uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
828
829   v -= REGNUAL_START_ADDRESS_COMPATIBLE;
830   v += (uint32_t)addr;
831   return v;
832 }
833
834
835 /*
836  * Entry point.
837  *
838  * NOTE: the main function is already a thread in the system on entry.
839  */
840 int
841 main (int argc, char **argv)
842 {
843   uint32_t entry;
844   chopstx_t led_thread, usb_thd;
845   unsigned int count;
846
847   (void)argc;
848   (void)argv;
849
850   fill_serial_no_by_unique_id ();
851
852   adc_init ();
853
854   event_flag_init (&led_event);
855   
856   chopstx_mutex_init (&usb_mtx);
857   chopstx_cond_init (&cnd_usb);
858
859   led_thread = chopstx_create (PRIO_LED, __stackaddr_led, __stacksize_led,
860                                led_blinker, NULL);
861
862 #ifdef FRAUCHEKY_SUPPORT
863   if (fraucheky_enabled ())
864     {
865       usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
866                                 usb_intr, NULL);
867       fraucheky_main ();
868       chopstx_cancel (usb_thd);
869       chopstx_join (usb_thd, NULL);
870       usb_lld_shutdown ();
871     }
872
873   running_neug = 1;
874 #endif
875
876   usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
877                             usb_intr, NULL);
878
879   neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
880
881   chopstx_mutex_lock (&usb_mtx);
882
883  not_configured:
884   count = 0;
885   /* A run-up */
886   while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
887     {
888       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
889         break;
890
891       chopstx_mutex_unlock (&usb_mtx);
892       neug_wait_full ();
893       neug_flush ();
894
895       if ((count & 0x0007) == 0)
896         event_flag_signal (&led_event, LED_ONESHOT_SHORT);
897       chopstx_usec_wait (25*1000);
898       count++;
899       chopstx_mutex_lock (&usb_mtx);
900     }
901
902   /* Holding USB_MTX.  */
903   while (1)
904     {
905       int last_was_fullsizepacket = 0;
906
907       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
908         break;
909
910       while (1)
911         {
912           wait_usb_connection = 5000*1000;
913           if (connected || bDeviceState != CONFIGURED
914               || fsij_device_state != FSIJ_DEVICE_RUNNING)
915             break;
916
917           chopstx_mutex_unlock (&usb_mtx);
918           neug_flush ();
919           neug_mode_select (line_coding.paritytype);
920           event_flag_signal (&led_event, LED_TWOSHOTS);
921           chopstx_usec_wait_var (&wait_usb_connection);
922           chopstx_mutex_lock (&usb_mtx);
923         }
924
925       if (bDeviceState != CONFIGURED)
926         goto not_configured;
927
928       /* The connection opened.  */
929       count = 0;
930
931       while (1)
932         {
933           int i;
934
935           chopstx_mutex_unlock (&usb_mtx);
936           /*
937            * No parity is standard.  It means providing conditioned output.
938            * When parity enabled, it means to provide raw output
939            * (CRC32 filtered when odd, direct sample of ADC when even).
940            *
941            * line_coding.paritytype:
942            *   0: None, 1: Odd, 2: Even
943            */
944           neug_mode_select (line_coding.paritytype);
945
946           if ((count & 0x03ff) == 0)
947             event_flag_signal (&led_event, LED_ONESHOT_SHORT);
948
949           i = neug_consume_random (copy_to_tx);
950
951           if (i == 0 && !last_was_fullsizepacket)
952             {    /* Only send ZLP when the last packet was fullsize.  */
953               neug_wait_full ();
954
955               chopstx_mutex_lock (&usb_mtx);
956               if (bDeviceState != CONFIGURED || !connected
957                   || fsij_device_state != FSIJ_DEVICE_RUNNING)
958                 break;
959             }
960           else
961             {
962               if (i == 64/4)
963                 last_was_fullsizepacket = 1;
964               else
965                 last_was_fullsizepacket = 0;
966
967               chopstx_mutex_lock (&usb_mtx);
968               if (bDeviceState != CONFIGURED || !connected
969                   || fsij_device_state != FSIJ_DEVICE_RUNNING)
970                 break;
971
972               /* Prepare sending random data.  */
973               usb_lld_tx_enable (ENDP1, i * 4);
974               chopstx_cond_wait (&cnd_usb, &usb_mtx);
975               count++;
976             }
977         }
978     }
979
980   chopstx_mutex_unlock (&usb_mtx);
981
982   chopstx_cancel (led_thread);
983   chopstx_join (led_thread, NULL);
984
985   /*
986    * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED.
987    */
988   neug_fini ();
989
990   chopstx_mutex_lock (&usb_mtx);
991   fsij_device_state = FSIJ_DEVICE_EXITED;
992
993   while (fsij_device_state == FSIJ_DEVICE_EXITED)
994     {
995       chopstx_mutex_unlock (&usb_mtx);
996       chopstx_usec_wait (500*1000);
997       chopstx_mutex_lock (&usb_mtx);
998     }
999   chopstx_mutex_unlock (&usb_mtx);
1000
1001   flash_unlock ();              /* Flash unlock should be done here */
1002   set_led (1);
1003   usb_lld_shutdown ();
1004
1005   /* Finish application.  */
1006   chopstx_cancel (usb_thd);
1007   chopstx_join (usb_thd, NULL);
1008
1009   /* Set vector */
1010   SCB->VTOR = (uint32_t)&_regnual_start;
1011   entry = calculate_regnual_entry_address (&_regnual_start);
1012 #ifdef DFU_SUPPORT
1013 #define FLASH_SYS_START_ADDR 0x08000000
1014 #define FLASH_SYS_END_ADDR (0x08000000+0x1000)
1015   {
1016     extern uint8_t _sys;
1017     uint32_t addr;
1018     handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
1019     void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[9];
1020
1021     /* Kill DFU */
1022     for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
1023          addr += FLASH_PAGE_SIZE)
1024       flash_erase_page (addr);
1025
1026     /* copy system service routines */
1027     flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
1028
1029     /* Leave NeuG to exec reGNUal */
1030     (*func) ((void (*)(void))entry);
1031     for (;;);
1032   }
1033 #else
1034   /* Leave NeuG to exec reGNUal */
1035   flash_erase_all_and_exec ((void (*)(void))entry);
1036 #endif
1037
1038   /* Never reached */
1039   return 0;
1040 }