Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
authorBdale Garbee <bdale@gag.com>
Sun, 6 Sep 2009 16:39:23 +0000 (10:39 -0600)
committerBdale Garbee <bdale@gag.com>
Sun, 6 Sep 2009 16:39:23 +0000 (10:39 -0600)
28 files changed:
.gitignore
ao-tools/Makefile.am
ao-tools/ao-dbg/ao-dbg-main.c
ao-tools/ao-dbg/ao-dbg-parse.c
ao-tools/ao-dbg/ao-dbg.1
ao-tools/ao-dbg/ao-dbg.h
ao-tools/ao-dumplog/Makefile.am [new file with mode: 0644]
ao-tools/ao-dumplog/ao-dumplog.1 [new file with mode: 0644]
ao-tools/ao-dumplog/ao-dumplog.c [new file with mode: 0644]
ao-tools/ao-eeprom/ao-eeprom.1
ao-tools/ao-load/ao-load.1
ao-tools/ao-load/ao-load.c
ao-tools/ao-postflight/Makefile.am [new file with mode: 0644]
ao-tools/ao-postflight/ao-postflight.1 [new file with mode: 0644]
ao-tools/ao-postflight/ao-postflight.c [new file with mode: 0644]
ao-tools/ao-rawload/ao-rawload.1
ao-tools/ao-rawload/ao-rawload.c
ao-tools/lib/Makefile.am
ao-tools/lib/cc-analyse.c [new file with mode: 0644]
ao-tools/lib/cc-convert.c [new file with mode: 0644]
ao-tools/lib/cc-log.c [new file with mode: 0644]
ao-tools/lib/cc-logfile.c [new file with mode: 0644]
ao-tools/lib/cc-telem.c [new file with mode: 0644]
ao-tools/lib/cc-usb.c
ao-tools/lib/cc-usb.h
ao-tools/lib/cc-util.c
ao-tools/lib/cc.h
configure.ac

index b3d2d5627233bebf65cafa6fecde3c2341de37b9..0ca4bed47f8dd406942e314167f798b8bb30d0b1 100644 (file)
@@ -22,9 +22,13 @@ ao-teleterra.h
 ao-tidongle.h
 ao-tools/ao-bitbang/ao-bitbang
 ao-tools/ao-dbg/ao-dbg
+ao-tools/ao-dumplog/ao-dumplog
 ao-tools/ao-eeprom/ao-eeprom
+ao-tools/ao-list/ao-list
 ao-tools/ao-load/ao-load
+ao-tools/ao-postflight/ao-postflight
 ao-tools/ao-rawload/ao-rawload
+ao-tools/ao-view/ao-view
 ao-view/Makefile
 ao-view/ao-view
 autom4te.cache
index 28e77b08ab7943214f5c0e6a1de36ea8a41ad86b..2850e909003cbe82e1171c8ff7be8f797a185306 100644 (file)
@@ -1 +1 @@
-SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load ao-view
+SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view
index f1e2c11199122a5ca4b1ca5b19a5c59fb7f839b7..21b83a3dbc2b6c01327f05fe1e72ae59111b400a 100644 (file)
@@ -34,6 +34,7 @@ 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;
@@ -52,6 +53,7 @@ void s51_sigint()
 
 static const struct option options[] = {
        { .name = "tty", .has_arg = 1, .val = 'T' },
+       { .name = "device", .has_arg = 1, .val = 'D' },
        { 0, 0, 0, 0 },
 };
 
@@ -114,6 +116,9 @@ main(int argc, char **argv)
                case 'T':
                        s51_tty = optarg;
                        break;
+               case 'D':
+                       s51_device = optarg;
+                       break;
                }
        }
        if (s51_port) {
index 825d0e9c74972d72bf809ed69c0d42e0624af89f..dcb9099df8cbe8d1742a2f877b9584bc5fa9c3a8 100644 (file)
@@ -195,6 +195,11 @@ command_read (void)
        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, "TIDongle");
+       }
        s51_dbg = ccdbg_open (s51_tty);
        if (!s51_dbg)
                exit(1);
