Version 0.05
[gnuk/neug.git] / src / main.c
index 0f3c104..1f2894c 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2011, 2012 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
@@ -13,7 +13,7 @@
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
- * Gnuk is distributed in the hope that it will be useful, but WITHOUT
+ * NeuG is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
  * License for more details.
@@ -30,6 +30,7 @@
 #include "neug.h"
 #include "usb_lld.h"
 #include "sys.h"
+#include "adc.h"
 
 /*
  * We are trying to avoid dependency to C library. 
@@ -38,7 +39,7 @@
 extern void *memcpy(void *dest, const void *src, size_t n);
 extern void *memset (void *s, int c, size_t n);
 
-static Thread *main_thread = NULL;
+static Thread *main_thread;
 
 \f
 #define ENDP0_RXADDR        (0x40)
@@ -170,7 +171,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, '5', 0,    /* Version number of NeuG.          */
   '-', 0,
   0, 0, 0, 0,  /* Filled by Unique device ID.      */
   0, 0, 0, 0,
@@ -204,7 +205,6 @@ static const struct Descriptor string_descs[] = {
 
 uint32_t bDeviceState = UNCONNECTED; /* USB device status */
 
-
 static void
 neug_device_reset (void)
 {
@@ -228,6 +228,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_INFO      254
 #define USB_NEUG_EXIT          255 /* Ask to exit and to receive reGNUal */
 
 enum {
@@ -274,20 +275,28 @@ static void neug_ctrl_write_finish (uint8_t req, uint8_t req_no,
 
   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
       && USB_SETUP_SET (req) && len == 0)
-    if (req_no == USB_FSIJ_EXEC)
-      {
-       if (fsij_device_state != FSIJ_DEVICE_EXITED)
-         return;
-
-       (void)value; (void)index;
-       usb_lld_prepare_shutdown (); /* No further USB communication */
-       fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED;
-      }
-    else if (req_no == USB_NEUG_EXIT)
-      {
-       chEvtSignalFlagsI (main_thread, 1);
-       chSchReadyI (main_thread);
-      }
+    {
+      if (req_no == USB_FSIJ_EXEC)
+       {
+         if (fsij_device_state != FSIJ_DEVICE_EXITED)
+           return;
+
+         (void)value; (void)index;
+         usb_lld_prepare_shutdown (); /* No further USB communication */
+         fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED;
+       }
+      else if (req_no == USB_NEUG_EXIT)
+       {
+         chSysLockFromIsr ();
+         if (main_thread->p_state == THD_STATE_SUSPENDED
+             || main_thread->p_state == THD_STATE_SLEEPING)
+           {
+             main_thread->p_u.rdymsg = RDY_OK;
+             chSchReadyI (main_thread);
+           }
+         chSysUnlockFromIsr ();
+       }
+    }
 }
 
 struct line_coding
@@ -327,15 +336,32 @@ 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 & 1) == 0)
+             if (connected == 0)
                /* It's Open call */
                connected++;
            }
          else
-           /* Close call */
-           connected++;
+           {
+             if (connected)
+               /* Close call */
+               connected = 0;
+           }
+
+         if (connected != connected_saved)
+           {
+             chSysLockFromIsr ();
+             if (main_thread->p_state == THD_STATE_SUSPENDED
+                 || main_thread->p_state == THD_STATE_SLEEPING)
+               {
+                 main_thread->p_u.rdymsg = RDY_OK;
+                 chSchReadyI (main_thread);
+               }
+             chSysUnlockFromIsr ();
+           }
 
          return USB_SUCCESS;
        }
