Initial Commit - Copy from Altus Metrum AltOS

This commit is contained in:
2024-06-25 19:03:04 +02:00
commit 13fc49c923
2048 changed files with 1206748 additions and 0 deletions

9
ao-tools/Makefile.am Normal file
View File

@@ -0,0 +1,9 @@
SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list \
ao-load ao-telem ao-send-telem ao-sky-flash \
ao-dumpflash ao-edit-telem ao-dump-up ao-elftohex \
ao-flash ao-usbload ao-test-igniter ao-test-baro \
ao-test-flash ao-cal-accel ao-test-gps ao-usbtrng \
ao-cal-freq ao-makebin ao-test-pressure
if LIBSTLINK
SUBDIRS += ao-stmload
endif

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-bitbang
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_BITBANG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_bitbang_DEPENDENCIES = $(AO_BITBANG_LIBS)
ao_bitbang_LDADD=$(AO_BITBANG_LIBS) $(LIBUSB_LIBS)
ao_bitbang_SOURCES = ao-bitbang.c
man_MANS=ao-bitbang.1

View File

@@ -0,0 +1,127 @@
.\"
.\" 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-BITBANG 1 "ao-bitbang" ""
.SH NAME
ao-bitbang \- Low-level cc1111 interface diagnostic tool
.SH SYNOPSIS
.B "ao-bitbang"
.SH DESCRIPTION
.I ao-bitbang
connects through a CP2103 usb-to-serial converter and uses the GPIO
pins to communicate with the debug port on a cc1111 device. It
provides raw access to the debug pins to help debug the lowest level
communication path.
.SH USAGE
.I ao-bitbang
reads a sequence of bit manipulations from stdin, sends them to the
device and reports status on stdout.
.P
Each line on stdin should contain a single letter command for each of
the three debug lines on the cc1111 -- clock, data and reset. Each bit
can be in one of three states -- on (C, D or R), off (.) or tri-state
(-) for input. Empty lines, or lines starting with '#' are
ignored. Anything beyond the last bit in a line is also ignored. The
bits must be listed in the correct order, and the 'on' values must
match the desired bit.
.SH EXAMPLE
.IP "Reset the target device"
.nf
# reset
C D R
C D R
C D R
C D R
.fi
.IP "Get Chip ID"
.nf
#
# Debug mode - drive RESET_N low for two clock cycles
#
C D R
. D .
C D .
. D .
C D .
. D R
#
# GET_CHIP_ID
C . R 0
. . R
C D R 1
. D R
C D R 1
. D R
C . R 0
. . R
C D R 1
. D R
C . R 0
. . R
C . R 0
. . R
C . R 0
. . R
#
# start reading again
#
C D R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C - R
. - R
C D R
.fi
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,33 @@
/*
* 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 "ccdbg.h"
int
main (int argc, char **argv)
{
struct ccdbg *dbg;
dbg = ccdbg_open("BITBANG");
if (!dbg)
exit (1);
ccdbg_add_debug(CC_DEBUG_BITBANG);
ccdbg_manual(dbg, stdin);
}

View File

@@ -0,0 +1,7 @@
bin_PROGRAMS=ao-bm70
AM_CFLAGS=-O0 -g
ao_bm70_SOURCES = ao-bm70.c
man_MANS=ao-bm70.1

View File

@@ -0,0 +1,9 @@
bin_PROGRAMS=ao-chaosread
AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_chaosread_LDADD=$(LIBUSB_LIBS)
ao_chaosread_SOURCES = ao-chaosread.c
man_MANS = ao-chaosread.1

1
ao-tools/ao-cal-accel/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ao-cal-accel

View File

@@ -0,0 +1,11 @@
bin_PROGRAMS=ao-cal-accel
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_cal_accel_DEPENDENCIES = $(top_builddir)/ao-tools/lib/libao-tools.a
ao_cal_accel_LDADD=$(top_builddir)/ao-tools/lib/libao-tools.a $(LIBUSB_LIBS)
ao_cal_accel_SOURCES=ao-cal-accel.c
man_MANS = ao-cal-accel.1

View File

@@ -0,0 +1,58 @@
.\"
.\" 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-LOAD 1 "ao-cal-accel" ""
.SH NAME
ao-cal-accel \- Calibrate AltOS flight computer accelerometers
.SH SYNOPSIS
.B "ao-cal-accel"
[\-T \fItty-device\fP]
[\--tty \fItty-device\fP]
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
.SH DESCRIPTION
.I ao-cal-accel
drives the built-in accelerometer calibration and validates the results.
.SH OPTIONS
.TP
\-T tty-device | --tty tty-device
This selects which tty device the debugger uses to communicate with
the target device. The special name 'BITBANG' directs ao-dbg to use
the cp2103 connection, otherwise this should be a usb serial port
connected to a suitable cc1111 debug node.
.TP
\-D AltOS-device | --device AltOS-device
Search for a connected device. This requires an argument of one of the
following forms:
.IP
TeleMega:2
.br
TeleMega
.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.
.SH USAGE
.I ao-cal-accel
opens the target device, executes the accelerometer calibration
command, verifies that it executed correctly, then shows the resulting
calibration values and saves them to configuration memory.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,233 @@
/*
* Copyright © 2014 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 <err.h>
#include <fcntl.h>
#include <gelf.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sysexits.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <stdbool.h>
#include <termios.h>
#include "ao-elf.h"
#include "ccdbg.h"
#include "cc-usb.h"
#include "cc.h"
#include "ao-verbose.h"
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
{ .name = "raw", .has_arg = 0, .val = 'r' },
{ .name = "verbose", .has_arg = 1, .val = 'v' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--verbose=<verbose>] [--device=<device>] [-tty=<tty>]\n", program);
exit(1);
}
static void
done(struct cc_usb *cc, int code)
{
cc_usb_close(cc);
exit (code);
}
static char **
tok(char *line) {
char **strs = malloc (sizeof (char *)), *str;
int n = 0;
while ((str = strtok(line, " \t"))) {
line = NULL;
strs = realloc(strs, (n + 2) * sizeof (char *));
strs[n] = strdup(str);
n++;
}
strs[n] = '\0';
return strs;
}
struct flash {
struct flash *next;
char line[512];
char **strs;
};
static struct flash *
flash(struct cc_usb *usb)
{
struct flash *head = NULL, **tail = &head;
cc_usb_printf(usb, "c s\nv\n");
for (;;) {
char line[512];
struct flash *b;
cc_usb_getline(usb, line, sizeof (line));
b = malloc (sizeof (struct flash));
strcpy(b->line, line);
b->strs = tok(line);
b->next = NULL;
*tail = b;
tail = &b->next;
if (strstr(line, "software-version"))
break;
}
return head;
}
static char **
find_flash(struct flash *b, char *word0) {
for (;b; b = b->next) {
if (strstr(b->line, word0))
return b->strs;
}
return NULL;
}
static void
await_key(void)
{
struct termios termios, termios_save;
char buf[512];
tcgetattr(0, &termios);
termios_save = termios;
cfmakeraw(&termios);
tcsetattr(0, TCSAFLUSH, &termios);
read(0, buf, sizeof (buf));
tcsetattr(0, TCSAFLUSH, &termios_save);
}
static int
do_cal(struct cc_usb *usb) {
struct flash *b;
char **accel;
char line[1024];
int l = 0;
int running = 0;
int worked = 1;
cc_usb_printf(usb, "E 1\nc a 0\n");
for (;;) {
int c = cc_usb_getchar_timeout(usb, 20*1000);
if (c == '\n')
l = 0;
else if (l < sizeof (line) - 1)
line[l++] = c;
line[l] = '\0';
putchar(c); fflush(stdout);
if (strstr(line, "press a key...")) {
await_key();
cc_usb_printf(usb, " ");
l = 0;
running = 1;
}
else if (strstr(line, "Invalid"))
worked = 0;
if (running && strstr(line, ">")) {
printf("\n");
break;
}
}
cc_usb_printf(usb, "E 0\n");
if (!worked) {
printf("Calibration failed\n");
return 0;
}
b = flash(usb);
accel = find_flash(b, "Accel cal");
if (!accel) {
printf("no response\n");
return 0;
}
printf ("Accel cal +1g: %s -1g: %s\n",
accel[3], accel[5]);
printf ("Saving..."); fflush(stdout);
cc_usb_printf (usb, "c w\n");
cc_usb_sync(usb);
b = flash(usb);
printf ("done\n");
return worked;
}
int
main (int argc, char **argv)
{
char *device = NULL;
int c;
struct cc_usb *cc = NULL;
char *tty = NULL;
int verbose = 0;
int ret = 0;
while ((c = getopt_long(argc, argv, "rT:D:c:s:v:", options, NULL)) != -1) {
switch (c) {
case 'T':
tty = optarg;
break;
case 'D':
device = optarg;
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
break;
}
}
ao_verbose = verbose;
if (verbose > 1)
ccdbg_add_debug(CC_DEBUG_BITBANG);
if (!tty)
tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
if (!tty)
tty = cc_usbdevs_find_by_arg(device, "TeleMega");
if (!tty)
tty = getenv("ALTOS_TTY");
if (!tty)
tty="/dev/ttyACM0";
cc = cc_usb_open(tty);
if (!cc)
exit(1);
if (!do_cal(cc))
ret = 1;
done(cc, ret);
}

1
ao-tools/ao-cal-freq/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ao-cal-freq

View File

@@ -0,0 +1,11 @@
bin_PROGRAMS=ao-cal-freq
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
ao_cal_freq_DEPENDENCIES = $(top_builddir)/ao-tools/lib/libao-tools.a
ao_cal_freq_LDADD=$(top_builddir)/ao-tools/lib/libao-tools.a $(LIBUSB_LIBS) -lm
ao_cal_freq_SOURCES=ao-cal-freq.c
man_MANS = ao-cal-freq.1

View File

@@ -0,0 +1,74 @@
.\"
.\" 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-LOAD 1 "ao-cal-freq" ""
.SH NAME
ao-cal-freq \- Calibrate AltOS flight computer frequency
.SH SYNOPSIS
.B "ao-cal-freq"
[\-T \fItty-device\fP]
[\--tty \fItty-device\fP]
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
[\-v] [\--verbose]
[\-n] [\--nosave]
[\-o \fIcal-value-output-file\fP]
[\--output \fIcal-value-output-file\fP]
.SH DESCRIPTION
.I ao-cal-freq
drives the frequency calibration process and saves the result.
.SH OPTIONS
.TP
\-T tty-device | --tty tty-device
This selects which tty device the debugger uses to communicate with
the target device. The special name 'BITBANG' directs ao-dbg to use
the cp2103 connection, otherwise this should be a usb serial port
connected to a suitable cc1111 debug node.
.TP
\-D AltOS-device | --device AltOS-device
Search for a connected device. This requires an argument of one of the
following forms:
.IP
TeleMega:2
.br
TeleMega
.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 cal-value-output-file | --output cal-value-output-file
Writes the resulting calibration value to the specified file.
.TP
\-n | --nosave
Inhibits saving the calibration value on the device. Necessary for
devices which don't have on-board configuration storage.
.TP
\-v | --verbose
Makes
.I ao-cal-freq
chatty about communication with the target device.
.SH USAGE
.I ao-cal-freq
opens the target device, interactively calibrates the frequency, then
shows the resulting calibration values and (optionally) saves them to
configuration memory and/or a file.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,296 @@
/*
* Copyright © 2014 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 <err.h>
#include <fcntl.h>
#include <gelf.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sysexits.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <stdbool.h>
#include <termios.h>
#include <math.h>
#include "ao-elf.h"
#include "ccdbg.h"
#include "cc-usb.h"
#include "cc.h"
#include "ao-verbose.h"
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
{ .name = "verbose", .has_arg = 0, .val = 'v' },
{ .name = "output", .has_arg = 1, .val = 'o' },
{ .name = "nosave", .has_arg = 0, .val = 'n' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--verbose] [--nosave] [--device=<device>] [-tty=<tty>] [--output=<cal-value-file>]\n", program);
exit(1);
}
static char **
tok(char *line) {
char **strs = malloc (sizeof (char *)), *str;
int n = 0;
while ((str = strtok(line, " \t"))) {
line = NULL;
strs = realloc(strs, (n + 2) * sizeof (char *));
strs[n] = strdup(str);
n++;
}
strs[n] = '\0';
return strs;
}
struct flash {
struct flash *next;
char line[512];
char **strs;
};
static struct flash *
flash(struct cc_usb *usb)
{
struct flash *head = NULL, **tail = &head;
cc_usb_printf(usb, "c s\nv\n");
for (;;) {
char line[512];
struct flash *b;
cc_usb_getline(usb, line, sizeof (line));
b = malloc (sizeof (struct flash));
strcpy(b->line, line);
b->strs = tok(line);
b->next = NULL;
*tail = b;
tail = &b->next;
if (strstr(line, "software-version"))
break;
}
return head;
}
static char **
find_flash(struct flash *b, char *word0) {
for (;b; b = b->next) {
if (strstr(b->line, word0))
return b->strs;
}
return NULL;
}
static int
do_save(struct cc_usb *usb)
{
int ret = 0;
printf("Saving calibration to device\n");
cc_usb_printf(usb, "c w\nv\n");
for (;;) {
char line[512];
cc_usb_getline(usb, line, sizeof (line));
if (strstr(line, "Nothing to save"))
ret = 1;
if (strstr(line, "Saved"))
ret = 1;
if (strstr(line, "software-version"))
break;
}
if (!ret) {
printf("Calibration save failed\n");
}
return ret;
}
static int
do_output(char *output, int cur_cal)
{
printf ("Saving calibration value to file \"%s\"\n", output);
FILE *out = fopen(output, "w");
int ret = 1;
if (!out) {
perror(output);
return 0;
}
if (fprintf(out, "%d\n", cur_cal) < 0) {
perror("fprintf");
ret = 0;
}
if (fflush(out) != 0) {
perror("fflush");
ret = 0;
}
if (fclose(out) != 0) {
perror("fclose");
ret = 0;
}
return ret;
}
static int
do_cal(char *tty, int save, char *output)
{
struct cc_usb *usb = NULL;
struct flash *b;
char line[1024];
double measured_freq;
char **cur_freq_words;
char **cur_cal_words;
char *line_end;
int cur_freq;
int cur_cal;
int new_cal;
int ret = 1;
int changed = 0;
for(;;) {
usb = cc_usb_open(tty);
if (!usb) {
fprintf(stderr, "failed to open device\n");
ret = 0;
break;
}
cc_usb_printf(usb, "E 0\n");
b = flash(usb);
cur_cal_words = find_flash(b, "Radio cal:");
cur_freq_words = find_flash(b, "Frequency:");
if (!cur_cal_words || !cur_freq_words) {
fprintf(stderr, "no response\n");
ret = 0;
break;
}
cur_cal = atoi(cur_cal_words[2]);
cur_freq = atoi(cur_freq_words[1]);
printf ("Current radio calibration %d\n", cur_cal);
printf ("Current radio frequency: %7.3f\n", cur_freq / 1000.0);
cc_usb_sync(usb);
cc_usb_printf(usb, "C 1\n");
cc_usb_sync(usb);
printf("Generating RF carrier. Please enter measured frequency [enter for done]: ");
fflush(stdout);
fgets(line, sizeof (line) - 1, stdin);
cc_usb_printf(usb, "C 0\n");
cc_usb_sync(usb);
measured_freq = strtod(line, &line_end);
if (line_end == line)
break;
new_cal = floor ((((double) cur_freq / 1000.0) / measured_freq) * cur_cal + 0.5);
if (new_cal == cur_cal) {
printf("Calibration value %d unchanged\n", cur_cal);
} else {
printf ("Setting cal value %d\n", new_cal);
cc_usb_printf (usb, "c f %d\n", new_cal);
changed = 1;
cc_usb_sync(usb);
}
cc_usb_close(usb);
}
if (usb) {
if (ret && save) {
if (changed) {
if (!do_save(usb))
ret = 0;
} else {
printf("Calibration unchanged, not saving\n");
}
}
if (ret && output) {
if (!do_output(output, cur_cal))
ret = 0;
}
cc_usb_close(usb);
}
return ret;
}
int
main (int argc, char **argv)
{
char *device = NULL;
int c;
char *tty = NULL;
int verbose = 0;
int save = 1;
int ret = 0;
char *output = NULL;
while ((c = getopt_long(argc, argv, "vnT:D:o:", options, NULL)) != -1) {
switch (c) {
case 'T':
tty = optarg;
break;
case 'D':
device = optarg;
break;
case 'v':
verbose++;
break;
case 'n':
save = 0;
break;
case 'o':
output = optarg;
break;
default:
usage(argv[0]);
break;
}
}
ao_verbose = verbose;
if (verbose)
ccdbg_add_debug(CC_DEBUG_BITBANG);
if (!tty)
tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
if (!tty)
tty = cc_usbdevs_find_by_arg(device, "TeleMega");
if (!tty)
tty = getenv("ALTOS_TTY");
if (!tty)
tty="/dev/ttyACM0";
if (!do_cal(tty, save, output))
ret = 1;
return ret;
}

1
ao-tools/ao-dbg/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
s51

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-dbg
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_DBG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
man_MANS = ao-dbg.1
ao_dbg_DEPENDENCIES = $(AO_DBG_LIBS)
ao_dbg_LDADD=$(AO_DBG_LIBS) $(LIBUSB_LIBS) $(LIBREADLINE)
ao_dbg_SOURCES = ao-dbg-parse.c ao-dbg-command.c ao-dbg-main.c

View File

@@ -0,0 +1,652 @@
/*
* Copyright © 2008 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 "ao-dbg.h"
static uint16_t start_address;
static enum command_result
parse_int(char *value, int *result)
{
char *endptr;
*result = strtol(value, &endptr, 0);
if (endptr == value)
return command_syntax;
return command_success;
}
static enum command_result
parse_uint16(char *value, uint16_t *uint16)
{
int v;
enum command_result result;
result = parse_int(value, &v);
if (result != command_success)
return command_error;
if (v < 0 || v > 0xffff)
return command_error;
*uint16 = v;
return command_success;
}
static enum command_result
parse_uint8(char *value, uint8_t *uint8)
{
int v;
enum command_result result;
result = parse_int(value, &v);
if (result != command_success)
return command_error;
if (v < 0 || v > 0xff)
return command_error;
*uint8 = v;
return command_success;
}
enum command_result
command_quit (int argc, char **argv)
{
ccdbg_reset(s51_dbg);
exit(0);
return command_error;
}
static void
dump_bytes(uint8_t *memory, int length, uint16_t start, char *format)
{
int group, i;
for (group = 0; group < length; group += 8) {
s51_printf(format, start + group);
for (i = group; i < length && i < group + 8; i++)
s51_printf("%02x ", memory[i]);
for (; i < group + 8; i++)
s51_printf(" ");
for (i = group; i < length && i < group + 8; i++) {
if (isascii(memory[i]) && isprint(memory[i]))
s51_printf("%c", memory[i]);
else
s51_printf(".");
}
s51_printf("\n");
}
}
enum command_result
command_di (int argc, char **argv)
{
uint16_t start, end;
uint8_t memory[65536];
uint8_t status;
int length;
if (argc != 3)
return command_error;
if (parse_uint16(argv[1], &start) != command_success)
return command_error;
if (parse_uint16(argv[2], &end) != command_success)
return command_error;
length = (int) end - (int) start + 1;
status = ccdbg_read_memory(s51_dbg, start + 0xff00, memory, length);
(void) status;
dump_bytes(memory, length, start, "0x%02x ");
return command_success;
}
enum command_result
command_ds (int argc, char **argv)
{
uint8_t start, end;
uint8_t memory[0x100];
uint8_t status;
int length;
if (argc != 3)
return command_error;
if (parse_uint8(argv[1], &start) != command_success)
return command_error;
if (parse_uint8(argv[2], &end) != command_success)
return command_error;
length = (int) end - (int) start + 1;
status = ccdbg_read_sfr(s51_dbg, start, memory, length);
(void) status;
dump_bytes(memory, length, start, "0x%02x ");
return command_success;
}
enum command_result
command_dx (int argc, char **argv)
{
uint16_t start, end;
uint8_t memory[65536];
uint8_t status;
int length;
if (argc != 3)
return command_error;
if (parse_uint16(argv[1], &start) != command_success)
return command_error;
if (parse_uint16(argv[2], &end) != command_success)
return command_error;
length = (int) end - (int) start + 1;
status = ccdbg_read_memory(s51_dbg, start, memory, length);
(void) status;
dump_bytes(memory, length, start, "0x%04x ");
return command_success;
}
enum command_result
command_set (int argc, char **argv)
{
uint16_t address;
uint8_t *data;
int len = argc - 3;
int i;
enum command_result ret = command_success;
if (len < 0)
return command_error;
if (parse_uint16(argv[2], &address) != command_success)
return command_error;
if (len == 0)
return command_success;
data = malloc(len);
if (!data)
return command_error;
for (i = 0; i < len; i++)
if (parse_uint8(argv[i+3], &data[i]) != command_success)
return command_error;
if (strcmp(argv[1], "xram") == 0) {
ccdbg_write_memory(s51_dbg, address, data, len);
} else if (strcmp(argv[1], "iram") == 0) {
ccdbg_write_memory(s51_dbg, address + 0xff00, data, len);
} else if (strcmp(argv[1], "sfr") == 0) {
ccdbg_write_sfr(s51_dbg, (uint8_t) address, data, len);
} else
ret = command_error;
free(data);
return ret;
}
enum command_result
command_dump (int argc, char **argv)
{
if (argv[1]) {
if (strcmp(argv[1], "rom") == 0 ||
strcmp(argv[1], "xram") == 0)
return command_dx(argc-1, argv+1);
if (strcmp(argv[1], "iram") == 0)
return command_di(argc-1, argv+1);
if (strcmp(argv[1], "sfr") == 0)
return command_ds(argc-1, argv+1);
}
return command_error;
}
enum command_result
command_file (int argc, char **argv)
{
struct ao_hex_file *hex;
struct ao_hex_image *image;
FILE *file;
if (argc != 2)
return command_error;
file = fopen (argv[1], "r");
if (!file)
return command_error;
hex = ao_hex_file_read(file, argv[1]);
fclose(file);
if (!hex)
return command_error;
if (hex->nrecord == 0) {
ao_hex_file_free(hex);
return command_error;
}
image = ao_hex_image_create(hex);
ao_hex_file_free(hex);
start_address = image->address;
ccdbg_set_rom(s51_dbg, image);
return command_success;
}
enum command_result
command_pc (int argc, char **argv)
{
uint16_t pc;
if (argv[1]) {
enum command_result result;
result = parse_uint16(argv[1], &pc);
if (result != command_success)
return result;
ccdbg_set_pc(s51_dbg, pc);
} else {
pc = ccdbg_get_pc(s51_dbg);
s51_printf(" 0x%04x 00\n", pc);
}
return command_success;
}
struct cc_break {
int enabled;
int temporary;
uint16_t address;
};
#define CC_NUM_BREAKPOINTS 4
static struct cc_break breakpoints[CC_NUM_BREAKPOINTS];
static void
disable_breakpoint(int b)
{
uint8_t status;
status = ccdbg_set_hw_brkpnt(s51_dbg, b, 0, breakpoints[b].address);
if (status != 0x00 && status != 0xff)
s51_printf("disable_breakpoint status 0x%02x\n", status);
}
static void
enable_breakpoint(int b)
{
uint8_t status;
status = ccdbg_set_hw_brkpnt(s51_dbg, b, 1, breakpoints[b].address);
if (status != 0xff)
s51_printf("enable_breakpoint status 0x%02x\n", status);
}
static void
enable_breakpoints(void)
{
int b;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
if (breakpoints[b].enabled)
enable_breakpoint(b);
}
static enum command_result
set_breakpoint(uint16_t address, int temporary)
{
int b;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
if (breakpoints[b].enabled == 0)
break;
if (breakpoints[b].address == address)
break;
}
if (b == CC_NUM_BREAKPOINTS) {
s51_printf("Error: too many breakpoints requested\n");
return command_success;
}
if (breakpoints[b].enabled == 0) {
breakpoints[b].address = address;
enable_breakpoint(b);
}
++breakpoints[b].enabled;
s51_printf("Breakpoint %d at 0x%04x\n", b, address);
breakpoints[b].temporary += temporary;
return command_success;
}
static enum command_result
clear_breakpoint(uint16_t address, int temporary)
{
int b;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
if (breakpoints[b].enabled != 0 &&
((breakpoints[b].temporary != 0) == (temporary != 0)) &&
breakpoints[b].address == address)
break;
}
if (b == CC_NUM_BREAKPOINTS) {
s51_printf("Error: no matching breakpoint found\n");
return command_success;
}
--breakpoints[b].enabled;
breakpoints[b].temporary -= temporary;
if (breakpoints[b].enabled == 0) {
disable_breakpoint(b);
breakpoints[b].address = -1;
}
return command_success;
}
static int
find_breakpoint(uint16_t address)
{
int b;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
if (breakpoints[b].enabled && breakpoints[b].address == address)
break;
if (b == CC_NUM_BREAKPOINTS)
return -1;
return b;
}
enum command_result
command_break (int argc, char **argv)
{
int b;
uint16_t address;
enum command_result result;
if (argc == 1) {
for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
if (breakpoints[b].enabled)
s51_printf("Breakpoint %d 0x%04x\n",
b, breakpoints[b].address);
return command_success;
}
if (argc != 2)
return command_error;
result = parse_uint16(argv[1], &address);
if (result != command_success)
return result;
return set_breakpoint(address, 0);
}
enum command_result
command_clear (int argc, char **argv)
{
uint16_t address;
enum command_result result;
if (argc != 2)
return command_error;
result = parse_uint16(argv[1], &address);
if (result != command_success)
return result;
return clear_breakpoint(address, 0);
}
static void
cc_stopped(uint8_t status)
{
uint16_t pc;
int b;
int code;
char *reason;
pc = ccdbg_get_pc(s51_dbg);
if (status & CC_STATUS_CPU_HALTED) {
if ((status & CC_STATUS_HALT_STATUS) != 0) {
pc = pc - 1;
code = 104;
reason = "Breakpoint";
b = find_breakpoint(pc);
if (b != -1 && breakpoints[b].temporary)
clear_breakpoint(pc, 1);
ccdbg_set_pc(s51_dbg, pc);
} else {
code = 105;
reason = "Interrupt";
}
s51_printf("Stop at 0x%04x: (%d) %s\n",
pc, code, reason);
}
}
static uint8_t
cc_step(uint16_t pc)
{
int b;
uint8_t status;
b = find_breakpoint(pc);
if (b != -1)
disable_breakpoint(b);
status = ccdbg_step_instr(s51_dbg);
if (b != -1)
enable_breakpoint(b);
return status;
}
enum command_result
command_run (int argc, char **argv)
{
uint16_t start, end;
enum command_result result;
uint16_t pc;
uint8_t status;
int b;
if (argv[1]) {
result = parse_uint16(argv[1], &start);
if (result != command_success)
return result;
if (argv[2]) {
result = parse_uint16(argv[2], &end);
if (result != command_success)
return result;
}
if (start_address && start == 0) {
start = start_address;
s51_printf("Starting at 0x%04x\n", start);
}
ccdbg_set_pc(s51_dbg, start);
}
else
start = ccdbg_get_pc(s51_dbg);
s51_printf("Resume at 0x%04x\n", start);
pc = start;
b = find_breakpoint(pc);
if (b != -1) {
cc_step(pc);
pc = ccdbg_get_pc(s51_dbg);
if (find_breakpoint(pc) != -1) {
status = ccdbg_read_status(s51_dbg);
cc_stopped(status);
return command_success;
}
}
ccdbg_resume(s51_dbg);
result = cc_wait();
return result;
}
enum command_result
command_next (int argc, char **argv)
{
return command_step(argc, argv);
}
enum command_result
command_step (int argc, char **argv)
{
uint16_t pc;
uint8_t opcode;
uint8_t a;
a = cc_step(ccdbg_get_pc(s51_dbg));
s51_printf(" ACC= 0x%02x\n", a);
pc = ccdbg_get_pc(s51_dbg);
ccdbg_read_memory(s51_dbg, pc, &opcode, 1);
s51_printf(" ? 0x%04x %02x\n", pc, opcode);
return command_success;
}
enum command_result
command_load (int argc, char **argv)
{
char *filename = argv[1];
FILE *file;
struct ao_hex_file *hex;
struct ao_hex_image *image;
if (!filename)
return command_error;
file = fopen(filename, "r");
if (!file) {
perror(filename);
return command_error;
}
hex = ao_hex_file_read(file, filename);
fclose(file);
if (!hex) {
return command_error;
}
image = ao_hex_image_create(hex);
ao_hex_file_free(hex);
if (!image) {
fprintf(stderr, "image create failed\n");
return command_error;
}
if (image->address >= 0xf000) {
printf("Loading %d bytes to RAM at 0x%04x\n",
image->length, image->address);
ccdbg_write_hex_image(s51_dbg, image, 0);
} else {
fprintf(stderr, "Can only load to RAM\n");
}
ao_hex_image_free(image);
return command_success;
}
enum command_result
command_halt (int argc, char **argv)
{
uint16_t pc;
ccdbg_halt(s51_dbg);
pc = ccdbg_get_pc(s51_dbg);
s51_printf("Halted at 0x%04x\n", pc);
return command_success;
}
enum command_result
command_stop (int argc, char **argv)
{
return command_success;
}
enum command_result
command_reset (int argc, char **argv)
{
ccdbg_debug_mode(s51_dbg);
ccdbg_halt(s51_dbg);
enable_breakpoints();
return command_success;
}
enum command_result
command_status(int argc, char **argv)
{
uint8_t status;
status = ccdbg_read_status(s51_dbg);
if ((status & CC_STATUS_CHIP_ERASE_DONE) == 0)
s51_printf("\tChip erase in progress\n");
if (status & CC_STATUS_PCON_IDLE)
s51_printf("\tCPU is idle (clock gated)\n");
if (status & CC_STATUS_CPU_HALTED)
s51_printf("\tCPU halted\n");
else
s51_printf("\tCPU running\n");
if ((status & CC_STATUS_POWER_MODE_0) == 0)
s51_printf("\tPower Mode 1-3 selected\n");
if (status & CC_STATUS_HALT_STATUS)
s51_printf("\tHalted by software or hw breakpoint\n");
else
s51_printf("\tHalted by debug command\n");
if (status & CC_STATUS_DEBUG_LOCKED)
s51_printf("\tDebug interface is locked\n");
if ((status & CC_STATUS_OSCILLATOR_STABLE) == 0)
s51_printf("\tOscillators are not stable\n");
if (status & CC_STATUS_STACK_OVERFLOW)
s51_printf("\tStack overflow\n");
return command_success;
}
static enum command_result
info_breakpoints(int argc, char **argv)
{
int b;
if (argc == 1) {
s51_printf("Num Type Disp Hit Cnt Address What\n");
for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
if (breakpoints[b].enabled) {
s51_printf("%-3d fetch %s 1 1 0x%04x uc::disass() unimplemented\n",
b,
breakpoints[b].temporary ? "del " : "keep",
breakpoints[b].address);
}
return command_success;
}
return command_syntax;
}
static enum command_result
info_help(int argc, char **argv);
static struct command_function infos[] = {
{ "breakpoints", "b", info_breakpoints, "[b]reakpoints",
"List current breakpoints\n" },
{ "help", "?", info_help, "help",
"Print this list\n" },
{ NULL, NULL, NULL, NULL, NULL },
};
static enum command_result
info_help(int argc, char **argv)
{
return command_function_help(infos, argc, argv);
}
enum command_result
command_info(int argc, char **argv)
{
struct command_function *func;
if (argc < 2)
return command_error;
func = command_string_to_function(infos, argv[1]);
if (!func)
return command_syntax;
return (*func->func)(argc-1, argv+1);
}
enum command_result
cc_wait(void)
{
for(;;) {
uint8_t status;
status = ccdbg_read_status(s51_dbg);
if (status & CC_STATUS_CPU_HALTED) {
cc_stopped(status);
return command_success;
}
if (s51_interrupted || s51_check_input()) {
ccdbg_halt(s51_dbg);
status = ccdbg_read_status(s51_dbg);
cc_stopped(status);
return command_interrupt;
}
}
}

View File

@@ -0,0 +1,256 @@
/*
* Copyright © 2008 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ao-dbg.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdarg.h>
#include <poll.h>
#include <getopt.h>
static int s51_port = 0;
static char *cpu = "8051";
static double freq = 11059200;
char *s51_prompt = "> ";
struct ccdbg *s51_dbg;
int s51_interrupted = 0;
int s51_monitor = 0;
char *s51_tty = NULL;
char *s51_device = NULL;
static FILE *s51_input;
static FILE *s51_output;
static void
usage(void)
{
fprintf(stderr, "You're doing it wrong.\n");
exit(1);
}
static void
s51_sigint(int signum)
{
s51_interrupted = 1;
}
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
{ 0, 0, 0, 0 },
};
int
main(int argc, char **argv)
{
int opt;
char *endptr;
while ((opt = getopt_long(argc, argv, "PVvHhmt:X:c:r:Z:s:S:p:T:", options, NULL)) != -1) {
switch (opt) {
case 't':
cpu = optarg;
break;
case 'X':
freq = strtod(optarg, &endptr);
if (endptr == optarg)
usage();
if (endptr[0] != '\0') {
if (!strcmp(endptr, "k"))
freq *= 1000;
else if (!strcmp(endptr, "M") )
freq *= 1000000;
else
usage ();
}
break;
case 'c':
break;
case 'r':
case 'Z':
s51_port = strtol(optarg, &endptr, 0);
if (endptr == optarg || strlen(endptr) != 0)
usage();
break;
case 's':
break;
case 'S':
break;
case 'p':
s51_prompt = optarg;
break;
case 'P':
s51_prompt = NULL;
break;
case 'V':
break;
case 'v':
break;
case 'H':
exit (0);
break;
case 'h':
usage ();
break;
case 'm':
s51_monitor = 1;
break;
case 'T':
s51_tty = optarg;
break;
case 'D':
s51_device = optarg;
break;
}
}
if (s51_port) {
int l, r, one = 1;
int s;
struct sockaddr_in in;
l = socket(AF_INET, SOCK_STREAM, 0);
if (l < 0) {
perror ("socket");
exit(1);
}
r = setsockopt(l, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (int));
if (r) {
perror("setsockopt");
exit(1);
}
in.sin_family = AF_INET;
in.sin_port = htons(s51_port);
in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
r = bind(l, (struct sockaddr *) &in, sizeof (in));
if (r) {
perror("bind");
exit(1);
}
r = listen(l, 5);
if (r) {
perror("listen");
exit(1);
}
for (;;) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof (struct sockaddr_in);
s = accept(l, (struct sockaddr *)
&client_addr, &client_len);
if (s < 0) {
perror("accept");
exit(1);
}
s51_input = fdopen(s, "r");
s51_output = fdopen(s, "w");
if (!s51_input || !s51_output) {
perror("fdopen");
exit(1);
}
signal(SIGINT, SIG_IGN);
command_read();
signal(SIGINT, SIG_DFL);
fclose(s51_input);
fclose(s51_output);
}
} else {
s51_input = stdin;
s51_output = stdout;
signal(SIGINT, s51_sigint);
command_read();
}
exit(0);
}
void
s51_printf(char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(s51_output, format, ap);
if (s51_monitor)
vfprintf(stdout, format, ap);
va_end(ap);
}
void
s51_putc(int c)
{
putc(c, s51_output);
}
#if HAVE_LIBREADLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif
int
s51_read_line(char *line, int len)
{
int ret;
#if HAVE_LIBREADLINE
if (s51_output == stdout && s51_input == stdin && s51_prompt) {
char *r;
r = readline(s51_prompt);
if (r == NULL)
return 0;
strncpy (line, r, len);
line[len-1] = '\0';
add_history(r);
return 1;
} else
#endif
{
if (s51_prompt)
s51_printf("%s", s51_prompt);
else
s51_putc('\0');
fflush(s51_output);
ret = fgets(line, len, s51_input) != NULL;
if (s51_monitor)
printf("> %s", line);
fflush(stdout);
}
return ret;
}
int
s51_check_input(void)
{
struct pollfd input;
int r;
input.fd = fileno(s51_input);
input.events = POLLIN;
r = poll(&input, 1, 0);
if (r > 0) {
char line[256];
(void) s51_read_line(line, sizeof (line));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright © 2008 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 "ao-dbg.h"
static struct command_function functions[] = {
{ "help", "?", command_help, "help", "Print this list\n" },
{ "quit", "q", command_quit, "[q]uit", "Quit\n" },
{ "di", "di", command_di, "di <start> <end>",
"Dump imem\n" },
{ "ds", "ds", command_ds, "ds <start> <end>",
"Dump sprs\n" },
{ "dx", "dx", command_dx, "dx <start> <end>",
"Dump xaddr\n" },
{ "set", "t", command_set, "se[t] mem <prefix> <address> <data> ...",
"Set mem {xram|rom|iram|sfr}\n"
"set bit <addr>\n" },
{ "dump", "d", command_dump, "[d]ump <prefix> <start> <end>",
"Dump {xram|rom|iram|sfr} <start> <end>\n" },
{ "file", "file", command_file, "file <filename>",
"Pretend to load executable from <filename>\n" },
{ "pc", "p", command_pc, "[p]c [addr]",
"Get or set pc value\n" },
{ "break", "b", command_break,"[b]reak <addr>",
"Set break point\n" },
{ "clear", "c", command_clear,"[c]lear <addr>",
"Clear break point\n" },
{ "run", "r", command_run, "[r]un [start] [stop]",
"Run with optional start and temp breakpoint addresses\n" },
{ "go", "g", command_run, "[g]o [start] [stop]",
"Run with optional start and temp breakpoint addresses\n" },
{ "next", "n", command_next, "[n]ext",
"Step over one instruction, past any call\n" },
{ "step", "s", command_step, "[s]tep",
"Single step\n" },
{ "load", "l", command_load, "[l]oad <file>",
"Load a hex file into memory or flash" },
{ "halt", "h", command_halt, "[h]alt",
"Halt the processor\n" },
{ "reset","res",command_reset, "[res]et",
"Reset the CPU\n" },
{ "status","status",command_status, "status",
"Display CC1111 debug status\n" },
{ "info", "i", command_info, "[i]info",
"Get information\n" },
{ "stop", "stop", command_stop, "stop",
"Ignored\n" },
{ NULL, NULL, NULL, NULL, NULL },
};
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif
struct command_function *
command_string_to_function(struct command_function *functions, char *name)
{
int i;
for (i = 0; functions[i].name; i++)
if (!strcmp(name, functions[i].name) ||
!strcmp(name, functions[i].alias))
return &functions[i];
return NULL;
}
enum command_result
command_function_help(struct command_function *functions, int argc, char **argv)
{
int i;
struct command_function *func;
if (argc == 1) {
for (i = 0; functions[i].name; i++)
s51_printf("%-10s%s\n", functions[i].name,
functions[i].usage);
} else {
for (i = 1; i < argc; i++) {
func = command_string_to_function(functions, argv[i]);
if (!func) {
s51_printf("%-10s unknown command\n", argv[i]);
return command_syntax;
}
s51_printf("%-10s %s\n%s", func->name,
func->usage, func->help);
}
}
return command_debug;
}
static int
command_split_into_words(char *line, char **argv)
{
char quotechar;
int argc;
argc = 0;
while (*line) {
while (isspace(*line))
line++;
if (!*line)
break;
if (*line == '"') {
quotechar = *line++;
*argv++ = line;
argc++;
while (*line && *line != quotechar)
line++;
if (*line)
*line++ = '\0';
} else {
*argv++ = line;
argc++;
while (*line && !isspace(*line))
line++;
if (*line)
*line++ = '\0';
}
}
*argv = 0;
return argc;
}
enum command_result
command_help(int argc, char **argv)
{
return command_function_help(functions, argc, argv);
}
void
command_syntax_error(int argc, char **argv)
{
s51_printf("Syntax error in:");
while (*argv)
s51_printf(" %s", *argv++);
s51_printf("\n");
}
void
command_read (void)
{
int argc;
char line[1024];
char *argv[20];
enum command_result result;
struct command_function *func;
if (!s51_tty) {
if (!s51_device)
s51_device = getenv("AO_DBG_DEVICE");
s51_tty = cc_usbdevs_find_by_arg(s51_device, "TeleDongle");
}
s51_dbg = ccdbg_open (s51_tty);
if (!s51_dbg)
exit(1);
ccdbg_debug_mode(s51_dbg);
ccdbg_halt(s51_dbg);
s51_printf("Welcome to the non-simulated processor\n");
for (;;) {
if (s51_read_line (line, sizeof line) == 0)
break;
s51_interrupted = 0;
argc = command_split_into_words(line, argv);
if (argc > 0) {
func = command_string_to_function(functions, argv[0]);
if (!func)
command_syntax_error(argc, argv);
else
{
result = (*func->func)(argc, argv);
if (s51_interrupted)
result = command_interrupt;
switch (result) {
case command_syntax:
command_syntax_error(argc, argv);
break;
case command_error:
s51_printf("Error\n");
break;
case command_success:
break;
case command_interrupt:
ccdbg_halt(s51_dbg);
s51_printf("Interrupted\n");
break;
default:
break;
}
}
}
}
ccdbg_close(s51_dbg);
s51_printf("...\n");
}

235
ao-tools/ao-dbg/ao-dbg.1 Normal file
View File

@@ -0,0 +1,235 @@
.\"
.\" 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-DBG 1 "ao-dbg" ""
.SH NAME
ao-dbg \- hex debugger for cc1111 processors
.SH SYNOPSIS
.B "ao-dbg"
[\-t \fIcpu-type\fP]
[\-X \fIfrequency\fP]
[\-c]
[\-r \fIlisten-port\fP]
[\-Z \fIlisten-port\fP]
[\-s]
[\-S]
[\-p \fIprompt\fP]
[\-V]
[\-v]
[\-H]
[\-h]
[\-m]
[\-T \fItty-device\fP]
[\--tty \fItty-device\fP]
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
.SH DESCRIPTION
.I ao-dbg
connects to a cc1111 processor through either a suitable cc1111 board
or a cp2103 usb to serial converter board, using the GPIO pins
available on that chip. It provides an interface compatible with the
8051 emulator from sdcc called s51, but communicating with the real
chip instead of an emulation. Using a modified version of the SDCC
debugger (sdcdb), you can control program execution on the target
machine at source-level.
.SH OPTIONS
The command line options are designed to be compatible with the 8051
emulator so that it can be used with sdcdb. As such, they're all one letter
long.
.IP "\-t \fIcpu-type\fP"
The 8051 emulator can operate as one of several different chips. Oddly, the
real hardware cannot, so this option is ignored.
.IP "\-X \fIfrequency\fP"
Similarly, the emulator can pretend to run at an arbitrary frequency
which the real hardware cannot do. Ignored.
.IP "\-c"
.IP "\-s"
.IP "\-S"
.IP "\-v"
.IP "\-V"
All ignored.
.IP "\-r \fIlisten-port\fP, -Z \fIlisten-port\fP"
The emulator and sdcdb communicate through a network socket. This option
switches the debugger from communicating through stdin/stdout to listening
on a specific network port instead. Once a connection is made, the debugger
continues on, using that network port for command input and output. The
debugger uses port 9756, and attempts to connect before launching ao-dbg, so if
ao-dbg is listening on this port before sdcdb is started, sdcdb will end up
talking to the existing ao-dbg instance. That's often useful for debugging ao-dbg
itself.
.IP "\-p \fIprompt\fP"
This sets the command prompt to the specified string.
.IP "\-P"
This sets the command prompt to a single NUL character. This is for use by
sdcdb.
.IP "\-h"
This should print a usage message, but does nothing useful currently.
.IP "\-m"
This option is not present in the original 8051 emulator, and causes ao-dbg to
dump all commands and replies that are received from and sent to sdcdb.
.TP
\-T tty-device | --tty tty-device
This selects which tty device the debugger uses to communicate with
the target device. The special name 'BITBANG' directs ao-dbg to use
the cp2103 connection, otherwise this should be a usb serial port
connected to a suitable cc1111 debug node.
.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.
.SH COMMANDS
Once started, ao-dbg connects to the cc1111 and then reads and
executes commands, either from stdin, or the network connection to
sdcdb.
.PP
Unlike the command line, ao-dbg contains built-in help for each of these
commands, via the 'help' command. Most of the commands are available in a
long form and a single character short form. Below, the short form follows
the long form after a comma.
.IP "help, ? {command}"
Without arguments, prints a list of available commands. With an argument
prints more detail about the specific command
.IP "quit, q"
Terminates the application, without changing the state of the target
processor.
.IP "di [start] [end]"
Dumps imem (256 bytes of "internal" memory) from start to end (inclusive).
.IP "ds [start] [end]"
Dumps sprs from start to end (inclusive). Note that while most sprs are
visible in the global address space, some are not, so use this command
instead of "dx" to read them.
.IP "dx [start] [end]"
Dump external (global) memory from start to end (inclusive).
.IP "set, t <prefix> [start] {data ...}"
Store to the memory space specified by prefix where prefix is one of "xram",
"rom", "iram", or "sfr". Store bytes starting at start.
.IP "dump, d <prefix> [start] [end]"
Dump from the memory space specified by prefix, where prefix is one of
"xram", "rom", "iram" or "sfr". Dumps from start to end (inclusive).
.IP "file [filename]"
Specifies an intel-format hex file (ihx) that contains the contents of the
rom area loaded into the cc1111. This is used to respond to requests to dump
rom memory contents without getting them from the cc1111 (which is slow).
.IP "pc, p {address}"
If the address argument is given, this sets the program counter to the
specified value. Otherwise, the current program counter value is displayed.
.IP "break, b [address]"
Sets a breakpoint at the specified address. This uses the built-in hardware
breakpoint support in the cc1111. As a result, it supports no more than four
breakpoints at once. You must therefore use a modified version of sdcdb which
changes how program execution is controlled to work within this limit.
.IP "clear, c [address]"
Clear a breakpoint from the specified address.
.IP "run, r, go, g {start} {stop}"
Resumes execution of the program. If the start argument is present, then it
begins at that address, otherwise it continues running at the current pc. If
a stop argument is present, then a temporary breakpoint is set at that
address. This temporary breakpoint will be removed when execution hits it.
.IP "next, n"
Step one instruction. In the original s51 program this would ignore
subroutines, but as sdcdb doesn't require this functionality, it's not
available here.
.IP "step, s"
Step one instruction.
.IP "load, l [filename]"
This is not implemented, but it is supposed to load a hex file into flash.
Use the ccload program instead.
.IP "halt, h"
Halt the processor. This is the only command which can be sent while the
program is running. It is ignored at other times.
.IP "reset, res"
Reset the processor. This pulls the reset pin low and re-enables debug mode.
Check the cc1111 documentation to see precisely what this does.
.IP "status"
This dumps the cc1111 debug status register.
.IP "info, i breakpoints, b"
List the current breakpoints.
.IP "info, i help, ?"
List the things you can get info on.
.IP "stop"
This doesn't do anything and is present only to retain compatibility with
the original 8051 emulator.
.SH "BOARD BRINGUP DEBUGGING"
.PP
While the original purpose for this program was to connect the source
debugger with the hardware, it can also be used as a low-level hex debugger
all on its own. In particular, all of the cc1111 peripherals can be
manipulated directly from the ao-dbg command line.
.IP "Starting ao-dbg"
First ensure that the target cc1111 device and intermediate cp2103 or
cc111 board are all hooked up correctly.
.IP
$ ao-dbg
.br
Welcome to the non-simulated processor
.br
> status
.br
CPU halted
.br
Halted by debug command
.br
>
.IP "Turning on LEDs"
Two of the cc1111 GPIO pins, P1_0 and P1_1 are capable of driving external
LEDs. To control these, set the Port 1 direction bits to make these output
pins and then change the Port 1 data to set them high or low:
.IP
> set sfr 0xfe 0x02 # set P1DIR to 0x2
.br
> set sfr 0x90 0x02 # set P1_1 to high
.br
> set sfr 0x90 0x00 # set P1_1 to low
.IP "Reading the A/D converters"
The six A/D converter inputs can each be connected to any of the P0 pins,
ground, the A/D voltage reference, an internal temperature sensor or VDD/3.
To read one of these values, select an A/D converter to use then start the
conversion process. The cc1111 manual has the table for selecting the input
on page 144.
.IP
To configure one of the P0 pins for use by the A/D unit, we program the
ADCCFG register, setting the bits in that which match the pins desired:
.IP
> set sfr 0xf2 0x3f # enable all 6 A/D inputs
.IP
To trigger a single conversion, we ask the A/D unit to perform an 'extra'
conversion, which means to do a single conversion not a whole sequence of
conversions. This is controlled by the ADCCON3 register at 0xB6:
.IP
> set sfr 0xb6 0xb2 # sample P0_2 using 12 bits of precision
.br
> ds 0xba 0xbb # dump the ADC data low and high regs
.br
> set sfr 0xb6 0xbe # sample internal temperature sensor
.br
> ds 0xba 0xbb # dump the ADC data low and high regs
.SH "SEE ALSO"
sdcdb(1), ccload(1)
.SH AUTHOR
Keith Packard

127
ao-tools/ao-dbg/ao-dbg.h Normal file
View File

@@ -0,0 +1,127 @@
/*
* Copyright © 2008 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 <ccdbg.h>
#include <cc.h>
#include <ctype.h>
extern char *s51_prompt;
extern struct ccdbg *s51_dbg;
extern int s51_interrupted;
extern int s51_monitor;
extern char *s51_tty;
extern char *s51_device;
enum command_result {
command_success, command_debug, command_syntax, command_interrupt, command_error,
};
struct command_function {
char *name;
char *alias;
enum command_result (*func)(int argc, char **argv);
char *usage;
char *help;
};
struct command_function *
command_string_to_function(struct command_function *functions, char *name);
enum command_result
command_function_help(struct command_function *functions, int argc, char **argv);
void
command_syntax_error(int argc, char **argv);
enum command_result
command_quit (int argc, char **argv);
enum command_result
command_help (int argc, char **argv);
enum command_result
command_stop (int argc, char **argv);
enum command_result
command_di (int argc, char **argv);
enum command_result
command_ds (int argc, char **argv);
enum command_result
command_dx (int argc, char **argv);
enum command_result
command_set (int argc, char **argv);
enum command_result
command_dump (int argc, char **argv);
enum command_result
command_file (int argc, char **argv);
enum command_result
command_pc (int argc, char **argv);
enum command_result
command_break (int argc, char **argv);
enum command_result
command_clear (int argc, char **argv);
enum command_result
command_run (int argc, char **argv);
enum command_result
command_next (int argc, char **argv);
enum command_result
command_step (int argc, char **argv);
enum command_result
command_load (int argc, char **argv);
enum command_result
command_halt (int argc, char **argv);
enum command_result
command_reset (int argc, char **argv);
enum command_result
command_status (int argc, char **argv);
enum command_result
command_info (int argc, char **argv);
enum command_result
cc_wait(void);
void
command_read (void);
void
s51_printf(char *format, ...);
void
s51_putc(int c);
int
s51_check_input(void);
int
s51_read_line(char *line, int len);

60
ao-tools/ao-dbg/commands Normal file
View File

@@ -0,0 +1,60 @@
Listens on port 9756 for a command stream.
Dump commands:
di <start> <end> - dump imem
ds <start> <end> - dump sprs
dx <start> <end> - dump xaddr
Returns a string of hex pairs, each preceded by a space,
with 8 pairs per line
Memory access commands:
set mem <prefix> <start> <end>
dump <prefix> <start> <end>
<prefix> is one of:
xram - external ram or external stack
rom - code space
iram - internal ram or stack
sfr - special function register
dump <addr>
set bit <addr>
bit addressable space
Set PC:
pc <addr>
Sets PC to specified address
pc
Returns current PC
Breakpoints
break <addr>
clear <addr>
Load a file
file "<filename>"
Execution control:
run <start> - run starting at <start>
run <start> <stop> - set temporary bp at <stop>
run - continue
next - step over calls(?)
step - step one instruction
reset - reset the simulator
res - synonym?
Error messages:
start with "Error:"

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-dump-up
AM_CFLAGS=$(WARN_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

View File

@@ -0,0 +1,49 @@
.\"
.\" 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]
[\--wait]
.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.
.TP
\--wait
Wait for a device to appear instead of exiting when no device is found.
.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

View File

@@ -0,0 +1,229 @@
/*
* 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 <stdbool.h>
#include <ctype.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 = "wait", .has_arg = 0, .val = 'w' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>] [--wait]\n", program);
exit(1);
}
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 const uint8_t test_data[] = {
0xfc, 0xfd, 0xfe, 0xff, 0xf8, 0xf9, 0xfa, 0xfb, 0x40, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x17, 0x08,
};
static bool test_failed;
static int test_pos;
static void
check_test(uint8_t b)
{
if (test_pos >= sizeof (test_data) || test_data[test_pos++] != b)
test_failed = true;
}
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);
check_test(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, -1) == 'M' && get_nonwhite(cc, 1000) == 'P')
return 1;
}
}
int
main (int argc, char **argv)
{
struct cc_usb *cc;
char *tty = NULL;
char *device = NULL;
int c;
int nsamples;
int i;
int crc;
int current_crc;
int wait = 0;
while ((c = getopt_long(argc, argv, "wT:D:", options, NULL)) != -1) {
switch (c) {
case 'w':
wait = 1;
break;
case 'T':
tty = optarg;
break;
case 'D':
device = optarg;
break;
default:
usage(argv[0]);
break;
}
}
if (!tty) {
for (;;) {
tty = cc_usbdevs_find_by_arg(device, "FT230X Basic UART");
if (tty) {
if (wait) {
printf("tty is %s\n", tty);
sleep(1);
}
break;
}
if (!wait)
break;
sleep(1);
}
}
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) {
if (!test_failed)
printf("\033[32mValid MicroTest Data\033[39m\n");
else
printf("CRC valid\n");
}
else
printf("CRC invalid\n");
cc_usb_close(cc);
exit (0);
}

1
ao-tools/ao-dumpflash/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ao-dumpflash

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-dumpflash
AM_CFLAGS=$(WARN_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

View File

@@ -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

View File

@@ -0,0 +1,168 @@
/*
* 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;
int serial_number = 0;
int freq = 434550;
char *call = "N0CALL";
int block;
int addr;
int received_addr;
int data[8];
int i;
int remote = 0;
int storage_size = 0;
char *out_name = NULL;
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);
}

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-dumplog
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS)
AO_DUMPLOG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_dumplog_DEPENDENCIES = $(AO_DUMPLOG_LIBS)
ao_dumplog_LDADD=$(AO_DUMPLOG_LIBS) $(LIBUSB_LIBS) $(GNOME_LIBS)
ao_dumplog_SOURCES = ao-dumplog.c
man_MANS = ao-dumplog.1

View File

@@ -0,0 +1,74 @@
.\"
.\" 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-dumplog" ""
.SH NAME
ao-dumplog \- Store flight log from TeleMetrum device
.SH SYNOPSIS
.B "ao-dumplog"
[\-T \fItty-device\fP]
[\--tty \fItty-device\fP]
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
[\--R\fP]
[\--remote\fP]
.SH OPTIONS
.TP
\-T tty-device | --tty tty-device
This selects which tty device ao-dumplog 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
\-R | --remote
This uses the command radio link to download the log from TeleMetrum
through a TeleDongle.
.SH DESCRIPTION
.I ao-dumplog
downloads the flight log from a connected TeleMetrum device and stores
it to the configured flight log directory using a name of the form
.IP
\fIyyyy\fP-\fImm\fP-\fIdd\fP-serialP-\fIsss\fP-flight-\fIfff\fP.eeprom
.PP
\fIyyyy\fP is the current year
.br
\fImm\fP is the current month
.br
\fIdd\fP is the current day
.br
\fIsss\fP is the device serial number
.br
\fIfff\fP is a flight sequence number (to make filenames unique)
.SH USAGE
.I ao-dumplog
connects to the specified target device and dumps the stored flight
log.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,230 @@
/*
* 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 = "channel", .has_arg = 1, .val = 'C' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>] [--remote] [--channel <radio-channel>]\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 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];
FILE *out;
char *filename;
int serial_number = 0;
int channel = 0;
int flight = 0;
char cmd;
int tick, a, b;
int block;
int addr;
int received_addr;
int data[8];
int done;
int column;
int remote = 0;
int any_valid;
int invalid;
char serial_line[8192];
unsigned storage_size;
int blocks;
while ((c = getopt_long(argc, argv, "T:D:C:R", options, NULL)) != -1) {
switch (c) {
case 'T':
tty = optarg;
break;
case 'D':
device = optarg;
break;
case 'R':
remote = 1;
break;
case 'C':
channel = atoi(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, channel);
/* send a 'version' command followed by a 'log' command */
cc_usb_printf(cc, "v\n");
out = NULL;
for (;;) {
cc_usb_getline(cc, line, sizeof (line));
if (sscanf(line, "serial-number %u", &serial_number) == 1)
strcpy(serial_line, line);
if (!strncmp(line, "software-version", 16))
break;
}
if (!serial_number) {
fprintf(stderr, "no serial number found\n");
cc_usb_close(cc);
exit(1);
}
cc_usb_printf(cc, "f\n");
storage_size = 0;
for (;;) {
cc_usb_getline(cc, line, sizeof(line));
if (sscanf(line, "Storage size: %u", &storage_size) == 1)
break;
}
printf ("Serial number: %d Storage size: %u\n", serial_number, storage_size);
if (storage_size)
blocks = storage_size / 256;
else
blocks = 511;
done = 0;
column = 0;
for (block = 0; !done && block < blocks; block++) {
cc_usb_printf(cc, "e %x\n", block);
if (column == 64) {
putchar('\n');
column = 0;
}
putchar('.'); fflush(stdout); column++;
any_valid = 0;
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);
if (log_checksum(data) != 0)
fprintf (stderr, "invalid checksum at 0x%x\n",
block * 256 + received_addr);
else
any_valid = 1;
cmd = data[0];
tick = data[2] + (data[3] << 8);
a = data[4] + (data[5] << 8);
b = data[6] + (data[7] << 8);
if (cmd == 'F') {
flight = b;
filename = cc_make_filename(serial_number, flight, "eeprom");
printf ("Flight: %d\n", flight);
printf ("File name: %s\n", filename);
out = fopen (filename, "w");
if (!out) {
perror(filename);
exit(1);
}
fprintf(out, "%s\n", serial_line);
}
if (cmd == 'S' && a <= 8) {
if (column) putchar('\n');
printf("%s\n", state_names[a]);
column = 0;
}
if (out) {
fprintf(out, "%c %4x %4x %4x\n",
cmd, tick, a, b);
if (cmd == 'S' && a == 8) {
fclose(out);
out = NULL;
done = 1;
}
}
addr += 8;
}
}
if (!any_valid) {
fclose(out);
out = NULL;
done = 1;
}
}
if (column)
putchar('\n');
if (out)
fclose (out);
cc_usb_close(cc);
exit (0);
}

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-edit-telem
AM_CFLAGS=$(WARN_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

View File

@@ -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

View File

@@ -0,0 +1,187 @@
/*
* 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.
*/
#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);
static 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 = 0;
FILE *file;
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;
}
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;
}

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-eeprom
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_EEPROM_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_eeprom_DEPENDENCIES = $(AO_EEPROM_LIBS)
ao_eeprom_LDADD=$(AO_EEPROM_LIBS) -ljson-c -lm
ao_eeprom_SOURCES = ao-eeprom.c
man_MANS = ao-eeprom.1