index a850c45407ed76b7e845c92ac2ea109bc1cee84f..00d3ac86318e24c83c21fc76e0a5c691cfab9dc6 100644 (file)
@@ -35,6 +35,9 @@ ao-dbg \- hex debugger for cc1111 processors
 [\-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
@@ -80,11 +83,26 @@ 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.
-.IP "\-T"
+.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 nework connection to
index c1789d10e30cfb930f380c7089763b05b51fecce..edc650a506c8d99c2c2a20de7ba43443a0726b3e 100644 (file)
  */
 
 #include <ccdbg.h>
+#include <cc.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,
diff --git a/ao-tools/ao-dumplog/Makefile.am b/ao-tools/ao-dumplog/Makefile.am
new file mode 100644 (file)
index 0000000..a80cac3
--- /dev/null
@@ -0,0 +1,12 @@
+bin_PROGRAMS=ao-dumplog
+
+AM_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
diff --git a/ao-tools/ao-dumplog/ao-dumplog.1 b/ao-tools/ao-dumplog/ao-dumplog.1
new file mode 100644 (file)
index 0000000..8c2df7c
--- /dev/null
@@ -0,0 +1,68 @@
+.\"
+.\" 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]
+.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.
+.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
diff --git a/ao-tools/ao-dumplog/ao-dumplog.c b/ao-tools/ao-dumplog/ao-dumplog.c
new file mode 100644 (file)
index 0000000..b930f0e
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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-usb.h"
+#include "cc.h"
+
+#define NUM_BLOCK      512
+
+static const struct option options[] = {
+       { .name = "tty", .has_arg = 1, .val = 'T' },
+       { .name = "device", .has_arg = 1, .val = 'D' },
+       { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+       fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>\n", program);
+       exit(1);
+}
+
+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;
+       char            cmd;
+       int             tick, a, b;
+
+       while ((c = getopt_long(argc, argv, "T:D:", options, NULL)) != -1) {
+               switch (c) {
+               case 'T':
+                       tty = optarg;
+                       break;
+               case 'D':
+                       device = optarg;
+                       break;
+               default:
+                       usage(argv[0]);
+                       break;
+               }
+       }
+       if (!tty)
+               tty = cc_usbdevs_find_by_arg(device, "TeleMetrum");
+       if (!tty)
+               tty = getenv("ALTOS_TTY");
+       if (!tty)
+               tty="/dev/ttyACM0";
+       cc = cc_usb_open(tty);
+       if (!cc)
+               exit(1);
+       /* send a 'version' command followed by a 'log' command */
+       cc_usb_printf(cc, "v\nl\n");
+       out = NULL;
+       for (;;) {
+               cc_usb_getline(cc, line, sizeof (line));
+               if (!strcmp (line, "end"))
+                       break;
+               if (sscanf(line, "serial-number %u", &serial_number) == 1) {
+                       filename = cc_make_filename(serial_number, "eeprom");
+                       out = fopen (filename, "w");
+                       if (!out) {
+                               perror(filename);
+                       }
+                       fprintf (out, "%s\n", line);
+               } else if (sscanf(line, "%c %x %x %x", &cmd, &tick, &a, &b) == 4) {
+                       if (out) {
+                               fprintf(out, "%s\n", line);
+                               if (cmd == 'S' && a == 8) {
+                                       fclose(out);
+                                       out = NULL;
+                               }
+                       }
+               }
+       }
+       if (out)
+               fclose (out);
+       cc_usb_close(cc);
+       exit (0);
+}
index 8caff9d1a1510efd51edc1fb24d8b48cf45dd3c2..ed498147fed27a007dadf0f23842539449db85e3 100644 (file)
 ao-eeprom \- Fetch eeprom contents from TeleMetrum device
 .SH SYNOPSIS
 .B "ao-eeprom"
-[\-tty \fItty-device\fP]
+[\-T \fItty-device\fP]
+[\--tty \fItty-device\fP]
+[\-D \fIaltos-device\fP]
+[\--device \fIaltos-device\fP]
+.SH OPTIONS
+.TP
+\-T tty-device | --tty tty-device
+This selects which tty device 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 DESCRIPTION
 .I ao-eeprom
 downloads the eeprom contents from a connected TeleMetrum device.
index 10484f3bc4eb47d6d30aa1c455e3e35a445590e5..eb2bc0d8bdd5d3748d0596cc831520a182b88daa 100644 (file)
 ao-load \- flash a program to a AltOS device
 .SH SYNOPSIS
 .B "ao-load"
-[\-tty \fItty-device\fP]
+[\-T \fItty-device\fP]
+[\--tty \fItty-device\fP]
+[\-D \fIaltos-device\fP]
+[\--device \fIaltos-device\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.
 .SH USAGE
 .I ao-load
 reads the specified .ihx file into memory, locates the matching .map
index c27fcbe9c4d191bcb3005f9e7d2964e2eaba3c00..f5466612c20b9a12b4def5c374008ad543b81a36 100644 (file)
@@ -22,6 +22,7 @@
 #include <unistd.h>
 #include <getopt.h>
 #include "ccdbg.h"
+#include "cc.h"
 
 #define AO_USB_DESC_STRING             3
 
@@ -91,12 +92,13 @@ rewrite(struct hex_image *image, unsigned addr, char *data, int len)
 
 static const struct option options[] = {
        { .name = "tty", .has_arg = 1, .val = 'T' },
+       { .name = "device", .has_arg = 1, .val = 'D' },
        { 0, 0, 0, 0},
 };
 
 static void usage(char *program)
 {
-       fprintf(stderr, "usage: %s [--tty <tty-name>] file.ihx serial-number\n", program);
+       fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>] file.ihx serial-number\n", program);
        exit(1);
 }
 
@@ -122,13 +124,17 @@ main (int argc, char **argv)
        unsigned        usb_descriptors;
        int             string_num;
        char            *tty = NULL;
+       char            *device = NULL;
        int             c;
 
-       while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "T:D:", options, NULL)) != -1) {
                switch (c) {
                case 'T':
                        tty = optarg;
                        break;
+               case 'D':
+                       device = optarg;
+                       break;
                default:
                        usage(argv[0]);
                        break;
@@ -219,6 +225,8 @@ main (int argc, char **argv)
        if (!rewrite(image, usb_descriptors + 2 + image->address, serial_ucs2, serial_ucs2_len))
                usage(argv[0]);
 
+       if (!tty)
+               tty = cc_usbdevs_find_by_arg(device, "TIDongle");
        dbg = ccdbg_open(tty);
        if (!dbg)
                exit (1);
diff --git a/ao-tools/ao-postflight/Makefile.am b/ao-tools/ao-postflight/Makefile.am
new file mode 100644 (file)
index 0000000..301ac45
--- /dev/null
@@ -0,0 +1,12 @@
+bin_PROGRAMS=ao-postflight
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_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)
+
+ao_postflight_SOURCES = ao-postflight.c
+
+man_MANS = ao-postflight.1
diff --git a/ao-tools/ao-postflight/ao-postflight.1 b/ao-tools/ao-postflight/ao-postflight.1
new file mode 100644 (file)
index 0000000..fe02587
--- /dev/null
@@ -0,0 +1,29 @@
+.\"
+.\" 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"
+{flight.eeprom|flight.telem}
+.SH DESCRIPTION
+.I ao-postflight
+reads the specified flight log and produces a summary of the flight on stdout.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c
new file mode 100644 (file)
index 0000000..9371f35
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * 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"
+
+#define NUM_BLOCK      512
+
+static const struct option options[] = {
+       { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+       fprintf(stderr, "usage: %s {flight-log} ...\n", program);
+       exit(1);
+}
+
+static const char *state_names[] = {
+       "startup",
+       "idle",
+       "pad",
+       "boost",
+       "fast",
+       "coast",
+       "drogue",
+       "main",
+       "landed",
+       "invalid"
+};
+
+void
+analyse_flight(struct cc_flightraw *f)
+{
+       double  height;
+       double  accel;
+       double  boost_start, boost_stop;
+       double  min_pres;
+       int     i;
+       int     pres_i, accel_i;
+       int     boost_start_set = 0;
+       int     boost_stop_set = 0;
+       enum ao_flight_state    state;
+       double  state_start, state_stop;
+
+       printf ("Flight:  %9d\nSerial:  %9d\n",
+               f->flight, f->serial);
+       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)
+       {
+               min_pres = f->pres.data[pres_i].value;
+               height = cc_barometer_to_altitude(min_pres) -
+                       cc_barometer_to_altitude(f->ground_pres);
+               printf ("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);
+       }
+
+       accel_i = cc_timedata_min(&f->accel, boost_start, boost_stop);
+       if (accel_i)
+       {
+               accel = cc_accelerometer_to_acceleration(f->accel.data[accel_i].value,
+                                                        f->ground_accel);
+               printf ("Max accel:  %9.2fm/s² %9.2fg  %9.2fs\n",
+                       accel, accel /  9.80665,
+                       (f->accel.data[accel_i].time - boost_start) / 100.0);
+       }
+       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;
+               printf("State: %s\n", state_names[state]);
+               printf("\tStart:      %9.2fs\n", (state_start - boost_start) / 100.0);
+               printf("\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);
+                       printf("\tMax accel:  %9.2fm/s² %9.2fg  %9.2fs\n",
+                              accel, accel / 9.80665,
+                              (f->accel.data[accel_i].time - boost_start) / 100.0);
+               }
+
+               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);
+                       printf ("\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);
+               }
+       }
+}
+
+int
+main (int argc, char **argv)
+{
+       FILE                    *file;
+       int                     i;
+       int                     ret = 0;
+       struct cc_flightraw     *raw;
+       int                     c;
+       int                     serial;
+       char                    *s;
+
+       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;
+               raw = cc_log_read(file);
+               if (!raw) {
+                       perror(argv[i]);
+                       ret++;
+                       continue;
+               }
+               if (!raw->serial)
+                       raw->serial = serial;
+               analyse_flight(raw);
+               cc_flightraw_free(raw);
+       }
+       return ret;
+}
index e79645f19a982653f633067474c412fadcad6ae5..6b6a6e2c7097bd9faac5e8e36ae0056a993eabfa 100644 (file)
 ao-rawload \- flash a program to a AltOS device
 .SH SYNOPSIS
 .B "ao-rawload"
-[\-tty \fItty-device\fP]
+[\-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 memory.
+.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.
 .SH USAGE
 .I ao-rawload
 reads the specified .ihx file into memory. It then connects to the
index 1f1537b9f12d59eb49f6de87c7e96ed39e7e1e1f..255f63eca2f7c99563cbd629c0bd14b969e63e1e 100644 (file)
 
 static const struct option options[] = {
        { .name = "tty", .has_arg = 1, .val = 'T' },
+       { .name = "device", .has_arg = 1, .val = 'D' },
        { 0, 0, 0, 0},
 };
 
 static void usage(char *program)
 {
-       fprintf(stderr, "usage: %s [--tty <tty-name>] file.ihx\n", program);
+       fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>] file.ihx\n", program);
        exit(1);
 }
 