@@ -359,6 +385,29 @@ 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_INFO)
+           {
+             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;
+
+             return USB_SUCCESS;
+           }
        }
       else /* SETUP_SET */
        {
@@ -568,24 +617,20 @@ static void fill_serial_no_by_unique_id (void)
 CH_IRQ_HANDLER (Vector90)
 {
   CH_IRQ_PROLOGUE();
-  chSysLockFromIsr();
-
   usb_interrupt_handler ();
-
-  chSysUnlockFromIsr();
   CH_IRQ_EPILOGUE();
 }
 
 void
 EP1_IN_Callback (void)
 {
-  if (main_thread != NULL)
+  chSysLockFromIsr ();
+  if (main_thread->p_state == THD_STATE_SUSPENDED)
     {
-      chSysLockFromIsr ();
       main_thread->p_u.rdymsg = RDY_OK;
       chSchReadyI (main_thread);
-      chSysUnlockFromIsr ();
     }
+  chSysUnlockFromIsr ();
 }
 
 void
@@ -601,8 +646,9 @@ EP3_OUT_Callback (void)
 \f
 static WORKING_AREA(wa_led, 64);
 
-#define LED_ONESHOT_SHORT ((eventmask_t)1)
-#define LED_ONESHOT_LONG  ((eventmask_t)2)
+#define LED_ONESHOT_SHORT      ((eventmask_t)1)
+#define LED_TWOSHOTS           ((eventmask_t)2)
+#define LED_ONESHOT_LONG       ((eventmask_t)4)
 static Thread *led_thread;
 
 /*
@@ -625,18 +671,31 @@ static msg_t led_blinker (void *arg)
 
       set_led (1);
       if (m == LED_ONESHOT_SHORT)
-       chThdSleep (MS2ST (100));
+       chThdSleepMilliseconds (100);
+      else if (m == LED_TWOSHOTS)
+       {
+         chThdSleepMilliseconds (50);
+         set_led (0);
+         chThdSleepMilliseconds (50);
+         set_led (1);
+         chThdSleepMilliseconds (50);
+       }
       else
-       chThdSleep (MS2ST (250));
+       chThdSleepMilliseconds (250);
       set_led (0);
     }
 
   return 0;
 }
 \f
-#define RANDOM_BYTES_LENGTH 60
+#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);
+}
+
 /*
  * Entry point.
  *
@@ -650,95 +709,117 @@ main (int argc, char **argv)
 
   fill_serial_no_by_unique_id ();
 
-  halInit();
-  chSysInit();
+  halInit ();
+  adc_init ();
+  chSysInit ();
 
   main_thread = chThdSelf ();
 
-  usb_lld_init (config_desc.Descriptor[7]);
-
   chThdCreateStatic (wa_led, sizeof (wa_led), NORMALPRIO, led_blinker, NULL);
 
   neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
 
+  usb_lld_init (config_desc.Descriptor[7]);
+
   while (1)
     {
       unsigned int count = 0;
-      uint32_t bitrate_saved;
+      int last_was_fullsizepacket = 0;
 
       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
        break;
 
-      connected = 0;
       while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
        {
          if (fsij_device_state != FSIJ_DEVICE_RUNNING)
            break;
 
-         (void)neug_get (NEUG_KICK_FILLING);
-         if ((count & 0x000f) == 0)
+         neug_wait_full ();
+         neug_flush ();
+
+         if ((count & 0x0007) == 0)
            chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
-         chEvtWaitOneTimeout (ALL_EVENTS, MS2ST (25));
+         chThdSleepMilliseconds (25);
          count++;
        }
 
     waiting_connection:
-      bitrate_saved = line_coding.bitrate;
-      while ((connected & 1) == 0)
+      while (connected == 0)
        {
          if (fsij_device_state != FSIJ_DEVICE_RUNNING)
            break;
 
          neug_flush ();
-         chEvtSignalFlags (led_thread, LED_ONESHOT_LONG);
-         chEvtWaitOneTimeout (ALL_EVENTS, MS2ST (2500));
+         chEvtSignalFlags (led_thread, LED_TWOSHOTS);
+         chThdSleepMilliseconds (5000);
        }
 
+      if (fsij_device_state != FSIJ_DEVICE_RUNNING)
+       break;
+
       /* The connection opened.  */
       count = 0;
-      if (bitrate_saved != line_coding.bitrate)
-       neug_select (line_coding.bitrate != 115200);
+      /*
+       * No parity is standard.  It means to provide conditioned output.
+       * When parity enabled, it means to provide raw output.
+       */
+      neug_mode_select (line_coding.paritytype); /* 0: None, 1: Odd, 2: Even */
 
       while (1)
        {
+         int i;
+
          if (fsij_device_state != FSIJ_DEVICE_RUNNING)
            break;
 
-         if ((connected & 1) == 0)
-           goto waiting_connection;
-
          if (bDeviceState != CONFIGURED)
            break;
 
-         neug_wait_full ();
-
-         if ((count & 0x00ff) == 0)
+         if ((count & 0x03ff) == 0)
            chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
 
-         usb_lld_txcpy (random_word, ENDP1, 0, RANDOM_BYTES_LENGTH);
-         neug_flush ();
+         i = neug_consume_random (copy_to_tx);
+
+         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;
 
          chSysLock ();
-         usb_lld_tx_enable (ENDP1, RANDOM_BYTES_LENGTH);
-         chSchGoSleepS (THD_STATE_SUSPENDED);
-         chSysUnlock();
+         if (connected == 0)
+           {
+             chSysUnlock();
+             goto waiting_connection;
+           }
+         else
+           {
+             usb_lld_tx_enable (ENDP1, i * 4);
+             chSchGoSleepS (THD_STATE_SUSPENDED);
+           }
+         chSysUnlock ();
 
          count++;
        }
     }
 
+  chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
+  chThdWait (led_thread);
+
   /*
    * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED.
    */
   neug_fini ();
 
-  chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
-  chThdWait (led_thread);
-
   fsij_device_state = FSIJ_DEVICE_EXITED;
 
   while (fsij_device_state == FSIJ_DEVICE_EXITED)
-    chThdSleep (MS2ST (500));
+    chThdSleepMilliseconds (500);
 
   flash_unlock ();             /* Flash unlock should be done here */
   set_led (1);