View File

@@ -0,0 +1,49 @@
.\"
.\" 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-EEPROM 1 "ao-eeprom" ""
.SH NAME
ao-eeprom \- Analyze an eeprom log
.SH SYNOPSIS
.B "ao-eeprom"
[\--raw]
[\--csum]
[\--verbose]
[\--len <record-len>]
{flight.eeprom} ...
.SH OPTIONS
.TP
\-r | --raw
This option makes ao-eeprom dump the raw bytes of each
log record in hex format.
.TP
\-c | --csum
This option makes ao-eeprom dump records that have checksum errors. By default,
ao-eeprom skips such records.
\-v | --verbose
This option makes ao-eeprom report when records are skipped due to
checksum errors.
\-l <record-len> | --len <record-len
Specify the eeprom record length rather than letting ao-eeprom
automatically determine it based on the file contents.
.SH DESCRIPTION
.I ao-eeprom
reads the specified eeprom log and display the contents of each
record.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,753 @@
/*
* 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 <stdbool.h>
#include <unistd.h>
#include <getopt.h>
#include <ao-eeprom-read.h>
#include <ao-atmosphere.h>
static const struct option options[] = {
{ .name = "raw", .has_arg = 0, .val = 'r' },
{ .name = "csum", .has_arg = 0, .val = 'c' },
{ .name = "verbose", .has_arg = 0, .val = 'v' },
{ .name = "len", .has_arg = 1, .val = 'l' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--raw] [--csum] [--verbose] [--len <record-len>] {flight.eeprom} ...\n", program);
exit(1);
}
static bool
ao_csum_valid(uint8_t *d, int len)
{
uint8_t sum = 0x5a;
int i;
for (i = 0; i < len; i++)
sum += d[i];
return sum == 0;
}
static void
ao_ms5607(uint32_t pres, uint32_t temp, struct ao_eeprom *eeprom, bool is_ms5611)
{
struct ao_ms5607_sample ms5607_sample = { .pres = pres, .temp = temp };
struct ao_ms5607_value ms5607_value;
ao_ms5607_convert(&ms5607_sample, &ms5607_value,
&eeprom->ms5607_prom, is_ms5611);
printf(" pres %9u %7.3f kPa %7.1f m temp %9u %6.2f °C",
pres,
ms5607_value.pres / 1000.0,
ao_pressure_to_altitude(ms5607_value.pres),
temp,
ms5607_value.temp / 100.0);
}
#define GRAVITY 9.80665
static void
ao_accel(int16_t accel, struct ao_eeprom *eeprom)
{
double accel_2g = eeprom->config.accel_minus_g - eeprom->config.accel_plus_g;
double accel_scale = GRAVITY * 2.0 / accel_2g;
printf(" accel %6d %7.2f m/s²",
accel, (eeprom->config.accel_plus_g - accel) * accel_scale);
}
static const char *state_names[] = {
"startup",
"idle",
"pad",
"boost",
"fast",
"coast",
"drogue",
"main",
"landed",
"invalid"
};
#define NUM_STATE (sizeof state_names/sizeof state_names[0])
static const char *
ao_state_name(uint16_t state)
{
if (state < NUM_STATE)
return state_names[state];
return "UNKNOWN";
}
static void
ao_state(uint16_t state, uint16_t reason)
{
printf(" state %5u %s reason %5u",
state, ao_state_name(state), reason);
}
static double
ao_adc_to_volts(int16_t value, int16_t max_adc, double ref, double r1, double r2)
{
return ref * ((double) value / max_adc) * (r1 + r2) / r2;
}
static void
ao_volts(const char *name, int16_t value, int16_t max_adc, double ref, double r1, double r2)
{
printf(" %s %5d",
name, value);
if (r1 && r2 && ref)
printf(" %6.3f V", ao_adc_to_volts(value, max_adc, ref, r1, r2));
}
static double lb_to_n(double lb)
{
return lb / 0.22480894;
}
static double psi_to_pa(double psi)
{
return psi * 6894.76;
}
static double
ao_volts_to_newtons(double volts)
{
/* this is a total guess */
return lb_to_n(volts * 57.88645 * GRAVITY);
}
static void
ao_thrust(int16_t value, int16_t max_adc, double ref, double r1, double r2)
{
printf(" thrust %5d", value);
if (r1 && r2 && ref) {
double volts = ao_adc_to_volts(value, max_adc, ref, r1, r2);
printf(" %6.3f V %8.1f N", volts, ao_volts_to_newtons(volts));
}
}
static void
ao_pressure(int16_t value, int16_t max_adc, double ref, double r1, double r2, double sensor_range)
{
printf(" pressure %5d", value);
if (r1 && r2 && ref) {
double volts = ao_adc_to_volts(value, max_adc, ref, r1, r2);
if (volts < 0.5) volts = 0.5;
if (volts > 4.5) volts = 4.5;
double psi = (volts - 0.5) / 4.0 * sensor_range;
double pa = psi_to_pa(psi);
printf(" %9.3f kPa", pa / 1000.0);
}
}
#if 0
static uint16_t
uint16(uint8_t *bytes, int off)
{
return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
}
static int16_t
int16(uint8_t *bytes, int off)
{
return (int16_t) uint16(bytes, off);
}
static uint32_t
uint32(uint8_t *bytes, int off)
{
return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
(((uint32_t) bytes[off+2]) << 16) |
(((uint32_t) bytes[off+3]) << 24);
}
static int32_t
int32(uint8_t *bytes, int off)
{
return (int32_t) uint32(bytes, off);
}
#endif
static uint32_t
uint24(uint8_t *bytes, int off)
{
return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
(((uint32_t) bytes[off+2]) << 16);
}
static int32_t
int24(uint8_t *bytes, int off)
{
return (int32_t) uint24(bytes, off);
}
int
main (int argc, char **argv)
{
struct ao_eeprom *eeprom;
FILE *file;
int c;
bool raw = false;
bool csum = false;
bool verbose = false;
int arg_len = 0;
char *end;
int ret = 0;
int i;
while ((c = getopt_long(argc, argv, "rcvl:", options, NULL)) != -1) {
switch (c) {
case 'r':
raw = true;
break;
case 'c':
csum = true;
break;
case 'v':
verbose = true;
break;
case 'l':
arg_len = strtol(optarg, &end, 0);
if (!*optarg || *end)
usage(argv[0]);
break;
default:
usage(argv[0]);
break;
}
}
for (i = optind; i < argc; i++) {
file = fopen(argv[i], "r");
if (!file) {
perror(argv[i]);
ret++;
continue;
}
eeprom = ao_eeprom_read(file);
fclose(file);
if (!eeprom) {
perror(argv[i]);
ret++;
continue;
}
int len = 0;
bool is_ms5611 = false;
int64_t current_tick = 0;
int64_t first_tick = 0x7fffffffffffffffLL;
double sense_r1 = 0.0, sense_r2 = 0.0;
double batt_r1 = 0.0, batt_r2 = 0.0;
double adc_ref = 0.0;
double pressure_sensor = 0.0;
int16_t max_adc = 0;
switch (eeprom->log_format) {
case AO_LOG_FORMAT_TELEMEGA_OLD:
len = 32;
break;
case AO_LOG_FORMAT_EASYMINI1:
len = 16;
max_adc = 32767;
if (eeprom->serial_number < 1000)
adc_ref = 3.0;
else
adc_ref = 3.3;
batt_r1 = sense_r1 = 100e3;
batt_r2 = sense_r2 = 27e3;
break;
case AO_LOG_FORMAT_TELEMETRUM:
len = 16;
max_adc = 4095;
adc_ref = 3.3;
batt_r1 = 5600;
batt_r2 = 10000;
sense_r1 = 100e3;
sense_r2 = 27e3;
break;
case AO_LOG_FORMAT_TELEMINI2:
len = 16;
break;
case AO_LOG_FORMAT_TELEGPS:
len = 32;
break;
case AO_LOG_FORMAT_TELEMEGA:
len = 32;
max_adc = 4095;
adc_ref = 3.3;
batt_r1 = 5600;
batt_r2 = 10000;
sense_r1 = 100e3;
sense_r2 = 27e3;
break;
case AO_LOG_FORMAT_DETHERM:
len = 16;
break;
case AO_LOG_FORMAT_TELEMINI3:
len = 16;
max_adc = 4095;
adc_ref = 3.3;
batt_r1 = 5600;
batt_r2 = 10000;
sense_r1 = 100e3;
sense_r2 = 27e3;
break;
case AO_LOG_FORMAT_TELEFIRETWO:
len = 32;
pressure_sensor = 2500.0;
max_adc = 4095;
adc_ref = 3.3;
sense_r1 = batt_r1 = 5600;
sense_r2 = batt_r2 = 10000;
break;
case AO_LOG_FORMAT_EASYMINI2:
len = 16;
max_adc = 4095;
adc_ref = 3.3;
batt_r1 = sense_r1 = 100e3;
batt_r2 = sense_r2 = 27e3;
break;
case AO_LOG_FORMAT_TELEMEGA_3:
len = 32;
max_adc = 4095;
adc_ref = 3.3;
batt_r1 = 5600;
batt_r2 = 10000;
sense_r1 = 100e3;
sense_r2 = 27e3;
break;
case AO_LOG_FORMAT_EASYMEGA_2:
len = 32;
max_adc = 4095;
adc_ref = 3.3;
batt_r1 = 5600;
batt_r2 = 10000;
sense_r1 = 100e3;
sense_r2 = 27e3;
break;
case AO_LOG_FORMAT_TELESTATIC:
len = 32;
break;
case AO_LOG_FORMAT_MICROPEAK2:
len = 2;
break;
case AO_LOG_FORMAT_TELEMEGA_4:
case AO_LOG_FORMAT_TELEMEGA_5:
case AO_LOG_FORMAT_TELEMEGA_6:
len = 32;
max_adc= 4095;
adc_ref = 3.3;
batt_r1 = 5600;
batt_r2 = 10000;
sense_r1 = 100e3;
sense_r2 = 27e3;
break;
case AO_LOG_FORMAT_EASYMOTOR:
len = 16;
max_adc = 32767;
adc_ref = 3.3;
pressure_sensor = 1600.0;
batt_r1 = 5600;
batt_r2 = 10000;
sense_r1 = 5600;
sense_r2 = 10000;
break;
}
if (arg_len)
len = arg_len;
if (len == 0) {
fprintf(stderr, "Unknown eeprom format %d and no specified length\n",
eeprom->log_format);
exit(1);
}
if (verbose)
printf("config major %d minor %d log format %d total %u len %d\n",
eeprom->config.major,
eeprom->config.minor,
eeprom->log_format,
eeprom->len,
len);
uint32_t pos;
for (pos = 0; pos < eeprom->len; pos += len) {
int i;
if (raw) {
printf("%9u", pos);
for (i = 0; i < len; i++)
printf(" %02x", eeprom->data[pos + i]);
} else {
struct ao_log_mega *log_mega;
struct ao_log_mini *log_mini;
struct ao_log_metrum *log_metrum;
struct ao_log_gps *log_gps;
struct ao_log_firetwo *log_firetwo;
struct ao_log_motor *log_motor;
if (!csum && !ao_csum_valid(&eeprom->data[pos], len)) {
if (verbose)
printf("\tchecksum error at %d\n", pos);
continue;
}
struct ao_log_header *log_header = (struct ao_log_header *) &eeprom->data[pos];
if (first_tick == 0x7fffffffffffffffLL) {
current_tick = first_tick = log_header->tick;
} else {
int16_t diff = (int16_t) (log_header->tick - (uint16_t) current_tick);
current_tick += diff;
}
printf("type %c tick %5u %6.2f S", log_header->type, log_header->tick, (current_tick - first_tick) / 100.0);
switch (eeprom->log_format) {
case AO_LOG_FORMAT_TELEMEGA_OLD:
case AO_LOG_FORMAT_TELEMEGA:
case AO_LOG_FORMAT_TELEMEGA_3:
case AO_LOG_FORMAT_EASYMEGA_2:
case AO_LOG_FORMAT_TELEMEGA_4:
case AO_LOG_FORMAT_TELEMEGA_5:
case AO_LOG_FORMAT_TELEMEGA_6:
log_mega = (struct ao_log_mega *) &eeprom->data[pos];
switch (log_mega->type) {
case AO_LOG_FLIGHT:
printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u kPa %7.1f %7.1f m",
eeprom->serial_number,
log_mega->u.flight.flight,
log_mega->u.flight.ground_accel,
log_mega->u.flight.ground_pres,
log_mega->u.flight.ground_pres / 1000.0,
ao_pressure_to_altitude(log_mega->u.flight.ground_pres));
printf(" along %6d aross %6d through %6d",
log_mega->u.flight.ground_accel_along,
log_mega->u.flight.ground_accel_across,
log_mega->u.flight.ground_accel_through);
printf(" roll %6d pitch %6d yaw %6d",
log_mega->u.flight.ground_roll,
log_mega->u.flight.ground_pitch,
log_mega->u.flight.ground_yaw);
break;
case AO_LOG_STATE:
ao_state(log_mega->u.state.state,
log_mega->u.state.reason);
break;
case AO_LOG_SENSOR:
ao_ms5607(log_mega->u.sensor.pres,
log_mega->u.sensor.temp,
eeprom, is_ms5611);
printf(" accel_x %6d accel_y %6d accel_z %6d",
log_mega->u.sensor.accel_x,
log_mega->u.sensor.accel_y,
log_mega->u.sensor.accel_z);
printf (" gyro_x %6d gyro_y %6d gyro_z %6d",
log_mega->u.sensor.gyro_x,
log_mega->u.sensor.gyro_y,
log_mega->u.sensor.gyro_z);
printf (" mag_x %6d mag_y %6d mag_z %6d",
log_mega->u.sensor.mag_x,
log_mega->u.sensor.mag_y,
log_mega->u.sensor.mag_z);
ao_accel(log_mega->u.sensor.accel, eeprom);
break;
case AO_LOG_TEMP_VOLT:
ao_volts("v_batt",
log_mega->u.volt.v_batt,
max_adc,
adc_ref,
batt_r1, batt_r2);
ao_volts("v_pbatt",
log_mega->u.volt.v_pbatt,
max_adc,
adc_ref,
sense_r1, sense_r2);
printf(" n_sense %1d",
log_mega->u.volt.n_sense);
for (i = 0; i < log_mega->u.volt.n_sense; i++) {
char name[10];
sprintf(name, "sense%d", i);
ao_volts(name,
log_mega->u.volt.sense[i],
max_adc,
adc_ref,
sense_r1, sense_r2);
}
printf(" pyro %04x", log_mega->u.volt.pyro);
break;
case AO_LOG_GPS_TIME:
printf(" lat %10.7f ° lon %10.7f ° alt %8d m",
log_mega->u.gps.latitude / 10000000.0,
log_mega->u.gps.longitude/ 10000000.0,
(int32_t) (log_mega->u.gps.altitude_low |
(log_mega->u.gps.altitude_high << 16)));
printf(" time %02d:%02d:%02d %04d-%02d-%02d flags %02x",
log_mega->u.gps.hour,
log_mega->u.gps.minute,
log_mega->u.gps.second,
log_mega->u.gps.year + 2000,
log_mega->u.gps.month,
log_mega->u.gps.day,
log_mega->u.gps.flags);
printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d",
log_mega->u.gps.course,
log_mega->u.gps.ground_speed,
log_mega->u.gps.climb_rate,
log_mega->u.gps.pdop,
log_mega->u.gps.hdop,
log_mega->u.gps.vdop,
log_mega->u.gps.mode);
break;
case AO_LOG_GPS_SAT:
printf(" channels %2d",
log_mega->u.gps_sat.channels);
for (i = 0; i < 12; i++) {
printf(" svid %3d c_n %2d",
log_mega->u.gps_sat.sats[i].svid,
log_mega->u.gps_sat.sats[i].c_n);
}
break;
}
break;
case AO_LOG_FORMAT_EASYMINI1:
case AO_LOG_FORMAT_EASYMINI2:
case AO_LOG_FORMAT_TELEMINI2:
case AO_LOG_FORMAT_TELEMINI3:
log_mini = (struct ao_log_mini *) &eeprom->data[pos];
switch (log_mini->type) {
case AO_LOG_FLIGHT:
printf(" serial %5u flight %5u ground_pres %9u kPa %7.1f %7.1f m",
eeprom->serial_number,
log_mini->u.flight.flight,
log_mini->u.flight.ground_pres,
log_mini->u.flight.ground_pres / 1000.0,
ao_pressure_to_altitude(log_mini->u.flight.ground_pres));
break;
case AO_LOG_STATE:
ao_state(log_mini->u.state.state,
log_mini->u.state.reason);
break;
case AO_LOG_SENSOR:
ao_ms5607(int24(log_mini->u.sensor.pres, 0),
int24(log_mini->u.sensor.temp, 0),
eeprom, is_ms5611);
ao_volts("sense_a",
log_mini->u.sensor.sense_a, max_adc,
adc_ref, sense_r1, sense_r2);
ao_volts("sense_m",
log_mini->u.sensor.sense_m, max_adc,
adc_ref, sense_r1, sense_r2);
ao_volts("v_batt",
log_mini->u.sensor.v_batt, max_adc,
adc_ref, batt_r1, batt_r2);
break;
} /* */
break;
case AO_LOG_FORMAT_TELEMETRUM:
log_metrum = (struct ao_log_metrum *) &eeprom->data[pos];
switch (log_metrum->type) {
case AO_LOG_FLIGHT:
printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u kPa %7.1f %7.1f m ground_temp %9u",
eeprom->serial_number,
log_metrum->u.flight.flight,
log_metrum->u.flight.ground_accel,
log_metrum->u.flight.ground_pres,
log_metrum->u.flight.ground_pres / 1000.0,
ao_pressure_to_altitude(log_metrum->u.flight.ground_pres),
log_metrum->u.flight.ground_temp);
break;
case AO_LOG_SENSOR:
ao_ms5607(log_metrum->u.sensor.pres,
log_metrum->u.sensor.temp,
eeprom, is_ms5611);
ao_accel(log_metrum->u.sensor.accel, eeprom);
break;
case AO_LOG_TEMP_VOLT:
ao_volts("v_batt",
log_metrum->u.volt.v_batt, max_adc,
adc_ref, batt_r1, batt_r2);
ao_volts("sense_a",
log_metrum->u.volt.sense_a, max_adc,
adc_ref, sense_r1, sense_r2);
ao_volts("sense_m",
log_metrum->u.volt.sense_m, max_adc,
adc_ref, sense_r1, sense_r2);
break;
case AO_LOG_DEPLOY:
break;
case AO_LOG_STATE:
ao_state(log_metrum->u.state.state,
log_metrum->u.state.reason);
break;
case AO_LOG_GPS_TIME:
printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x pdop %3u",
log_metrum->u.gps_time.hour,
log_metrum->u.gps_time.minute,
log_metrum->u.gps_time.second,
log_metrum->u.gps_time.year,
log_metrum->u.gps_time.month,
log_metrum->u.gps_time.day,
log_metrum->u.gps_time.flags,
log_metrum->u.gps_time.pdop);
break;
case AO_LOG_GPS_SAT:
printf(" channels %2d more %1d",
log_metrum->u.gps_sat.channels,
log_metrum->u.gps_sat.more);
for (i = 0; i < 4; i++) {
printf(" svid %3d c_n %2d",
log_metrum->u.gps_sat.sats[i].svid,
log_metrum->u.gps_sat.sats[i].c_n);
}
break;
case AO_LOG_GPS_POS:
printf(" lat %10.7f° lon %10.7f° alt %8d m",
log_metrum->u.gps.latitude / 10000000.0,
log_metrum->u.gps.longitude/ 10000000.0,
(int32_t) (log_metrum->u.gps.altitude_low |
(log_metrum->u.gps.altitude_high << 16)));
break;
default:
printf(" unknown");
}
break;
case AO_LOG_FORMAT_TELEFIRETWO:
log_firetwo = (struct ao_log_firetwo *) &eeprom->data[pos];
switch (log_firetwo->type) {
case AO_LOG_FLIGHT:
printf(" serial %5u flight %5u",
eeprom->serial_number,
log_firetwo->u.flight.flight);
break;
case AO_LOG_STATE:
ao_state(log_firetwo->u.state.state,
log_firetwo->u.state.reason);
break;
case AO_LOG_SENSOR:
ao_pressure(log_firetwo->u.sensor.pressure,
max_adc, adc_ref,
sense_r1, sense_r2,
pressure_sensor);
ao_thrust(log_firetwo->u.sensor.thrust,
max_adc, adc_ref,
sense_r1, sense_r2);
for (i = 0; i < 4; i++) {
char name[20];
sprintf(name, "thermistor%d", i);
ao_volts(name,
log_firetwo->u.sensor.thermistor[i],
max_adc, adc_ref,
sense_r1, sense_r2);
}
break;
}
break;
case AO_LOG_FORMAT_TELEGPS:
log_gps = (struct ao_log_gps *) &eeprom->data[pos];
switch (log_gps->type) {
case AO_LOG_GPS_TIME:
printf(" lat %10.7f ° lon %10.7f ° alt %8d m",
log_gps->u.gps.latitude / 10000000.0,
log_gps->u.gps.longitude/ 10000000.0,
(int32_t) (log_gps->u.gps.altitude_low |
(log_gps->u.gps.altitude_high << 16)));
printf(" time %02d:%02d:%02d %04d-%02d-%02d flags %02x",
log_gps->u.gps.hour,
log_gps->u.gps.minute,
log_gps->u.gps.second,
log_gps->u.gps.year + 2000,
log_gps->u.gps.month,
log_gps->u.gps.day,
log_gps->u.gps.flags);
printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d",
log_gps->u.gps.course,
log_gps->u.gps.ground_speed,
log_gps->u.gps.climb_rate,
log_gps->u.gps.pdop,
log_gps->u.gps.hdop,
log_gps->u.gps.vdop,
log_gps->u.gps.mode);
break;
case AO_LOG_GPS_SAT:
printf(" channels %2d",
log_gps->u.gps_sat.channels);
for (i = 0; i < 12; i++) {
printf(" svid %3d c_n %2d",
log_gps->u.gps_sat.sats[i].svid,
log_gps->u.gps_sat.sats[i].c_n);
}
break;
default:
printf (" unknown");
break;
}
break;
case AO_LOG_FORMAT_EASYMOTOR:
log_motor = (struct ao_log_motor *) &eeprom->data[pos];
switch (log_motor->type) {
case AO_LOG_FLIGHT:
printf(" serial %5u flight %5u ground_accel %6d",
eeprom->serial_number,
log_motor->u.flight.flight,
log_motor->u.flight.ground_accel);
printf(" along %6d aross %6d through %6d",
log_motor->u.flight.ground_accel_along,
log_motor->u.flight.ground_accel_across,
log_motor->u.flight.ground_accel_through);
ao_volts("ground pressure",
log_motor->u.flight.ground_motor_pressure,
max_adc, adc_ref,
sense_r1, sense_r2);
break;
case AO_LOG_STATE:
ao_state(log_motor->u.state.state,
log_motor->u.state.reason);
break;
case AO_LOG_SENSOR:
ao_volts("pressure",
log_motor->u.sensor.pressure,
max_adc, adc_ref,
sense_r1, sense_r2);
ao_volts("v_batt",
log_motor->u.sensor.v_batt,
max_adc,
adc_ref, batt_r1, batt_r2);
printf(" accel %6d",
log_motor->u.sensor.accel);
printf(" along %6d aross %6d through %6d",
log_motor->u.sensor.accel_along,
log_motor->u.sensor.accel_across,
log_motor->u.sensor.accel_through);
break;
}
break;
case AO_LOG_FORMAT_DETHERM:
break;
}
}
printf("\n");
}
}
return ret;
}

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-elftohex
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_ELFTOHEX_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_elftohex_DEPENDENCIES = $(AO_ELFTOHEX_LIBS)
ao_elftohex_LDADD=$(AO_ELFTOHEX_LIBS) -lelf
ao_elftohex_SOURCES=ao-elftohex.c
man_MANS = ao-elftohex.1

