Newer Chopstx
[gnuk/neug.git] / src / main.c
index 8a7dec1..f3248c4 100644 (file)
@@ -2,10 +2,10 @@
  * main.c - main routine of neug
  *
  * Main routine:
- * Copyright (C) 2011, 2012 Free Software Initiative of Japan
+ * Copyright (C) 2011, 2012, 2013 Free Software Initiative of Japan
  * Author: NIIBE Yutaka <gniibe@fsij.org>
  *
- * This file is a part of NeuG, a Random Number Generator
+ * This file is a part of NeuG, a True Random Number Generator
  * implementation.
  *
  * NeuG is free software: you can redistribute it and/or modify it
  *
  */
 
+
+#include <stdint.h>
+#include <string.h>
+#include <chopstx.h>
+
 #include "config.h"
-#include "ch.h"
-#include "hal.h"
-#include "board.h"
 #include "neug.h"
 #include "usb_lld.h"
 #include "sys.h"
+#include "stm32f103.h"
 #include "adc.h"
 
-/*
- * We are trying to avoid dependency to C library. 
- * GCC built-in function(s) are declared here.
- */
-extern void *memcpy(void *dest, const void *src, size_t n);
-extern void *memset (void *s, int c, size_t n);
+chopstx_mutex_t usb_mtx;
+chopstx_cond_t cnd_usb;
 
-static Thread *main_thread = NULL;
+extern uint8_t __process0_stack_end__;
+static chopstx_t main_thd = (uint32_t)(&__process0_stack_end__ - 60);
 
-\f
 #define ENDP0_RXADDR        (0x40)
 #define ENDP0_TXADDR        (0x80)
 #define ENDP1_TXADDR        (0xc0)
@@ -171,7 +170,7 @@ static const uint8_t vcom_string0[4] = {
 static uint8_t vcom_string3[28] = {
   28,                    /* bLength.                         */
   USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType.                 */
-  '0', 0,  '.', 0,  '0', 0, '2', 0,    /* Version number of NeuG.          */
+  '0', 0,  '.', 0,  '0', 0, '6', 0,    /* Version number of NeuG.          */
   '-', 0,
   0, 0, 0, 0,  /* Filled by Unique device ID.      */
   0, 0, 0, 0,
@@ -179,43 +178,19 @@ static uint8_t vcom_string3[28] = {
   0, 0, 0, 0,
 };
 
-static const struct Descriptor device_desc = {
-  vcom_device_desc,
-  sizeof (vcom_device_desc)
-};
-
-static const struct Descriptor config_desc = {
-  vcom_configuration_desc,
-  sizeof (vcom_configuration_desc)
-};
-
-static const struct Descriptor string_descs[] = {
-  {vcom_string0, sizeof vcom_string0},
-  {neug_string_vendor, sizeof (neug_string_vendor)},
-  {neug_string_product, sizeof (neug_string_product)},
-  {vcom_string3, sizeof (vcom_string3)},
-  {neug_revision_detail, sizeof (neug_revision_detail)},
-  {neug_config_options, sizeof (neug_config_options)},
-  {sys_version, sizeof (sys_version)},
-};
-
-#define NUM_STRING_DESC (sizeof (string_descs)/sizeof (struct Descriptor))
 
 #define NUM_INTERFACES 2
 
 uint32_t bDeviceState = UNCONNECTED; /* USB device status */
 
-#define NEUG_WAIT_FOR_TX_READY 1
-static uint8_t neug_state;
-
-static void
-neug_device_reset (void)
+void
+usb_cb_device_reset (void)
 {
   /* Set DEVICE as not configured */
   usb_lld_set_configuration (0);
 
   /* Current Feature initialization */
-  usb_lld_set_feature (config_desc.Descriptor[7]);
+  usb_lld_set_feature (vcom_configuration_desc[7]);
 
   usb_lld_reset ();
 
@@ -231,7 +206,7 @@ static const uint8_t *const mem_info[] = { &_regnual_start,  &__heap_end__, };
 #define USB_FSIJ_MEMINFO         0
 #define USB_FSIJ_DOWNLOAD        1
 #define USB_FSIJ_EXEC            2
-#define USB_NEUG_GET_ERR_COUNT 254
+#define USB_NEUG_GET_INFO      254
 #define USB_NEUG_EXIT          255 /* Ask to exit and to receive reGNUal */
 
 enum {
@@ -270,9 +245,9 @@ static int download_check_crc32 (const uint32_t *end_p)
   return USB_UNSUPPORT;
 }
 
-static void neug_ctrl_write_finish (uint8_t req, uint8_t req_no,
-                                   uint16_t value, uint16_t index,
-                                   uint16_t len)
+void
+usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
+                         uint16_t index, uint16_t len)
 {
   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
 
@@ -290,15 +265,10 @@ static void neug_ctrl_write_finish (uint8_t req, uint8_t req_no,
        }
       else if (req_no == USB_NEUG_EXIT)
        {
-         chSysLockFromIsr ();
-         if (neug_state == NEUG_WAIT_FOR_TX_READY)
-           {
-             main_thread->p_u.rdymsg = RDY_OK;
-             chSchReadyI (main_thread);
-           }
-         else
-           chEvtSignalFlagsI (main_thread, 1);
-         chSysUnlockFromIsr ();
+         /* Force exit from the main loop.  */
+         chopstx_mutex_lock (&usb_mtx);
+         chopstx_cond_signal (&cnd_usb);
+         chopstx_mutex_unlock (&usb_mtx);
        }
     }
 }
@@ -340,6 +310,8 @@ vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value)
        }
       else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
        {
+         uint8_t connected_saved = connected;
+
          if (value != 0)
            {
              if (connected == 0)
@@ -349,19 +321,15 @@ vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value)
          else
            {
              if (connected)
-               {
-                 /* Close call */
-                 connected = 0;
-                 chSysLockFromIsr ();
-                 if (neug_state == NEUG_WAIT_FOR_TX_READY)
-                   {
-                     main_thread->p_u.rdymsg = RDY_OK;
-                     chSchReadyI (main_thread);
-                   }
-                 chSysUnlockFromIsr ();
-               }
+               /* Close call */
+               connected = 0;
            }
 
+         chopstx_mutex_lock (&usb_mtx);
+         if (connected != connected_saved)
+           chopstx_cond_signal (&cnd_usb);
+         chopstx_mutex_unlock (&usb_mtx);
+
          return USB_SUCCESS;
        }
     }
