summaryrefslogtreecommitdiff
path: root/ao-tools
diff options
context:
space:
mode:
Diffstat (limited to 'ao-tools')
-rw-r--r--ao-tools/Makefile.am2
-rw-r--r--ao-tools/ao-chaosread/.gitignore1
-rw-r--r--ao-tools/ao-chaosread/Makefile.am9
-rw-r--r--ao-tools/ao-chaosread/ao-chaosread.136
-rw-r--r--ao-tools/ao-chaosread/ao-chaosread.c272
-rw-r--r--ao-tools/ao-dump-up/ao-dump-up.c14
-rw-r--r--ao-tools/ao-makebin/Makefile.am12
-rw-r--r--ao-tools/ao-makebin/ao-makebin.147
-rw-r--r--ao-tools/ao-makebin/ao-makebin.c172
-rw-r--r--ao-tools/lib/Makefile.am2
-rw-r--r--ao-tools/lib/ao-dfu.c202
-rw-r--r--ao-tools/lib/ao-dfu.h35
-rw-r--r--ao-tools/lib/ao-elf.c6
-rw-r--r--ao-tools/lib/ao-hex.c33
-rw-r--r--ao-tools/lib/ao-hex.h3
15 files changed, 824 insertions, 22 deletions
diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am
index 66d2560e..fb554857 100644
--- a/ao-tools/Makefile.am
+++ b/ao-tools/Makefile.am
@@ -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 ao-makebin
if LIBSTLINK
SUBDIRS += ao-stmload
endif
diff --git a/ao-tools/ao-chaosread/.gitignore b/ao-tools/ao-chaosread/.gitignore
new file mode 100644
index 00000000..b9443879
--- /dev/null
+++ b/ao-tools/ao-chaosread/.gitignore
@@ -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
index 00000000..581eb2d2
--- /dev/null
+++ b/ao-tools/ao-chaosread/Makefile.am
@@ -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
index 00000000..d8ed6cb3
--- /dev/null
+++ b/ao-tools/ao-chaosread/ao-chaosread.1
@@ -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
index 00000000..806c2ef9
--- /dev/null
+++ b/ao-tools/ao-chaosread/ao-chaosread.c
@@ -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);
+}
diff --git a/ao-tools/ao-dump-up/ao-dump-up.c b/ao-tools/ao-dump-up/ao-dump-up.c
index b1f85af6..df05088c 100644
--- a/ao-tools/ao-dump-up/ao-dump-up.c
+++ b/ao-tools/ao-dump-up/ao-dump-up.c
@@ -140,20 +140,6 @@ static int find_header(struct cc_usb *cc)
}
}
-static const char *state_names[] = {
- "startup",
- "idle",
- "pad",
- "boost",
- "fast",
- "coast",
- "drogue",
- "main",
- "landed",
- "invalid"
-};
-
-
int
main (int argc, char **argv)
{
diff --git a/ao-tools/ao-makebin/Makefile.am b/ao-tools/ao-makebin/Makefile.am
new file mode 100644
index 00000000..758097a4
--- /dev/null
+++ b/ao-tools/ao-makebin/Makefile.am
@@ -0,0 +1,12 @@
+bin_PROGRAMS=ao-makebin
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_ELFTOHEX_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_makebin_DEPENDENCIES = $(AO_ELFTOHEX_LIBS)
+
+ao_makebin_LDADD=$(AO_ELFTOHEX_LIBS) -lelf
+
+ao_makebin_SOURCES=ao-makebin.c
+
+man_MANS = ao-makebin.1
diff --git a/ao-tools/ao-makebin/ao-makebin.1 b/ao-tools/ao-makebin/ao-makebin.1
new file mode 100644
index 00000000..e19ec2cc
--- /dev/null
+++ b/ao-tools/ao-makebin/ao-makebin.1
@@ -0,0 +1,47 @@
+.\"
+.\" Copyright © 2013 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-makebin" ""
+.SH NAME
+ao-makebin \- construct raw binary file or DFU image from collection of ELF files
+.SH SYNOPSIS
+.B "ao-makebin"
+[\--base=\fIbase-address\fP]
+[\--output=\fIoutput.bin\fP]
+[\--dfu]
+[\--verbose]
+\fIinput.elf ...\fP
+.SH DESCRIPTION
+.I ao-makebin
+reads the specified .elf files and writes out a raw binary flash image
+.SH OPTIONS
+.TP
+\--base=\fIbase-address\fP
+This specifies the target address for the first byte of the file (default is 0)
+.TP
+\--output=\fIoutput.bin\fP
+This specifies the output file (default is stdout)
+.TP
+\--dfu
+Creates a DFU file (as documented by ST's UM0391 user manual) instead
+of a raw binary file.
+.TP
+\--verbose
+Dumps some debug information.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-makebin/ao-makebin.c b/ao-tools/ao-makebin/ao-makebin.c
new file mode 100644
index 00000000..31ce1889
--- /dev/null
+++ b/ao-tools/ao-makebin/ao-makebin.c
@@ -0,0 +1,172 @@
+/*
+ * 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 <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "ao-hex.h"
+#include "ao-elf.h"
+#include "ao-dfu.h"
+
+static const struct option options[] = {
+ { .name = "verbose", .has_arg = 0, .val = 'v' },
+ { .name = "output", .has_arg = 1, .val = 'o' },
+ { .name = "base", .has_arg = 1, .val = 'b' },
+ { .name = "align", .has_arg = 1, .val = 'a' },
+ { .name = "dfu", .has_arg = 0, .val = 'd' },
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s [--verbose=<level>] [--output=<output.bin>] [--base=<base-address>] [--align=<align>] [--dfu] <input.elf> ...\n", program);
+ exit(1);
+}
+
+static int
+ends_with(char *whole, char *suffix)
+{
+ int whole_len = strlen(whole);
+ int suffix_len = strlen(suffix);
+
+ if (suffix_len > whole_len)
+ return 0;
+ return strcmp(whole + whole_len - suffix_len, suffix) == 0;
+}
+
+static struct ao_dfu_info dfu_info = {
+ .bcdDevice = 0x0000,
+ .idProduct = 0xdf11,
+ .idVendor = 0x0483,
+};
+
+int
+main (int argc, char **argv)
+{
+ char *output = NULL;
+ struct ao_hex_image *image = NULL;
+ struct ao_sym *file_symbols;
+ int num_file_symbols;
+ FILE *file;
+ int c;
+ uint32_t base = 0xffffffff;
+ uint32_t align = 0;
+ uint32_t length;
+ int verbose = 0;
+ int dfu = 0;
+
+ while ((c = getopt_long(argc, argv, "dvo:b:a:", options, NULL)) != -1) {
+ switch (c) {
+ case 'o':
+ output = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'b':
+ base = strtoul(optarg, NULL, 0);
+ break;
+ case 'a':
+ align = strtoul(optarg, NULL, 0);
+ break;
+ case 'd':
+ dfu = 1;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ while (argv[optind]) {
+ char *input = argv[optind];
+ struct ao_hex_image *tmp;
+
+ if (ends_with (input, ".ihx"))
+ tmp = ao_hex_load(input, &file_symbols, &num_file_symbols);
+ else
+ tmp = ao_load_elf(input, &file_symbols, &num_file_symbols);
+
+ if (!tmp)
+ usage(argv[0]);
+
+ if (verbose)
+ fprintf(stderr, "%s: 0x%x %d\n", input, tmp->address, tmp->length);
+
+ if (image) {
+ image = ao_hex_image_cat(image, tmp);
+ if (!image)
+ usage(argv[0]);
+ } else
+ image = tmp;
+ optind++;
+ }
+
+ if (base != 0xffffffff && base > image->address) {
+ fprintf(stderr, "requested base 0x%x is after image address 0x%x\n",
+ base, image->address);
+ usage(argv[0]);
+ }
+
+ if (verbose)
+ fprintf(stderr, "%s: base 0x%x length %d\n", output ? output : "<stdout>", image->address, image->length);
+
+ if (!output)
+ file = stdout;
+ else {
+ file = fopen(output, "w");
+ if (!file) {
+ perror(output);
+ exit(1);
+ }
+ }
+
+ if (dfu) {
+ if (!ao_dfu_write(file, &dfu_info, 1, image)) {
+ fprintf(stderr, "%s: dfu_write failed: %s\n", output, strerror(errno));
+ if (output)
+ unlink(output);
+ exit(1);
+ }
+ } else {
+ while (base < image->address) {
+ fputc(0xff, file);
+ base++;
+ }
+
+ if (fwrite(image->data, 1, image->length, file) != image->length) {
+ fprintf(stderr, "%s: failed to write bin file\n", output ? output : "<stdout>");
+ if (output)
+ unlink(output);
+ exit(1);
+ }
+
+ if (align) {
+ length = image->length;
+
+ while (length % align) {
+ fputc(0xff, file);
+ length++;
+ }
+ }
+ fflush(file);
+ }
+
+ exit(0);
+}
diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am
index a03a976c..a33d682d 100644
--- a/ao-tools/lib/Makefile.am
+++ b/ao-tools/lib/Makefile.am
@@ -46,6 +46,8 @@ libao_tools_a_SOURCES = \
ao-editaltos.h \
ao-elf.c \
ao-elf.h \
+ ao-dfu.c \
+ ao-dfu.h \
ao-selfload.c \
ao-selfload.h \
ao-verbose.c \
diff --git a/ao-tools/lib/ao-dfu.c b/ao-tools/lib/ao-dfu.c
new file mode 100644
index 00000000..b6778495
--- /dev/null
+++ b/ao-tools/lib/ao-dfu.c
@@ -0,0 +1,202 @@
+/*
+ * 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 <stdarg.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include "ao-hex.h"
+#include "ao-dfu.h"
+
+static uint32_t dfu_crc;
+static FILE *dfu_file;
+static int dfu_failed;
+static int dfu_error;
+
+static uint32_t update_crc(uint32_t crc, uint8_t byte)
+{
+ int j;
+ uint32_t mask;
+
+ crc = crc ^ byte;
+ for (j = 0; j < 8; j++) {
+ mask = -(crc & 1);
+ crc = (crc >> 1) ^ (0xEDB88320 & mask);
+ }
+ return crc;
+}
+
+static void dfu_init(FILE *file)
+{
+ dfu_crc = 0xffffffff;
+ dfu_file = file;
+ dfu_failed = 0;
+ dfu_error = 0;
+}
+
+static int dfu_fini(void)
+{
+ if (fflush(dfu_file) == EOF) {
+ if (!dfu_failed) {
+ dfu_failed = 1;
+ dfu_error = errno;
+ }
+ }
+ if (dfu_failed)
+ errno = dfu_error;
+ return !dfu_failed;
+}
+
+static void dfu_8(uint8_t byte) {
+ if (putc(byte, dfu_file) == EOF) {
+ if (!dfu_failed) {
+ dfu_failed = 1;
+ dfu_error = errno;
+ }
+ }
+ dfu_crc = update_crc(dfu_crc, byte);
+}
+
+static void dfu_pad(int len) {
+ while (len--)
+ dfu_8(0);
+}
+
+static void dfu_string(char *string) {
+ char c;
+
+ while ((c = *string++))
+ dfu_8((uint8_t) c);
+}
+
+static void dfu_string_pad(char *string, int len) {
+ char c;
+
+ while ((c = *string++)) {
+ dfu_8((uint8_t) c);
+ len--;
+ }
+ dfu_pad(len);
+}
+
+static void dfu_block(uint8_t *bytes, int len) {
+ while (len--)
+ dfu_8(*bytes++);
+}
+
+static void dfu_lsb16(uint16_t value) {
+ dfu_8(value);
+ dfu_8(value>>8);
+}
+
+static void dfu_lsb32(uint32_t value) {
+ dfu_8(value);
+ dfu_8(value >> 8);
+ dfu_8(value >> 16);
+ dfu_8(value >> 24);
+}
+
+static uint32_t dfu_image_size(struct ao_hex_image *image) {
+ return 8 + image->length;
+}
+
+static uint32_t dfu_images_size(int num_image, struct ao_hex_image images[])
+{
+ uint32_t size = 0;
+ int i;
+
+ for (i = 0; i < num_image; i++)
+ size += dfu_image_size(&images[i]);
+ return size;
+}
+
+static void dfu_image(struct ao_hex_image *image)
+{
+ dfu_lsb32(image->address);
+ dfu_lsb32(image->length);
+ dfu_block(image->data, image->length);
+}
+
+static void dfu_target(char *name, int num_image, struct ao_hex_image images[])
+{
+ uint32_t images_size = dfu_images_size(num_image, images);
+ int i;
+
+ dfu_string("Target");
+ dfu_8(0);
+ if (name) {
+ dfu_8(1);
+ dfu_pad(3);
+ dfu_string_pad(name, 255);
+ } else {
+ dfu_8(0);
+ dfu_pad(3);
+ dfu_pad(255);
+ }
+ dfu_lsb32(images_size);
+ dfu_lsb32(num_image);
+ for (i = 0; i < num_image; i++)
+ dfu_image(&images[i]);
+}
+
+static uint32_t dfu_target_size(int num_image, struct ao_hex_image images[])
+{
+ return 274 + dfu_images_size(num_image, images);
+}
+
+static uint32_t
+dfu_size(int num_image, struct ao_hex_image images[])
+{
+ uint32_t size = 0;
+ size += 11; /* DFU Prefix */
+
+ size += dfu_target_size(num_image, images);
+
+ return size;
+}
+
+int
+ao_dfu_write(FILE *file, struct ao_dfu_info *info, int num_image, struct ao_hex_image images[])
+{
+ uint32_t total_size;
+
+ total_size = dfu_size(num_image, images);
+
+ dfu_init(file);
+ /* DFU Prefix */
+ dfu_string(DFU_SIGNATURE);
+ dfu_8(0x01);
+ dfu_lsb32(total_size);
+ dfu_8(0x01);
+
+ dfu_target("ST...", num_image, images);
+
+ /* DFU Suffix */
+ dfu_lsb16(info->bcdDevice);
+ dfu_lsb16(info->idProduct);
+ dfu_lsb16(info->idVendor);
+ dfu_lsb16(DFU_SPEC_VERSION);
+ dfu_string("UFD");
+ dfu_8(16);
+ dfu_lsb32(dfu_crc);
+ return dfu_fini();
+}
+
diff --git a/ao-tools/lib/ao-dfu.h b/ao-tools/lib/ao-dfu.h
new file mode 100644
index 00000000..c3dfc496
--- /dev/null
+++ b/ao-tools/lib/ao-dfu.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_DFU_H_
+#define _AO_DFU_H_
+
+struct ao_dfu_info {
+ uint16_t bcdDevice;
+ uint16_t idProduct;
+ uint16_t idVendor;
+};
+
+#define DFU_SIGNATURE "DfuSe"
+#define DFU_SPEC_VERSION 0x011a
+
+#define DFU_TARGET_SIGNATURE "Target"
+
+int
+ao_dfu_write(FILE *file, struct ao_dfu_info *info, int num_image, struct ao_hex_image images[]);
+
+#endif /* _AO_DFU_H_ */
diff --git a/ao-tools/lib/ao-elf.c b/ao-tools/lib/ao-elf.c
index 99b37210..680a80f0 100644
--- a/ao-tools/lib/ao-elf.c
+++ b/ao-tools/lib/ao-elf.c
@@ -206,7 +206,7 @@ get_load(Elf *e)
#endif
size_t nshdr;
size_t s;
-
+
if (elf_getshdrstrndx(e, &shstrndx) < 0)
return 0;
@@ -238,7 +238,7 @@ get_load(Elf *e)
(uint32_t) phdr.p_filesz,
(uint32_t) phdr.p_memsz);
#endif
-
+
for (s = 0; s < nshdr; s++) {
scn = elf_getscn(e, s);
@@ -256,7 +256,7 @@ get_load(Elf *e)
#endif
if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) {
-
+
if (shdr.sh_size == 0)
continue;
diff --git a/ao-tools/lib/ao-hex.c b/ao-tools/lib/ao-hex.c
index 5cfc63c1..2ceed7ab 100644
--- a/ao-tools/lib/ao-hex.c
+++ b/ao-tools/lib/ao-hex.c
@@ -294,7 +294,7 @@ load_symbols(struct ao_hex_file *hex,
struct ao_sym *symbol;
int num_symbols = 0;
int size_symbols = 0;
-
+
extended_addr = 0;
for (i = 0; i < hex->nrecord; i++) {
record = hex->records[i];
@@ -451,6 +451,31 @@ ao_hex_image_free(struct ao_hex_image *image)
free(image);
}
+uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
+uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
+
+struct ao_hex_image *
+ao_hex_image_cat(struct ao_hex_image *a, struct ao_hex_image *b)
+{
+ struct ao_hex_image *n;
+ uint32_t base, bound;
+ uint32_t length;
+
+ base = min(a->address, b->address);
+ bound = max(a->address + a->length, b->address + b->length);
+ length = bound - base;
+
+ n = calloc (sizeof (struct ao_hex_image) + length, 1);
+ if (!n)
+ return NULL;
+ n->address = base;
+ n->length = length;
+ memset(n->data, 0xff, length);
+ memcpy(n->data + a->address - n->address, a->data, a->length);
+ memcpy(n->data + b->address - n->address, b->data, b->length);
+ return n;
+}
+
int
ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b)
{
@@ -471,7 +496,7 @@ ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbolsp)
file = fopen (filename, "r");
if (!file)
return NULL;
-
+
hex_file = ao_hex_file_read(file, filename);
fclose(file);
if (!hex_file)
@@ -549,7 +574,7 @@ ao_hex_file_create(struct ao_hex_image *image, struct ao_sym *symbols, int num_s
ao_hex_record_set_checksum(record);
hex_file->records[nrecord++] = record;
-
+
/* Add the symbols
*/
@@ -616,7 +641,7 @@ ao_hex_save(FILE *file, struct ao_hex_image *image,
goto write_failed;
}
ret = true;
-
+
if (fflush(file) != 0)
ret = false;
write_failed:
diff --git a/ao-tools/lib/ao-hex.h b/ao-tools/lib/ao-hex.h
index eb510ba2..a1ab490c 100644
--- a/ao-tools/lib/ao-hex.h
+++ b/ao-tools/lib/ao-hex.h
@@ -71,6 +71,9 @@ ao_hex_image_free(struct ao_hex_image *image);
struct ao_hex_image *
ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbols);
+struct ao_hex_image *
+ao_hex_image_cat(struct ao_hex_image *a, struct ao_hex_image *b);
+
int
ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b);