View File

@@ -0,0 +1,43 @@
.\"
.\" Copyright © 2013 Keith Packard <keithp@keithp.com>
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful, but
.\" WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
.\" General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License along
.\" with this program; if not, write to the Free Software Foundation, Inc.,
.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
.\"
.\"
.TH AO-LOAD 1 "ao-elftohex" ""
.SH NAME
ao-elftohex \- convert programs to IHX format
.SH SYNOPSIS
.B "ao-elftohex"
[\--output-\fIoutput.ihx\fP]
[\--verbose]
\fIinput.elf ...\fP
.SH DESCRIPTION
.I ao-elftohex
reads the specified .elf files and writes out a .ihx version.
.SH OPTIONS
.TP
\--output=\fIoutput.ihx\fP
This specifies the output file (default is stdout)
.TP
\--verbose
Dumps some debug information.
.TP
\--nosym
Excluded symbol table information from the resulting file. This
information is a non-standard extension supported by the Altus Metrum
tools.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,134 @@
/*
* 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.
*/
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ao-hex.h"
#include "ao-elf.h"
#include "ao-verbose.h"
static const struct option options[] = {
{ .name = "verbose", .has_arg = 1, .val = 'v' },
{ .name = "output", .has_arg = 1, .val = 'o' },
{ .name = "nosym", .has_arg = 0, .val = 'n' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--verbose=<level>] [--output=<output.ihx>] <input.elf>\n", program);
exit(1);
}
static int
ends_with(char *whole, char *suffix)
{
int whole_len = strlen(whole);
int suffix_len = strlen(suffix);
if (suffix_len > whole_len)
return 0;
return strcmp(whole + whole_len - suffix_len, suffix) == 0;
}
int
main (int argc, char **argv)
{
char *input = NULL;
char *output = NULL;
struct ao_hex_image *full_image = NULL;
struct ao_sym *file_symbols = NULL;
int num_file_symbols;
FILE *file;
int c;
int i;
int nosym = 0;
while ((c = getopt_long(argc, argv, "nv:o:", options, NULL)) != -1) {
switch (c) {
case 'o':
output = optarg;
break;
case 'v':
ao_verbose = (int) strtol(optarg, NULL, 0);
break;
case 'n':
nosym = 1;
break;
default:
usage(argv[0]);
break;
}
}
if (optind >= argc)
usage(argv[0]);
for (i = optind; i < argc; i++) {
struct ao_hex_image *image;
input = argv[i];
free(file_symbols);
num_file_symbols = 0;
if (ends_with (input, ".ihx"))
image = ao_hex_load(input, &file_symbols, &num_file_symbols);
else
image = ao_load_elf(input, &file_symbols, &num_file_symbols);
if (!image) {
fprintf(stderr, "Failed to load %s\n", input);
usage(argv[0]);
}
if (nosym) {
free(file_symbols);
file_symbols = NULL;
num_file_symbols = 0;
}
if (full_image) {
full_image = ao_hex_image_cat(full_image, image);
if (!full_image) {
fprintf(stderr, "Can't merge image %s\n", input);
usage(argv[0]);
}
} else
full_image = image;
}
if (!output)
file = stdout;
else {
file = fopen(output, "w");
if (!file) {
perror(output);
exit(1);
}
}
if (!ao_hex_save(file, full_image, file_symbols, num_file_symbols)) {
fprintf(stderr, "%s: failed to write hex file\n", output ? output : "<stdout>");
if (output)
unlink(output);
exit(1);
}
exit(0);
}

