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