2 * main.c - main routine of neug
5 * Copyright (C) 2011, 2012 Free Software Initiative of Japan
6 * Author: NIIBE Yutaka <gniibe@fsij.org>
8 * This file is a part of NeuG, a Random Number Generator
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.
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.
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/>.
36 * We are trying to avoid dependency to C library.
37 * GCC built-in function(s) are declared here.
39 extern void *memcpy(void *dest, const void *src, size_t n);
40 extern void *memset (void *s, int c, size_t n);
42 static Thread *main_thread;
45 #define ENDP0_RXADDR (0x40)
46 #define ENDP0_TXADDR (0x80)
47 #define ENDP1_TXADDR (0xc0)
48 #define ENDP2_TXADDR (0x100)
49 #define ENDP3_RXADDR (0x140)
51 #define USB_CDC_REQ_SET_LINE_CODING 0x20
52 #define USB_CDC_REQ_GET_LINE_CODING 0x21
53 #define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
54 #define USB_CDC_REQ_SEND_BREAK 0x23
56 /* USB Device Descriptor */
57 static const uint8_t vcom_device_desc[18] = {
59 USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
60 0x10, 0x01, /* bcdUSB = 1.1 */
61 0x02, /* bDeviceClass (CDC). */
62 0x00, /* bDeviceSubClass. */
63 0x00, /* bDeviceProtocol. */
64 0x40, /* bMaxPacketSize. */
65 #include "usb-vid-pid-ver.c.inc"
66 1, /* iManufacturer. */
68 3, /* iSerialNumber. */
69 1 /* bNumConfigurations. */
72 /* Configuration Descriptor tree for a CDC.*/
73 static const uint8_t vcom_configuration_desc[67] = {
75 USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
76 /* Configuration Descriptor.*/
77 67, 0x00, /* wTotalLength. */
78 0x02, /* bNumInterfaces. */
79 0x01, /* bConfigurationValue. */
80 0, /* iConfiguration. */
81 0x80, /* bmAttributes (bus powered). */
82 50, /* bMaxPower (100mA). */
83 /* Interface Descriptor.*/
85 USB_INTERFACE_DESCRIPTOR_TYPE,
86 0x00, /* bInterfaceNumber. */
87 0x00, /* bAlternateSetting. */
88 0x01, /* bNumEndpoints. */
89 0x02, /* bInterfaceClass (Communications Interface Class,
91 0x02, /* bInterfaceSubClass (Abstract Control Model, CDC
93 0x01, /* bInterfaceProtocol (AT commands, CDC section
96 /* Header Functional Descriptor (CDC section 5.2.3).*/
98 0x24, /* bDescriptorType (CS_INTERFACE). */
99 0x00, /* bDescriptorSubtype (Header Functional Descriptor). */
100 0x10, 0x01, /* bcdCDC. */
101 /* Call Management Functional Descriptor. */
102 5, /* bFunctionLength. */
103 0x24, /* bDescriptorType (CS_INTERFACE). */
104 0x01, /* bDescriptorSubtype (Call Management Functional
106 0x03, /* bmCapabilities (D0+D1). */
107 0x01, /* bDataInterface. */
108 /* ACM Functional Descriptor.*/
109 4, /* bFunctionLength. */
110 0x24, /* bDescriptorType (CS_INTERFACE). */
111 0x02, /* bDescriptorSubtype (Abstract Control Management
113 0x02, /* bmCapabilities. */
114 /* Union Functional Descriptor.*/
115 5, /* bFunctionLength. */
116 0x24, /* bDescriptorType (CS_INTERFACE). */
117 0x06, /* bDescriptorSubtype (Union Functional
119 0x00, /* bMasterInterface (Communication Class
121 0x01, /* bSlaveInterface0 (Data Class Interface). */
122 /* Endpoint 2 Descriptor.*/
124 USB_ENDPOINT_DESCRIPTOR_TYPE,
125 ENDP2|0x80, /* bEndpointAddress. */
126 0x03, /* bmAttributes (Interrupt). */
127 0x08, 0x00, /* wMaxPacketSize. */
128 0xFF, /* bInterval. */
129 /* Interface Descriptor.*/
131 USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
132 0x01, /* bInterfaceNumber. */
133 0x00, /* bAlternateSetting. */
134 0x02, /* bNumEndpoints. */
135 0x0A, /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
136 0x00, /* bInterfaceSubClass (CDC section 4.6). */
137 0x00, /* bInterfaceProtocol (CDC section 4.7). */
138 0x00, /* iInterface. */
139 /* Endpoint 3 Descriptor.*/
141 USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
142 ENDP3, /* bEndpointAddress. */
143 0x02, /* bmAttributes (Bulk). */
144 0x40, 0x00, /* wMaxPacketSize. */
145 0x00, /* bInterval. */
146 /* Endpoint 1 Descriptor.*/
148 USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
149 ENDP1|0x80, /* bEndpointAddress. */
150 0x02, /* bmAttributes (Bulk). */
151 0x40, 0x00, /* wMaxPacketSize. */
152 0x00 /* bInterval. */
157 * U.S. English language identifier.
159 static const uint8_t vcom_string0[4] = {
161 USB_STRING_DESCRIPTOR_TYPE,
162 0x09, 0x04 /* LangID = 0x0409: US-English */
165 #define USB_STRINGS_FOR_NEUG 1
166 #include "usb-strings.c.inc"
169 * Serial Number string. NOTE: This does not have CONST qualifier.
171 static uint8_t vcom_string3[28] = {
173 USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType. */
174 '0', 0, '.', 0, '0', 0, '3', 0, /* Version number of NeuG. */
176 0, 0, 0, 0, /* Filled by Unique device ID. */
182 static const struct Descriptor device_desc = {
184 sizeof (vcom_device_desc)
187 static const struct Descriptor config_desc = {
188 vcom_configuration_desc,
189 sizeof (vcom_configuration_desc)
192 static const struct Descriptor string_descs[] = {
193 {vcom_string0, sizeof vcom_string0},
194 {neug_string_vendor, sizeof (neug_string_vendor)},
195 {neug_string_product, sizeof (neug_string_product)},
196 {vcom_string3, sizeof (vcom_string3)},
197 {neug_revision_detail, sizeof (neug_revision_detail)},
198 {neug_config_options, sizeof (neug_config_options)},
199 {sys_version, sizeof (sys_version)},
202 #define NUM_STRING_DESC (sizeof (string_descs)/sizeof (struct Descriptor))
204 #define NUM_INTERFACES 2
206 uint32_t bDeviceState = UNCONNECTED; /* USB device status */
209 neug_device_reset (void)
211 /* Set DEVICE as not configured */
212 usb_lld_set_configuration (0);
214 /* Current Feature initialization */
215 usb_lld_set_feature (config_desc.Descriptor[7]);
219 /* Initialize Endpoint 0 */
220 usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
223 extern uint8_t _regnual_start, __heap_end__;
225 static const uint8_t *const mem_info[] = { &_regnual_start, &__heap_end__, };
227 /* USB vendor requests to control pipe */
228 #define USB_FSIJ_MEMINFO 0
229 #define USB_FSIJ_DOWNLOAD 1
230 #define USB_FSIJ_EXEC 2
231 #define USB_NEUG_GET_INFO 254
232 #define USB_NEUG_EXIT 255 /* Ask to exit and to receive reGNUal */
235 FSIJ_DEVICE_RUNNING = 0,
237 FSIJ_DEVICE_EXEC_REQUESTED,
239 FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255
242 static uint8_t fsij_device_state = FSIJ_DEVICE_RUNNING;
244 static uint32_t rbit (uint32_t v)
248 asm ("rbit %0, %1" : "=r" (r) : "r" (v));
252 /* After calling this function, CRC module remain enabled. */
253 static int download_check_crc32 (const uint32_t *end_p)
255 uint32_t crc32 = *end_p;
258 RCC->AHBENR |= RCC_AHBENR_CRCEN;
259 CRC->CR = CRC_CR_RESET;
261 for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
264 if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
267 return USB_UNSUPPORT;
270 static void neug_ctrl_write_finish (uint8_t req, uint8_t req_no,
271 uint16_t value, uint16_t index,
274 uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
276 if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
277 && USB_SETUP_SET (req) && len == 0)
279 if (req_no == USB_FSIJ_EXEC)
281 if (fsij_device_state != FSIJ_DEVICE_EXITED)
284 (void)value; (void)index;
285 usb_lld_prepare_shutdown (); /* No further USB communication */
286 fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED;
288 else if (req_no == USB_NEUG_EXIT)
291 if (main_thread->p_state == THD_STATE_SUSPENDED
292 || main_thread->p_state == THD_STATE_SLEEPING)
294 main_thread->p_u.rdymsg = RDY_OK;
295 chSchReadyI (main_thread);
297 chSysUnlockFromIsr ();
310 static struct line_coding line_coding = {
311 115200, /* baud rate: 115200 */
312 0x00, /* stop bits: 1 */
313 0x00, /* parity: none */
317 static uint8_t connected;
320 vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value)
322 if (USB_SETUP_GET (req))
324 if (req_no == USB_CDC_REQ_GET_LINE_CODING)
326 usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
330 else /* USB_SETUP_SET (req) */
332 if (req_no == USB_CDC_REQ_SET_LINE_CODING)
334 usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
337 else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
339 uint8_t connected_saved = connected;
354 if (connected != connected_saved)
357 if (main_thread->p_state == THD_STATE_SUSPENDED
358 || main_thread->p_state == THD_STATE_SLEEPING)
360 main_thread->p_u.rdymsg = RDY_OK;
361 chSchReadyI (main_thread);
363 chSysUnlockFromIsr ();
370 return USB_UNSUPPORT;
374 neug_setup (uint8_t req, uint8_t req_no,
375 uint16_t value, uint16_t index, uint16_t len)
377 uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
379 if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
381 if (USB_SETUP_GET (req))
383 if (req_no == USB_FSIJ_MEMINFO)
385 usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
388 else if (req_no == USB_NEUG_GET_INFO)
391 usb_lld_set_data_to_send (&neug_mode, sizeof (uint8_t));
393 usb_lld_set_data_to_send (&neug_err_cnt, sizeof (uint16_t));
395 usb_lld_set_data_to_send (&neug_err_cnt_rc, sizeof (uint16_t));
397 usb_lld_set_data_to_send (&neug_err_cnt_p64, sizeof (uint16_t));
399 usb_lld_set_data_to_send (&neug_err_cnt_p4k, sizeof (uint16_t));
401 usb_lld_set_data_to_send (&neug_rc_max, sizeof (uint16_t));
403 usb_lld_set_data_to_send (&neug_p64_max, sizeof (uint16_t));
405 usb_lld_set_data_to_send (&neug_p4k_max, sizeof (uint16_t));
407 return USB_UNSUPPORT;
414 uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
416 if (req_no == USB_FSIJ_DOWNLOAD)
418 if (fsij_device_state != FSIJ_DEVICE_EXITED)
419 return USB_UNSUPPORT;
421 if (addr < &_regnual_start || addr + len > &__heap_end__)
422 return USB_UNSUPPORT;
424 if (index + len < 256)
425 memset (addr + index + len, 0, 256 - (index + len));
427 usb_lld_set_data_to_recv (addr, len);
430 else if (req_no == USB_FSIJ_EXEC && len == 0)
432 if (fsij_device_state != FSIJ_DEVICE_EXITED)
433 return USB_UNSUPPORT;
435 if (((uint32_t)addr & 0x03))
436 return USB_UNSUPPORT;
438 return download_check_crc32 ((uint32_t *)addr);
440 else if (req_no == USB_NEUG_EXIT && len == 0)
442 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
443 return USB_UNSUPPORT;
445 fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
450 else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
452 return vcom_port_data_setup (req, req_no, value);
454 return USB_UNSUPPORT;
458 neug_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
461 if (desc_type == DEVICE_DESCRIPTOR)
463 usb_lld_set_data_to_send (device_desc.Descriptor,
464 device_desc.Descriptor_Size);
467 else if (desc_type == CONFIG_DESCRIPTOR)
469 usb_lld_set_data_to_send (config_desc.Descriptor,
470 config_desc.Descriptor_Size);
473 else if (desc_type == STRING_DESCRIPTOR)
475 uint8_t desc_index = value & 0xff;
477 if (desc_index < NUM_STRING_DESC)
479 usb_lld_set_data_to_send (string_descs[desc_index].Descriptor,
480 string_descs[desc_index].Descriptor_Size);
485 return USB_UNSUPPORT;
489 neug_setup_endpoints_for_interface (uint16_t interface, int stop)
494 usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
496 usb_lld_stall_tx (ENDP2);
498 else if (interface == 1)
502 usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
503 usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
507 usb_lld_stall_tx (ENDP1);
508 usb_lld_stall_rx (ENDP3);
513 static int neug_usb_event (uint8_t event_type, uint16_t value)
516 uint8_t current_conf;
520 case USB_EVENT_ADDRESS:
521 bDeviceState = ADDRESSED;
523 case USB_EVENT_CONFIG:
524 current_conf = usb_lld_current_configuration ();
525 if (current_conf == 0)
528 return USB_UNSUPPORT;
530 usb_lld_set_configuration (1);
531 for (i = 0; i < NUM_INTERFACES; i++)
532 neug_setup_endpoints_for_interface (i, 0);
533 bDeviceState = CONFIGURED;
535 else if (current_conf != value)
538 return USB_UNSUPPORT;
540 usb_lld_set_configuration (0);
541 for (i = 0; i < NUM_INTERFACES; i++)
542 neug_setup_endpoints_for_interface (i, 1);
543 bDeviceState = ADDRESSED;
545 /* Do nothing when current_conf == value */
553 return USB_UNSUPPORT;
557 static int neug_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
559 static uint8_t zero = 0;
561 if (interface >= NUM_INTERFACES)
562 return USB_UNSUPPORT;
566 case USB_SET_INTERFACE:
568 return USB_UNSUPPORT;
571 neug_setup_endpoints_for_interface (interface, 0);
575 case USB_GET_INTERFACE:
576 usb_lld_set_data_to_send (&zero, 1);
580 case USB_QUERY_INTERFACE:
585 const struct usb_device_method Device_Method = {
587 neug_ctrl_write_finish,
596 static void fill_serial_no_by_unique_id (void)
598 extern const uint8_t * unique_device_id (void);
599 uint8_t *p = &vcom_string3[12];
600 const uint8_t *u = unique_device_id ();
603 for (i = 0; i < 4; i++)
609 nibble += (nibble >= 10 ? ('A' - 10) : '0');
612 nibble += (nibble >= 10 ? ('A' - 10) : '0');
617 CH_IRQ_HANDLER (Vector90)
620 usb_interrupt_handler ();
625 EP1_IN_Callback (void)
628 if (main_thread->p_state == THD_STATE_SUSPENDED)
630 main_thread->p_u.rdymsg = RDY_OK;
631 chSchReadyI (main_thread);
633 chSysUnlockFromIsr ();
637 EP2_IN_Callback (void)
642 EP3_OUT_Callback (void)
644 usb_lld_rx_enable (ENDP3);
647 static WORKING_AREA(wa_led, 64);
649 #define LED_ONESHOT_SHORT ((eventmask_t)1)
650 #define LED_TWOSHOTS ((eventmask_t)2)
651 #define LED_ONESHOT_LONG ((eventmask_t)4)
652 static Thread *led_thread;
655 * LED blinker: When notified, let LED emit for 100ms.
657 static msg_t led_blinker (void *arg)
661 led_thread = chThdSelf ();
668 m = chEvtWaitOne (ALL_EVENTS);
669 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
673 if (m == LED_ONESHOT_SHORT)
674 chThdSleepMilliseconds (100);
675 else if (m == LED_TWOSHOTS)
677 chThdSleepMilliseconds (50);
679 chThdSleepMilliseconds (50);
681 chThdSleepMilliseconds (50);
684 chThdSleepMilliseconds (250);
691 #define RANDOM_BYTES_LENGTH 64
692 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
697 * NOTE: the main function is already a thread in the system on entry.
700 main (int argc, char **argv)
705 fill_serial_no_by_unique_id ();
711 main_thread = chThdSelf ();
713 chThdCreateStatic (wa_led, sizeof (wa_led), NORMALPRIO, led_blinker, NULL);
715 neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
717 usb_lld_init (config_desc.Descriptor[7]);
721 unsigned int count = 0;
722 int last_was_fullsizepacket = 0;
724 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
727 while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
729 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
735 if ((count & 0x0007) == 0)
736 chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
737 chThdSleepMilliseconds (25);
742 while (connected == 0)
744 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
748 chEvtSignalFlags (led_thread, LED_TWOSHOTS);
749 chThdSleepMilliseconds (5000);
752 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
755 /* The connection opened. */
758 * No parity is standard. It means to provide conditioned output.
759 * When parity enabled, it means to provide raw output.
761 neug_mode_select (line_coding.paritytype); /* 0: None, 1: Odd, 2: Even */
767 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
770 if (bDeviceState != CONFIGURED)
773 if ((count & 0x03ff) == 0)
774 chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
776 for (i = 0; i < 64/4; i++)
780 if (neug_get_nonblock (&v) < 0)
783 usb_lld_txcpy (&v, ENDP1, i * 4, 4);
786 if (i == 0 && !last_was_fullsizepacket)
787 { /* Only send ZLP when the last packet was fullsize. */
788 chThdSleepMicroseconds (250);
793 last_was_fullsizepacket = 1;
795 last_was_fullsizepacket = 0;
801 goto waiting_connection;
805 usb_lld_tx_enable (ENDP1, i * 4);
806 chSchGoSleepS (THD_STATE_SUSPENDED);
814 chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
815 chThdWait (led_thread);
818 * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED.
822 fsij_device_state = FSIJ_DEVICE_EXITED;
824 while (fsij_device_state == FSIJ_DEVICE_EXITED)
825 chThdSleepMilliseconds (500);
827 flash_unlock (); /* Flash unlock should be done here */
830 /* Disable SysTick */
832 /* Disable all interrupts */
835 SCB->VTOR = (uint32_t)&_regnual_start;
837 #define FLASH_SYS_START_ADDR 0x08000000
838 #define FLASH_SYS_END_ADDR (0x08000000+0x1000)
842 handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
843 void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[10];
846 for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
847 addr += FLASH_PAGE_SIZE)
848 flash_erase_page (addr);
850 /* copy system service routines */
851 flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
853 /* Leave NeuG to exec reGNUal */
854 (*func) (*((void (**)(void))(&_regnual_start+4)));
858 /* Leave NeuG to exec reGNUal */
859 flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4)));