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