@@ -42,13 +43,17 @@ main (int argc, char **argv)
        char            *filename;
        FILE            *file;
        char            *tty = NULL;
+       char            *device = NULL;
        int             c;
 
-       while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "T:D:", options, NULL)) != -1) {
                switch (c) {
                case 'T':
                        tty = optarg;
                        break;
+               case 'D':
+                       device = optarg;
+                       break;
                default:
                        usage(argv[0]);
                        break;
@@ -75,6 +80,8 @@ main (int argc, char **argv)
        }
 
        ccdbg_hex_file_free(hex);
+       if (!tty)
+               tty = cc_usbdevs_find_by_arg(device, "TIDongle");
        dbg = ccdbg_open(tty);
        if (!dbg)
                exit (1);
index f66ee0a99634a0e663393b549c3e618895f53944..e682f757d68d8aa85c1e22d948c99c1443704849 100644 (file)
@@ -1,6 +1,6 @@
 noinst_LIBRARIES = libao-tools.a
 
-AM_CFLAGS=$(WARN_CFLAGS) $(LIBUSB_CFLAGS)
+AM_CFLAGS=$(WARN_CFLAGS) $(LIBUSB_CFLAGS) $(GNOME_CFLAGS)
 
 libao_tools_a_SOURCES = \
        ccdbg-command.c \
@@ -14,6 +14,9 @@ libao_tools_a_SOURCES = \
        ccdbg-memory.c \
        ccdbg-rom.c \
        ccdbg-state.c \
+       cc-analyse.c \
+       cc-convert.c \
+       cc-log.c \
        cc-usb.c \
        cc-usb.h \
        cc.h \
@@ -21,5 +24,7 @@ libao_tools_a_SOURCES = \
        cc-util.c \
        cc-bitbang.c \
        cc-bitbang.h \
+       cc-logfile.c \
+       cc-telem.c \
        cp-usb-async.c \
        cp-usb-async.h
diff --git a/ao-tools/lib/cc-analyse.c b/ao-tools/lib/cc-analyse.c
new file mode 100644 (file)
index 0000000..fc8a841
--- /dev/null
@@ -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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "cc.h"
+
+int
+cc_timedata_min(struct cc_timedata *d, double min_time, double max_time)
+{
+       int     i;
+       int     set = 0;
+       int     min_i = -1;
+       double  min;
+
+       if (d->num == 0)
+               return -1;
+       for (i = 0; i < d->num; i++)
+               if (min_time <= d->data[i].time && d->data[i].time <= max_time)
+                       if (!set || d->data[i].value < min) {
+                               min_i = i;
+                               min = d->data[i].value;
+                               set = 1;
+                       }
+       return min_i;
+}
+
+int
+cc_timedata_max(struct cc_timedata *d, double min_time, double max_time)
+{
+       int     i;
+       double  max;
+       int     max_i = -1;
+       int     set = 0;
+
+       if (d->num == 0)
+               return -1;
+       for (i = 0; i < d->num; i++)
+               if (min_time <= d->data[i].time && d->data[i].time <= max_time)
+                       if (!set || d->data[i].value > max) {
+                               max_i = i;
+                               max = d->data[i].value;
+                               set = 1;
+                       }
+       return max_i;
+}
diff --git a/ao-tools/lib/cc-convert.c b/ao-tools/lib/cc-convert.c
new file mode 100644 (file)
index 0000000..ac6962b
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "cc.h"
+#include <math.h>
+
+/*
+ * Pressure Sensor Model, version 1.1
+ *
+ * written by Holly Grimes
+ *
+ * Uses the International Standard Atmosphere as described in
+ *   "A Quick Derivation relating altitude to air pressure" (version 1.03)
+ *    from the Portland State Aerospace Society, except that the atmosphere
+ *    is divided into layers with each layer having a different lapse rate.
+ *
+ * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007
+ *    at site <http://en.wikipedia.org/wiki/International_Standard_Atmosphere
+ *
+ * Height measurements use the local tangent plane.  The postive z-direction is up.
+ *
+ * All measurements are given in SI units (Kelvin, Pascal, meter, meters/second^2).
+ *   The lapse rate is given in Kelvin/meter, the gas constant for air is given
+ *   in Joules/(kilogram-Kelvin).
+ */
+
+#define GRAVITATIONAL_ACCELERATION -9.80665
+#define AIR_GAS_CONSTANT       287.053
+#define NUMBER_OF_LAYERS       7
+#define MAXIMUM_ALTITUDE       84852.0
+#define MINIMUM_PRESSURE       0.3734
+#define LAYER0_BASE_TEMPERATURE        288.15
+#define LAYER0_BASE_PRESSURE   101325
+
+/* lapse rate and base altitude for each layer in the atmosphere */
+static const double lapse_rate[NUMBER_OF_LAYERS] = {
+       -0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002
+};
+
+static const int base_altitude[NUMBER_OF_LAYERS] = {
+       0, 11000, 20000, 32000, 47000, 51000, 71000
+};
+
+/* outputs atmospheric pressure associated with the given altitude. altitudes
+   are measured with respect to the mean sea level */
+double
+cc_altitude_to_pressure(double altitude)
+{
+
+   double base_temperature = LAYER0_BASE_TEMPERATURE;
+   double base_pressure = LAYER0_BASE_PRESSURE;
+
+   double pressure;
+   double base; /* base for function to determine pressure */
+   double exponent; /* exponent for function to determine pressure */
+   int layer_number; /* identifies layer in the atmosphere */
+   int delta_z; /* difference between two altitudes */
+
+   if (altitude > MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */
+      return 0;
+
+   /* calculate the base temperature and pressure for the atmospheric layer
+      associated with the inputted altitude */
+   for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
+      delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
+      if (lapse_rate[layer_number] == 0.0) {
+         exponent = GRAVITATIONAL_ACCELERATION * delta_z
+              / AIR_GAS_CONSTANT / base_temperature;
+         base_pressure *= exp(exponent);
+      }
+      else {
+         base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+         exponent = GRAVITATIONAL_ACCELERATION /
+              (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+         base_pressure *= pow(base, exponent);
+      }
+      base_temperature += delta_z * lapse_rate[layer_number];
+   }
+
+   /* calculate the pressure at the inputted altitude */
+   delta_z = altitude - base_altitude[layer_number];
+   if (lapse_rate[layer_number] == 0.0) {
+      exponent = GRAVITATIONAL_ACCELERATION * delta_z
+           / AIR_GAS_CONSTANT / base_temperature;
+      pressure = base_pressure * exp(exponent);
+   }
+   else {
+      base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+      exponent = GRAVITATIONAL_ACCELERATION /
+           (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+      pressure = base_pressure * pow(base, exponent);
+   }
+
+   return pressure;
+}
+
+
+/* outputs the altitude associated with the given pressure. the altitude
+   returned is measured with respect to the mean sea level */
+double
+cc_pressure_to_altitude(double pressure)
+{
+
+   double next_base_temperature = LAYER0_BASE_TEMPERATURE;
+   double next_base_pressure = LAYER0_BASE_PRESSURE;
+
+   double altitude;
+   double base_pressure;
+   double base_temperature;
+   double base; /* base for function to determine base pressure of next layer */
+   double exponent; /* exponent for function to determine base pressure
+                             of next layer */
+   double coefficient;
+   int layer_number; /* identifies layer in the atmosphere */
+   int delta_z; /* difference between two altitudes */
+
+   if (pressure < 0)  /* illegal pressure */
+      return -1;
+   if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */
+      return MAXIMUM_ALTITUDE;
+
+   /* calculate the base temperature and pressure for the atmospheric layer
+      associated with the inputted pressure. */
+   layer_number = -1;
+   do {
+      layer_number++;
+      base_pressure = next_base_pressure;
+      base_temperature = next_base_temperature;
+      delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
+      if (lapse_rate[layer_number] == 0.0) {
+         exponent = GRAVITATIONAL_ACCELERATION * delta_z
+              / AIR_GAS_CONSTANT / base_temperature;
+         next_base_pressure *= exp(exponent);
+      }
+      else {
+         base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+         exponent = GRAVITATIONAL_ACCELERATION /
+              (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+         next_base_pressure *= pow(base, exponent);
+      }
+      next_base_temperature += delta_z * lapse_rate[layer_number];
+   }
+   while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure);
+
+   /* calculate the altitude associated with the inputted pressure */
+   if (lapse_rate[layer_number] == 0.0) {
+      coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION)
+                                                    * base_temperature;
+      altitude = base_altitude[layer_number]
+                    + coefficient * log(pressure / base_pressure);
+   }
+   else {
+      base = pressure / base_pressure;
+      exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number]
+                                       / GRAVITATIONAL_ACCELERATION;
+      coefficient = base_temperature / lapse_rate[layer_number];
+      altitude = base_altitude[layer_number]
+                      + coefficient * (pow(base, exponent) - 1);
+   }
+
+   return altitude;
+}
+
+/*
+ * Values for our MP3H6115A pressure sensor
+ *
+ * From the data sheet:
+ *
+ * Pressure range: 15-115 kPa
+ * Voltage at 115kPa: 2.82
+ * Output scale: 27mV/kPa
+ *
+ *
+ * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa
+ * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
+ */
+
+static const double counts_per_kPa = 27 * 2047 / 3300;
+static const double counts_at_101_3kPa = 1674.0;
+
+double
+cc_barometer_to_pressure(double count)
+{
+       return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0;
+}
+
+double
+cc_barometer_to_altitude(double baro)
+{
+       double Pa = cc_barometer_to_pressure(baro);
+       return cc_pressure_to_altitude(Pa);
+}
+
+static const double count_per_mss = 27.0;
+
+double
+cc_accelerometer_to_acceleration(double accel, double ground_accel)
+{
+       return (ground_accel - accel) / count_per_mss;
+}
+
+double
+cc_thermometer_to_temperature(double thermo)
+{
+       return ((thermo / 32767 * 3.3) - 0.5) / 0.01;
+}
+
+double
+cc_battery_to_voltage(double battery)
+{
+       return battery / 32767.0 * 5.0;
+}
+
+double
+cc_ignitor_to_voltage(double ignite)
+{
+       return ignite / 32767 * 15.0;
+}
+
+static inline double sqr(double a) { return a * a; }
+
+void
+cc_great_circle (double start_lat, double start_lon,
+                double end_lat, double end_lon,
+                double *dist, double *bearing)
+{
+       const double rad = M_PI / 180;
+       const double earth_radius = 6371.2 * 1000;      /* in meters */
+       double lat1 = rad * start_lat;
+       double lon1 = rad * -start_lon;
+       double lat2 = rad * end_lat;
+       double lon2 = rad * -end_lon;
+
+//     double d_lat = lat2 - lat1;
+       double d_lon = lon2 - lon1;
+
+       /* From http://en.wikipedia.org/wiki/Great-circle_distance */
+       double vdn = sqrt(sqr(cos(lat2) * sin(d_lon)) +
+                         sqr(cos(lat1) * sin(lat2) -
+                             sin(lat1) * cos(lat2) * cos(d_lon)));
+       double vdd = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(d_lon);
+       double d = atan2(vdn,vdd);
+       double course;
+
+       if (cos(lat1) < 1e-20) {
+               if (lat1 > 0)
+                       course = M_PI;
+               else
+                       course = -M_PI;
+       } else {
+               if (d < 1e-10)
+                       course = 0;
+               else
+                       course = acos((sin(lat2)-sin(lat1)*cos(d)) /
+                                     (sin(d)*cos(lat1)));
+               if (sin(lon2-lon1) > 0)
+                       course = 2 * M_PI-course;
+       }
+       *dist = d * earth_radius;
+       *bearing = course * 180/M_PI;
+}
diff --git a/ao-tools/lib/cc-log.c b/ao-tools/lib/cc-log.c
new file mode 100644 (file)
index 0000000..dd8177f
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <gconf/gconf-client.h>
+#include "cc.h"
+
+static char *cc_file_dir;
+
+#define ALTOS_DIR_PATH "/apps/aoview/log_dir"
+#define DEFAULT_DIR    "AltOS"
+
+static void
+cc_file_save_conf(void)
+{
+       GConfClient     *gconf_client;
+
+       g_type_init();
+       gconf_client = gconf_client_get_default();
+       if (gconf_client)
+       {
+               gconf_client_set_string(gconf_client,
+                                       ALTOS_DIR_PATH,
+                                       cc_file_dir,
+                                       NULL);
+               g_object_unref(G_OBJECT(gconf_client));
+       }
+}
+
+static void
+cc_file_load_conf(void)
+{
+       char *file_dir;
+       GConfClient     *gconf_client;
+
+       g_type_init();
+       gconf_client = gconf_client_get_default();
+       if (gconf_client)
+       {
+               file_dir = gconf_client_get_string(gconf_client,
+                                                  ALTOS_DIR_PATH,
+                                                  NULL);
+               g_object_unref(G_OBJECT(gconf_client));
+               if (file_dir)
+                       cc_file_dir = strdup(file_dir);
+       }
+}
+
+void
+cc_set_log_dir(char *dir)
+{
+       cc_file_dir = strdup(dir);
+       cc_file_save_conf();
+}
+
+char *
+cc_get_log_dir(void)
+{
+       cc_file_load_conf();
+       if (!cc_file_dir) {
+               cc_file_dir = cc_fullname(getenv("HOME"), DEFAULT_DIR);
+               cc_file_save_conf();
+       }
+       return cc_file_dir;
+}
+
+char *
+cc_make_filename(int serial, char *ext)
+{
+       char            base[50];
+       struct tm       tm;
+       time_t          now;
+       char            *full;
+       int             r;
+       int             sequence;
+
+       now = time(NULL);
+       (void) localtime_r(&now, &tm);
+       cc_mkdir(cc_get_log_dir());
+       sequence = 0;
+       for (;;) {
+               snprintf(base, sizeof (base), "%04d-%02d-%02d-serial-%03d-flight-%03d.%s",
+                       tm.tm_year + 1900,
+                       tm.tm_mon + 1,
+                       tm.tm_mday,
+                       serial,
+                       sequence,
+                       ext);
+               full = cc_fullname(cc_get_log_dir(), base);
+               r = access(full, F_OK);
+               if (r < 0)
+                       return full;
+               free(full);
+               sequence++;
+       }
+
+}
diff --git a/ao-tools/lib/cc-logfile.c b/ao-tools/lib/cc-logfile.c
new file mode 100644 (file)
index 0000000..4abf7eb
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "cc.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int
+timedata_add(struct cc_timedata *data, double time, double value)
+{
+       struct cc_timedataelt   *newdata;
+       int                     newsize;
+       if (data->size == data->num) {
+               if (data->size == 0)
+                       newdata = malloc((newsize = 256) * sizeof (struct cc_timedataelt));
+               else
+                       newdata = realloc (data->data, (newsize = data->size * 2)
+                                          * sizeof (struct cc_timedataelt));
+               if (!newdata)
+                       return 0;
+               data->size = newsize;
+               data->data = newdata;
+       }
+       time += data->time_offset;
+       if (data->num && data->data[data->num-1].time > time) {
+               data->time_offset += 65536;
+               time += 65536;
+       }
+       data->data[data->num].time = time;
+       data->data[data->num].value = value;
+       data->num++;
+       return 1;
+}
+
+static void
+timedata_free(struct cc_timedata *data)
+{
+       if (data->data)
+               free(data->data);
+}
+
+static int
+gpsdata_add(struct cc_gpsdata *data, struct cc_gpselt *elt)
+{
+       struct cc_gpselt        *newdata;
+       int                     newsize;
+       if (data->size == data->num) {
+               if (data->size == 0)
+                       newdata = malloc((newsize = 256) * sizeof (struct cc_gpselt));
+               else
+                       newdata = realloc (data->data, (newsize = data->size * 2)
+                                          * sizeof (struct cc_gpselt));
+               if (!newdata)
+                       return 0;
+               data->size = newsize;
+               data->data = newdata;
+       }
+       elt->time += data->time_offset;
+       if (data->num && data->data[data->num-1].time > elt->time) {
+               data->time_offset += 65536;
+               elt->time += 65536;
+       }
+       data->data[data->num] = *elt;
+       data->num++;
+       return 1;
+}
+
+static void
+gpsdata_free(struct cc_gpsdata *data)
+{
+       if (data->data)
+               free(data->data);
+}
+
+#define AO_LOG_FLIGHT          'F'
+#define AO_LOG_SENSOR          'A'
+#define AO_LOG_TEMP_VOLT       'T'
+#define AO_LOG_DEPLOY          'D'
+#define AO_LOG_STATE           'S'
+#define AO_LOG_GPS_TIME                'G'
+#define AO_LOG_GPS_LAT         'N'
+#define AO_LOG_GPS_LON         'W'
+#define AO_LOG_GPS_ALT         'H'
+#define AO_LOG_GPS_SAT         'V'
+
+#define AO_LOG_POS_NONE                (~0UL)
+
+static int
+read_eeprom(const char *line, struct cc_flightraw *f, double *ground_pres, int *ground_pres_count)
+{
+       char    type;
+       int     tick;
+       int     a, b;
+       struct cc_gpselt        gps;
+       int     serial;
+
+       if (sscanf(line, "serial-number %u", &serial) == 1) {
+               f->serial = serial;
+               return 1;
+       }
+       if (sscanf(line, "%c %x %x %x", &type, &tick, &a, &b) != 4)
+               return 0;
+       switch (type) {
+       case AO_LOG_FLIGHT:
+               f->ground_accel = a;
+               f->ground_pres = 0;
+               f->flight = b;
+               *ground_pres = 0;
+               *ground_pres_count = 0;
+               break;
+       case AO_LOG_SENSOR:
+               timedata_add(&f->accel, tick, a);
+               timedata_add(&f->pres, tick, b);
+               if (*ground_pres_count < 20) {
+                       *ground_pres += b;
+                       (*ground_pres_count)++;
+                       if (*ground_pres_count >= 20)
+                               f->ground_pres = *ground_pres / *ground_pres_count;
+               }
+               break;
+       case AO_LOG_TEMP_VOLT:
+               timedata_add(&f->temp, tick, a);
+               timedata_add(&f->volt, tick, b);
+               break;
+       case AO_LOG_DEPLOY:
+               timedata_add(&f->drogue, tick, a);
+               timedata_add(&f->main, tick, b);
+               break;
+       case AO_LOG_STATE:
+               timedata_add(&f->state, tick, a);
+               break;
+       case AO_LOG_GPS_TIME:
+               gps.time = tick;
+               break;
+       case AO_LOG_GPS_LAT:
+               gps.lat = ((int32_t) (a + (b << 16))) / 10000000.0;
+               break;
+       case AO_LOG_GPS_LON:
+               gps.lon = ((int32_t) (a + (b << 16))) / 10000000.0;
+               break;
+       case AO_LOG_GPS_ALT:
+               gps.alt = ((int32_t) (a + (b << 16)));
+               gpsdata_add(&f->gps, &gps);
+               break;
+       case AO_LOG_GPS_SAT:
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static const char *state_names[] = {
+       "startup",
+       "idle",
+       "pad",
+       "boost",
+       "fast",
+       "coast",
+       "drogue",
+       "main",
+       "landed",
+       "invalid"
+};
+
+static enum ao_flight_state
+state_name_to_state(char *state_name)
+{
+       enum ao_flight_state    state;
+       for (state = ao_flight_startup; state < ao_flight_invalid; state++)
+               if (!strcmp(state_names[state], state_name))
+                       return state;
+       return ao_flight_invalid;
+}
+
+static int
+read_telem(const char *line, struct cc_flightraw *f)
+{
+       struct cc_telem         telem;
+       struct cc_gpselt        gps;
+       if (!cc_telem_parse(line, &telem))
+               return 0;
+       f->ground_accel = telem.ground_accel;
+       f->ground_pres = telem.ground_pres;
+       f->flight = 0;
+       timedata_add(&f->accel, telem.tick, telem.flight_accel);
+       timedata_add(&f->pres, telem.tick, telem.flight_pres);
+       timedata_add(&f->temp, telem.tick, telem.temp);
+       timedata_add(&f->volt, telem.tick, telem.batt);
+       timedata_add(&f->drogue, telem.tick, telem.drogue);
+       timedata_add(&f->main, telem.tick, telem.main);
+       timedata_add(&f->state, telem.tick, state_name_to_state(telem.state));
+       if (telem.gps.gps_locked) {
+               gps.time = telem.tick;
+               gps.lat = telem.gps.lat;
+               gps.lon = telem.gps.lon;
+               gps.alt = telem.gps.alt;
+               gpsdata_add(&f->gps, &gps);
+       }
+       return 1;
+}
+
+struct cc_flightraw *
+cc_log_read(FILE *file)
+{
+       struct cc_flightraw     *f;
+       char                    line[8192];
+       double                  ground_pres;
+       int                     ground_pres_count;
+
+       f = calloc(1, sizeof (struct cc_flightraw));
+       if (!f)
+               return NULL;
+       while (fgets(line, sizeof (line), file)) {
+               if (read_eeprom(line, f, &ground_pres, &ground_pres_count))
+                       continue;
+               if (read_telem(line, f))
+                       continue;
+               fprintf (stderr, "invalid line: %s", line);
+       }
+       return f;
+}
+
+void
+cc_flightraw_free(struct cc_flightraw *raw)
+{
+       timedata_free(&raw->accel);
+       timedata_free(&raw->pres);
+       timedata_free(&raw->temp);
+       timedata_free(&raw->volt);
+       timedata_free(&raw->main);
+       timedata_free(&raw->drogue);
+       timedata_free(&raw->state);
+       gpsdata_free(&raw->gps);
+       free(raw);
+}
diff --git a/ao-tools/lib/cc-telem.c b/ao-tools/lib/cc-telem.c
new file mode 100644 (file)
index 0000000..a6ac031
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "cc.h"
+#include <string.h>
+#include <stdlib.h>
+
+static void
+cc_parse_string(char *target, int len, char *source)
+{
+       strncpy(target, source, len-1);
+       target[len-1] = '\0';
+}
+
+static void
+cc_parse_int(int *target, char *source)
+{
+       *target = strtol(source, NULL, 0);
+}
+
+static void
+cc_parse_hex(int *target, char *source)
+{
+       *target = strtol(source, NULL, 16);
+}
+
+static void
+cc_parse_pos(double *target, char *source)
+{
+       int     deg;
+       double  min;
+       char    dir;
+       double  r;
+
+       if (sscanf(source, "%d°%lf'%c", &deg, &min, &dir) != 3) {
+               *target = 0;
+               return;
+       }
+       r = deg + min / 60.0;
+       if (dir == 'S' || dir == 'W')
+               r = -r;
+       *target = r;
+}
+
+#define PARSE_MAX_WORDS        512
+
+int
+cc_telem_parse(const char *input_line, struct cc_telem *telem)
+{
+       char *saveptr;
+       char *words[PARSE_MAX_WORDS];
+       int nword;
+       char line_buf[8192], *line;
+       int     tracking_pos;
+
+       /* avoid smashing our input parameter */
+       strncpy (line_buf, input_line, sizeof (line_buf)-1);
+       line_buf[sizeof(line_buf) - 1] = '\0';
+       line = line_buf;
+       for (nword = 0; nword < PARSE_MAX_WORDS; nword++) {
+               words[nword] = strtok_r(line, " \t\n", &saveptr);
+               line = NULL;
+               if (words[nword] == NULL)
+                       break;
+       }
+       if (nword < 36)
+               return FALSE;
+       if (strcmp(words[0], "CALL") != 0)
+               return FALSE;
+       cc_parse_string(telem->callsign, sizeof (telem->callsign), words[1]);
+       cc_parse_int(&telem->serial, words[3]);
+
+       cc_parse_int(&telem->rssi, words[5]);
+       cc_parse_string(telem->state, sizeof (telem->state), words[9]);
+       cc_parse_int(&telem->tick, words[10]);
+       cc_parse_int(&telem->accel, words[12]);
+       cc_parse_int(&telem->pres, words[14]);
+       cc_parse_int(&telem->temp, words[16]);
+       cc_parse_int(&telem->batt, words[18]);
+       cc_parse_int(&telem->drogue, words[20]);
+       cc_parse_int(&telem->main, words[22]);
+       cc_parse_int(&telem->flight_accel, words[24]);
+       cc_parse_int(&telem->ground_accel, words[26]);
+       cc_parse_int(&telem->flight_vel, words[28]);
+       cc_parse_int(&telem->flight_pres, words[30]);
+       cc_parse_int(&telem->ground_pres, words[32]);
+       cc_parse_int(&telem->gps.nsat, words[34]);
+       if (strcmp (words[36], "unlocked") == 0) {
+               telem->gps.gps_connected = 1;
+               telem->gps.gps_locked = 0;
+               telem->gps.gps_time.hour = telem->gps.gps_time.minute = telem->gps.gps_time.second = 0;
+               telem->gps.lat = telem->gps.lon = 0;
+               telem->gps.alt = 0;
+               tracking_pos = 37;
+       } else if (nword >= 40) {
+               telem->gps.gps_locked = 1;
+               telem->gps.gps_connected = 1;
+               sscanf(words[36], "%d:%d:%d", &telem->gps.gps_time.hour, &telem->gps.gps_time.minute, &telem->gps.gps_time.second);
+               cc_parse_pos(&telem->gps.lat, words[37]);
+               cc_parse_pos(&telem->gps.lon, words[38]);
+               sscanf(words[39], "%dm", &telem->gps.alt);
+               tracking_pos = 46;
+       } else {
+               telem->gps.gps_connected = 0;
+               telem->gps.gps_locked = 0;
+               telem->gps.gps_time.hour = telem->gps.gps_time.minute = telem->gps.gps_time.second = 0;
+               telem->gps.lat = telem->gps.lon = 0;
+               telem->gps.alt = 0;
+               tracking_pos = -1;
+       }
+       if (nword >= 46) {
+               telem->gps.gps_extended = 1;
+               sscanf(words[40], "%lfm/s", &telem->gps.ground_speed);
+               sscanf(words[41], "%d", &telem->gps.course);
+               sscanf(words[42], "%lfm/s", &telem->gps.climb_rate);
+               sscanf(words[43], "%lf", &telem->gps.hdop);
+               sscanf(words[44], "%d", &telem->gps.h_error);
+               sscanf(words[45], "%d", &telem->gps.v_error);
+       } else {
+               telem->gps.gps_extended = 0;
+               telem->gps.ground_speed = 0;
+               telem->gps.course = 0;
+               telem->gps.climb_rate = 0;
+               telem->gps.hdop = 0;
+               telem->gps.h_error = 0;
+               telem->gps.v_error = 0;
+       }
+       if (tracking_pos >= 0 && nword >= tracking_pos + 2 && strcmp(words[tracking_pos], "SAT") == 0) {
+               int     c, n, pos;
+               cc_parse_int(&n, words[tracking_pos + 1]);
+               pos = tracking_pos + 2;
+               if (nword >= pos + n * 3) {
+                       telem->gps_tracking.channels = n;
+                       for (c = 0; c < n; c++) {
+                               cc_parse_int(&telem->gps_tracking.sats[c].svid,
+                                                words[pos + 0]);
+                               cc_parse_hex(&telem->gps_tracking.sats[c].state,
+                                                words[pos + 1]);
+                               cc_parse_int(&telem->gps_tracking.sats[c].c_n0,
+                                                words[pos + 2]);
+                               pos += 3;
+                       }
+               } else {
+                       telem->gps_tracking.channels = 0;
+               }
+       } else {
+               telem->gps_tracking.channels = 0;
+       }
+       return TRUE;
+}
index 17f059117477994458e3296adfb5d9b2ac1be65b..80d9c04f7ec5271074c730b3bf01c17f2845f610 100644 (file)
 #include "cc-usb.h"
 
 
-#define CC_NUM_READ            16
+#define CC_NUM_HEX_READ                64
 /*
  * AltOS has different buffer sizes for in/out packets
  */
-#define CC_IN_BUF              256
+#define CC_IN_BUF              65536
 #define CC_OUT_BUF             64
 #define DEFAULT_TTY            "/dev/ttyACM0"
 
-struct cc_read {
+struct cc_hex_read {
        uint8_t *buf;
        int     len;
 };
 
 struct cc_usb {
-       int             fd;
-       uint8_t         in_buf[CC_IN_BUF];
-       int             in_count;
-       uint8_t         out_buf[CC_OUT_BUF];
-       int             out_count;
-       struct cc_read  read_buf[CC_NUM_READ];
-       int             read_count;
+       int                     fd;
+       uint8_t                 in_buf[CC_IN_BUF];
+       int                     in_pos;
+       int                     in_count;
+       uint8_t                 out_buf[CC_OUT_BUF];
+       int                     out_count;
+
+       struct cc_hex_read      hex_buf[CC_NUM_HEX_READ];
+       int                     hex_count;
 };
 
 #define NOT_HEX        0xff
@@ -72,61 +74,48 @@ cc_hex_nibble(uint8_t c)
  * and write them to the waiting buffer
  */
 static void
-cc_handle_in(struct cc_usb *cc)
+cc_handle_hex_read(struct cc_usb *cc)
 {
        uint8_t h, l;
-       int     in_pos;
-       int     read_pos;
+       int     hex_pos;
 
-       in_pos = 0;
-       read_pos = 0;
-       while (read_pos < cc->read_count && in_pos < cc->in_count) {
+       hex_pos = 0;
+       while (hex_pos < cc->hex_count && cc->in_pos < cc->in_count) {
                /*
                 * Skip to next hex character
                 */
-               while (in_pos < cc->in_count &&
-                      cc_hex_nibble(cc->in_buf[in_pos]) == NOT_HEX)
-                       in_pos++;
+               while (cc->in_pos < cc->in_count &&
+                      cc_hex_nibble(cc->in_buf[cc->in_pos]) == NOT_HEX)
+                       cc->in_pos++;
                /*
                 * Make sure we have two characters left
                 */
-               if (cc->in_count - in_pos < 2)
+               if (cc->in_count - cc->in_pos < 2)
                        break;
                /*
                 * Parse hex number
                 */
-               h = cc_hex_nibble(cc->in_buf[in_pos]);
-               l = cc_hex_nibble(cc->in_buf[in_pos+1]);
+               h = cc_hex_nibble(cc->in_buf[cc->in_pos]);
+               l = cc_hex_nibble(cc->in_buf[cc->in_pos+1]);
                if (h == NOT_HEX || l == NOT_HEX) {
                        fprintf(stderr, "hex read error\n");
                        break;
                }
-               in_pos += 2;
+               cc->in_pos += 2;
                /*
                 * Store hex number
                 */
-               *cc->read_buf[read_pos].buf++ = (h << 4) | l;
-               if (--cc->read_buf[read_pos].len <= 0)
-                       read_pos++;
-       }
-
-       /* Move remaining bytes to the start of the input buffer */
-       if (in_pos) {
-               memmove(cc->in_buf, cc->in_buf + in_pos,
-                       cc->in_count - in_pos);
-               cc->in_count -= in_pos;
+               *cc->hex_buf[hex_pos].buf++ = (h << 4) | l;
+               if (--cc->hex_buf[hex_pos].len <= 0)
+                       hex_pos++;
        }
 
-       /* Move pending reads to the start of the array */
-       if (read_pos) {
-               memmove(cc->read_buf, cc->read_buf + read_pos,
-                       (cc->read_count - read_pos) * sizeof (cc->read_buf[0]));
-               cc->read_count -= read_pos;
+       /* Move pending hex reads to the start of the array */
+       if (hex_pos) {
+               memmove(cc->hex_buf, cc->hex_buf + hex_pos,
+                       (cc->hex_count - hex_pos) * sizeof (cc->hex_buf[0]));
+               cc->hex_count -= hex_pos;
        }
-
-       /* Once we're done reading, flush any pending input */
-       if (cc->read_count == 0)
-               cc->in_count = 0;
 }
 
 static void
@@ -158,8 +147,8 @@ cc_usb_dbg(int indent, uint8_t *bytes, int len)
  * Flush pending writes, fill pending reads
  */
 
-int
-cc_usb_sync(struct cc_usb *cc)
+static int
+_cc_usb_sync(struct cc_usb *cc, int wait_for_input)
 {
        int             ret;
        struct pollfd   fds;
@@ -167,26 +156,33 @@ cc_usb_sync(struct cc_usb *cc)
 
        fds.fd = cc->fd;
        for (;;) {
-               if (cc->read_count || cc->out_count)
+               if (cc->hex_count || cc->out_count)
                        timeout = 5000;
+               else if (wait_for_input && cc->in_pos == cc->in_count)
+                       timeout = wait_for_input;
                else
                        timeout = 0;
                fds.events = 0;
+               /* Move remaining bytes to the start of the input buffer */
+               if (cc->in_pos) {
+                       memmove(cc->in_buf, cc->in_buf + cc->in_pos,
+                               cc->in_count - cc->in_pos);
+                       cc->in_count -= cc->in_pos;
+                       cc->in_pos = 0;
+               }
                if (cc->in_count < CC_IN_BUF)
                        fds.events |= POLLIN;
                if (cc->out_count)
                        fds.events |= POLLOUT;
                ret = poll(&fds, 1, timeout);
                if (ret == 0) {
-                       if (timeout) {
-                               fprintf(stderr, "USB link timeout\n");
-                               exit(1);
-                       }
+                       if (timeout)
+                               return -1;
                        break;
                }
                if (ret < 0) {
                        perror("poll");
-                       break;
+                       return -1;
                }
                if (fds.revents & POLLIN) {
                        ret = read(cc->fd, cc->in_buf + cc->in_count,
@@ -194,7 +190,8 @@ cc_usb_sync(struct cc_usb *cc)
                        if (ret > 0) {
                                cc_usb_dbg(24, cc->in_buf + cc->in_count, ret);
                                cc->in_count += ret;
-                               cc_handle_in(cc);
+                               if (cc->hex_count)
+                                       cc_handle_hex_read(cc);
                        } else if (ret < 0)
                                perror("read");
                }
@@ -211,6 +208,16 @@ cc_usb_sync(struct cc_usb *cc)
                                perror("write");
                }
        }
+       return 0;
+}
+
+void
+cc_usb_sync(struct cc_usb *cc)
+{
+       if (_cc_usb_sync(cc, 0) < 0) {
+               fprintf(stderr, "USB link timeout\n");
+               exit(1);
+       }
 }
 
 void
@@ -244,6 +251,38 @@ cc_usb_printf(struct cc_usb *cc, char *format, ...)
        }
 }
 
+int
+cc_usb_getchar(struct cc_usb *cc)
+{
+       while (cc->in_pos == cc->in_count) {
+               if (_cc_usb_sync(cc, 5000) < 0) {
+                       fprintf(stderr, "USB link timeout\n");
+                       exit(1);
+               }
+       }
+       return cc->in_buf[cc->in_pos++];
+}
+
+void
+cc_usb_getline(struct cc_usb *cc, char *line, int max)
+{
+       int     c;
+
+       while ((c = cc_usb_getchar(cc)) != '\n') {
+               switch (c) {
+               case '\r':
+                       break;
+               default:
+                       if (max > 1) {
+                               *line++ = c;
+                               max--;
+                       }
+                       break;
+               }
+       }
+       *line++ = '\0';
+}
+
 int
 cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len)
 {
@@ -266,12 +305,18 @@ cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len)
 void
 cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len)
 {
-       struct cc_read  *read_buf;
-       while (cc->read_count >= CC_NUM_READ)
+       struct cc_hex_read      *hex_buf;
+
+       /* At the start of a command sequence, flush any pending input */
+       if (cc->hex_count == 0) {
                cc_usb_sync(cc);
-       read_buf = &cc->read_buf[cc->read_count++];
-       read_buf->buf = buf;
-       read_buf->len = len;
+               cc->in_count = 0;
+       }
+       while (cc->hex_count >= CC_NUM_HEX_READ)
+               cc_usb_sync(cc);
+       hex_buf = &cc->hex_buf[cc->hex_count++];
+       hex_buf->buf = buf;
+       hex_buf->len = len;
 }
 
 int
@@ -351,9 +396,10 @@ cc_usb_open(char *tty)
        cfmakeraw(&termios);
        tcsetattr(cc->fd, TCSAFLUSH, &termios);
        cc_usb_printf(cc, "E 0\nm 0\n");
-       cc_usb_sync(cc);
-       sleep(1);
-       cc_usb_sync(cc);
+       do {
+               cc->in_count = cc->in_pos = 0;
+               _cc_usb_sync(cc, 100);
+       } while (cc->in_count > 0);
        return cc;
 }
 
index 9baabd9598fbb9356f43ee33332fe3deed917414..7b6be350f02e6badefe61b5142fdd660f51e8a06 100644 (file)
@@ -47,12 +47,18 @@ cc_usb_debug_mode(struct cc_usb *cc);
 int
 cc_usb_reset(struct cc_usb *cc);
 
-int
+void
 cc_usb_sync(struct cc_usb *cc);
 
 void
 cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len);
 
