diff options
Diffstat (limited to 'ao-tools')
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 Binary files differnew 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 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 Binary files differnew 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 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); |
