2 * main.c - main routine of neug
5 * Copyright (C) 2011, 2012, 2013 Free Software Initiative of Japan
6 * Author: NIIBE Yutaka <gniibe@fsij.org>
8 * This file is a part of NeuG, a True 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/>.
35 #include "stm32f103.h"
39 FSIJ_DEVICE_RUNNING = 0,
41 FSIJ_DEVICE_EXEC_REQUESTED,
43 FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255
46 #ifdef FRAUCHEKY_SUPPORT
47 static uint8_t running_neug;
50 static chopstx_mutex_t usb_mtx;
51 static chopstx_cond_t cnd_usb;
52 static uint32_t bDeviceState = UNCONNECTED; /* USB device status */
53 static uint8_t fsij_device_state = FSIJ_DEVICE_RUNNING;
54 static uint8_t connected;
55 static uint32_t wait_usb_connection; /* Timer variable. */
58 extern uint8_t __process0_stack_end__;
59 static chopstx_t main_thd = (uint32_t)(&__process0_stack_end__ - 60);
61 #define ENDP0_RXADDR (0x40)
62 #define ENDP0_TXADDR (0x80)
63 #define ENDP1_TXADDR (0xc0)
64 #define ENDP2_TXADDR (0x100)
65 #define ENDP3_RXADDR (0x140)
67 #define USB_CDC_REQ_SET_LINE_CODING 0x20
68 #define USB_CDC_REQ_GET_LINE_CODING 0x21
69 #define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
70 #define USB_CDC_REQ_SEND_BREAK 0x23
72 /* USB Device Descriptor */
73 static const uint8_t vcom_device_desc[18] = {
75 USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
76 0x10, 0x01, /* bcdUSB = 1.1 */
77 0x02, /* bDeviceClass (CDC). */
78 0x00, /* bDeviceSubClass. */
79 0x00, /* bDeviceProtocol. */
80 0x40, /* bMaxPacketSize. */
81 #include "usb-vid-pid-ver.c.inc"
82 1, /* iManufacturer. */
84 3, /* iSerialNumber. */
85 1 /* bNumConfigurations. */
88 /* Configuration Descriptor tree for a CDC.*/
89 static const uint8_t vcom_configuration_desc[67] = {
91 USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
92 /* Configuration Descriptor.*/
93 67, 0x00, /* wTotalLength. */
94 0x02, /* bNumInterfaces. */
95 0x01, /* bConfigurationValue. */
96 0, /* iConfiguration. */
97 0x80, /* bmAttributes (bus powered). */
98 50, /* bMaxPower (100mA). */
99 /* Interface Descriptor.*/
101 USB_INTERFACE_DESCRIPTOR_TYPE,
102 0x00, /* bInterfaceNumber. */
103 0x00, /* bAlternateSetting. */
104 0x01, /* bNumEndpoints. */
105 0x02, /* bInterfaceClass (Communications Interface Class,
107 0x02, /* bInterfaceSubClass (Abstract Control Model, CDC
109 0x01, /* bInterfaceProtocol (AT commands, CDC section
112 /* Header Functional Descriptor (CDC section 5.2.3).*/
114 0x24, /* bDescriptorType (CS_INTERFACE). */
115 0x00, /* bDescriptorSubtype (Header Functional Descriptor). */
116 0x10, 0x01, /* bcdCDC. */
117 /* Call Management Functional Descriptor. */
118 5, /* bFunctionLength. */
119 0x24, /* bDescriptorType (CS_INTERFACE). */
120 0x01, /* bDescriptorSubtype (Call Management Functional
122 0x03, /* bmCapabilities (D0+D1). */
123 0x01, /* bDataInterface. */
124 /* ACM Functional Descriptor.*/
125 4, /* bFunctionLength. */
126 0x24, /* bDescriptorType (CS_INTERFACE). */
127 0x02, /* bDescriptorSubtype (Abstract Control Management
129 0x02, /* bmCapabilities. */
130 /* Union Functional Descriptor.*/
131 5, /* bFunctionLength. */
132 0x24, /* bDescriptorType (CS_INTERFACE). */
133 0x06, /* bDescriptorSubtype (Union Functional
135 0x00, /* bMasterInterface (Communication Class
137 0x01, /* bSlaveInterface0 (Data Class Interface). */
138 /* Endpoint 2 Descriptor.*/
140 USB_ENDPOINT_DESCRIPTOR_TYPE,
141 ENDP2|0x80, /* bEndpointAddress. */
142 0x03, /* bmAttributes (Interrupt). */
143 0x08, 0x00, /* wMaxPacketSize. */
144 0xFF, /* bInterval. */
145 /* Interface Descriptor.*/
147 USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
148 0x01, /* bInterfaceNumber. */
149 0x00, /* bAlternateSetting. */
150 0x02, /* bNumEndpoints. */
151 0x0A, /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
152 0x00, /* bInterfaceSubClass (CDC section 4.6). */
153 0x00, /* bInterfaceProtocol (CDC section 4.7). */
154 0x00, /* iInterface. */
155 /* Endpoint 3 Descriptor.*/
157 USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
158 ENDP3, /* bEndpointAddress. */
159 0x02, /* bmAttributes (Bulk). */
160 0x40, 0x00, /* wMaxPacketSize. */
161 0x00, /* bInterval. */
162 /* Endpoint 1 Descriptor.*/
164 USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
165 ENDP1|0x80, /* bEndpointAddress. */
166 0x02, /* bmAttributes (Bulk). */
167 0x40, 0x00, /* wMaxPacketSize. */
168 0x00 /* bInterval. */
173 * U.S. English language identifier.
175 static const uint8_t vcom_string0[4] = {
177 USB_STRING_DESCRIPTOR_TYPE,
178 0x09, 0x04 /* LangID = 0x0409: US-English */
181 #include "usb-strings.c.inc"
183 #ifdef FRAUCHEKY_SUPPORT
184 extern int fraucheky_enabled (void);
185 extern void fraucheky_main (void);
187 extern void fraucheky_setup_endpoints_for_interface (int stop);
188 extern int fraucheky_setup (uint8_t req, uint8_t req_no, uint16_t value,
190 extern int fraucheky_get_descriptor (uint8_t rcp, uint8_t desc_type,
191 uint8_t desc_index, uint16_t index);
194 #define NUM_INTERFACES 2
197 usb_cb_device_reset (void)
199 /* Set DEVICE as not configured */
200 usb_lld_set_configuration (0);
202 /* Current Feature initialization */
203 usb_lld_set_feature (vcom_configuration_desc[7]);
207 /* Initialize Endpoint 0 */
208 usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
211 extern uint8_t _regnual_start, __heap_end__;
213 static const uint8_t *const mem_info[] = { &_regnual_start, &__heap_end__, };
215 /* USB vendor requests to control pipe */
216 #define USB_FSIJ_MEMINFO 0
217 #define USB_FSIJ_DOWNLOAD 1
218 #define USB_FSIJ_EXEC 2
219 #define USB_NEUG_SET_PASSWD 253
220 #define USB_NEUG_GET_INFO 254
221 #define USB_NEUG_EXIT 255 /* Ask to exit and to receive reGNUal */
223 uint8_t neug_passwd[33] __attribute__ ((section(".passwd"))) = {
225 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
226 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
227 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
229 static uint8_t passwd_data[33];
231 #define DEFAULT_PASSWD "12345678"
232 #define DEFAULT_PASSWD_LEN 8
234 static void set_passwd (void)
237 if (neug_passwd[0] != 0xff)
238 flash_erase_page ((uint32_t)neug_passwd);
239 if (passwd_data[0] == DEFAULT_PASSWD_LEN
240 && !memcmp (passwd_data + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
242 flash_write ((uint32_t)neug_passwd, passwd_data, passwd_data[0] + 1);
245 static uint32_t rbit (uint32_t v)
249 asm ("rbit %0, %1" : "=r" (r) : "r" (v));
253 /* After calling this function, CRC module remain enabled. */
254 static int download_check_crc32 (const uint32_t *end_p)
256 uint32_t crc32 = *end_p;
259 RCC->AHBENR |= RCC_AHBENR_CRCEN;
260 CRC->CR = CRC_CR_RESET;
262 for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
265 if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
268 return USB_UNSUPPORT;
272 usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
273 uint16_t index, uint16_t len)
275 uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
277 if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
279 if (req_no == USB_FSIJ_EXEC && len == 0)
281 chopstx_mutex_lock (&usb_mtx);
282 if (fsij_device_state == FSIJ_DEVICE_EXITED)
284 usb_lld_prepare_shutdown (); /* No further USB communication */
285 fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED;
287 chopstx_mutex_unlock (&usb_mtx);
289 else if (req_no == USB_NEUG_SET_PASSWD)
291 else if (req_no == USB_NEUG_EXIT)
293 if ((neug_passwd[0] == 0xff && passwd_data[0] == DEFAULT_PASSWD_LEN
294 && !memcmp (passwd_data + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
295 || (neug_passwd[0] == passwd_data[0]
296 && !memcmp (neug_passwd+1, passwd_data+1, neug_passwd[0])))
298 chopstx_mutex_lock (&usb_mtx);
299 fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
300 chopstx_wakeup_usec_wait (main_thd);
301 chopstx_cond_signal (&cnd_usb);
302 chopstx_mutex_unlock (&usb_mtx);
306 else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
307 && index == 0 && USB_SETUP_SET (req)
308 && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
310 /* Open/close the connection. */
311 chopstx_mutex_lock (&usb_mtx);
312 connected = (value != 0)? 1 : 0;
313 if (wait_usb_connection)
314 { /* It is waiting a connection. */
315 if (connected) /* It's now connected. */
316 chopstx_wakeup_usec_wait (main_thd);
319 chopstx_cond_signal (&cnd_usb);
320 chopstx_mutex_unlock (&usb_mtx);
330 } __attribute__((packed));
332 static struct line_coding line_coding = {
333 115200, /* baud rate: 115200 */
334 0x00, /* stop bits: 1 */
335 0x00, /* parity: none */
341 vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value,
345 if (USB_SETUP_GET (req))
347 if (req_no == USB_CDC_REQ_GET_LINE_CODING
348 && len == sizeof (line_coding))
350 usb_lld_set_data_to_send (&line_coding, sizeof (line_coding));
354 else /* USB_SETUP_SET (req) */
356 if (req_no == USB_CDC_REQ_SET_LINE_CODING
357 && len == sizeof (line_coding))
359 usb_lld_set_data_to_recv (&line_coding, sizeof (line_coding));
362 else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
366 return USB_UNSUPPORT;
370 usb_cb_setup (uint8_t req, uint8_t req_no,
371 uint16_t value, uint16_t index, uint16_t len)
373 uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
375 if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
377 if (USB_SETUP_GET (req))
379 if (req_no == USB_FSIJ_MEMINFO)
381 chopstx_mutex_lock (&usb_mtx);
382 if (fsij_device_state != FSIJ_DEVICE_EXITED)
384 chopstx_mutex_unlock (&usb_mtx);
385 return USB_UNSUPPORT;
387 chopstx_mutex_unlock (&usb_mtx);
388 usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
391 else if (req_no == USB_NEUG_GET_INFO)
394 usb_lld_set_data_to_send (&neug_mode, sizeof (uint8_t));
396 usb_lld_set_data_to_send (&neug_err_cnt, sizeof (uint16_t));
398 usb_lld_set_data_to_send (&neug_err_cnt_rc, sizeof (uint16_t));
400 usb_lld_set_data_to_send (&neug_err_cnt_p64, sizeof (uint16_t));
402 usb_lld_set_data_to_send (&neug_err_cnt_p4k, sizeof (uint16_t));
404 usb_lld_set_data_to_send (&neug_rc_max, sizeof (uint16_t));
406 usb_lld_set_data_to_send (&neug_p64_max, sizeof (uint16_t));
408 usb_lld_set_data_to_send (&neug_p4k_max, sizeof (uint16_t));
410 return USB_UNSUPPORT;
417 uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
419 if (req_no == USB_FSIJ_DOWNLOAD)
421 chopstx_mutex_lock (&usb_mtx);
422 if (fsij_device_state != FSIJ_DEVICE_EXITED)
424 chopstx_mutex_unlock (&usb_mtx);
425 return USB_UNSUPPORT;
427 chopstx_mutex_unlock (&usb_mtx);
429 if (addr < &_regnual_start || addr + len > &__heap_end__)
430 return USB_UNSUPPORT;
432 if (index + len < 256)
433 memset (addr + index + len, 0, 256 - (index + len));
435 usb_lld_set_data_to_recv (addr, len);
438 else if (req_no == USB_FSIJ_EXEC && len == 0)
440 chopstx_mutex_lock (&usb_mtx);
441 if (fsij_device_state != FSIJ_DEVICE_EXITED)
443 chopstx_mutex_unlock (&usb_mtx);
444 return USB_UNSUPPORT;
446 chopstx_mutex_unlock (&usb_mtx);
448 if (((uint32_t)addr & 0x03))
449 return USB_UNSUPPORT;
451 return download_check_crc32 ((uint32_t *)addr);
453 else if (req_no == USB_NEUG_SET_PASSWD && len <= 32)
455 passwd_data[0] = len;
456 usb_lld_set_data_to_recv (passwd_data + 1, len);
459 else if (req_no == USB_NEUG_EXIT && len <= 32)
461 chopstx_mutex_lock (&usb_mtx);
462 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
464 chopstx_mutex_unlock (&usb_mtx);
465 return USB_UNSUPPORT;
467 chopstx_mutex_unlock (&usb_mtx);
469 passwd_data[0] = len;
470 usb_lld_set_data_to_recv (passwd_data + 1, len);
475 else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
479 #ifdef FRAUCHEKY_SUPPORT
481 return vcom_port_data_setup (req, req_no, value, len);
483 fraucheky_setup (req, req_no, value, len);
485 return vcom_port_data_setup (req, req_no, value, len);
490 return USB_UNSUPPORT;
494 usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
497 #ifdef FRAUCHEKY_SUPPORT
499 return fraucheky_get_descriptor (rcp, desc_type, desc_index, index);
504 if (rcp != DEVICE_RECIPIENT)
505 return USB_UNSUPPORT;
507 if (desc_type == DEVICE_DESCRIPTOR)
509 usb_lld_set_data_to_send (vcom_device_desc, sizeof (vcom_device_desc));
512 else if (desc_type == CONFIG_DESCRIPTOR)
514 usb_lld_set_data_to_send (vcom_configuration_desc,
515 sizeof (vcom_configuration_desc));
518 else if (desc_type == STRING_DESCRIPTOR)
527 size = sizeof (vcom_string0);
530 str = neug_string_vendor;
531 size = sizeof (neug_string_vendor);
534 str = neug_string_product;
535 size = sizeof (neug_string_product);
538 str = neug_string_serial;
539 size = sizeof (neug_string_serial);
542 str = neug_revision_detail;
543 size = sizeof (neug_revision_detail);
546 str = neug_config_options;
547 size = sizeof (neug_config_options);
551 size = sizeof (sys_version);
554 return USB_UNSUPPORT;
557 usb_lld_set_data_to_send (str, size);
561 return USB_UNSUPPORT;
565 neug_setup_endpoints_for_interface (uint16_t interface, int stop)
569 #ifdef FRAUCHEKY_SUPPORT
573 usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
575 usb_lld_stall_tx (ENDP2);
578 fraucheky_setup_endpoints_for_interface (stop);
581 usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
583 usb_lld_stall_tx (ENDP2);
586 else if (interface == 1)
590 usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
591 usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
595 usb_lld_stall_tx (ENDP1);
596 usb_lld_stall_rx (ENDP3);
601 int usb_cb_handle_event (uint8_t event_type, uint16_t value)
604 uint8_t current_conf;
608 case USB_EVENT_ADDRESS:
609 chopstx_mutex_lock (&usb_mtx);
610 bDeviceState = ADDRESSED;
611 chopstx_mutex_unlock (&usb_mtx);
613 case USB_EVENT_CONFIG:
614 current_conf = usb_lld_current_configuration ();
615 if (current_conf == 0)
618 return USB_UNSUPPORT;
620 usb_lld_set_configuration (1);
621 for (i = 0; i < NUM_INTERFACES; i++)
622 neug_setup_endpoints_for_interface (i, 0);
623 chopstx_mutex_lock (&usb_mtx);
624 bDeviceState = CONFIGURED;
625 chopstx_mutex_unlock (&usb_mtx);
627 else if (current_conf != value)
630 return USB_UNSUPPORT;
632 usb_lld_set_configuration (0);
633 for (i = 0; i < NUM_INTERFACES; i++)
634 neug_setup_endpoints_for_interface (i, 1);
635 chopstx_mutex_lock (&usb_mtx);
636 bDeviceState = ADDRESSED;
637 chopstx_mutex_unlock (&usb_mtx);
639 /* Do nothing when current_conf == value */
647 return USB_UNSUPPORT;
651 int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
653 static uint8_t zero = 0;
655 if (interface >= NUM_INTERFACES)
656 return USB_UNSUPPORT;
660 case USB_SET_INTERFACE:
662 return USB_UNSUPPORT;
665 neug_setup_endpoints_for_interface (interface, 0);
669 case USB_GET_INTERFACE:
670 usb_lld_set_data_to_send (&zero, 1);
674 case USB_QUERY_INTERFACE:
679 #define INTR_REQ_USB 20
685 chopstx_intr_t interrupt;
688 usb_lld_init (vcom_configuration_desc[7]);
689 chopstx_claim_irq (&interrupt, INTR_REQ_USB);
690 usb_interrupt_handler ();
694 chopstx_intr_wait (&interrupt);
696 /* Process interrupt. */
697 usb_interrupt_handler ();
703 #define ID_OFFSET (2+SERIALNO_STR_LEN*2)
704 static void fill_serial_no_by_unique_id (void)
706 extern const uint8_t * unique_device_id (void);
707 uint8_t *p = &neug_string_serial[ID_OFFSET];
708 const uint8_t *u = unique_device_id () + 8;
711 for (i = 0; i < 4; i++)
717 nibble += (nibble >= 10 ? ('A' - 10) : '0');
721 nibble += (nibble >= 10 ? ('A' - 10) : '0');
728 EP1_IN_Callback (void)
730 chopstx_mutex_lock (&usb_mtx);
731 chopstx_cond_signal (&cnd_usb);
732 chopstx_mutex_unlock (&usb_mtx);
736 EP2_IN_Callback (void)
741 EP3_OUT_Callback (void)
743 usb_lld_rx_enable (ENDP3);
746 typedef uint32_t eventmask_t;
747 #define ALL_EVENTS (~0)
750 chopstx_mutex_t mutex;
755 static void event_flag_init (struct event_flag *ev)
758 chopstx_mutex_init (&ev->mutex);
759 chopstx_cond_init (&ev->cond);
763 static eventmask_t event_flag_waitone (struct event_flag *ev, eventmask_t m)
767 chopstx_mutex_lock (&ev->mutex);
768 while (!(ev->flag & m))
769 chopstx_cond_wait (&ev->cond, &ev->mutex);
771 n = __builtin_ffs ((ev->flag & m));
772 ev->flag &= ~(1 << (n - 1));
773 chopstx_mutex_unlock (&ev->mutex);
775 return (1 << (n - 1));
778 static void event_flag_signal (struct event_flag *ev, eventmask_t m)
780 chopstx_mutex_lock (&ev->mutex);
782 chopstx_cond_signal (&ev->cond);
783 chopstx_mutex_unlock (&ev->mutex);
786 extern uint8_t __process1_stack_base__, __process1_stack_size__;
787 extern uint8_t __process3_stack_base__, __process3_stack_size__;
789 const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
790 const size_t __stacksize_led = (size_t)&__process1_stack_size__;
791 const uint32_t __stackaddr_usb = (uint32_t)&__process3_stack_base__;
792 const size_t __stacksize_usb = (size_t)&__process3_stack_size__;
796 static struct event_flag led_event;
798 #define LED_ONESHOT_SHORT ((eventmask_t)1)
799 #define LED_TWOSHOTS ((eventmask_t)2)
800 #define LED_ONESHOT_LONG ((eventmask_t)4)
803 * LED blinker: When notified, let LED emit for 100ms.
806 led_blinker (void *arg)
816 m = event_flag_waitone (&led_event, ALL_EVENTS);
817 if (fsij_device_state != FSIJ_DEVICE_RUNNING) /* No usb_mtx lock. */
821 if (m == LED_ONESHOT_SHORT)
822 chopstx_usec_wait (100*1000);
823 else if (m == LED_TWOSHOTS)
825 chopstx_usec_wait (50*1000);
827 chopstx_usec_wait (50*1000);
829 chopstx_usec_wait (50*1000);
832 chopstx_usec_wait (250*1000);
839 #define RANDOM_BYTES_LENGTH 64
840 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
842 static void copy_to_tx (uint32_t v, int i)
844 usb_lld_txcpy (&v, ENDP1, i * 4, 4);
848 * In Gnuk 1.0.[12], reGNUal was not relocatable.
849 * Now, it's relocatable, but we need to calculate its entry address
850 * based on it's pre-defined address.
852 #define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
854 calculate_regnual_entry_address (const uint8_t *addr)
856 const uint8_t *p = addr + 4;
857 uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
859 v -= REGNUAL_START_ADDRESS_COMPATIBLE;
868 * NOTE: the main function is already a thread in the system on entry.
871 main (int argc, char **argv)
874 chopstx_t led_thread, usb_thd;
880 fill_serial_no_by_unique_id ();
884 event_flag_init (&led_event);
886 chopstx_mutex_init (&usb_mtx);
887 chopstx_cond_init (&cnd_usb);
889 led_thread = chopstx_create (PRIO_LED, __stackaddr_led, __stacksize_led,
892 #ifdef FRAUCHEKY_SUPPORT
893 if (fraucheky_enabled ())
895 usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
898 chopstx_cancel (usb_thd);
899 chopstx_join (usb_thd, NULL);
906 usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
909 neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
911 chopstx_mutex_lock (&usb_mtx);
916 while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
918 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
921 chopstx_mutex_unlock (&usb_mtx);
925 if ((count & 0x0007) == 0)
926 event_flag_signal (&led_event, LED_ONESHOT_SHORT);
927 chopstx_usec_wait (25*1000);
929 chopstx_mutex_lock (&usb_mtx);
932 /* Holding USB_MTX. */
935 int last_was_fullsizepacket = 0;
937 if (fsij_device_state != FSIJ_DEVICE_RUNNING)
942 wait_usb_connection = 5000*1000;
943 if (connected || bDeviceState != CONFIGURED
944 || fsij_device_state != FSIJ_DEVICE_RUNNING)
947 chopstx_mutex_unlock (&usb_mtx);
949 neug_mode_select (line_coding.paritytype);
950 event_flag_signal (&led_event, LED_TWOSHOTS);
951 chopstx_usec_wait_var (&wait_usb_connection);
952 chopstx_mutex_lock (&usb_mtx);
955 if (bDeviceState != CONFIGURED)
958 /* The connection opened. */
965 chopstx_mutex_unlock (&usb_mtx);
967 * No parity is standard. It means providing conditioned output.
968 * When parity enabled, it means to provide raw output
969 * (CRC32 filtered when odd, direct sample of ADC when even).
971 * line_coding.paritytype:
972 * 0: None, 1: Odd, 2: Even
974 neug_mode_select (line_coding.paritytype);
976 if ((count & 0x03ff) == 0)
977 event_flag_signal (&led_event, LED_ONESHOT_SHORT);
979 i = neug_consume_random (copy_to_tx);
981 if (i == 0 && !last_was_fullsizepacket)
982 { /* Only send ZLP when the last packet was fullsize. */
985 chopstx_mutex_lock (&usb_mtx);
986 if (bDeviceState != CONFIGURED || !connected
987 || fsij_device_state != FSIJ_DEVICE_RUNNING)
993 last_was_fullsizepacket = 1;
995 last_was_fullsizepacket = 0;
997 chopstx_mutex_lock (&usb_mtx);
998 if (bDeviceState != CONFIGURED || !connected
999 || fsij_device_state != FSIJ_DEVICE_RUNNING)
1002 /* Prepare sending random data. */
1003 usb_lld_tx_enable (ENDP1, i * 4);
1004 chopstx_cond_wait (&cnd_usb, &usb_mtx);
1010 chopstx_mutex_unlock (&usb_mtx);
1012 chopstx_cancel (led_thread);
1013 chopstx_join (led_thread, NULL);
1016 * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED.
1020 chopstx_mutex_lock (&usb_mtx);
1021 fsij_device_state = FSIJ_DEVICE_EXITED;
1023 while (fsij_device_state == FSIJ_DEVICE_EXITED)
1025 chopstx_mutex_unlock (&usb_mtx);
1026 chopstx_usec_wait (500*1000);
1027 chopstx_mutex_lock (&usb_mtx);
1029 chopstx_mutex_unlock (&usb_mtx);
1031 flash_unlock (); /* Flash unlock should be done here */
1033 usb_lld_shutdown ();
1035 /* Finish application. */
1036 chopstx_cancel (usb_thd);
1037 chopstx_join (usb_thd, NULL);
1040 SCB->VTOR = (uint32_t)&_regnual_start;
1041 entry = calculate_regnual_entry_address (&_regnual_start);
1043 #define FLASH_SYS_START_ADDR 0x08000000
1044 #define FLASH_SYS_END_ADDR (0x08000000+0x1000)
1046 extern uint8_t _sys;
1048 handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
1049 void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[9];
1052 for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
1053 addr += FLASH_PAGE_SIZE)
1054 flash_erase_page (addr);
1056 /* copy system service routines */
1057 flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
1059 /* Leave NeuG to exec reGNUal */
1060 (*func) ((void (*)(void))entry);
1064 /* Leave NeuG to exec reGNUal */
1065 flash_erase_all_and_exec ((void (*)(void))entry);