View File

@@ -0,0 +1,3 @@
bin_SCRIPTS=ao-flash-stm ao-flash-lpc ao-flash-stm32f0x ao-reset-lpc ao-flash-samd21 ao-flash-stm32f1
man_MANS = ao-flash-stm.1 ao-flash-lpc.1 ao-flash-stm32f0x.1 ao-reset-lpc.1 ao-flash-samd21.1 ao-flash-stm32f1.1

17
ao-tools/ao-flash/ao-flash-lpc Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
case "$#" in
0)
echo "usage: $0 <filename> ..."
exit 1
;;
esac
cmds=/tmp/flash$$
trap "rm $cmds" 0 1 15
file="$1"
echo "program $file reset" > $cmds
openocd \
-f interface/stlink-v2.cfg \
-f target/lpc11xx.cfg \
-c 'adapter speed 1000' \
-f $cmds \
-c shutdown

View File

@@ -0,0 +1,36 @@
.\"
.\" 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-FLASH-LPC 1 "ao-flash-lpc" ""
.SH NAME
ao-flash-lpc \- flash a program to an LPC11U14-based AltOS device using openocd
.SH SYNOPSIS
.B "ao-flash-lpc"
\fIfile.elf\fP
.SH DESCRIPTION
.I ao-flash-lpc
loads the specified .elf file into the target device flash memory.
.SH USAGE
.I ao-flash-lpc
is a simple script that passes the correct arguments to openocd to
load a file into the target device via a connected STlink
debugging dongle.
.SH "SEE ALSO"
openocd(1)
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,19 @@
#!/bin/sh
case "$#" in
1)
;;
*)
echo "usage: $0 <filename> ..."
exit 1
;;
esac
openocd -f interface/stlink.cfg \
-c 'transport select hla_swd' \
-c 'set CHIPNAME at91samd21g18' \
-c 'set CPUTAPID 0x0bc11477' \
-f target/at91samdXX.cfg \
-c init \
-c 'reset halt' \
-c 'at91samd bootloader 0' \
-c "program $1 verify reset" \
-c "shutdown"

