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