@@ -369,8 +337,8 @@ vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value)
   return USB_UNSUPPORT;
 }
 
-static int
-neug_setup (uint8_t req, uint8_t req_no,
+int
+usb_cb_setup (uint8_t req, uint8_t req_no,
               uint16_t value, uint16_t index, uint16_t len)
 {
   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
@@ -384,11 +352,27 @@ neug_setup (uint8_t req, uint8_t req_no,
              usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
              return USB_SUCCESS;
            }
-         else if (req_no == USB_NEUG_GET_ERR_COUNT)
+         else if (req_no == USB_NEUG_GET_INFO)
            {
-             extern uint16_t neug_err_count;
+             if (index == 0)
+               usb_lld_set_data_to_send (&neug_mode, sizeof (uint8_t));
+             else if (index == 1)
+               usb_lld_set_data_to_send (&neug_err_cnt, sizeof (uint16_t));
+             else if (index == 2)
+               usb_lld_set_data_to_send (&neug_err_cnt_rc, sizeof (uint16_t));
+             else if (index == 3)
+               usb_lld_set_data_to_send (&neug_err_cnt_p64, sizeof (uint16_t));
+             else if (index == 4)
+               usb_lld_set_data_to_send (&neug_err_cnt_p4k, sizeof (uint16_t));
+             else if (index == 5)
+               usb_lld_set_data_to_send (&neug_rc_max, sizeof (uint16_t));
+             else if (index == 6)
+               usb_lld_set_data_to_send (&neug_p64_max, sizeof (uint16_t));
+             else if (index == 7)
+               usb_lld_set_data_to_send (&neug_p4k_max, sizeof (uint16_t));
+             else
+               return USB_UNSUPPORT;
 
-             usb_lld_set_data_to_send (&neug_err_count, sizeof (uint16_t));
              return USB_SUCCESS;
            }
        }
@@ -426,6 +410,8 @@ neug_setup (uint8_t req, uint8_t req_no,
                return USB_UNSUPPORT;
 
              fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
+             chopstx_wakeup_usec_wait (main_thd);
+
              return USB_SUCCESS;
            }
        }
@@ -437,32 +423,63 @@ neug_setup (uint8_t req, uint8_t req_no,
   return USB_UNSUPPORT;
 }
 
