ao-tools: Add ao-chaosread
authorKeith Packard <keithp@keithp.com>
Wed, 2 Mar 2016 22:36:31 +0000 (14:36 -0800)
committerKeith Packard <keithp@keithp.com>
Wed, 2 Mar 2016 22:36:31 +0000 (14:36 -0800)
This reads from the raw descriptor to help validate the hardware.

Signed-off-by: Keith Packard <keithp@keithp.com>
ao-tools/Makefile.am
ao-tools/ao-chaosread/.gitignore [new file with mode: 0644]
ao-tools/ao-chaosread/Makefile.am [new file with mode: 0644]
ao-tools/ao-chaosread/ao-chaosread.1 [new file with mode: 0644]
ao-tools/ao-chaosread/ao-chaosread.c [new file with mode: 0644]
configure.ac

index 66d2560e0faa36b8ce09e8455fe235bf01362067..dad85e83e7390de7d9e1f4c0075cd06c364c2029 100644 (file)
@@ -3,7 +3,7 @@ SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list \
        ao-dumpflash ao-edit-telem ao-dump-up ao-elftohex \
        ao-flash ao-usbload ao-test-igniter ao-test-baro \
        ao-test-flash ao-cal-accel ao-test-gps ao-usbtrng \
-       ao-cal-freq
+       ao-cal-freq ao-chaosread
 if LIBSTLINK
 SUBDIRS += ao-stmload
 endif
