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