View File

@@ -0,0 +1,36 @@
.\"
.\" Copyright © 2022 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-FLASH-LPC 1 "ao-flash-samd21" ""
.SH NAME
ao-flash-samd21 \- flash a program to an SAMD21-based AltOS device using openocd
.SH SYNOPSIS
.B "ao-flash-samd21"
\fIfile.elf\fP
.SH DESCRIPTION
.I ao-flash-samd21
loads the specified .elf file into the target device flash memory.
.SH USAGE
.I ao-flash-samd21
is a simple script that passes the correct arguments to openocd to
load a file into the target device via a connected STlink
debugging dongle.
.SH "SEE ALSO"
openocd(1)
.SH AUTHOR
Keith Packard

16
ao-tools/ao-flash/ao-flash-stm Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
case "$#" in
0)
echo "usage: $0 <filename> ..."
exit 1
;;
esac
cmds=/tmp/flash$$
trap "rm $cmds" 0 1 15
file="$1"
echo "program $file reset" > $cmds
openocd \
-f interface/stlink-v2.cfg \
-f target/stm32l1.cfg \
-f $cmds \
-c shutdown

View File

@@ -0,0 +1,38 @@
.\"
.\" 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-FLASH-STM 1 "ao-flash-stm" ""
.SH NAME
ao-flash-stm \- flash a program to an STM32-based AltOS device using st-flash
.SH SYNOPSIS
.B "ao-flash-stm"
\fIfile.elf\fP
.SH DESCRIPTION
.I ao-flash-stm
loads the specified .elf file into the target device flash memory.
.SH USAGE
.I ao-flash-stm
converts the specified .elf file into a raw binary file and then uses
st-flash to load it into the target device via a connected STlink
debugging dongle. If st-flash is not available,
.I ao-flash-stm
will emit an error message and terminate.
.SH "SEE ALSO"
st-flash(1)
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,16 @@
#!/bin/sh
case "$#" in
0)
echo "usage: $0 <filename> ..."
exit 1
;;
esac
cmds=/tmp/flash$$
trap "rm $cmds" 0 1 15
file="$1"
echo "program $file verify reset" > $cmds
openocd \
-f interface/stlink.cfg \
-f target/stm32f0x.cfg \
-f $cmds \
-c shutdown

View File

@@ -0,0 +1,36 @@
.\"
.\" 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-FLASH-LPC 1 "ao-flash-stm32f0x" ""
.SH NAME
ao-flash-stm32f0x \- flash a program to a STM32F0x-based AltOS device using openocd
.SH SYNOPSIS
.B "ao-flash-stm32f0x"
\fIfile.elf\fP
.SH DESCRIPTION
.I ao-flash-stm32f0x
loads the specified .elf file into the target device flash memory.
.SH USAGE
.I ao-flash-stm32f0x
is a simple script that passes the correct arguments to openocd to
load a file into the target device via a connected STlink
debugging dongle.
.SH "SEE ALSO"
openocd(1)
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,15 @@
#!/bin/sh
case "$#" in
0)
echo "usage: $0 <filename> ..."
exit 1
;;
esac
openocd \
-f interface/stlink.cfg \
-c 'transport select hla_swd' \
-f target/stm32f1x.cfg \
-c init \
-c 'reset halt' \
-c "program $1 verify reset" \
-c 'shutdown'

View File

@@ -0,0 +1,36 @@
.\"
.\" Copyright © 2022 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-FLASH-LPC 1 "ao-flash-stm32f1" ""
.SH NAME
ao-flash-stm32f1 \- flash a program to an STM32F1x-based AltOS device using openocd
.SH SYNOPSIS
.B "ao-flash-stm32f1"
\fIfile.elf\fP
.SH DESCRIPTION
.I ao-flash-stm32f1
loads the specified .elf file into the target device flash memory.
.SH USAGE
.I ao-flash-stm32f1
is a simple script that passes the correct arguments to openocd to
load a file into the target device via a connected STlink
debugging dongle.
.SH "SEE ALSO"
openocd(1)
.SH AUTHOR
Keith Packard

9
ao-tools/ao-flash/ao-reset-lpc Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
cmds=/tmp/flash$$
trap "rm $cmds" 0 1 15
echo "reset" > $cmds
openocd \
-f interface/stlink-v2.cfg \
-f target/lpc11xx.cfg \
-f $cmds \
-c shutdown

View File

@@ -0,0 +1,35 @@
.\"
.\" Copyright © 2018 Bdale Garbee <bdale@gag.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-RESET-LPC 1 "ao-reset-lpc" ""
.SH NAME
ao-reset-lpc \- reset an LPC11U14-based AltOS device using openocd
.SH SYNOPSIS
.B "ao-reset-lpc"
.SH DESCRIPTION
.I ao-reset-lpc
resets the target device.
.SH USAGE
.I ao-reset-lpc
is a simple script that passes the correct arguments to openocd to
reset the target device via a connected STlink debugging dongle.
.SH "SEE ALSO"
openocd(1)
.SH AUTHOR
Bdale Garbee

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-list
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_LIST_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_list_DEPENDENCIES = $(AO_LIST_LIBS)
ao_list_LDADD=$(AO_LIST_LIBS) $(LIBUSB_LIBS)
ao_list_SOURCES = ao-list.c
man_MANS = ao-list.1

View File

@@ -0,0 +1,32 @@
/.\"
.\" 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-LIST 1 "ao-list" ""
.SH NAME
ao-list \- List connected AltOS devices
.SH SYNOPSIS
.B "ao-list"
.SH DESCRIPTION
.I ao-list
scans the attached USB devices, locates those running AltOS and
displays their product name and serial number along with the tty
device associated with the serial port over USB provided by AltOS.
.SH USAGE
.I ao-list
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,42 @@
/*
* 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 "cc.h"
int
main (int argc, char **argv)
{
struct cc_usbdevs *devs;
struct cc_usbdev *dev;
int i;
devs = cc_usbdevs_scan(TRUE);
if (devs) {
for (i = 0; i < devs->ndev; i++) {
dev = devs->dev[i];
printf ("%-20.20s %6d %s\n",
dev->product, dev->serial, dev->tty ? dev->tty : "(none)");
}
cc_usbdevs_free(devs);
}
return 0;
}

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-load
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_LOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_load_DEPENDENCIES = $(AO_LOAD_LIBS)
ao_load_LDADD=$(AO_LOAD_LIBS) $(LIBUSB_LIBS)
ao_load_SOURCES = ao-load.c
man_MANS = ao-load.1

View File

@@ -0,0 +1,73 @@
.\"
.\" 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-LOAD 1 "ao-load" ""
.SH NAME
ao-load \- flash a program to a AltOS device
.SH SYNOPSIS
.B "ao-load"
[\-T \fItty-device\fP]
[\--tty \fItty-device\fP]
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
[\--cal \fIradio-calibration\fP]
\fIfile.ihx\fP
\fIdevice serial number\fP
.SH DESCRIPTION
.I ao-load
loads the specified .ihx file into the target device flash memory,
customizing the AltOS image with the specified serial number.
.SH OPTIONS
.TP
\-T tty-device | --tty tty-device
This selects which tty device the debugger uses to communicate with
the target device. The special name 'BITBANG' directs ao-dbg to use
the cp2103 connection, otherwise this should be a usb serial port
connected to a suitable cc1111 debug node.
.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
\-c radio-calibration | --cal radio-calibration
This programs the radio calibration value into the image for hardware
which doesn't have any eeprom storage for this value. The value here
can be computed given the current radio calibration value, the
measured frequency and the desired frequency:
.IP
cal' = cal * (desired/measured)
.IP
The default calibration value is 1186611.
.SH USAGE
.I ao-load
reads the specified .ihx file into memory, locates the matching .map
file and edits the image to customize it using the specified serial
number. It then connects to the specified target device and writes the
program to the target device flash memory.
.SH AUTHOR
Keith Packard

286
ao-tools/ao-load/ao-load.c Normal file
View File

@@ -0,0 +1,286 @@
/*
* Copyright © 2008 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 <stdlib.h>
#include <limits.h>
#include <stdint.h>
#include <unistd.h>
#include <getopt.h>
#include "ccdbg.h"
#include "cc.h"
#define AO_USB_DESC_STRING 3
static struct sym {
unsigned addr;
char *name;
int required;
} ao_symbols[] = {
{ 0, "_ao_serial_number", 1 },
#define AO_SERIAL_NUMBER (ao_symbols[0].addr)
{ 0, "_ao_usb_descriptors", 0 },
#define AO_USB_DESCRIPTORS (ao_symbols[1].addr)
{ 0, "_ao_radio_cal", 1 },
#define AO_RADIO_CAL (ao_symbols[2].addr)
};
#define NUM_SYMBOLS 3
#define NUM_REQUIRED_SYMBOLS 2
static int
find_symbols(FILE *map)
{
char line[2048];
char *addr, *addr_end;
char *name;
char *save;
char *colon;
unsigned long a;
int s;
int required = 0;
while (fgets(line, sizeof(line), map) != NULL) {
line[sizeof(line)-1] = '\0';
addr = strtok_r(line, " \t\n", &save);
if (!addr)
continue;
name = strtok_r(NULL, " \t\n", &save);
if (!name)
continue;
colon = strchr (addr, ':');
if (!colon)
continue;
a = strtoul(colon+1, &addr_end, 16);
if (a == ULONG_MAX || addr_end == addr)
continue;
for (s = 0; s < NUM_SYMBOLS; s++)
if (!strcmp(ao_symbols[s].name, name)) {
ao_symbols[s].addr = (unsigned) a;
if (ao_symbols[s].required)
++required;
break;
}
}
return required >= NUM_REQUIRED_SYMBOLS;
}
static int
rewrite(struct ao_hex_image *image, unsigned addr, char *data, int len)
{
int i;
if (addr < image->address || image->address + image->length < addr + len)
return 0;
printf("rewrite %04x:", addr);
for (i = 0; i < len; i++)
printf (" %02x", image->data[addr - image->address + i]);
printf(" ->");
for (i = 0; i < len; i++)
printf (" %02x", data[i]);
printf("\n");
memcpy(image->data + addr - image->address, data, len);
return 1;
}
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
{ .name = "cal", .has_arg = 1, .val = 'c' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--tty=<tty-name>] [--device=<device-name>] [--cal=<radio-cal>] file.ihx serial-number\n", program);
exit(1);
}
int
main (int argc, char **argv)
{
struct ccdbg *dbg;
struct ao_hex_file *hex;
struct ao_hex_image *image;
char *filename;
FILE *file;
FILE *map;
char *serial_string;
unsigned int serial;
char *mapname, *dot;
char *serial_ucs2;
int serial_ucs2_len;
char serial_int[2];
unsigned int s;
int i;
int string_num;
char *tty = NULL;
char *device = NULL;
uint32_t cal = 0;
char cal_int[4];
char *cal_end;
int c;
while ((c = getopt_long(argc, argv, "T:D:c:", options, NULL)) != -1) {
switch (c) {
case 'T':
tty = optarg;
break;
case 'D':
device = optarg;
break;
case 'c':
cal = strtoul(optarg, &cal_end, 10);
if (cal_end == optarg || *cal_end != '\0')
usage(argv[0]);
break;
default:
usage(argv[0]);
break;
}
}
filename = argv[optind];
if (filename == NULL)
usage(argv[0]);
mapname = strdup(filename);
dot = strrchr(mapname, '.');
if (!dot || strcmp(dot, ".ihx") != 0)
usage(argv[0]);
strcpy(dot, ".map");
serial_string = argv[optind + 1];
if (serial_string == NULL)
usage(argv[0]);
file = fopen(filename, "r");
if (!file) {
perror(filename);
exit(1);
}
map = fopen(mapname, "r");
if (!map) {
perror(mapname);
exit(1);
}
if (!find_symbols(map)) {
fprintf(stderr, "Cannot find symbols in \"%s\"\n", mapname);
exit(1);
}
fclose(map);
hex = ao_hex_file_read(file, filename);
fclose(file);
if (!hex) {
perror(filename);
exit (1);
}
image = ao_hex_image_create(hex);
if (!image) {
fprintf(stderr, "image create failed\n");
exit (1);
}
ao_hex_file_free(hex);
serial = strtoul(serial_string, NULL, 0);
if (!serial)
usage(argv[0]);
serial_int[0] = serial & 0xff;
serial_int[1] = (serial >> 8) & 0xff;
if (!rewrite(image, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {
fprintf(stderr, "Cannot rewrite serial integer at %04x\n",
AO_SERIAL_NUMBER);
exit(1);
}
if (AO_USB_DESCRIPTORS) {
unsigned usb_descriptors;
usb_descriptors = AO_USB_DESCRIPTORS - image->address;
string_num = 0;
while (image->data[usb_descriptors] != 0 && usb_descriptors < image->length) {
if (image->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
++string_num;
if (string_num == 4)
break;
}
usb_descriptors += image->data[usb_descriptors];
}
if (usb_descriptors >= image->length || image->data[usb_descriptors] == 0 ) {
fprintf(stderr, "Cannot rewrite serial string at %04x\n", AO_USB_DESCRIPTORS);
exit(1);
}
serial_ucs2_len = image->data[usb_descriptors] - 2;
serial_ucs2 = malloc(serial_ucs2_len);
if (!serial_ucs2) {
fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len);
exit(1);
}
s = serial;
for (i = serial_ucs2_len / 2; i; i--) {
serial_ucs2[i * 2 - 1] = 0;
serial_ucs2[i * 2 - 2] = (s % 10) + '0';
s /= 10;
}
if (!rewrite(image, usb_descriptors + 2 + image->address, serial_ucs2, serial_ucs2_len))
usage(argv[0]);
}
if (cal) {
cal_int[0] = cal & 0xff;
cal_int[1] = (cal >> 8) & 0xff;
cal_int[2] = (cal >> 16) & 0xff;
cal_int[3] = (cal >> 24) & 0xff;
if (!AO_RADIO_CAL) {
fprintf(stderr, "Cannot find radio calibration location in image\n");
exit(1);
}
if (!rewrite(image, AO_RADIO_CAL, cal_int, sizeof (cal_int))) {
fprintf(stderr, "Cannot rewrite radio calibration at %04x\n", AO_RADIO_CAL);
exit(1);
}
}
if (!tty)
tty = cc_usbdevs_find_by_arg(device, "TIDongle");
dbg = ccdbg_open(tty);
if (!dbg)
exit (1);
ccdbg_add_debug(CC_DEBUG_FLASH);
ccdbg_debug_mode(dbg);
ccdbg_halt(dbg);
if (image->address == 0xf000) {
printf("Loading %d bytes to execute from RAM\n",
image->length);
ccdbg_write_hex_image(dbg, image, 0);
} else if (image->address == 0x0000) {
printf("Loading %d bytes to execute from FLASH\n",
image->length);
ccdbg_flash_hex_image(dbg, image);
} else {
printf("Cannot load code to 0x%04x\n",
image->address);
ao_hex_image_free(image);
ccdbg_close(dbg);
exit(1);
}
ccdbg_set_pc(dbg, image->address);
ccdbg_resume(dbg);
ccdbg_close(dbg);
exit (0);
}

1
ao-tools/ao-makebin/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ao-makebin

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-makebin
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_ELFTOHEX_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_makebin_DEPENDENCIES = $(AO_ELFTOHEX_LIBS)
ao_makebin_LDADD=$(AO_ELFTOHEX_LIBS) -lelf
ao_makebin_SOURCES=ao-makebin.c
man_MANS = ao-makebin.1

View File

@@ -0,0 +1,47 @@
.\"
.\" Copyright © 2013 Keith Packard <keithp@keithp.com>
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful, but
.\" WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
.\" General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License along
.\" with this program; if not, write to the Free Software Foundation, Inc.,
.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
.\"
.\"
.TH AO-LOAD 1 "ao-makebin" ""
.SH NAME
ao-makebin \- construct raw binary file or DFU image from collection of ELF files
.SH SYNOPSIS
.B "ao-makebin"
[\--base=\fIbase-address\fP]
[\--output=\fIoutput.bin\fP]
[\--dfu]
[\--verbose]
\fIinput.elf ...\fP
.SH DESCRIPTION
.I ao-makebin
reads the specified .elf files and writes out a raw binary flash image
.SH OPTIONS
.TP
\--base=\fIbase-address\fP
This specifies the target address for the first byte of the file (default is 0)
.TP
\--output=\fIoutput.bin\fP
This specifies the output file (default is stdout)
.TP
\--dfu
Creates a DFU file (as documented by ST's UM0391 user manual) instead
of a raw binary file.
.TP
\--verbose
Dumps some debug information.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,173 @@
/*
* Copyright © 2016 Keith Packard <keithp@keithp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "ao-hex.h"
#include "ao-elf.h"
#include "ao-dfu.h"
static const struct option options[] = {
{ .name = "verbose", .has_arg = 0, .val = 'v' },
{ .name = "output", .has_arg = 1, .val = 'o' },
{ .name = "base", .has_arg = 1, .val = 'b' },
{ .name = "align", .has_arg = 1, .val = 'a' },
{ .name = "dfu", .has_arg = 0, .val = 'd' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--verbose=<level>] [--output=<output.bin>] [--base=<base-address>] [--align=<align>] [--dfu] <input.elf> ...\n", program);
exit(1);
}
static int
ends_with(char *whole, char *suffix)
{
int whole_len = strlen(whole);
int suffix_len = strlen(suffix);
if (suffix_len > whole_len)
return 0;
return strcmp(whole + whole_len - suffix_len, suffix) == 0;
}
static struct ao_dfu_info dfu_info = {
.bcdDevice = 0x0000,
.idProduct = 0xdf11,
.idVendor = 0x0483,
};
int
main (int argc, char **argv)
{
char *output = NULL;
struct ao_hex_image *image = NULL;
struct ao_sym *file_symbols;
int num_file_symbols;
FILE *file;
int c;
uint32_t base = 0xffffffff;
uint32_t align = 0;
uint32_t length;
int verbose = 0;
int dfu = 0;
while ((c = getopt_long(argc, argv, "dvo:b:a:", options, NULL)) != -1) {
switch (c) {
case 'o':
output = optarg;
break;
case 'v':
verbose++;
break;
case 'b':
base = strtoul(optarg, NULL, 0);
break;
case 'a':
align = strtoul(optarg, NULL, 0);
break;
case 'd':
dfu = 1;
break;
default:
usage(argv[0]);
break;
}
}
while (argv[optind]) {
char *input = argv[optind];
struct ao_hex_image *tmp;
if (ends_with (input, ".ihx"))
tmp = ao_hex_load(input, &file_symbols, &num_file_symbols);
else
tmp = ao_load_elf(input, &file_symbols, &num_file_symbols);
if (!tmp)
usage(argv[0]);
if (verbose)
fprintf(stderr, "%s: 0x%x %d\n", input, tmp->address, tmp->length);
if (image) {
image = ao_hex_image_cat(image, tmp);
if (!image)
usage(argv[0]);
} else
image = tmp;
optind++;
}
if (base != 0xffffffff && base > image->address) {
fprintf(stderr, "requested base 0x%x is after image address 0x%x\n",
base, image->address);
usage(argv[0]);
}
if (verbose)
fprintf(stderr, "%s: base 0x%x length %d\n", output ? output : "<stdout>", image->address, image->length);
if (!output)
file = stdout;
else {
file = fopen(output, "w");
if (!file) {
perror(output);
exit(1);
}
}
if (dfu) {
if (!ao_dfu_write(file, &dfu_info, 1, image)) {
fprintf(stderr, "%s: dfu_write failed: %s\n", output, strerror(errno));
if (output)
unlink(output);
exit(1);
}
} else {
while (base < image->address) {
fputc(0xff, file);
base++;
}
if (fwrite(image->data, 1, image->length, file) != image->length) {
fprintf(stderr, "%s: failed to write bin file\n", output ? output : "<stdout>");
if (output)
unlink(output);
exit(1);
}
if (align) {
length = image->length;
while (length % align) {
fputc(0xff, file);
length++;
}
}
fflush(file);
}
exit(0);
}

1
ao-tools/ao-mega/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ao-mega

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-mega
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_mega_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
ao_mega_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS)
ao_mega_SOURCES = ao-mega.c
man_MANS = ao-mega.1

View File

@@ -0,0 +1,30 @@
.\"
.\" 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-TELEM 1 "ao-mega" ""
.SH NAME
ao-mega \- Dump a mega flight log (eeprom only)
.SH SYNOPSIS
.B "ao-mega"
{flight.mega}
.SH DESCRIPTION
.I ao-mega
reads the specified flight log and dumps it in human readable format.
output.
.SH AUTHOR
Keith Packard

143
ao-tools/ao-mega/ao-mega.c Normal file
View File

@@ -0,0 +1,143 @@
/*
* Copyright © 2011 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.
*/
#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[] = {
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s\n"
"\t{flight.mega} ...\n", program);
exit(1);
}
#define bool(b) ((b) ? "true" : "false")
static const char *state_names[] = {
"startup",
"idle",
"pad",
"boost",
"fast",
"coast",
"drogue",
"main",
"landed",
"invalid"
};
#define NUM_STATE (sizeof state_names/sizeof state_names[0])
int
main (int argc, char **argv)
{
char line[256];
int c, i, ret, j;
char *s;
FILE *file;
int serial;
const char *state;
while ((c = getopt_long(argc, argv, "", options, NULL)) != -1) {
switch (c) {
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)) {
struct ao_log_mega log;
if (cc_mega_parse(line, &log)) {
if (log.is_config) {
printf ("config %2d %s", log.u.config_int.kind, line);
} else {
printf ("tick %5d ", log.tick);
switch (log.type) {
case AO_LOG_FLIGHT:
printf ("flight %5u ground_accel %d ground_pres %u\n",
log.u.flight.flight,
log.u.flight.ground_accel,
log.u.flight.ground_pres);
break;
case AO_LOG_STATE:
if (log.u.state.state < NUM_STATE)
state = state_names[log.u.state.state];
else
state = "invalid";
printf ("state %d (%s)\n", log.u.state.state, state);
break;
case AO_LOG_SENSOR:
printf ("p %9u t %9u ax %6d ay %6d az %6d gx %6d gy %6d gz %6d mx %6d my %6d mz %6d a %6d\n",
log.u.sensor.pres,
log.u.sensor.temp,
log.u.sensor.accel_x,
log.u.sensor.accel_y,
log.u.sensor.accel_z,
log.u.sensor.gyro_x,
log.u.sensor.gyro_y,
log.u.sensor.gyro_z,
log.u.sensor.mag_x,
log.u.sensor.mag_y,
log.u.sensor.mag_z,
log.u.sensor.accel);
break;
case AO_LOG_TEMP_VOLT:
printf ("batt %6d pbatt %6d n_sense %d",
log.u.volt.v_batt,
log.u.volt.v_pbatt,
log.u.volt.n_sense);
for (j = 0; j < log.u.volt.n_sense; j++) {
printf (" s%d %6d",
j, log.u.volt.sense[j]);
}
printf (" pyro %04x\n", log.u.volt.pyro);
break;
default:
printf ("type %c\n", log.type, log.tick);
break;
}
}
}
}
fclose (file);
}
return ret;
}

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-postflight
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS) $(PLPLOT_CFLAGS)
AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_postflight_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
ao_postflight_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS) $(GNOME_LIBS) $(PLPLOT_LIBS)
ao_postflight_SOURCES = ao-postflight.c
man_MANS = ao-postflight.1