diff --git a/ao-tools/ao-chaosread/.gitignore b/ao-tools/ao-chaosread/.gitignore
new file mode 100644 (file)
index 0000000..b944387
--- /dev/null
@@ -0,0 +1 @@
+ao-chaosread
diff --git a/ao-tools/ao-chaosread/Makefile.am b/ao-tools/ao-chaosread/Makefile.am
new file mode 100644 (file)
index 0000000..581eb2d
--- /dev/null
@@ -0,0 +1,9 @@
+bin_PROGRAMS=ao-chaosread
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+
+ao_chaosread_LDADD=$(LIBUSB_LIBS)
+
+ao_chaosread_SOURCES = ao-chaosread.c
+
+man_MANS = ao-chaosread.1
diff --git a/ao-tools/ao-chaosread/ao-chaosread.1 b/ao-tools/ao-chaosread/ao-chaosread.1
new file mode 100644 (file)
index 0000000..d8ed6cb
--- /dev/null
@@ -0,0 +1,36 @@
+.\"
+.\" Copyright © 2016 Keith Packard <keithp@keithp.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program 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.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH AO-LOAD 1 "ao-chaosread" ""
+.SH NAME
+ao-chaosread \- read raw noise source from chaoskey
+.SH SYNOPSIS
+.B "ao-chaosread"
+.SH DESCRIPTION
+.I ao-chaosread
+reads ADC values from the noise source on the attached ChaosKey device.
+.SH OPTIONS
+.TP
+\-s serial | --serial serial
+This selects a ChaosKey by serial number instead of using the first
+one found.
+.SH USAGE
+.I ao-chaosread
+reads noise data.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-chaosread/ao-chaosread.c b/ao-tools/ao-chaosread/ao-chaosread.c
new file mode 100644 (file)
index 0000000..806c2ef
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libusb.h>
+#include <getopt.h>
+#include <string.h>
+#include <strings.h>
+
+#define CHAOS_SIZE     64
+
+#define CHAOS_VENDOR   0x1d50
+#define CHAOS_PRODUCT  0x60c6
+
+struct chaoskey {
+       libusb_context          *ctx;
+       libusb_device_handle    *handle;
+       int                     kernel_active;
+};
+
+libusb_device_handle *
+chaoskey_match(libusb_device *dev, char *match_serial)
+{
+       struct libusb_device_descriptor desc;
+       int ret;
+       int match_len;
+       char *device_serial = NULL;
+       libusb_device_handle *handle = NULL;
+
+       ret = libusb_get_device_descriptor(dev, &desc);
+       if (ret < 0) {
+               fprintf(stderr, "failed to get device descriptor: %s\n", libusb_strerror(ret));
+               return 0;
+       }
+
+       if (desc.idVendor != CHAOS_VENDOR)
+               return NULL;
+       if (desc.idProduct != CHAOS_PRODUCT)
+               return NULL;
+
+       ret = libusb_open(dev, &handle);
+
+       if (match_serial == NULL)
+               return handle;
+
+       if (ret < 0) {
+               fprintf(stderr, "failed to open device: %s\n", libusb_strerror(ret));
+               return NULL;
+       }
+
+       match_len = strlen(match_serial);
+       device_serial = malloc(match_len + 2);
+
+       if (!device_serial) {
+               fprintf(stderr, "malloc failed\n");
+               goto out;
+       }
+
+       ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, device_serial, match_len + 1);
+
+       if (ret < 0) {
+               fprintf(stderr, "failed to get serial number: %s\n", libusb_strerror(ret));
+               goto out;
+       }
+
+       device_serial[ret] = '\0';
+
+       ret = strcmp(device_serial, match_serial);
+       free(device_serial);
+       if (ret)
+               goto out;
+
+       return handle;
+
+out:
+       free(device_serial);
+       if (handle)
+               libusb_close(handle);
+       return 0;
+}
+
+struct chaoskey *
+chaoskey_open(char *serial)
+{
+       struct chaoskey *ck;
+       int             ret;
+       ssize_t         num;
+       libusb_device   **list;
+       libusb_device   *device = NULL;
+       int             d;
+
+       ck = calloc(sizeof (struct chaoskey), 1);
+       if (!ck)
+               goto out;
+       ret = libusb_init(&ck->ctx);
+       if (ret ) {
+               fprintf(stderr, "libusb_init failed: %s\n", libusb_strerror(ret));
+               goto out;
+       }
+
+       num = libusb_get_device_list(ck->ctx, &list);
+       if (num < 0) {
+               fprintf(stderr, "libusb_get_device_list failed: %s\n", libusb_strerror(num));
+               goto out;
+       }
+
+       for (d = 0; d < num; d++) {
+               libusb_device_handle *handle;
+
+               handle = chaoskey_match(list[d], serial);
+               if (handle) {
+                       ck->handle = handle;
+                       break;
+               }
+       }
+
+       libusb_free_device_list(list, 1);
+
+       if (!ck->handle) {
+               if (serial)
+                       fprintf (stderr, "No chaoskey matching %s\n", serial);
+               else
+                       fprintf (stderr, "No chaoskey\n");
+               goto out;
+       }
+
+       ck->kernel_active = libusb_kernel_driver_active(ck->handle, 0);
+       if (ck->kernel_active) {
+               ret = libusb_detach_kernel_driver(ck->handle, 0);
+               if (ret)
+                       goto out;
+       }
+
+       ret = libusb_claim_interface(ck->handle, 0);
+       if (ret)
+               goto out;
+
+       return ck;
+out:
+       if (ck->kernel_active)
+               libusb_attach_kernel_driver(ck->handle, 0);
+       if (ck->ctx)
+               libusb_exit(ck->ctx);
+       free(ck);
+       return NULL;
+}
+
+void
+chaoskey_close(struct chaoskey *ck)
+{
+       libusb_release_interface(ck->handle, 0);
+       if (ck->kernel_active)
+               libusb_attach_kernel_driver(ck->handle, 0);
+       libusb_close(ck->handle);
+       libusb_exit(ck->ctx);
+       free(ck);
+}
+
+void
+chaoskey_transfer_callback(struct libusb_transfer *transfer)
+{
+       struct chaoskey *ck = transfer->user_data;
+}
+
+#define ENDPOINT       0x86
+
+int
+chaoskey_read(struct chaoskey *ck, uint8_t *buffer, int len)
+{
+       int     total = 0;
+
+       while (len) {
+               int     ret;
+               int     transferred;
+
+               ret = libusb_bulk_transfer(ck->handle, ENDPOINT, buffer, len, &transferred, 10000);
+               if (ret) {
+                       if (total)
+                               return total;
+                       else {
+                               errno = EIO;
+                               return -1;
+                       }
+               }
+               len -= transferred;
+               buffer += transferred;
+       }
+}
+
+static const struct option options[] = {
+       { .name = "serial", .has_arg = 1, .val = 's' },
+       { .name = "length", .has_arg = 1, .val = 'l' },
+       { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+       fprintf(stderr, "usage: %s [--serial=<serial>] [--length=<length>[kMG]]\n", program);
+       exit(1);
+}
+
+int
+main (int argc, char **argv)
+{
+       struct chaoskey *ck;
+       char    buf[1024];
+       int     got;
+       int     c;
+       char    *serial = NULL;
+       char    *length_string;
+       char    *length_end;
+       unsigned long   length = sizeof(buf);
+       int             this_time;
+
+       while ((c = getopt_long(argc, argv, "s:l:", options, NULL)) != -1) {
+               switch (c) {
+               case 's':
+                       serial = optarg;
+                       break;
+               case 'l':
+                       length_string = optarg;
+                       length = strtoul(length_string, &length_end, 10);
+                       if (!strcasecmp(length_end, "k"))
+                               length *= 1024;
+                       else if (!strcasecmp(length_end, "m"))
+                               length *= 1024 * 1024;
+                       else if (!strcasecmp(length_end, "g"))
+                               length *= 1024 * 1024 * 1024;
+                       else if (strlen(length_end))
+                                usage(argv[0]);
+                       break;
+               default:
+                       usage(argv[0]);
+                       break;
+               }
+       }
+
+       ck = chaoskey_open(serial);
+       if (!ck)
+               exit(1);
+
+       while (length) {
+               this_time = sizeof(buf);
+               if (length < sizeof(buf))
+                       this_time = (int) length;
+               got = chaoskey_read(ck, buf, this_time);
+               if (got < 0) {
+                       perror("read");
+                       exit(1);
+               }
+               write(1, buf, got);
+               length -= got;
+       }
+       exit(0);
+}
index addaad0c61c2e2bb75338f0bd5fd29943baa4b61..1cb162595cc449b439511aa53413c7737541c54a 100644 (file)
@@ -557,6 +557,7 @@ ao-tools/ao-cal-accel/Makefile
 ao-tools/ao-cal-freq/Makefile
 ao-tools/ao-test-gps/Makefile
 ao-tools/ao-usbtrng/Makefile
+ao-tools/ao-chaosread/Makefile
 ao-utils/Makefile
 src/Version
 ])