-static int
-neug_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
+int
+usb_cb_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
 {
   (void)index;
   if (desc_type == DEVICE_DESCRIPTOR)
     {
-      usb_lld_set_data_to_send (device_desc.Descriptor,
-                               device_desc.Descriptor_Size);
+      usb_lld_set_data_to_send (vcom_device_desc, sizeof (vcom_device_desc));
       return USB_SUCCESS;
     }
   else if (desc_type == CONFIG_DESCRIPTOR)
     {
-      usb_lld_set_data_to_send (config_desc.Descriptor,
-                               config_desc.Descriptor_Size);
+      usb_lld_set_data_to_send (vcom_configuration_desc,
+                               sizeof (vcom_configuration_desc));
       return USB_SUCCESS;
     }
   else if (desc_type == STRING_DESCRIPTOR)
     {
       uint8_t desc_index = value & 0xff;
+      const uint8_t *str;
+      int size;
 
-      if (desc_index < NUM_STRING_DESC)
+      switch (desc_index)
        {
-         usb_lld_set_data_to_send (string_descs[desc_index].Descriptor,
-                                   string_descs[desc_index].Descriptor_Size);
-         return USB_SUCCESS;
+       case 0:
+         str = vcom_string0;
+         size = sizeof (vcom_string0);
+         break;
+       case 1:
+         str = neug_string_vendor;
+         size = sizeof (neug_string_vendor);
+         break;
+       case 2:
+         str = neug_string_product;
+         size = sizeof (neug_string_product);
+         break;
+       case 3:
+         str = vcom_string3;
+         size = sizeof (vcom_string3);
+         break;
+       case 4:
+         str = neug_revision_detail;
+         size = sizeof (neug_revision_detail);
+         break;
+       case 5:
+         str = neug_config_options;
+         size = sizeof (neug_config_options);
+         break;
+       case 6:
+         str = sys_version;
+         size = sizeof (sys_version);
+         break;
+       default:
+         return USB_UNSUPPORT;
        }
+
+      usb_lld_set_data_to_send (str, size);
+      return USB_SUCCESS;
     }
 
   return USB_UNSUPPORT;
@@ -493,7 +510,7 @@ neug_setup_endpoints_for_interface (uint16_t interface, int stop)
     }
 }
 
-static int neug_usb_event (uint8_t event_type, uint16_t value)
+int usb_cb_handle_event (uint8_t event_type, uint16_t value)
 {
   int i;
   uint8_t current_conf;
@@ -537,7 +554,7 @@ static int neug_usb_event (uint8_t event_type, uint16_t value)
 }
 
 
-static int neug_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
+int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
 {
   static uint8_t zero = 0;
 
@@ -565,15 +582,29 @@ static int neug_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
     }
 }
 
-const struct usb_device_method Device_Method = {
-  neug_device_reset,
-  neug_ctrl_write_finish,
-  neug_setup,
-  neug_get_descriptor,
-  neug_usb_event,
-  neug_interface,
-};
+#define INTR_REQ_USB 20
+#define PRIO_USB 4
 
+static void *
+usb_intr (void *arg)
+{
+  chopstx_intr_t interrupt;
+
+  (void)arg;
+  usb_lld_init (vcom_configuration_desc[7]);
+  chopstx_claim_irq (&interrupt, INTR_REQ_USB);
+  usb_interrupt_handler ();
+
+  while (1)
+    {
+      chopstx_intr_wait (&interrupt);
+
+      /* Process interrupt. */
+      usb_interrupt_handler ();
+    }
+
+  return NULL;
+}
 
 
 static void fill_serial_no_by_unique_id (void)
@@ -597,27 +628,12 @@ static void fill_serial_no_by_unique_id (void)
     }
 }
 \f
-CH_IRQ_HANDLER (Vector90)
-{
-  CH_IRQ_PROLOGUE();
-  chSysLockFromIsr();
-
-  usb_interrupt_handler ();
-
-  chSysUnlockFromIsr();
-  CH_IRQ_EPILOGUE();
-}
-
 void
 EP1_IN_Callback (void)
 {
-  chSysLockFromIsr ();
-  if (main_thread != NULL && neug_state == NEUG_WAIT_FOR_TX_READY)
-    {
-      main_thread->p_u.rdymsg = RDY_OK;
-      chSchReadyI (main_thread);
-    }
-  chSysUnlockFromIsr ();
+  chopstx_mutex_lock (&usb_mtx);
+  chopstx_cond_signal (&cnd_usb);
+  chopstx_mutex_unlock (&usb_mtx);
 }
 
 void
@@ -631,53 +647,124 @@ EP3_OUT_Callback (void)
   usb_lld_rx_enable (ENDP3);
 }
 \f