View File

@@ -0,0 +1,61 @@
.\"
.\" 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-POSTFLIGHT 1 "ao-postflight" ""
.SH NAME
ao-postflight \- Analyse a flight log (either telemetry or eeprom)
.SH SYNOPSIS
.B "ao-postflight"
[\-s <summary-file>]
[\--summary=<summary-file>]
[\-d <detail-file>]
[\--detail=<detail-file>]
[\-r <raw-file>]
[\--raw=<raw-file>]
[\-p <plot-file>]
[\--plot=<plot-file>]
[\-g <gps-file]
[\--gps=<gps-file]
[\-k <kml-file]
[\--kml=<kml-file]
{flight.eeprom|flight.telem}
.SH DESCRIPTION
.I ao-postflight
reads the specified flight log and produces several different kinds of
output.
.IP Summary
By default, summary information is shown on stdout. With the --summary
option, it can be redirected to a file.
.IP Detail
When requested with the --detail option, a filtered version of the
flight position, speed and acceleration are written to the specified
file.
.IP Raw
The --raw option writes the unfiltered, but converted acceleration
and height data to the specified file.
.IP Plot
The --plot option writes plots of height, speed and acceleration to
the specified file in .svg format
.IP GPS
The --gps option writes the recorded GPS data to the specified file in
three columns.
.IP KML
The --kml option writes the recorded GPS data to the specified file in
Keyhole Markup Language format, which can be displayed in Googleearth.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,827 @@
/*
* 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.
*/
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include "cc-usb.h"
#include "cc.h"
#include <plplot/plplot.h>
static const char *state_names[] = {
"startup",
"idle",
"pad",
"boost",
"fast",
"coast",
"drogue",
"main",
"landed",
"invalid"
};
static const char *kml_state_colours[] = {
"FF000000",
"FF000000",
"FF000000",
"FF0000FF",
"FF4080FF",
"FF00FFFF",
"FFFF0000",
"FF00FF00",
"FF000000",
"FFFFFFFF"
};
static int plot_colors[3][3] = {
{ 0, 0x90, 0 }, /* height */
{ 0xa0, 0, 0 }, /* speed */
{ 0, 0, 0xc0 }, /* accel */
};
#define PLOT_HEIGHT 0
#define PLOT_SPEED 1
#define PLOT_ACCEL 2
static void
plot_perioddata(struct cc_perioddata *d, char *axis_label, char *plot_label,
double min_time, double max_time, int plot_type)
{
double *times;
double ymin, ymax;
int ymin_i, ymax_i;
int i;
int start, stop;
if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return;
times = calloc(stop - start + 1, sizeof (double));
for (i = start; i <= stop; i++)
times[i-start] = i * d->step / 100.0;
ymin_i = cc_perioddata_min(d, min_time, max_time);
ymax_i = cc_perioddata_max(d, min_time, max_time);
ymin = d->data[ymin_i];
ymax = d->data[ymax_i];
plscol0(1, 0, 0, 0);
plscol0(2, plot_colors[plot_type][0], plot_colors[plot_type][1], plot_colors[plot_type][2]);
plcol0(1);
plenv(times[0], times[stop-start],
ymin, ymax, 0, 2);
pllab("Time", axis_label, plot_label);
plcol0(2);
plline(stop - start + 1, times, d->data + start);
free(times);
}
static void
plot_timedata(struct cc_timedata *d, char *axis_label, char *plot_label,
double min_time, double max_time, int plot_type)
{
double *times;
double *values;
double ymin, ymax;
int ymin_i, ymax_i;
int i;
int start = -1, stop = -1;
double start_time = 0, stop_time = 0;
int num;
for (i = 0; i < d->num; i++) {
if (start < 0 && d->data[i].time >= min_time) {
start_time = d->data[i].time;
start = i;
}
if (d->data[i].time <= max_time) {
stop_time = d->data[i].time;
stop = i;
}
}
times = calloc(stop - start + 1, sizeof (double));
values = calloc(stop - start + 1, sizeof (double));
ymin_i = cc_timedata_min(d, min_time, max_time);
ymax_i = cc_timedata_max(d, min_time, max_time);
ymin = d->data[ymin_i].value;
ymax = d->data[ymax_i].value;
for (i = start; i <= stop; i++) {
times[i-start] = (d->data[i].time - start_time)/100.0;
values[i-start] = d->data[i].value;
}
plscol0(1, 0, 0, 0);
plscol0(2, plot_colors[plot_type][0], plot_colors[plot_type][1], plot_colors[plot_type][2]);
plcol0(1);
plenv(times[0], times[stop-start], ymin, ymax, 0, 2);
pllab("Time", axis_label, plot_label);
plcol0(2);
plline(stop - start + 1, times, values);
free(times);
free(values);
}
static struct cc_perioddata *
merge_data(struct cc_perioddata *first, struct cc_perioddata *last, double split_time)
{
int i;
struct cc_perioddata *pd;
int num;
double start_time, stop_time;
double t;
pd = calloc(1, sizeof (struct cc_perioddata));
start_time = first->start;
stop_time = last->start + last->step * last->num;
num = (stop_time - start_time) / first->step;
pd->num = num;
pd->data = calloc(num, sizeof (double));
pd->start = first->start;
pd->step = first->step;
for (i = 0; i < num; i++) {
t = pd->start + i * pd->step;
if (t <= split_time) {
pd->data[i] = first->data[i];
} else {
int j;
j = (t - last->start) / last->step;
if (j < 0 || j >= last->num)
pd->data[i] = 0;
else
pd->data[i] = last->data[j];
}
}
return pd;
}
static const char kml_header_start[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
"<Document>\n"
" <name>%s</name>\n"
" <description>\n";
static const char kml_header_end[] =
" </description>\n"
" <open>0</open>\n";
static const char kml_style_start[] =
" <Style id=\"ao-flightstate-%s\">\n"
" <LineStyle><color>%s</color><width>4</width></LineStyle>\n"
" <BalloonStyle>\n"
" <text>\n";
static const char kml_style_end[] =
" </text>\n"
" </BalloonStyle>\n"
" </Style>\n";
static const char kml_placemark_start[] =
" <Placemark>\n"
" <name>%s</name>\n"
" <styleUrl>#ao-flightstate-%s</styleUrl>\n"
" <LineString>\n"
" <tessellate>1</tessellate>\n"
" <altitudeMode>absolute</altitudeMode>\n"
" <coordinates>\n";
static const char kml_coord_fmt[] =
" %12.7f, %12.7f, %12.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
static const char kml_placemark_end[] =
" </coordinates>\n"
" </LineString>\n"
" </Placemark>\n";
static const char kml_footer[] =
" </coordinates>\n"
" </LineString>\n"
" </Placemark>\n"
"</Document>\n"
"</kml>\n";
static unsigned
gps_daytime(struct cc_gpselt *gps)
{
return ((gps->hour * 60 +
gps->minute) * 60 +
gps->second) * 1000;
}
int
daytime_hour(unsigned daytime)
{
return daytime / 1000 / 60 / 60;
}
int
daytime_minute(unsigned daytime)
{
return (daytime / 1000 / 60) % 60;
}
int
daytime_second(unsigned daytime)
{
return (daytime / 1000) % 60;
}
int
daytime_millisecond(unsigned daytime)
{
return daytime % 1000;
}
static unsigned
compute_daytime_ms(double time, struct cc_gpsdata *gps)
{
int i;
unsigned gps_start_daytime, gps_stop_daytime;
if (time <= gps->data[0].time) {
gps_stop_daytime = gps_daytime(&gps->data[0]);
return gps_stop_daytime - (gps->data[0].time - time) * 10;
}
for (i = 0; i < gps->num - 1; i++)
if (time > gps->data[i].time)
break;
gps_start_daytime = gps_daytime(&gps->data[i]);
if (i == gps->num - 1) {
return gps_start_daytime + (time - gps->data[i].time) * 10;
} else {
unsigned gps_period_daytime;
double gps_period_time;
double time_since_start;
gps_stop_daytime = gps_daytime(&gps->data[i + 1]);
/* range of gps daytime values */
gps_period_daytime = gps_stop_daytime - gps_start_daytime;
/* range of gps time values */
gps_period_time = gps->data[i+1].time - gps->data[i].time;
/* sample time after first gps time */
time_since_start = time - gps->data[i].time;
return gps_start_daytime +
gps_period_daytime * time_since_start / gps_period_time;
}
}
static void
analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
FILE *raw_file, char *plot_name, FILE *gps_file, FILE *kml_file)
{
double height;
double accel;
double speed;
double avg_speed;
double boost_start, boost_stop;
double min_pres;
int i;
int pres_i, accel_i, speed_i;
int boost_start_set = 0;
int boost_stop_set = 0;
enum ao_flight_state state;
double state_start, state_stop;
struct cc_flightcooked *cooked;
double apogee;
char buf[128];
if (kml_file) {
snprintf(buf, sizeof (buf), "AO Flight#%d S/N: %03d", f->flight, f->serial);
fprintf(kml_file, kml_header_start, buf);
}
fprintf(summary_file,
"Serial: %9d\n"
"Flight: %9d\n",
f->serial, f->flight);
if (f->year) {
snprintf(buf, sizeof (buf),
"Date: %04d-%02d-%02d\n",
f->year, f->month, f->day);
fprintf(summary_file, "%s", buf);
if (kml_file) fprintf(kml_file, "%s", buf);
}
if (f->gps.num) {
snprintf(buf, sizeof (buf),
"Time: %2d:%02d:%02d\n",
f->gps.data[0].hour,
f->gps.data[0].minute,
f->gps.data[0].second);
fprintf(summary_file, "%s", buf);
if (kml_file) fprintf(kml_file, "%s", buf);
}
boost_start = f->accel.data[0].time;
boost_stop = f->accel.data[f->accel.num-1].time;
for (i = 0; i < f->state.num; i++) {
if (f->state.data[i].value == ao_flight_boost && !boost_start_set) {
boost_start = f->state.data[i].time;
boost_start_set = 1;
}
if (f->state.data[i].value > ao_flight_boost && !boost_stop_set) {
boost_stop = f->state.data[i].time;
boost_stop_set = 1;
}
}
pres_i = cc_timedata_min(&f->pres, f->pres.data[0].time,
f->pres.data[f->pres.num-1].time);
if (pres_i >= 0)
{
min_pres = f->pres.data[pres_i].value;
height = cc_barometer_to_altitude(min_pres) -
cc_barometer_to_altitude(f->ground_pres);
apogee = f->pres.data[pres_i].time;
snprintf(buf, sizeof (buf), "Max height: %9.2fm %9.2fft %9.2fs\n",
height, height * 100 / 2.54 / 12,
(f->pres.data[pres_i].time - boost_start) / 100.0);
fprintf(summary_file, "%s", buf);
if (kml_file) fprintf(kml_file, "%s", buf);
}
cooked = cc_flight_cook(f);
if (cooked) {
speed_i = cc_perioddata_max(&cooked->accel_speed, boost_start, boost_stop);
if (speed_i >= 0) {
speed = cooked->accel_speed.data[speed_i];
snprintf(buf, sizeof (buf), "Max speed: %9.2fm/s %9.2fft/s %9.2fs\n",
speed, speed * 100 / 2.4 / 12.0,
(cooked->accel_speed.start + speed_i * cooked->accel_speed.step - boost_start) / 100.0);
fprintf(summary_file, "%s", buf);
if (kml_file) fprintf(kml_file, "%s", buf);
}
}
accel_i = cc_timedata_min(&f->accel, boost_start, boost_stop);
if (accel_i >= 0)
{
accel = cc_accelerometer_to_acceleration(f->accel.data[accel_i].value,
f->ground_accel);
snprintf(buf, sizeof (buf), "Max accel: %9.2fm/s² %9.2fg %9.2fs\n",
accel, accel / 9.80665,
(f->accel.data[accel_i].time - boost_start) / 100.0);
fprintf(summary_file, "%s", buf);
if (kml_file) fprintf(kml_file, "%s", buf);
}
if (kml_file)
fprintf(kml_file, "%s", kml_header_end);
for (i = 0; i < f->state.num; i++) {
state = f->state.data[i].value;
state_start = f->state.data[i].time;
while (i < f->state.num - 1 && f->state.data[i+1].value == state)
i++;
if (i < f->state.num - 1)
state_stop = f->state.data[i + 1].time;
else
state_stop = f->accel.data[f->accel.num-1].time;
fprintf(summary_file, "State: %s\n", state_names[state]);
fprintf(summary_file, "\tStart: %9.2fs\n", (state_start - boost_start) / 100.0);
fprintf(summary_file, "\tDuration: %9.2fs\n", (state_stop - state_start) / 100.0);
if (kml_file) {
fprintf(kml_file, kml_style_start, state_names[state], kml_state_colours[state]);
fprintf(kml_file, "\tState: %s\n", state_names[state]);
fprintf(kml_file, "\tStart: %9.2fs\n", (state_start - boost_start) / 100.0);
fprintf(kml_file, "\tDuration: %9.2fs\n", (state_stop - state_start) / 100.0);
}
accel_i = cc_timedata_min(&f->accel, state_start, state_stop);
if (accel_i >= 0)
{
accel = cc_accelerometer_to_acceleration(f->accel.data[accel_i].value,
f->ground_accel);
snprintf(buf, sizeof (buf), "\tMax accel: %9.2fm/s² %9.2fg %9.2fs\n",
accel, accel / 9.80665,
(f->accel.data[accel_i].time - boost_start) / 100.0);
fprintf(summary_file, "%s", buf);
if (kml_file) fprintf(kml_file, "%s", buf);
}
if (cooked) {
if (state < ao_flight_drogue) {
speed_i = cc_perioddata_max_mag(&cooked->accel_speed, state_start, state_stop);
if (speed_i >= 0)
speed = cooked->accel_speed.data[speed_i];
avg_speed = cc_perioddata_average(&cooked->accel_speed, state_start, state_stop);
} else {
speed_i = cc_perioddata_max_mag(&cooked->pres_speed, state_start, state_stop);
if (speed_i >= 0)
speed = cooked->pres_speed.data[speed_i];
avg_speed = cc_perioddata_average(&cooked->pres_speed, state_start, state_stop);
}
if (speed_i >= 0)
{
snprintf(buf, sizeof (buf), "\tMax speed: %9.2fm/s %9.2fft/s %9.2fs\n",
speed, speed * 100 / 2.4 / 12.0,
(cooked->accel_speed.start + speed_i * cooked->accel_speed.step - boost_start) / 100.0);
fprintf(summary_file, "%s", buf);
if (kml_file) fprintf(kml_file, "%s", buf);
snprintf(buf, sizeof (buf), "\tAvg speed: %9.2fm/s %9.2fft/s\n",
avg_speed, avg_speed * 100 / 2.4 / 12.0);
fprintf(summary_file, "%s", buf);
if (kml_file) fprintf(kml_file, "%s", buf);
}
}
pres_i = cc_timedata_min(&f->pres, state_start, state_stop);
if (pres_i >= 0)
{
min_pres = f->pres.data[pres_i].value;
height = cc_barometer_to_altitude(min_pres) -
cc_barometer_to_altitude(f->ground_pres);
snprintf(buf, sizeof (buf), "\tMax height: %9.2fm %9.2fft %9.2fs\n",
height, height * 100 / 2.54 / 12,
(f->pres.data[pres_i].time - boost_start) / 100.0);
fprintf(summary_file, "%s", buf);
if (kml_file) fprintf(kml_file, "%s", buf);
}
if (kml_file) fprintf(kml_file, "%s", kml_style_end);
}
if (cooked && detail_file) {
double max_height = 0;
int i;
double *times;
fprintf(detail_file, "%9s %9s %9s %9s %9s\n",
"time", "height", "speed", "accel", "daytime");
for (i = 0; i < cooked->pres_pos.num; i++) {
double clock_time = cooked->accel_accel.start + i * cooked->accel_accel.step;
double time = (clock_time - boost_start) / 100.0;
double accel = cooked->accel_accel.data[i];
double pos = cooked->pres_pos.data[i];
double speed;
unsigned daytime;
if (cooked->pres_pos.start + cooked->pres_pos.step * i < apogee)
speed = cooked->accel_speed.data[i];
else
speed = cooked->pres_speed.data[i];
if (f->gps.num)
daytime = compute_daytime_ms(clock_time, &f->gps);
else
daytime = 0;
fprintf(detail_file, "%9.2f %9.2f %9.2f %9.2f %02d:%02d:%02d.%03d\n",
time, pos, speed, accel,
daytime_hour(daytime),
daytime_minute(daytime),
daytime_second(daytime),
daytime_millisecond(daytime));
}
}
if (raw_file) {
fprintf(raw_file, "%9s %9s %9s %9s\n",
"time", "height", "accel", "daytime");
for (i = 0; i < cooked->pres.num; i++) {
double time = cooked->pres.data[i].time;
double pres = cooked->pres.data[i].value;
double accel = cooked->accel.data[i].value;
unsigned daytime;
if (f->gps.num)
daytime = compute_daytime_ms(time, &f->gps);
else
daytime = 0;
fprintf(raw_file, "%9.2f %9.2f %9.2f %02d:%02d:%02d.%03d\n",
time, pres, accel,
daytime_hour(daytime),
daytime_minute(daytime),
daytime_second(daytime),
daytime_millisecond(daytime));
}
}
if (gps_file || kml_file) {
int j = 0, baro_pos;
double baro_offset;
double baro = 0.0;
int state_idx = 0;
if (gps_file)
fprintf(gps_file, "%2s %2s %2s %9s %12s %12s %9s %8s %5s\n",
"hr", "mn", "sc",
"time", "lat", "lon", "alt", "baro", "nsat");
if (kml_file)
fprintf(kml_file, kml_placemark_start,
state_names[(int)f->state.data[state_idx].value],
state_names[(int)f->state.data[state_idx].value]);
if (f->gps.num)
baro_offset = f->gps.data[0].alt;
else
baro_offset = 0;
baro_pos = 0;
for (i = 0; i < f->gps.num; i++) {
int nsat = 0;
int k;
while (j < f->gps.numsats - 1) {
if (f->gps.sats[j].sat[0].time <= f->gps.data[i].time &&
f->gps.data[i].time < f->gps.sats[j+1].sat[0].time)
break;
j++;
}
if (cooked) {
while (baro_pos < cooked->pres_pos.num) {
double baro_time = cooked->accel_accel.start + baro_pos * cooked->accel_accel.step;
if (baro_time >= f->gps.data[i].time)
break;
baro_pos++;
}
if (baro_pos < cooked->pres_pos.num)
baro = cooked->pres_pos.data[baro_pos];
}
if (gps_file)
fprintf(gps_file, "%2d %2d %2d %12.7f %12.7f %12.7f %7.1f %7.1f",
f->gps.data[i].hour,
f->gps.data[i].minute,
f->gps.data[i].second,
(f->gps.data[i].time - boost_start) / 100.0,
f->gps.data[i].lat,
f->gps.data[i].lon,
f->gps.data[i].alt,
baro + baro_offset);
nsat = 0;
if (f->gps.sats) {
for (k = 0; k < f->gps.sats[j].nsat; k++) {
if (f->gps.sats[j].sat[k].svid != 0)
nsat++;
}
if (gps_file) {
fprintf(gps_file, " %4d", nsat);
for (k = 0; k < f->gps.sats[j].nsat; k++) {
if (f->gps.sats[j].sat[k].svid != 0) {
fprintf (gps_file, " %3d(%4.1f)",
f->gps.sats[j].sat[k].svid,
(double) f->gps.sats[j].sat[k].c_n);
}
}
fprintf(gps_file, "\n");
}
}
if (kml_file) {
snprintf(buf, sizeof (buf), kml_coord_fmt,
f->gps.data[i].lon,
f->gps.data[i].lat,
baro + baro_offset,
f->gps.data[i].alt,
(f->gps.data[i].time - boost_start) / 100.0,
nsat);
fprintf(kml_file, "%s", buf);
if (state_idx + 1 < f->state.num && f->state.data[state_idx + 1].time <= f->gps.data[i].time) {
state_idx++;
if (f->state.data[state_idx - 1].value != f->state.data[state_idx].value) {
fprintf(kml_file, "%s", kml_placemark_end);
fprintf(kml_file, kml_placemark_start,
state_names[(int)f->state.data[state_idx].value],
state_names[(int)f->state.data[state_idx].value]);
fprintf(kml_file, "%s", buf);
}
}
}
}
if (kml_file)
fprintf(kml_file, "%s", kml_footer);
}
if (cooked && plot_name) {
struct cc_perioddata *speed;
plsdev("svgcairo");
plsfnam(plot_name);
#define PLOT_DPI 96
plspage(PLOT_DPI, PLOT_DPI, 8 * PLOT_DPI, 8 * PLOT_DPI, 0, 0);
plscolbg(0xff, 0xff, 0xff);
plscol0(1,0,0,0);
plstar(2, 3);
speed = merge_data(&cooked->accel_speed, &cooked->pres_speed, apogee);
plot_perioddata(&cooked->pres_pos, "meters", "Height",
-1e10, 1e10, PLOT_HEIGHT);
plot_perioddata(&cooked->pres_pos, "meters", "Height to Apogee",
boost_start, apogee + (apogee - boost_start) / 10.0, PLOT_HEIGHT);
plot_perioddata(speed, "meters/second", "Speed",
-1e10, 1e10, PLOT_SPEED);
plot_perioddata(speed, "meters/second", "Speed to Apogee",
boost_start, apogee + (apogee - boost_start) / 10.0, PLOT_SPEED);
plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration",
-1e10, 1e10, PLOT_ACCEL);
/* plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration during Boost",
boost_start, boost_stop + (boost_stop - boost_start) / 2.0, PLOT_ACCEL); */
plot_timedata(&cooked->accel, "meters/second²", "Acceleration during Boost",
boost_start, boost_stop + (boost_stop - boost_start) / 2.0, PLOT_ACCEL);
free(speed->data);
free(speed);
plend();
}
if (cooked)
cc_flightcooked_free(cooked);
}
static const struct option options[] = {
{ .name = "summary", .has_arg = 2, .val = 's' },
{ .name = "detail", .has_arg = 2, .val = 'd' },
{ .name = "plot", .has_arg = 2, .val = 'p' },
{ .name = "raw", .has_arg = 2, .val = 'r' },
{ .name = "gps", .has_arg = 2, .val = 'g' },
{ .name = "kml", .has_arg = 2, .val = 'k' },
{ .name = "all", .has_arg = 0, .val = 'a' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s\n"
"\t[--all] [-a]\n"
"\t[--summary=<summary-file>] [-s <summary-file>]\n"
"\t[--detail=<detail-file] [-d <detail-file>]\n"
"\t[--raw=<raw-file> -r <raw-file]\n"
"\t[--plot=<plot-file> -p <plot-file>]\n"
"\t[--gps=<gps-file> -g <gps-file>]\n"
"\t[--kml=<kml-file> -k <kml-file>]\n"
"\t{flight-log} ...\n", program);
exit(1);
}
char *
replace_extension(char *file, char *extension)
{
char *slash;
char *dot;
char *new;
int newlen;
slash = strrchr(file, '/');
dot = strrchr(file, '.');
if (!dot || (slash && dot < slash))
dot = file + strlen(file);
newlen = (dot - file) + strlen (extension) + 1;
new = malloc (newlen);
strncpy (new, file, dot - file);
new[dot-file] = '\0';
strcat (new, extension);
return new;
}
FILE *
open_output(char *outname, char *inname, char *extension)
{
char *o;
FILE *out;
if (outname)
o = outname;
else
o = replace_extension(inname, extension);
out = fopen(o, "w");
if (!out) {
perror (o);
exit(1);
}
if (o != outname)
free(o);
return out;
}
int
main (int argc, char **argv)
{
FILE *file;
FILE *summary_file = NULL;
FILE *detail_file = NULL;
FILE *raw_file = NULL;
FILE *gps_file = NULL;
FILE *kml_file = NULL;
int i;
int ret = 0;
struct cc_flightraw *raw;
int c;
int serial;
char *s;
char *summary_name = NULL;
char *detail_name = NULL;
char *raw_name = NULL;
char *plot_name = NULL;
char *gps_name = NULL;
char *kml_name = NULL;
int has_summary = 0;
int has_detail = 0;
int has_plot = 0;
int has_raw = 0;
int has_gps = 0;
int has_kml = 0;
char *this_plot_name = NULL;;
while ((c = getopt_long(argc, argv, "s:d:p:r:g:k:a", options, NULL)) != -1) {
switch (c) {
case 's':
summary_name = optarg;
has_summary = 1;
break;
case 'd':
detail_name = optarg;
has_detail = 1;
break;
case 'p':
plot_name = optarg;
has_plot = 1;
break;
case 'r':
raw_name = optarg;
has_raw = 1;
break;
case 'g':
gps_name = optarg;
has_gps = 1;
break;
case 'k':
kml_name = optarg;
has_kml = 1;
break;
case 'a':
has_summary = has_detail = has_plot = has_raw = has_gps = has_kml = 1;
break;
default:
usage(argv[0]);
break;
}
}
if (!has_summary)
summary_file = stdout;
for (i = optind; i < argc; i++) {
file = fopen(argv[i], "r");
if (!file) {
perror(argv[i]);
ret++;
continue;
}
if (has_summary && !summary_file)
summary_file = open_output(summary_name, argv[i], ".summary");
if (has_detail && !detail_file)
detail_file = open_output(detail_name, argv[i], ".detail");
if (has_plot) {
if (plot_name)
this_plot_name = plot_name;
else
this_plot_name = replace_extension(argv[i], ".plot");
}
if (has_raw && !raw_file)
raw_file = open_output(raw_name, argv[i], ".raw");
if (has_gps && !gps_file)
gps_file = open_output(gps_name, argv[i], ".gps");
if (has_kml && !kml_file)
kml_file = open_output(kml_name, argv[i], ".kml");
s = strstr(argv[i], "-serial-");
if (s)
serial = atoi(s + 8);
else
serial = 0;
raw = cc_log_read(file);
if (!raw) {
perror(argv[i]);
ret++;
continue;
}
if (!raw->serial)
raw->serial = serial;
analyse_flight(raw, summary_file, detail_file, raw_file, this_plot_name, gps_file, kml_file);
cc_flightraw_free(raw);
if (has_summary && !summary_name) {
fclose(summary_file); summary_file = NULL;
}
if (has_detail && !detail_name) {
fclose(detail_file); detail_file = NULL;
}
if (this_plot_name && this_plot_name != plot_name) {
free (this_plot_name); this_plot_name = NULL;
}
if (has_raw && !raw_name) {
fclose(raw_file); raw_file = NULL;
}
if (has_gps && !gps_name) {
fclose(gps_file); gps_file = NULL;
}
if (has_kml && !kml_name) {
fclose(kml_file); kml_file = NULL;
}
}
return ret;
}

