summaryrefslogtreecommitdiff
path: root/src/drivers/ao_trng_send.c
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2016-03-02 13:54:58 -0800
committerKeith Packard <keithp@keithp.com>2016-03-02 13:59:21 -0800
commit05fcb717bfc44aba3c1cfd43281e323505a46402 (patch)
treea27b543f7a6f65b87fec29e77ca4151e0c1ee59d /src/drivers/ao_trng_send.c
parent05354b8fee6a9af05d66bb7f4761f597da038fdd (diff)
altos/chaoskey: Add another USB endpoint to read raw data
This replaces having the single output switch based on a pin value and allows us to box the device and still fetch raw data. For now, this will use a special libusb2 program, ao-chaosread, to pull bits as I haven't figure out how to make linux provide two /dev entries for one USB device. Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src/drivers/ao_trng_send.c')
-rw-r--r--src/drivers/ao_trng_send.c149
1 files changed, 107 insertions, 42 deletions
diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c
index f8222993..171a345f 100644
--- a/src/drivers/ao_trng_send.c
+++ b/src/drivers/ao_trng_send.c
@@ -22,54 +22,97 @@
#include <ao_exti.h>
#include <ao_power.h>
+static struct ao_task ao_trng_send_task, ao_trng_send_raw_task;
static uint8_t trng_running;
static AO_TICK_TYPE trng_power_time;
-/* Make sure there's at least 8 bits of variance in the samples */
-#define MIN_VARIANCE (128 * 128)
-
-#define DECLARE_STATS int32_t sum = 0, sum2 = 0
-
-#define ADD_STATS(value) do { \
- sum += (value); \
- sum2 += (value) * (value); \
- } while(0)
-
-#define GOOD_STATS(i) (((sum2 - (sum * sum) / i) / i) >= MIN_VARIANCE)
-
#define TRNG_ENABLE_DELAY AO_MS_TO_TICKS(100)
-static int
-ao_trng_send_raw(uint16_t *buf)
+static uint8_t random_mutex;
+
+static void
+ao_trng_get_raw(uint16_t *buf)
{
uint16_t i;
uint16_t t;
uint16_t v;
- DECLARE_STATS;
-
t = ao_adc_get(AO_USB_IN_SIZE>>1); /* one 16-bit value per two output bytes */
for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) {
v = ao_adc_ring[t];
*buf++ = v;
t = (t + 1) & (AO_ADC_RING_SIZE - 1);
+ }
+ ao_adc_ack(AO_USB_IN_SIZE>>1);
+}
+
+static void
+ao_trng_send_raw(void)
+{
+ static uint16_t *buffer[2];
+ int usb_buf_id;
- ADD_STATS(v);
+ if (!buffer[0]) {
+ buffer[0] = ao_usb_alloc();
+ buffer[1] = ao_usb_alloc();
+ if (!buffer[0])
+ ao_exit();
+ }
+
+ usb_buf_id = 0;
+
+ for (;;) {
+ ao_mutex_get(&random_mutex);
+ if (!trng_running) {
+ AO_TICK_TYPE delay;
+
+ delay = trng_power_time + TRNG_ENABLE_DELAY - ao_time();
+ if (delay > TRNG_ENABLE_DELAY)
+ delay = TRNG_ENABLE_DELAY;
+
+ /* Delay long enough for the HV power supply
+ * to stabilize so that the first bits we read
+ * aren't of poor quality
+ */
+ ao_delay(delay);
+ trng_running = TRUE;
+ }
+#ifdef AO_LED_TRNG_RAW
+ ao_led_on(AO_LED_TRNG_RAW);
+#endif
+ ao_trng_get_raw(buffer[usb_buf_id]);
+#ifdef AO_LED_TRNG_RAW
+ ao_led_off(AO_LED_TRNG_RAW);
+#endif
+ ao_mutex_put(&random_mutex);
+ ao_usb_write2(buffer[usb_buf_id], AO_USB_IN_SIZE);
+ usb_buf_id = 1-usb_buf_id;
}
- return GOOD_STATS(AO_USB_IN_SIZE / sizeof (uint16_t));
}
+/* Make sure there's at least 8 bits of variance in the samples */
+#define MIN_VARIANCE (128 * 128)
+
+/* Make sure the signal is spread around a bit */
+#define MAX_VARIANCE (512 * 512)
+
+#define ADD_STATS(value) do { \
+ sum += (value); \
+ sum2 += (value) * (value); \
+ } while(0)
+
+#define VARIANCE(n) ((sum2 - (sum / (n) * sum)) / (n))
+
static int
-ao_trng_send_cooked(uint16_t *buf)
+ao_trng_get_cooked(uint16_t *buf)
{
uint16_t i;
uint16_t t;
uint32_t *rnd = (uint32_t *) ao_adc_ring;
+ int32_t sum, sum2, var;
- DECLARE_STATS;
-
+ sum = sum2 = 0;
t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* one 16-bit value per output byte */
-
for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) {
uint32_t v;
uint16_t v1, v2;
@@ -86,14 +129,13 @@ ao_trng_send_cooked(uint16_t *buf)
ADD_STATS(v1);
ADD_STATS(v2);
}
- return GOOD_STATS(2 * AO_USB_IN_SIZE / sizeof (uint16_t));
+ ao_adc_ack(AO_USB_IN_SIZE);
+ var = VARIANCE(2 * AO_USB_IN_SIZE / sizeof (uint16_t));
+ return var >= MIN_VARIANCE && var <= MAX_VARIANCE;
}
-static inline int
-ao_send_raw(void)
-{
- return !ao_gpio_get(AO_RAW_PORT, AO_RAW_BIT, AO_RAW_PIN);
-}
+#define AO_TRNG_START_WAIT 1024
+#define AO_TRNG_START_CHECK 32
static void
ao_trng_send(void)
@@ -101,13 +143,14 @@ ao_trng_send(void)
static uint16_t *buffer[2];
int usb_buf_id;
int good_bits;
- int failed = 0;
+ int failed;
+ int s;
if (!buffer[0]) {
buffer[0] = ao_usb_alloc();
buffer[1] = ao_usb_alloc();
if (!buffer[0])
- return;
+ ao_exit();
}
usb_buf_id = 0;
@@ -119,7 +162,33 @@ ao_trng_send(void)
ao_crc_reset();
+ ao_delay(TRNG_ENABLE_DELAY);
+
+ for (s = 0; s < AO_TRNG_START_WAIT; s++) {
+ if (ao_trng_get_cooked(buffer[0]))
+ break;
+ ao_delay(AO_MS_TO_TICKS(10));
+ }
+
+ /* Validate the hardware before enabling USB */
+ failed = 0;
+ for (s = 0; s < AO_TRNG_START_CHECK; s++) {
+ if (!ao_trng_get_cooked(buffer[0])) {
+ failed++;
+ ao_delay(AO_MS_TO_TICKS(10));
+ }
+ }
+ if (failed > AO_TRNG_START_CHECK / 4)
+ ao_panic(AO_PANIC_DMA);
+
+ ao_add_task(&ao_trng_send_raw_task, ao_trng_send_raw, "trng_send_raw");
+
+#ifdef AO_USB_START_DISABLED
+ ao_usb_enable();
+#endif
+
for (;;) {
+ ao_mutex_get(&random_mutex);
if (!trng_running) {
AO_TICK_TYPE delay;
@@ -134,16 +203,14 @@ ao_trng_send(void)
ao_delay(delay);
trng_running = TRUE;
}
- if (ao_send_raw()) {
- ao_led_on(AO_LED_TRNG_RAW);
- good_bits = ao_trng_send_raw(buffer[usb_buf_id]);
- ao_led_off(AO_LED_TRNG_RAW);
- } else {
- ao_led_on(AO_LED_TRNG_COOKED);
- good_bits = ao_trng_send_cooked(buffer[usb_buf_id]);
- ao_led_off(AO_LED_TRNG_COOKED);
- }
- ao_adc_ack(AO_USB_IN_SIZE);
+#ifdef AO_LED_TRNG_COOKED
+ ao_led_on(AO_LED_TRNG_COOKED);
+#endif
+ good_bits = ao_trng_get_cooked(buffer[usb_buf_id]);
+#ifdef AO_LED_TRNG_COOKED
+ ao_led_off(AO_LED_TRNG_COOKED);
+#endif
+ ao_mutex_put(&random_mutex);
if (good_bits) {
ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE);
usb_buf_id = 1-usb_buf_id;
@@ -159,8 +226,6 @@ ao_trng_send(void)
}
}
-static struct ao_task ao_trng_send_task;
-
#if AO_POWER_MANAGEMENT
static void ao_trng_suspend(void *arg)