-static WORKING_AREA(wa_led, 64);
+typedef uint32_t eventmask_t;
+#define ALL_EVENTS (~0)
+
+struct event_flag {
+  chopstx_mutex_t mutex;
+  chopstx_cond_t cond;
+  eventmask_t flag;
+};
+
+static void event_flag_init (struct event_flag *ev)
+{
+  ev->flag = 0;
+  chopstx_mutex_init (&ev->mutex);
+  chopstx_cond_init (&ev->cond);
+}
+
+
+static eventmask_t event_flag_waitone (struct event_flag *ev, eventmask_t m)
+{
+  int n;
+
+  chopstx_mutex_lock (&ev->mutex);
+  while (!(ev->flag & m))
+    chopstx_cond_wait (&ev->cond, &ev->mutex);
+
+  n = __builtin_ffs ((ev->flag & m));
+  ev->flag &= ~(1 << (n - 1));
+  chopstx_mutex_unlock (&ev->mutex);
+
+  return (1 << (n - 1));
+}
+
+static void event_flag_signal (struct event_flag *ev, eventmask_t m)
+{
+  chopstx_mutex_lock (&ev->mutex);
+  ev->flag |= m;
+  chopstx_cond_signal (&ev->cond);
+  chopstx_mutex_unlock (&ev->mutex);
+}
+
+extern uint8_t __process1_stack_base__, __process1_stack_size__;
+extern uint8_t __process3_stack_base__, __process3_stack_size__;
+
+const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
+const size_t __stacksize_led = (size_t)&__process1_stack_size__;
+const uint32_t __stackaddr_usb = (uint32_t)&__process3_stack_base__;
+const size_t __stacksize_usb = (size_t)&__process3_stack_size__;
+
+
+#define PRIO_LED 1
+struct event_flag led_event;
 
 #define LED_ONESHOT_SHORT      ((eventmask_t)1)
 #define LED_TWOSHOTS           ((eventmask_t)2)
 #define LED_ONESHOT_LONG       ((eventmask_t)4)
-static Thread *led_thread;
 
 /*
  * LED blinker: When notified, let LED emit for 100ms.
  */
-static msg_t led_blinker (void *arg)
+static void *led_blinker (void *arg)
 {
   (void)arg;
 
-  led_thread = chThdSelf ();
   set_led (0);
 
   while (1)
     {
       eventmask_t m;
 
-      m = chEvtWaitOne (ALL_EVENTS);
+      m = event_flag_waitone (&led_event, ALL_EVENTS);
       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
        break;
 
       set_led (1);
       if (m == LED_ONESHOT_SHORT)
-       chThdSleep (MS2ST (100));
+       chopstx_usec_wait (100*1000);
       else if (m == LED_TWOSHOTS)
        {
-         chThdSleep (MS2ST (50));
+         chopstx_usec_wait (50*1000);
          set_led (0);
-         chThdSleep (MS2ST (50));
+         chopstx_usec_wait (50*1000);
          set_led (1);
-         chThdSleep (MS2ST (50));
+         chopstx_usec_wait (50*1000);
        }
       else
-       chThdSleep (MS2ST (250));
+       chopstx_usec_wait (250*1000);
       set_led (0);
     }
 
   return 0;
 }
 \f
-#define RANDOM_BYTES_LENGTH 32
+#define RANDOM_BYTES_LENGTH 64
 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
 