1
ao-tools/ao-rawload/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ccload

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-rawload
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_RAWLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_rawload_DEPENDENCIES = $(AO_RAWLOAD_LIBS)
ao_rawload_LDADD=$(AO_RAWLOAD_LIBS) $(LIBUSB_LIBS)
ao_rawload_SOURCES = ao-rawload.c
man_MANS=ao-rawload.1

View File

@@ -0,0 +1,65 @@
.\"
.\" 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-RAWLOAD 1 "ao-rawload" ""
.SH NAME
ao-rawload \- flash a program to a AltOS device
.SH SYNOPSIS
.B "ao-rawload"
[\-T \fItty-device\fP]
[\--tty \fItty-device\fP]
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
\fIfile.ihx\fP
.SH DESCRIPTION
.I ao-rawload
loads the specified .ihx file, without modification, into the target
device flash or ram (depending on the base address of the .ihx file).
.SH OPTIONS
.TP
\-T tty-device | --tty tty-device
This selects which tty device the debugger uses to communicate with
the target device. The special name 'BITBANG' directs ao-dbg to use
the cp2103 connection, otherwise this should be a usb serial port
connected to a suitable cc1111 debug node.
.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
\-r | --run
After the file has been loaded, set the PC to the base address of the
image and resume execution there.
the .ihx file.
.SH USAGE
.I ao-rawload
reads the specified .ihx file into memory. It then connects to the
specified target device and writes the program to the target device
memory and, optionally, starts the program executing.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,118 @@
/*
* Copyright © 2008 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 <unistd.h>
#include <getopt.h>
#include "ccdbg.h"
#include "cc.h"
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
{ .name = "run", .has_arg = 0, .val = 'r' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>] [--run] file.ihx\n", program);
exit(1);
}
int
main (int argc, char **argv)
{
struct ccdbg *dbg;
struct ao_hex_file *hex;
struct ao_hex_image *image;
char *filename;
FILE *file;
char *tty = NULL;
char *device = NULL;
int c;
int run = 0;
while ((c = getopt_long(argc, argv, "rT:D:", options, NULL)) != -1) {
switch (c) {
case 'T':
tty = optarg;
break;
case 'D':
device = optarg;
break;
case 'r':
run = 1;
break;
default:
usage(argv[0]);
break;
}
}
filename = argv[optind];
if (filename == NULL) {
usage(argv[0]);
exit(1);
}
file = fopen(filename, "r");
if (!file) {
perror(filename);
exit(1);
}
hex = ao_hex_file_read(file, filename);
fclose(file);
if (!hex)
exit (1);
image = ao_hex_image_create(hex);
if (!image) {
fprintf(stderr, "image create failed\n");
exit (1);
}
ao_hex_file_free(hex);
if (!tty)
tty = cc_usbdevs_find_by_arg(device, "TIDongle");
dbg = ccdbg_open(tty);
if (!dbg)
exit (1);
ccdbg_add_debug(CC_DEBUG_FLASH);
ccdbg_debug_mode(dbg);
ccdbg_halt(dbg);
if (image->address == 0xf000) {
printf("Loading %d bytes to execute from RAM\n",
image->length);
ccdbg_write_hex_image(dbg, image, 0);
} else if (image->address == 0x0000) {
printf("Loading %d bytes to execute from FLASH\n",
image->length);
ccdbg_flash_hex_image(dbg, image);
} else {
printf("Cannot load code to 0x%04x\n",
image->address);
ao_hex_image_free(image);
ccdbg_close(dbg);
exit(1);
}
if (run) {
ccdbg_set_pc(dbg, image->address);
ccdbg_resume(dbg);
}
ccdbg_close(dbg);
exit (0);
}

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-send-telem
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_send_telem_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
ao_send_telem_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS)
ao_send_telem_SOURCES = ao-send-telem.c
man_MANS = ao-send-telem.1

View File

@@ -0,0 +1,64 @@
.\"
.\" 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-SEND-TELEM 1 "ao-send-telem" ""
.SH NAME
ao-send-telem \- Re-transmit stored telemetry file
.SH SYNOPSIS
.B "ao-send-telem"
[\-T \fItty-device\fP]
[\--tty \fItty-device\fP]
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
[\-F \fIfrequency (kHz)\fP]
[\--frequency \fIfrequency (kHz)\fP]
[\-R]
[\--realtime]
<flight.telem>
.SH OPTIONS
.TP
\-T tty-device | --tty tty-device
This selects which tty device ao-dumplog 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
TeleDongle:2
.br
TeleDongle
.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
\-F kHz | --frequency kHz
This selects which frequency to send the specified packets on.
.TP
\-R | --realtime
This makes the program delay between packets in pad mode. Normally,
pad mode packets are sent as quickly as possible.
.SH DESCRIPTION
.I ao-send-telem
reads the specified flight telemetry log and re-transmits it via the
specified ground station device
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,295 @@
/*
* Copyright © 2011 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.
*/
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include "cc.h"
#include "cc-usb.h"
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
{ .name = "frequency", .has_arg = 1, .val = 'F' },
{ .name = "realtime", .has_arg = 0, .val = 'R' },
{ .name = "verbose", .has_arg = 0, .val = 'v' },
{ .name = "fake", .has_arg = 0, .val = 'f' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>] [--frequency <kHz>] [--realtime] [--verbose] [--fake] file.telem ...\n", program);
exit(1);
}
#define bool(b) ((b) ? "true" : "false")
struct ao_telem_list {
struct ao_telem_list *next;
union ao_telemetry_all telem;
};
static struct ao_telem_list *telem_list, **telem_last;
static void
trim_telem(uint16_t time)
{
while (telem_list && (int16_t) (time - telem_list->telem.generic.tick) > 0) {
struct ao_telem_list *next = telem_list->next;
free(telem_list);
telem_list = next;
}
if (!telem_list)
telem_last = &telem_list;
}
static void
add_telem(union ao_telemetry_all *telem)
{
struct ao_telem_list *new = malloc (sizeof (struct ao_telem_list));
trim_telem((uint16_t) (telem->generic.tick - 20 * 100));
new->telem = *telem;
new->next = 0;
*telem_last = new;
telem_last = &new->next;
}
static enum ao_flight_state cur_state = ao_flight_invalid;
static enum ao_flight_state last_state = ao_flight_invalid;
static enum ao_flight_state
packet_state(union ao_telemetry_all *telem)
{
switch (telem->generic.type) {
case AO_TELEMETRY_SENSOR_TELEMETRUM:
case AO_TELEMETRY_SENSOR_TELEMINI:
case AO_TELEMETRY_SENSOR_TELENANO:
cur_state = telem->sensor.state;
break;
case AO_TELEMETRY_MEGA_DATA:
cur_state = telem->mega_data.state;
break;
case AO_TELEMETRY_METRUM_SENSOR:
cur_state = telem->metrum_sensor.state;
break;
case AO_TELEMETRY_MINI:
cur_state = telem->mini.state;
break;
}
return cur_state;
}
static const char *state_names[] = {
"startup",
"idle",
"pad",
"boost",
"fast",
"coast",
"drogue",
"main",
"landed",
"invalid"
};
static void
send_telem(struct cc_usb *cc, union ao_telemetry_all *telem)
{
int i;
uint8_t *b;
packet_state(telem);
if (cur_state != last_state) {
if (0 <= cur_state && cur_state < sizeof(state_names) / sizeof (state_names[0]))
printf ("%s\n", state_names[cur_state]);
last_state = cur_state;
}
cc_usb_printf(cc, "S 20\n");
b = (uint8_t *) telem;
for (i = 0; i < 0x20; i++)
cc_usb_printf(cc, "%02x", b[i]);
cc_usb_sync(cc);
}
static void
do_delay(uint16_t now, uint16_t then)
{
int16_t delay = (int16_t) (now - then);
if (delay > 0 && delay < 1000)
usleep(delay * 10 * 1000);
}
static uint16_t
send_queued(struct cc_usb *cc, int pause)
{
struct ao_telem_list *next;
uint16_t tick = 0;
int started = 0;
while (telem_list) {
if (started && pause)
do_delay(telem_list->telem.generic.tick, tick);
tick = telem_list->telem.generic.tick;
started = 1;
send_telem(cc, &telem_list->telem);
next = telem_list->next;
free(telem_list);
telem_list = next;
}
return tick;
}
int
main (int argc, char **argv)
{
struct cc_usb *cc;
char *tty = NULL;
char *device = NULL;
char line[80];
int c, i, ret = 0;
int freq = 434550;
FILE *file;
uint16_t last_tick;
int started;
int realtime = 0;
int verbose = 0;
int fake = 0;
int rate = 0;
while ((c = getopt_long(argc, argv, "vRfT:D:F:r:", options, NULL)) != -1) {
switch (c) {
case 'T':
tty = optarg;
break;
case 'D':
device = optarg;
break;
case 'F':
freq = atoi(optarg);
break;
case 'R':
realtime = 1;
break;
case 'v':
verbose++;
break;
case 'f':
fake++;
break;
case 'r':
rate = atoi(optarg);
switch (rate) {
case 38400:
rate = 0;
break;
case 9600:
rate = 1;
break;
case 2400:
rate = 2;
break;
default:
fprintf(stderr, "Rate %d isn't 38400, 9600 or 2400\n", rate);
usage(argv[0]);
break;
}
break;
default:
usage(argv[0]);
break;
}
}
if (!tty)
tty = cc_usbdevs_find_by_arg(device, "TeleDongle");
if (!tty)
tty = getenv("ALTOS_TTY");
if (!tty)
tty="/dev/ttyACM0";
cc = cc_usb_open(tty);
if (!cc)
exit (1);
cc_usb_printf(cc, "m 0\n");
cc_usb_printf(cc, "c F %d\n", freq);
cc_usb_printf(cc, "c T %d\n", rate);
if (fake) {
union ao_telemetry_all telem;
int i;
memset(&telem, '\0', sizeof (telem));
telem.generic.serial = 1;
telem.generic.type = 0;
for (i = 0; i < sizeof (telem.generic.payload); i++)
telem.generic.payload[i] = i & 7;
for (;;) {
telem.generic.tick += 50;
send_telem(cc, &telem);
do_delay(50, 0);
}
} else {
for (i = optind; i < argc; i++) {
file = fopen(argv[i], "r");
if (!file) {
perror(argv[i]);
ret++;
continue;
}
started = 0;
last_tick = 0;
while (fgets(line, sizeof (line), file)) {
union ao_telemetry_all telem;
if (cc_telemetry_parse(line, &telem)) {
/*
* Skip packets with CRC errors.
*/
if ((telem.generic.status & (1 << 7)) == 0)
continue;
if (verbose)
printf ("type %4d\n", telem.generic.type);
if (started || realtime) {
do_delay(telem.generic.tick, last_tick);
last_tick = telem.generic.tick;
send_telem(cc, &telem);
} else {
enum ao_flight_state state = packet_state(&telem);
printf ("\tstate %4d\n", state);
add_telem(&telem);
if (ao_flight_pad < state && state < ao_flight_landed) {
printf ("started\n");
started = 1;
last_tick = send_queued(cc, realtime);
}
}
}
}
fclose (file);
}
}
return ret;
}