+int
+cc_usb_getchar(struct cc_usb *cc);
+
+void
+cc_usb_getline(struct cc_usb *cc, char *line, int max);
+
 void
 cc_usb_printf(struct cc_usb *cc, char *format, ...);
 
index 7104470c4cbd34c6939c7cd8d4bfc142b1b1a61a..65488ee9b7f6e36a9c8918be3c56ee3fbc3972d6 100644 (file)
@@ -15,8 +15,8 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-#include "cc.h"
 #define _GNU_SOURCE
+#include "cc.h"
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
index 0933f2725a9fe79ee1db50bc3e2803ed16a84943..57f80b8d5e938220e709c4eb6026ee4ba9481404 100644 (file)
@@ -18,6 +18,8 @@
 #ifndef _CC_H_
 #define _CC_H_
 
+#include <stdio.h>
+
 char *
 cc_fullname (char *dir, char *file);
 
@@ -51,4 +53,219 @@ cc_usbdevs_scan(void);
 char *
 cc_usbdevs_find_by_arg(char *arg, char *default_product);
 
+void
+cc_set_log_dir(char *dir);
+
+char *
+cc_get_log_dir(void);
+
+char *
+cc_make_filename(int serial, char *ext);
+
+/*
+ * For sequential data which are not evenly spaced
+ */
+
+struct cc_timedataelt {
+       double  time;
+       double  value;
+};
+
+struct cc_timedata {
+       int                     num;
+       int                     size;
+       struct cc_timedataelt   *data;
+       double                  time_offset;
+};
+
+
+/*
+ * For GPS data
+ */
+
+struct cc_gpselt {
+       double          time;
+       double          lat;
+       double          lon;
+       double          alt;
+};
+
+struct cc_gpsdata {
+       int                     num;
+       int                     size;
+       struct cc_gpselt        *data;
+       double                  time_offset;
+};
+
+/*
+ * For sequential data which are evenly spaced
+ */
+struct cc_perioddata {
+       int             num;
+       double          start;
+       double          step;
+       double          *data;
+};
+
+enum ao_flight_state {
+       ao_flight_startup = 0,
+       ao_flight_idle = 1,
+       ao_flight_pad = 2,
+       ao_flight_boost = 3,
+       ao_flight_fast = 4,
+       ao_flight_coast = 5,
+       ao_flight_drogue = 6,
+       ao_flight_main = 7,
+       ao_flight_landed = 8,
+       ao_flight_invalid = 9
+};
+
+struct cc_flightraw {
+       int                     flight;
+       int                     serial;
+       double                  ground_accel;
+       double                  ground_pres;
+       struct cc_timedata      accel;
+       struct cc_timedata      pres;
+       struct cc_timedata      temp;
+       struct cc_timedata      volt;
+       struct cc_timedata      main;
+       struct cc_timedata      drogue;
+       struct cc_timedata      state;
+       struct cc_gpsdata       gps;
+};
+
+struct cc_flightraw *
+cc_log_read(FILE *file);
+
+void
+cc_flightraw_free(struct cc_flightraw *raw);
+
+struct cc_flightcooked {
+       struct cc_perioddata    accel_accel;
+       struct cc_perioddata    accel_speed;
+       struct cc_perioddata    accel_pos;
+       struct cc_perioddata    pres_pos;
+       struct cc_perioddata    pres_speed;
+       struct cc_perioddata    pres_accel;
+       struct cc_perioddata    gps_lat;
+       struct cc_perioddata    gps_lon;
+       struct cc_perioddata    gps_alt;
+       struct cc_timedata      state;
+};
+
+/*
+ * Telemetry data contents
+ */
+
+
+struct cc_gps_time {
+       int hour;
+       int minute;
+       int second;
+};
+
+struct cc_gps {
+       int     nsat;
+       int     gps_locked;
+       int     gps_connected;
+       struct cc_gps_time gps_time;
+       double  lat;            /* degrees (+N -S) */
+       double  lon;            /* degrees (+E -W) */
+       int     alt;            /* m */
+
+       int     gps_extended;   /* has extra data */
+       double  ground_speed;   /* m/s */
+       int     course;         /* degrees */
+       double  climb_rate;     /* m/s */
+       double  hdop;           /* unitless? */
+       int     h_error;        /* m */
+       int     v_error;        /* m */
+};
+
+#define SIRF_SAT_STATE_ACQUIRED                        (1 << 0)
+#define SIRF_SAT_STATE_CARRIER_PHASE_VALID     (1 << 1)
+#define SIRF_SAT_BIT_SYNC_COMPLETE             (1 << 2)
+#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE                (1 << 3)
+#define SIRF_SAT_CARRIER_PULLIN_COMPLETE       (1 << 4)
+#define SIRF_SAT_CODE_LOCKED                   (1 << 5)
+#define SIRF_SAT_ACQUISITION_FAILED            (1 << 6)
+#define SIRF_SAT_EPHEMERIS_AVAILABLE           (1 << 7)
+
+struct cc_gps_sat {
+       int     svid;
+       int     state;
+       int     c_n0;
+};
+
+struct cc_gps_tracking {
+       int                     channels;
+       struct cc_gps_sat       sats[12];
+};
+
+struct cc_telem {
+       char    callsign[16];
+       int     serial;
+       int     rssi;
+       char    state[16];
+       int     tick;
+       int     accel;
+       int     pres;
+       int     temp;
+       int     batt;
+       int     drogue;
+       int     main;
+       int     flight_accel;
+       int     ground_accel;
+       int     flight_vel;
+       int     flight_pres;
+       int     ground_pres;
+       struct cc_gps   gps;
+       struct cc_gps_tracking  gps_tracking;
+};
+
+int
+cc_telem_parse(const char *input_line, struct cc_telem *telem);
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/* Conversion functions */
+double
+cc_pressure_to_altitude(double pressure);
+
+double
+cc_altitude_to_pressure(double altitude);
+
+double
+cc_barometer_to_pressure(double baro);
+
+double
+cc_barometer_to_altitude(double baro);
+
+double
+cc_accelerometer_to_acceleration(double accel, double ground_accel);
+
+double
+cc_thermometer_to_temperature(double thermo);
+
+double
+cc_battery_to_voltage(double battery);
+
+double
+cc_ignitor_to_voltage(double ignite);
+
+void
+cc_great_circle (double start_lat, double start_lon,
+                double end_lat, double end_lon,
+                double *dist, double *bearing);
+
+int
+cc_timedata_min(struct cc_timedata *d, double min_time, double max_time);
+
+int
+cc_timedata_max(struct cc_timedata *d, double min_time, double max_time);
+
 #endif /* _CC_H_ */
index 564028572a2ab0ec6ff070a65555d9c32b7fd55d..c668df0473016af16d7e25b56a411ce4099ecad3 100644 (file)
@@ -77,10 +77,12 @@ ao-tools/Makefile
 ao-tools/lib/Makefile
 ao-tools/ao-rawload/Makefile
 ao-tools/ao-dbg/Makefile
+ao-tools/ao-dumplog/Makefile
 ao-tools/ao-bitbang/Makefile
 ao-tools/ao-eeprom/Makefile
 ao-tools/ao-list/Makefile
 ao-tools/ao-load/Makefile
+ao-tools/ao-postflight/Makefile
 ao-tools/ao-view/Makefile
 ao-utils/Makefile
 ])