+static void copy_to_tx (uint32_t v, int i)
+{
+  usb_lld_txcpy (&v, ENDP1, i * 4, 4);
+}
+
+/*
+ * In Gnuk 1.0.[12], reGNUal was not relocatable.
+ * Now, it's relocatable, but we need to calculate its entry address
+ * based on it's pre-defined address.
+ */
+#define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
+static uint32_t
+calculate_regnual_entry_address (const uint8_t *addr)
+{
+  const uint8_t *p = addr + 4;
+  uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
+
+  v -= REGNUAL_START_ADDRESS_COMPATIBLE;
+  v += (uint32_t)addr;
+  return v;
+}
+
+
 /*
  * Entry point.
  *
@@ -686,26 +773,33 @@ static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
 int
 main (int argc, char **argv)
 {
+  uint32_t entry;
+  chopstx_t led_thread, usb_thd;
+
   (void)argc;
   (void)argv;
 
   fill_serial_no_by_unique_id ();
 
-  halInit ();
   adc_init ();
-  chSysInit ();
 
-  main_thread = chThdSelf ();
+  event_flag_init (&led_event);
+  
+  led_thread = chopstx_create (PRIO_LED, __stackaddr_led, __stacksize_led,
+                              led_blinker, NULL);
 
-  chThdCreateStatic (wa_led, sizeof (wa_led), NORMALPRIO, led_blinker, NULL);
+  chopstx_mutex_init (&usb_mtx);
+  chopstx_cond_init (&cnd_usb);
 
-  neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
+  usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
+                           usb_intr, NULL);
 
-  usb_lld_init (config_desc.Descriptor[7]);
+  neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
 
   while (1)
     {
       unsigned int count = 0;
+      int last_was_fullsizepacket = 0;
 
       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
        break;
@@ -719,8 +813,8 @@ main (int argc, char **argv)
          neug_flush ();
 
          if ((count & 0x0007) == 0)
-           chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
-         chEvtWaitOneTimeout (ALL_EVENTS, MS2ST (25));
+           event_flag_signal (&led_event, LED_ONESHOT_SHORT);
+         chopstx_usec_wait (25*1000);
          count++;
        }
 
@@ -731,8 +825,8 @@ main (int argc, char **argv)
            break;
 
          neug_flush ();
-         chEvtSignalFlags (led_thread, LED_TWOSHOTS);
-         chEvtWaitOneTimeout (ALL_EVENTS, MS2ST (5000));
+         event_flag_signal (&led_event, LED_TWOSHOTS);
+         chopstx_usec_wait (5000*1000);
        }
 
       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
@@ -748,41 +842,49 @@ main (int argc, char **argv)
 
       while (1)
        {
+         int i;
+
          if (fsij_device_state != FSIJ_DEVICE_RUNNING)
            break;
 
          if (bDeviceState != CONFIGURED)
            break;
 
-         neug_wait_full ();
-
          if ((count & 0x03ff) == 0)
-           chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
+           event_flag_signal (&led_event, LED_ONESHOT_SHORT);
 
-         usb_lld_txcpy (random_word, ENDP1, 0, RANDOM_BYTES_LENGTH);
-         neug_flush ();
+         i = neug_consume_random (copy_to_tx);
 
-         chSysLock ();
+         if (i == 0 && !last_was_fullsizepacket)
+           {    /* Only send ZLP when the last packet was fullsize.  */
+             neug_wait_full ();
+             continue;
+           }
+
+         if (i == 64/4)
+           last_was_fullsizepacket = 1;
+         else
+           last_was_fullsizepacket = 0;
+
+         chopstx_mutex_lock (&usb_mtx);
          if (connected == 0)
            {
-             chSysUnlock();
+             chopstx_mutex_unlock (&usb_mtx);
              goto waiting_connection;
            }
          else
            {
-             neug_state = NEUG_WAIT_FOR_TX_READY;
-             usb_lld_tx_enable (ENDP1, RANDOM_BYTES_LENGTH);
-             chSchGoSleepS (THD_STATE_SUSPENDED);
-             neug_state = 0;
+             usb_lld_tx_enable (ENDP1, i * 4);
+             chopstx_cond_wait (&cnd_usb, &usb_mtx);
            }
-         chSysUnlock();
+         chopstx_mutex_unlock (&usb_mtx);
 
          count++;
        }
     }
 
-  chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
-  chThdWait (led_thread);
+  chopstx_cancel (led_thread);
+  chopstx_join (led_thread, NULL);
 
   /*
    * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED.
@@ -792,17 +894,19 @@ main (int argc, char **argv)
   fsij_device_state = FSIJ_DEVICE_EXITED;
 
   while (fsij_device_state == FSIJ_DEVICE_EXITED)
-    chThdSleep (MS2ST (500));
+    chopstx_usec_wait (500*1000);
 
   flash_unlock ();             /* Flash unlock should be done here */
   set_led (1);
   usb_lld_shutdown ();
-  /* Disable SysTick */
-  SysTick->CTRL = 0;
-  /* Disable all interrupts */
-  port_disable ();
+
+  /* Finish application.  */
+  chopstx_cancel (usb_thd);
+  chopstx_join (usb_thd, NULL);
+
   /* Set vector */
   SCB->VTOR = (uint32_t)&_regnual_start;
+  entry = calculate_regnual_entry_address (&_regnual_start);
 #ifdef DFU_SUPPORT
 #define FLASH_SYS_START_ADDR 0x08000000
 #define FLASH_SYS_END_ADDR (0x08000000+0x1000)
@@ -821,12 +925,12 @@ main (int argc, char **argv)
     flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
 
     /* Leave NeuG to exec reGNUal */
-    (*func) (*((void (**)(void))(&_regnual_start+4)));
+    (*func) ((void (*)(void))entry);
     for (;;);
   }
 #else
   /* Leave NeuG to exec reGNUal */
-  flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4)));
+  flash_erase_all_and_exec ((void (*)(void))entry);
 #endif
 
   /* Never reached */