View File

@@ -0,0 +1,18 @@
bin_PROGRAMS=ao-sky-flash
AM_CFLAGS=$(WARN_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

View File

@@ -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

View File

@@ -0,0 +1,74 @@
/*
* 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; 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 "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 = %ld 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);
}

View File

@@ -0,0 +1,112 @@
/*
* 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; 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 <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;
}

View File

@@ -0,0 +1,250 @@
/*
* 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; 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 "sky_flash.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <getopt.h>
#include <unistd.h>
#include "cc.h"
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
{ .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"
" [--firmware <binary firmware file>]\n"
" [--query]\n"
" [--quiet]\n"
" [--raw]\n", program);
exit(1);
}
static 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;
}
static 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;
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;
int ret;
int c;
char *tty = NULL;
char *device = NULL;
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 '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;
}

View File

@@ -0,0 +1,74 @@
/*
* 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; 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.
*/
/* 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 void *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_millis(void);
void
skytraq_dbg_newline(void);
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);

View File

@@ -0,0 +1,256 @@
/*
* 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; 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.
*/
#define _DEFAULT_SOURCE 1
#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 void *d, int len)
{
const char *data = d;
int r;
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;
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 = 0;
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);
}

View File

@@ -0,0 +1,61 @@
/*
* 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; 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 "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;
}

View File

@@ -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

View File

@@ -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

1
ao-tools/ao-stmload/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ao-stmload

View File

@@ -0,0 +1,16 @@
if LIBSTLINK
bin_PROGRAMS=ao-stmload
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(STLINK_CFLAGS) $(LIBUSB_CFLAGS)
AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_stmload_DEPENDENCIES = $(AO_STMLOAD_LIBS)
ao_stmload_LDADD=$(AO_STMLOAD_LIBS) $(STLINK_LIBS) $(LIBUSB_LIBS) -lelf
ao_stmload_SOURCES=ao-stmload.c ao-stmload.h
man_MANS = ao-stmload.1
endif

View File

@@ -0,0 +1,61 @@
.\"
.\" 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-LOAD 1 "ao-stmload" ""
.SH NAME
ao-stmload \- flash a program to an STM32-based AltOS device
.SH SYNOPSIS
.B "ao-stmload"
[\-D \fI/dev/sgX\fP]
[\--device \fI/dev/sgX\fP]
[\--cal \fIradio-calibration\fP]
[\--serial \fserial-number\fP]
\fIfile.elf\fP
.SH DESCRIPTION
.I ao-stmload
loads the specified .elf file into the target device flash memory,
using either existing serial number and radio calibration values or
taking either of those from the command line.
.SH OPTIONS
.TP
\-D /dev/sgX | --device /dev/sgX
This targets an STlinkV1 connection rather than STlinkV2
.TP
\-s serial-number | --serial serial-number
This programs the device serial number into the image. If no serial
number is specified, then the existing serial number, if any, will be
read from the device.
.TP
\-c radio-calibration | --cal radio-calibration This programs the
radio calibration value into the image for hardware which doesn't have
any eeprom storage for this value. If no calibration value is
specified, an existing calibration value will be used. The value here
can be computed given the current radio calibration value, the
measured frequency and the desired frequency:
.IP
cal' = cal * (desired/measured)
.IP
The default calibration value is 7119667.
.SH USAGE
.I ao-stmload
reads the specified .elf file into memory, edits the image to
customize it using the specified serial number and radio calibration
values. It then connects to the debug dongle and writes the program to
the target device flash memory.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,338 @@
/*
* 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; 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 <err.h>
#include <fcntl.h>
#include <gelf.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sysexits.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <stdbool.h>
#include "stlink-common.h"
#include "ao-elf.h"
#include "ccdbg.h"
#include "cc.h"
#include "ao-stmload.h"
#include "ao-selfload.h"
#include "ao-verbose.h"
#include "ao-editaltos.h"
/*
* Read a 16-bit value from the target device with arbitrary
* alignment
*/
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;
uint16_t result;
sl->q_len = 0;
actual_addr = addr & ~3;
stlink_read_mem32(sl, actual_addr, 8);
if (sl->q_len != 8)
abort();
off = addr & 3;
result = data[off] | (data[off + 1] << 8);
return result;
}
static uint16_t
get_uint16(stlink_t *sl, uint32_t addr)
{
uint16_t result;
result = get_uint16_sl(sl, addr);
printf ("read 0x%08x = 0x%04x\n", addr, result);
return result;
}
/*
* Read a 32-bit value from the target device with arbitrary
* alignment
*/
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;
uint32_t result;
sl->q_len = 0;
printf ("read 0x%x\n", addr);
actual_addr = addr & ~3;
stlink_read_mem32(sl, actual_addr, 8);
if (sl->q_len != 8)
abort();
off = addr & 3;
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, uint32_t addr)
{
uint32_t result;
result = get_uint32_sl(sl, addr);
printf ("read 0x%08x = 0x%08x\n", addr, result);
return result;
}
/*
* Check to see if the target device has been
* flashed with a similar firmware image before
*
* This is done by looking for the same romconfig version,
* which should be at the same location as the linker script
* places this at 0x100 from the start of the rom section
*/
static int
check_flashed(stlink_t *sl)
{
uint16_t romconfig_version = get_uint16(sl, AO_ROMCONFIG_VERSION);
uint16_t romconfig_check = get_uint16(sl, AO_ROMCONFIG_CHECK);
if (romconfig_version != (uint16_t) ~romconfig_check) {
fprintf (stderr, "Device has not been flashed before\n");
return 0;
}
return 1;
}
static const struct option options[] = {
{ .name = "v1", .has_arg = 0, .val = '1' },
{ .name = "raw", .has_arg = 0, .val = 'r' },
{ .name = "cal", .has_arg = 1, .val = 'c' },
{ .name = "serial", .has_arg = 1, .val = 's' },
{ .name = "verbose", .has_arg = 1, .val = 'v' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--v1] [--raw] [--verbose=<verbose>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
exit(1);
}
void
done(stlink_t *sl, int code)
{
stlink_reset(sl);
stlink_run(sl);
stlink_exit_debug_mode(sl);
stlink_close(sl);
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)
{
int stlink_v1 = 0;
int raw = 0;
char *filename;
Elf *e;
char *serial_end;
unsigned int serial = 0;
char *serial_ucs2;
int serial_ucs2_len;
char serial_int[2];
unsigned int s;
int i;
int string_num;
uint32_t cal = 0;
char cal_int[4];
char *cal_end;
int c;
stlink_t *sl = NULL;
int was_flashed = 0;
struct ao_hex_image *load;
int tries;
int success;
int verbose = 0;
struct ao_sym *file_symbols;
int num_file_symbols;
while ((c = getopt_long(argc, argv, "1rc:s:v:", options, NULL)) != -1) {
switch (c) {
case '1':
stlink_v1 = 1;
break;
case 'r':
raw = 1;
break;
case 'c':
cal = strtoul(optarg, &cal_end, 10);
if (cal_end == optarg || *cal_end != '\0')
usage(argv[0]);
break;
case 's':
serial = strtoul(optarg, &serial_end, 10);
if (serial_end == optarg || *serial_end != '\0')
usage(argv[0]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
break;
}
}
ao_verbose = verbose;
if (verbose > 1)
ccdbg_add_debug(CC_DEBUG_BITBANG);
filename = argv[optind];
if (filename == NULL)
usage(argv[0]);
if (ends_with (filename, ".elf")) {
load = ao_load_elf(filename, &file_symbols, &num_file_symbols);
} else if (ends_with (filename, ".ihx")) {
load = ao_hex_load(filename, &file_symbols, &num_file_symbols);
} else
usage(argv[0]);
if (!raw) {
if (!ao_editaltos_find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols)) {
fprintf(stderr, "Cannot find required symbols\n");
usage(argv[0]);
}
}
/* Connect to the programming dongle
*/
for (tries = 0; tries < 3; tries++) {
if (stlink_v1) {
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->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->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, 1);
}
/* 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 (!raw) {
/* Go fetch existing config values
* if available
*/
was_flashed = check_flashed(sl);
if (!serial) {
if (!was_flashed) {
fprintf (stderr, "Must provide serial number\n");
done(sl, 1);
}
serial = get_uint16(sl, AO_SERIAL_NUMBER);
if (!serial || serial == 0xffff) {
fprintf (stderr, "Invalid existing serial %d\n", serial);
done(sl, 1);
}
}
if (!cal && AO_RADIO_CAL && was_flashed) {
cal = get_uint32(sl, AO_RADIO_CAL);
if (!cal || cal == 0xffffffff) {
fprintf (stderr, "Invalid existing rf cal %d\n", cal);
done(sl, 1);
}
}
if (!ao_editaltos(load, serial, cal))
done(sl, 1);
}
/* And flash the resulting image to the device
*/
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, 0);
}

View File

@@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef _AO_STMLOAD_H_
#define _AO_STMLOAD_H_
#include "ao-elf.h"
#define AO_BOOT_APPLICATION_BASE 0x08001000
extern struct ao_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]);
#endif /* _AO_STMLOAD_H_ */

1
ao-tools/ao-telem/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ao-telem

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-telem
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_telem_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
ao_telem_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS)
ao_telem_SOURCES = ao-telem.c
man_MANS = ao-telem.1

View File

@@ -0,0 +1,36 @@
.\"
.\" 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-TELEM 1 "ao-telem" ""
.SH NAME
ao-telem \- Analyze a telemetry log
.SH SYNOPSIS
.B "ao-telem"
[\--crc]
{flight.telem} ...
.SH OPTIONS
.TP
\-c | --crc
This option makes ao-telem analyze records with CRC errors. By
default, these records are skipped.
.SH DESCRIPTION
.I ao-telem
reads the specified telemetry log and display the contents of each
record.
.SH AUTHOR
Keith Packard

View File

@@ -0,0 +1,255 @@
/*
* Copyright © 2011 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.
*/
#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 = "crc", .has_arg = 0, .val = 'c' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
fprintf(stderr, "usage: %s [--crc] {flight.telem} ...\n",program);
exit(1);
}
#define bool(b) ((b) ? "true" : "false")
static int ignore_crc;
static void
process(FILE *file)
{
char line[1024];
int c;
while (fgets(line, sizeof (line), file)) {
union ao_telemetry_all telem;
char call[AO_MAX_CALLSIGN+1];
char version[AO_MAX_VERSION+1];
if (cc_telemetry_parse(line, &telem)) {
int rssi = (int8_t) telem.generic.rssi / 2 - 74;
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 (!ignore_crc && (telem.generic.status & (1 << 7)) == 0) {
printf ("CRC error\n");
continue;
}
switch (telem.generic.type) {
case AO_TELEMETRY_SENSOR_TELEMETRUM:
case AO_TELEMETRY_SENSOR_TELEMINI:
case AO_TELEMETRY_SENSOR_TELENANO:
printf ("state %1d accel %5d pres %5d ",
telem.sensor.state, telem.sensor.accel, telem.sensor.pres);
printf ("accel %6.2f speed %6.2f height %5d ",
telem.sensor.acceleration / 16.0,
telem.sensor.speed / 16.0,
telem.sensor.height);
printf ("ground_pres %5d ground_accel %5d accel_plus %5d accel_minus %5d\n",
telem.sensor.ground_pres,
telem.sensor.ground_accel,
telem.sensor.accel_plus_g,
telem.sensor.accel_minus_g);
break;
case AO_TELEMETRY_CONFIGURATION:
memcpy(call, telem.configuration.callsign, AO_MAX_CALLSIGN);
memcpy(version, telem.configuration.version, AO_MAX_VERSION);
call[AO_MAX_CALLSIGN] = '\0';
version[AO_MAX_CALLSIGN] = '\0';
printf ("device %3d flight %5d config %3d.%03d delay %2d main %4d log_max %5d",
telem.configuration.device,
telem.configuration.flight,
telem.configuration.config_major,
telem.configuration.config_minor,
telem.configuration.apogee_delay,
telem.configuration.main_deploy,
telem.configuration.flight_log_max);
printf (" call %8s version %8s\n", call, version);
break;
case AO_TELEMETRY_LOCATION:
printf ("sats %d flags %s%s%s%s",
telem.location.flags & 0xf,
(telem.location.flags & (1 << 4)) ? "valid" : "invalid",
(telem.location.flags & (1 << 5)) ? ",running" : "",
(telem.location.flags & (1 << 6)) ? ",date" : "",
(telem.location.flags & (1 << 7)) ? ",course" : "");
printf (" alt %5d lat %12.7f lon %12.7f",
AO_TELEMETRY_LOCATION_ALTITUDE(&telem.location),
telem.location.latitude / 1e7,
telem.location.longitude / 1e7);
if ((telem.location.flags & (1 << 6)) != 0) {
printf (" year %2d month %2d day %2d",
telem.location.year,
telem.location.month,
telem.location.day);
printf (" hour %2d minute %2d second %2d",
telem.location.hour,
telem.location.minute,
telem.location.second);
}
printf (" pdop %3.1f hdop %3.1f vdop %3.1f mode %d",
telem.location.pdop / 5.0,
telem.location.hdop / 5.0,
telem.location.vdop / 5.0,
telem.location.mode);
if ((telem.location.flags & (1 << 7)) != 0)
printf (" ground_speed %6.2f climb_rate %6.2f course %d",
telem.location.ground_speed / 100.0,
telem.location.climb_rate / 100.0,
telem.location.course * 2);
printf ("\n");
break;
case AO_TELEMETRY_SATELLITE:
printf ("sats %d", telem.satellite.channels);
for (c = 0; c < 12 && c < telem.satellite.channels; c++) {
printf (" sat %d svid %d c_n_1 %d",
c,
telem.satellite.sats[c].svid,
telem.satellite.sats[c].c_n_1);
}
printf ("\n");
break;
case AO_TELEMETRY_MEGA_SENSOR_MPU:
case AO_TELEMETRY_MEGA_SENSOR_BMX160:
printf ("orient %3d accel %5d pres %9d temp %5d accel_x %5d accel_y %5d accel_z %5d gyro_x %5d gyro_y %5d gyro_z %5d mag_x %5d mag_y %5d mag_z %5d\n",
telem.mega_sensor.orient,
telem.mega_sensor.accel,
telem.mega_sensor.pres,
telem.mega_sensor.temp,
telem.mega_sensor.accel_x,
telem.mega_sensor.accel_y,
telem.mega_sensor.accel_z,
telem.mega_sensor.gyro_x,
telem.mega_sensor.gyro_y,
telem.mega_sensor.gyro_z,
telem.mega_sensor.mag_x,
telem.mega_sensor.mag_y,
telem.mega_sensor.mag_z);
break;
case AO_TELEMETRY_COMPANION:
printf("board_id %3d update_period %3d channels %2d",
telem.companion.board_id,
telem.companion.update_period,
telem.companion.channels);
for (c = 0; c < telem.companion.channels; c++)
printf(" %6d", telem.companion.companion_data[c]);
printf("\n");
break;
case AO_TELEMETRY_MEGA_DATA:
printf ("state %1d v_batt %5d v_pyro %5d ",
telem.mega_data.state,
telem.mega_data.v_batt,
telem.mega_data.v_pyro);
for (c = 0; c < 6; c++)
printf ("s%1d %5d ", c,
telem.mega_data.sense[c] |
(telem.mega_data.sense[c] << 8));
printf ("ground_pres %5d ground_accel %5d accel_plus %5d accel_minus %5d ",
telem.mega_data.ground_pres,
telem.mega_data.ground_accel,
telem.mega_data.accel_plus_g,
telem.mega_data.accel_minus_g);
printf ("accel %6.2f speed %6.2f height %5d\n",
telem.mega_data.acceleration / 16.0,
telem.mega_data.speed / 16.0,
telem.mega_data.height);
break;
case AO_TELEMETRY_METRUM_SENSOR:
printf ("state %1d accel %5d pres %9d temp %6.2f acceleration %6.2f speed %6.2f height %5d v_batt %5d sense_a %5d sense_m %5d\n",
telem.metrum_sensor.state,
telem.metrum_sensor.accel,
telem.metrum_sensor.pres,
telem.metrum_sensor.temp / 100.0,
telem.metrum_sensor.acceleration / 16.0,
telem.metrum_sensor.speed / 16.0,
telem.metrum_sensor.height,
telem.metrum_sensor.v_batt,
telem.metrum_sensor.sense_a,
telem.metrum_sensor.sense_m);
break;
case AO_TELEMETRY_METRUM_DATA:
printf ("ground_pres %9d ground_accel %5d accel_plus %5d accel_minus %5d\n",
telem.metrum_data.ground_pres,
telem.metrum_data.ground_accel,
telem.metrum_data.accel_plus_g,
telem.metrum_data.accel_minus_g);
break;
case AO_TELEMETRY_MINI:
printf ("state %1d v_batt %5d sense_a %5d sense_m %5d pres %9d temp %6.2f acceleration %6.2f speed %6.2f height %5d ground_pres %9d\n",
telem.mini.state,
telem.mini.v_batt,
telem.mini.sense_a,
telem.mini.sense_m,
telem.mini.pres,
telem.mini.temp / 100.0,
telem.mini.acceleration / 16.0,
telem.mini.speed / 16.0,
telem.mini.height,
telem.mini.ground_pres);
break;
default:
printf("\n");
}
}
}
}
int
main (int argc, char **argv)
{
int c, i, ret = 0;
FILE *file;
while ((c = getopt_long(argc, argv, "c", options, NULL)) != -1) {
switch (c) {
case 'c':
ignore_crc = 1;
break;
default:
usage(argv[0]);
break;
}
}
if (optind < argc) {
for (i = optind; i < argc; i++) {
file = fopen(argv[i], "r");
if (!file) {
perror(argv[i]);
ret++;
continue;
}
process(file);
fclose (file);
}
} else
process(stdin);
return ret;
}

1
ao-tools/ao-test-baro/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ao-test-baro

Some files were not shown because too many files have changed in this diff Show More