summaryrefslogtreecommitdiff
path: root/ao-tools
diff options
context:
space:
mode:
Diffstat (limited to 'ao-tools')
-rw-r--r--ao-tools/Makefile.am4
-rw-r--r--ao-tools/ao-dump-up/Makefile.am12
-rw-r--r--ao-tools/ao-dump-up/ao-dump-up.145
-rw-r--r--ao-tools/ao-dump-up/ao-dump-up.c207
-rw-r--r--ao-tools/ao-dumpflash/.gitignore1
-rw-r--r--ao-tools/ao-dumpflash/Makefile.am12
-rw-r--r--ao-tools/ao-dumpflash/ao-dumpflash.171
-rw-r--r--ao-tools/ao-dumpflash/ao-dumpflash.c175
-rw-r--r--ao-tools/ao-edit-telem/Makefile.am12
-rw-r--r--ao-tools/ao-edit-telem/ao-edit-telem.133
-rw-r--r--ao-tools/ao-edit-telem/ao-edit-telem.c192
-rw-r--r--ao-tools/ao-sky-flash/Makefile.am18
-rw-r--r--ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.binbin0 -> 318000 bytes
-rw-r--r--ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.binbin0 -> 303344 bytes
-rw-r--r--ao-tools/ao-sky-flash/ao-sky-flash.185
-rw-r--r--ao-tools/ao-sky-flash/sky_bin.c73
-rw-r--r--ao-tools/ao-sky-flash/sky_debug.c111
-rw-r--r--ao-tools/ao-sky-flash/sky_flash.c259
-rw-r--r--ao-tools/ao-sky-flash/sky_flash.h67
-rw-r--r--ao-tools/ao-sky-flash/sky_serial.c257
-rw-r--r--ao-tools/ao-sky-flash/sky_srec.c60
-rw-r--r--ao-tools/ao-sky-flash/srec_115200.bin346
-rw-r--r--ao-tools/ao-sky-flash/srec_9600.bin346
-rw-r--r--ao-tools/ao-stmload/Makefile.am9
-rw-r--r--ao-tools/ao-stmload/ao-elf.c303
-rw-r--r--ao-tools/ao-stmload/ao-elf.h24
-rw-r--r--ao-tools/ao-stmload/ao-selfload.c127
-rw-r--r--ao-tools/ao-stmload/ao-stmload.c591
-rw-r--r--ao-tools/ao-stmload/ao-stmload.h49
-rw-r--r--ao-tools/ao-telem/ao-telem.c9
-rw-r--r--ao-tools/lib/cc-telemetry.c30
-rw-r--r--ao-tools/lib/cc-telemetry.h12
-rw-r--r--ao-tools/lib/cc-usb.c31
-rw-r--r--ao-tools/lib/cc-usb.h5
-rw-r--r--ao-tools/lib/cc-usbdev.c25
-rw-r--r--ao-tools/lib/cc.h116
-rw-r--r--ao-tools/lib/ccdbg-flash.c5
-rw-r--r--ao-tools/lib/ccdbg-hex.c95
-rw-r--r--ao-tools/lib/ccdbg.h7
39 files changed, 3457 insertions, 367 deletions
diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am
index 257fdaec..4600f1d6 100644
--- a/ao-tools/Makefile.am
+++ b/ao-tools/Makefile.am
@@ -1 +1,3 @@
-SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load ao-telem ao-stmload ao-send-telem
+SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list \
+ ao-load ao-telem ao-stmload ao-send-telem ao-sky-flash \
+ ao-dumpflash ao-edit-telem ao-dump-up
diff --git a/ao-tools/ao-dump-up/Makefile.am b/ao-tools/ao-dump-up/Makefile.am
new file mode 100644
index 00000000..94bb94a9
--- /dev/null
+++ b/ao-tools/ao-dump-up/Makefile.am
@@ -0,0 +1,12 @@
+bin_PROGRAMS=ao-dump-up
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS)
+AO_DUMP_LOG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_dump_up_DEPENDENCIES = $(AO_DUMP_LOG_LIBS)
+
+ao_dump_up_LDADD=$(AO_DUMP_LOG_LIBS) $(LIBUSB_LIBS) $(GNOME_LIBS)
+
+ao_dump_up_SOURCES = ao-dump-up.c
+
+man_MANS = ao-dump-up.1
diff --git a/ao-tools/ao-dump-up/ao-dump-up.1 b/ao-tools/ao-dump-up/ao-dump-up.1
new file mode 100644
index 00000000..cfa81b46
--- /dev/null
+++ b/ao-tools/ao-dump-up/ao-dump-up.1
@@ -0,0 +1,45 @@
+.\"
+.\" Copyright © 2009 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-DUMPLOG 1 "ao-dump-up" ""
+.SH NAME
+ao-dump-up \- Dump flight log from MicroPeak flight computer
+.SH SYNOPSIS
+.B "ao-dump-up"
+[\-T \fItty-device\fP]
+[\--tty \fItty-device\fP]
+[\-D \fIaltos-device\fP]
+[\--device \fIaltos-device\fP]
+.SH OPTIONS
+.TP
+\-T tty-device | --tty tty-device
+This selects which tty device ao-dump-up uses to communicate with
+the target device.
+.TP
+\-D AltOS-device | --device AltOS-device
+Search for a connected device. This forces the program to look
+for a specific USB device name.
+.SH DESCRIPTION
+.I ao-dump-up
+downloads a MicroPeak flight log from a connected MicroPeak USB adapter.
+.SH USAGE
+.I ao-dump-up
+connects to the specified target device and dumps the stored flight
+log.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-dump-up/ao-dump-up.c b/ao-tools/ao-dump-up/ao-dump-up.c
new file mode 100644
index 00000000..6268dc8b
--- /dev/null
+++ b/ao-tools/ao-dump-up/ao-dump-up.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright © 2009 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include "cc-usb.h"
+#include "cc.h"
+
+#define NUM_BLOCK 512
+
+static const struct option options[] = {
+ { .name = "tty", .has_arg = 1, .val = 'T' },
+ { .name = "device", .has_arg = 1, .val = 'D' },
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>]\n", program);
+ exit(1);
+}
+
+static uint8_t
+log_checksum(int d[8])
+{
+ uint8_t sum = 0x5a;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ sum += (uint8_t) d[i];
+ return -sum;
+}
+
+static int get_nonwhite(struct cc_usb *cc, int timeout)
+{
+ int c;
+
+ for (;;) {
+ c = cc_usb_getchar_timeout(cc, timeout);
+ putchar(c);
+ if (!isspace(c))
+ return c;
+ }
+}
+
+static uint8_t
+get_hexc(struct cc_usb *cc)
+{
+ int c = get_nonwhite(cc, 1000);
+
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+ fprintf(stderr, "Non-hex char '%c'\n", c);
+ exit(1);
+}
+
+static int file_crc;
+
+static const int POLY = 0x8408;
+
+static int
+log_crc(int crc, int b)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (((crc & 0x0001) ^ (b & 0x0001)) != 0)
+ crc = (crc >> 1) ^ POLY;
+ else
+ crc = crc >> 1;
+ b >>= 1;
+ }
+ return crc & 0xffff;
+}
+
+static uint8_t
+get_hex(struct cc_usb *cc)
+{
+ int a = get_hexc(cc);
+ int b = get_hexc(cc);
+ int h = (a << 4) + b;
+
+ file_crc = log_crc(file_crc, h);
+ return h;
+}
+
+static int get_32(struct cc_usb *cc)
+{
+ int v = 0;
+ int i;
+ for (i = 0; i < 4; i++) {
+ v += get_hex(cc) << (i * 8);
+ }
+ return v;
+}
+
+static int get_16(struct cc_usb *cc)
+{
+ int v = 0;
+ int i;
+ for (i = 0; i < 2; i++) {
+ v += get_hex(cc) << (i * 8);
+ }
+ return v;
+}
+
+static int swap16(int i)
+{
+ return ((i << 8) & 0xff00) | ((i >> 8) & 0xff);
+}
+
+static int find_header(struct cc_usb *cc)
+{
+ for (;;) {
+ if (get_nonwhite(cc, 0) == 'M' && get_nonwhite(cc, 1000) == 'P')
+ return 1;
+ }
+}
+
+static const char *state_names[] = {
+ "startup",
+ "idle",
+ "pad",
+ "boost",
+ "fast",
+ "coast",
+ "drogue",
+ "main",
+ "landed",
+ "invalid"
+};
+
+
+int
+main (int argc, char **argv)
+{
+ struct cc_usb *cc;
+ char *tty = NULL;
+ char *device = NULL;
+ int c;
+ char line[8192];
+ int nsamples;
+ int i;
+ int crc;
+ int current_crc;
+
+ while ((c = getopt_long(argc, argv, "T:D:", options, NULL)) != -1) {
+ switch (c) {
+ case 'T':
+ tty = optarg;
+ break;
+ case 'D':
+ device = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ if (!tty)
+ tty = cc_usbdevs_find_by_arg(device, "FT230X Basic UART");
+ if (!tty)
+ tty = getenv("ALTOS_TTY");
+ if (!tty)
+ tty="/dev/ttyUSB0";
+ cc = cc_usb_open(tty);
+ if (!cc)
+ exit(1);
+ find_header(cc);
+ file_crc = 0xffff;
+ get_32(cc); /* ground pressure */
+ get_32(cc); /* min pressure */
+ nsamples = get_16(cc); /* nsamples */
+ for (i = 0; i < nsamples; i++)
+ get_16(cc); /* sample i */
+ current_crc = swap16(~file_crc & 0xffff);
+ crc = get_16(cc); /* crc */
+ putchar ('\n');
+ if (crc == current_crc)
+ printf("CRC valid\n");
+ else
+ printf("CRC invalid\n");
+ cc_usb_close(cc);
+ exit (0);
+}
diff --git a/ao-tools/ao-dumpflash/.gitignore b/ao-tools/ao-dumpflash/.gitignore
new file mode 100644
index 00000000..bbce511a
--- /dev/null
+++ b/ao-tools/ao-dumpflash/.gitignore
@@ -0,0 +1 @@
+ao-dumpflash
diff --git a/ao-tools/ao-dumpflash/Makefile.am b/ao-tools/ao-dumpflash/Makefile.am
new file mode 100644
index 00000000..db99f5ae
--- /dev/null
+++ b/ao-tools/ao-dumpflash/Makefile.am
@@ -0,0 +1,12 @@
+bin_PROGRAMS=ao-dumpflash
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_DUMPLOG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_dumpflash_DEPENDENCIES = $(AO_DUMPLOG_LIBS)
+
+ao_dumpflash_LDADD=$(AO_DUMPLOG_LIBS) $(LIBUSB_LIBS)
+
+ao_dumpflash_SOURCES = ao-dumpflash.c
+
+man_MANS = ao-dumpflash.1
diff --git a/ao-tools/ao-dumpflash/ao-dumpflash.1 b/ao-tools/ao-dumpflash/ao-dumpflash.1
new file mode 100644
index 00000000..07a08ba8
--- /dev/null
+++ b/ao-tools/ao-dumpflash/ao-dumpflash.1
@@ -0,0 +1,71 @@
+.\"
+.\" 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-DUMPFLASH 1 "ao-dumpflash" ""
+.SH NAME
+ao-dumpflash \- Fetch flash memory contents from AltOS device
+.SH SYNOPSIS
+.B "ao-dumpflash"
+[\--tty \fItty-device\fP]
+[\--device \fIaltos-device\fP]
+[\--output \fIoutput-file\fP]
+[\--remote\fP]
+[\--frequency \fIfrequency\fP]
+[\--call \fIcallsign\fP]
+.SH OPTIONS
+.TP
+\-T tty-device | --tty tty-device
+This selects which tty device ao-dumpflash uses to communicate with
+the target device.
+.TP
+\-D AltOS-device | --device AltOS-device
+Search for a connected device. This requires an argument of one of the
+following forms:
+.IP
+TeleMetrum:2
+.br
+TeleMetrum
+.br
+2
+.IP
+Leaving out the product name will cause the tool to select a suitable
+product, leaving out the serial number will cause the tool to match
+one of the available devices.
+.TP
+\-o output-file | --output output-file
+Write flash contents to the specified file rather than stdout.
+.TP
+\-R | --remote
+This uses the command radio link to download the flash from TeleMetrum
+through a TeleDongle.
+.TP
+\-F frequency | --frequency frequency
+Specifies the radio frequency to use for remote communications in
+kHz. Default is 434550.
+.TP
+\-C callsign | --call callsign
+Specifies the callsign to use for remote communications. Default is N0CALL.
+.SH DESCRIPTION
+.I ao-dumpflash
+downloads the entire flash memory contents from a connected AltOS device and writes
+it to either stdout or the specified output file.
+.SH USAGE
+.I ao-dumpflash
+connects to the specified target device and dumps the flash.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-dumpflash/ao-dumpflash.c b/ao-tools/ao-dumpflash/ao-dumpflash.c
new file mode 100644
index 00000000..3cd21e66
--- /dev/null
+++ b/ao-tools/ao-dumpflash/ao-dumpflash.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright © 2009 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include "cc-usb.h"
+#include "cc.h"
+
+#define NUM_BLOCK 512
+
+static const struct option options[] = {
+ { .name = "tty", .has_arg = 1, .val = 'T' },
+ { .name = "device", .has_arg = 1, .val = 'D' },
+ { .name = "remote", .has_arg = 0, .val = 'R' },
+ { .name = "frequency", .has_arg = 1, .val = 'F' },
+ { .name = "call", .has_arg = 1, .val = 'C' },
+ { .name = "output", .has_arg = 1, .val = 'o' },
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>] [--remote] [--frequency <radio-frequency>] [--call <radio-callsign>]\n", program);
+ exit(1);
+}
+
+int
+main (int argc, char **argv)
+{
+ struct cc_usb *cc;
+ char *tty = NULL;
+ char *device = NULL;
+ int c;
+ char line[8192];
+ FILE *out;
+ char *filename;
+ int serial_number = 0;
+ int freq = 434550;
+ char *call = "N0CALL";
+ int flight = 0;
+ char cmd;
+ int block;
+ int addr;
+ int received_addr;
+ int data[8];
+ int done;
+ int i;
+ int column;
+ int remote = 0;
+ int any_valid;
+ int invalid;
+ int storage_size = 0;
+ char *out_name;
+
+ while ((c = getopt_long(argc, argv, "T:D:F:C:o:R", options, NULL)) != -1) {
+ switch (c) {
+ case 'T':
+ tty = optarg;
+ break;
+ case 'D':
+ device = optarg;
+ break;
+ case 'R':
+ remote = 1;
+ break;
+ case 'F':
+ freq = atoi(optarg);
+ break;
+ case 'C':
+ call = optarg;
+ break;
+ case 'o':
+ out_name = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ if (!tty) {
+ if (remote)
+ tty = cc_usbdevs_find_by_arg(device, "TeleDongle");
+ else
+ tty = cc_usbdevs_find_by_arg(device, "TeleMetrum");
+ }
+ if (!tty)
+ tty = getenv("ALTOS_TTY");
+ if (!tty)
+ tty="/dev/ttyACM0";
+
+ cc = cc_usb_open(tty);
+ if (!cc)
+ exit(1);
+ if (remote)
+ cc_usb_open_remote(cc, freq, call);
+
+ if (out_name) {
+ out = fopen(out_name, "w");
+ if (!out) {
+ perror(out_name);
+ cc_usb_close(cc);
+ exit(1);
+ }
+ } else
+ out = stdout;
+
+ /* send a 'version' command followed by a 'flash' command */
+ cc_usb_printf(cc, "f\nv\n");
+ for (;;) {
+ cc_usb_getline(cc, line, sizeof (line));
+ if (sscanf(line, "serial-number %u", &serial_number) == 1)
+ continue;
+ if (sscanf(line, "Storage size: %u", &storage_size) == 1)
+ continue;
+ if (!strncmp(line, "software-version", 16))
+ break;
+ }
+ if (!serial_number) {
+ fprintf(stderr, "no serial number found\n");
+ cc_usb_close(cc);
+ exit(1);
+ }
+ if (!storage_size) {
+ fprintf(stderr, "no storage size found\n");
+ cc_usb_close(cc);
+ exit(1);
+ }
+ printf ("Serial number: %d\n", serial_number);
+ printf ("Storage size: %d\n", storage_size);
+ fprintf (stderr, "%7d of %7d", 0, storage_size/256);
+ for (block = 0; block < storage_size / 256; block++) {
+ cc_usb_printf(cc, "e %x\n", block);
+ fprintf (stderr, "\r%7d of %7d", block + 1, storage_size/256); fflush(stderr);
+ for (addr = 0; addr < 0x100;) {
+ cc_usb_getline(cc, line, sizeof (line));
+ if (sscanf(line, "00%x %x %x %x %x %x %x %x %x",
+ &received_addr,
+ &data[0], &data[1], &data[2], &data[3],
+ &data[4], &data[5], &data[6], &data[7]) == 9)
+ {
+ if (received_addr != addr)
+ fprintf(stderr, "data out of sync at 0x%x\n",
+ block * 256 + received_addr);
+
+ fprintf (out, "%08x", block * 256 + addr);
+ for (i = 0; i < 8; i++)
+ fprintf (out, " %02x", data[i]);
+ fprintf (out, "\n");
+
+ addr += 8;
+ }
+ }
+ }
+ fprintf(stderr, "\n");
+ cc_usb_close(cc);
+ exit (0);
+}
diff --git a/ao-tools/ao-edit-telem/Makefile.am b/ao-tools/ao-edit-telem/Makefile.am
new file mode 100644
index 00000000..c5965c47
--- /dev/null
+++ b/ao-tools/ao-edit-telem/Makefile.am
@@ -0,0 +1,12 @@
+bin_PROGRAMS=ao-edit-telem
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_edit_telem_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
+
+ao_edit_telem_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS)
+
+ao_edit_telem_SOURCES = ao-edit-telem.c
+
+man_MANS = ao-edit-telem.1
diff --git a/ao-tools/ao-edit-telem/ao-edit-telem.1 b/ao-tools/ao-edit-telem/ao-edit-telem.1
new file mode 100644
index 00000000..8f125878
--- /dev/null
+++ b/ao-tools/ao-edit-telem/ao-edit-telem.1
@@ -0,0 +1,33 @@
+.\"
+.\" 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-EDIT-TELEM 1 "ao-edit-telem" ""
+.SH NAME
+ao-edit-telem \- Edit telemetry file, creating new telemetry stream
+.SH SYNOPSIS
+.B "ao-edit-telem"
+[\--lat=<pad-lat>]
+[\--lon=<pad-lon>]
+{flight.telem}
+.SH DESCRIPTION
+.I ao-edit-telem
+reads the specified telemetry log and produces a new telemetry log,
+changed as directed by the options provided.
+output.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-edit-telem/ao-edit-telem.c b/ao-tools/ao-edit-telem/ao-edit-telem.c
new file mode 100644
index 00000000..3f6830e7
--- /dev/null
+++ b/ao-tools/ao-edit-telem/ao-edit-telem.c
@@ -0,0 +1,192 @@
+/*
+ * 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; 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.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include "cc.h"
+
+static const struct option options[] = {
+ { .name = "lat", .has_arg = 1, .val = 'L' },
+ { .name = "lon", .has_arg = 1, .val = 'l' },
+ { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+ fprintf(stderr, "usage: %s [--lat <pad-lat>] [--lon <pad-lon>]\n"
+ "\t{flight-log} ...\n", program);
+ exit(1);
+}
+
+#define bool(b) ((b) ? "true" : "false")
+
+struct telem_ent {
+ struct telem_ent *next;
+ union ao_telemetry_all telem;
+};
+
+static struct telem_ent *pad, **last = &pad;
+
+static void
+save_telem(union ao_telemetry_all *telem)
+{
+ struct telem_ent *t = malloc (sizeof *t);
+ t->telem = *telem;
+ t->next = NULL;
+ *last = t;
+ last = &t->next;
+}
+
+static void
+dump_telem(union ao_telemetry_all *telem)
+{
+ char s[CC_TELEMETRY_BUFSIZE];
+
+ cc_telemetry_unparse(telem, s);
+ printf("%s\n", s);
+}
+
+double pad_lat = 0, pad_lon = 0;
+double target_pad_lat = 0, target_pad_lon = 0;
+double lat_off = 0, lon_off = 0;
+int pending = 1;
+
+static void
+dump_saved(void);
+
+void
+doit(union ao_telemetry_all *telem)
+{
+ double lat, lon;
+
+ switch (telem->generic.type) {
+ case AO_TELEMETRY_SENSOR_TELEMETRUM:
+ case AO_TELEMETRY_SENSOR_TELEMINI:
+ case AO_TELEMETRY_SENSOR_TELENANO:
+ if (telem->sensor.state > ao_flight_pad && pad) {
+ pending = 0;
+ if (target_pad_lat)
+ lat_off = target_pad_lat - pad_lat;
+ if (target_pad_lon)
+ lon_off = target_pad_lon - pad_lon;
+ dump_saved();
+ }
+ break;
+ case AO_TELEMETRY_LOCATION: {
+ lat = telem->location.latitude / 1.0e7;
+ lon = telem->location.longitude / 1.0e7;
+ if (pending) {
+ if (telem->location.flags & (1 << 4)) {
+ if (pad_lat) {
+ pad_lat = pad_lat - pad_lat / 32 + lat / 32.0;
+ pad_lon = pad_lon - pad_lon / 32 + lon / 32.0;
+ } else {
+ pad_lat = lat;
+ pad_lon = lon;
+ }
+ }
+ } else {
+ lat += lat_off;
+ lon += lon_off;
+ if (lat > 90)
+ lat = 90;
+ if (lat < -90)
+ lat = -90;
+ while (lon > 180)
+ lon -= 360;
+ while (lon < -180)
+ lon += 360;
+ telem->location.latitude = lat * 1.0e7;
+ telem->location.longitude = lon * 1.0e7;
+ }
+ break;
+ }
+ }
+}
+
+static void
+dump_saved(void)
+{
+ struct telem_ent *t, *n;
+
+ for (t = pad; t; t = n) {
+ n = t->next;
+ doit(&t->telem);
+ dump_telem(&t->telem);
+ free(t);
+ }
+ pad = NULL;
+ last = &pad;
+}
+
+int
+main (int argc, char **argv)
+{
+ char line[80];
+ int c, i, ret;
+ char *s;
+ FILE *file;
+ int serial;
+ while ((c = getopt_long(argc, argv, "l:L:", options, NULL)) != -1) {
+ switch (c) {
+ case 'L':
+ target_pad_lat = strtod(optarg, NULL);
+ break;
+ case 'l':
+ target_pad_lon = strtod(optarg, NULL);
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ for (i = optind; i < argc; i++) {
+ file = fopen(argv[i], "r");
+ if (!file) {
+ perror(argv[i]);
+ ret++;
+ continue;
+ }
+ s = strstr(argv[i], "-serial-");
+ if (s)
+ serial = atoi(s + 8);
+ else
+ serial = 0;
+ while (fgets(line, sizeof (line), file)) {
+ union ao_telemetry_all telem;
+
+ if (cc_telemetry_parse(line, &telem)) {
+ if ((telem.generic.status & (1 << 7)) == 0) {
+ dump_telem(&telem);
+ continue;
+ }
+ doit (&telem);
+ if (pending)
+ save_telem(&telem);
+ else
+ dump_telem(&telem);
+ }
+ }
+ fclose (file);
+
+ }
+ return ret;
+}
diff --git a/ao-tools/ao-sky-flash/Makefile.am b/ao-tools/ao-sky-flash/Makefile.am
new file mode 100644
index 00000000..f6c5089a
--- /dev/null
+++ b/ao-tools/ao-sky-flash/Makefile.am
@@ -0,0 +1,18 @@
+bin_PROGRAMS=ao-sky-flash
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_SKY_FLASH_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_sky_flash_DEPENDENCIES = $(AO_SKY_FLASH_LIBS)
+
+ao_sky_flash_LDADD=$(AO_SKY_FLASH_LIBS) $(LIBUSB_LIBS)
+
+ao_sky_flash_SOURCES = \
+ sky_bin.c \
+ sky_debug.c \
+ sky_flash.c \
+ sky_flash.h \
+ sky_serial.c \
+ sky_srec.c
+
+man_MANS = ao-sky-flash.1
diff --git a/ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin b/ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin
new file mode 100644
index 00000000..c698add2
--- /dev/null
+++ b/ao-tools/ao-sky-flash/STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin
Binary files differ
diff --git a/ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin b/ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin
new file mode 100644
index 00000000..9e256897
--- /dev/null
+++ b/ao-tools/ao-sky-flash/STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin
Binary files differ
diff --git a/ao-tools/ao-sky-flash/ao-sky-flash.1 b/ao-tools/ao-sky-flash/ao-sky-flash.1
new file mode 100644
index 00000000..d61c9c9d
--- /dev/null
+++ b/ao-tools/ao-sky-flash/ao-sky-flash.1
@@ -0,0 +1,85 @@
+.\"
+.\" Copyright © 2009 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-SKY-FLASH 1 "ao-sky-flash" ""
+.SH NAME
+ao-sky-flash \- flash GPS firmware program to a SkyTraq GPS chip
+.SH SYNOPSIS
+.B "ao-sky-flash"
+[\-T \fItty-device\fP]
+[\--tty \fItty-device\fP]
+[\-D \fIaltos-device\fP]
+[\--device \fIaltos-device\fP]
+[\--loader \fIboot-loader\fP]
+[\--firmware \fIgps-firmware\fP]
+[\--query]
+[\--quiet]
+[\--raw]
+.SH DESCRIPTION
+.I ao-sky-flash
+loads the specified GPS firmware file into the target GPS chip flash
+memory using the specified boot loader.
+.SH OPTIONS
+.TP
+\-T tty-device | --tty tty-device
+This selects which tty device the debugger uses to communicate with
+the target device.
+.TP
+\-D AltOS-device | --device AltOS-device
+Search for a connected device. This requires an argument of one of the
+following forms:
+.IP
+TeleMetrum:2
+.br
+TeleMetrum
+.br
+2
+.IP
+Leaving out the product name will cause the tool to select a suitable
+product, leaving out the serial number will cause the tool to match
+one of the available devices.
+.TP
+\--loader boot-loader
+This specifies the desired boot loader to use for reflashing the
+device. You should use srec_115200.bin unless you have a good reason
+not to. This should be in S record format.
+.TP
+\--firmware gps-firmware
+This specifies the new GPS firmware image to load onto the target GPS
+chip. No checking is done on this device at all; flash garbage and the
+GPS chip will probably fail to boot.
+.TP
+\--query
+Instead of loading new firmware, query the current version of firmware
+running on the target device.
+.TP
+\--quiet
+Normally, ao-spy-flash is quite chatty. This shuts it up, except for
+error messages.
+.TP
+\--raw
+The expected target for reflashing is an Altus Metrum product with the
+GPS chip connected to the CPU on that board and not directly to the
+USB serial port. This option says that the target GPS chip is directly
+connected, which changes how things are initialized a bit.
+.SH USAGE
+.I ao-sky-flash
+loads the specified bootloader into device RAM and then uses that to
+load new firmware to flash.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-sky-flash/sky_bin.c b/ao-tools/ao-sky-flash/sky_bin.c
new file mode 100644
index 00000000..04cfec35
--- /dev/null
+++ b/ao-tools/ao-sky-flash/sky_bin.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2012 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 "sky_flash.h"
+#include <stdio.h>
+#include <string.h>
+
+#define FLASHBYTES 8192
+
+int
+skytraq_send_bin(int fd, const char *filename)
+{
+ FILE *file;
+ char buf[FLASHBYTES];
+ int count;
+ unsigned char cksum;
+ int c;
+ long size;
+ long pos;
+ char message[1024];
+ int ret;
+
+ file = fopen(filename, "r");
+ if (!file) {
+ perror(filename);
+ return -1;
+ }
+
+ /* Compute checksum, figure out how long the file */
+ cksum = 0;
+ while ((c = getc(file)) != EOF)
+ cksum += (unsigned char) c;
+ size = ftell(file);
+ rewind(file);
+
+ sprintf(message, "BINSIZE = %d Checksum = %d Loopnumber = %d ", size, cksum, 1);
+
+ ret = skytraq_cmd_wait(fd, message, strlen(message) + 1, "OK", 20000);
+ if (ret < 0)
+ printf ("waitstatus failed %d\n", ret);
+
+ pos = 0;
+ for (;;) {
+ count = fread(buf, 1, sizeof (buf), file);
+ if (count < 0) {
+ perror("fread");
+ fclose(file);
+ return -1;
+ }
+ if (count == 0)
+ break;
+ skytraq_dbg_printf (0, "%7d of %7d ", pos + count, size);
+ pos += count;
+ ret = skytraq_cmd_wait(fd, buf, count, "OK", 20000);
+ if (ret < 0)
+ return ret;
+ }
+ return skytraq_waitstatus(fd, "END", 30000);
+}
diff --git a/ao-tools/ao-sky-flash/sky_debug.c b/ao-tools/ao-sky-flash/sky_debug.c
new file mode 100644
index 00000000..32571f0e
--- /dev/null
+++ b/ao-tools/ao-sky-flash/sky_debug.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2012 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 <stdint.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include "sky_flash.h"
+
+static int dbg_input;
+static int dbg_newline = 1;
+
+int
+skytraq_millis(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+static void
+skytraq_dbg_time(void)
+{
+ int delta = skytraq_millis() - skytraq_open_time;
+
+ if (!skytraq_verbose)
+ return;
+ printf ("%4d.%03d ", delta / 1000, delta % 1000);
+}
+
+void
+skytraq_dbg_newline(void)
+{
+ if (!skytraq_verbose)
+ return;
+ if (!dbg_newline) {
+ putchar('\n');
+ dbg_newline = 1;
+ }
+}
+
+static void
+skytraq_dbg_set(int input)
+{
+ if (!skytraq_verbose)
+ return;
+ if (input != dbg_input) {
+ skytraq_dbg_newline();
+ if (input)
+ putchar('\t');
+ dbg_input = input;
+ }
+}
+
+void
+skytraq_dbg_char(int input, char c)
+{
+ if (!skytraq_verbose)
+ return;
+ skytraq_dbg_set(input);
+ if (dbg_newline)
+ skytraq_dbg_time();
+ if (c < ' ' || c > '~')
+ printf ("\\%02x", (unsigned char) c);
+ else
+ putchar(c);
+ dbg_newline = 0;
+ if (c == '\n')
+ dbg_input = 2;
+ fflush(stdout);
+}
+
+void
+skytraq_dbg_buf(int input, const char *buf, int len)
+{
+ if (!skytraq_verbose)
+ return;
+ while (len--)
+ skytraq_dbg_char(input, *buf++);
+}
+
+void
+skytraq_dbg_printf(int input, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!skytraq_verbose)
+ return;
+ skytraq_dbg_set(input);
+ if (dbg_newline)
+ skytraq_dbg_time();
+ va_start (ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ dbg_newline = 0;
+}
diff --git a/ao-tools/ao-sky-flash/sky_flash.c b/ao-tools/ao-sky-flash/sky_flash.c
new file mode 100644
index 00000000..55cb2cb6
--- /dev/null
+++ b/ao-tools/ao-sky-flash/sky_flash.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright © 2012 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 "sky_flash.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include "cc.h"
+
+static const struct option options[] = {
+ { .name = "tty", .has_arg = 1, .val = 'T' },
+ { .name = "device", .has_arg = 1, .val = 'D' },
+ { .name = "loader", .has_arg = 1, .val = 'l' },
+ { .name = "firmware", .has_arg = 1, .val = 'f' },
+ { .name = "query", .has_arg = 0, .val = 'q' },
+ { .name = "raw", .has_arg = 0, .val = 'r' },
+ { .name = "quiet", .has_arg = 0, .val = 'Q' },
+ { 0, 0, 0, 0},
+};
+
+static uint8_t query_version[] = {
+ 0xa0, 0xa1, 0x00, 0x02, 0x02, 0x01, 0x03, 0x0d, 0x0a
+};
+
+static void
+usage(char *program)
+{
+ fprintf(stderr,
+ "usage: %s [--tty <tty-name>]\n"
+ " [--device <device-name>]\n"
+ " [--loader <srec bootloader file>]\n"
+ " [--firmware <binary firmware file>]\n"
+ " [--query]\n"
+ " [--quiet]\n"
+ " [--raw]\n", program);
+ exit(1);
+}
+
+int
+skytraq_expect(int fd, uint8_t want, int timeout) {
+ int c;
+
+ c = skytraq_waitchar(fd, timeout);
+ if (c < 0)
+ return -1;
+ if (c == want)
+ return 1;
+ return 0;
+}
+
+int
+skytraq_wait_reply(int fd, uint8_t reply, uint8_t *buf, uint8_t reply_len) {
+
+ for(;;) {
+ uint8_t a, b;
+ uint8_t cksum_computed, cksum_read;
+ int len;
+ switch (skytraq_expect(fd, 0xa0, 10000)) {
+ case -1:
+ return -1;
+ case 0:
+ continue;
+ case 1:
+ break;
+ }
+ switch (skytraq_expect(fd, 0xa1, 1000)) {
+ case -1:
+ return -1;
+ case 0:
+ continue;
+ }
+ a = skytraq_waitchar(fd, 1000);
+ b = skytraq_waitchar(fd, 1000);
+ switch (skytraq_expect(fd, reply, 1000)) {
+ case -1:
+ return -1;
+ case 0:
+ continue;
+ }
+ len = (a << 16) | b;
+ if (len != reply_len)
+ continue;
+ *buf++ = reply;
+ len--;
+ cksum_computed = reply;
+ while (len--) {
+ a = skytraq_waitchar(fd, 1000);
+ if (a < 0)
+ return a;
+ cksum_computed ^= a;
+ *buf++ = a;
+ }
+ switch (skytraq_expect(fd, cksum_computed, 1000)) {
+ case -1:
+ return -1;
+ case 0:
+ continue;
+ }
+ switch (skytraq_expect(fd, 0x0d, 1000)) {
+ case -1:
+ return -1;
+ case 0:
+ continue;
+ }
+ switch (skytraq_expect(fd, 0x0a, 1000)) {
+ case -1:
+ return -1;
+ case 0:
+ continue;
+ }
+ break;
+ }
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ int fd;
+ char buf[512];
+ int ret;
+ FILE *input;
+ long size;
+ unsigned char cksum;
+ int c;
+ char message[1024];
+ char *tty = NULL;
+ char *device = NULL;
+ char *loader = "srec_115200.bin";
+ char *file = NULL;
+ int query = 0;
+ int raw = 0;
+
+ while ((c = getopt_long(argc, argv, "T:D:l:f:qQr", options, NULL)) != -1) {
+ switch (c) {
+ case 'T':
+ tty = optarg;
+ break;
+ case 'D':
+ device = optarg;
+ break;
+ case 'l':
+ loader = optarg;
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ case 'q':
+ query = 1;
+ break;
+ case 'Q':
+ skytraq_verbose = 0;
+ break;
+ case 'r':
+ raw = 1;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (!tty)
+ tty = cc_usbdevs_find_by_arg(device, "TeleMetrum");
+ if (!tty)
+ tty = getenv("ALTOS_TTY");
+ if (!tty)
+ tty="/dev/ttyACM0";
+ fd = skytraq_open(tty);
+ if (fd < 0)
+ exit(1);
+
+ if (raw) {
+ /* Set the baud rate to 115200 */
+ skytraq_setcomm(fd, 115200);
+ sleep(1);
+ skytraq_setspeed(fd, 115200);
+ } else {
+ /* Connect TM to the device */
+ skytraq_write(fd, "U\n", 2);
+ }
+
+ /* Wait for the device to stabilize after baud rate changes */
+ for (c = 0; c < 6; c++) {
+ skytraq_flush(fd);
+ sleep(1);
+ }
+
+ if (query) {
+ uint8_t query_reply[14];
+
+ uint8_t software_type;
+ uint32_t kernel_version;
+ uint32_t odm_version;
+ uint32_t revision;
+
+ skytraq_write(fd, query_version, 9);
+ if (skytraq_wait_reply(fd, 0x80, query_reply, sizeof (query_reply)) != 0) {
+ fprintf(stderr, "query reply failed\n");
+ exit(1);
+ }
+
+#define i8(o) query_reply[(o)-1]
+#define i32(o) ((i8(o) << 24) | (i8(o+1) << 16) | (i8(o+2) << 8) | (i8(o+3)))
+ software_type = i8(2);
+ kernel_version = i32(3);
+ odm_version = i32(7);
+ revision = i32(11);
+ skytraq_dbg_printf(0, "\n");
+ printf ("Software Type %d. Kernel Version %d.%d.%d. ODM Version %d.%d.%d. Revision %d.%d.%d.\n",
+ software_type,
+ kernel_version >> 16 & 0xff,
+ kernel_version >> 8 & 0xff,
+ kernel_version >> 0 & 0xff,
+ odm_version >> 16 & 0xff,
+ odm_version >> 8 & 0xff,
+ odm_version >> 0 & 0xff,
+ revision >> 16 & 0xff,
+ revision >> 8 & 0xff,
+ revision >> 0 & 0xff);
+ exit(0);
+ }
+
+ if (!file)
+ usage(argv[0]);
+
+ ret = skytraq_send_srec(fd, "srec_115200.bin");
+ skytraq_dbg_printf (0, "srec ret %d\n", ret);
+ if (ret < 0)
+ exit(1);
+
+ sleep(2);
+
+// ret = skytraq_send_bin(fd, "STI_01.04.42-01.10.23_4x_9600_Bin_20100901.bin");
+ ret = skytraq_send_bin(fd, "STI_01.06.10-01.07.23_balloon_CRC_7082_9600_20120913.bin");
+
+ printf ("bin ret %d\n", ret);
+ if (ret < 0)
+ exit(1);
+
+ return 0;
+}
diff --git a/ao-tools/ao-sky-flash/sky_flash.h b/ao-tools/ao-sky-flash/sky_flash.h
new file mode 100644
index 00000000..77f4c742
--- /dev/null
+++ b/ao-tools/ao-sky-flash/sky_flash.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+/* sky_serial.c */
+
+extern int skytraq_open_time;
+extern int skytraq_verbose;
+
+int
+skytraq_open(const char *path);
+
+int
+skytraq_setspeed(int fd, int baud);
+
+int
+skytraq_setcomm(int fd, int baudrate);
+
+int
+skytraq_write(int fd, const char *data, int len);
+
+int
+skytraq_waitchar(int fd, int timeout);
+
+int
+skytraq_waitstatus(int fd, const char *status, int timeout);
+
+void
+skytraq_flush(int fd);
+
+int
+skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout);
+
+int
+skytraq_cmd_nowait(int fd, const char *message, int len);
+
+/* sky_debug.c */
+
+void
+skytraq_dbg_printf(int input, const char *fmt, ...);
+
+void
+skytraq_dbg_buf(int input, const char *buf, int len);
+
+void
+skytraq_dbg_char(int input, char c);
+
+/* sky_srec.c */
+int
+skytraq_send_srec(int fd, const char *file);
+
+/* sky_bin.c */
+int
+skytraq_send_bin(int fd, const char *filename);
diff --git a/ao-tools/ao-sky-flash/sky_serial.c b/ao-tools/ao-sky-flash/sky_serial.c
new file mode 100644
index 00000000..7230bf8c
--- /dev/null
+++ b/ao-tools/ao-sky-flash/sky_serial.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+#define _BSD_SOURCE
+#include <termios.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <poll.h>
+#include "sky_flash.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+int skytraq_verbose = 1;
+
+int
+skytraq_setspeed(int fd, int baud)
+{
+ int b;
+ int ret;
+ struct termios term;
+
+ switch (baud) {
+ case 9600:
+ b = B9600;
+ break;
+ case 38400:
+ b = B38400;
+ break;
+ case 115200:
+ b = B115200;
+ break;
+ default:
+ fprintf (stderr, "Invalid baudrate %d\n", baud);
+ return -1;
+ }
+ ret = tcgetattr(fd, &term);
+ cfmakeraw(&term);
+#ifdef USE_POLL
+ term.c_cc[VMIN] = 1;
+ term.c_cc[VTIME] = 0;
+#else
+ term.c_cc[VMIN] = 0;
+ term.c_cc[VTIME] = 1;
+#endif
+
+ cfsetspeed(&term, b);
+
+ ret = tcsetattr(fd, TCSAFLUSH, &term);
+ return ret;
+}
+
+int skytraq_open_time;
+
+int
+skytraq_open(const char *path)
+{
+ int fd;
+ int ret;
+
+ fd = open(path, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ perror (path);
+ return -1;
+ }
+
+ ret = skytraq_setspeed(fd, 9600);
+ if (ret < 0) {
+ close (fd);
+ return -1;
+ }
+ skytraq_open_time = skytraq_millis();
+ return fd;
+}
+
+
+#define BAUD 57600
+#define BPS (BAUD/10 * 9/10)
+#define US_PER_CHAR (1000000 / BPS)
+
+int
+skytraq_write(int fd, const char *data, int len)
+{
+ const char *d = data;
+ int r;
+ int us;
+
+ skytraq_dbg_printf (0, "%4d: ", len);
+ if (len < 70)
+ skytraq_dbg_buf(0, data, len);
+ while (len) {
+ int this_time = len;
+ if (this_time > 128)
+ this_time = 128;
+ skytraq_dbg_printf(0, ".");
+ fflush(stdout);
+ r = write(fd, data, this_time);
+ if (r <= 0)
+ return r;
+ us = r * US_PER_CHAR;
+ usleep(r * US_PER_CHAR);
+ data += r;
+ len -= r;
+ }
+ skytraq_dbg_newline();
+ return 1;
+}
+
+int
+skytraq_setcomm(int fd, int baudrate)
+{
+ uint8_t msg[11];
+ int i;
+ uint8_t cksum;
+
+ int target_baudrate;
+ switch(baudrate)
+ {
+ case 4800:
+ target_baudrate=0;
+ break;
+ case 9600:
+ target_baudrate=1;
+ break;
+ case 19200:
+ target_baudrate=2;
+ break;
+ case 38400:
+ target_baudrate=3;
+ break;
+ case 57600:
+ target_baudrate=4;
+ break;
+ case 115200:
+ target_baudrate=5;
+ break;
+ case 230400:
+ target_baudrate=6;
+ break;
+ }
+ msg[0] = 0xa0; /* header */
+ msg[1] = 0xa1;
+ msg[2] = 0x00; /* length */
+ msg[3] = 0x04;
+ msg[4] = 0x05; /* configure serial port */
+ msg[5] = 0x00; /* COM 1 */
+ msg[6] = target_baudrate;
+ msg[7] = 0x00; /* update to SRAM only */
+
+ cksum = 0;
+ for (i = 4; i < 8; i++)
+ cksum ^= msg[i];
+ msg[8] = cksum;
+ msg[9] = 0x0d;
+ msg[10] = 0x0a;
+ return skytraq_write(fd, msg, 11);
+}
+
+int
+skytraq_waitchar(int fd, int timeout)
+{
+ struct pollfd fds[1];
+ int ret;
+ unsigned char c;
+
+ for (;;) {
+ fds[0].fd = fd;
+ fds[0].events = POLLIN;
+ ret = poll(fds, 1, timeout);
+ if (ret >= 1) {
+ if (fds[0].revents & POLLIN) {
+ ret = read(fd, &c, 1);
+ if (ret == 1) {
+ skytraq_dbg_char(1, c);
+ return c;
+ }
+ }
+ } else if (ret == 0)
+ return -2;
+ else {
+ perror("poll");
+ return -1;
+ }
+ }
+}
+
+int
+skytraq_waitstatus(int fd, const char *status, int timeout)
+{
+ const char *s;
+ int c;
+
+ for (;;) {
+ c = skytraq_waitchar(fd, timeout);
+ if (c < 0) {
+ skytraq_dbg_newline();
+ return c;
+ }
+ if ((char) c == *status) {
+ s = status + 1;
+ for (;;) {
+ c = skytraq_waitchar(fd, timeout);
+ if (c < 0) {
+ skytraq_dbg_newline();
+ return c;
+ }
+ if ((char) c != *s)
+ break;
+ if (!*s) {
+ skytraq_dbg_newline();
+ return 0;
+ }
+ s++;
+ }
+ }
+ }
+}
+
+void
+skytraq_flush(int fd)
+{
+ while (skytraq_waitchar(fd, 1) >= 0)
+ ;
+}
+
+int
+skytraq_cmd_wait(int fd, const char *message, int len, const char *status, int timeout)
+{
+ skytraq_flush(fd);
+ skytraq_write(fd, message, len);
+ return skytraq_waitstatus(fd, status, timeout);
+}
+
+int
+skytraq_cmd_nowait(int fd, const char *message, int len)
+{
+ skytraq_flush(fd);
+ return skytraq_write(fd, message, len);
+}
diff --git a/ao-tools/ao-sky-flash/sky_srec.c b/ao-tools/ao-sky-flash/sky_srec.c
new file mode 100644
index 00000000..6d00f58c
--- /dev/null
+++ b/ao-tools/ao-sky-flash/sky_srec.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2012 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 "sky_flash.h"
+#include <stdio.h>
+#include <string.h>
+
+static const char loader_start[] = "$LOADER DOWNLOAD";
+
+int
+skytraq_send_srec(int fd, const char *filename)
+{
+ FILE *file;
+ int ret;
+ char line[1024];
+
+ file = fopen(filename, "r");
+ if (!file) {
+ perror(filename);
+ return -1;
+ }
+
+ ret = skytraq_cmd_wait(fd, loader_start, strlen(loader_start) + 1, "OK", 1000);
+ if (ret)
+ return ret;
+
+ for (;;) {
+ char *s;
+ int len;
+
+ s = fgets(line, sizeof(line), file);
+ if (!s)
+ break;
+ len = strlen(s);
+ if (len < 3) /* Terminated with \r\n */
+ break;
+ s[len-2] = '\n'; /* Smash \r */
+ s[len-1] = '\0'; /* Smash \n */
+ skytraq_cmd_nowait(fd, s, len);
+ }
+ fclose(file);
+
+ ret = skytraq_waitstatus(fd, "END", 10000);
+ skytraq_dbg_newline();
+ return ret;
+}
diff --git a/ao-tools/ao-sky-flash/srec_115200.bin b/ao-tools/ao-sky-flash/srec_115200.bin
new file mode 100644
index 00000000..8ea8e7cd
--- /dev/null
+++ b/ao-tools/ao-sky-flash/srec_115200.bin
@@ -0,0 +1,346 @@
+S0130000666C6173683131353230302E73726563DA
+S31550000000033FFFF7821063209DE380011920000013
+S31550000010D2030000173FFFF79612E3E4AC07BFF890
+S31550000020D225800BD005800B133FFFC0900A0009E4
+S3155000003090122977D0230000E00320901B0800136C
+S31550000040C0232090D20320149E136018D225800B13
+S31550000050D005800B1300180090120009900A3FF04B
+S31550000060D0232014D20300001100003FD225800B6C
+S31550000070D405800B901223FF940A800813043E0087
+S3155000008094128009D4230000D003C0009A13601C38
+S31550000090D025800BD205800B11004000902A4008D5
+S315500000A0D023C000D403400011000040D425800B5B
+S315500000B0D205800BA00C204092124008A13C20068D
+S315500000C011140005E02A2180D2234000B8102000E8
+S315500000D0400004C890102005130004004000017031
+S315500000E090102001213FFFF84000036F90058010CB
+S315500000F0A014200A92058010B6102000B4102000DB
+S31550000100A6102000AE10200096102000D00A400005
+S3155000011080A2202002800006920260019602E00131
+S3155000012080A2E06324BFFFFBD00A40009810200055
+S3155000013080A3000B1680000F113FFFF89012200A83
+S31550000140940580089810000B912CE0029002001341
+S31550000150D20A8000912A200190020009A6023FD0BF
+S3155000016098833FFF12BFFFF99402A0019810000B2D
+S315500001709205800C113FFFF894024008961020001B
+S315500001809002800BD20A201680A2602002800007BF
+S3155000019080A2E0009602E00180A2E06304BFFFFA6D
+S315500001A09002800B80A2E0000480000F113FFFF800
+S315500001B09205800C9012201698024008900DE0FF90
+S315500001C0932A2002D40B000092024008932A600121
+S315500001D094028009AE02BFD09682FFFF12BFFFF88D
+S315500001E098032001133FFFF794126384921263869B
+S315500001F090078009400001A89207800A80A220003B
+S3155000020002800122153FFFF79012A386D21780086D
+S3155000021080A2601C0280010E9012A384113FFFF74A
+S31550000220961223849012238692102037D237800854
+S31550000230941020B5D437800B900F2001213FFFF743
+S31550000240AB2A201392142386110001E1D41780099A
+S3155000025090122154A2142384A4054008D617801165
+S3155000026090100012400002289210202080A22000F8
+S31550000270028000CA11140005B0100010B21000110F
+S31550000280A0102000113FFFEA80A420000280000445
+S315500002909212225511000015921221AA912A60102D
+S315500002A0A8162386A3322010D617801990048010E2
+S315500002B0D417801492102002400001DA98100011D1
+S315500002C080A22000028000B511140005D0148010C1
+S315500002D080A44008128000B0A004200280A420030D
+S315500002E004BFFFEA113FFFEA213FFFF79214238430
+S315500002F0D617800990100012D417801440000202BD
+S3155000030092102020170001DF9012E3F8D20200006D
+S31550000310941423E4D225800AA01423E0C02580102B
+S31550000320D005800A80A23FFF228000BB9012E3FCDA
+S31550000330113FFFF7A2122384A0122386110001C198
+S31550000340D417801090122154D61780119210202065
+S31550000350400001ED90054008110001E9D4178010C6
+S3155000036090122154D617801192102020400001E699
+S3155000037090054008110001F1D417801090122154B5
+S31550000380D617801192102020400001DF90054008BA
+S31550000390133FFFF8D00D800980A220421280000B37
+S315500003A0A410001392058009D00A600180A220494A
+S315500003B03280000721140005D00A600280A2204E28
+S315500003C022800008D417801021140005400002F640
+S315500003D09014202890142028400002F39E03FCF02D
+S315500003E090102000D6178011400001C792100013BC
+S315500003F080A2200022800069111400051114000506
+S31550000400400002E990122030400000BE010000007A
+S3155000041011000007A81223FFB010001480A4801406
+S31550000420148000031300000892100012113FFFF8C9
+S315500004304000036F90058008A2922000028000734E
+S31550000440A010200080A40011B40680111A8000214B
+S31550000450A4248011333FFFF71100003FAA1223FF57
+S31550000460BA1663849810001092102000A00420023F
+S31550000470173FFFF89005800CD40A000B932A6008AA
+S315500004809803200180A3001006BFFFFB9212400A7A
+S31550000490912A60109932201080A300150280000A1C
+S315500004A090166386D417800892102002D617801DA6
+S315500004B04000015C9010001B80A220000280003793
+S315500004C01114000580A400110ABFFFE7B606E0022A
+S315500004D0900E801880A0000892603FFF80A0001206
+S315500004E090603FFF809240080280000680A68013ED
+S315500004F011140005400002AC9012203080A68013E3
+S3155000050012BFFFC880A480149410200080A28013CC
+S315500005101680000996102000D21280009132600891
+S315500005209002C0089402A00280A2801306BFFFFB6F
+S3155000053096020009920AE0FF900DE0FF80A2400863
+S31550000540028000041114000510BFFFA49012203839
+S31550000550153FFFF79012A3E0D205800880A26001F4
+S31550000560128000109212A3849012A386D41780088A
+S3155000057098102A01D6178009110001DF901223FC2A
+S31550000580400001289210200280A22000128000060E
+S31550000590211400051114000510BFFF909012202061
+S315500005A02114000540000280901420404000027E35
+S315500005B090142040901020F013080013D0302000E3
+S315500005C092126020D012400015200000900A3FFE83
+S315500005D0D03240009612A04C90102010D022C0006D
+S315500005E0D802C0009412A0B813080004D822800084
+S315500005F092126014D0024000900A3FFED022400072
+S3155000060010800000010000001114000510BFFF7398
+S3155000061090122048D20200001102807FD225800A13
+S31550000620901223FFD0258010D205800AD005801065
+S3155000063080A2400832BFFF40113FFFF790102001C3
+S31550000640D025801010BFFF3C113FFFF7D61780080A
+S31550000650921AE0B980A0000994603FFF901AE0DA40
+S3155000066080A0000892603FFF8092800902BFFEED95
+S31550000670113FFFF780A2E0DA22BFFEF0B81020014A
+S3155000068010BFFEEF900F20012114000540000246D6
+S315500006909014205030BFFFFE01000000941020F04F
+S315500006A019080013D430200098132020170800048E
+S315500006B0D41300008212E01417200000940ABFFEE3
+S315500006C09A12E0B8D4330000900A20FF9612E04CFC
+S315500006D0D222C00080A22001128000070100000033
+S315500006E0D202C000D2234000D0004000900A3FFE04
+S315500006F0D02040000100000081C3E0080100000046
+S315500007001308000492126014D00240009012200187
+S31550000710D02240000100000081C3E0080100000023
+S315500007209C03BF90D233A066D213A06696100008E1
+S31550000730920A6080D012000080A0000994402000E8
+S31550000740900A208080A000089240200080A2400A93
+S315500007500280000D01000000D012C000808A2020C7
+S315500007601280000901000000D012C000900A2080BB
+S3155000077080A000089240200080A2400A12BFFFF7D6
+S3155000078001000000D012C000900A208080A000080E
+S3155000079090402000901A000A901A20010100000093
+S315500007A081C3E0089C23BF909DE3BF90B20E60FFCB
+S315500007B0A0100018C027BFF480A660BA14800006A7
+S315500007C080A660DA80A660B916800006153FFFEA5B
+S315500007D080A660B512800027B0102000153FFFEAB2
+S315500007E096102AAA9412A2AA13000015D432C00059
+S315500007F09212615598102554113FFFE0D2330000F4
+S3155000080090122080D032C000D432C000D2330000C3
+S315500008101100000C2300003F90122030130000C33B
+S31550000820D0340000A412613FB21463FF921463FFE8
+S315500008307FFFFFBC90100010B0100008D007BFF427
+S3155000084090022001D027BFF4D214000080A64009A0
+S315500008500280000880A620011280000601000000D8
+S31550000860D007BFF480A2001208BFFFF2921463FFB4
+S31550000870D007BFF4130000C39212613F80A2400814
+S3155000088094403FFFB00E000A0100000081C7E00807
+S3155000089081E80000153FFFEA98102AAA9412A2AAEE
+S315500008A0D4330000170000159612E155153FFFE4AA
+S315500008B0D63025549412A090D4330000D61022007E
+S315500008C09A100008960AE0FFD6320000901030F0D9
+S315500008D0D0330000D613400098100009901AE03724
+S315500008E080A0000894603FFF901AE01C80A000088A
+S315500008F092603FFF8092800912800007821020008C
+S3155000090080A2E0C20280000480A2E0201280004251
+S3155000091090102000113FFFEA94102AAA901222AAA2
+S31550000920D03280001300001592126155113FFFE43A
+S31550000930D230255490122090D0328000D21022020C
+S31550000940901030F0920A60FFD2330000D03280000F
+S31550000950D013400080A220370280002A80A2202097
+S31550000960D41300000280001D912AA0109002BF47A8
+S31550000970912A201091322010952AA01080A2200290
+S315500009809532A01092602000901AA0B580A0000861
+S31550000990920A600190603FFF809240083280000BBF
+S315500009A08210200180A2A0B90280000A80A2A0BABB
+S315500009B00280000880A2A0EF0280000680A2A0DA82
+S315500009C02280000282102001108000139010000136
+S315500009D010BFFFFE821020019132201080A220EE1F
+S315500009E012BFFFE49002BF479010201CD033400046
+S315500009F0921020B9D233000010BFFFDD941020B9F9
+S31550000A00D413000080A2A03402BFFFF880A2202099
+S31550000A1030BFFFD50100000081C3E008010000008F
+S31550000A209DE3BF88B72EE010C037BFF4B736E0104D
+S31550000A30A0100018C027BFEC80A6E0BA14800006AC
+S31550000A4080A6E0DA80A6E0B916800006113FFFEADC
+S31550000A5080A6E0B512800023B0102000113FFFEAB7
+S31550000A6094102AAA901222AAD032800013000015A0
+S31550000A7092126155113FFFE8D2302554901220A0B2
+S31550000A80D0328000F837BFF2D017BFF2130000C340
+S31550000A90D0340000B612613FD217BFF27FFFFF215C
+S31550000AA090100010B0100008D007BFEC9002200143
+S31550000AB0D027BFECD2140000D017BFF280A2000995
+S31550000AC00280000880A62001128000060100000066
+S31550000AD0D007BFEC80A2001B08BFFFF0010000004A
+S31550000AE0D007BFEC130000C39212613F80A24008AA
+S31550000AF094403FFFB00E000A0100000081C7E00895
+S31550000B0081E800009DE3BF9811140005D4022150DE
+S31550000B10A210200080A4400AA410001B9A102000A6
+S31550000B20A0102000A610200116800012961020005A
+S31550000B30912EA010B5322010932EE0109810000A76
+S31550000B40111400059332601094122060D002A00C4C
+S31550000B5080A2001A22800048D002A0109602E0011E
+S31550000B6080A2C00C06BFFFFA9402A05011140005D3
+S31550000B70D202215080A2C009028000449010200168
+S31550000B8080A6200008800016912AE0029002000BF1
+S31550000B9013140005B4126060992A20049E10200197
+S31550000BA0912C200290020010912A200290030008F6
+S31550000BB09002001AD4022004A2046001D202200836
+S31550000BC080A4400A932BC0099A034009A0643FFFB2
+S31550000BD080A6000D18BFFFF4912C200280A660005D
+S31550000BE00480001F932AE0029202400BB60CA0FF2D
+S31550000BF011140005A4122060B52A60049210001B3F
+S31550000C007FFFFEEA90100018932C200292024010AB
+S31550000C10932A6002920680099402401280A2200014
+S31550000C2002800013A2046001D202A0089010200195
+S31550000C30912A000980A64008B00600080680000ADE
+S31550000C40B2264008D002A00480A44008A0643FFF0A
+S31550000C5080A6600014BFFFEB9210001B1080000BA3
+S31550000C6090100013108000099010200110BFFFFC57
+S31550000C70A610200080A2000932BFFFBA9602E001FA
+S31550000C8010BFFFBC1114000581C7E00891E80008A9
+S31550000C9013140005D40A61801708000013000013CE
+S31550000CA09212630C952AA00294028009D202C00ABD
+S31550000CB0941000089132601F80A22001028000002B
+S31550000CC09132601D808A20012280000490102001FC
+S31550000CD0C022800030800002D022800081C3E0080C
+S31550000CE09010000911140005D20A21801508000041
+S31550000CF0110000139012230C932A600292024008AE
+S31550000D00D20280099132601F80A220010280000029
+S31550000D100100000081C3E008901000099DE3BF90D8
+S31550000D2011140005E00A2180B00E20FF11140005B1
+S31550000D3090122154B12E2002E2020018A12C20025A
+S31550000D40110000139012230CA00400087FFFFFD15E
+S31550000D509007BFF4D207BFF411060000932A601E15
+S31550000D60921240112308000092124008D2244010DB
+S31550000D707FFFFFC89007BFF4D207BFF411070000EA
+S31550000D80932A601E92124008D22440107FFFFFC162
+S31550000D909007BFF4D207BFF411030000932A601ED8
+S31550000DA092124008D22440107FFFFFBA9007BFF43A
+S31550000DB0D207BFF41104000090122003932A601E3C
+S31550000DC092124008D22440107FFFFFB29007BFF422
+S31550000DD0D207BFF411050000932A601E92124008F4
+S31550000DE0D22440107FFFFFC0010000000100000028
+S31550000DF081C7E00881E800009DE3BF90111400050B
+S31550000E00E00A218025080000110000139012230CDF
+S31550000E10A12C2002A00400087FFFFF9E9007BFF47C
+S31550000E20D207BFF411050000932A601E92124008A3
+S31550000E30D22480107FFFFF979007BFF4A2100008BE
+S31550000E40D007BFF427040000912A201E90120013E9
+S31550000E50D02480107FFFFF8F9007BFF4D207BFF4D6
+S31550000E6011040004932A601E92124008D224801066
+S31550000E707FFFFF889007BFF4D007BFF4A20C60FF36
+S31550000E80912A201E9012001190120013D024801027
+S31550000E907FFFFF95010000000100000081C7E008B8
+S31550000EA081E800009DE3BF9011140005D20A21800D
+S31550000EB02708000011000013932A60029012230C99
+S31550000EC09202400893326002AC100009AB2A6002CD
+S31550000ED0AE1000097FFFFF6F9007BFF4D007BFF435
+S31550000EE023030000912A201E90120011D024C01511
+S31550000EF07FFFFF7D0100000091322016A08A200F4F
+S31550000F0032800011A2102000A4100011A32DA002BF
+S31550000F107FFFFF609007BFF4D207BFF4932A601E8D
+S31550000F2092124012D224C0117FFFFF6F01000000C1
+S31550000F3091322016A08A200F02BFFFF60100000052
+S31550000F40A210200080A440101ABFFFE3A52DE00296
+S31550000F50290100007FFFFF4F9007BFF4D007BFF471
+S31550000F60A2046001912A201E90120014D024C012AF
+S31550000F707FFFFF5D01000000D02E0000808A20FF19
+S31550000F8002800006B006200180A440100ABFFFF27E
+S31550000F900100000030BFFFD00100000081C7E0080B
+S31550000FA081E800009DE3BF9011140005D20A21800C
+S31550000FB025080000D40E000011000013932A600289
+S31550000FC09012230C80A2A000028000849202400856
+S31550000FD0AD2A60109135A012A72A2002AA10000847
+S31550000FE0A81000137FFFFF2B9007BFF4D007BFF464
+S31550000FF021030000912A201E90120010D024801345
+S315500010007FFFFF3901000000900A200680A22006CB
+S315500010100280001001000000A2100010A12D6002F5
+S315500010207FFFFF1C9007BFF4D207BFF4932A601EC0
+S3155000103092124011D22480107FFFFF2B0100000036
+S31550001040900A200680A2200612BFFFF6010000007B
+S315500010507FFFFF109007BFF4D007BFF4D20E0000F9
+S31550001060912A201E90120009D02480147FFFFF1E63
+S31550001070B0062001D00E000080A2200012BFFFDA79
+S31550001080010000009135A010D404800880A2A00071
+S315500010900680004C010000009132A01D808A20017C
+S315500010A00280004690102001C027BFF4D007BFF43D
+S315500010B013030000912A201E901200099335A010A8
+S315500010C0D0248009D404800980A2A0000680003470
+S315500010D0900AA00680A22006028000169135A01222
+S315500010E09A1000089E102001972A2002190300002A
+S315500010F09132A01D808A2001128000039210200098
+S315500011009210000F912A601E9012000CD024800B72
+S31550001110D404800B80A2A0000680001A900AA00674
+S3155000112080A2200612BFFFF49132A01DD227BFF431
+S315500011309132A01D808A200102800010901020015B
+S31550001140C027BFF4D007BFF49335A010912A201EB4
+S31550001150D0248009D404800980A2A00016800021E2
+S3155000116090100009D404800880A2A00006BFFFFE9C
+S31550001170010000003080001B10BFFFF3D027BFF4E2
+S31550001180912B6002D404800880A2A00006BFFFFE07
+S315500011900100000010BFFFE3900AA006901000095E
+S315500011A0D404800880A2A00006BFFFFE0100000004
+S315500011B010BFFFC9900AA00610BFFFBDD027BFF4CD
+S315500011C0D404800880A2A00006BFFFFE01000000E4
+S315500011D010BFFFB39132A01D10BFFFABAD2A6010F8
+S315500011E00100000081C7E00881E800009DE3BF9838
+S315500011F035140005F60EA180921000183500001324
+S31550001200B416A30CB72EE002B606C01A992EE010FB
+S31550001210B53320129B2EA002A210001AA610001958
+S315500012203B080000961020009410000DA410001AE0
+S31550001230F807400D80A7200006800064B137201DB6
+S31550001240B00E200180A00018B0603FFFB12E201EC6
+S3155000125033030000B0160019F027400AF807400A79
+S3155000126080A7200006800052B1372016B48E200F7A
+S315500012701280001A82102000B3332012310003D09E
+S31550001280901000199E162240B32E600237030000BC
+S3155000129080A0400F8200600118800053B0102000DB
+S315500012A0B137201DB00E200180A00018B0603FFF5E
+S315500012B0B12E201EB016001BF0274019F807401912
+S315500012C080A7200006800033B1372016B48E200F39
+S315500012D002BFFFF180A0400F8210200080A0401A6C
+S315500012E01ABFFFD4B1332012B72E20029010001827
+S315500012F09E10001BA0100018F807401B80A7200066
+S315500013000680001DB137201DB00E200180A00018A8
+S31550001310B0603FFFB12E201E33010000B0160019F9
+S31550001320F027400FF807400F80A720000680000CDA
+S31550001330B12C20029602E001F82A400080A2C01388
+S3155000134002800029B010000B8200600180A0401A74
+S315500013500ABFFFEA9202600130BFFFB6F807401895
+S3155000136080A7200006BFFFFE0100000010BFFFF35C
+S315500013709602E001B12A2002F807401880A7200003
+S3155000138006BFFFFE0100000010BFFFE0B137201D71
+S31550001390B12A2002F807401880A7200006BFFFFE9A
+S315500013A00100000010BFFFCAB1372016B12CA002B1
+S315500013B0F807401880A7200006BFFFFE0100000076
+S315500013C010BFFFABB1372016B12C6002F80740189A
+S315500013D080A7200006BFFFFE0100000010BFFF9946
+S315500013E0B137201D0100000081C7E00881E80000E8
+S315500013F09DE3BF987FFFFE81B00E20FF7FFFFE4822
+S3155000140081E800000100000000000000000000001C
+S315500014100000000000000000000000000000000076
+S315500014204572726F723400004572726F72330000EB
+S315500014304F4B0000000000004572726F7232000080
+S31550001440454E4400000000004572726F7235000030
+S315500014504572726F723100000000000000000000FB
+S3155000146000000000000000010000000E00000037E0
+S31550001470000000B500004000000000030000000D11
+S3155000148000000037000000B5000080000000000496
+S315500014900000000F00000037000000B500010000FA
+S315500014A00000000B0000001000000037000000B5DF
+S315500014B00000000000000007000000100000001CA3
+S315500014C0000000B900007000000000080000000F86
+S315500014D00000001C000000B9000078000000000A5F
+S315500014E00000000D0000001C000000B900007C0048
+S315500014F00000000B0000000E0000001C000000B9A8
+S31550001500000000000000000F000000100000001C4A
+S31550001510000000DA00007000000000100000000F0C
+S315500015200000001C000000DA0000700000000012ED
+S315500015300000000D0000001C000000DA00007000E2
+S31550001540000000130000000E0000001C000000DA2E
+S3155000155000000003000001AA000000D50000006A48
+S3155000156000000035000000230000001100000008B4
+S3115000157000000000000000000000000019
+S70550000000AA
diff --git a/ao-tools/ao-sky-flash/srec_9600.bin b/ao-tools/ao-sky-flash/srec_9600.bin
new file mode 100644
index 00000000..9a29ab1b
--- /dev/null
+++ b/ao-tools/ao-sky-flash/srec_9600.bin
@@ -0,0 +1,346 @@
+S0190000666C6173685F3139646F74355F393630302E737265638A
+S31550000000033FFFF7821063209DE380011920000013
+S31550000010D2030000173FFFF79612E3E4AC07BFF890
+S31550000020D225800BD005800B133FFFC0900A0009E4
+S3155000003090122977D0230000E00320901B0800136C
+S31550000040C0232090D20320149E136018D225800B13
+S31550000050D005800B1300180090120009900A3FF04B
+S31550000060D0232014D20300001100003FD225800B6C
+S31550000070D405800B901223FF940A800813043E0087
+S3155000008094128009D4230000D003C0009A13601C38
+S31550000090D025800BD205800B11004000902A4008D5
+S315500000A0D023C000D403400011000040D425800B5B
+S315500000B0D205800BA00C204092124008A13C20068D
+S315500000C011140005E02A2180D2234000B8102000E8
+S315500000D0400004C890102001130004004000017035
+S315500000E090102001213FFFF84000036F90058010CB
+S315500000F0A014200A92058010B6102000B4102000DB
+S31550000100A6102000AE10200096102000D00A400005
+S3155000011080A2202002800006920260019602E00131
+S3155000012080A2E06324BFFFFBD00A40009810200055
+S3155000013080A3000B1680000F113FFFF89012200A83
+S31550000140940580089810000B912CE0029002001341
+S31550000150D20A8000912A200190020009A6023FD0BF
+S3155000016098833FFF12BFFFF99402A0019810000B2D
+S315500001709205800C113FFFF894024008961020001B
+S315500001809002800BD20A201680A2602002800007BF
+S3155000019080A2E0009602E00180A2E06304BFFFFA6D
+S315500001A09002800B80A2E0000480000F113FFFF800
+S315500001B09205800C9012201698024008900DE0FF90
+S315500001C0932A2002D40B000092024008932A600121
+S315500001D094028009AE02BFD09682FFFF12BFFFF88D
+S315500001E098032001133FFFF794126384921263869B
+S315500001F090078009400001A89207800A80A220003B
+S3155000020002800122153FFFF79012A386D21780086D
+S3155000021080A2601C0280010E9012A384113FFFF74A
+S31550000220961223849012238692102037D237800854
+S31550000230941020B5D437800B900F2001213FFFF743
+S31550000240AB2A201392142386110001E1D41780099A
+S3155000025090122154A2142384A4054008D617801165
+S3155000026090100012400002289210202080A22000F8
+S31550000270028000CA11140005B0100010B21000110F
+S31550000280A0102000113FFFEA80A420000280000445
+S315500002909212225511000015921221AA912A60102D
+S315500002A0A8162386A3322010D617801990048010E2
+S315500002B0D417801492102002400001DA98100011D1
+S315500002C080A22000028000B511140005D0148010C1
+S315500002D080A44008128000B0A004200280A420030D
+S315500002E004BFFFEA113FFFEA213FFFF79214238430
+S315500002F0D617800990100012D417801440000202BD
+S3155000030092102020170001DF9012E3F8D20200006D
+S31550000310941423E4D225800AA01423E0C02580102B
+S31550000320D005800A80A23FFF228000BB9012E3FCDA
+S31550000330113FFFF7A2122384A0122386110001C198
+S31550000340D417801090122154D61780119210202065
+S31550000350400001ED90054008110001E9D4178010C6
+S3155000036090122154D617801192102020400001E699
+S3155000037090054008110001F1D417801090122154B5
+S31550000380D617801192102020400001DF90054008BA
+S31550000390133FFFF8D00D800980A220421280000B37
+S315500003A0A410001392058009D00A600180A220494A
+S315500003B03280000721140005D00A600280A2204E28
+S315500003C022800008D417801021140005400002F640
+S315500003D09014202890142028400002F39E03FCF02D
+S315500003E090102000D6178011400001C792100013BC
+S315500003F080A2200022800069111400051114000506
+S31550000400400002E990122030400000BE010000007A
+S3155000041011000007A81223FFB010001480A4801406
+S31550000420148000031300000892100012113FFFF8C9
+S315500004304000036F90058008A2922000028000734E
+S31550000440A010200080A40011B40680111A8000214B
+S31550000450A4248011333FFFF71100003FAA1223FF57
+S31550000460BA1663849810001092102000A00420023F
+S31550000470173FFFF89005800CD40A000B932A6008AA
+S315500004809803200180A3001006BFFFFB9212400A7A
+S31550000490912A60109932201080A300150280000A1C
+S315500004A090166386D417800892102002D617801DA6
+S315500004B04000015C9010001B80A220000280003793
+S315500004C01114000580A400110ABFFFE7B606E0022A
+S315500004D0900E801880A0000892603FFF80A0001206
+S315500004E090603FFF809240080280000680A68013ED
+S315500004F011140005400002AC9012203080A68013E3
+S3155000050012BFFFC880A480149410200080A28013CC
+S315500005101680000996102000D21280009132600891
+S315500005209002C0089402A00280A2801306BFFFFB6F
+S3155000053096020009920AE0FF900DE0FF80A2400863
+S31550000540028000041114000510BFFFA49012203839
+S31550000550153FFFF79012A3E0D205800880A26001F4
+S31550000560128000109212A3849012A386D41780088A
+S3155000057098102A01D6178009110001DF901223FC2A
+S31550000580400001289210200280A22000128000060E
+S31550000590211400051114000510BFFF909012202061
+S315500005A02114000540000280901420404000027E35
+S315500005B090142040901020F013080013D0302000E3
+S315500005C092126020D012400015200000900A3FFE83
+S315500005D0D03240009612A04C90102010D022C0006D
+S315500005E0D802C0009412A0B813080004D822800084
+S315500005F092126014D0024000900A3FFED022400072
+S3155000060010800000010000001114000510BFFF7398
+S3155000061090122048D20200001102807FD225800A13
+S31550000620901223FFD0258010D205800AD005801065
+S3155000063080A2400832BFFF40113FFFF790102001C3
+S31550000640D025801010BFFF3C113FFFF7D61780080A
+S31550000650921AE0B980A0000994603FFF901AE0DA40
+S3155000066080A0000892603FFF8092800902BFFEED95
+S31550000670113FFFF780A2E0DA22BFFEF0B81020014A
+S3155000068010BFFEEF900F20012114000540000246D6
+S315500006909014205030BFFFFE01000000941020F04F
+S315500006A019080013D430200098132020170800048E
+S315500006B0D41300008212E01417200000940ABFFEE3
+S315500006C09A12E0B8D4330000900A20FF9612E04CFC
+S315500006D0D222C00080A22001128000070100000033
+S315500006E0D202C000D2234000D0004000900A3FFE04
+S315500006F0D02040000100000081C3E0080100000046
+S315500007001308000492126014D00240009012200187
+S31550000710D02240000100000081C3E0080100000023
+S315500007209C03BF90D233A066D213A06696100008E1
+S31550000730920A6080D012000080A0000994402000E8
+S31550000740900A208080A000089240200080A2400A93
+S315500007500280000D01000000D012C000808A2020C7
+S315500007601280000901000000D012C000900A2080BB
+S3155000077080A000089240200080A2400A12BFFFF7D6
+S3155000078001000000D012C000900A208080A000080E
+S3155000079090402000901A000A901A20010100000093
+S315500007A081C3E0089C23BF909DE3BF90B20E60FFCB
+S315500007B0A0100018C027BFF480A660BA14800006A7
+S315500007C080A660DA80A660B916800006153FFFEA5B
+S315500007D080A660B512800027B0102000153FFFEAB2
+S315500007E096102AAA9412A2AA13000015D432C00059
+S315500007F09212615598102554113FFFE0D2330000F4
+S3155000080090122080D032C000D432C000D2330000C3
+S315500008101100000C2300003F90122030130000C33B
+S31550000820D0340000A412613FB21463FF921463FFE8
+S315500008307FFFFFBC90100010B0100008D007BFF427
+S3155000084090022001D027BFF4D214000080A64009A0
+S315500008500280000880A620011280000601000000D8
+S31550000860D007BFF480A2001208BFFFF2921463FFB4
+S31550000870D007BFF4130000C39212613F80A2400814
+S3155000088094403FFFB00E000A0100000081C7E00807
+S3155000089081E80000153FFFEA98102AAA9412A2AAEE
+S315500008A0D4330000170000159612E155153FFFE4AA
+S315500008B0D63025549412A090D4330000D61022007E
+S315500008C09A100008960AE0FFD6320000901030F0D9
+S315500008D0D0330000D613400098100009901AE03724
+S315500008E080A0000894603FFF901AE01C80A000088A
+S315500008F092603FFF8092800912800007821020008C
+S3155000090080A2E0C20280000480A2E0201280004251
+S3155000091090102000113FFFEA94102AAA901222AAA2
+S31550000920D03280001300001592126155113FFFE43A
+S31550000930D230255490122090D0328000D21022020C
+S31550000940901030F0920A60FFD2330000D03280000F
+S31550000950D013400080A220370280002A80A2202097
+S31550000960D41300000280001D912AA0109002BF47A8
+S31550000970912A201091322010952AA01080A2200290
+S315500009809532A01092602000901AA0B580A0000861
+S31550000990920A600190603FFF809240083280000BBF
+S315500009A08210200180A2A0B90280000A80A2A0BABB
+S315500009B00280000880A2A0EF0280000680A2A0DA82
+S315500009C02280000282102001108000139010000136
+S315500009D010BFFFFE821020019132201080A220EE1F
+S315500009E012BFFFE49002BF479010201CD033400046
+S315500009F0921020B9D233000010BFFFDD941020B9F9
+S31550000A00D413000080A2A03402BFFFF880A2202099
+S31550000A1030BFFFD50100000081C3E008010000008F
+S31550000A209DE3BF88B72EE010C037BFF4B736E0104D
+S31550000A30A0100018C027BFEC80A6E0BA14800006AC
+S31550000A4080A6E0DA80A6E0B916800006113FFFEADC
+S31550000A5080A6E0B512800023B0102000113FFFEAB7
+S31550000A6094102AAA901222AAD032800013000015A0
+S31550000A7092126155113FFFE8D2302554901220A0B2
+S31550000A80D0328000F837BFF2D017BFF2130000C340
+S31550000A90D0340000B612613FD217BFF27FFFFF215C
+S31550000AA090100010B0100008D007BFEC9002200143
+S31550000AB0D027BFECD2140000D017BFF280A2000995
+S31550000AC00280000880A62001128000060100000066
+S31550000AD0D007BFEC80A2001B08BFFFF0010000004A
+S31550000AE0D007BFEC130000C39212613F80A24008AA
+S31550000AF094403FFFB00E000A0100000081C7E00895
+S31550000B0081E800009DE3BF9811140005D4022150DE
+S31550000B10A210200080A4400AA410001B9A102000A6
+S31550000B20A0102000A610200116800012961020005A
+S31550000B30912EA010B5322010932EE0109810000A76
+S31550000B40111400059332601094122060D002A00C4C
+S31550000B5080A2001A22800048D002A0109602E0011E
+S31550000B6080A2C00C06BFFFFA9402A05011140005D3
+S31550000B70D202215080A2C009028000449010200168
+S31550000B8080A6200008800016912AE0029002000BF1
+S31550000B9013140005B4126060992A20049E10200197
+S31550000BA0912C200290020010912A200290030008F6
+S31550000BB09002001AD4022004A2046001D202200836
+S31550000BC080A4400A932BC0099A034009A0643FFFB2
+S31550000BD080A6000D18BFFFF4912C200280A660005D
+S31550000BE00480001F932AE0029202400BB60CA0FF2D
+S31550000BF011140005A4122060B52A60049210001B3F
+S31550000C007FFFFEEA90100018932C200292024010AB
+S31550000C10932A6002920680099402401280A2200014
+S31550000C2002800013A2046001D202A0089010200195
+S31550000C30912A000980A64008B00600080680000ADE
+S31550000C40B2264008D002A00480A44008A0643FFF0A
+S31550000C5080A6600014BFFFEB9210001B1080000BA3
+S31550000C6090100013108000099010200110BFFFFC57
+S31550000C70A610200080A2000932BFFFBA9602E001FA
+S31550000C8010BFFFBC1114000581C7E00891E80008A9
+S31550000C9013140005D40A61801708000013000013CE
+S31550000CA09212630C952AA00294028009D202C00ABD
+S31550000CB0941000089132601F80A22001028000002B
+S31550000CC09132601D808A20012280000490102001FC
+S31550000CD0C022800030800002D022800081C3E0080C
+S31550000CE09010000911140005D20A21801508000041
+S31550000CF0110000139012230C932A600292024008AE
+S31550000D00D20280099132601F80A220010280000029
+S31550000D100100000081C3E008901000099DE3BF90D8
+S31550000D2011140005E00A2180B00E20FF11140005B1
+S31550000D3090122154B12E2002E2020018A12C20025A
+S31550000D40110000139012230CA00400087FFFFFD15E
+S31550000D509007BFF4D207BFF411060000932A601E15
+S31550000D60921240112308000092124008D2244010DB
+S31550000D707FFFFFC89007BFF4D207BFF411070000EA
+S31550000D80932A601E92124008D22440107FFFFFC162
+S31550000D909007BFF4D207BFF411030000932A601ED8
+S31550000DA092124008D22440107FFFFFBA9007BFF43A
+S31550000DB0D207BFF41104000090122003932A601E3C
+S31550000DC092124008D22440107FFFFFB29007BFF422
+S31550000DD0D207BFF411050000932A601E92124008F4
+S31550000DE0D22440107FFFFFC0010000000100000028
+S31550000DF081C7E00881E800009DE3BF90111400050B
+S31550000E00E00A218025080000110000139012230CDF
+S31550000E10A12C2002A00400087FFFFF9E9007BFF47C
+S31550000E20D207BFF411050000932A601E92124008A3
+S31550000E30D22480107FFFFF979007BFF4A2100008BE
+S31550000E40D007BFF427040000912A201E90120013E9
+S31550000E50D02480107FFFFF8F9007BFF4D207BFF4D6
+S31550000E6011040004932A601E92124008D224801066
+S31550000E707FFFFF889007BFF4D007BFF4A20C60FF36
+S31550000E80912A201E9012001190120013D024801027
+S31550000E907FFFFF95010000000100000081C7E008B8
+S31550000EA081E800009DE3BF9011140005D20A21800D
+S31550000EB02708000011000013932A60029012230C99
+S31550000EC09202400893326002AC100009AB2A6002CD
+S31550000ED0AE1000097FFFFF6F9007BFF4D007BFF435
+S31550000EE023030000912A201E90120011D024C01511
+S31550000EF07FFFFF7D0100000091322016A08A200F4F
+S31550000F0032800011A2102000A4100011A32DA002BF
+S31550000F107FFFFF609007BFF4D207BFF4932A601E8D
+S31550000F2092124012D224C0117FFFFF6F01000000C1
+S31550000F3091322016A08A200F02BFFFF60100000052
+S31550000F40A210200080A440101ABFFFE3A52DE00296
+S31550000F50290100007FFFFF4F9007BFF4D007BFF471
+S31550000F60A2046001912A201E90120014D024C012AF
+S31550000F707FFFFF5D01000000D02E0000808A20FF19
+S31550000F8002800006B006200180A440100ABFFFF27E
+S31550000F900100000030BFFFD00100000081C7E0080B
+S31550000FA081E800009DE3BF9011140005D20A21800C
+S31550000FB025080000D40E000011000013932A600289
+S31550000FC09012230C80A2A000028000849202400856
+S31550000FD0AD2A60109135A012A72A2002AA10000847
+S31550000FE0A81000137FFFFF2B9007BFF4D007BFF464
+S31550000FF021030000912A201E90120010D024801345
+S315500010007FFFFF3901000000900A200680A22006CB
+S315500010100280001001000000A2100010A12D6002F5
+S315500010207FFFFF1C9007BFF4D207BFF4932A601EC0
+S3155000103092124011D22480107FFFFF2B0100000036
+S31550001040900A200680A2200612BFFFF6010000007B
+S315500010507FFFFF109007BFF4D007BFF4D20E0000F9
+S31550001060912A201E90120009D02480147FFFFF1E63
+S31550001070B0062001D00E000080A2200012BFFFDA79
+S31550001080010000009135A010D404800880A2A00071
+S315500010900680004C010000009132A01D808A20017C
+S315500010A00280004690102001C027BFF4D007BFF43D
+S315500010B013030000912A201E901200099335A010A8
+S315500010C0D0248009D404800980A2A0000680003470
+S315500010D0900AA00680A22006028000169135A01222
+S315500010E09A1000089E102001972A2002190300002A
+S315500010F09132A01D808A2001128000039210200098
+S315500011009210000F912A601E9012000CD024800B72
+S31550001110D404800B80A2A0000680001A900AA00674
+S3155000112080A2200612BFFFF49132A01DD227BFF431
+S315500011309132A01D808A200102800010901020015B
+S31550001140C027BFF4D007BFF49335A010912A201EB4
+S31550001150D0248009D404800980A2A00016800021E2
+S3155000116090100009D404800880A2A00006BFFFFE9C
+S31550001170010000003080001B10BFFFF3D027BFF4E2
+S31550001180912B6002D404800880A2A00006BFFFFE07
+S315500011900100000010BFFFE3900AA006901000095E
+S315500011A0D404800880A2A00006BFFFFE0100000004
+S315500011B010BFFFC9900AA00610BFFFBDD027BFF4CD
+S315500011C0D404800880A2A00006BFFFFE01000000E4
+S315500011D010BFFFB39132A01D10BFFFABAD2A6010F8
+S315500011E00100000081C7E00881E800009DE3BF9838
+S315500011F035140005F60EA180921000183500001324
+S31550001200B416A30CB72EE002B606C01A992EE010FB
+S31550001210B53320129B2EA002A210001AA610001958
+S315500012203B080000961020009410000DA410001AE0
+S31550001230F807400D80A7200006800064B137201DB6
+S31550001240B00E200180A00018B0603FFFB12E201EC6
+S3155000125033030000B0160019F027400AF807400A79
+S3155000126080A7200006800052B1372016B48E200F7A
+S315500012701280001A82102000B3332012310003D09E
+S31550001280901000199E162240B32E600237030000BC
+S3155000129080A0400F8200600118800053B0102000DB
+S315500012A0B137201DB00E200180A00018B0603FFF5E
+S315500012B0B12E201EB016001BF0274019F807401912
+S315500012C080A7200006800033B1372016B48E200F39
+S315500012D002BFFFF180A0400F8210200080A0401A6C
+S315500012E01ABFFFD4B1332012B72E20029010001827
+S315500012F09E10001BA0100018F807401B80A7200066
+S315500013000680001DB137201DB00E200180A00018A8
+S31550001310B0603FFFB12E201E33010000B0160019F9
+S31550001320F027400FF807400F80A720000680000CDA
+S31550001330B12C20029602E001F82A400080A2C01388
+S3155000134002800029B010000B8200600180A0401A74
+S315500013500ABFFFEA9202600130BFFFB6F807401895
+S3155000136080A7200006BFFFFE0100000010BFFFF35C
+S315500013709602E001B12A2002F807401880A7200003
+S3155000138006BFFFFE0100000010BFFFE0B137201D71
+S31550001390B12A2002F807401880A7200006BFFFFE9A
+S315500013A00100000010BFFFCAB1372016B12CA002B1
+S315500013B0F807401880A7200006BFFFFE0100000076
+S315500013C010BFFFABB1372016B12C6002F80740189A
+S315500013D080A7200006BFFFFE0100000010BFFF9946
+S315500013E0B137201D0100000081C7E00881E80000E8
+S315500013F09DE3BF987FFFFE81B00E20FF7FFFFE4822
+S3155000140081E800000100000000000000000000001C
+S315500014100000000000000000000000000000000076
+S315500014204572726F723400004572726F72330000EB
+S315500014304F4B0000000000004572726F7232000080
+S31550001440454E4400000000004572726F7235000030
+S315500014504572726F723100000000000000000000FB
+S3155000146000000000000000010000000E00000037E0
+S31550001470000000B500004000000000030000000D11
+S3155000148000000037000000B5000080000000000496
+S315500014900000000F00000037000000B500010000FA
+S315500014A00000000B0000001000000037000000B5DF
+S315500014B00000000000000007000000100000001CA3
+S315500014C0000000B900007000000000080000000F86
+S315500014D00000001C000000B9000078000000000A5F
+S315500014E00000000D0000001C000000B900007C0048
+S315500014F00000000B0000000E0000001C000000B9A8
+S31550001500000000000000000F000000100000001C4A
+S31550001510000000DA00007000000000100000000F0C
+S315500015200000001C000000DA0000700000000012ED
+S315500015300000000D0000001C000000DA00007000E2
+S31550001540000000130000000E0000001C000000DA2E
+S3155000155000000003000001FB000000FD0000007EBB
+S315500015600000003F0000002A000000150000000A9D
+S3115000157000000000000000000000000019
+S70550000000AA
diff --git a/ao-tools/ao-stmload/Makefile.am b/ao-tools/ao-stmload/Makefile.am
index 5aea7db4..4eaf699c 100644
--- a/ao-tools/ao-stmload/Makefile.am
+++ b/ao-tools/ao-stmload/Makefile.am
@@ -4,11 +4,14 @@ bin_PROGRAMS=ao-stmload
LIBSTLINKDIR=/local/src/stlink
-AM_CFLAGS=$(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS) -I../lib
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS)
+AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
-ao_stmload_LDADD=$(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf
+ao_stmload_DEPENDENCIES = $(AO_STMLOAD_LIBS)
-ao_stmload_SOURCES=ao-stmload.c
+ao_stmload_LDADD=$(AO_STMLOAD_LIBS) $(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf
+
+ao_stmload_SOURCES=ao-stmload.c ao-elf.c ao-stmload.h ao-selfload.c
man_MANS = ao-stmload.1
diff --git a/ao-tools/ao-stmload/ao-elf.c b/ao-tools/ao-stmload/ao-elf.c
new file mode 100644
index 00000000..dad8fb80
--- /dev/null
+++ b/ao-tools/ao-stmload/ao-elf.c
@@ -0,0 +1,303 @@
+/*
+ * 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; 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 "ao-elf.h"
+#include <err.h>
+#include <gelf.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "ccdbg.h"
+#include "ao-stmload.h"
+
+/*
+ * Look through the Elf file for the AltOS symbols
+ * that can be adjusted before the image is written
+ * to the device
+ */
+static int
+find_symbols (Elf *e)
+{
+ Elf_Scn *scn;
+ Elf_Data *symbol_data = NULL;
+ GElf_Shdr shdr;
+ GElf_Sym sym;
+ int i, symbol_count, s;
+ int required = 0;
+ char *symbol_name;
+ char *section_name;
+ size_t shstrndx;
+
+ if (elf_getshdrstrndx(e, &shstrndx) < 0)
+ return 0;
+
+ /*
+ * Find the symbols
+ */
+
+ scn = NULL;
+ while ((scn = elf_nextscn(e, scn)) != NULL) {
+
+ if (gelf_getshdr(scn, &shdr) != &shdr)
+ return 0;
+
+ if (shdr.sh_type == SHT_SYMTAB) {
+ symbol_data = elf_getdata(scn, NULL);
+ symbol_count = shdr.sh_size / shdr.sh_entsize;
+ break;
+ }
+ }
+
+ if (!symbol_data)
+ return 0;
+
+ for (i = 0; i < symbol_count; i++) {
+ gelf_getsym(symbol_data, i, &sym);
+
+ symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name);
+
+ for (s = 0; s < ao_num_symbols; s++)
+ if (!strcmp (ao_symbols[s].name, symbol_name)) {
+ int t;
+ ao_symbols[s].addr = sym.st_value;
+ if (ao_symbols[s].required)
+ ++required;
+ }
+ }
+
+ return required >= ao_num_required_symbols;
+}
+
+uint32_t round4(uint32_t a) {
+ return (a + 3) & ~3;
+}
+
+struct hex_image *
+new_load (uint32_t addr, uint32_t len)
+{
+ struct hex_image *new;
+
+ len = round4(len);
+ new = calloc (1, sizeof (struct hex_image) + len);
+ if (!new)
+ abort();
+
+ new->address = addr;
+ new->length = len;
+ return new;
+}
+
+void
+load_paste(struct hex_image *into, struct hex_image *from)
+{
+ if (from->address < into->address || into->address + into->length < from->address + from->length)
+ abort();
+
+ memcpy(into->data + from->address - into->address, from->data, from->length);
+}
+
+/*
+ * Make a new load structure large enough to hold the old one and
+ * the new data
+ */
+struct hex_image *
+expand_load(struct hex_image *from, uint32_t address, uint32_t length)
+{
+ struct hex_image *new;
+
+ if (from) {
+ uint32_t from_last = from->address + from->length;
+ uint32_t last = address + length;
+
+ if (address > from->address)
+ address = from->address;
+ if (last < from_last)
+ last = from_last;
+
+ length = last - address;
+
+ if (address == from->address && length == from->length)
+ return from;
+ }
+ new = new_load(address, length);
+ if (from) {
+ load_paste(new, from);
+ free (from);
+ }
+ return new;
+}
+
+/*
+ * Create a new load structure with data from the existing one
+ * and the new data
+ */
+struct hex_image *
+load_write(struct hex_image *from, uint32_t address, uint32_t length, void *data)
+{
+ struct hex_image *new;
+
+ new = expand_load(from, address, length);
+ memcpy(new->data + address - new->address, data, length);
+ return new;
+}
+
+/*
+ * Construct a large in-memory block for all
+ * of the loaded sections of the program
+ */
+static struct hex_image *
+get_load(Elf *e)
+{
+ Elf_Scn *scn;
+ size_t shstrndx;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ char *got_name;
+ size_t nphdr;
+ size_t p;
+ GElf_Phdr phdr;
+ GElf_Addr p_paddr;
+ GElf_Off p_offset;
+ GElf_Addr sh_paddr;
+ struct hex_image *load = NULL;
+ char *section_name;
+ size_t nshdr;
+ size_t s;
+
+ if (elf_getshdrstrndx(e, &shstrndx) < 0)
+ return 0;
+
+ if (elf_getphdrnum(e, &nphdr) < 0)
+ return 0;
+
+ if (elf_getshdrnum(e, &nshdr) < 0)
+ return 0;
+
+ /*
+ * As far as I can tell, all of the phdr sections should
+ * be flashed to memory
+ */
+ for (p = 0; p < nphdr; p++) {
+
+ /* Find this phdr */
+ gelf_getphdr(e, p, &phdr);
+
+ if (phdr.p_type != PT_LOAD)
+ continue;
+
+ p_offset = phdr.p_offset;
+ /* Get the associated file section */
+
+#if 0
+ printf ("offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n",
+ (uint32_t) phdr.p_offset,
+ (uint32_t) phdr.p_vaddr,
+ (uint32_t) phdr.p_paddr,
+ (uint32_t) phdr.p_filesz,
+ (uint32_t) phdr.p_memsz);
+#endif
+
+ for (s = 0; s < nshdr; s++) {
+ scn = elf_getscn(e, s);
+
+ if (!scn) {
+ printf ("getscn failed\n");
+ abort();
+ }
+ if (gelf_getshdr(scn, &shdr) != &shdr) {
+ printf ("gelf_getshdr failed\n");
+ abort();
+ }
+
+ section_name = elf_strptr(e, shstrndx, shdr.sh_name);
+
+ if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) {
+
+ if (shdr.sh_size == 0)
+ continue;
+
+ sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset;
+
+ printf ("\tsize %08x rom %08x exec %08x %s\n",
+ (uint32_t) shdr.sh_size,
+ (uint32_t) sh_paddr,
+ (uint32_t) shdr.sh_addr,
+ section_name);
+
+ data = elf_getdata(scn, NULL);
+
+ /* Write the section data into the memory block */
+ load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf);
+ }
+ }
+ }
+ return load;
+}
+
+/*
+ * Open the specified ELF file and
+ * check for the symbols we need
+ */
+
+struct hex_image *
+ao_load_elf(char *name)
+{
+ int fd;
+ Elf *e;
+ Elf_Scn *scn;
+ Elf_Data *symbol_data = NULL;
+ GElf_Shdr shdr;
+ GElf_Sym sym;
+ size_t n, shstrndx, sz;
+ int i, symbol_count, s;
+ int required = 0;
+ struct hex_image *image;
+
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ return NULL;
+
+ fd = open(name, O_RDONLY, 0);
+
+ if (fd < 0)
+ return NULL;
+
+ e = elf_begin(fd, ELF_C_READ, NULL);
+
+ if (!e)
+ return NULL;
+
+ if (elf_kind(e) != ELF_K_ELF)
+ return NULL;
+
+ if (elf_getshdrstrndx(e, &shstrndx) != 0)
+ return NULL;
+
+ if (!find_symbols(e)) {
+ fprintf (stderr, "Cannot find required symbols\n");
+ return NULL;
+ }
+
+ image = get_load(e);
+ if (!image) {
+ fprintf (stderr, "Cannot create memory image from file\n");
+ return NULL;
+ }
+
+ return image;
+}
diff --git a/ao-tools/ao-stmload/ao-elf.h b/ao-tools/ao-stmload/ao-elf.h
new file mode 100644
index 00000000..4303d5ca
--- /dev/null
+++ b/ao-tools/ao-stmload/ao-elf.h
@@ -0,0 +1,24 @@
+/*
+ * 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; 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_ELF_H_
+#define _AO_ELF_H_
+
+struct hex_image *
+ao_load_elf(char *name);
+
+#endif
diff --git a/ao-tools/ao-stmload/ao-selfload.c b/ao-tools/ao-stmload/ao-selfload.c
new file mode 100644
index 00000000..95667dca
--- /dev/null
+++ b/ao-tools/ao-stmload/ao-selfload.c
@@ -0,0 +1,127 @@
+/*
+ * 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; 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 <stdint.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <string.h>
+#include "cc.h"
+#include "cc-usb.h"
+#include "ccdbg.h"
+#include "ao-stmload.h"
+
+int ao_self_verbose;
+
+#define TRACE(...) if (ao_self_verbose) printf (__VA_ARGS__)
+
+void
+ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256])
+{
+ int byte;
+ cc_usb_sync(cc);
+ cc_usb_printf(cc, "R %x\n", address);
+ for (byte = 0; byte < 0x100; byte++) {
+ block[byte] = cc_usb_getchar(cc);
+ }
+ TRACE ("\nread %08x\n", address);
+ for (byte = 0; byte < 0x100; byte++) {
+ TRACE (" %02x", block[byte]);
+ if ((byte & 0xf) == 0xf)
+ TRACE ("\n");
+ }
+}
+
+void
+ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256])
+{
+ int byte;
+ cc_usb_sync(cc);
+ cc_usb_printf(cc, "W %x\n", address);
+ TRACE ("write %08x\n", address);
+ for (byte = 0; byte < 0x100; byte++) {
+ TRACE (" %02x", block[byte]);
+ if ((byte & 0xf) == 0xf)
+ TRACE ("\n");
+ }
+ for (byte = 0; byte < 0x100; byte++) {
+ cc_usb_printf(cc, "%c", block[byte]);
+ }
+}
+
+struct hex_image *
+ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length)
+{
+ struct hex_image *image;
+ int pages;
+ int page;
+ uint32_t base = address & ~0xff;
+ uint32_t bound = (address + length + 0xff) & ~0xff;
+
+ image = calloc(sizeof (struct hex_image) + (bound - base), 1);
+ image->address = base;
+ image->length = bound - base;
+ pages = image->length / 0x100;
+ for (page = 0; page < pages; page++)
+ ao_self_block_read(cc, image->address + page * 0x100, image->data + page * 0x100);
+ return image;
+}
+
+int
+ao_self_write(struct cc_usb *cc, struct hex_image *image)
+{
+ uint8_t block[256];
+ uint8_t check[256];
+ uint32_t base, bound, length, address;
+ uint32_t pages;
+ uint32_t page;
+
+ base = image->address & ~0xff;
+ bound = (image->address + image->length + 0xff) & ~0xff;
+
+ address = base;
+ length = bound - base;
+
+ pages = length / 0x100;
+ printf ("Write %08x %d pages: ", address, length/0x100); fflush(stdout);
+ for (page = 0; page < pages; page++) {
+ uint32_t start, stop;
+ address = base + page * 0x100;
+
+ if (address < image->address || address + 0x100 > image->address + image->length) {
+ ao_self_block_read(cc, address, block);
+ }
+ start = address;
+ stop = address + 0x100;
+ if (start < image->address)
+ start = image->address;
+ if (stop > image->address + image->length)
+ stop = image->address + image->length;
+ memcpy(block + start - address, image->data + start - image->address, stop - start);
+ ao_self_block_write(cc, address, block);
+ ao_self_block_read(cc, address, check);
+ if (memcmp(block, check, 0x100) != 0) {
+ fprintf(stderr, "Block at 0x%08x doesn't match\n", address);
+ return 0;
+ }
+ putchar('.'); fflush(stdout);
+ }
+ printf("done\n");
+ cc_usb_printf(cc,"a\n");
+ return 1;
+}
diff --git a/ao-tools/ao-stmload/ao-stmload.c b/ao-tools/ao-stmload/ao-stmload.c
index a471dcc4..dd25f07f 100644
--- a/ao-tools/ao-stmload/ao-stmload.c
+++ b/ao-tools/ao-stmload/ao-stmload.c
@@ -26,293 +26,107 @@
#include <getopt.h>
#include <string.h>
#include "stlink-common.h"
+#include "ao-elf.h"
+#include "ccdbg.h"
+#include "cc-usb.h"
+#include "cc.h"
+#include "ao-stmload.h"
#define AO_USB_DESC_STRING 3
-struct sym {
- unsigned addr;
- char *name;
- int required;
-} ao_symbols[] = {
+struct sym ao_symbols[] = {
- { 0, "ao_romconfig_version", 1 },
+ { 0, AO_BOOT_APPLICATION_BASE + 0x100, "ao_romconfig_version", 1 },
#define AO_ROMCONFIG_VERSION (ao_symbols[0].addr)
- { 0, "ao_romconfig_check", 1 },
+ { 0, AO_BOOT_APPLICATION_BASE + 0x102, "ao_romconfig_check", 1 },
#define AO_ROMCONFIG_CHECK (ao_symbols[1].addr)
- { 0, "ao_serial_number", 1 },
+ { 0, AO_BOOT_APPLICATION_BASE + 0x104, "ao_serial_number", 1 },
#define AO_SERIAL_NUMBER (ao_symbols[2].addr)
- { 0, "ao_usb_descriptors", 0 },
-#define AO_USB_DESCRIPTORS (ao_symbols[3].addr)
+ { 0, AO_BOOT_APPLICATION_BASE + 0x108, "ao_radio_cal", 0 },
+#define AO_RADIO_CAL (ao_symbols[3].addr)
- { 0, "ao_radio_cal", 0 },
-#define AO_RADIO_CAL (ao_symbols[4].addr)
+ { 0, AO_BOOT_APPLICATION_BASE + 0x10c, "ao_usb_descriptors", 0 },
+#define AO_USB_DESCRIPTORS (ao_symbols[4].addr)
};
#define NUM_SYMBOLS 5
#define NUM_REQUIRED_SYMBOLS 3
-/*
- * Look through the Elf file for the AltOS symbols
- * that can be adjusted before the image is written
- * to the device
- */
-static int
-find_symbols (Elf *e)
-{
- Elf_Scn *scn;
- Elf_Data *symbol_data = NULL;
- GElf_Shdr shdr;
- GElf_Sym sym;
- int i, symbol_count, s;
- int required = 0;
- char *symbol_name;
-
- /*
- * Find the symbols
- */
-
- scn = NULL;
- while ((scn = elf_nextscn(e, scn)) != NULL) {
- if (gelf_getshdr(scn, &shdr) != &shdr)
- return 0;
-
- if (shdr.sh_type == SHT_SYMTAB) {
- symbol_data = elf_getdata(scn, NULL);
- symbol_count = shdr.sh_size / shdr.sh_entsize;
- break;
- }
- }
-
- if (!symbol_data)
- return 0;
-
- for (i = 0; i < symbol_count; i++) {
- gelf_getsym(symbol_data, i, &sym);
-
- symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name);
-
- for (s = 0; s < NUM_SYMBOLS; s++)
- if (!strcmp (ao_symbols[s].name, symbol_name)) {
- int t;
- ao_symbols[s].addr = sym.st_value;
- if (ao_symbols[s].required)
- ++required;
- }
- }
-
- return required >= NUM_REQUIRED_SYMBOLS;
-}
-
-struct load {
- uint32_t addr;
- uint32_t len;
- uint8_t buf[0];
-};
-
-uint32_t round4(uint32_t a) {
- return (a + 3) & ~3;
-}
-
-struct load *
-new_load (uint32_t addr, uint32_t len)
-{
- struct load *new;
-
- len = round4(len);
- new = calloc (1, sizeof (struct load) + len);
- if (!new)
- abort();
-
- new->addr = addr;
- new->len = len;
- return new;
-}
-
-void
-load_paste(struct load *into, struct load *from)
-{
- if (from->addr < into->addr || into->addr + into->len < from->addr + from->len)
- abort();
-
- memcpy(into->buf + from->addr - into->addr, from->buf, from->len);
-}
-
-/*
- * Make a new load structure large enough to hold the old one and
- * the new data
- */
-struct load *
-expand_load(struct load *from, uint32_t addr, uint32_t len)
-{
- struct load *new;
-
- if (from) {
- uint32_t from_last = from->addr + from->len;
- uint32_t last = addr + len;
-
- if (addr > from->addr)
- addr = from->addr;
- if (last < from_last)
- last = from_last;
-
- len = last - addr;
-
- if (addr == from->addr && len == from->len)
- return from;
- }
- new = new_load(addr, len);
- if (from) {
- load_paste(new, from);
- free (from);
- }
- return new;
-}
-
-/*
- * Create a new load structure with data from the existing one
- * and the new data
- */
-struct load *
-load_write(struct load *from, uint32_t addr, uint32_t len, void *data)
-{
- struct load *new;
-
- new = expand_load(from, addr, len);
- memcpy(new->buf + addr - new->addr, data, len);
- return new;
-}
-
-/*
- * Construct a large in-memory block for all
- * of the loaded sections of the program
- */
-static struct load *
-get_load(Elf *e)
-{
- Elf_Scn *scn;
- size_t shstrndx;
- GElf_Shdr shdr;
- Elf_Data *data;
- uint8_t *buf;
- char *got_name;
- size_t nphdr;
- int p;
- GElf_Phdr phdr;
- struct load *load = NULL;
-
- if (elf_getshdrstrndx(e, &shstrndx) < 0)
- return 0;
-
- if (elf_getphdrnum(e, &nphdr) < 0)
- return 0;
-
- /*
- * As far as I can tell, all of the phdr sections should
- * be flashed to memory
- */
- for (p = 0; p < nphdr; p++) {
-
- /* Find this phdr */
- gelf_getphdr(e, p, &phdr);
-
- /* Get the associated file section */
- scn = gelf_offscn(e, phdr.p_offset);
-
- if (gelf_getshdr(scn, &shdr) != &shdr)
- abort();
-
- data = elf_getdata(scn, NULL);
-
- /* Write the section data into the memory block */
- load = load_write(load, phdr.p_paddr, phdr.p_filesz, data->d_buf);
- }
- return load;
-}
+int ao_num_symbols = NUM_SYMBOLS;
+int ao_num_required_symbols = NUM_REQUIRED_SYMBOLS;
/*
* Edit the to-be-written memory block
*/
static int
-rewrite(struct load *load, unsigned addr, uint8_t *data, int len)
+rewrite(struct hex_image *load, unsigned address, uint8_t *data, int length)
{
int i;
- if (addr < load->addr || load->addr + load->len < addr + len)
+ if (address < load->address || load->address + load->length < address + length)
return 0;
- printf("rewrite %04x:", addr);
- for (i = 0; i < len; i++)
- printf (" %02x", load->buf[addr - load->addr + i]);
+ printf("rewrite %04x:", address);
+ for (i = 0; i < length; i++)
+ printf (" %02x", load->data[address - load->address + i]);
printf(" ->");
- for (i = 0; i < len; i++)
+ for (i = 0; i < length; i++)
printf (" %02x", data[i]);
printf("\n");
- memcpy(load->buf + addr - load->addr, data, len);
+ memcpy(load->data + address - load->address, data, length);
}
/*
- * Open the specified ELF file and
- * check for the symbols we need
+ * Read a 16-bit value from the USB target
*/
-Elf *
-ao_open_elf(char *name)
+static uint16_t
+get_uint16_cc(struct cc_usb *cc, uint32_t addr)
{
- int fd;
- Elf *e;
- Elf_Scn *scn;
- Elf_Data *symbol_data = NULL;
- GElf_Shdr shdr;
- GElf_Sym sym;
- size_t n, shstrndx, sz;
- int i, symbol_count, s;
- int required = 0;
-
- if (elf_version(EV_CURRENT) == EV_NONE)
- return NULL;
-
- fd = open(name, O_RDONLY, 0);
-
- if (fd < 0)
- return NULL;
+ struct hex_image *hex = ao_self_read(cc, addr, 2);
+ uint16_t v;
+ uint8_t *data;
- e = elf_begin(fd, ELF_C_READ, NULL);
-
- if (!e)
- return NULL;
-
- if (elf_kind(e) != ELF_K_ELF)
- return NULL;
-
- if (elf_getshdrstrndx(e, &shstrndx) != 0)
- return NULL;
+ if (!hex)
+ return 0;
+ data = hex->data + addr - hex->address;
+ v = data[0] | (data[1] << 8);
+ free(hex);
+ return v;
+}
- if (!find_symbols(e)) {
- fprintf (stderr, "Cannot find required symbols\n");
- return NULL;
- }
+static uint32_t
+get_uint32_cc(struct cc_usb *cc, uint32_t addr)
+{
+ struct hex_image *hex = ao_self_read(cc, addr, 4);
+ uint32_t v;
+ uint8_t *data;
- return e;
+ if (!hex)
+ return 0;
+ data = hex->data + addr - hex->address;
+ v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+ free(hex);
+ return v;
}
/*
- * Read a 32-bit value from the target device with arbitrary
+ * Read a 16-bit value from the target device with arbitrary
* alignment
*/
-static uint32_t
-get_uint32(stlink_t *sl, uint32_t addr)
+static uint16_t
+get_uint16_sl(stlink_t *sl, uint32_t addr)
{
const uint8_t *data = sl->q_buf;
uint32_t actual_addr;
int off;
- uint32_t result;
+ uint16_t result;
sl->q_len = 0;
- printf ("read 0x%x\n", addr);
actual_addr = addr & ~3;
@@ -322,25 +136,37 @@ get_uint32(stlink_t *sl, uint32_t addr)
abort();
off = addr & 3;
- result = data[off] | (data[off + 1] << 8) | (data[off+2] << 16) | (data[off+3] << 24);
- printf ("read 0x%08x = 0x%08x\n", addr, result);
+ result = data[off] | (data[off + 1] << 8);
+ return result;
+}
+
+static uint16_t
+get_uint16(stlink_t *sl, struct cc_usb *cc, uint32_t addr)
+{
+ uint16_t result;
+ if (cc)
+ result = get_uint16_cc(cc, addr);
+ else
+ result = get_uint16_sl(sl, addr);
+ printf ("read 0x%08x = 0x%04x\n", addr, result);
return result;
}
/*
- * Read a 16-bit value from the target device with arbitrary
+ * Read a 32-bit value from the target device with arbitrary
* alignment
*/
-static uint16_t
-get_uint16(stlink_t *sl, uint32_t addr)
+static uint32_t
+get_uint32_sl(stlink_t *sl, uint32_t addr)
{
const uint8_t *data = sl->q_buf;
uint32_t actual_addr;
int off;
- uint16_t result;
+ uint32_t result;
sl->q_len = 0;
+ printf ("read 0x%x\n", addr);
actual_addr = addr & ~3;
@@ -350,8 +176,24 @@ get_uint16(stlink_t *sl, uint32_t addr)
abort();
off = addr & 3;
- result = data[off] | (data[off + 1] << 8);
- printf ("read 0x%08x = 0x%04x\n", addr, result);
+ result = data[off] | (data[off + 1] << 8) | (data[off+2] << 16) | (data[off+3] << 24);
+ return result;
+}
+
+/*
+ * Read a 32-bit value from the target device with arbitrary
+ * alignment
+ */
+static uint32_t
+get_uint32(stlink_t *sl, struct cc_usb *cc, uint32_t addr)
+{
+ uint32_t result;
+
+ if (cc)
+ result = get_uint32_cc(cc, addr);
+ else
+ result = get_uint32_sl(sl, addr);
+ printf ("read 0x%08x = 0x%08x\n", addr, result);
return result;
}
@@ -364,10 +206,10 @@ get_uint16(stlink_t *sl, uint32_t addr)
* places this at 0x100 from the start of the rom section
*/
static int
-check_flashed(stlink_t *sl)
+check_flashed(stlink_t *sl, struct cc_usb *cc)
{
- uint16_t romconfig_version = get_uint16(sl, AO_ROMCONFIG_VERSION);
- uint16_t romconfig_check = get_uint16(sl, AO_ROMCONFIG_CHECK);
+ uint16_t romconfig_version = get_uint16(sl, cc, AO_ROMCONFIG_VERSION);
+ uint16_t romconfig_check = get_uint16(sl, cc, AO_ROMCONFIG_CHECK);
if (romconfig_version != (uint16_t) ~romconfig_check) {
fprintf (stderr, "Device has not been flashed before\n");
@@ -377,21 +219,28 @@ check_flashed(stlink_t *sl)
}
static const struct option options[] = {
+ { .name = "stlink", .has_arg = 0, .val = 'S' },
+ { .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
{ .name = "cal", .has_arg = 1, .val = 'c' },
{ .name = "serial", .has_arg = 1, .val = 's' },
+ { .name = "verbose", .has_arg = 0, .val = 'v' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
- fprintf(stderr, "usage: %s [--cal=<radio-cal>] [--serial=<serial>] file.elf\n", program);
+ fprintf(stderr, "usage: %s [--stlink] [--verbose] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
exit(1);
}
void
-done(stlink_t *sl, int code)
+done(stlink_t *sl, struct cc_usb *cc, int code)
{
+ if (cc) {
+/* cc_usb_printf(cc, "a\n"); */
+ cc_usb_close(cc);
+ }
if (sl) {
stlink_reset(sl);
stlink_run(sl);
@@ -401,6 +250,17 @@ done(stlink_t *sl, int code)
exit (code);
}
+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;
+}
+
int
main (int argc, char **argv)
{
@@ -419,12 +279,21 @@ main (int argc, char **argv)
char cal_int[4];
char *cal_end;
int c;
- stlink_t *sl;
+ stlink_t *sl = NULL;
int was_flashed = 0;
- struct load *load;
-
- while ((c = getopt_long(argc, argv, "D:c:s:", options, NULL)) != -1) {
+ struct hex_image *load;
+ int tries;
+ struct cc_usb *cc = NULL;
+ int use_stlink = 0;
+ char *tty = NULL;
+ int success;
+ int verbose = 0;
+
+ while ((c = getopt_long(argc, argv, "T:D:c:s:Sv", options, NULL)) != -1) {
switch (c) {
+ case 'T':
+ tty = optarg;
+ break;
case 'D':
device = optarg;
break;
@@ -438,92 +307,168 @@ main (int argc, char **argv)
if (serial_end == optarg || *serial_end != '\0')
usage(argv[0]);
break;
+ case 'S':
+ use_stlink = 1;
+ break;
+ case 'v':
+ verbose++;
+ break;
default:
usage(argv[0]);
break;
}
}
+ ao_self_verbose = verbose;
+
+ if (verbose > 1)
+ ccdbg_add_debug(CC_DEBUG_BITBANG);
+
filename = argv[optind];
if (filename == NULL)
usage(argv[0]);
- /*
- * Open the source file and load the symbols and
- * flash data
- */
-
- e = ao_open_elf(filename);
- if (!e) {
- fprintf(stderr, "Cannot open file \"%s\"\n", filename);
- exit(1);
- }
-
- if (!find_symbols(e)) {
- fprintf(stderr, "Cannot find symbols in \"%s\"\n", filename);
- exit(1);
- }
+ if (ends_with (filename, ".elf")) {
+ load = ao_load_elf(filename);
+ } else if (ends_with (filename, ".ihx")) {
+ int i;
+ load = ccdbg_hex_load(filename);
+ for (i = 0; i < ao_num_symbols; i++)
+ ao_symbols[i].addr = ao_symbols[i].default_addr;
+ } else
+ usage(argv[0]);
- if (!(load = get_load(e))) {
- fprintf(stderr, "Cannot find program data in \"%s\"\n", filename);
- exit(1);
- }
-
- /* Connect to the programming dongle
- */
+ if (use_stlink) {
+ /* Connect to the programming dongle
+ */
- if (device) {
- sl = stlink_v1_open(50);
- } else {
- sl = stlink_open_usb(50);
+ for (tries = 0; tries < 3; tries++) {
+ if (device) {
+ sl = stlink_v1_open(50);
+ } else {
+ sl = stlink_open_usb(50);
- }
- if (!sl) {
- fprintf (stderr, "No STLink devices present\n");
- done (sl, 1);
- }
+ }
+ if (!sl) {
+ fprintf (stderr, "No STLink devices present\n");
+ done (sl, NULL, 1);
+ }
- sl->verbose = 50;
+ if (sl->chip_id != 0)
+ break;
+ stlink_reset(sl);
+ stlink_close(sl);
+ sl = NULL;
+ }
+ if (!sl) {
+ fprintf (stderr, "Debugger connection failed\n");
+ exit(1);
+ }
- /* Verify that the loaded image fits entirely within device flash
- */
- if (load->addr < sl->flash_base ||
- sl->flash_base + sl->flash_size < load->addr + load->len) {
- fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename,
- load->addr, load->addr + load->len);
- done(sl, 1);
- }
+ /* Verify that the loaded image fits entirely within device flash
+ */
+ if (load->address < sl->flash_base ||
+ sl->flash_base + sl->flash_size < load->address + load->length) {
+ fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename,
+ load->address, load->address + load->length);
+ done(sl, NULL, 1);
+ }
- /* Enter debugging mode
- */
- if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
- stlink_exit_dfu_mode(sl);
+ /* Enter debugging mode
+ */
+ if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
+ stlink_exit_dfu_mode(sl);
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
- stlink_enter_swd_mode(sl);
+ if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
+ stlink_enter_swd_mode(sl);
+ } else {
+ int is_loader;
+ int tries;
+
+ for (tries = 0; tries < 3; tries++) {
+ char *this_tty = tty;
+ if (!this_tty)
+ this_tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
+ if (!this_tty)
+ this_tty = cc_usbdevs_find_by_arg(device, "MegaMetrum");
+ if (!this_tty)
+ this_tty = getenv("ALTOS_TTY");
+ if (!this_tty)
+ this_tty="/dev/ttyACM0";
+
+ cc = cc_usb_open(this_tty);
+
+ if (!cc)
+ exit(1);
+ cc_usb_printf(cc, "v\n");
+ is_loader = 0;
+ for (;;) {
+ char line[256];
+ cc_usb_getline(cc, line, sizeof(line));
+ if (!strncmp(line, "altos-loader", 12))
+ is_loader = 1;
+ if (!strncmp(line, "software-version", 16))
+ break;
+ }
+ if (is_loader)
+ break;
+ printf ("rebooting to loader\n");
+ cc_usb_printf(cc, "X\n");
+ cc_usb_close(cc);
+ sleep(1);
+ cc = NULL;
+ }
+ if (!is_loader) {
+ fprintf(stderr, "Cannot switch to boot loader\n");
+ exit(1);
+ }
+#if 0
+ {
+ uint8_t check[256];
+ int i = 0;
+
+ ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, check);
+ for (;;) {
+ uint8_t block[256];
+ putchar ('.');
+ if (++i == 40) {
+ putchar('\n');
+ i = 0;
+ }
+ fflush(stdout);
+ ao_self_block_write(cc, AO_BOOT_APPLICATION_BASE, block);
+ ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, block);
+ if (memcmp(block, check, 256) != 0) {
+ fprintf (stderr, "read differed\n");
+ exit(1);
+ }
+ }
+ }
+#endif
+ }
/* Go fetch existing config values
* if available
*/
- was_flashed = check_flashed(sl);
+ was_flashed = check_flashed(sl, cc);
if (!serial) {
if (!was_flashed) {
fprintf (stderr, "Must provide serial number\n");
- done(sl, 1);
+ done(sl, cc, 1);
}
- serial = get_uint16(sl, AO_SERIAL_NUMBER);
+ serial = get_uint16(sl, cc, AO_SERIAL_NUMBER);
if (!serial || serial == 0xffff) {
fprintf (stderr, "Invalid existing serial %d\n", serial);
- done(sl, 1);
+ done(sl, cc, 1);
}
}
if (!cal && AO_RADIO_CAL && was_flashed) {
- cal = get_uint32(sl, AO_RADIO_CAL);
+ cal = get_uint32(sl, cc, AO_RADIO_CAL);
if (!cal || cal == 0xffffffff) {
fprintf (stderr, "Invalid existing rf cal %d\n", cal);
- done(sl, 1);
+ done(sl, cc, 1);
}
}
@@ -536,32 +481,31 @@ main (int argc, char **argv)
if (!rewrite(load, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {
fprintf(stderr, "Cannot rewrite serial integer at %08x\n",
AO_SERIAL_NUMBER);
- done(sl, 1);
+ done(sl, cc, 1);
}
if (AO_USB_DESCRIPTORS) {
- unsigned usb_descriptors;
- usb_descriptors = AO_USB_DESCRIPTORS - load->addr;
+ uint32_t usb_descriptors = AO_USB_DESCRIPTORS - load->address;
string_num = 0;
- while (load->buf[usb_descriptors] != 0 && usb_descriptors < load->len) {
- if (load->buf[usb_descriptors+1] == AO_USB_DESC_STRING) {
+ while (load->data[usb_descriptors] != 0 && usb_descriptors < load->length) {
+ if (load->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
++string_num;
if (string_num == 4)
break;
}
- usb_descriptors += load->buf[usb_descriptors];
+ usb_descriptors += load->data[usb_descriptors];
}
- if (usb_descriptors >= load->len || load->buf[usb_descriptors] == 0 ) {
+ if (usb_descriptors >= load->length || load->data[usb_descriptors] == 0 ) {
fprintf(stderr, "Cannot rewrite serial string at %08x\n", AO_USB_DESCRIPTORS);
- done(sl, 1);
+ done(sl, cc, 1);
}
- serial_ucs2_len = load->buf[usb_descriptors] - 2;
+ serial_ucs2_len = load->data[usb_descriptors] - 2;
serial_ucs2 = malloc(serial_ucs2_len);
if (!serial_ucs2) {
fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len);
- done(sl, 1);
+ done(sl, cc, 1);
}
s = serial;
for (i = serial_ucs2_len / 2; i; i--) {
@@ -569,9 +513,9 @@ main (int argc, char **argv)
serial_ucs2[i * 2 - 2] = (s % 10) + '0';
s /= 10;
}
- if (!rewrite(load, usb_descriptors + 2 + load->addr, serial_ucs2, serial_ucs2_len)) {
+ if (!rewrite(load, usb_descriptors + 2 + load->address, serial_ucs2, serial_ucs2_len)) {
fprintf (stderr, "Cannot rewrite USB descriptor at %08x\n", AO_USB_DESCRIPTORS);
- done(sl, 1);
+ done(sl, cc, 1);
}
}
@@ -589,10 +533,15 @@ main (int argc, char **argv)
/* And flash the resulting image to the device
*/
- if (stlink_write_flash(sl, load->addr, load->buf, load->len) < 0) {
+ if (cc)
+ success = ao_self_write(cc, load);
+ else
+ success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0);
+
+ if (!success) {
fprintf (stderr, "\"%s\": Write failed\n", filename);
- done(sl, 1);
+ done(sl, cc, 1);
}
- done(sl, 0);
+ done(sl, cc, 0);
}
diff --git a/ao-tools/ao-stmload/ao-stmload.h b/ao-tools/ao-stmload/ao-stmload.h
new file mode 100644
index 00000000..98884535
--- /dev/null
+++ b/ao-tools/ao-stmload/ao-stmload.h
@@ -0,0 +1,49 @@
+/*
+ * 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; 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_STMLOAD_H_
+#define _AO_STMLOAD_H_
+
+struct sym {
+ unsigned addr;
+ unsigned default_addr;
+ char *name;
+ int required;
+};
+
+#define AO_BOOT_APPLICATION_BASE 0x08001000
+
+extern struct sym ao_symbols[];
+
+extern int ao_num_symbols;
+extern int ao_num_required_symbols;
+
+void
+ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256]);
+
+void
+ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256]);
+
+struct hex_image *
+ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length);
+
+int
+ao_self_write(struct cc_usb *cc, struct hex_image *image);
+
+extern int ao_self_verbose;
+
+#endif /* _AO_STMLOAD_H_ */
diff --git a/ao-tools/ao-telem/ao-telem.c b/ao-tools/ao-telem/ao-telem.c
index e7fc8e26..d2dae5a7 100644
--- a/ao-tools/ao-telem/ao-telem.c
+++ b/ao-tools/ao-telem/ao-telem.c
@@ -24,6 +24,7 @@
#include "cc.h"
static const struct option options[] = {
+ { .name = "crc", .has_arg = 0, .val = 'c' },
{ 0, 0, 0, 0},
};
@@ -44,8 +45,12 @@ main (int argc, char **argv)
char *s;
FILE *file;
int serial;
- while ((c = getopt_long(argc, argv, "", options, NULL)) != -1) {
+ int ignore_crc = 0;
+ while ((c = getopt_long(argc, argv, "c", options, NULL)) != -1) {
switch (c) {
+ case 'c':
+ ignore_crc = 1;
+ break;
default:
usage(argv[0]);
break;
@@ -74,7 +79,7 @@ main (int argc, char **argv)
printf ("serial %5d rssi %d status %02x tick %5d type %3d ",
telem.generic.serial, rssi, telem.generic.status,
telem.generic.tick, telem.generic.type);
- if ((telem.generic.status & (1 << 7)) == 0) {
+ if (!ignore_crc && (telem.generic.status & (1 << 7)) == 0) {
printf ("CRC error\n");
continue;
}
diff --git a/ao-tools/lib/cc-telemetry.c b/ao-tools/lib/cc-telemetry.c
index 99da2680..88da7f03 100644
--- a/ao-tools/lib/cc-telemetry.c
+++ b/ao-tools/lib/cc-telemetry.c
@@ -60,3 +60,33 @@ cc_telemetry_parse(const char *input_line, union ao_telemetry_all *telemetry)
memcpy(telemetry, hex+1, 34);
return TRUE;
}
+
+uint8_t
+cc_telemetry_cksum(const union ao_telemetry_all *telemetry)
+{
+ const uint8_t *x = (const uint8_t *) telemetry;
+ int i;
+ uint8_t sum = 0x5a;
+ for (i = 0; i < 34; i++)
+ sum += x[i];
+ return sum;
+}
+
+void
+cc_telemetry_unparse(const union ao_telemetry_all *telemetry, char output_line[CC_TELEMETRY_BUFSIZE])
+{
+ uint8_t hex[36];
+ int i;
+ int p;
+
+ hex[0] = 34;
+ memcpy(hex+1, telemetry, 34);
+ hex[35] = cc_telemetry_cksum(telemetry);
+ strcpy(output_line, "TELEM ");
+ p = strlen(output_line);
+ for (i = 0; i < 36; i++) {
+ sprintf(output_line + p, "%02x", hex[i]);
+ p += 2;
+ }
+}
+
diff --git a/ao-tools/lib/cc-telemetry.h b/ao-tools/lib/cc-telemetry.h
index e849cd3b..9a5be49f 100644
--- a/ao-tools/lib/cc-telemetry.h
+++ b/ao-tools/lib/cc-telemetry.h
@@ -237,7 +237,19 @@ union ao_telemetry_all {
struct ao_telemetry_baro baro;
};
+#define CC_TELEMETRY_HEADER "TELEM"
+
+/* "TELEM " 1 byte length 32 data bytes 1 rssi 1 status 1 checksum 1 null */
+
+#define CC_TELEMETRY_BUFSIZE (6 + (1 + 32 + 3) * 2 + 1)
+
int
cc_telemetry_parse(const char *input_line, union ao_telemetry_all *telemetry);
+uint8_t
+cc_telemetry_cksum(const union ao_telemetry_all *telemetry);
+
+void
+cc_telemetry_unparse(const union ao_telemetry_all *telemetry, char output_line[CC_TELEMETRY_BUFSIZE]);
+
#endif
diff --git a/ao-tools/lib/cc-usb.c b/ao-tools/lib/cc-usb.c
index 1580c6d9..d7ac138c 100644
--- a/ao-tools/lib/cc-usb.c
+++ b/ao-tools/lib/cc-usb.c
@@ -123,9 +123,10 @@ cc_handle_hex_read(struct cc_usb *cc)
static void
cc_usb_dbg(int indent, uint8_t *bytes, int len)
{
- int eol = 1;
+ static int eol = 1;
int i;
uint8_t c;
+ ccdbg_debug(CC_DEBUG_BITBANG, "<<<%d bytes>>>", len);
while (len--) {
c = *bytes++;
if (eol) {
@@ -135,12 +136,17 @@ cc_usb_dbg(int indent, uint8_t *bytes, int len)
}
switch (c) {
case '\r':
- ccdbg_debug(CC_DEBUG_BITBANG, "^M");
+ ccdbg_debug(CC_DEBUG_BITBANG, "\\r");
break;
case '\n':
eol = 1;
+ ccdbg_debug(CC_DEBUG_BITBANG, "\\n\n");
+ break;
default:
- ccdbg_debug(CC_DEBUG_BITBANG, "%c", c);
+ if (c < ' ' || c > '~')
+ ccdbg_debug(CC_DEBUG_BITBANG, "\\%02x", c);
+ else
+ ccdbg_debug(CC_DEBUG_BITBANG, "%c", c);
}
}
}
@@ -254,10 +260,10 @@ cc_usb_printf(struct cc_usb *cc, char *format, ...)
}
int
-cc_usb_getchar(struct cc_usb *cc)
+cc_usb_getchar_timeout(struct cc_usb *cc, int timeout)
{
while (cc->in_pos == cc->in_count) {
- if (_cc_usb_sync(cc, 5000) < 0) {
+ if (_cc_usb_sync(cc, timeout) < 0) {
fprintf(stderr, "USB link timeout\n");
exit(1);
}
@@ -265,6 +271,12 @@ cc_usb_getchar(struct cc_usb *cc)
return cc->in_buf[cc->in_pos++];
}
+int
+cc_usb_getchar(struct cc_usb *cc)
+{
+ return cc_usb_getchar_timeout(cc, 5000);
+}
+
void
cc_usb_getline(struct cc_usb *cc, char *line, int max)
{
@@ -375,11 +387,12 @@ cc_usb_reset(struct cc_usb *cc)
}
void
-cc_usb_open_remote(struct cc_usb *cc, int channel)
+cc_usb_open_remote(struct cc_usb *cc, int freq, char *call)
{
if (!cc->remote) {
- printf ("channel %d\n", channel);
- cc_usb_printf(cc, "\nc r %d\np\nE 0\n", channel);
+ fprintf (stderr, "freq %dkHz\n", freq);
+ fprintf (stderr, "call %s\n", call);
+ cc_usb_printf(cc, "\nc F %d\nc c %s\np\nE 0\n", freq, call);
do {
cc->in_count = cc->in_pos = 0;
_cc_usb_sync(cc, 100);
@@ -419,6 +432,8 @@ cc_usb_open(char *tty)
tcgetattr(cc->fd, &termios);
save_termios = termios;
cfmakeraw(&termios);
+ cfsetospeed(&termios, B9600);
+ cfsetispeed(&termios, B9600);
tcsetattr(cc->fd, TCSAFLUSH, &termios);
cc_usb_printf(cc, "\nE 0\nm 0\n");
do {
diff --git a/ao-tools/lib/cc-usb.h b/ao-tools/lib/cc-usb.h
index d3539281..f1193456 100644
--- a/ao-tools/lib/cc-usb.h
+++ b/ao-tools/lib/cc-usb.h
@@ -54,6 +54,9 @@ void
cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len);
int
+cc_usb_getchar_timeout(struct cc_usb *cc, int timeout);
+
+int
cc_usb_getchar(struct cc_usb *cc);
void
@@ -63,7 +66,7 @@ void
cc_usb_printf(struct cc_usb *cc, char *format, ...);
void
-cc_usb_open_remote(struct cc_usb *cc, int channel);
+cc_usb_open_remote(struct cc_usb *cc, int freq, char *call);
void
cc_usb_close_remote(struct cc_usb *cc);
diff --git a/ao-tools/lib/cc-usbdev.c b/ao-tools/lib/cc-usbdev.c
index a19e231c..95bfa244 100644
--- a/ao-tools/lib/cc-usbdev.c
+++ b/ao-tools/lib/cc-usbdev.c
@@ -132,13 +132,25 @@ usb_tty(char *sys)
/* Check for tty/ttyACMx style names
*/
tty_dir = cc_fullname(endpoint_full, "tty");
- free(endpoint_full);
ntty = scandir(tty_dir, &namelist,
dir_filter_tty,
alphasort);
free (tty_dir);
if (ntty > 0) {
tty = cc_fullname("/dev", namelist[0]->d_name);
+ free(endpoint_full);
+ free(namelist);
+ return tty;
+ }
+
+ /* Check for ttyACMx style names
+ */
+ ntty = scandir(endpoint_full, &namelist,
+ dir_filter_tty,
+ alphasort);
+ free(endpoint_full);
+ if (ntty > 0) {
+ tty = cc_fullname("/dev", namelist[0]->d_name);
free(namelist);
return tty;
}
@@ -197,6 +209,15 @@ dir_filter_dev(const struct dirent *d)
return 1;
}
+static int
+is_am(int idVendor, int idProduct) {
+ if (idVendor == 0xfffe)
+ return 1;
+ if (idVendor == 0x0403 && idProduct == 0x6015)
+ return 1;
+ return 0;
+}
+
struct cc_usbdevs *
cc_usbdevs_scan(void)
{
@@ -220,7 +241,7 @@ cc_usbdevs_scan(void)
dir = cc_fullname(USB_DEVICES, ents[e]->d_name);
dev = usb_scan_device(dir);
free(dir);
- if (dev->idVendor == 0xfffe && dev->tty) {
+ if (is_am(dev->idVendor, dev->idProduct) && dev->tty) {
if (devs->dev)
devs->dev = realloc(devs->dev,
(devs->ndev + 1) * sizeof (struct usbdev *));
diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h
index 6257ee44..625540bb 100644
--- a/ao-tools/lib/cc.h
+++ b/ao-tools/lib/cc.h
@@ -269,6 +269,122 @@ struct cc_telem {
int
cc_telem_parse(const char *input_line, struct cc_telem *telem);
+struct ao_log_mega {
+ char type; /* 0 */
+ uint8_t is_config; /* 1 */
+ uint16_t tick; /* 2 */
+ union { /* 4 */
+ /* AO_LOG_FLIGHT */
+ struct {
+ uint16_t flight; /* 4 */
+ int16_t ground_accel; /* 6 */
+ uint32_t ground_pres; /* 8 */
+ } flight; /* 12 */
+ /* AO_LOG_STATE */
+ struct {
+ uint16_t state;
+ uint16_t reason;
+ } state;
+ /* AO_LOG_SENSOR */
+ struct {
+ uint32_t pres; /* 4 */
+ uint32_t temp; /* 8 */
+ int16_t accel_x; /* 12 */
+ int16_t accel_y; /* 14 */
+ int16_t accel_z; /* 16 */
+ int16_t gyro_x; /* 18 */
+ int16_t gyro_y; /* 20 */
+ int16_t gyro_z; /* 22 */
+ int16_t mag_x; /* 24 */
+ int16_t mag_y; /* 26 */
+ int16_t mag_z; /* 28 */
+ int16_t accel; /* 30 */
+ } sensor; /* 32 */
+ /* AO_LOG_TEMP_VOLT */
+ struct {
+ int16_t v_batt; /* 4 */
+ int16_t v_pbatt; /* 6 */
+ int16_t n_sense; /* 8 */
+ int16_t sense[10]; /* 10 */
+ } volt; /* 30 */
+ /* AO_LOG_GPS_TIME */
+ struct {
+ int32_t latitude; /* 4 */
+ int32_t longitude; /* 8 */
+ int16_t altitude; /* 12 */
+ uint8_t hour; /* 14 */
+ uint8_t minute; /* 15 */
+ uint8_t second; /* 16 */
+ uint8_t flags; /* 17 */
+ uint8_t year; /* 18 */
+ uint8_t month; /* 19 */
+ uint8_t day; /* 20 */
+ uint8_t pad; /* 21 */
+ } gps; /* 22 */
+ /* AO_LOG_GPS_SAT */
+ struct {
+ uint16_t channels; /* 4 */
+ struct {
+ uint8_t svid;
+ uint8_t c_n;
+ } sats[12]; /* 6 */
+ } gps_sat; /* 30 */
+
+ struct {
+ uint32_t kind;
+ int32_t data[6];
+ } config_int;
+
+ struct {
+ uint32_t kind;
+ char string[24];
+ } config_str;
+
+ /* Raw bytes */
+ uint8_t bytes[28];
+ } u;
+};
+
+#define AO_CONFIG_CONFIG 1
+#define AO_CONFIG_MAIN 2
+#define AO_CONFIG_APOGEE 3
+#define AO_CONFIG_LOCKOUT 4
+#define AO_CONFIG_FREQUENCY 5
+#define AO_CONFIG_RADIO_ENABLE 6
+#define AO_CONFIG_ACCEL_CAL 7
+#define AO_CONFIG_RADIO_CAL 8
+#define AO_CONFIG_MAX_LOG 9
+#define AO_CONFIG_IGNITE_MODE 10
+#define AO_CONFIG_PAD_ORIENTATION 11
+#define AO_CONFIG_SERIAL_NUMBER 12
+#define AO_CONFIG_LOG_FORMAT 13
+#define AO_CONFIG_MS5607_RESERVED 14
+#define AO_CONFIG_MS5607_SENS 15
+#define AO_CONFIG_MS5607_OFF 16
+#define AO_CONFIG_MS5607_TCS 17
+#define AO_CONFIG_MS5607_TCO 18
+#define AO_CONFIG_MS5607_TREF 19
+#define AO_CONFIG_MS5607_TEMPSENS 20
+#define AO_CONFIG_MS5607_CRC 21
+
+
+#define AO_LOG_FLIGHT 'F'
+#define AO_LOG_SENSOR 'A'
+#define AO_LOG_TEMP_VOLT 'T'
+#define AO_LOG_DEPLOY 'D'
+#define AO_LOG_STATE 'S'
+#define AO_LOG_GPS_TIME 'G'
+#define AO_LOG_GPS_LAT 'N'
+#define AO_LOG_GPS_LON 'W'
+#define AO_LOG_GPS_ALT 'H'
+#define AO_LOG_GPS_SAT 'V'
+#define AO_LOG_GPS_DATE 'Y'
+
+#define AO_LOG_CONFIG 'c'
+
+int
+cc_mega_parse(const char *input_line, struct ao_log_mega *l);
+
#ifndef TRUE
#define TRUE 1
#define FALSE 0
diff --git a/ao-tools/lib/ccdbg-flash.c b/ao-tools/lib/ccdbg-flash.c
index 3e672985..1b46870b 100644
--- a/ao-tools/lib/ccdbg-flash.c
+++ b/ao-tools/lib/ccdbg-flash.c
@@ -240,7 +240,6 @@ ccdbg_flash_lock(struct ccdbg *dbg, uint8_t lock)
uint8_t
ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
{
- uint16_t offset;
uint16_t flash_prog;
uint16_t flash_len;
uint8_t fwt;
@@ -249,7 +248,6 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
uint16_t flash_words;
uint8_t flash_words_high, flash_words_low;
uint16_t ram_addr;
- uint16_t pc;
uint8_t status;
uint16_t remain, this_time, start;
uint8_t verify[0x400];
@@ -284,8 +282,6 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
if (this_time > 0x400)
this_time = 0x400;
- offset = ram_addr - (image->address + start);
-
ccdbg_debug(CC_DEBUG_FLASH, "Upload %d bytes at 0x%04x\n", this_time, ram_addr);
ccdbg_write_memory(dbg, ram_addr, image->data + start, this_time);
#if 0
@@ -319,7 +315,6 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_LOW, flash_words_low);
ccdbg_set_pc(dbg, flash_prog);
- pc = ccdbg_get_pc(dbg);
ccdbg_debug(CC_DEBUG_FLASH, "Flashing %d bytes at 0x%04x\n",
this_time, flash_addr);
status = ccdbg_resume(dbg);
diff --git a/ao-tools/lib/ccdbg-hex.c b/ao-tools/lib/ccdbg-hex.c
index dfea9156..184b4e3b 100644
--- a/ao-tools/lib/ccdbg-hex.c
+++ b/ao-tools/lib/ccdbg-hex.c
@@ -233,15 +233,6 @@ ccdbg_hex_file_free(struct hex_file *hex)
free(hex);
}
-static int
-ccdbg_hex_record_compar(const void *av, const void *bv)
-{
- const struct hex_record *a = *(struct hex_record **) av;
- const struct hex_record *b = *(struct hex_record **) bv;
-
- return (int) a->address - (int) b->address;
-}
-
struct hex_file *
ccdbg_hex_file_read(FILE *file, char *name)
{
@@ -272,11 +263,6 @@ ccdbg_hex_file_read(FILE *file, char *name)
if (record->type == HEX_RECORD_EOF)
done = 1;
}
- /*
- * Sort them into increasing addresses, except for EOF
- */
- qsort(hex->records, hex->nrecord - 1, sizeof (struct hex_record *),
- ccdbg_hex_record_compar);
return hex;
bail:
@@ -288,16 +274,45 @@ struct hex_image *
ccdbg_hex_image_create(struct hex_file *hex)
{
struct hex_image *image;
- struct hex_record *first, *last, *record;
+ struct hex_record *record;
int i;
+ uint32_t addr;
uint32_t base, bound;
uint32_t offset;
+ uint32_t extended_addr;
+
int length;
- first = hex->records[0];
- last = hex->records[hex->nrecord - 2]; /* skip EOF */
- base = (uint32_t) first->address;
- bound = (uint32_t) last->address + (uint32_t) last->length;
+ base = 0xffffffff;
+ bound = 0x0;
+ extended_addr = 0;
+ for (i = 0; i < hex->nrecord; i++) {
+ uint32_t r_bound;
+ record = hex->records[i];
+ switch (record->type) {
+ case 0:
+ addr = extended_addr + record->address;
+ r_bound = addr + record->length;
+ if (addr < base)
+ base = addr;
+ if (r_bound > bound)
+ bound = r_bound;
+ break;
+ case 1:
+ break;
+ case 2:
+ if (record->length != 2)
+ return NULL;
+ extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
+ break;
+ case 4:
+ if (record->length != 2)
+ return NULL;
+ extended_addr = ((record->data[0] << 8) | record->data[1]) << 16;
+ break;
+ }
+
+ }
length = bound - base;
image = calloc(sizeof(struct hex_image) + length, 1);
if (!image)
@@ -305,10 +320,24 @@ ccdbg_hex_image_create(struct hex_file *hex)
image->address = base;
image->length = length;
memset(image->data, 0xff, length);
- for (i = 0; i < hex->nrecord - 1; i++) {
+ extended_addr = 0;
+ for (i = 0; i < hex->nrecord; i++) {
record = hex->records[i];
- offset = record->address - base;
- memcpy(image->data + offset, record->data, record->length);
+ switch (record->type) {
+ case 0:
+ addr = extended_addr + record->address;
+ offset = addr - base;
+ memcpy(image->data + offset, record->data, record->length);
+ break;
+ case 1:
+ break;
+ case 2:
+ extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
+ break;
+ case 4:
+ extended_addr = ((record->data[0] << 8) | record->data[1]) << 16;
+ break;
+ }
}
return image;
}
@@ -328,3 +357,25 @@ ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b)
return 0;
return 1;
}
+
+struct hex_image *
+ccdbg_hex_load(char *filename)
+{
+ FILE *file;
+ struct hex_file *hex_file;
+ struct hex_image *hex_image;
+
+ file = fopen (filename, "r");
+ if (!file)
+ return 0;
+
+ hex_file = ccdbg_hex_file_read(file, filename);
+ fclose(file);
+ if (!hex_file)
+ return 0;
+ hex_image = ccdbg_hex_image_create(hex_file);
+ if (!hex_image)
+ return 0;
+ ccdbg_hex_file_free(hex_file);
+ return hex_image;
+}
diff --git a/ao-tools/lib/ccdbg.h b/ao-tools/lib/ccdbg.h
index ca596143..a27ff5d1 100644
--- a/ao-tools/lib/ccdbg.h
+++ b/ao-tools/lib/ccdbg.h
@@ -122,8 +122,8 @@ struct hex_file {
};
struct hex_image {
- uint16_t address;
- uint16_t length;
+ uint32_t address;
+ uint32_t length;
uint8_t data[0];
};
@@ -253,6 +253,9 @@ ccdbg_hex_image_create(struct hex_file *hex);
void
ccdbg_hex_image_free(struct hex_image *image);
+struct hex_image *
+ccdbg_hex_load(char *filename);
+
int
ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b);