From 0c771d999914f9d17c723900f2987acc45fd0fbb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 4 Sep 2009 13:00:02 -0700 Subject: Move usb scanning code to ao-tools library This will allow the scanning code to be used by the command line tools as well as the ao-view GUI. Now that ao-view depends on the ao-tools library, it has been moved to the ao-tools directory as well. Signed-off-by: Keith Packard --- ao-tools/lib/Makefile.am | 3 + ao-tools/lib/cc-usbdev.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++ ao-tools/lib/cc-util.c | 80 +++++++++++++++++ ao-tools/lib/cc.h | 51 +++++++++++ 4 files changed, 362 insertions(+) create mode 100644 ao-tools/lib/cc-usbdev.c create mode 100644 ao-tools/lib/cc-util.c create mode 100644 ao-tools/lib/cc.h (limited to 'ao-tools/lib') diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index 9584e216..f66ee0a9 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -16,6 +16,9 @@ libao_tools_a_SOURCES = \ ccdbg-state.c \ cc-usb.c \ cc-usb.h \ + cc.h \ + cc-usbdev.c \ + cc-util.c \ cc-bitbang.c \ cc-bitbang.h \ cp-usb-async.c \ diff --git a/ao-tools/lib/cc-usbdev.c b/ao-tools/lib/cc-usbdev.c new file mode 100644 index 00000000..d8bb8b11 --- /dev/null +++ b/ao-tools/lib/cc-usbdev.c @@ -0,0 +1,228 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "cc.h" + +#include +#include +#include +#include +#include + +static char * +load_string(char *dir, char *file) +{ + char *full = cc_fullname(dir, file); + char line[4096]; + char *r; + FILE *f; + int rlen; + + f = fopen(full, "r"); + free(full); + if (!f) + return NULL; + r = fgets(line, sizeof (line), f); + fclose(f); + if (!r) + return NULL; + rlen = strlen(r); + if (r[rlen-1] == '\n') + r[rlen-1] = '\0'; + return strdup(r); +} + +static int +load_hex(char *dir, char *file) +{ + char *line; + char *end; + long i; + + line = load_string(dir, file); + if (!line) + return -1; + i = strtol(line, &end, 16); + free(line); + if (end == line) + return -1; + return i; +} + +static int +dir_filter_tty_colon(const struct dirent *d) +{ + return strncmp(d->d_name, "tty:", 4) == 0; +} + +static int +dir_filter_tty(const struct dirent *d) +{ + return strncmp(d->d_name, "tty", 3) == 0; +} + +static char * +usb_tty(char *sys) +{ + char *base; + int num_configs; + int config; + struct dirent **namelist; + int interface; + int num_interfaces; + char endpoint_base[20]; + char *endpoint_full; + char *tty_dir; + int ntty; + char *tty; + + base = cc_basename(sys); + num_configs = load_hex(sys, "bNumConfigurations"); + num_interfaces = load_hex(sys, "bNumInterfaces"); + for (config = 1; config <= num_configs; config++) { + for (interface = 0; interface < num_interfaces; interface++) { + sprintf(endpoint_base, "%s:%d.%d", + base, config, interface); + endpoint_full = cc_fullname(sys, endpoint_base); + + /* Check for tty:ttyACMx style names + */ + ntty = scandir(endpoint_full, &namelist, + dir_filter_tty_colon, + alphasort); + if (ntty > 0) { + free(endpoint_full); + tty = cc_fullname("/dev", namelist[0]->d_name + 4); + free(namelist); + return tty; + } + + /* Check for tty/ttyACMx style names + */ + tty_dir = cc_fullname(endpoint_full, "tty"); + free(endpoint_full); + ntty = scandir(tty_dir, &namelist, + dir_filter_tty, + alphasort); + free (tty_dir); + if (ntty > 0) { + tty = cc_fullname("/dev", namelist[0]->d_name); + free(namelist); + return tty; + } + } + } + return NULL; +} + +static struct cc_usbdev * +usb_scan_device(char *sys) +{ + struct cc_usbdev *usbdev; + + usbdev = calloc(1, sizeof (struct cc_usbdev)); + if (!usbdev) + return NULL; + usbdev->sys = strdup(sys); + usbdev->manufacturer = load_string(sys, "manufacturer"); + usbdev->product = load_string(sys, "product"); + usbdev->serial = load_string(sys, "serial"); + usbdev->idProduct = load_hex(sys, "idProduct"); + usbdev->idVendor = load_hex(sys, "idVendor"); + usbdev->tty = usb_tty(sys); + return usbdev; +} + +static void +usbdev_free(struct cc_usbdev *usbdev) +{ + free(usbdev->sys); + free(usbdev->manufacturer); + free(usbdev->product); + free(usbdev->serial); + free(usbdev->tty); + free(usbdev); +} + +#define USB_DEVICES "/sys/bus/usb/devices" + +static int +dir_filter_dev(const struct dirent *d) +{ + const char *n = d->d_name; + char c; + + while ((c = *n++)) { + if (isdigit(c)) + continue; + if (c == '-') + continue; + if (c == '.' && n != d->d_name + 1) + continue; + return 0; + } + return 1; +} + +struct cc_usbdevs * +cc_usbdevs_scan(void) +{ + int e; + struct dirent **ents; + char *dir; + struct cc_usbdev *dev; + struct cc_usbdevs *devs; + int n; + + devs = calloc(1, sizeof (struct cc_usbdevs)); + if (!devs) + return NULL; + + n = scandir (USB_DEVICES, &ents, + dir_filter_dev, + alphasort); + if (!n) + return 0; + for (e = 0; e < n; e++) { + dir = cc_fullname(USB_DEVICES, ents[e]->d_name); + dev = usb_scan_device(dir); + free(dir); + if (dev->idVendor == 0xfffe && dev->tty) { + if (devs->dev) + devs->dev = realloc(devs->dev, + devs->ndev + 1 * sizeof (struct usbdev *)); + else + devs->dev = malloc (sizeof (struct usbdev *)); + devs->dev[devs->ndev++] = dev; + } + } + free(ents); + return devs; +} + +void +cc_usbdevs_free(struct cc_usbdevs *usbdevs) +{ + int i; + + if (!usbdevs) + return; + for (i = 0; i < usbdevs->ndev; i++) + usbdev_free(usbdevs->dev[i]); + free(usbdevs); +} diff --git a/ao-tools/lib/cc-util.c b/ao-tools/lib/cc-util.c new file mode 100644 index 00000000..7104470c --- /dev/null +++ b/ao-tools/lib/cc-util.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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" +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +char * +cc_fullname (char *dir, char *file) +{ + char *new; + int dlen = strlen (dir); + int flen = strlen (file); + int slen = 0; + + if (dir[dlen-1] != '/') + slen = 1; + new = malloc (dlen + slen + flen + 1); + if (!new) + return 0; + strcpy(new, dir); + if (slen) + strcat (new, "/"); + strcat(new, file); + return new; +} + +char * +cc_basename(char *file) +{ + char *b; + + b = strrchr(file, '/'); + if (!b) + return file; + return b + 1; +} + +int +cc_mkdir(char *dir) +{ + char *slash; + char *d; + char *part; + + d = dir; + for (;;) { + slash = strchr (d, '/'); + if (!slash) + slash = d + strlen(d); + if (!*slash) + break; + part = strndup(dir, slash - dir); + if (!access(part, F_OK)) + if (mkdir(part, 0777) < 0) + return -errno; + free(part); + d = slash + 1; + } + return 0; +} diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h new file mode 100644 index 00000000..dad11bf3 --- /dev/null +++ b/ao-tools/lib/cc.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _CC_H_ +#define _CC_H_ + +char * +cc_fullname (char *dir, char *file); + +char * +cc_basename(char *file); + +int +cc_mkdir(char *dir); + +struct cc_usbdev { + char *sys; + char *tty; + char *manufacturer; + char *product; + char *serial; + int idProduct; + int idVendor; +}; + +struct cc_usbdevs { + struct cc_usbdev **dev; + int ndev; +}; + +void +cc_usbdevs_free(struct cc_usbdevs *usbdevs); + +struct cc_usbdevs * +cc_usbdevs_scan(void); + +#endif /* _CC_H_ */ -- cgit v1.2.3 From 0935d6a7e907e20381a42882ae728051f9bece02 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 4 Sep 2009 14:21:19 -0700 Subject: Parse the USB serial number as an integer. AltOS devices use simple integer serial numbers, so parse the USB value as such to make matching values more forgiving. Signed-off-by: Keith Packard --- ao-tools/ao-view/aoview_dev_dialog.c | 2 +- ao-tools/lib/cc-usbdev.c | 97 ++++++++++++++++++++++++++++++++++-- ao-tools/lib/cc.h | 5 +- 3 files changed, 98 insertions(+), 6 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-view/aoview_dev_dialog.c b/ao-tools/ao-view/aoview_dev_dialog.c index 87396c1f..2ea43203 100644 --- a/ao-tools/ao-view/aoview_dev_dialog.c +++ b/ao-tools/ao-view/aoview_dev_dialog.c @@ -29,7 +29,7 @@ aoview_dev_dialog_map(GtkWidget *widget, gpointer data) list_store = gtk_list_store_new(3, G_TYPE_STRING, - G_TYPE_STRING, + G_TYPE_INT, G_TYPE_STRING); devs = cc_usbdevs_scan(); diff --git a/ao-tools/lib/cc-usbdev.c b/ao-tools/lib/cc-usbdev.c index d8bb8b11..ed39c062 100644 --- a/ao-tools/lib/cc-usbdev.c +++ b/ao-tools/lib/cc-usbdev.c @@ -16,8 +16,8 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#define _GNU_SOURCE #include "cc.h" - #include #include #include @@ -64,6 +64,23 @@ load_hex(char *dir, char *file) return i; } +static int +load_dec(char *dir, char *file) +{ + char *line; + char *end; + long i; + + line = load_string(dir, file); + if (!line) + return -1; + i = strtol(line, &end, 10); + free(line); + if (end == line) + return -1; + return i; +} + static int dir_filter_tty_colon(const struct dirent *d) { @@ -141,7 +158,7 @@ usb_scan_device(char *sys) usbdev->sys = strdup(sys); usbdev->manufacturer = load_string(sys, "manufacturer"); usbdev->product = load_string(sys, "product"); - usbdev->serial = load_string(sys, "serial"); + usbdev->serial = load_dec(sys, "serial"); usbdev->idProduct = load_hex(sys, "idProduct"); usbdev->idVendor = load_hex(sys, "idVendor"); usbdev->tty = usb_tty(sys); @@ -154,8 +171,9 @@ usbdev_free(struct cc_usbdev *usbdev) free(usbdev->sys); free(usbdev->manufacturer); free(usbdev->product); - free(usbdev->serial); - free(usbdev->tty); + /* this can get used as a return value */ + if (usbdev->tty) + free(usbdev->tty); free(usbdev); } @@ -226,3 +244,74 @@ cc_usbdevs_free(struct cc_usbdevs *usbdevs) usbdev_free(usbdevs->dev[i]); free(usbdevs); } + +static char * +match_dev(char *product, int serial) +{ + struct cc_usbdevs *devs; + struct cc_usbdev *dev; + int i; + char *tty = NULL; + + devs = cc_usbdevs_scan(); + if (!devs) + return NULL; + for (i = 0; i < devs->ndev; i++) { + dev = devs->dev[i]; + if (product && strcmp (product, dev->product) != 0) + continue; + if (serial && serial != dev->serial) + continue; + break; + } + if (i < devs->ndev) { + tty = devs->dev[i]->tty; + devs->dev[i]->tty = NULL; + } + cc_usbdevs_free(devs); + return tty; +} + +char * +cc_usbdevs_find_by_arg(char *arg, char *default_product) +{ + char *product; + int serial; + char *end; + char *colon; + char *tty; + + if (arg) + { + /* check for */ + serial = strtol(arg, &end, 0); + if (end != arg) { + if (*end != '\0') + return NULL; + product = NULL; + } else { + /* check for : */ + colon = strchr(arg, ':'); + if (colon) { + product = strndup(arg, colon - arg); + serial = strtol(colon + 1, &end, 0); + if (*end != '\0') + return NULL; + } else { + product = arg; + serial = 0; + } + } + } else { + product = NULL; + serial = 0; + } + tty = NULL; + if (!product && default_product) + tty = match_dev(default_product, serial); + if (!tty) + tty = match_dev(product, serial); + if (product && product != arg) + free(product); + return tty; +} diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index dad11bf3..0933f272 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -32,7 +32,7 @@ struct cc_usbdev { char *tty; char *manufacturer; char *product; - char *serial; + int serial; /* AltOS always uses simple integer serial numbers */ int idProduct; int idVendor; }; @@ -48,4 +48,7 @@ cc_usbdevs_free(struct cc_usbdevs *usbdevs); struct cc_usbdevs * cc_usbdevs_scan(void); +char * +cc_usbdevs_find_by_arg(char *arg, char *default_product); + #endif /* _CC_H_ */ -- cgit v1.2.3 From 332b056459b1352e233a8bf5f08498df12d32160 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 4 Sep 2009 15:01:32 -0700 Subject: 'fix' ao-eeprom to read two blocks at once. Work around kernel bugs. The kernel appears to leave serial data undelivered at times. Reading two blocks at once appears to make it relinquish the queued data. Signed-off-by: Keith Packard --- ao-tools/Makefile.am | 2 +- ao-tools/ao-eeprom/ao-eeprom.c | 20 ++++++++++++++------ ao-tools/lib/cc-usb.c | 12 +++++++++--- ao-tools/lib/cc-usb.h | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am index 02b4785e..28e77b08 100644 --- a/ao-tools/Makefile.am +++ b/ao-tools/Makefile.am @@ -1 +1 @@ -SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-load ao-view +SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load ao-view diff --git a/ao-tools/ao-eeprom/ao-eeprom.c b/ao-tools/ao-eeprom/ao-eeprom.c index 726cc22c..b865e298 100644 --- a/ao-tools/ao-eeprom/ao-eeprom.c +++ b/ao-tools/ao-eeprom/ao-eeprom.c @@ -21,17 +21,19 @@ #include #include #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 ]\n", program); + fprintf(stderr, "usage: %s [--tty ] [--device \n", program); exit(1); } @@ -40,23 +42,29 @@ main (int argc, char **argv) { struct cc_usb *cc; int block; - uint8_t bytes[32 * (2 + 8)]; + uint8_t bytes[2 * 32 * (2 + 8)]; uint8_t *b; int i, j; uint32_t addr; 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; } } + if (!tty) + tty = cc_usbdevs_find_by_arg(device, "TeleMetrum"); if (!tty) tty = getenv("ALTOS_TTY"); if (!tty) @@ -64,11 +72,11 @@ main (int argc, char **argv) cc = cc_usb_open(tty); if (!cc) exit(1); - for (block = 0; block < NUM_BLOCK; block++) { + for (block = 0; block < NUM_BLOCK; block += 2) { cc_queue_read(cc, bytes, sizeof (bytes)); - cc_usb_printf(cc, "e %x\n", block); + cc_usb_printf(cc, "e %x\ne %x\n", block, block + 1); cc_usb_sync(cc); - for (i = 0; i < 32; i++) { + for (i = 0; i < 32 * 2; i++) { b = bytes + (i * 10); addr = block * 256 + i * 8; printf ("%06x", addr); diff --git a/ao-tools/lib/cc-usb.c b/ao-tools/lib/cc-usb.c index 81309983..17f05911 100644 --- a/ao-tools/lib/cc-usb.c +++ b/ao-tools/lib/cc-usb.c @@ -157,7 +157,8 @@ cc_usb_dbg(int indent, uint8_t *bytes, int len) /* * Flush pending writes, fill pending reads */ -void + +int cc_usb_sync(struct cc_usb *cc) { int ret; @@ -167,7 +168,7 @@ cc_usb_sync(struct cc_usb *cc) fds.fd = cc->fd; for (;;) { if (cc->read_count || cc->out_count) - timeout = -1; + timeout = 5000; else timeout = 0; fds.events = 0; @@ -176,8 +177,13 @@ cc_usb_sync(struct cc_usb *cc) if (cc->out_count) fds.events |= POLLOUT; ret = poll(&fds, 1, timeout); - if (ret == 0) + if (ret == 0) { + if (timeout) { + fprintf(stderr, "USB link timeout\n"); + exit(1); + } break; + } if (ret < 0) { perror("poll"); break; diff --git a/ao-tools/lib/cc-usb.h b/ao-tools/lib/cc-usb.h index d7acfbd2..9baabd95 100644 --- a/ao-tools/lib/cc-usb.h +++ b/ao-tools/lib/cc-usb.h @@ -47,7 +47,7 @@ cc_usb_debug_mode(struct cc_usb *cc); int cc_usb_reset(struct cc_usb *cc); -void +int cc_usb_sync(struct cc_usb *cc); void -- cgit v1.2.3 From 26f56b51bd11aa91f1d77b81827b49c28cb6ec5f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 5 Sep 2009 00:29:26 -0700 Subject: Add ao-dumplog to capture flight log from command line This duplicates the functionality of the flight log stuf in ao-view, except from the command line where it belongs. Signed-off-by: Keith Packard --- ao-tools/Makefile.am | 2 +- ao-tools/ao-dumplog/Makefile.am | 12 +++ ao-tools/ao-dumplog/ao-dumplog.1 | 68 ++++++++++++++++ ao-tools/ao-dumplog/ao-dumplog.c | 103 ++++++++++++++++++++++++ ao-tools/lib/Makefile.am | 3 +- ao-tools/lib/cc-usb.c | 164 +++++++++++++++++++++++++-------------- ao-tools/lib/cc-usb.h | 8 +- ao-tools/lib/cc.h | 9 +++ configure.ac | 1 + 9 files changed, 308 insertions(+), 62 deletions(-) create mode 100644 ao-tools/ao-dumplog/Makefile.am create mode 100644 ao-tools/ao-dumplog/ao-dumplog.1 create mode 100644 ao-tools/ao-dumplog/ao-dumplog.c (limited to 'ao-tools/lib') diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am index 28e77b08..b61f045f 100644 --- a/ao-tools/Makefile.am +++ b/ao-tools/Makefile.am @@ -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-view diff --git a/ao-tools/ao-dumplog/Makefile.am b/ao-tools/ao-dumplog/Makefile.am new file mode 100644 index 00000000..a80cac33 --- /dev/null +++ b/ao-tools/ao-dumplog/Makefile.am @@ -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 index 00000000..8c2df7c6 --- /dev/null +++ b/ao-tools/ao-dumplog/ao-dumplog.1 @@ -0,0 +1,68 @@ +.\" +.\" Copyright © 2009 Keith Packard +.\" +.\" 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 index 00000000..4bccfd61 --- /dev/null +++ b/ao-tools/ao-dumplog/ao-dumplog.c @@ -0,0 +1,103 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include +#include +#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 ] [--device \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); + } + } 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); +} diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index f66ee0a9..da13ede9 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -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,7 @@ libao_tools_a_SOURCES = \ ccdbg-memory.c \ ccdbg-rom.c \ ccdbg-state.c \ + cc-log.c \ cc-usb.c \ cc-usb.h \ cc.h \ diff --git a/ao-tools/lib/cc-usb.c b/ao-tools/lib/cc-usb.c index 17f05911..80d9c04f 100644 --- a/ao-tools/lib/cc-usb.c +++ b/ao-tools/lib/cc-usb.c @@ -30,27 +30,29 @@ #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; } diff --git a/ao-tools/lib/cc-usb.h b/ao-tools/lib/cc-usb.h index 9baabd95..7b6be350 100644 --- a/ao-tools/lib/cc-usb.h +++ b/ao-tools/lib/cc-usb.h @@ -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, ...); diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 0933f272..f92a29f7 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -51,4 +51,13 @@ 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); + #endif /* _CC_H_ */ diff --git a/configure.ac b/configure.ac index 56402857..73a33ac3 100644 --- a/configure.ac +++ b/configure.ac @@ -77,6 +77,7 @@ 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 -- cgit v1.2.3 From c46e832b28820d7c5be4efaacbbd7c0607927fe5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 5 Sep 2009 22:03:31 -0700 Subject: Add simple post-flight analysis tool (ao-postflight) This tool reads either an eeprom or telem log file and displays some rudimentary data (max accel/alt for each flight stage). Signed-off-by: Keith Packard --- .gitignore | 4 + ao-tools/Makefile.am | 2 +- ao-tools/ao-dumplog/ao-dumplog.c | 1 + ao-tools/ao-postflight/Makefile.am | 12 ++ ao-tools/ao-postflight/ao-postflight.1 | 29 ++++ ao-tools/ao-postflight/ao-postflight.c | 166 ++++++++++++++++++++ ao-tools/lib/Makefile.am | 4 + ao-tools/lib/cc-analyse.c | 58 +++++++ ao-tools/lib/cc-convert.c | 275 +++++++++++++++++++++++++++++++++ ao-tools/lib/cc-log.c | 114 ++++++++++++++ ao-tools/lib/cc-logfile.c | 218 ++++++++++++++++++++++++++ ao-tools/lib/cc-telem.c | 164 ++++++++++++++++++++ ao-tools/lib/cc-util.c | 2 +- ao-tools/lib/cc.h | 207 +++++++++++++++++++++++++ configure.ac | 1 + 15 files changed, 1255 insertions(+), 2 deletions(-) create mode 100644 ao-tools/ao-postflight/Makefile.am create mode 100644 ao-tools/ao-postflight/ao-postflight.1 create mode 100644 ao-tools/ao-postflight/ao-postflight.c create mode 100644 ao-tools/lib/cc-analyse.c create mode 100644 ao-tools/lib/cc-convert.c create mode 100644 ao-tools/lib/cc-log.c create mode 100644 ao-tools/lib/cc-logfile.c create mode 100644 ao-tools/lib/cc-telem.c (limited to 'ao-tools/lib') diff --git a/.gitignore b/.gitignore index b3d2d562..0ca4bed4 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am index b61f045f..2850e909 100644 --- a/ao-tools/Makefile.am +++ b/ao-tools/Makefile.am @@ -1 +1 @@ -SUBDIRS=lib ao-rawload ao-dbg ao-dumplog 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 diff --git a/ao-tools/ao-dumplog/ao-dumplog.c b/ao-tools/ao-dumplog/ao-dumplog.c index 4bccfd61..b930f0e5 100644 --- a/ao-tools/ao-dumplog/ao-dumplog.c +++ b/ao-tools/ao-dumplog/ao-dumplog.c @@ -86,6 +86,7 @@ main (int argc, char **argv) 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); diff --git a/ao-tools/ao-postflight/Makefile.am b/ao-tools/ao-postflight/Makefile.am new file mode 100644 index 00000000..301ac454 --- /dev/null +++ b/ao-tools/ao-postflight/Makefile.am @@ -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 index 00000000..fe02587f --- /dev/null +++ b/ao-tools/ao-postflight/ao-postflight.1 @@ -0,0 +1,29 @@ +.\" +.\" Copyright © 2009 Keith Packard +.\" +.\" 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 index 00000000..f0e2c2ae --- /dev/null +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include +#include +#include +#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); + 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); + 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; + 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); + 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); + 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; +} diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index da13ede9..e682f757 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -14,6 +14,8 @@ 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 \ @@ -22,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 index 00000000..6fd36cdc --- /dev/null +++ b/ao-tools/lib/cc-analyse.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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; + double min; + + if (d->num == 0) + return 0; + 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; + int set = 0; + + if (d->num == 0) + return 0; + 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 index 00000000..ac6962ba --- /dev/null +++ b/ao-tools/lib/cc-convert.c @@ -0,0 +1,275 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 + +/* + * 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 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 index 00000000..dd8177f4 --- /dev/null +++ b/ao-tools/lib/cc-log.c @@ -0,0 +1,114 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include +#include +#include +#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 index 00000000..444ff089 --- /dev/null +++ b/ao-tools/lib/cc-logfile.c @@ -0,0 +1,218 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include + +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; + } + if (data->num && data->data[data->num-1].time > time) + 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; + } + 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 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); + 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 index 00000000..a6ac0313 --- /dev/null +++ b/ao-tools/lib/cc-telem.c @@ -0,0 +1,164 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include + +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", °, &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; +} diff --git a/ao-tools/lib/cc-util.c b/ao-tools/lib/cc-util.c index 7104470c..65488ee9 100644 --- a/ao-tools/lib/cc-util.c +++ b/ao-tools/lib/cc-util.c @@ -15,8 +15,8 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include "cc.h" #define _GNU_SOURCE +#include "cc.h" #include #include #include diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index f92a29f7..3975cf1b 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -18,6 +18,8 @@ #ifndef _CC_H_ #define _CC_H_ +#include + char * cc_fullname (char *dir, char *file); @@ -60,4 +62,209 @@ 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; +}; + + +/* + * For GPS data + */ + +struct cc_gpselt { + double time; + double lat; + double lon; + double alt; +}; + +struct cc_gpsdata { + int num; + int size; + double time_offset; + struct cc_gpselt *data; +}; + +/* + * 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_ */ diff --git a/configure.ac b/configure.ac index 73a33ac3..c668df04 100644 --- a/configure.ac +++ b/configure.ac @@ -82,6 +82,7 @@ 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 ]) -- cgit v1.2.3 From 6d018ab933832e2d80bb1564c339d9fb18b57be2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 5 Sep 2009 22:45:49 -0700 Subject: Handle vageries of .telem files in ao-postflight Telem files have multiple entries of the same state, and sometimes long gaps between recordings. Deal with this as best as possible. Signed-off-by: Keith Packard --- ao-tools/ao-postflight/ao-postflight.c | 60 +++++++++++++++++++++------------- ao-tools/lib/cc-analyse.c | 8 ++--- ao-tools/lib/cc-logfile.c | 35 +++++++++++++++++++- ao-tools/lib/cc.h | 3 +- 4 files changed, 77 insertions(+), 29 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c index f0e2c2ae..9371f351 100644 --- a/ao-tools/ao-postflight/ao-postflight.c +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -81,43 +81,57 @@ analyse_flight(struct cc_flightraw *f) pres_i = cc_timedata_min(&f->pres, f->pres.data[0].time, f->pres.data[f->pres.num-1].time); - 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); + 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); - 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); + 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; + 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); - 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); + 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); - 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); + 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); + } } } diff --git a/ao-tools/lib/cc-analyse.c b/ao-tools/lib/cc-analyse.c index 6fd36cdc..fc8a8417 100644 --- a/ao-tools/lib/cc-analyse.c +++ b/ao-tools/lib/cc-analyse.c @@ -22,11 +22,11 @@ cc_timedata_min(struct cc_timedata *d, double min_time, double max_time) { int i; int set = 0; - int min_i; + int min_i = -1; double min; if (d->num == 0) - return 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) { @@ -42,11 +42,11 @@ cc_timedata_max(struct cc_timedata *d, double min_time, double max_time) { int i; double max; - int max_i; + int max_i = -1; int set = 0; if (d->num == 0) - return 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) { diff --git a/ao-tools/lib/cc-logfile.c b/ao-tools/lib/cc-logfile.c index 444ff089..4abf7eb6 100644 --- a/ao-tools/lib/cc-logfile.c +++ b/ao-tools/lib/cc-logfile.c @@ -18,6 +18,7 @@ #include "cc.h" #include #include +#include static int timedata_add(struct cc_timedata *data, double time, double value) @@ -35,8 +36,11 @@ timedata_add(struct cc_timedata *data, double time, double value) data->size = newsize; data->data = newdata; } - if (data->num && data->data[data->num-1].time > time) + 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++; @@ -66,6 +70,11 @@ gpsdata_add(struct cc_gpsdata *data, struct cc_gpselt *elt) 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; @@ -156,6 +165,29 @@ read_eeprom(const char *line, struct cc_flightraw *f, double *ground_pres, int * 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) { @@ -172,6 +204,7 @@ read_telem(const char *line, struct cc_flightraw *f) 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; diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 3975cf1b..57f80b8d 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -75,6 +75,7 @@ struct cc_timedata { int num; int size; struct cc_timedataelt *data; + double time_offset; }; @@ -92,8 +93,8 @@ struct cc_gpselt { struct cc_gpsdata { int num; int size; - double time_offset; struct cc_gpselt *data; + double time_offset; }; /* -- cgit v1.2.3 From 7a19aac5e881e635962a64fff73027ca2143b96f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Sep 2009 12:51:48 -0700 Subject: Add DSP code to filter data, allowing for integration/differentiation This adds the computation of speed from both accelerometer and barometer measurements and then presents a periodic flight profile using filtered data as a detailed flight record. Signed-off-by: Keith Packard --- ao-tools/ao-postflight/ao-postflight.c | 135 +++++++++-- ao-tools/lib/Makefile.am | 10 +- ao-tools/lib/cc-analyse.c | 57 +++++ ao-tools/lib/cc-dsp.c | 145 ++++++++++++ ao-tools/lib/cc-integrate.c | 78 +++++++ ao-tools/lib/cc-period.c | 64 +++++ ao-tools/lib/cc-process.c | 140 +++++++++++ ao-tools/lib/cc.h | 28 +++ ao-tools/lib/cephes.h | 122 ++++++++++ ao-tools/lib/chbevl.c | 81 +++++++ ao-tools/lib/cmath.h | 179 ++++++++++++++ ao-tools/lib/i0.c | 414 +++++++++++++++++++++++++++++++++ ao-tools/lib/mconf.h | 211 +++++++++++++++++ 13 files changed, 1639 insertions(+), 25 deletions(-) create mode 100644 ao-tools/lib/cc-dsp.c create mode 100644 ao-tools/lib/cc-integrate.c create mode 100644 ao-tools/lib/cc-period.c create mode 100644 ao-tools/lib/cc-process.c create mode 100644 ao-tools/lib/cephes.h create mode 100644 ao-tools/lib/chbevl.c create mode 100644 ao-tools/lib/cmath.h create mode 100644 ao-tools/lib/i0.c create mode 100644 ao-tools/lib/mconf.h (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c index 9371f351..c5814c93 100644 --- a/ao-tools/ao-postflight/ao-postflight.c +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -27,16 +27,6 @@ #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", @@ -51,20 +41,23 @@ static const char *state_names[] = { }; void -analyse_flight(struct cc_flightraw *f) +analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file) { double height; double accel; + double speed; double boost_start, boost_stop; double min_pres; int i; - int pres_i, accel_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; - printf ("Flight: %9d\nSerial: %9d\n", + fprintf(summary_file, "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; @@ -81,25 +74,37 @@ analyse_flight(struct cc_flightraw *f) pres_i = cc_timedata_min(&f->pres, f->pres.data[0].time, f->pres.data[f->pres.num-1].time); - if (pres_i) + 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 ("Max height: %9.2fm %9.2fft %9.2fs\n", + fprintf(summary_file, "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); + apogee = f->pres.data[pres_i].time; } + 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]; + fprintf(summary_file, "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); + } + } accel_i = cc_timedata_min(&f->accel, boost_start, boost_stop); - if (accel_i) + if (accel_i >= 0) { 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", + fprintf(summary_file, "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; @@ -109,50 +114,132 @@ analyse_flight(struct cc_flightraw *f) 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); + 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); 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", + fprintf(summary_file, "\tMax accel: %9.2fm/s² %9.2fg %9.2fs\n", accel, accel / 9.80665, (f->accel.data[accel_i].time - boost_start) / 100.0); } + if (cooked) { + if (state_start < apogee) { + speed_i = cc_perioddata_max(&cooked->accel_speed, state_start, state_stop); + if (speed_i >= 0) + speed = cooked->accel_speed.data[speed_i]; + } else { + speed_i = cc_perioddata_max(&cooked->pres_speed, state_start, state_stop); + if (speed_i >= 0) + speed = cooked->pres_speed.data[speed_i]; + } + if (speed_i >= 0) + fprintf(summary_file, "\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); + } 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", + fprintf(summary_file, "\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); } } + if (cooked && detail_file) { + double apogee_time; + double max_height = 0; + int i; + + for (i = 0; i < cooked->pres_pos.num; i++) { + if (cooked->pres_pos.data[i] > max_height) { + max_height = cooked->pres_pos.data[i]; + apogee_time = cooked->pres_pos.start + cooked->pres_pos.step * i; + } + } + fprintf(detail_file, "%9s %9s %9s %9s\n", + "time", "height", "speed", "accel"); + for (i = 0; i < cooked->pres_pos.num; i++) { + double time = (cooked->accel_accel.start + i * cooked->accel_accel.step - boost_start) / 100.0; + double accel = cooked->accel_accel.data[i]; + double pos = cooked->pres_pos.data[i]; + double speed; + if (cooked->pres_pos.start + cooked->pres_pos.step * i < apogee_time) + speed = cooked->accel_speed.data[i]; + else + speed = cooked->pres_speed.data[i]; + fprintf(detail_file, "%9.2f %9.2f %9.2f %9.2f\n", + time, pos, speed, accel); + } + } +} + +static const struct option options[] = { + { .name = "summary", .has_arg = 1, .val = 'S' }, + { .name = "detail", .has_arg = 1, .val = 'D' }, + { 0, 0, 0, 0}, +}; + +static void usage(char *program) +{ + fprintf(stderr, "usage: %s [--summary=] [--detail=serial) raw->serial = serial; - analyse_flight(raw); + analyse_flight(raw, summary_file, detail_file); cc_flightraw_free(raw); } return ret; diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index e682f757..79972f46 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -16,7 +16,11 @@ libao_tools_a_SOURCES = \ ccdbg-state.c \ cc-analyse.c \ cc-convert.c \ + cc-dsp.c \ cc-log.c \ + cc-integrate.c \ + cc-period.c \ + cc-process.c \ cc-usb.c \ cc-usb.h \ cc.h \ @@ -27,4 +31,8 @@ libao_tools_a_SOURCES = \ cc-logfile.c \ cc-telem.c \ cp-usb-async.c \ - cp-usb-async.h + cp-usb-async.h \ + i0.c \ + chbevl.c \ + mconf.h \ + cephes.h diff --git a/ao-tools/lib/cc-analyse.c b/ao-tools/lib/cc-analyse.c index fc8a8417..0e020115 100644 --- a/ao-tools/lib/cc-analyse.c +++ b/ao-tools/lib/cc-analyse.c @@ -16,6 +16,7 @@ */ #include "cc.h" +#include int cc_timedata_min(struct cc_timedata *d, double min_time, double max_time) @@ -56,3 +57,59 @@ cc_timedata_max(struct cc_timedata *d, double min_time, double max_time) } return max_i; } + +int +cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time) +{ + int start, stop; + int i; + double min; + int min_i; + + if (d->num == 0) + return -1; + start = (int) ceil((min_time - d->start) / d->step); + if (start < 0) + start = 0; + stop = (int) floor((max_time - d->start) / d->step); + if (stop >= d->num) + stop = d->num - 1; + if (stop < start) + return -1; + min = d->data[start]; + min_i = start; + for (i = start + 1; i <= stop; i++) + if (d->data[i] < min) { + min = d->data[i]; + min_i = i; + } + return min_i; +} + +int +cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time) +{ + int start, stop; + int i; + double max; + int max_i; + + if (d->num == 0) + return -1; + start = (int) ceil((min_time - d->start) / d->step); + if (start < 0) + start = 0; + stop = (int) floor((max_time - d->start) / d->step); + if (stop >= d->num) + stop = d->num - 1; + if (stop < start) + return -1; + max = d->data[start]; + max_i = start; + for (i = start + 1; i <= stop; i++) + if (fabs(d->data[i]) > max) { + max = fabs(d->data[i]); + max_i = i; + } + return max_i; +} diff --git a/ao-tools/lib/cc-dsp.c b/ao-tools/lib/cc-dsp.c new file mode 100644 index 00000000..518c1a68 --- /dev/null +++ b/ao-tools/lib/cc-dsp.c @@ -0,0 +1,145 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 "cephes.h" +#include +#include + +static inline double sqr (double x) { return x * x; } + +/* + * Kaiser Window digital filter + */ + +#if 0 +/* not used in this program */ +static double highpass (double n, double m, double wc) +{ + double alpha = m/2; + double dist; + + dist = n - alpha; + if (dist == 0) + return (M_PI/2 - wc) / M_PI; + return -sin(dist * (M_PI/2-wc)) / (M_PI * dist); +} +#endif + +static double lowpass (double n, double m, double wc) +{ + double alpha = m/2; + double dist; + dist = n - alpha; + if (dist == 0) + return wc / M_PI; + return sin (wc * dist) / (M_PI * dist); +} + +static double kaiser (double n, double m, double beta) +{ + double alpha = m / 2; + return i0 (beta * sqrt (1 - sqr((n - alpha) / alpha))) / i0(beta); +} + +static double beta (double A) +{ + if (A > 50) + return 0.1102 * (A - 8.7); + else if (A >= 21) + return 0.5842 * pow((A - 21), 0.4) + 0.07886 * (A - 21); + else + return 0.0; +} + +static int M (double A, double delta_omega) +{ + if (A > 21) + return ceil ((A - 7.95) / (2.285 * delta_omega)); + else + return ceil(5.79 / delta_omega); +} + +struct filter_param { + double omega_pass; + double delta_omega; + double A; + double beta; + int M; +} filter_param_t; + +static struct filter_param +filter (double omega_pass, double omega_stop, double error) +{ + struct filter_param p; + p.omega_pass = omega_pass; + p.delta_omega = omega_stop - omega_pass; + p.A = -20 * log10 (error); + p.beta = beta (p.A); + p.M = M (p.A, p.delta_omega); + if ((p.M & 1) == 1) + p.M++; + return p; +} + +static double * +make_low_pass_filter(double omega_pass, double omega_stop, double error, int *length_p) +{ + struct filter_param p = filter(omega_pass, omega_stop, error); + int length; + int n; + double *lpf; + + length = p.M + 1; + lpf = calloc (length, sizeof(double)); + for (n = 0; n < length; n++) + lpf[n] = lowpass(n, p.M, omega_pass) * kaiser(n, p.M, p.beta); + *length_p = length; + return lpf; +} + +static double * +convolve(double *d, int d_len, double *e, int e_len) +{ + int w = (e_len - 1) / 2; + int n; + double *con = calloc (d_len, sizeof (double)); + + for (n = 0; n < d_len; n++) { + double v = 0; + int o; + for (o = -w; o <= w; o++) { + int p = n + o; + double sample = p < 0 ? d[0] : p >= d_len ? d[d_len-1] : d[p]; + v += sample * e[o + w]; + } + con[n] = v; + } + return con; +} + +double * +cc_low_pass(double *data, int data_len, double omega_pass, double omega_stop, double error) +{ + int fir_len; + double *fir = make_low_pass_filter(omega_pass, omega_stop, error, &fir_len); + double *result; + + result = convolve(data, data_len, fir, fir_len); + free(fir); + return result; +} diff --git a/ao-tools/lib/cc-integrate.c b/ao-tools/lib/cc-integrate.c new file mode 100644 index 00000000..08ca295c --- /dev/null +++ b/ao-tools/lib/cc-integrate.c @@ -0,0 +1,78 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 + +struct cc_timedata * +cc_timedata_convert(struct cc_timedata *d, double (*f)(double v, double a), double a) +{ + struct cc_timedata *r; + int n; + + r = calloc (1, sizeof (struct cc_timedata)); + r->num = d->num; + r->size = d->num; + r->data = calloc (r->size, sizeof (struct cc_timedataelt)); + r->time_offset = d->time_offset; + for (n = 0; n < d->num; n++) { + r->data[n].time = d->data[n].time; + r->data[n].value = f(d->data[n].value, a); + } + return r; +} + +struct cc_timedata * +cc_timedata_integrate(struct cc_timedata *d) +{ + struct cc_timedata *i; + int n; + + i = calloc (1, sizeof (struct cc_timedata)); + i->num = d->num; + i->size = d->num; + i->data = calloc (i->size, sizeof (struct cc_timedataelt)); + i->time_offset = d->time_offset; + for (n = 0; n < d->num; n++) { + i->data[n].time = d->data[n].time; + if (n == 0) { + i->data[n].value = 0; + } else { + i->data[n].value = i->data[n-1].value + + (d->data[n].value + d->data[n-1].value) / 2 * + ((d->data[n].time - d->data[n-1].time) / 100.0); + } + } + return i; +} + +struct cc_perioddata * +cc_perioddata_differentiate(struct cc_perioddata *i) +{ + struct cc_perioddata *d; + int n; + + d = calloc (1, sizeof (struct cc_perioddata)); + d->num = i->num; + d->start = i->start; + d->step = i->step; + d->data = calloc (d->num, sizeof(double)); + for (n = 1; n < d->num; n++) + d->data[n] = (i->data[n] - i->data[n-1]) / i->step; + d->data[0] = d->data[1]; + return d; +} diff --git a/ao-tools/lib/cc-period.c b/ao-tools/lib/cc-period.c new file mode 100644 index 00000000..c74cf9dc --- /dev/null +++ b/ao-tools/lib/cc-period.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 + +struct cc_perioddata * +cc_period_make(struct cc_timedata *td, double start_time, double stop_time) +{ + int len = stop_time - start_time + 1; + struct cc_perioddata *pd; + int i; + double prev_time; + double next_time; + double interval; + + pd = calloc(1, sizeof (struct cc_perioddata)); + pd->start = start_time; + pd->step = 1; + pd->num = len; + pd->data = calloc(len, sizeof(double)); + prev_time = start_time; + for (i = 0; i < td->num; i++) { + if (start_time <= td->data[i].time && td->data[i].time <= stop_time) { + int pos = td->data[i].time - start_time; + + if (i < td->num - 1 && td->data[i+1].time < stop_time) + next_time = (td->data[i].time + td->data[i+1].time) / 2.0; + else + next_time = stop_time; + interval = next_time - prev_time; + pd->data[pos] = td->data[i].value * interval; + prev_time = next_time; + } + } + return pd; +} + +struct cc_perioddata * +cc_period_low_pass(struct cc_perioddata *raw, double omega_pass, double omega_stop, double error) +{ + struct cc_perioddata *filtered; + + filtered = calloc (1, sizeof (struct cc_perioddata)); + filtered->start = raw->start; + filtered->step = raw->step; + filtered->num = raw->num; + filtered->data = cc_low_pass(raw->data, raw->num, omega_pass, omega_stop, error); + return filtered; +} diff --git a/ao-tools/lib/cc-process.c b/ao-tools/lib/cc-process.c new file mode 100644 index 00000000..e906b635 --- /dev/null +++ b/ao-tools/lib/cc-process.c @@ -0,0 +1,140 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include + +static void +cook_timed(struct cc_timedata *td, struct cc_perioddata *pd, + double start_time, double stop_time, + double omega_pass, double omega_stop, double error) +{ + struct cc_perioddata *unfiltered, *filtered; + + unfiltered = cc_period_make(td, start_time, stop_time); + filtered = cc_period_low_pass (unfiltered, omega_pass, omega_stop, error); + *pd = *filtered; + free (filtered); + free (unfiltered->data); + free (unfiltered); + free (td->data); + free (td); +} + +static double +barometer_to_altitude(double b, double pad_alt) +{ + return cc_barometer_to_altitude(b) - pad_alt; +} + +struct cc_flightcooked * +cc_flight_cook(struct cc_flightraw *raw) +{ + struct cc_flightcooked *cooked; + double flight_start; + double flight_stop; + int start_set = 0; + int stop_set = 0; + int i; + struct cc_timedata *accel; + struct cc_timedata *accel_speed; + struct cc_timedata *accel_pos; + struct cc_timedata *pres; + struct cc_perioddata *pres_speed; + struct cc_perioddata *pres_accel; + + if (raw->accel.num == 0) + return NULL; + + cooked = calloc (1, sizeof (struct cc_flightcooked)); + + /* + * Find flight start and stop times by looking at + * state transitions. The stop time is set to the time + * of landing, which may be long after it landed (due to radio + * issues). Refine this value by looking through the sensor data + */ + for (i = 0; i < raw->state.num; i++) { + if (!start_set && raw->state.data[i].value > ao_flight_pad) { + flight_start = raw->state.data[i].time; + start_set = 1; + } + if (!stop_set && raw->state.data[i].value > ao_flight_main) { + flight_stop = raw->state.data[i].time; + stop_set = 1; + } + } + + if (!start_set) + flight_start = raw->accel.data[0].time; + if (stop_set) { + for (i = 0; i < raw->accel.num - 1; i++) { + if (raw->accel.data[i+1].time >= flight_stop) { + flight_stop = raw->accel.data[i].time; + break; + } + } + } else { + flight_stop = raw->accel.data[raw->accel.num-1].time; + } + + /* Integrate the accelerometer data to get speed and position */ + accel = cc_timedata_convert(&raw->accel, cc_accelerometer_to_acceleration, raw->ground_accel); + accel_speed = cc_timedata_integrate(accel); + accel_pos = cc_timedata_integrate(accel_speed); + +#define ACCEL_OMEGA_PASS (2 * M_PI * 5 / 100) +#define ACCEL_OMEGA_STOP (2 * M_PI * 8 / 100) +#define BARO_OMEGA_PASS (2 * M_PI * .5 / 100) +#define BARO_OMEGA_STOP (2 * M_PI * 1 / 100) +#define FILTER_ERROR (1e-8) + + cook_timed(accel, &cooked->accel_accel, + flight_start, flight_stop, + ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR); + cook_timed(accel_speed, &cooked->accel_speed, + flight_start, flight_stop, + ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR); + cook_timed(accel_pos, &cooked->accel_pos, + flight_start, flight_stop, + ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR); + + /* Filter the pressure data */ + pres = cc_timedata_convert(&raw->pres, barometer_to_altitude, + cc_barometer_to_altitude(raw->ground_pres)); + cook_timed(pres, &cooked->pres_pos, + flight_start, flight_stop, + BARO_OMEGA_PASS, BARO_OMEGA_STOP, FILTER_ERROR); + /* differentiate twice to get to acceleration */ + pres_speed = cc_perioddata_differentiate(&cooked->pres_pos); + pres_accel = cc_perioddata_differentiate(pres_speed); + + cooked->pres_speed = *pres_speed; + free(pres_speed); + cooked->pres_accel = *pres_accel; + free(pres_accel); + + /* copy state */ + cooked->state.num = raw->state.num; + cooked->state.size = raw->state.num; + cooked->state.data = calloc(cooked->state.num, sizeof (struct cc_timedataelt)); + memcpy(cooked->state.data, raw->state.data, cooked->state.num * sizeof (struct cc_timedataelt)); + cooked->state.time_offset = raw->state.time_offset; + return cooked; +} diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 57f80b8d..356794e0 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -268,4 +268,32 @@ 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); +int +cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time); + +int +cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time); + +double * +cc_low_pass(double *data, int data_len, double omega_pass, double omega_stop, double error); + +struct cc_perioddata * +cc_period_make(struct cc_timedata *td, double start_time, double stop_time); + +struct cc_perioddata * +cc_period_low_pass(struct cc_perioddata *raw, double omega_pass, double omega_stop, double error); + +struct cc_timedata * +cc_timedata_convert(struct cc_timedata *d, double (*f)(double v, double a), double a); + +struct cc_timedata * +cc_timedata_integrate(struct cc_timedata *d); + +struct cc_perioddata * +cc_perioddata_differentiate(struct cc_perioddata *i); + +struct cc_flightcooked * +cc_flight_cook(struct cc_flightraw *raw); + + #endif /* _CC_H_ */ diff --git a/ao-tools/lib/cephes.h b/ao-tools/lib/cephes.h new file mode 100644 index 00000000..f8ec264f --- /dev/null +++ b/ao-tools/lib/cephes.h @@ -0,0 +1,122 @@ +/* + * This file comes from the cephes math library, which was + * released under the GPLV2+ license as a part of the Debian labplot + * package (I've included the GPLV2 license reference here to make + * this clear) - Keith Packard + * + * Cephes Math Library Release 2.0: April, 1987 + * Copyright 1984, 1987 by Stephen L. Moshier + * Direct inquiries to 30 Frost Street, Cambridge, MA 02140 + * + * 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. + */ +/* + * Prototypes of Cephes functions + */ + +#ifndef _CEPHES_H_ +#define _CEPHES_H_ + +/* Variable for error reporting. See mtherr.c. */ +extern int merror; + +#if 0 +extern int airy ( double x, double *ai, double *aip, double *bi, double *bip ); +extern double beta ( double a, double b ); +extern double lbeta ( double a, double b ); +extern double chdtrc ( double df, double x ); +extern double chdtr ( double df, double x ); +extern double chdtri ( double df, double y ); +extern double dawsn ( double xx ); +extern double ellie ( double phi, double m ); +extern double ellik ( double phi, double m ); +extern double ellpe ( double x ); +extern double ellpk ( double x ); +extern double expn ( int n, double x ); +extern double fac ( int i ); +extern double fdtrc ( int ia, int ib, double x ); +extern double fdtr ( int ia, int ib, double x ); +extern double fdtri ( int ia, int ib, double y ); +extern double frexp ( double x, int *pw2 ); +extern double ldexp ( double x, int pw2 ); +extern int fresnl ( double xxa, double *ssa, double *cca ); +extern double gdtr ( double a, double b, double x ); +extern double gdtrc ( double a, double b, double x ); +extern double hyp2f0 ( double a, double b, double x, int type, double *err ); +extern double hyp2f1 ( double a, double b, double c, double x ); +extern double hyperg ( double a, double b, double x ); +#endif +extern double i0 ( double x ); +extern double i0e ( double x ); +#if 0 +extern double i1 ( double x ); +extern double i1e ( double x ); +extern double iv ( double v, double x ); +extern double igamc ( double a, double x ); +extern double igam ( double a, double x ); +extern double igami ( double a, double y0_ ); +extern double incbet ( double aa, double bb, double xx ); +extern double incbi ( double aa, double bb, double yy0 ); +extern double jv ( double n, double x ); +extern double k0 ( double x ); +extern double k0e ( double x ); +extern double k1 ( double x ); +extern double k1e ( double x ); +extern double kn ( int nn, double x ); +extern int mtherr ( char *name, int code ); +extern double ndtr ( double a ); +extern double ndtri ( double y0_ ); +extern double pdtrc ( int k, double m ); +extern double pdtr ( int k, double m ); +extern double pdtri ( int k, double y ); +extern double psi ( double x ); +extern void revers ( double y[], double x[], int n ); +extern double true_gamma ( double x ); +extern double rgamma ( double x ); +extern int shichi ( double x, double *si, double *ci ); +extern int sici ( double x, double *si, double *ci ); +extern double spence ( double x ); +extern double stdtr ( int k, double t ); +extern double stdtri ( int k, double p ); +extern double onef2 ( double a, double b, double c, double x, double *err ); +extern double threef0 ( double a, double b, double c, double x, double *err ); +extern double struve ( double v, double x ); +extern double log1p ( double x ); +extern double expm1 ( double x ); +extern double cosm1 ( double x ); +extern double yv ( double v, double x ); +extern double zeta ( double x, double q ); +extern double zetac ( double x ); + +#endif +extern double chbevl ( double x, void *P, int n ); +#if 0 +extern double polevl ( double x, void *P, int n ); +extern double p1evl ( double x, void *P, int n ); + +/* polyn.c */ +extern void polini ( int maxdeg ); +extern void polprt ( double a[], int na, int d ); +extern void polclr ( double *a, int n ); +extern void polmov ( double *a, int na, double *b ); +extern void polmul ( double a[], int na, double b[], int nb, double c[] ); +extern void poladd ( double a[], int na, double b[], int nb, double c[] ); +extern void polsub ( double a[], int na, double b[], int nb, double c[] ); +extern int poldiv ( double a[], int na, double b[], int nb, double c[] ); +extern void polsbt ( double a[], int na, double b[], int nb, double c[] ); +extern double poleva ( double a[], int na, double x ); + +#endif + +#endif /* _CEPHES_H_ */ diff --git a/ao-tools/lib/chbevl.c b/ao-tools/lib/chbevl.c new file mode 100644 index 00000000..22892413 --- /dev/null +++ b/ao-tools/lib/chbevl.c @@ -0,0 +1,81 @@ +/* chbevl.c + * + * Evaluate Chebyshev series + * + * + * + * SYNOPSIS: + * + * int N; + * double x, y, coef[N], chebevl(); + * + * y = chbevl( x, coef, N ); + * + * + * + * DESCRIPTION: + * + * Evaluates the series + * + * N-1 + * - ' + * y = > coef[i] T (x/2) + * - i + * i=0 + * + * of Chebyshev polynomials Ti at argument x/2. + * + * Coefficients are stored in reverse order, i.e. the zero + * order term is last in the array. Note N is the number of + * coefficients, not the order. + * + * If coefficients are for the interval a to b, x must + * have been transformed to x -> 2(2x - b - a)/(b-a) before + * entering the routine. This maps x from (a, b) to (-1, 1), + * over which the Chebyshev polynomials are defined. + * + * If the coefficients are for the inverted interval, in + * which (a, b) is mapped to (1/b, 1/a), the transformation + * required is x -> 2(2ab/x - b - a)/(b-a). If b is infinity, + * this becomes x -> 4a/x - 1. + * + * + * + * SPEED: + * + * Taking advantage of the recurrence properties of the + * Chebyshev polynomials, the routine requires one more + * addition per loop than evaluating a nested polynomial of + * the same degree. + * + */ + /* chbevl.c */ + +/* +Cephes Math Library Release 2.0: April, 1987 +Copyright 1985, 1987 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ + +#include "cephes.h" + +double chbevl(double x,void* array,int n ) +{ +double b0, b1, b2, *p; +int i; + +p = (double *) array; +b0 = *p++; +b1 = 0.0; +i = n - 1; + +do + { + b2 = b1; + b1 = b0; + b0 = x * b1 - b2 + *p++; + } +while( --i ); + +return( 0.5*(b0-b2) ); +} diff --git a/ao-tools/lib/cmath.h b/ao-tools/lib/cmath.h new file mode 100644 index 00000000..2751aecf --- /dev/null +++ b/ao-tools/lib/cmath.h @@ -0,0 +1,179 @@ +/* + * Grace - GRaphing, Advanced Computation and Exploration of data + * + * Home page: http://plasma-gate.weizmann.ac.il/Grace/ + * + * Copyright (c) 1991-1995 Paul J Turner, Portland, OR + * Copyright (c) 1996-2000 Grace Development Team + * + * Maintained by Evgeny Stambulchik + * + * + * All Rights Reserved + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* cmath.h - replacement for math.h or missing in libm functions */ + +#if defined(HAVE_MATH_H) +# include +#endif +#if defined(HAVE_FLOAT_H) +# include +#endif +#if defined(HAVE_IEEEFP_H) +# include +#endif + +#ifndef __GRACE_SOURCE_ + +#ifndef MACHEP +extern double MACHEP; +#endif + +#ifndef UFLOWTHRESH +extern double UFLOWTHRESH; +#endif + +#ifndef MAXNUM +extern double MAXNUM; +#endif + +#endif /* __GRACE_SOURCE_ */ + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +#ifndef M_SQRT2 +# define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#endif + +#ifndef M_SQRT1_2 +# define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ +#endif + +#ifndef M_SQRT1_3 +# define M_SQRT1_3 0.57735026918962576451 /* 1/sqrt(3) */ +#endif + +#ifndef HAVE_HYPOT +# define hypot(x, y) sqrt((x)*(x) + (y)*(y)) +#endif + +extern double round ( double x ); +#ifndef HAVE_RINT +# define rint round +#else +# ifndef HAVE_RINT_DECL +extern double rint ( double x ); +# endif +#endif + +#ifndef HAVE_CBRT_DECL +extern double cbrt ( double x ); +#endif + +/* Cygnus gnuwin32 has the log2 macro */ +#ifdef log2 +# undef log2 +#endif + +#ifndef HAVE_LOG2_DECL +extern double log2 ( double x ); +#endif + +#ifndef HAVE_LGAMMA +extern int sgngam; +# define lgamma lgam +# define signgam sgngam +extern double lgam ( double x ); +#else +# ifndef HAVE_LGAMMA_DECL +extern double lgamma ( double x ); +# endif +# ifndef HAVE_SIGNGAM_DECL +extern int signgam; +# endif +# define lgam lgamma +# define sgngam signgam +#endif + +#ifndef HAVE_ACOSH_DECL +extern double acosh ( double x ); +#endif + +#ifndef HAVE_ASINH_DECL +extern double asinh ( double x ); +#endif + +#ifndef HAVE_ATANH_DECL +extern double atanh ( double x ); +#endif + +#ifndef HAVE_ERF_DECL +extern double erf ( double x ); +#endif + +#ifndef HAVE_ERFC_DECL +extern double erfc ( double x ); +#endif + +#ifndef HAVE_Y0_DECL +extern double y0 ( double x ); +#endif +#ifndef HAVE_Y1_DECL +extern double y1 ( double x ); +#endif +#ifndef HAVE_YN_DECL +extern double yn ( int n, double x ); +#endif +#ifndef HAVE_J0_DECL +extern double j0 ( double x ); +#endif +#ifndef HAVE_J1_DECL +extern double j1 ( double x ); +#endif +#ifndef HAVE_JN_DECL +extern double jn ( int n, double x ); +#endif + +/* isfinite is a macro */ +#ifdef isfinite +# define HAVE_ISFINITE_MACRO +#endif + +#ifndef HAVE_FINITE +# define finite isfinite +# if !defined(HAVE_ISFINITE_DECL) && !defined(HAVE_ISFINITE_MACRO) +extern int isfinite ( double x ); +# endif +#else +# ifndef HAVE_FINITE_DECL +extern int finite ( double x ); +# endif +#endif + +#ifndef HAVE_ISNAN_DECL +#ifdef __FreeBSD__ +# include +# if __FreeBSD_version < 500100 +extern int isnan ( double x ); +# endif +#endif +#else +extern int isnan ( double x ); +#endif diff --git a/ao-tools/lib/i0.c b/ao-tools/lib/i0.c new file mode 100644 index 00000000..6f7b5a57 --- /dev/null +++ b/ao-tools/lib/i0.c @@ -0,0 +1,414 @@ +/* + * This file comes from the cephes math library, which was + * released under the GPLV2+ license as a part of the Debian labplot + * package (I've included the GPLV2 license reference here to make + * this clear) - Keith Packard + * + * Cephes Math Library Release 2.0: April, 1987 + * Copyright 1984, 1987 by Stephen L. Moshier + * Direct inquiries to 30 Frost Street, Cambridge, MA 02140 + * + * 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. + */ + +/* i0.c + * + * Modified Bessel function of order zero + * + * + * + * SYNOPSIS: + * + * double x, y, i0(); + * + * y = i0( x ); + * + * + * + * DESCRIPTION: + * + * Returns modified Bessel function of order zero of the + * argument. + * + * The function is defined as i0(x) = j0( ix ). + * + * The range is partitioned into the two intervals [0,8] and + * (8, infinity). Chebyshev polynomial expansions are employed + * in each interval. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC 0,30 6000 8.2e-17 1.9e-17 + * IEEE 0,30 30000 5.8e-16 1.4e-16 + * + */ + /* i0e.c + * + * Modified Bessel function of order zero, + * exponentially scaled + * + * + * + * SYNOPSIS: + * + * double x, y, i0e(); + * + * y = i0e( x ); + * + * + * + * DESCRIPTION: + * + * Returns exponentially scaled modified Bessel function + * of order zero of the argument. + * + * The function is defined as i0e(x) = exp(-|x|) j0( ix ). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0,30 30000 5.4e-16 1.2e-16 + * See i0(). + * + */ + +/* i0.c */ + + +/* +Cephes Math Library Release 2.0: April, 1987 +Copyright 1984, 1987 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ + +#include +#include "mconf.h" +#include "cephes.h" + +/* Chebyshev coefficients for exp(-x) I0(x) + * in the interval [0,8]. + * + * lim(x->0){ exp(-x) I0(x) } = 1. + */ + +#ifdef UNK +static double A[] = +{ +-4.41534164647933937950E-18, + 3.33079451882223809783E-17, +-2.43127984654795469359E-16, + 1.71539128555513303061E-15, +-1.16853328779934516808E-14, + 7.67618549860493561688E-14, +-4.85644678311192946090E-13, + 2.95505266312963983461E-12, +-1.72682629144155570723E-11, + 9.67580903537323691224E-11, +-5.18979560163526290666E-10, + 2.65982372468238665035E-9, +-1.30002500998624804212E-8, + 6.04699502254191894932E-8, +-2.67079385394061173391E-7, + 1.11738753912010371815E-6, +-4.41673835845875056359E-6, + 1.64484480707288970893E-5, +-5.75419501008210370398E-5, + 1.88502885095841655729E-4, +-5.76375574538582365885E-4, + 1.63947561694133579842E-3, +-4.32430999505057594430E-3, + 1.05464603945949983183E-2, +-2.37374148058994688156E-2, + 4.93052842396707084878E-2, +-9.49010970480476444210E-2, + 1.71620901522208775349E-1, +-3.04682672343198398683E-1, + 6.76795274409476084995E-1 +}; +#endif + +#ifdef DEC +static unsigned short A[] = { +0121642,0162671,0004646,0103567, +0022431,0115424,0135755,0026104, +0123214,0023533,0110365,0156635, +0023767,0033304,0117662,0172716, +0124522,0100426,0012277,0157531, +0025254,0155062,0054461,0030465, +0126010,0131143,0013560,0153604, +0026517,0170577,0006336,0114437, +0127227,0162253,0152243,0052734, +0027724,0142766,0061641,0160200, +0130416,0123760,0116564,0125262, +0031066,0144035,0021246,0054641, +0131537,0053664,0060131,0102530, +0032201,0155664,0165153,0020652, +0132617,0061434,0074423,0176145, +0033225,0174444,0136147,0122542, +0133624,0031576,0056453,0020470, +0034211,0175305,0172321,0041314, +0134561,0054462,0147040,0165315, +0035105,0124333,0120203,0162532, +0135427,0013750,0174257,0055221, +0035726,0161654,0050220,0100162, +0136215,0131361,0000325,0041110, +0036454,0145417,0117357,0017352, +0136702,0072367,0104415,0133574, +0037111,0172126,0072505,0014544, +0137302,0055601,0120550,0033523, +0037457,0136543,0136544,0043002, +0137633,0177536,0001276,0066150, +0040055,0041164,0100655,0010521 +}; +#endif + +#ifdef IBMPC +static unsigned short A[] = { +0xd0ef,0x2134,0x5cb7,0xbc54, +0xa589,0x977d,0x3362,0x3c83, +0xbbb4,0x721e,0x84eb,0xbcb1, +0x5eba,0x93f6,0xe6d8,0x3cde, +0xfbeb,0xc297,0x5022,0xbd0a, +0x2627,0x4b26,0x9b46,0x3d35, +0x1af0,0x62ee,0x164c,0xbd61, +0xd324,0xe19b,0xfe2f,0x3d89, +0x6abc,0x7a94,0xfc95,0xbdb2, +0x3c10,0xcc74,0x98be,0x3dda, +0x9556,0x13ae,0xd4fe,0xbe01, +0xcb34,0xa454,0xd903,0x3e26, +0x30ab,0x8c0b,0xeaf6,0xbe4b, +0x6435,0x9d4d,0x3b76,0x3e70, +0x7f8d,0x8f22,0xec63,0xbe91, +0xf4ac,0x978c,0xbf24,0x3eb2, +0x6427,0xcba5,0x866f,0xbed2, +0x2859,0xbe9a,0x3f58,0x3ef1, +0x1d5a,0x59c4,0x2b26,0xbf0e, +0x7cab,0x7410,0xb51b,0x3f28, +0xeb52,0x1f15,0xe2fd,0xbf42, +0x100e,0x8a12,0xdc75,0x3f5a, +0xa849,0x201a,0xb65e,0xbf71, +0xe3dd,0xf3dd,0x9961,0x3f85, +0xb6f0,0xf121,0x4e9e,0xbf98, +0xa32d,0xcea8,0x3e8a,0x3fa9, +0x06ea,0x342d,0x4b70,0xbfb8, +0x88c0,0x77ac,0xf7ac,0x3fc5, +0xcd8d,0xc057,0x7feb,0xbfd3, +0xa22a,0x9035,0xa84e,0x3fe5, +}; +#endif + +#ifdef MIEEE +static unsigned short A[] = { +0xbc54,0x5cb7,0x2134,0xd0ef, +0x3c83,0x3362,0x977d,0xa589, +0xbcb1,0x84eb,0x721e,0xbbb4, +0x3cde,0xe6d8,0x93f6,0x5eba, +0xbd0a,0x5022,0xc297,0xfbeb, +0x3d35,0x9b46,0x4b26,0x2627, +0xbd61,0x164c,0x62ee,0x1af0, +0x3d89,0xfe2f,0xe19b,0xd324, +0xbdb2,0xfc95,0x7a94,0x6abc, +0x3dda,0x98be,0xcc74,0x3c10, +0xbe01,0xd4fe,0x13ae,0x9556, +0x3e26,0xd903,0xa454,0xcb34, +0xbe4b,0xeaf6,0x8c0b,0x30ab, +0x3e70,0x3b76,0x9d4d,0x6435, +0xbe91,0xec63,0x8f22,0x7f8d, +0x3eb2,0xbf24,0x978c,0xf4ac, +0xbed2,0x866f,0xcba5,0x6427, +0x3ef1,0x3f58,0xbe9a,0x2859, +0xbf0e,0x2b26,0x59c4,0x1d5a, +0x3f28,0xb51b,0x7410,0x7cab, +0xbf42,0xe2fd,0x1f15,0xeb52, +0x3f5a,0xdc75,0x8a12,0x100e, +0xbf71,0xb65e,0x201a,0xa849, +0x3f85,0x9961,0xf3dd,0xe3dd, +0xbf98,0x4e9e,0xf121,0xb6f0, +0x3fa9,0x3e8a,0xcea8,0xa32d, +0xbfb8,0x4b70,0x342d,0x06ea, +0x3fc5,0xf7ac,0x77ac,0x88c0, +0xbfd3,0x7feb,0xc057,0xcd8d, +0x3fe5,0xa84e,0x9035,0xa22a +}; +#endif + + +/* Chebyshev coefficients for exp(-x) sqrt(x) I0(x) + * in the inverted interval [8,infinity]. + * + * lim(x->inf){ exp(-x) sqrt(x) I0(x) } = 1/sqrt(2pi). + */ + +#ifdef UNK +static double B[] = +{ +-7.23318048787475395456E-18, +-4.83050448594418207126E-18, + 4.46562142029675999901E-17, + 3.46122286769746109310E-17, +-2.82762398051658348494E-16, +-3.42548561967721913462E-16, + 1.77256013305652638360E-15, + 3.81168066935262242075E-15, +-9.55484669882830764870E-15, +-4.15056934728722208663E-14, + 1.54008621752140982691E-14, + 3.85277838274214270114E-13, + 7.18012445138366623367E-13, +-1.79417853150680611778E-12, +-1.32158118404477131188E-11, +-3.14991652796324136454E-11, + 1.18891471078464383424E-11, + 4.94060238822496958910E-10, + 3.39623202570838634515E-9, + 2.26666899049817806459E-8, + 2.04891858946906374183E-7, + 2.89137052083475648297E-6, + 6.88975834691682398426E-5, + 3.36911647825569408990E-3, + 8.04490411014108831608E-1 +}; +#endif + +#ifdef DEC +static unsigned short B[] = { +0122005,0066672,0123124,0054311, +0121662,0033323,0030214,0104602, +0022515,0170300,0113314,0020413, +0022437,0117350,0035402,0007146, +0123243,0000135,0057220,0177435, +0123305,0073476,0144106,0170702, +0023777,0071755,0017527,0154373, +0024211,0052214,0102247,0033270, +0124454,0017763,0171453,0012322, +0125072,0166316,0075505,0154616, +0024612,0133770,0065376,0025045, +0025730,0162143,0056036,0001632, +0026112,0015077,0150464,0063542, +0126374,0101030,0014274,0065457, +0127150,0077271,0125763,0157617, +0127412,0104350,0040713,0120445, +0027121,0023765,0057500,0001165, +0030407,0147146,0003643,0075644, +0031151,0061445,0044422,0156065, +0031702,0132224,0003266,0125551, +0032534,0000076,0147153,0005555, +0033502,0004536,0004016,0026055, +0034620,0076433,0142314,0171215, +0036134,0146145,0013454,0101104, +0040115,0171425,0062500,0047133 +}; +#endif + +#ifdef IBMPC +static unsigned short B[] = { +0x8b19,0x54ca,0xadb7,0xbc60, +0x9130,0x6611,0x46da,0xbc56, +0x8421,0x12d9,0xbe18,0x3c89, +0x41cd,0x0760,0xf3dd,0x3c83, +0x1fe4,0xabd2,0x600b,0xbcb4, +0xde38,0xd908,0xaee7,0xbcb8, +0xfb1f,0xa3ea,0xee7d,0x3cdf, +0xe6d7,0x9094,0x2a91,0x3cf1, +0x629a,0x7e65,0x83fe,0xbd05, +0xbb32,0xcf68,0x5d99,0xbd27, +0xc545,0x0d5f,0x56ff,0x3d11, +0xc073,0x6b83,0x1c8c,0x3d5b, +0x8cec,0xfa26,0x4347,0x3d69, +0x8d66,0x0317,0x9043,0xbd7f, +0x7bf2,0x357e,0x0fd7,0xbdad, +0x7425,0x0839,0x511d,0xbdc1, +0x004f,0xabe8,0x24fe,0x3daa, +0x6f75,0xc0f4,0xf9cc,0x3e00, +0x5b87,0xa922,0x2c64,0x3e2d, +0xd56d,0x80d6,0x5692,0x3e58, +0x616e,0xd9cd,0x8007,0x3e8b, +0xc586,0xc101,0x412b,0x3ec8, +0x9e52,0x7899,0x0fa3,0x3f12, +0x9049,0xa2e5,0x998c,0x3f6b, +0x09cb,0xaca8,0xbe62,0x3fe9 +}; +#endif + +#ifdef MIEEE +static unsigned short B[] = { +0xbc60,0xadb7,0x54ca,0x8b19, +0xbc56,0x46da,0x6611,0x9130, +0x3c89,0xbe18,0x12d9,0x8421, +0x3c83,0xf3dd,0x0760,0x41cd, +0xbcb4,0x600b,0xabd2,0x1fe4, +0xbcb8,0xaee7,0xd908,0xde38, +0x3cdf,0xee7d,0xa3ea,0xfb1f, +0x3cf1,0x2a91,0x9094,0xe6d7, +0xbd05,0x83fe,0x7e65,0x629a, +0xbd27,0x5d99,0xcf68,0xbb32, +0x3d11,0x56ff,0x0d5f,0xc545, +0x3d5b,0x1c8c,0x6b83,0xc073, +0x3d69,0x4347,0xfa26,0x8cec, +0xbd7f,0x9043,0x0317,0x8d66, +0xbdad,0x0fd7,0x357e,0x7bf2, +0xbdc1,0x511d,0x0839,0x7425, +0x3daa,0x24fe,0xabe8,0x004f, +0x3e00,0xf9cc,0xc0f4,0x6f75, +0x3e2d,0x2c64,0xa922,0x5b87, +0x3e58,0x5692,0x80d6,0xd56d, +0x3e8b,0x8007,0xd9cd,0x616e, +0x3ec8,0x412b,0xc101,0xc586, +0x3f12,0x0fa3,0x7899,0x9e52, +0x3f6b,0x998c,0xa2e5,0x9049, +0x3fe9,0xbe62,0xaca8,0x09cb +}; +#endif + +double i0(double x) +{ +double y; + +if( x < 0 ) + x = -x; +if( x <= 8.0 ) + { + y = (x/2.0) - 2.0; + return( exp(x) * chbevl( y, A, 30 ) ); + } + +return( exp(x) * chbevl( 32.0/x - 2.0, B, 25 ) / sqrt(x) ); + +} + + + + +double i0e(double x ) +{ +double y; + +if( x < 0 ) + x = -x; +if( x <= 8.0 ) + { + y = (x/2.0) - 2.0; + return( chbevl( y, A, 30 ) ); + } + +return( chbevl( 32.0/x - 2.0, B, 25 ) / sqrt(x) ); + +} diff --git a/ao-tools/lib/mconf.h b/ao-tools/lib/mconf.h new file mode 100644 index 00000000..af1ebb51 --- /dev/null +++ b/ao-tools/lib/mconf.h @@ -0,0 +1,211 @@ +/* + * This file comes from the cephes math library, which was + * released under the GPLV2+ license as a part of the Debian labplot + * package (I've included the GPLV2 license reference here to make + * this clear) - Keith Packard + * + * Cephes Math Library Release 2.0: April, 1987 + * Copyright 1984, 1987 by Stephen L. Moshier + * Direct inquiries to 30 Frost Street, Cambridge, MA 02140 + * + * 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. + */ +/* mconf.h + * + * Common include file for math routines + * + * + * + * SYNOPSIS: + * + * #include "mconf.h" + * + * + * + * DESCRIPTION: + * + * This file contains definitions for error codes that are + * passed to the common error handling routine mtherr() + * (which see). + * + * The file also includes a conditional assembly definition + * for the type of computer arithmetic (IEEE, DEC, Motorola + * IEEE, or UNKnown). + * + * For Digital Equipment PDP-11 and VAX computers, certain + * IBM systems, and others that use numbers with a 56-bit + * significand, the symbol DEC should be defined. In this + * mode, most floating point constants are given as arrays + * of octal integers to eliminate decimal to binary conversion + * errors that might be introduced by the compiler. + * + * For little-endian computers, such as IBM PC, that follow the + * IEEE Standard for Binary Floating Point Arithmetic (ANSI/IEEE + * Std 754-1985), the symbol IBMPC should be defined. These + * numbers have 53-bit significands. In this mode, constants + * are provided as arrays of hexadecimal 16 bit integers. + * + * Big-endian IEEE format is denoted MIEEE. On some RISC + * systems such as Sun SPARC, double precision constants + * must be stored on 8-byte address boundaries. Since integer + * arrays may be aligned differently, the MIEEE configuration + * may fail on such machines. + * + * To accommodate other types of computer arithmetic, all + * constants are also provided in a normal decimal radix + * which one can hope are correctly converted to a suitable + * format by the available C language compiler. To invoke + * this mode, define the symbol UNK. + * + * An important difference among these modes is a predefined + * set of machine arithmetic constants for each. The numbers + * MACHEP (the machine roundoff error), MAXNUM (largest number + * represented), and several other parameters are preset by + * the configuration symbol. Check the file const.c to + * ensure that these values are correct for your computer. + * + * Configurations NANS, INFINITIES, MINUSZERO, and DENORMAL + * may fail on many systems. Verify that they are supposed + * to work on your computer. + */ + +/* +Cephes Math Library Release 2.3: June, 1995 +Copyright 1984, 1987, 1989, 1995 by Stephen L. Moshier + +Adjusted for use with ACE/gr by Evgeny Stambulchik, October 1997 +*/ + +#define __GRACE_SOURCE_ + +#include "cmath.h" + +/* Type of computer arithmetic */ +/* In ACE/gr, defined as a compiler directive - no need to define here */ + +/* PDP-11, Pro350, VAX: + */ +#if defined(HAVE_DEC_FPU) +# define DEC 1 +#endif + +/* Intel IEEE, low order words come first: + */ +#if defined(HAVE_LIEEE_FPU) +# define IBMPC 1 +#endif + +/* Motorola IEEE, high order words come first + * (Sun 680x0 workstation): + */ +#if defined(HAVE_BIEEE_FPU) +# define MIEEE 1 +#endif + +/* UNKnown arithmetic, invokes coefficients given in + * normal decimal format. Beware of range boundary + * problems (MACHEP, MAXLOG, etc. in const.c) and + * roundoff problems in pow.c: + * (Sun SPARCstation) + */ + +#if (!defined (DEC) && !defined (IBMPC) && !defined (MIEEE)) +# define UNK 1 +#endif + +/* Define this `volatile' if your compiler thinks + * that floating point arithmetic obeys the associative + * and distributive laws. It will defeat some optimizations + * (but probably not enough of them). + * + * #define VOLATILE volatile + */ + +#ifndef VOLATILE +# define VOLATILE +#endif + +#ifdef PI +# undef PI +#endif + +#ifdef NAN +# undef NAN +#endif + +#ifdef INFINITY +# undef INFINITY +#endif + +/* Constant definitions for math error conditions + */ + +#if defined(DOMAIN) +# undef DOMAIN +#endif +#define DOMAIN 1 /* argument domain error */ + +#if defined(SING) +# undef SING +#endif +#define SING 2 /* argument singularity */ + +#if defined(OVERFLOW) +# undef OVERFLOW +#endif +#define OVERFLOW 3 /* overflow range error */ + +#if defined(UNDERFLOW) +# undef UNDERFLOW +#endif +#define UNDERFLOW 4 /* underflow range error */ + +#if defined(TLOSS) +# undef TLOSS +#endif +#define TLOSS 5 /* total loss of precision */ + +#if defined(PLOSS) +# undef PLOSS +#endif +#define PLOSS 6 /* partial loss of precision */ + +#if defined(EDOM) +# undef EDOM +#endif +#define EDOM 33 + +#if defined(ERANGE) +# undef ERANGE +#endif +#define ERANGE 34 + +#if !defined (UNK) + /* Define to support tiny denormal numbers, else undefine. */ +# define DENORMAL 1 + + /* Define to ask for infinity support, else undefine. */ +# define INFINITIES 1 + + /* Define to ask for support of numbers that are Not-a-Number, + else undefine. This may automatically define INFINITIES in some files. */ +# define NANS 1 + + /* Define to distinguish between -0.0 and +0.0. */ +# define MINUSZERO 1 +#endif + +/* Define 1 for ANSI C atan2() function + See atan.c and clog.c. */ +#define ANSIC 1 -- cgit v1.2.3 From 73f4a57239f770aff603b961169c0e2cfe2c276b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Sep 2009 13:08:54 -0700 Subject: Use pressure speed for drogue and beyond states. Fix differentiation time. Drogue state should always use pressure speeds. Differentiation code was using centi-seconds instead of seconds. Signed-off-by: Keith Packard --- ao-tools/ao-postflight/ao-postflight.c | 2 +- ao-tools/lib/cc-integrate.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c index 6683c67c..0c632c34 100644 --- a/ao-tools/ao-postflight/ao-postflight.c +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -128,7 +128,7 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file) } if (cooked) { - if (state_start < apogee) { + if (state < ao_flight_drogue) { speed_i = cc_perioddata_max(&cooked->accel_speed, state_start, state_stop); if (speed_i >= 0) speed = cooked->accel_speed.data[speed_i]; diff --git a/ao-tools/lib/cc-integrate.c b/ao-tools/lib/cc-integrate.c index 08ca295c..f9793dcd 100644 --- a/ao-tools/lib/cc-integrate.c +++ b/ao-tools/lib/cc-integrate.c @@ -72,7 +72,7 @@ cc_perioddata_differentiate(struct cc_perioddata *i) d->step = i->step; d->data = calloc (d->num, sizeof(double)); for (n = 1; n < d->num; n++) - d->data[n] = (i->data[n] - i->data[n-1]) / i->step; + d->data[n] = (i->data[n] - i->data[n-1]) / (i->step / 100.0); d->data[0] = d->data[1]; return d; } -- cgit v1.2.3 From 32d3536706324808df6cd02248a236302b831571 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Sep 2009 16:24:35 -0700 Subject: Add plots to ao-postflight using the plplot library It's not perfect, but it generates .svg plot output. Signed-off-by: Keith Packard --- ao-tools/ao-postflight/Makefile.am | 4 +- ao-tools/ao-postflight/ao-postflight.c | 132 +++++++++++++++++++++---- ao-tools/lib/cc-analyse.c | 174 +++++++++++++++++++++++++++++---- ao-tools/lib/cc-process.c | 18 ++++ ao-tools/lib/cc.h | 29 ++++++ configure.ac | 2 + 6 files changed, 318 insertions(+), 41 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-postflight/Makefile.am b/ao-tools/ao-postflight/Makefile.am index 301ac454..589d164a 100644 --- a/ao-tools/ao-postflight/Makefile.am +++ b/ao-tools/ao-postflight/Makefile.am @@ -1,11 +1,11 @@ bin_PROGRAMS=ao-postflight -AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS) +AM_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) +ao_postflight_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS) $(GNOME_LIBS) $(PLPLOT_LIBS) ao_postflight_SOURCES = ao-postflight.c diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c index c1e4d800..bc6638e9 100644 --- a/ao-tools/ao-postflight/ao-postflight.c +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -24,8 +24,7 @@ #include #include "cc-usb.h" #include "cc.h" - -#define NUM_BLOCK 512 +#include static const char *state_names[] = { "startup", @@ -40,12 +39,75 @@ static const char *state_names[] = { "invalid" }; -void -analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file) +static void +plot_perioddata(struct cc_perioddata *d, char *axis_label, char *plot_label, + double min_time, double max_time) +{ + 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]; + plenv(times[0], times[stop-start], + ymin, ymax, 0, 2); + plcol0(1); + pllab("Time", axis_label, plot_label); + plline(stop - start + 1, times, d->data + start); +} + +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 void +analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, char *plot_name) { double height; double accel; double speed; + double avg_speed; double boost_start, boost_stop; double min_pres; int i; @@ -129,18 +191,24 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file) if (cooked) { if (state < ao_flight_drogue) { - speed_i = cc_perioddata_max(&cooked->accel_speed, state_start, state_stop); + 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(&cooked->pres_speed, state_start, state_stop); + 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) + { fprintf(summary_file, "\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, "\tAvg speed: %9.2fm/s %9.2fft/s\n", + avg_speed, avg_speed * 100 / 2.4 / 12.0); + } } pres_i = cc_timedata_min(&f->pres, state_start, state_stop); if (pres_i >= 0) @@ -154,16 +222,10 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file) } } if (cooked && detail_file) { - double apogee_time; double max_height = 0; int i; + double *times; - for (i = 0; i < cooked->pres_pos.num; i++) { - if (cooked->pres_pos.data[i] > max_height) { - max_height = cooked->pres_pos.data[i]; - apogee_time = cooked->pres_pos.start + cooked->pres_pos.step * i; - } - } fprintf(detail_file, "%9s %9s %9s %9s\n", "time", "height", "speed", "accel"); for (i = 0; i < cooked->pres_pos.num; i++) { @@ -171,7 +233,7 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file) double accel = cooked->accel_accel.data[i]; double pos = cooked->pres_pos.data[i]; double speed; - if (cooked->pres_pos.start + cooked->pres_pos.step * i < apogee_time) + if (cooked->pres_pos.start + cooked->pres_pos.step * i < apogee) speed = cooked->accel_speed.data[i]; else speed = cooked->pres_speed.data[i]; @@ -179,17 +241,41 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file) time, pos, speed, accel); } } + 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_perioddata(&cooked->pres_pos, "meters", "Height", boost_start, apogee); + plot_perioddata(speed, "meters/second", "Speed", -1e10, 1e10); + plot_perioddata(speed, "meters/second", "Speed", boost_start, apogee); + plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration", -1e10, 1e10); + plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration", boost_start, apogee); + free(speed->data); + free(speed); + plend(); + } + if (cooked) + cc_flightcooked_free(cooked); } static const struct option options[] = { - { .name = "summary", .has_arg = 1, .val = 'S' }, - { .name = "detail", .has_arg = 1, .val = 'D' }, + { .name = "summary", .has_arg = 1, .val = 's' }, + { .name = "detail", .has_arg = 1, .val = 'd' }, + { .name = "plot", .has_arg = 1, .val = 'p' }, { 0, 0, 0, 0}, }; static void usage(char *program) { - fprintf(stderr, "usage: %s [--summary=] [--detail=] [--detail=] {flight-log} ...\n", program); exit(1); } @@ -206,15 +292,19 @@ main (int argc, char **argv) int serial; char *s; char *summary_name = NULL, *detail_name = NULL; + char *plot_name = NULL; - while ((c = getopt_long(argc, argv, "S:D:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "s:d:p:", options, NULL)) != -1) { switch (c) { - case 'S': + case 's': summary_name = optarg; break; - case 'D': + case 'd': detail_name = optarg; break; + case 'p': + plot_name = optarg; + break; default: usage(argv[0]); break; @@ -260,7 +350,7 @@ main (int argc, char **argv) } if (!raw->serial) raw->serial = serial; - analyse_flight(raw, summary_file, detail_file); + analyse_flight(raw, summary_file, detail_file, plot_name); cc_flightraw_free(raw); } return ret; diff --git a/ao-tools/lib/cc-analyse.c b/ao-tools/lib/cc-analyse.c index 0e020115..cdb16f02 100644 --- a/ao-tools/lib/cc-analyse.c +++ b/ao-tools/lib/cc-analyse.c @@ -38,6 +38,26 @@ cc_timedata_min(struct cc_timedata *d, double min_time, double max_time) return min_i; } +int +cc_timedata_min_mag(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 || fabs(d->data[i].value) < min) { + min_i = i; + min = fabs(d->data[i].value); + set = 1; + } + return min_i; +} + int cc_timedata_max(struct cc_timedata *d, double min_time, double max_time) { @@ -58,23 +78,81 @@ cc_timedata_max(struct cc_timedata *d, double min_time, double max_time) return max_i; } +int +cc_timedata_max_mag(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 || fabs(d->data[i].value) > max) { + max_i = i; + max = fabs(d->data[i].value); + set = 1; + } + return max_i; +} + +double +cc_timedata_average(struct cc_timedata *td, double start_time, double stop_time) +{ + int i; + double prev_time; + double next_time; + double interval; + double sum = 0.0; + double period = 0.0; + + prev_time = start_time; + for (i = 0; i < td->num; i++) { + if (start_time <= td->data[i].time && td->data[i].time <= stop_time) { + if (i < td->num - 1 && td->data[i+1].time < stop_time) + next_time = (td->data[i].time + td->data[i+1].time) / 2.0; + else + next_time = stop_time; + interval = next_time - prev_time; + sum += td->data[i].value * interval; + period += interval; + prev_time = next_time; + } + } + return sum / period; +} + +int +cc_perioddata_limits(struct cc_perioddata *d, double min_time, double max_time, int *start, int *stop) +{ + double start_d, stop_d; + + if (d->num == 0) + return 0; + start_d = ceil((min_time - d->start) / d->step); + if (start_d < 0) + start_d = 0; + stop_d = floor((max_time - d->start) / d->step); + if (stop_d >= d->num) + stop_d = d->num - 1; + if (stop_d < start_d) + return 0; + *start = (int) start_d; + *stop = (int) stop_d; + return 1; +} + int cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time) { - int start, stop; int i; double min; int min_i; + int start, stop; - if (d->num == 0) - return -1; - start = (int) ceil((min_time - d->start) / d->step); - if (start < 0) - start = 0; - stop = (int) floor((max_time - d->start) / d->step); - if (stop >= d->num) - stop = d->num - 1; - if (stop < start) + if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop)) return -1; min = d->data[start]; min_i = start; @@ -86,6 +164,26 @@ cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time) return min_i; } +int +cc_perioddata_min_mag(struct cc_perioddata *d, double min_time, double max_time) +{ + int start, stop; + int i; + double min; + int min_i; + + if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop)) + return -1; + min = d->data[start]; + min_i = start; + for (i = start + 1; i <= stop; i++) + if (fabs(d->data[i]) < min) { + min = fabs(d->data[i]); + min_i = i; + } + return min_i; +} + int cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time) { @@ -94,15 +192,27 @@ cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time) double max; int max_i; - if (d->num == 0) + if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop)) return -1; - start = (int) ceil((min_time - d->start) / d->step); - if (start < 0) - start = 0; - stop = (int) floor((max_time - d->start) / d->step); - if (stop >= d->num) - stop = d->num - 1; - if (stop < start) + max = d->data[start]; + max_i = start; + for (i = start + 1; i <= stop; i++) + if (d->data[i] > max) { + max = d->data[i]; + max_i = i; + } + return max_i; +} + +int +cc_perioddata_max_mag(struct cc_perioddata *d, double min_time, double max_time) +{ + int start, stop; + int i; + double max; + int max_i; + + if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop)) return -1; max = d->data[start]; max_i = start; @@ -113,3 +223,31 @@ cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time) } return max_i; } + +double +cc_perioddata_average(struct cc_perioddata *d, double min_time, double max_time) +{ + int start, stop; + int i; + double sum = 0.0; + + if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop)) + return 0.0; + for (i = start; i <= stop; i++) + sum += d->data[i]; + return sum / (stop - start + 1); +} + +double +cc_perioddata_average_mag(struct cc_perioddata *d, double min_time, double max_time) +{ + int start, stop; + int i; + double sum = 0.0; + + if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop)) + return 0.0; + for (i = start; i <= stop; i++) + sum += fabs(d->data[i]); + return sum / (stop - start + 1); +} diff --git a/ao-tools/lib/cc-process.c b/ao-tools/lib/cc-process.c index e906b635..469ad2f2 100644 --- a/ao-tools/lib/cc-process.c +++ b/ao-tools/lib/cc-process.c @@ -138,3 +138,21 @@ cc_flight_cook(struct cc_flightraw *raw) cooked->state.time_offset = raw->state.time_offset; return cooked; } + +#define if_free(x) ((x) ? free(x) : (void) 0) + +void +cc_flightcooked_free(struct cc_flightcooked *cooked) +{ + if_free(cooked->accel_accel.data); + if_free(cooked->accel_speed.data); + if_free(cooked->accel_pos.data); + if_free(cooked->pres_pos.data); + if_free(cooked->pres_speed.data); + if_free(cooked->pres_accel.data); + if_free(cooked->gps_lat.data); + if_free(cooked->gps_lon.data); + if_free(cooked->gps_alt.data); + if_free(cooked->state.data); + free(cooked); +} diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 356794e0..4e9aadc4 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -265,15 +265,42 @@ cc_great_circle (double start_lat, double start_lon, int cc_timedata_min(struct cc_timedata *d, double min_time, double max_time); +int +cc_timedata_min_mag(struct cc_timedata *d, double min_time, double max_time); + int cc_timedata_max(struct cc_timedata *d, double min_time, double max_time); +int +cc_timedata_max_mag(struct cc_timedata *d, double min_time, double max_time); + +double +cc_timedata_average(struct cc_timedata *d, double min_time, double max_time); + +double +cc_timedata_average_mag(struct cc_timedata *d, double min_time, double max_time); + +int +cc_perioddata_limits(struct cc_perioddata *d, double min_time, double max_time, int *start, int *stop); + int cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time); +int +cc_perioddata_min_mag(struct cc_perioddata *d, double min_time, double max_time); + int cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time); +int +cc_perioddata_max_mag(struct cc_perioddata *d, double min_time, double max_time); + +double +cc_perioddata_average(struct cc_perioddata *d, double min_time, double max_time); + +double +cc_perioddata_average_mag(struct cc_perioddata *d, double min_time, double max_time); + double * cc_low_pass(double *data, int data_len, double omega_pass, double omega_stop, double error); @@ -295,5 +322,7 @@ cc_perioddata_differentiate(struct cc_perioddata *i); struct cc_flightcooked * cc_flight_cook(struct cc_flightraw *raw); +void +cc_flightcooked_free(struct cc_flightcooked *cooked); #endif /* _CC_H_ */ diff --git a/configure.ac b/configure.ac index c668df04..6265c34e 100644 --- a/configure.ac +++ b/configure.ac @@ -71,6 +71,8 @@ PKG_CHECK_MODULES([LIBUSB], [libusb-1.0]) PKG_CHECK_MODULES([ALSA], [alsa]) +PKG_CHECK_MODULES([PLPLOT], [plplotd-gnome2]) + AC_OUTPUT([ Makefile ao-tools/Makefile -- cgit v1.2.3 From 932f1539b38567e565fd484171c13539b1467308 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Sep 2009 20:26:17 -0700 Subject: Color plots, integrate only flight portion of data. Telemetry files have piles of pad data which shouldn't be integrated into the velocity data as it tends to generate huge values from the noise of the sensor. Also make the data lines colored to keep them visually distinct from the rest of the plot image. Signed-off-by: Keith Packard --- ao-tools/ao-postflight/ao-postflight.1 | 22 ++++-- ao-tools/ao-postflight/ao-postflight.c | 118 ++++++++++++++++++++++++++++----- ao-tools/lib/cc-analyse.c | 14 ++++ ao-tools/lib/cc-integrate.c | 21 +++--- ao-tools/lib/cc-period.c | 26 +++----- ao-tools/lib/cc-process.c | 20 ++++-- ao-tools/lib/cc.h | 12 +++- 7 files changed, 180 insertions(+), 53 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-postflight/ao-postflight.1 b/ao-tools/ao-postflight/ao-postflight.1 index ac1c18a4..eca4bb34 100644 --- a/ao-tools/ao-postflight/ao-postflight.1 +++ b/ao-tools/ao-postflight/ao-postflight.1 @@ -23,15 +23,29 @@ ao-postflight \- Analyse a flight log (either telemetry or eeprom) .B "ao-postflight" [\-s ] [\--summary=] -[\-d ] [\--detail=] +[\-r ] +[\--raw=] [\-p ] [\--plot=] {flight.eeprom|flight.telem} .SH DESCRIPTION .I ao-postflight -reads the specified flight log and produces a summary of the flight on -stdout or to the specified file along with an optional .svg format -plot and detailed table of time/height/speed/accel. +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 .SH AUTHOR Keith Packard diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c index 4ca39c24..ded2f3c2 100644 --- a/ao-tools/ao-postflight/ao-postflight.c +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -39,9 +39,19 @@ static const char *state_names[] = { "invalid" }; +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) + double min_time, double max_time, int plot_type) { double *times; double ymin, ymax; @@ -60,11 +70,58 @@ plot_perioddata(struct cc_perioddata *d, char *axis_label, char *plot_label, 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); - plcol0(1); 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) +{ + 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; + plcol0(1); + pllab("Time", axis_label, plot_label); + for (i = start; i <= stop; i++) { + times[i-start] = (d->data[i].time - start_time)/100.0; + values[i-start] = d->data[i].value; + } + plenv(times[0], times[stop-start], ymin, ymax, 0, 2); + plline(stop - start + 1, times, values); + free(times); + free(values); } static struct cc_perioddata * @@ -102,7 +159,7 @@ merge_data(struct cc_perioddata *first, struct cc_perioddata *last, double split } static void -analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, char *plot_name) +analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, FILE *raw_file, char *plot_name) { double height; double accel; @@ -241,6 +298,17 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, ch time, pos, speed, accel); } } + if (raw_file) { + fprintf(raw_file, "%9s %9s %9s\n", + "time", "height", "accel"); + 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; + fprintf(raw_file, "%9.2f %9.2f %9.2f %9.2f\n", + time, pres, accel); + } + } if (cooked && plot_name) { struct cc_perioddata *speed; plsdev("svgcairo"); @@ -252,12 +320,12 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, ch plstar(2, 3); speed = merge_data(&cooked->accel_speed, &cooked->pres_speed, apogee); - plot_perioddata(&cooked->pres_pos, "meters", "Height", -1e10, 1e10); - plot_perioddata(&cooked->pres_pos, "meters", "Height", boost_start, apogee); - plot_perioddata(speed, "meters/second", "Speed", -1e10, 1e10); - plot_perioddata(speed, "meters/second", "Speed", boost_start, apogee); - plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration", -1e10, 1e10); - plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration", boost_start, apogee); + plot_perioddata(&cooked->pres_pos, "meters", "Height", -1e10, 1e10, PLOT_HEIGHT); + plot_perioddata(&cooked->pres_pos, "meters", "Height to Apogee", boost_start, apogee, PLOT_HEIGHT); + plot_perioddata(speed, "meters/second", "Speed", -1e10, 1e10, PLOT_SPEED); + plot_perioddata(speed, "meters/second", "Speed to Apogee", boost_start, apogee, PLOT_SPEED); + plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration", -1e10, 1e10, PLOT_ACCEL); + plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration to Apogee", boost_start, apogee, PLOT_ACCEL); free(speed->data); free(speed); plend(); @@ -270,12 +338,18 @@ static const struct option options[] = { { .name = "summary", .has_arg = 1, .val = 's' }, { .name = "detail", .has_arg = 1, .val = 'd' }, { .name = "plot", .has_arg = 1, .val = 'p' }, + { .name = "raw", .has_arg = 1, .val = 'r' }, { 0, 0, 0, 0}, }; static void usage(char *program) { - fprintf(stderr, "usage: %s [--summary=] [-s ] [--detail=] [--plot= -p ] {flight-log} ...\n", program); + fprintf(stderr, "usage: %s\n" + "\t[--summary=] [-s ]\n" + "\t[--detail=]\n" + "\t[--raw= -r -p ]\n" + "\t{flight-log} ...\n", program); exit(1); } @@ -283,18 +357,21 @@ int main (int argc, char **argv) { FILE *file; - FILE *summary_file; - FILE *detail_file; + FILE *summary_file = NULL; + FILE *detail_file = NULL; + FILE *raw_file = NULL; int i; int ret = 0; struct cc_flightraw *raw; int c; int serial; char *s; - char *summary_name = NULL, *detail_name = NULL; + char *summary_name = NULL; + char *detail_name = NULL; + char *raw_name = NULL; char *plot_name = NULL; - while ((c = getopt_long(argc, argv, "s:d:p:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "s:d:p:r:", options, NULL)) != -1) { switch (c) { case 's': summary_name = optarg; @@ -305,13 +382,15 @@ main (int argc, char **argv) case 'p': plot_name = optarg; break; + case 'r': + raw_name = optarg; + break; default: usage(argv[0]); break; } } summary_file = stdout; - detail_file = NULL; if (summary_name) { summary_file = fopen(summary_name, "w"); if (!summary_file) { @@ -330,6 +409,13 @@ main (int argc, char **argv) } } } + if (raw_name) { + raw_file = fopen (raw_name, "w"); + if (!raw_file) { + perror(raw_name); + exit(1); + } + } for (i = optind; i < argc; i++) { file = fopen(argv[i], "r"); if (!file) { @@ -350,7 +436,7 @@ main (int argc, char **argv) } if (!raw->serial) raw->serial = serial; - analyse_flight(raw, summary_file, detail_file, plot_name); + analyse_flight(raw, summary_file, detail_file, raw_file, plot_name); cc_flightraw_free(raw); } return ret; diff --git a/ao-tools/lib/cc-analyse.c b/ao-tools/lib/cc-analyse.c index cdb16f02..27c416a6 100644 --- a/ao-tools/lib/cc-analyse.c +++ b/ao-tools/lib/cc-analyse.c @@ -18,6 +18,20 @@ #include "cc.h" #include +void +cc_timedata_limits(struct cc_timedata *d, double min_time, double max_time, int *start, int *stop) +{ + int i; + + *start = -1; + for (i = 0; i < d->num; i++) { + if (*start < 0 && min_time <= d->data[i].time) + *start = i; + if (d->data[i].time <= max_time) + *stop = i; + } +} + int cc_timedata_min(struct cc_timedata *d, double min_time, double max_time) { diff --git a/ao-tools/lib/cc-integrate.c b/ao-tools/lib/cc-integrate.c index f9793dcd..ba50761b 100644 --- a/ao-tools/lib/cc-integrate.c +++ b/ao-tools/lib/cc-integrate.c @@ -37,24 +37,27 @@ cc_timedata_convert(struct cc_timedata *d, double (*f)(double v, double a), doub } struct cc_timedata * -cc_timedata_integrate(struct cc_timedata *d) +cc_timedata_integrate(struct cc_timedata *d, double min_time, double max_time) { struct cc_timedata *i; - int n; + int n, m; + int start, stop; + cc_timedata_limits(d, min_time, max_time, &start, &stop); i = calloc (1, sizeof (struct cc_timedata)); - i->num = d->num; - i->size = d->num; + i->num = stop - start + 1; + i->size = i->num; i->data = calloc (i->size, sizeof (struct cc_timedataelt)); - i->time_offset = d->time_offset; - for (n = 0; n < d->num; n++) { - i->data[n].time = d->data[n].time; + i->time_offset = d->data[start].time; + for (n = 0; n < i->num; n++) { + m = n + start; + i->data[n].time = d->data[m].time; if (n == 0) { i->data[n].value = 0; } else { i->data[n].value = i->data[n-1].value + - (d->data[n].value + d->data[n-1].value) / 2 * - ((d->data[n].time - d->data[n-1].time) / 100.0); + (d->data[m].value + d->data[m-1].value) / 2 * + ((d->data[m].time - d->data[m-1].time) / 100.0); } } return i; diff --git a/ao-tools/lib/cc-period.c b/ao-tools/lib/cc-period.c index c74cf9dc..2a4e5952 100644 --- a/ao-tools/lib/cc-period.c +++ b/ao-tools/lib/cc-period.c @@ -17,35 +17,27 @@ #include "cc.h" #include +#include struct cc_perioddata * cc_period_make(struct cc_timedata *td, double start_time, double stop_time) { int len = stop_time - start_time + 1; struct cc_perioddata *pd; - int i; - double prev_time; - double next_time; - double interval; + int i, j; + double t; pd = calloc(1, sizeof (struct cc_perioddata)); pd->start = start_time; pd->step = 1; pd->num = len; pd->data = calloc(len, sizeof(double)); - prev_time = start_time; - for (i = 0; i < td->num; i++) { - if (start_time <= td->data[i].time && td->data[i].time <= stop_time) { - int pos = td->data[i].time - start_time; - - if (i < td->num - 1 && td->data[i+1].time < stop_time) - next_time = (td->data[i].time + td->data[i+1].time) / 2.0; - else - next_time = stop_time; - interval = next_time - prev_time; - pd->data[pos] = td->data[i].value * interval; - prev_time = next_time; - } + j = 0; + for (i = 0; i < pd->num; i++) { + t = start_time + i * pd->step; + while (j < td->num - 1 && fabs(t - td->data[j].time) > fabs(t - td->data[j+1].time)) + j++; + pd->data[i] = td->data[j].value; } return pd; } diff --git a/ao-tools/lib/cc-process.c b/ao-tools/lib/cc-process.c index 469ad2f2..5c1acc6b 100644 --- a/ao-tools/lib/cc-process.c +++ b/ao-tools/lib/cc-process.c @@ -33,8 +33,6 @@ cook_timed(struct cc_timedata *td, struct cc_perioddata *pd, free (filtered); free (unfiltered->data); free (unfiltered); - free (td->data); - free (td); } static double @@ -93,11 +91,15 @@ cc_flight_cook(struct cc_flightraw *raw) } else { flight_stop = raw->accel.data[raw->accel.num-1].time; } + cooked->flight_start = flight_start; + cooked->flight_stop = flight_stop; /* Integrate the accelerometer data to get speed and position */ accel = cc_timedata_convert(&raw->accel, cc_accelerometer_to_acceleration, raw->ground_accel); - accel_speed = cc_timedata_integrate(accel); - accel_pos = cc_timedata_integrate(accel_speed); + cooked->accel = *accel; + free(accel); + accel_speed = cc_timedata_integrate(&cooked->accel, flight_start - 10, flight_stop); + accel_pos = cc_timedata_integrate(accel_speed, flight_start - 10, flight_stop); #define ACCEL_OMEGA_PASS (2 * M_PI * 5 / 100) #define ACCEL_OMEGA_STOP (2 * M_PI * 8 / 100) @@ -105,20 +107,24 @@ cc_flight_cook(struct cc_flightraw *raw) #define BARO_OMEGA_STOP (2 * M_PI * 1 / 100) #define FILTER_ERROR (1e-8) - cook_timed(accel, &cooked->accel_accel, + cook_timed(&cooked->accel, &cooked->accel_accel, flight_start, flight_stop, ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR); cook_timed(accel_speed, &cooked->accel_speed, flight_start, flight_stop, ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR); + free(accel_speed->data); free(accel_speed); cook_timed(accel_pos, &cooked->accel_pos, flight_start, flight_stop, ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR); + free(accel_pos->data); free(accel_pos); /* Filter the pressure data */ pres = cc_timedata_convert(&raw->pres, barometer_to_altitude, cc_barometer_to_altitude(raw->ground_pres)); - cook_timed(pres, &cooked->pres_pos, + cooked->pres = *pres; + free(pres); + cook_timed(&cooked->pres, &cooked->pres_pos, flight_start, flight_stop, BARO_OMEGA_PASS, BARO_OMEGA_STOP, FILTER_ERROR); /* differentiate twice to get to acceleration */ @@ -154,5 +160,7 @@ cc_flightcooked_free(struct cc_flightcooked *cooked) if_free(cooked->gps_lon.data); if_free(cooked->gps_alt.data); if_free(cooked->state.data); + if_free(cooked->accel.data); + if_free(cooked->pres.data); free(cooked); } diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 4e9aadc4..01226958 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -142,6 +142,9 @@ void cc_flightraw_free(struct cc_flightraw *raw); struct cc_flightcooked { + double flight_start; + double flight_stop; + struct cc_perioddata accel_accel; struct cc_perioddata accel_speed; struct cc_perioddata accel_pos; @@ -151,6 +154,10 @@ struct cc_flightcooked { struct cc_perioddata gps_lat; struct cc_perioddata gps_lon; struct cc_perioddata gps_alt; + + /* unfiltered, but converted */ + struct cc_timedata pres; + struct cc_timedata accel; struct cc_timedata state; }; @@ -262,6 +269,9 @@ cc_great_circle (double start_lat, double start_lon, double end_lat, double end_lon, double *dist, double *bearing); +void +cc_timedata_limits(struct cc_timedata *d, double min_time, double max_time, int *start, int *stop); + int cc_timedata_min(struct cc_timedata *d, double min_time, double max_time); @@ -314,7 +324,7 @@ struct cc_timedata * cc_timedata_convert(struct cc_timedata *d, double (*f)(double v, double a), double a); struct cc_timedata * -cc_timedata_integrate(struct cc_timedata *d); +cc_timedata_integrate(struct cc_timedata *d, double min_time, double max_time); struct cc_perioddata * cc_perioddata_differentiate(struct cc_perioddata *i); -- cgit v1.2.3 From 9e660315e1bd2bf71ab1c0574e895e1f7608a58f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Sep 2009 21:01:44 -0700 Subject: Fix cc_period_make to not get stuck on samples with matching time When two samples have matching times, step to the second one; otherwise, we'll get stuck forever. Signed-off-by: Keith Packard --- ao-tools/lib/cc-period.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/lib/cc-period.c b/ao-tools/lib/cc-period.c index 2a4e5952..844ac79e 100644 --- a/ao-tools/lib/cc-period.c +++ b/ao-tools/lib/cc-period.c @@ -35,7 +35,7 @@ cc_period_make(struct cc_timedata *td, double start_time, double stop_time) j = 0; for (i = 0; i < pd->num; i++) { t = start_time + i * pd->step; - while (j < td->num - 1 && fabs(t - td->data[j].time) > fabs(t - td->data[j+1].time)) + while (j < td->num - 1 && fabs(t - td->data[j].time) >= fabs(t - td->data[j+1].time)) j++; pd->data[i] = td->data[j].value; } -- cgit v1.2.3 From 7ea371a09385e2a93199f78685e8cb86793ed104 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 20 Sep 2009 13:33:26 -0700 Subject: Add --gps option to ao-postflight --- ao-tools/ao-postflight/ao-postflight.c | 31 ++++++++++++++-- ao-tools/lib/cc-logfile.c | 66 ++++++++++++++++++++++++++++++++-- ao-tools/lib/cc.h | 25 +++++++++++++ 3 files changed, 116 insertions(+), 6 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c index 1e6ac744..6418521e 100644 --- a/ao-tools/ao-postflight/ao-postflight.c +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -162,7 +162,7 @@ merge_data(struct cc_perioddata *first, struct cc_perioddata *last, double split } static void -analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, FILE *raw_file, char *plot_name) +analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, FILE *raw_file, char *plot_name, FILE *gps_file) { double height; double accel; @@ -312,6 +312,17 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, FI time, pres, accel); } } + if (gps_file) { + fprintf(gps_file, "%9s %12s %12s %12s\n", + "time", "lat", "lon", "alt"); + for (i = 0; i < f->gps.num; i++) { + fprintf(gps_file, "%12.7f %12.7f %12.7f %12.7f\n", + (f->gps.data[i].time - boost_start) / 100.0, + f->gps.data[i].lat, + f->gps.data[i].lon, + f->gps.data[i].alt); + } + } if (cooked && plot_name) { struct cc_perioddata *speed; plsdev("svgcairo"); @@ -350,6 +361,7 @@ static const struct option options[] = { { .name = "detail", .has_arg = 1, .val = 'd' }, { .name = "plot", .has_arg = 1, .val = 'p' }, { .name = "raw", .has_arg = 1, .val = 'r' }, + { .name = "gps", .has_arg = 1, .val = 'g' }, { 0, 0, 0, 0}, }; @@ -360,6 +372,7 @@ static void usage(char *program) "\t[--detail=]\n" "\t[--raw= -r -p ]\n" + "\t[--gps= -g ]\n" "\t{flight-log} ...\n", program); exit(1); } @@ -371,6 +384,7 @@ main (int argc, char **argv) FILE *summary_file = NULL; FILE *detail_file = NULL; FILE *raw_file = NULL; + FILE *gps_file = NULL; int i; int ret = 0; struct cc_flightraw *raw; @@ -381,8 +395,9 @@ main (int argc, char **argv) char *detail_name = NULL; char *raw_name = NULL; char *plot_name = NULL; + char *gps_name = NULL; - while ((c = getopt_long(argc, argv, "s:d:p:r:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "s:d:p:r:g:", options, NULL)) != -1) { switch (c) { case 's': summary_name = optarg; @@ -396,6 +411,9 @@ main (int argc, char **argv) case 'r': raw_name = optarg; break; + case 'g': + gps_name = optarg; + break; default: usage(argv[0]); break; @@ -427,6 +445,13 @@ main (int argc, char **argv) exit(1); } } + if (gps_name) { + gps_file = fopen(gps_name, "w"); + if (!gps_file) { + perror(gps_name); + exit(1); + } + } for (i = optind; i < argc; i++) { file = fopen(argv[i], "r"); if (!file) { @@ -447,7 +472,7 @@ main (int argc, char **argv) } if (!raw->serial) raw->serial = serial; - analyse_flight(raw, summary_file, detail_file, raw_file, plot_name); + analyse_flight(raw, summary_file, detail_file, raw_file, plot_name, gps_file); cc_flightraw_free(raw); } return ret; diff --git a/ao-tools/lib/cc-logfile.c b/ao-tools/lib/cc-logfile.c index 4abf7eb6..2136eec4 100644 --- a/ao-tools/lib/cc-logfile.c +++ b/ao-tools/lib/cc-logfile.c @@ -80,6 +80,44 @@ gpsdata_add(struct cc_gpsdata *data, struct cc_gpselt *elt) return 1; } +static int +gpssat_add(struct cc_gpsdata *data, struct cc_gpssat *sat) +{ + int i, j; + int reuse = 0; + int newsizesats; + struct cc_gpssats *newsats; + + for (i = data->numsats; --i >= 0;) { + if (data->sats[i].sat[0].time == sat->time) { + reuse = 1; + break; + } + if (data->sats[i].sat[0].time < sat->time) + break; + } + if (!reuse) { + if (data->numsats == data->sizesats) { + if (data->sizesats == 0) + newsats = malloc((newsizesats = 256) * sizeof (struct cc_gpssats)); + else + newsats = realloc (data->data, (newsizesats = data->sizesats * 2) + * sizeof (struct cc_gpssats)); + if (!newsats) + return 0; + data->sats = newsats; + } + i = data->numsats++; + data->sats[i].nsat = 0; + } + j = data->sats[i].nsat; + if (j < 12) { + data->sats[i].sat[j] = *sat; + data->sats[i].nsat = j + 1; + } + return 1; +} + static void gpsdata_free(struct cc_gpsdata *data) { @@ -100,13 +138,20 @@ gpsdata_free(struct cc_gpsdata *data) #define AO_LOG_POS_NONE (~0UL) +#define GPS_TIME 1 +#define GPS_LAT 2 +#define GPS_LON 4 +#define GPS_ALT 8 + 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; + static struct cc_gpselt gps; + static int gps_valid; + struct cc_gpssat sat; int serial; if (sscanf(line, "serial-number %u", &serial) == 1) { @@ -145,23 +190,38 @@ read_eeprom(const char *line, struct cc_flightraw *f, double *ground_pres, int * timedata_add(&f->state, tick, a); break; case AO_LOG_GPS_TIME: + /* the flight computer writes TIME first, so reset + * any stale data before adding this record + */ gps.time = tick; + gps_valid = GPS_TIME; break; case AO_LOG_GPS_LAT: gps.lat = ((int32_t) (a + (b << 16))) / 10000000.0; + gps_valid |= GPS_LAT; break; case AO_LOG_GPS_LON: gps.lon = ((int32_t) (a + (b << 16))) / 10000000.0; + gps_valid |= GPS_LON; break; case AO_LOG_GPS_ALT: - gps.alt = ((int32_t) (a + (b << 16))); - gpsdata_add(&f->gps, &gps); + gps.alt = (int16_t) a; + gps_valid |= GPS_ALT; break; case AO_LOG_GPS_SAT: + sat.time = tick; + sat.svid = a; + sat.state = (b & 0xff); + sat.c_n = (b >> 8) & 0xff; + gpssat_add(&f->gps, &sat); break; default: return 0; } + if (gps_valid == 0xf) { + gps_valid = 0; + gpsdata_add(&f->gps, &gps); + } return 1; } diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 01226958..b5f1132f 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -19,6 +19,7 @@ #define _CC_H_ #include +#include char * cc_fullname (char *dir, char *file); @@ -90,11 +91,35 @@ struct cc_gpselt { double alt; }; +#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_gpssat { + double time; + uint16_t svid; + uint8_t state; + uint8_t c_n; +}; + +struct cc_gpssats { + int nsat; + struct cc_gpssat sat[12]; +}; + struct cc_gpsdata { int num; int size; struct cc_gpselt *data; double time_offset; + int numsats; + int sizesats; + struct cc_gpssats *sats; }; /* -- cgit v1.2.3 From 27ebaf8e13aed06bb1ea6e770f767495a02be6c5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 3 Nov 2009 01:27:37 -0800 Subject: Add ability to dump eeprom data over radio link. This adds a '-R' option to ao-dumplog to redirect the connection through a USB attached TeleDongle over the radio link to a remote TeleMetrum device. Signed-off-by: Keith Packard --- ao-tools/ao-dumplog/ao-dumplog.c | 19 +++++++++++++++---- ao-tools/lib/cc-usb.c | 26 ++++++++++++++++++++++++++ ao-tools/lib/cc-usb.h | 6 ++++++ 3 files changed, 47 insertions(+), 4 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-dumplog/ao-dumplog.c b/ao-tools/ao-dumplog/ao-dumplog.c index 158a445b..4bfb7e51 100644 --- a/ao-tools/ao-dumplog/ao-dumplog.c +++ b/ao-tools/ao-dumplog/ao-dumplog.c @@ -28,12 +28,13 @@ static const struct option options[] = { { .name = "tty", .has_arg = 1, .val = 'T' }, { .name = "device", .has_arg = 1, .val = 'D' }, + { .name = "remote", .has_arg = 1, .val = 'R' }, { 0, 0, 0, 0}, }; static void usage(char *program) { - fprintf(stderr, "usage: %s [--tty ] [--device \n", program); + fprintf(stderr, "usage: %s [--tty ] [--device ] [-R]\n", program); exit(1); } @@ -80,8 +81,9 @@ main (int argc, char **argv) int data[8]; int done; int column; + int remote = 0; - while ((c = getopt_long(argc, argv, "T:D:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "T:D:R", options, NULL)) != -1) { switch (c) { case 'T': tty = optarg; @@ -89,13 +91,20 @@ main (int argc, char **argv) case 'D': device = optarg; break; + case 'R': + remote = 1; + break; default: usage(argv[0]); break; } } - if (!tty) - tty = cc_usbdevs_find_by_arg(device, "TeleMetrum"); + 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) @@ -103,6 +112,8 @@ main (int argc, char **argv) cc = cc_usb_open(tty); if (!cc) exit(1); + if (remote) + cc_usb_open_remote(cc); /* send a 'version' command followed by a 'log' command */ cc_usb_printf(cc, "v\n"); out = NULL; diff --git a/ao-tools/lib/cc-usb.c b/ao-tools/lib/cc-usb.c index 80d9c04f..9b3b831f 100644 --- a/ao-tools/lib/cc-usb.c +++ b/ao-tools/lib/cc-usb.c @@ -53,6 +53,8 @@ struct cc_usb { struct cc_hex_read hex_buf[CC_NUM_HEX_READ]; int hex_count; + + int remote; }; #define NOT_HEX 0xff @@ -372,6 +374,28 @@ cc_usb_reset(struct cc_usb *cc) return 1; } +void +cc_usb_open_remote(struct cc_usb *cc) +{ + if (!cc->remote) { + cc_usb_printf(cc, "p\nE 0\n"); + do { + cc->in_count = cc->in_pos = 0; + _cc_usb_sync(cc, 100); + } while (cc->in_count > 0); + cc->remote = 1; + } +} + +void +cc_usb_close_remote(struct cc_usb *cc) +{ + if (cc->remote) { + cc_usb_printf(cc, "~"); + cc->remote = 0; + } +} + static struct termios save_termios; struct cc_usb * @@ -406,6 +430,8 @@ cc_usb_open(char *tty) void cc_usb_close(struct cc_usb *cc) { + cc_usb_close_remote(cc); + cc_usb_sync(cc); tcsetattr(cc->fd, TCSAFLUSH, &save_termios); close (cc->fd); free (cc); diff --git a/ao-tools/lib/cc-usb.h b/ao-tools/lib/cc-usb.h index 7b6be350..627f1b5d 100644 --- a/ao-tools/lib/cc-usb.h +++ b/ao-tools/lib/cc-usb.h @@ -62,4 +62,10 @@ cc_usb_getline(struct cc_usb *cc, char *line, int max); void cc_usb_printf(struct cc_usb *cc, char *format, ...); +void +cc_usb_open_remote(struct cc_usb *cc); + +void +cc_usb_close_remote(struct cc_usb *cc); + #endif /* _CC_USB_H_ */ -- cgit v1.2.3 From 843ee489aac34ad6d81f55f1c85fb9eecc42d86b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 4 Nov 2009 21:59:12 -0800 Subject: Flush pending input when switching to remote packet mode Any pending input would just confuse the application, so pull it off the link and dump it. Signed-off-by: Keith Packard --- ao-tools/lib/cc-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/lib/cc-usb.c b/ao-tools/lib/cc-usb.c index 9b3b831f..53a50741 100644 --- a/ao-tools/lib/cc-usb.c +++ b/ao-tools/lib/cc-usb.c @@ -378,7 +378,7 @@ void cc_usb_open_remote(struct cc_usb *cc) { if (!cc->remote) { - cc_usb_printf(cc, "p\nE 0\n"); + cc_usb_printf(cc, "\np\nE 0\n"); do { cc->in_count = cc->in_pos = 0; _cc_usb_sync(cc, 100); @@ -419,7 +419,7 @@ cc_usb_open(char *tty) save_termios = termios; cfmakeraw(&termios); tcsetattr(cc->fd, TCSAFLUSH, &termios); - cc_usb_printf(cc, "E 0\nm 0\n"); + cc_usb_printf(cc, "\nE 0\nm 0\n"); do { cc->in_count = cc->in_pos = 0; _cc_usb_sync(cc, 100); -- cgit v1.2.3 From 03092d1a72a9651711e22c58dca6d6aba5705c5e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 14 Nov 2009 16:35:12 -0800 Subject: ao-postflight: fix sloppy gps sat data realloc code (was crashing). Realloc'ing the wrong data, and failing to set the realloc'ed size was causing ao-postflight to crash while reading long logs. Signed-off-by: Keith Packard --- ao-tools/lib/cc-logfile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/lib/cc-logfile.c b/ao-tools/lib/cc-logfile.c index 2136eec4..3d346bcc 100644 --- a/ao-tools/lib/cc-logfile.c +++ b/ao-tools/lib/cc-logfile.c @@ -101,11 +101,12 @@ gpssat_add(struct cc_gpsdata *data, struct cc_gpssat *sat) if (data->sizesats == 0) newsats = malloc((newsizesats = 256) * sizeof (struct cc_gpssats)); else - newsats = realloc (data->data, (newsizesats = data->sizesats * 2) + newsats = realloc (data->sats, (newsizesats = data->sizesats * 2) * sizeof (struct cc_gpssats)); if (!newsats) return 0; data->sats = newsats; + data->sizesats = newsizesats; } i = data->numsats++; data->sats[i].nsat = 0; -- cgit v1.2.3 From 4cffc9c4b079e39c8196ddbaf91129cda6df7f8b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 14 Nov 2009 22:24:37 -0800 Subject: Share telemetry parsing code in cc library. ao-view had a private copy of the telemetry parsing code which included the ability to parse the newer version of that file. Those changes have been moved to the library version and the private copy removed. Signed-off-by: Keith Packard --- ao-tools/ao-view/aoview.h | 77 ++---------------- ao-tools/ao-view/aoview_monitor.c | 159 +------------------------------------- ao-tools/ao-view/aoview_state.c | 4 +- ao-tools/lib/cc-telem.c | 24 +++++- ao-tools/lib/cc.h | 2 + 5 files changed, 33 insertions(+), 233 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-view/aoview.h b/ao-tools/ao-view/aoview.h index b6d5bcdf..b937df7c 100644 --- a/ao-tools/ao-view/aoview.h +++ b/ao-tools/ao-view/aoview.h @@ -43,79 +43,12 @@ #include #include -struct aogps_time { - int hour; - int minute; - int second; -}; - -struct aogps { - int nsat; - int gps_locked; - int gps_connected; - struct aogps_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 aogps_sat { - int svid; - int state; - int c_n0; -}; - -struct aogps_tracking { - int channels; - struct aogps_sat sats[12]; -}; - -struct aodata { - 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; - int accel_plus_g; - int accel_minus_g; - struct aogps gps; - struct aogps_tracking gps_tracking; -}; - struct aostate { - struct aodata data; + struct cc_telem data; /* derived data */ - struct aodata prev_data; + struct cc_telem prev_data; double report_time; @@ -135,8 +68,8 @@ struct aostate { double max_acceleration; double max_speed; - struct aogps gps; - struct aogps_tracking gps_tracking; + struct cc_gps gps; + struct cc_gps_tracking gps_tracking; int gps_valid; double pad_lat; @@ -201,7 +134,7 @@ void aoview_dev_dialog_init(GladeXML *xml); void -aoview_state_notify(struct aodata *data); +aoview_state_notify(struct cc_telem *data); void aoview_state_new(void); diff --git a/ao-tools/ao-view/aoview_monitor.c b/ao-tools/ao-view/aoview_monitor.c index 6d57f556..0f4afb0f 100644 --- a/ao-tools/ao-view/aoview_monitor.c +++ b/ao-tools/ao-view/aoview_monitor.c @@ -34,167 +34,14 @@ aoview_monitor_disconnect(void) aoview_log_new(); } -static void -aoview_parse_string(char *target, int len, char *source) -{ - strncpy(target, source, len-1); - target[len-1] = '\0'; -} - -static void -aoview_parse_int(int *target, char *source) -{ - *target = strtol(source, NULL, 0); -} - -static void -aoview_parse_hex(int *target, char *source) -{ - *target = strtol(source, NULL, 16); -} - -static void -aoview_parse_pos(double *target, char *source) -{ - int deg; - double min; - char dir; - double r; - - if (sscanf(source, "%d°%lf'%c", °, &min, &dir) != 3) { - *target = 0; - return; - } - r = deg + min / 60.0; - if (dir == 'S' || dir == 'W') - r = -r; - *target = r; -} - -#define PARSE_MAX_WORDS 256 - gboolean aoview_monitor_parse(const char *input_line) { - char *saveptr; - char *raw_words[PARSE_MAX_WORDS]; - char **words; - int version = 0; - int nword; - char line_buf[8192], *line; - struct aodata data; - int tracking_pos; - int channel; + struct cc_telem telem; - /* 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++) { - raw_words[nword] = strtok_r(line, " \t\n", &saveptr); - line = NULL; - if (raw_words[nword] == NULL) - break; - } - if (nword < 36) - return FALSE; - words = raw_words; - if (strcmp(words[0], "VERSION") == 0) { - aoview_parse_int(&version, words[1]); - words += 2; - nword -= 2; - } - if (strcmp(words[0], "CALL") != 0) + if (!cc_telem_parse(input_line, &telem)) return FALSE; - aoview_parse_string(data.callsign, sizeof (data.callsign), words[1]); - aoview_parse_int(&data.serial, words[3]); - - aoview_parse_int(&data.rssi, words[5]); - aoview_parse_string(data.state, sizeof (data.state), words[9]); - aoview_parse_int(&data.tick, words[10]); - aoview_parse_int(&data.accel, words[12]); - aoview_parse_int(&data.pres, words[14]); - aoview_parse_int(&data.temp, words[16]); - aoview_parse_int(&data.batt, words[18]); - aoview_parse_int(&data.drogue, words[20]); - aoview_parse_int(&data.main, words[22]); - aoview_parse_int(&data.flight_accel, words[24]); - aoview_parse_int(&data.ground_accel, words[26]); - aoview_parse_int(&data.flight_vel, words[28]); - aoview_parse_int(&data.flight_pres, words[30]); - aoview_parse_int(&data.ground_pres, words[32]); - if (version >= 1) { - aoview_parse_int(&data.accel_plus_g, words[34]); - aoview_parse_int(&data.accel_minus_g, words[36]); - words += 4; - nword -= 4; - } else { - data.accel_plus_g = data.ground_accel; - data.accel_minus_g = data.ground_accel + 530; - } - aoview_parse_int(&data.gps.nsat, words[34]); - if (strcmp (words[36], "unlocked") == 0) { - data.gps.gps_connected = 1; - data.gps.gps_locked = 0; - data.gps.gps_time.hour = data.gps.gps_time.minute = data.gps.gps_time.second = 0; - data.gps.lat = data.gps.lon = 0; - data.gps.alt = 0; - tracking_pos = 37; - } else if (nword >= 40) { - data.gps.gps_locked = 1; - data.gps.gps_connected = 1; - sscanf(words[36], "%d:%d:%d", &data.gps.gps_time.hour, &data.gps.gps_time.minute, &data.gps.gps_time.second); - aoview_parse_pos(&data.gps.lat, words[37]); - aoview_parse_pos(&data.gps.lon, words[38]); - sscanf(words[39], "%dm", &data.gps.alt); - tracking_pos = 46; - } else { - data.gps.gps_connected = 0; - data.gps.gps_locked = 0; - data.gps.gps_time.hour = data.gps.gps_time.minute = data.gps.gps_time.second = 0; - data.gps.lat = data.gps.lon = 0; - data.gps.alt = 0; - tracking_pos = -1; - } - if (nword >= 46) { - data.gps.gps_extended = 1; - sscanf(words[40], "%lfm/s", &data.gps.ground_speed); - sscanf(words[41], "%d", &data.gps.course); - sscanf(words[42], "%lfm/s", &data.gps.climb_rate); - sscanf(words[43], "%lf", &data.gps.hdop); - sscanf(words[44], "%d", &data.gps.h_error); - sscanf(words[45], "%d", &data.gps.v_error); - } else { - data.gps.gps_extended = 0; - data.gps.ground_speed = 0; - data.gps.course = 0; - data.gps.climb_rate = 0; - data.gps.hdop = 0; - data.gps.h_error = 0; - data.gps.v_error = 0; - } - if (tracking_pos >= 0 && nword >= tracking_pos + 2 && strcmp(words[tracking_pos], "SAT") == 0) { - int c, n, pos; - aoview_parse_int(&n, words[tracking_pos + 1]); - pos = tracking_pos + 2; - if (nword >= pos + n * 3) { - data.gps_tracking.channels = n; - for (c = 0; c < n; c++) { - aoview_parse_int(&data.gps_tracking.sats[c].svid, - words[pos + 0]); - aoview_parse_hex(&data.gps_tracking.sats[c].state, - words[pos + 1]); - aoview_parse_int(&data.gps_tracking.sats[c].c_n0, - words[pos + 2]); - pos += 3; - } - } else { - data.gps_tracking.channels = 0; - } - } else { - data.gps_tracking.channels = 0; - } - aoview_state_notify(&data); + aoview_state_notify(&telem); return TRUE; } diff --git a/ao-tools/ao-view/aoview_state.c b/ao-tools/ao-view/aoview_state.c index f8f01685..a7545c51 100644 --- a/ao-tools/ao-view/aoview_state.c +++ b/ao-tools/ao-view/aoview_state.c @@ -99,7 +99,7 @@ aoview_time(void) * Fill out the derived data fields */ static void -aoview_state_derive(struct aodata *data, struct aostate *state) +aoview_state_derive(struct cc_telem *data, struct aostate *state) { int i; double new_height; @@ -274,7 +274,7 @@ aoview_state_reset(void) } void -aoview_state_notify(struct aodata *data) +aoview_state_notify(struct cc_telem *data) { struct aostate *state = &aostate; aoview_state_derive(data, state); diff --git a/ao-tools/lib/cc-telem.c b/ao-tools/lib/cc-telem.c index a6ac0313..f82ab961 100644 --- a/ao-tools/lib/cc-telem.c +++ b/ao-tools/lib/cc-telem.c @@ -62,7 +62,9 @@ int cc_telem_parse(const char *input_line, struct cc_telem *telem) { char *saveptr; - char *words[PARSE_MAX_WORDS]; + char *raw_words[PARSE_MAX_WORDS]; + char **words; + int version = 0; int nword; char line_buf[8192], *line; int tracking_pos; @@ -72,13 +74,20 @@ cc_telem_parse(const char *input_line, struct cc_telem *telem) 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); + raw_words[nword] = strtok_r(line, " \t\n", &saveptr); line = NULL; - if (words[nword] == NULL) + if (raw_words[nword] == NULL) break; } if (nword < 36) return FALSE; + words = raw_words; + if (strcmp(words[0], "VERSION") == 0) { + cc_parse_int(&version, words[1]); + words += 2; + nword -= 2; + } + if (strcmp(words[0], "CALL") != 0) return FALSE; cc_parse_string(telem->callsign, sizeof (telem->callsign), words[1]); @@ -98,6 +107,15 @@ cc_telem_parse(const char *input_line, struct cc_telem *telem) cc_parse_int(&telem->flight_vel, words[28]); cc_parse_int(&telem->flight_pres, words[30]); cc_parse_int(&telem->ground_pres, words[32]); + if (version >= 1) { + cc_parse_int(&telem->accel_plus_g, words[34]); + cc_parse_int(&telem->accel_minus_g, words[36]); + words += 4; + nword -= 4; + } else { + telem->accel_plus_g = telem->ground_accel; + telem->accel_minus_g = telem->ground_accel + 530; + } cc_parse_int(&telem->gps.nsat, words[34]); if (strcmp (words[36], "unlocked") == 0) { telem->gps.gps_connected = 1; diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index b5f1132f..fd461e5c 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -252,6 +252,8 @@ struct cc_telem { int flight_vel; int flight_pres; int ground_pres; + int accel_plus_g; + int accel_minus_g; struct cc_gps gps; struct cc_gps_tracking gps_tracking; }; -- cgit v1.2.3 From 3ee279ba76c2a79d142c466f19ef758cf4c01d70 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 15 Nov 2009 15:59:01 -0800 Subject: Add flight number to telemetry stream. This makes it easier to tie the telemetry and eeprom files together as they're now both labeled with serial and flight numbers, which should be unique. Signed-off-by: Keith Packard --- ao-tools/ao-view/aoview_state.c | 1 + ao-tools/lib/cc-telem.c | 7 ++++++ ao-tools/lib/cc.h | 1 + src/ao.h | 11 +++++---- src/ao_log.c | 51 +++++++++++------------------------------ src/ao_monitor.c | 3 ++- src/ao_telemetry.c | 3 +++ 7 files changed, 34 insertions(+), 43 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-view/aoview_state.c b/ao-tools/ao-view/aoview_state.c index a7545c51..2f613d44 100644 --- a/ao-tools/ao-view/aoview_state.c +++ b/ao-tools/ao-view/aoview_state.c @@ -288,6 +288,7 @@ aoview_state_notify(struct cc_telem *data) aoview_table_add_row(0, "Rocket state", "%s", state->data.state); aoview_table_add_row(0, "Callsign", "%s", state->data.callsign); aoview_table_add_row(0, "Rocket serial", "%d", state->data.serial); + aoview_table_add_row(0, "Rocket flight", "%d", state->data.flight); aoview_table_add_row(0, "RSSI", "%6ddBm", state->data.rssi); aoview_table_add_row(0, "Height", "%6dm", state->height); diff --git a/ao-tools/lib/cc-telem.c b/ao-tools/lib/cc-telem.c index f82ab961..0e1483f7 100644 --- a/ao-tools/lib/cc-telem.c +++ b/ao-tools/lib/cc-telem.c @@ -93,6 +93,13 @@ cc_telem_parse(const char *input_line, struct cc_telem *telem) cc_parse_string(telem->callsign, sizeof (telem->callsign), words[1]); cc_parse_int(&telem->serial, words[3]); + if (version >= 2) { + cc_parse_int(&telem->flight, words[5]); + words += 2; + nword -= 2; + } else + telem->flight = 0; + cc_parse_int(&telem->rssi, words[5]); cc_parse_string(telem->state, sizeof (telem->state), words[9]); cc_parse_int(&telem->tick, words[10]); diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index fd461e5c..b8e3c061 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -238,6 +238,7 @@ struct cc_gps_tracking { struct cc_telem { char callsign[16]; int serial; + int flight; int rssi; char state[16]; int tick; diff --git a/src/ao.h b/src/ao.h index 2df81d2a..f266ac64 100644 --- a/src/ao.h +++ b/src/ao.h @@ -553,11 +553,11 @@ ao_log_data(struct ao_log_record *log); void ao_log_flush(void); -/* Log dumping API: - * ao_log_dump_first() - get first log record - * ao_log_dump_next() - get next log record +/* We record flight numbers in the first record of + * the log. Tasks may wait for this to be initialized + * by sleeping on this variable. */ -extern __xdata struct ao_log_record ao_log_dump; +extern __xdata uint16_t ao_flight_number; /* Retrieve first log record for the current flight */ uint8_t @@ -788,10 +788,11 @@ ao_gps_report_init(void); */ #define AO_MAX_CALLSIGN 8 -#define AO_TELEMETRY_VERSION 1 +#define AO_TELEMETRY_VERSION 2 struct ao_telemetry { uint8_t addr; + uint16_t flight; uint8_t flight_state; int16_t flight_accel; int16_t ground_accel; diff --git a/src/ao_log.c b/src/ao_log.c index 50778f55..44ce90e0 100644 --- a/src/ao_log.c +++ b/src/ao_log.c @@ -59,51 +59,30 @@ ao_log_flush(void) ao_ee_flush(); } -__xdata struct ao_log_record ao_log_dump; -static __xdata uint16_t ao_log_dump_flight; -static __xdata uint32_t ao_log_dump_pos; +__xdata struct ao_log_record log; +__xdata uint16_t ao_flight_number; static uint8_t ao_log_dump_check_data(void) { - if (ao_log_csum((uint8_t *) &ao_log_dump) != 0) + if (ao_log_csum((uint8_t *) &log) != 0) return 0; return 1; } -static uint8_t -ao_log_dump_scan(void) +static void +ao_log_scan(void) { - if (!ao_ee_read(0, (uint8_t *) &ao_log_dump, sizeof (struct ao_log_record))) + if (!ao_ee_read(0, (uint8_t *) &log, sizeof (struct ao_log_record))) ao_panic(AO_PANIC_LOG); - if (ao_log_dump_check_data() && ao_log_dump.type == AO_LOG_FLIGHT) { - ao_log_dump_flight = ao_log_dump.u.flight.flight; - return 1; + if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT) { + ao_flight_number = log.u.flight.flight + 1; + if (ao_flight_number == 0) + ao_flight_number = 1; } else { - ao_log_dump_flight = 0; - return 0; + ao_flight_number = 1; } -} - -uint8_t -ao_log_dump_first(void) -{ - ao_log_dump_pos = 0; - if (!ao_log_dump_scan()) - return 0; - return 1; -} - -uint8_t -ao_log_dump_next(void) -{ - ao_log_dump_pos += sizeof (struct ao_log_record); - if (ao_log_dump_pos >= AO_EE_DEVICE_SIZE) - return 0; - if (!ao_ee_read(ao_log_dump_pos, (uint8_t *) &ao_log_dump, - sizeof (struct ao_log_record))) - return 0; - return ao_log_dump_check_data(); + ao_wakeup(&ao_flight_number); } __xdata uint8_t ao_log_adc_pos; @@ -115,9 +94,7 @@ typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_record))] ; void ao_log(void) { - static __xdata struct ao_log_record log; - - ao_log_dump_scan(); + ao_log_scan(); while (!ao_log_running) ao_sleep(&ao_log_running); @@ -125,7 +102,7 @@ ao_log(void) log.type = AO_LOG_FLIGHT; log.tick = ao_flight_tick; log.u.flight.ground_accel = ao_ground_accel; - log.u.flight.flight = ao_log_dump_flight + 1; + log.u.flight.flight = ao_flight_number; ao_log_data(&log); /* Write the whole contents of the ring to the log diff --git a/src/ao_monitor.c b/src/ao_monitor.c index cd0d693e..628b6e67 100644 --- a/src/ao_monitor.c +++ b/src/ao_monitor.c @@ -37,10 +37,11 @@ ao_monitor(void) if (state > ao_flight_invalid) state = ao_flight_invalid; if (recv.status & PKT_APPEND_STATUS_1_CRC_OK) { - printf("VERSION %d CALL %s SERIAL %3d RSSI %4d STATUS %02x STATE %7s ", + printf("VERSION %d CALL %s SERIAL %3d FLIGHT %5u RSSI %4d STATUS %02x STATE %7s ", AO_TELEMETRY_VERSION, callsign, recv.telemetry.addr, + recv.telemetry.flight, (int) recv.rssi - 74, recv.status, ao_state_names[state]); printf("%5u a: %5d p: %5d t: %5d v: %5d d: %5d m: %5d " diff --git a/src/ao_telemetry.c b/src/ao_telemetry.c index 9c923984..88ac142c 100644 --- a/src/ao_telemetry.c +++ b/src/ao_telemetry.c @@ -30,8 +30,11 @@ ao_telemetry(void) static __xdata struct ao_telemetry telemetry; ao_config_get(); + while (!ao_flight_number) + ao_sleep(&ao_flight_number); memcpy(telemetry.callsign, ao_config.callsign, AO_MAX_CALLSIGN); telemetry.addr = ao_serial_number; + telemetry.flight = ao_flight_number; telemetry.accel_plus_g = ao_config.accel_plus_g; telemetry.accel_minus_g = ao_config.accel_minus_g; ao_rdf_time = ao_time(); -- cgit v1.2.3 From 524665fc221b0d483453c67b7211e282cebc8980 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 15 Nov 2009 16:04:41 -0800 Subject: Add date to GPS data, captured from GPRMC packet. Pull the date out of the GPS stream and send it over the telemetry link and write it to the eeprom. Signed-off-by: Keith Packard --- ao-tools/ao-view/aoview_state.c | 4 +++ ao-tools/lib/cc-telem.c | 12 ++++++++ ao-tools/lib/cc.h | 3 ++ src/ao.h | 10 ++++++ src/ao_gps_print.c | 4 +++ src/ao_gps_report.c | 12 ++++++-- src/ao_gps_skytraq.c | 67 ++++++++++++++++++++++++++++++++++++----- src/ao_gps_test.c | 4 +++ src/ao_gps_test_skytraq.c | 4 +++ 9 files changed, 111 insertions(+), 9 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-view/aoview_state.c b/ao-tools/ao-view/aoview_state.c index 2f613d44..21cea99a 100644 --- a/ao-tools/ao-view/aoview_state.c +++ b/ao-tools/ao-view/aoview_state.c @@ -315,6 +315,10 @@ aoview_state_notify(struct cc_telem *data) aoview_state_add_deg(1, "Longitude", state->gps.lon, 'E', 'W'); aoview_table_add_row(1, "GPS altitude", "%d", state->gps.alt); aoview_table_add_row(1, "GPS height", "%d", state->gps_height); + aoview_table_add_row(1, "GPS date", "%04d-%02d-%02d", + state->gps.gps_time.year, + state->gps.gps_time.month, + state->gps.gps_time.day); aoview_table_add_row(1, "GPS time", "%02d:%02d:%02d", state->gps.gps_time.hour, state->gps.gps_time.minute, diff --git a/ao-tools/lib/cc-telem.c b/ao-tools/lib/cc-telem.c index 0e1483f7..9a2f6155 100644 --- a/ao-tools/lib/cc-telem.c +++ b/ao-tools/lib/cc-telem.c @@ -127,6 +127,7 @@ cc_telem_parse(const char *input_line, struct cc_telem *telem) if (strcmp (words[36], "unlocked") == 0) { telem->gps.gps_connected = 1; telem->gps.gps_locked = 0; + telem->gps.gps_time.year = telem->gps.gps_time.month = telem->gps.gps_time.day = 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; @@ -134,6 +135,16 @@ cc_telem_parse(const char *input_line, struct cc_telem *telem) } else if (nword >= 40) { telem->gps.gps_locked = 1; telem->gps.gps_connected = 1; + if (version >= 2) { + sscanf(words[36], "%d-%d-%d", + &telem->gps.gps_time.year, + &telem->gps.gps_time.month, + &telem->gps.gps_time.day); + words += 1; + nword -= 1; + } else { + telem->gps.gps_time.year = telem->gps.gps_time.month = telem->gps.gps_time.day = 0; + } 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]); @@ -142,6 +153,7 @@ cc_telem_parse(const char *input_line, struct cc_telem *telem) } else { telem->gps.gps_connected = 0; telem->gps.gps_locked = 0; + telem->gps.gps_time.year = telem->gps.gps_time.month = telem->gps.gps_time.day = 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; diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index b8e3c061..ebc0db7d 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -192,6 +192,9 @@ struct cc_flightcooked { struct cc_gps_time { + int year; + int month; + int day; int hour; int minute; int second; diff --git a/src/ao.h b/src/ao.h index f266ac64..c1a0f6e3 100644 --- a/src/ao.h +++ b/src/ao.h @@ -493,6 +493,7 @@ ao_ee_init(void); #define AO_LOG_GPS_LON 'W' #define AO_LOG_GPS_ALT 'H' #define AO_LOG_GPS_SAT 'V' +#define AO_LOG_GPS_DATE 'Y' #define AO_LOG_POS_NONE (~0UL) @@ -538,6 +539,11 @@ struct ao_log_record { uint8_t state; uint8_t c_n; } gps_sat; + struct { + uint8_t year; + uint8_t month; + uint8_t day; + } gps_date; struct { uint16_t d0; uint16_t d1; @@ -720,8 +726,12 @@ ao_serial_init(void); #define AO_GPS_VALID (1 << 4) #define AO_GPS_RUNNING (1 << 5) +#define AO_GPS_DATE_VALID (1 << 6) struct ao_gps_data { + uint8_t year; + uint8_t month; + uint8_t day; uint8_t hour; uint8_t minute; uint8_t second; diff --git a/src/ao_gps_print.c b/src/ao_gps_print.c index cc751337..95439ec7 100644 --- a/src/ao_gps_print.c +++ b/src/ao_gps_print.c @@ -53,6 +53,10 @@ ao_gps_print(__xdata struct ao_gps_data *gps_data) __reentrant ao_gps_split(gps_data->latitude, &lat); ao_gps_split(gps_data->longitude, &lon); + printf(" 20%02d-%02d-%02d", + gps_data->year, + gps_data->month, + gps_data->day); printf(" %2d:%02d:%02d", gps_data->hour, gps_data->minute, diff --git a/src/ao_gps_report.c b/src/ao_gps_report.c index 75c944f5..e3e27523 100644 --- a/src/ao_gps_report.c +++ b/src/ao_gps_report.c @@ -22,6 +22,7 @@ ao_gps_report(void) { static __xdata struct ao_log_record gps_log; static __xdata struct ao_gps_data gps_data; + uint8_t date_reported = 0; for (;;) { ao_sleep(&ao_gps_data); @@ -49,6 +50,14 @@ ao_gps_report(void) gps_log.u.gps_altitude.altitude = gps_data.altitude; gps_log.u.gps_altitude.unused = 0xffff; ao_log_data(&gps_log); + if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) { + date_reported = 1; + gps_log.type = AO_LOG_GPS_DATE; + gps_log.u.gps_date.year = gps_data.year; + gps_log.u.gps_date.month = gps_data.month; + gps_log.u.gps_date.day = gps_data.day; + ao_log_data(&gps_log); + } } } @@ -71,8 +80,7 @@ ao_gps_tracking_report(void) gps_log.tick = ao_time(); gps_log.type = AO_LOG_GPS_SAT; for (c = 0; c < n; c++) - if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid) && - (gps_log.u.gps_sat.state = gps_tracking_data.sats[c].state)) + if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid)) { gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1; ao_log_data(&gps_log); diff --git a/src/ao_gps_skytraq.c b/src/ao_gps_skytraq.c index cd5f78b9..b2eef04b 100644 --- a/src/ao_gps_skytraq.c +++ b/src/ao_gps_skytraq.c @@ -19,9 +19,9 @@ #include "ao.h" #endif -#define AO_GPS_LEADER 3 +#define AO_GPS_LEADER 2 -static const char ao_gps_header[] = "GPG"; +static const char ao_gps_header[] = "GP"; __xdata uint8_t ao_gps_mutex; static __xdata char ao_gps_char; @@ -32,6 +32,7 @@ __xdata struct ao_gps_data ao_gps_data; __xdata struct ao_gps_tracking_data ao_gps_tracking_data; static __xdata struct ao_gps_data ao_gps_next; +static __xdata uint8_t ao_gps_date_flags; static __xdata struct ao_gps_tracking_data ao_gps_tracking_next; static const char ao_gps_config[] = { @@ -181,7 +182,7 @@ ao_gps_parse_flag(char no_c, char yes_c) __reentrant void ao_gps(void) __reentrant { - char c; + char a, c; uint8_t i; ao_serial_set_speed(AO_SERIAL_SPEED_9600); @@ -198,7 +199,7 @@ ao_gps(void) __reentrant ao_gps_cksum = 0; ao_gps_error = 0; - /* Skip anything other than GPG */ + /* Skip anything other than GP */ for (i = 0; i < AO_GPS_LEADER; i++) { ao_gps_lexchar(); if (ao_gps_char != ao_gps_header[i]) @@ -209,6 +210,8 @@ ao_gps(void) __reentrant /* pull the record identifier characters off the link */ ao_gps_lexchar(); + a = ao_gps_char; + ao_gps_lexchar(); c = ao_gps_char; ao_gps_lexchar(); i = ao_gps_char; @@ -216,7 +219,7 @@ ao_gps(void) __reentrant if (ao_gps_char != ',') continue; - if (c == (uint8_t) 'G' && i == (uint8_t) 'A') { + if (a == (uint8_t) 'G' && c == (uint8_t) 'G' && i == (uint8_t) 'A') { /* Now read the data into the gps data record * * $GPGGA,025149.000,4528.1723,N,12244.2480,W,1,05,2.0,103.5,M,-19.5,M,,0000*66 @@ -245,7 +248,7 @@ ao_gps(void) __reentrant * *66 checksum */ - ao_gps_next.flags = AO_GPS_RUNNING; + ao_gps_next.flags = AO_GPS_RUNNING | ao_gps_date_flags; ao_gps_next.hour = ao_gps_decimal(2); ao_gps_next.minute = ao_gps_decimal(2); ao_gps_next.second = ao_gps_decimal(2); @@ -290,7 +293,7 @@ ao_gps(void) __reentrant ao_mutex_put(&ao_gps_mutex); ao_wakeup(&ao_gps_data); } - } else if (c == (uint8_t) 'S' && i == (uint8_t) 'V') { + } else if (a == (uint8_t) 'G' && c == (uint8_t) 'S' && i == (uint8_t) 'V') { uint8_t done; /* Now read the data into the GPS tracking data record * @@ -345,6 +348,56 @@ ao_gps(void) __reentrant ao_mutex_put(&ao_gps_mutex); ao_wakeup(&ao_gps_tracking_data); } + } else if (a == (uint8_t) 'R' && c == (uint8_t) 'M' && i == (uint8_t) 'C') { + /* Parse the RMC record to read out the current date */ + + /* $GPRMC,111636.932,A,2447.0949,N,12100.5223,E,000.0,000.0,030407,,,A*61 + * + * Recommended Minimum Specific GNSS Data + * + * 111636.932 UTC time 11:16:36.932 + * A Data Valid (V = receiver warning) + * 2447.0949 Latitude + * N North/south indicator + * 12100.5223 Longitude + * E East/west indicator + * 000.0 Speed over ground + * 000.0 Course over ground + * 030407 UTC date (ddmmyy format) + * A Mode indicator: + * N = data not valid + * A = autonomous mode + * D = differential mode + * E = estimated (dead reckoning) mode + * M = manual input mode + * S = simulator mode + * 61 checksum + */ + ao_gps_skip_field(); + for (i = 0; i < 8; i++) { + ao_gps_lexchar(); + ao_gps_skip_field(); + } + a = ao_gps_decimal(2); + c = ao_gps_decimal(2); + i = ao_gps_decimal(2); + /* Skip remaining fields */ + while (ao_gps_char != '*' && ao_gps_char != '\n' && ao_gps_char != '\r') { + ao_gps_lexchar(); + ao_gps_skip_field(); + } + if (ao_gps_char == '*') { + uint8_t cksum = ao_gps_cksum ^ '*'; + if (cksum != ao_gps_hex(2)) + ao_gps_error = 1; + } else + ao_gps_error = 1; + if (!ao_gps_error) { + ao_gps_next.year = i; + ao_gps_next.month = c; + ao_gps_next.day = a; + ao_gps_date_flags = AO_GPS_DATE_VALID; + } } } } diff --git a/src/ao_gps_test.c b/src/ao_gps_test.c index 366bca71..3692f0e5 100644 --- a/src/ao_gps_test.c +++ b/src/ao_gps_test.c @@ -27,8 +27,12 @@ #define AO_GPS_VALID (1 << 4) #define AO_GPS_RUNNING (1 << 5) +#define AO_GPS_DATE_VALID (1 << 6) struct ao_gps_data { + uint8_t year; + uint8_t month; + uint8_t day; uint8_t hour; uint8_t minute; uint8_t second; diff --git a/src/ao_gps_test_skytraq.c b/src/ao_gps_test_skytraq.c index 510bc419..ccf96378 100644 --- a/src/ao_gps_test_skytraq.c +++ b/src/ao_gps_test_skytraq.c @@ -27,8 +27,12 @@ #define AO_GPS_VALID (1 << 4) #define AO_GPS_RUNNING (1 << 5) +#define AO_GPS_DATE_VALID (1 << 6) struct ao_gps_data { + uint8_t year; + uint8_t month; + uint8_t day; uint8_t hour; uint8_t minute; uint8_t second; -- cgit v1.2.3 From b0d7e3f9c9322542e9b649bb6ad7f7e5bb99dffa Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 15 Nov 2009 16:20:18 -0800 Subject: Stop using SiRF state info. With the switch to the skytraq GPS unit, we don't have the same level of detail in the GPS stream, so stop reporting that in the telemetry stream, in the UI and writing it to eeprom. Signed-off-by: Keith Packard --- ao-tools/ao-postflight/ao-postflight.c | 4 ++-- ao-tools/lib/cc-logfile.c | 1 - ao-tools/lib/cc-telem.c | 17 ++++++++++++----- ao-tools/lib/cc.h | 1 - src/ao.h | 12 +----------- src/ao_gps_print.c | 7 +++---- src/ao_gps_sirf.c | 5 +---- src/ao_gps_skytraq.c | 6 ++---- src/ao_gps_test.c | 5 ++--- 9 files changed, 23 insertions(+), 35 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c index 733eb38c..c12939aa 100644 --- a/ao-tools/ao-postflight/ao-postflight.c +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -360,7 +360,7 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, nsat = 0; for (k = 0; k < f->gps.sats[j].nsat; k++) { fprintf (gps_file, " %12.7f", (double) f->gps.sats[j].sat[k].c_n); - if (f->gps.sats[j].sat[k].state == 0xbf) + if (f->gps.sats[j].sat[k].svid != 0) nsat++; } fprintf(gps_file, " %d\n", nsat); @@ -381,7 +381,7 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, } nsat = 0; for (k = 0; k < f->gps.sats[j].nsat; k++) - if (f->gps.sats[j].sat[k].state == 0xbf) + if (f->gps.sats[j].sat[k].svid != 0) nsat++; fprintf(kml_file, "%12.7f, %12.7f, %12.7f ", diff --git a/ao-tools/lib/cc-logfile.c b/ao-tools/lib/cc-logfile.c index 3d346bcc..9d086c82 100644 --- a/ao-tools/lib/cc-logfile.c +++ b/ao-tools/lib/cc-logfile.c @@ -212,7 +212,6 @@ read_eeprom(const char *line, struct cc_flightraw *f, double *ground_pres, int * case AO_LOG_GPS_SAT: sat.time = tick; sat.svid = a; - sat.state = (b & 0xff); sat.c_n = (b >> 8) & 0xff; gpssat_add(&f->gps, &sat); break; diff --git a/ao-tools/lib/cc-telem.c b/ao-tools/lib/cc-telem.c index 9a2f6155..ccd40ac2 100644 --- a/ao-tools/lib/cc-telem.c +++ b/ao-tools/lib/cc-telem.c @@ -178,18 +178,25 @@ cc_telem_parse(const char *input_line, struct cc_telem *telem) } if (tracking_pos >= 0 && nword >= tracking_pos + 2 && strcmp(words[tracking_pos], "SAT") == 0) { int c, n, pos; + int per_sat; + int state; + + if (version >= 2) + per_sat = 2; + else + per_sat = 3; cc_parse_int(&n, words[tracking_pos + 1]); pos = tracking_pos + 2; - if (nword >= pos + n * 3) { + if (nword >= pos + n * per_sat) { 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]); + if (version < 2) + cc_parse_hex(&state, words[pos + 1]); cc_parse_int(&telem->gps_tracking.sats[c].c_n0, - words[pos + 2]); - pos += 3; + words[pos + per_sat - 1]); + pos += per_sat; } } else { telem->gps_tracking.channels = 0; diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index ebc0db7d..0e8ced8a 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -103,7 +103,6 @@ struct cc_gpselt { struct cc_gpssat { double time; uint16_t svid; - uint8_t state; uint8_t c_n; }; diff --git a/src/ao.h b/src/ao.h index c1a0f6e3..b72cac5c 100644 --- a/src/ao.h +++ b/src/ao.h @@ -536,7 +536,7 @@ struct ao_log_record { } gps_altitude; struct { uint16_t svid; - uint8_t state; + uint8_t unused; uint8_t c_n; } gps_sat; struct { @@ -747,18 +747,8 @@ struct ao_gps_data { uint16_t 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 ao_gps_sat_data { uint8_t svid; - uint8_t state; uint8_t c_n_1; }; diff --git a/src/ao_gps_print.c b/src/ao_gps_print.c index 95439ec7..b8b73cd2 100644 --- a/src/ao_gps_print.c +++ b/src/ao_gps_print.c @@ -112,17 +112,16 @@ ao_gps_tracking_print(__xdata struct ao_gps_tracking_data *gps_tracking_data) __ sat = gps_tracking_data->sats; v = 0; for (c = 0; c < n; c++) { - if (sat->svid && sat->state) + if (sat->svid) v++; sat++; } printf("%d ", v); sat = gps_tracking_data->sats; for (c = 0; c < n; c++) { - if (sat->svid && sat->state) - printf (" %3d %02x %3d", + if (sat->svid) + printf (" %3d %3d", sat->svid, - sat->state, sat->c_n_1); sat++; } diff --git a/src/ao_gps_sirf.c b/src/ao_gps_sirf.c index 58438760..eb00224c 100644 --- a/src/ao_gps_sirf.c +++ b/src/ao_gps_sirf.c @@ -108,7 +108,6 @@ static __xdata struct sirf_geodetic_nav_data ao_sirf_data; struct sirf_measured_sat_data { uint8_t svid; - uint16_t state; uint8_t c_n_1; }; @@ -264,8 +263,7 @@ static const struct sirf_packet_parse measured_tracker_data_packet[] = { static const struct sirf_packet_parse measured_sat_data_packet[] = { { SIRF_U8, offsetof (struct sirf_measured_sat_data, svid) }, /* 0 SV id */ - { SIRF_DISCARD, 2 }, /* 1 azimuth, 2 elevation */ - { SIRF_U16, offsetof (struct sirf_measured_sat_data, state) }, /* 2 state */ + { SIRF_DISCARD, 4 }, /* 1 azimuth, 2 elevation, 3 state */ { SIRF_U8, offsetof (struct sirf_measured_sat_data, c_n_1) }, /* C/N0 1 */ { SIRF_DISCARD, 9 }, /* C/N0 2-10 */ { SIRF_END, 0 }, @@ -421,7 +419,6 @@ ao_gps(void) __reentrant ao_gps_tracking_data.channels = ao_sirf_tracker_data.channels; for (i = 0; i < 12; i++) { ao_gps_tracking_data.sats[i].svid = ao_sirf_tracker_data.sats[i].svid; - ao_gps_tracking_data.sats[i].state = (uint8_t) ao_sirf_tracker_data.sats[i].state; ao_gps_tracking_data.sats[i].c_n_1 = ao_sirf_tracker_data.sats[i].c_n_1; } ao_mutex_put(&ao_gps_mutex); diff --git a/src/ao_gps_skytraq.c b/src/ao_gps_skytraq.c index b2eef04b..bf192f28 100644 --- a/src/ao_gps_skytraq.c +++ b/src/ao_gps_skytraq.c @@ -326,10 +326,8 @@ ao_gps(void) __reentrant ao_gps_skip_field(); /* elevation */ ao_gps_lexchar(); ao_gps_skip_field(); /* azimuth */ - if (ao_gps_tracking_next.sats[i].c_n_1 = ao_gps_decimal(2)) /* C/N0 */ - ao_gps_tracking_next.sats[i].state = 0xbf; - else - ao_gps_tracking_next.sats[i].state = 0; + if (!(ao_gps_tracking_next.sats[i].c_n_1 = ao_gps_decimal(2))) /* C/N0 */ + ao_gps_tracking_next.sats[i].svid = 0; ao_gps_tracking_next.channels = i + 1; } if (ao_gps_char == '*') { diff --git a/src/ao_gps_test.c b/src/ao_gps_test.c index 3692f0e5..fddfedfd 100644 --- a/src/ao_gps_test.c +++ b/src/ao_gps_test.c @@ -59,7 +59,6 @@ struct ao_gps_data { struct ao_gps_sat_data { uint8_t svid; - uint8_t state; uint8_t c_n_1; }; @@ -435,9 +434,9 @@ ao_dump_state(void *wchan) printf("\n"); printf ("\t"); for (i = 0; i < 12; i++) - printf (" %2d(%02x)", + printf (" %2d(%02d)", ao_gps_tracking_data.sats[i].svid, - ao_gps_tracking_data.sats[i].state); + ao_gps_tracking_data.sats[i].c_n_1); printf ("\n"); } -- cgit v1.2.3 From 8065b8146a31438e66f83c13b99281ec47439a73 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 20 Nov 2009 11:56:48 -0800 Subject: Add GPS date/time output to ao-postflight. GPS date/time information was already being stored in the log, it just wasn't getting displayed by ao-postflight. Signed-off-by: Keith Packard --- ao-tools/ao-postflight/ao-postflight.c | 12 ++++++++++++ ao-tools/lib/cc-logfile.c | 16 ++++++++++++++++ ao-tools/lib/cc.h | 5 +++++ 3 files changed, 33 insertions(+) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c index c12939aa..a19b7ebb 100644 --- a/ao-tools/ao-postflight/ao-postflight.c +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -208,6 +208,18 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, "Serial: %9d\n" "Flight: %9d\n", f->serial, f->flight); + if (f->year) { + fprintf(summary_file, + "Date: %04d-%02d-%02d\n", + f->year, f->month, f->day); + } + if (f->gps.num) { + fprintf(summary_file, + "Time: %2d:%02d:%02d\n", + f->gps.data[0].hour, + f->gps.data[0].minute, + f->gps.data[0].second); + } 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++) { diff --git a/ao-tools/lib/cc-logfile.c b/ao-tools/lib/cc-logfile.c index 9d086c82..b0fff9f8 100644 --- a/ao-tools/lib/cc-logfile.c +++ b/ao-tools/lib/cc-logfile.c @@ -136,6 +136,7 @@ gpsdata_free(struct cc_gpsdata *data) #define AO_LOG_GPS_LON 'W' #define AO_LOG_GPS_ALT 'H' #define AO_LOG_GPS_SAT 'V' +#define AO_LOG_GPS_DATE 'Y' #define AO_LOG_POS_NONE (~0UL) @@ -195,6 +196,10 @@ read_eeprom(const char *line, struct cc_flightraw *f, double *ground_pres, int * * any stale data before adding this record */ gps.time = tick; + gps.hour = (a & 0xff); + gps.minute = (a >> 8) & 0xff; + gps.second = (b & 0xff); + gps.flags = (b >> 8) & 0xff; gps_valid = GPS_TIME; break; case AO_LOG_GPS_LAT: @@ -215,6 +220,11 @@ read_eeprom(const char *line, struct cc_flightraw *f, double *ground_pres, int * sat.c_n = (b >> 8) & 0xff; gpssat_add(&f->gps, &sat); break; + case AO_LOG_GPS_DATE: + f->year = 2000 + (a & 0xff); + f->month = (a >> 8) & 0xff; + f->day = (b & 0xff); + break; default: return 0; } @@ -266,10 +276,16 @@ read_telem(const char *line, struct cc_flightraw *f) 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) { + f->year = telem.gps.gps_time.year; + f->month = telem.gps.gps_time.month; + f->day = telem.gps.gps_time.day; gps.time = telem.tick; gps.lat = telem.gps.lat; gps.lon = telem.gps.lon; gps.alt = telem.gps.alt; + gps.hour = telem.gps.gps_time.hour; + gps.minute = telem.gps.gps_time.minute; + gps.second = telem.gps.gps_time.second; gpsdata_add(&f->gps, &gps); } return 1; diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 0e8ced8a..bdeeaaf5 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -86,6 +86,10 @@ struct cc_timedata { struct cc_gpselt { double time; + int hour; + int minute; + int second; + int flags; double lat; double lon; double alt; @@ -149,6 +153,7 @@ struct cc_flightraw { int serial; double ground_accel; double ground_pres; + int year, month, day; struct cc_timedata accel; struct cc_timedata pres; struct cc_timedata temp; -- cgit v1.2.3 From 87e6f3e5c1688503ab8595912d8d6eb7139830b7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 20 Nov 2009 12:16:37 -0800 Subject: Eliminate SiRF state values from ao-view. With Skytraq not having any visible GPS state information, just remove this from the display. Signed-off-by: Keith Packard --- ao-tools/ao-view/aoview_state.c | 15 +++------------ ao-tools/lib/cc.h | 1 - 2 files changed, 3 insertions(+), 13 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-view/aoview_state.c b/ao-tools/ao-view/aoview_state.c index 21cea99a..838899a7 100644 --- a/ao-tools/ao-view/aoview_state.c +++ b/ao-tools/ao-view/aoview_state.c @@ -342,23 +342,14 @@ aoview_state_notify(struct cc_telem *data) } if (state->gps.gps_connected) { int nsat_vis = 0; - int nsat_locked = 0; int c; - for (c = 0; c < state->gps_tracking.channels; c++) { - if ((state->gps_tracking.sats[c].state & 0xff) == 0xbf) - nsat_locked++; - } aoview_table_add_row(2, "Satellites Visible", "%d", state->gps_tracking.channels); - aoview_table_add_row(2, "Satellites Locked", "%d", nsat_locked); for (c = 0; c < state->gps_tracking.channels; c++) { - aoview_table_add_row(2, "Satellite id,state,C/N0", - "%3d,%02x,%2d%s", + aoview_table_add_row(2, "Satellite id,C/N0", + "%3d,%2d", state->gps_tracking.sats[c].svid, - state->gps_tracking.sats[c].state, - state->gps_tracking.sats[c].c_n0, - (state->gps_tracking.sats[c].state & 0xff) == 0xbf ? - " LOCKED" : ""); + state->gps_tracking.sats[c].c_n0); } } aoview_table_finish(); diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index bdeeaaf5..46b16a8e 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -233,7 +233,6 @@ struct cc_gps { struct cc_gps_sat { int svid; - int state; int c_n0; }; -- cgit v1.2.3 From 2d77c18b15834046b7b79d49d87211828f2409e9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 21 Nov 2009 21:10:09 -0800 Subject: Convert telemetry file GPS satellite information in cc_log_read The satellite info wasn't being correctly converted from telemetry files to the data log structure, so ao-postflight was not seeing it. Signed-off-by: Keith Packard --- ao-tools/lib/cc-logfile.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'ao-tools/lib') diff --git a/ao-tools/lib/cc-logfile.c b/ao-tools/lib/cc-logfile.c index b0fff9f8..842e5c7c 100644 --- a/ao-tools/lib/cc-logfile.c +++ b/ao-tools/lib/cc-logfile.c @@ -263,6 +263,9 @@ read_telem(const char *line, struct cc_flightraw *f) { struct cc_telem telem; struct cc_gpselt gps; + struct cc_gpssat sat; + int s; + if (!cc_telem_parse(line, &telem)) return 0; f->ground_accel = telem.ground_accel; @@ -288,6 +291,12 @@ read_telem(const char *line, struct cc_flightraw *f) gps.second = telem.gps.gps_time.second; gpsdata_add(&f->gps, &gps); } + for (s = 0; s < telem.gps_tracking.channels; s++) { + sat.time = telem.tick; + sat.svid = telem.gps_tracking.sats[s].svid; + sat.c_n = telem.gps_tracking.sats[s].c_n0; + gpssat_add(&f->gps, &sat); + } return 1; } -- cgit v1.2.3 From d6ba07e885bdc62ba64719c9d8cc42fcecbcb09d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 22 Nov 2009 01:10:44 -0800 Subject: Automatically extract flight number for eeprom and telem filenames. Extract flight number from either telemetry or eeprom files and use that in the resulting filenames. To ensure that files remain unique, add a new field, -seq-%03d. This is appended only when the sequence number is non-zero as it shouldn't occur in normal usage. This also eliminates some duplicate filename creation code in the library and aoview sources. Signed-off-by: Keith Packard --- ao-tools/ao-dumplog/ao-dumplog.c | 32 +++++++++++++++-------- ao-tools/ao-view/aoview_eeprom.c | 2 ++ ao-tools/ao-view/aoview_file.c | 53 +++++++++++++++++++-------------------- ao-tools/ao-view/aoview_log.c | 12 +++++++++ ao-tools/ao-view/aoview_monitor.c | 1 + ao-tools/lib/cc-log.c | 23 +++++++++++------ ao-tools/lib/cc.h | 2 +- 7 files changed, 78 insertions(+), 47 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-dumplog/ao-dumplog.c b/ao-tools/ao-dumplog/ao-dumplog.c index b3a0a25a..440a02b5 100644 --- a/ao-tools/ao-dumplog/ao-dumplog.c +++ b/ao-tools/ao-dumplog/ao-dumplog.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "cc-usb.h" #include "cc.h" @@ -62,6 +63,7 @@ static const char *state_names[] = { "invalid" }; + int main (int argc, char **argv) { @@ -72,7 +74,8 @@ main (int argc, char **argv) char line[8192]; FILE *out; char *filename; - int serial_number; + int serial_number = 0; + int flight = 0; char cmd; int tick, a, b; int block; @@ -84,6 +87,7 @@ main (int argc, char **argv) int remote = 0; int any_valid; int invalid; + char serial_line[8192]; while ((c = getopt_long(argc, argv, "T:D:R", options, NULL)) != -1) { switch (c) { @@ -121,24 +125,17 @@ main (int argc, char **argv) out = NULL; for (;;) { cc_usb_getline(cc, line, sizeof (line)); - 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); - } + if (sscanf(line, "serial-number %u", &serial_number) == 1) + strcpy(serial_line, line); if (!strncmp(line, "software-version", 16)) break; } - if (!out) { + if (!serial_number) { fprintf(stderr, "no serial number found\n"); cc_usb_close(cc); exit(1); } printf ("Serial number: %d\n", serial_number); - printf ("File name: %s\n", filename); done = 0; column = 0; for (block = 0; !done && block < 511; block++) { @@ -170,6 +167,19 @@ main (int argc, char **argv) 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]); diff --git a/ao-tools/ao-view/aoview_eeprom.c b/ao-tools/ao-view/aoview_eeprom.c index 34e2deed..447b83a4 100644 --- a/ao-tools/ao-view/aoview_eeprom.c +++ b/ao-tools/ao-view/aoview_eeprom.c @@ -66,6 +66,8 @@ aoview_eeprom_parse(struct aoview_serial *serial, if (sscanf(line, "serial-number %u", &serial_number) == 1) { aoview_file_set_serial(eeprom_file, serial_number); } else if (sscanf(line, "%c %x %x %x", &cmd, &tick, &a, &b) == 4) { + if (cmd == 'F') + aoview_file_set_flight(eeprom_file, b); aoview_file_printf(eeprom_file, "%s\n", line); if (cmd == 'S' && a == 8) { aoview_eeprom_done(serial); diff --git a/ao-tools/ao-view/aoview_file.c b/ao-tools/ao-view/aoview_file.c index 5288c2f7..292887a0 100644 --- a/ao-tools/ao-view/aoview_file.c +++ b/ao-tools/ao-view/aoview_file.c @@ -28,6 +28,7 @@ struct aoview_file { char *name; int failed; int serial; + int flight; int sequence; }; @@ -94,6 +95,7 @@ gboolean aoview_file_start(struct aoview_file *file) { char base[50]; + char seq[20]; struct tm tm; time_t now; char *full; @@ -105,34 +107,17 @@ aoview_file_start(struct aoview_file *file) if (file->failed) return FALSE; - now = time(NULL); - (void) localtime_r(&now, &tm); - aoview_mkdir(aoview_file_dir); - for (;;) { - snprintf(base, sizeof (base), "%04d-%02d-%02d-serial-%03d-flight-%03d.%s", - tm.tm_year + 1900, - tm.tm_mon + 1, - tm.tm_mday, - file->serial, - file->sequence, - file->ext); - full = aoview_fullname(aoview_file_dir, base); - r = access(full, F_OK); - if (r < 0) { - file->file = fopen(full, "w"); - if (!file->file) { - aoview_file_open_failed(full); - free(full); - file->failed = 1; - return FALSE; - } else { - setlinebuf(file->file); - file->name = full; - return TRUE; - } - } + full = cc_make_filename(file->serial, file->flight, file->ext); + file->file = fopen(full, "w"); + if (!file->file) { + aoview_file_open_failed(full); free(full); - file->sequence++; + file->failed = 1; + return FALSE; + } else { + setlinebuf(file->file); + file->name = full; + return TRUE; } } @@ -195,6 +180,20 @@ aoview_file_get_serial(struct aoview_file *file) return file->serial; } +void +aoview_file_set_flight(struct aoview_file *file, int flight) +{ + if (flight != file->flight) + aoview_file_finish(file); + file->flight = flight; +} + +int +aoview_file_get_flight(struct aoview_file *file) +{ + return file->flight; +} + void aoview_file_init(GladeXML *xml) { diff --git a/ao-tools/ao-view/aoview_log.c b/ao-tools/ao-view/aoview_log.c index 1b89c28c..2880ecb1 100644 --- a/ao-tools/ao-view/aoview_log.c +++ b/ao-tools/ao-view/aoview_log.c @@ -38,6 +38,18 @@ aoview_log_get_serial(void) return aoview_file_get_serial(aoview_log); } +void +aoview_log_set_flight(int flight) +{ + aoview_file_set_flight(aoview_log, flight); +} + +int +aoview_log_get_flight(void) +{ + return aoview_file_get_flight(aoview_log); +} + void aoview_log_printf(char *format, ...) { diff --git a/ao-tools/ao-view/aoview_monitor.c b/ao-tools/ao-view/aoview_monitor.c index 3d235e44..4d7e7a9f 100644 --- a/ao-tools/ao-view/aoview_monitor.c +++ b/ao-tools/ao-view/aoview_monitor.c @@ -68,6 +68,7 @@ aoview_monitor_callback(gpointer user_data, if (monitor_pos) { if (aoview_monitor_parse(monitor_line)) { aoview_log_set_serial(aostate.data.serial); + aoview_log_set_flight(aostate.data.flight); if (aoview_log_get_serial()) aoview_log_printf ("%s\n", monitor_line); } diff --git a/ao-tools/lib/cc-log.c b/ao-tools/lib/cc-log.c index dd8177f4..ed51f87e 100644 --- a/ao-tools/lib/cc-log.c +++ b/ao-tools/lib/cc-log.c @@ -82,9 +82,10 @@ cc_get_log_dir(void) } char * -cc_make_filename(int serial, char *ext) +cc_make_filename(int serial, int flight, char *ext) { char base[50]; + char seq[20]; struct tm tm; time_t now; char *full; @@ -96,13 +97,19 @@ cc_make_filename(int serial, char *ext) 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); + if (sequence) + snprintf(seq, sizeof(seq), "-seq-%03d", sequence); + else + seq[0] = '\0'; + + snprintf(base, sizeof (base), "%04d-%02d-%02d-serial-%03d-flight-%03d%s.%s", + tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + serial, + flight, + seq, + ext); full = cc_fullname(cc_get_log_dir(), base); r = access(full, F_OK); if (r < 0) diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 46b16a8e..ede46aa0 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -61,7 +61,7 @@ char * cc_get_log_dir(void); char * -cc_make_filename(int serial, char *ext); +cc_make_filename(int serial, int flight, char *ext); /* * For sequential data which are not evenly spaced -- cgit v1.2.3 From 9856b7c4397afcecc8f541af9a83824e817b3612 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 10 Jan 2010 16:31:50 -0800 Subject: Switch to using internal cc1111 temperature sensor v0.2 has no temperature sensor, and several of the v0.1 boards didn't get a temperature sensor loaded. Use the internal temperature sensor on the cc1111 in all cases instead. Signed-off-by: Keith Packard --- ao-tools/ao-view/aoview_state.c | 8 ++++---- ao-tools/lib/cc-convert.c | 11 ++++++++++- src/ao_adc.c | 12 +++++++----- src/ao_convert.c | 10 +++++++++- 4 files changed, 30 insertions(+), 11 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-view/aoview_state.c b/ao-tools/ao-view/aoview_state.c index 838899a7..505bcddc 100644 --- a/ao-tools/ao-view/aoview_state.c +++ b/ao-tools/ao-view/aoview_state.c @@ -127,10 +127,10 @@ aoview_state_derive(struct cc_telem *data, struct aostate *state) accel_counts_per_mss = ((data->accel_minus_g - data->accel_plus_g) / 2.0) / 9.80665; state->acceleration = (data->ground_accel - data->flight_accel) / accel_counts_per_mss; state->speed = data->flight_vel / (accel_counts_per_mss * 100.0); - state->temperature = ((data->temp / 32767.0 * 3.3) - 0.5) / 0.01; - state->drogue_sense = data->drogue / 32767.0 * 15.0; - state->main_sense = data->main / 32767.0 * 15.0; - state->battery = data->batt / 32767.0 * 5.0; + state->temperature = cc_thermometer_to_temperature(data->temp); + state->drogue_sense = cc_ignitor_to_voltage(data->drogue); + state->main_sense = cc_ignitor_to_voltage(data->main); + state->battery = cc_battery_to_voltage(data->batt); if (!strcmp(data->state, "pad")) { if (data->gps.gps_locked && data->gps.nsat >= 4) { state->npad++; diff --git a/ao-tools/lib/cc-convert.c b/ao-tools/lib/cc-convert.c index ac6962ba..8d6876a0 100644 --- a/ao-tools/lib/cc-convert.c +++ b/ao-tools/lib/cc-convert.c @@ -213,10 +213,19 @@ cc_accelerometer_to_acceleration(double accel, double ground_accel) return (ground_accel - accel) / count_per_mss; } +/* Value for the CC1111 built-in temperature sensor + * Output voltage at 0°C = 0.755V + * Coefficient = 0.00247V/°C + * Reference voltage = 1.25V + * + * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 + * = (value - 19791.268) / 32768 * 1.25 / 0.00247 + */ + double cc_thermometer_to_temperature(double thermo) { - return ((thermo / 32767 * 3.3) - 0.5) / 0.01; + return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247; } double diff --git a/src/ao_adc.c b/src/ao_adc.c index b0bfceb1..2b972e6c 100644 --- a/src/ao_adc.c +++ b/src/ao_adc.c @@ -46,16 +46,18 @@ ao_adc_isr(void) interrupt 1 uint8_t __xdata *a; sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT; + if (sequence == ADCCON3_ECH_TEMP) + sequence = 2; a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence); a[0] = ADCL; a[1] = ADCH; if (sequence < 5) { /* start next channel conversion */ - sequence++; - /* skip channel 2, we don't have a temp sensor on v0.2 */ - if (sequence == 2) - sequence++; - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence; + /* v0.2 replaces external temp sensor with internal one */ + if (sequence == 1) + ADCCON3 = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; + else + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | (sequence + 1); } else { /* record this conversion series */ ao_adc_ring[ao_adc_head].tick = ao_time(); diff --git a/src/ao_convert.c b/src/ao_convert.c index 57ed7370..f29ce9e9 100644 --- a/src/ao_convert.c +++ b/src/ao_convert.c @@ -49,7 +49,15 @@ ao_temp_to_dC(int16_t temp) __reentrant int16_t ret; ao_mutex_get(&ao_temp_mutex); - ret = (int16_t) ((temp >> 4) * 3300L / 2047L) - 500; + /* Output voltage at 0°C = 0.755V + * Coefficient = 0.00247V/°C + * Reference voltage = 1.25V + * + * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247 + * = (value - 19791.268) / 32768 * 1.25 / 0.00247 + * ≃ (value - 19791) * 1012 / 65536 + */ + ret = ((temp - 19791) * 1012L) >> 16; ao_mutex_put(&ao_temp_mutex); return ret; } -- cgit v1.2.3 From c83615567b4567f3dc45a7f7b894943b45fbb65c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 7 Feb 2010 00:25:22 -0800 Subject: Pull in a bit more data for filtering the start of the boost --- ao-tools/lib/cc-process.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/lib/cc-process.c b/ao-tools/lib/cc-process.c index 5c1acc6b..c756b570 100644 --- a/ao-tools/lib/cc-process.c +++ b/ao-tools/lib/cc-process.c @@ -70,7 +70,7 @@ cc_flight_cook(struct cc_flightraw *raw) */ for (i = 0; i < raw->state.num; i++) { if (!start_set && raw->state.data[i].value > ao_flight_pad) { - flight_start = raw->state.data[i].time; + flight_start = raw->state.data[i].time - 10; start_set = 1; } if (!stop_set && raw->state.data[i].value > ao_flight_main) { @@ -79,7 +79,7 @@ cc_flight_cook(struct cc_flightraw *raw) } } - if (!start_set) + if (!start_set || flight_start < raw->accel.data[0].time) flight_start = raw->accel.data[0].time; if (stop_set) { for (i = 0; i < raw->accel.num - 1; i++) { @@ -101,8 +101,8 @@ cc_flight_cook(struct cc_flightraw *raw) accel_speed = cc_timedata_integrate(&cooked->accel, flight_start - 10, flight_stop); accel_pos = cc_timedata_integrate(accel_speed, flight_start - 10, flight_stop); -#define ACCEL_OMEGA_PASS (2 * M_PI * 5 / 100) -#define ACCEL_OMEGA_STOP (2 * M_PI * 8 / 100) +#define ACCEL_OMEGA_PASS (2 * M_PI * 20 / 100) +#define ACCEL_OMEGA_STOP (2 * M_PI * 30 / 100) #define BARO_OMEGA_PASS (2 * M_PI * .5 / 100) #define BARO_OMEGA_STOP (2 * M_PI * 1 / 100) #define FILTER_ERROR (1e-8) -- cgit v1.2.3 From 1e60deca147c85a064719dfad14ccabd1049bbbd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 25 Feb 2010 16:33:34 -0800 Subject: Allow product names to have suffixes (like board revisions) When looking for a board by product name, just look at the prefix of the name instead of requiring an exact match. This will allow products to have board version suffixes. Signed-off-by: Keith Packard --- ao-tools/lib/cc-usbdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/lib/cc-usbdev.c b/ao-tools/lib/cc-usbdev.c index ed39c062..afa91d49 100644 --- a/ao-tools/lib/cc-usbdev.c +++ b/ao-tools/lib/cc-usbdev.c @@ -258,7 +258,7 @@ match_dev(char *product, int serial) return NULL; for (i = 0; i < devs->ndev; i++) { dev = devs->dev[i]; - if (product && strcmp (product, dev->product) != 0) + if (product && strncmp (product, dev->product, strlen(product)) != 0) continue; if (serial && serial != dev->serial) continue; -- cgit v1.2.3 From a9ec6be0e92dee01f7aac006ef6f7779c1da1b36 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 3 Jul 2010 17:42:36 -0400 Subject: Telemetry code was mis-computing RSSI The RSSI data from the hardware reports in 1/2 dBm increments, and so must be divided to report plain RSSI numbers. Signed-off-by: Keith Packard --- ao-tools/lib/cc-telem.c | 4 ++++ configure.ac | 2 ++ src/ao.h | 2 +- src/ao_monitor.c | 10 +++++++--- 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/lib/cc-telem.c b/ao-tools/lib/cc-telem.c index ccd40ac2..aa52b7c5 100644 --- a/ao-tools/lib/cc-telem.c +++ b/ao-tools/lib/cc-telem.c @@ -101,6 +101,10 @@ cc_telem_parse(const char *input_line, struct cc_telem *telem) telem->flight = 0; cc_parse_int(&telem->rssi, words[5]); + if (version <= 2) { + /* Older telemetry versions mis-computed the rssi value */ + telem->rssi = (telem->rssi + 74) / 2 - 74; + } cc_parse_string(telem->state, sizeof (telem->state), words[9]); cc_parse_int(&telem->tick, words[10]); cc_parse_int(&telem->accel, words[12]); diff --git a/configure.ac b/configure.ac index d6c8682b..fafc6b34 100644 --- a/configure.ac +++ b/configure.ac @@ -77,6 +77,8 @@ PKG_CHECK_MODULES([ALSA], [alsa]) PKG_CHECK_MODULES([PLPLOT], [plplotd]) +PKG_CHECK_MODULES([SNDFILE], [sndfile]) + AC_OUTPUT([ Makefile ao-tools/Makefile diff --git a/src/ao.h b/src/ao.h index a2dfadd0..dfff8a8d 100644 --- a/src/ao.h +++ b/src/ao.h @@ -804,7 +804,7 @@ ao_gps_report_init(void); */ #define AO_MAX_CALLSIGN 8 -#define AO_TELEMETRY_VERSION 2 +#define AO_TELEMETRY_VERSION 3 struct ao_telemetry { uint8_t addr; diff --git a/src/ao_monitor.c b/src/ao_monitor.c index f2f3fc2e..f019d3b4 100644 --- a/src/ao_monitor.c +++ b/src/ao_monitor.c @@ -26,6 +26,7 @@ ao_monitor(void) __xdata struct ao_radio_recv recv; __xdata char callsign[AO_MAX_CALLSIGN+1]; uint8_t state; + int16_t rssi; for (;;) { __critical while (!ao_monitoring) @@ -33,6 +34,9 @@ ao_monitor(void) if (!ao_radio_recv(&recv)) continue; state = recv.telemetry.flight_state; + + /* Typical RSSI offset for 38.4kBaud at 433 MHz is 74 */ + rssi = (int16_t) (recv.rssi >> 1) - 74; memcpy(callsign, recv.telemetry.callsign, AO_MAX_CALLSIGN); if (state > ao_flight_invalid) state = ao_flight_invalid; @@ -42,7 +46,7 @@ ao_monitor(void) callsign, recv.telemetry.addr, recv.telemetry.flight, - (int) recv.rssi - 74, recv.status, + rssi, recv.status, ao_state_names[state]); printf("%5u a: %5d p: %5d t: %5d v: %5d d: %5d m: %5d " "fa: %5d ga: %d fv: %7ld fp: %5d gp: %5d a+: %5d a-: %5d ", @@ -64,9 +68,9 @@ ao_monitor(void) putchar(' '); ao_gps_tracking_print(&recv.telemetry.gps_tracking); putchar('\n'); - ao_rssi_set((int) recv.rssi - 74); + ao_rssi_set(rssi); } else { - printf("CRC INVALID RSSI %3d\n", (int) recv.rssi - 74); + printf("CRC INVALID RSSI %3d\n", rssi); } ao_usb_flush(); ao_led_toggle(ao_monitor_led); -- cgit v1.2.3 From 294d9c7db21eaf1e71504dbcca5040371abcce55 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Aug 2010 22:30:55 -0400 Subject: ao-dumplog: add --channel option (for use with -R option) Sets the channel when downloading data with the -R option. Signed-off-by: Keith Packard --- ao-tools/ao-dumplog/ao-dumplog.c | 9 +++++++-- ao-tools/lib/cc-usb.c | 5 +++-- ao-tools/lib/cc-usb.h | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-dumplog/ao-dumplog.c b/ao-tools/ao-dumplog/ao-dumplog.c index 440a02b5..57c43290 100644 --- a/ao-tools/ao-dumplog/ao-dumplog.c +++ b/ao-tools/ao-dumplog/ao-dumplog.c @@ -30,12 +30,13 @@ static const struct option options[] = { { .name = "tty", .has_arg = 1, .val = 'T' }, { .name = "device", .has_arg = 1, .val = 'D' }, { .name = "remote", .has_arg = 1, .val = 'R' }, + { .name = "channel", .has_arg = 1, .val = 'C' }, { 0, 0, 0, 0}, }; static void usage(char *program) { - fprintf(stderr, "usage: %s [--tty ] [--device ] [-R]\n", program); + fprintf(stderr, "usage: %s [--tty ] [--device ] [--remote] [--channel ]\n", program); exit(1); } @@ -75,6 +76,7 @@ main (int argc, char **argv) FILE *out; char *filename; int serial_number = 0; + int channel = 0; int flight = 0; char cmd; int tick, a, b; @@ -100,6 +102,9 @@ main (int argc, char **argv) case 'R': remote = 1; break; + case 'C': + channel = atoi(optarg); + break; default: usage(argv[0]); break; @@ -119,7 +124,7 @@ main (int argc, char **argv) if (!cc) exit(1); if (remote) - cc_usb_open_remote(cc); + cc_usb_open_remote(cc, channel); /* send a 'version' command followed by a 'log' command */ cc_usb_printf(cc, "v\n"); out = NULL; diff --git a/ao-tools/lib/cc-usb.c b/ao-tools/lib/cc-usb.c index 53a50741..1580c6d9 100644 --- a/ao-tools/lib/cc-usb.c +++ b/ao-tools/lib/cc-usb.c @@ -375,10 +375,11 @@ cc_usb_reset(struct cc_usb *cc) } void -cc_usb_open_remote(struct cc_usb *cc) +cc_usb_open_remote(struct cc_usb *cc, int channel) { if (!cc->remote) { - cc_usb_printf(cc, "\np\nE 0\n"); + printf ("channel %d\n", channel); + cc_usb_printf(cc, "\nc r %d\np\nE 0\n", channel); do { cc->in_count = cc->in_pos = 0; _cc_usb_sync(cc, 100); diff --git a/ao-tools/lib/cc-usb.h b/ao-tools/lib/cc-usb.h index 627f1b5d..d3539281 100644 --- a/ao-tools/lib/cc-usb.h +++ b/ao-tools/lib/cc-usb.h @@ -63,7 +63,7 @@ void cc_usb_printf(struct cc_usb *cc, char *format, ...); void -cc_usb_open_remote(struct cc_usb *cc); +cc_usb_open_remote(struct cc_usb *cc, int channel); void cc_usb_close_remote(struct cc_usb *cc); -- cgit v1.2.3 From 3b87dd6f46922cf5f98deb2dffa2148c4244e48e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 13 Aug 2011 15:00:14 -0700 Subject: ao-tools: ao-list was crashing with more than 3 devices connected the list of devices was getting realloced for each new device, but that realloc was too small. Signed-off-by: Keith Packard --- ao-tools/lib/cc-usbdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/lib/cc-usbdev.c b/ao-tools/lib/cc-usbdev.c index afa91d49..a19e231c 100644 --- a/ao-tools/lib/cc-usbdev.c +++ b/ao-tools/lib/cc-usbdev.c @@ -223,7 +223,7 @@ cc_usbdevs_scan(void) if (dev->idVendor == 0xfffe && dev->tty) { if (devs->dev) devs->dev = realloc(devs->dev, - devs->ndev + 1 * sizeof (struct usbdev *)); + (devs->ndev + 1) * sizeof (struct usbdev *)); else devs->dev = malloc (sizeof (struct usbdev *)); devs->dev[devs->ndev++] = dev; -- cgit v1.2.3 From 63808e0392f43633f92fee137d968e969dd364c9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 23 Aug 2011 23:20:00 -0700 Subject: Remove stale tools (ao-dumplog, ao-postflight, ao-view) These tools have all been supplanted by altosui at this point, and keeping them around increases the build dependencies by quite a lot. Signed-off-by: Keith Packard --- ao-tools/Makefile.am | 2 +- ao-tools/lib/Makefile.am | 4 +++- configure.ac | 25 ------------------------- debian/control | 4 ++-- 4 files changed, 6 insertions(+), 29 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am index 2850e909..8144be1c 100644 --- a/ao-tools/Makefile.am +++ b/ao-tools/Makefile.am @@ -1 +1 @@ -SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view +SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index 79972f46..da355db5 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -2,6 +2,9 @@ noinst_LIBRARIES = libao-tools.a AM_CFLAGS=$(WARN_CFLAGS) $(LIBUSB_CFLAGS) $(GNOME_CFLAGS) +libao_tools_a_uneeded = \ + cc-log.c + libao_tools_a_SOURCES = \ ccdbg-command.c \ ccdbg-debug.c \ @@ -17,7 +20,6 @@ libao_tools_a_SOURCES = \ cc-analyse.c \ cc-convert.c \ cc-dsp.c \ - cc-log.c \ cc-integrate.c \ cc-period.c \ cc-process.c \ diff --git a/configure.ac b/configure.ac index 93f53115..0a6001b8 100644 --- a/configure.ac +++ b/configure.ac @@ -95,20 +95,6 @@ if test "x$GCC" = "xyes"; then fi AC_SUBST(WARN_CFLAGS) -AC_CHECK_HEADERS(flite/flite.h,HAVE_FLITE_H=yes,HAVE_FLITE_H=no) -AC_CHECK_LIB(flite, flite_init,HAVE_LIBFLITE=yes,HAVE_LIBFLITE=no,-lasound -lm) - -if test "x$HAVE_FLITE_H" = "xyes" -a "x$HAVE_LIBFLITE" = "xyes"; then - AC_DEFINE(HAVE_FLITE,1,[Define if the flite library is usable]) - AC_SUBST(FLITE_LIBS,"-lflite_cmu_us_kal16 -lflite_usenglish -lflite_cmulex -lflite -lasound -lm") - AC_SUBST(FLITE_INCS,-Iflite) - save_LIBS="$LIBS" - LIBS="$LIBS $FLITE_LIBS" - AC_CHECK_FUNCS([register_cmu_us_kal16 register_cmu_us_kal],break) - LIBS="$save_LIBS" -fi -AM_CONDITIONAL(USE_FLITE,test "x$HAVE_FLITE_H" = "xyes" -a "x$HAVE_LIBFLITE" = "xyes") - AC_CHECK_PROG([HAVE_SDCC], [sdcc], yes, no) if test "x$HAVE_SDCC" = "xno"; then AC_MSG_ERROR([Please install sdcc to build AltOs]) @@ -121,16 +107,8 @@ fi AC_CHECK_LIB(readline, readline) -PKG_CHECK_MODULES([GNOME], [gtk+-2.0 libglade-2.0 gconf-2.0]) - PKG_CHECK_MODULES([LIBUSB], [libusb-1.0]) -PKG_CHECK_MODULES([ALSA], [alsa]) - -PKG_CHECK_MODULES([PLPLOT], [plplotd]) - -PKG_CHECK_MODULES([SNDFILE], [sndfile]) - AC_OUTPUT([ Makefile altosui/Makefile @@ -140,13 +118,10 @@ 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 src/Version ]) diff --git a/debian/control b/debian/control index fc70c8e0..f784a702 100644 --- a/debian/control +++ b/debian/control @@ -3,13 +3,13 @@ Section: otherosfs Priority: extra Maintainer: Bdale Garbee Uploaders: Keith Packard -Build-Depends: debhelper (>= 7), autoconf, automake, flite1-dev, gawk, libasound2-dev, libgconf2-dev, libglade2-dev, libgtk2.0-dev, libreadline-dev, libusb-1.0-0-dev, nickle, sdcc, libplplot-dev, xsltproc, fop, docbook-xml, docbook-xsl, libsndfile1-dev, swig, openjdk-6-jdk, freetts, libtool, libjfreechart-java, libbluetooth-dev +Build-Depends: debhelper (>= 7), autoconf, automake, gawk, libreadline-dev, libusb-1.0-0-dev, nickle, sdcc, xsltproc, fop, docbook-xml, docbook-xsl, swig, openjdk-6-jdk, freetts, libtool, libjfreechart-java, libbluetooth-dev Standards-Version: 3.9.2 Homepage: http://altusmetrum.org/AltOS Package: altos Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, default-jre | java2-runtime, freetts, nickle, plplot9-driver-cairo +Depends: ${shlibs:Depends}, ${misc:Depends}, default-jre | java2-runtime, freetts, nickle Suggests: slim | gdm Replaces: altusmetrum-themes, slim-altusmetrum Conflicts: altusmetrum-themes, slim-altusmetrum -- cgit v1.2.3 From 82604193ed0c522c1fba0072b504fe88b027f1ee Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 8 Oct 2011 11:50:24 -0600 Subject: ao-telem: Add new program to convert telem data to ascii This reads telem files and displays them in ascii form. It's not done, and it's not documented, but it's a start. Signed-off-by: Keith Packard --- ao-tools/Makefile.am | 2 +- ao-tools/ao-telem/Makefile.am | 12 +++ ao-tools/ao-telem/ao-telem.1 | 61 ++++++++++++++ ao-tools/ao-telem/ao-telem.c | 112 +++++++++++++++++++++++++ ao-tools/lib/Makefile.am | 2 + ao-tools/lib/cc-telemetry.c | 62 ++++++++++++++ ao-tools/lib/cc-telemetry.h | 188 ++++++++++++++++++++++++++++++++++++++++++ ao-tools/lib/cc.h | 1 + configure.ac | 1 + 9 files changed, 440 insertions(+), 1 deletion(-) create mode 100644 ao-tools/ao-telem/Makefile.am create mode 100644 ao-tools/ao-telem/ao-telem.1 create mode 100644 ao-tools/ao-telem/ao-telem.c create mode 100644 ao-tools/lib/cc-telemetry.c create mode 100644 ao-tools/lib/cc-telemetry.h (limited to 'ao-tools/lib') diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am index 8144be1c..611bb7dc 100644 --- a/ao-tools/Makefile.am +++ b/ao-tools/Makefile.am @@ -1 +1 @@ -SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load +SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list ao-load ao-telem diff --git a/ao-tools/ao-telem/Makefile.am b/ao-tools/ao-telem/Makefile.am new file mode 100644 index 00000000..3436443e --- /dev/null +++ b/ao-tools/ao-telem/Makefile.am @@ -0,0 +1,12 @@ +bin_PROGRAMS=ao-telem + +AM_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 diff --git a/ao-tools/ao-telem/ao-telem.1 b/ao-tools/ao-telem/ao-telem.1 new file mode 100644 index 00000000..8e6699d5 --- /dev/null +++ b/ao-tools/ao-telem/ao-telem.1 @@ -0,0 +1,61 @@ +.\" +.\" Copyright © 2009 Keith Packard +.\" +.\" 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 \- Analyse a flight log (either telemetry or eeprom) +.SH SYNOPSIS +.B "ao-telem" +[\-s ] +[\--summary=] +[\-d ] +[\--detail=] +[\-r ] +[\--raw=] +[\-p ] +[\--plot=] +[\-g + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "cc.h" + +static const struct option options[] = { + { 0, 0, 0, 0}, +}; + +static void usage(char *program) +{ + fprintf(stderr, "usage: %s\n" + "\t{flight-log} ...\n", program); + exit(1); +} + +int +main (int argc, char **argv) +{ + char line[80]; + int c, i, ret; + char *s; + FILE *file; + int serial; + while ((c = getopt_long(argc, argv, "", 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)) { + union ao_telemetry_all telem; + char call[AO_MAX_CALLSIGN+1]; + char version[AO_MAX_VERSION+1]; + + if (cc_telemetry_parse(line, &telem)) { + printf ("serial %5d tick %5d type %3d ", + telem.generic.serial, telem.generic.tick, telem.generic.type); + 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 %5d speed %5d height %5d ", + telem.sensor.acceleration, + telem.sensor.speed, + 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", + 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; + default: + printf("\n"); + } + } + } + fclose (file); + + } + return ret; +} diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index da355db5..1f8f2e42 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -32,6 +32,8 @@ libao_tools_a_SOURCES = \ cc-bitbang.h \ cc-logfile.c \ cc-telem.c \ + cc-telemetry.c \ + cc-telemetry.h \ cp-usb-async.c \ cp-usb-async.h \ i0.c \ diff --git a/ao-tools/lib/cc-telemetry.c b/ao-tools/lib/cc-telemetry.c new file mode 100644 index 00000000..2cdb9cac --- /dev/null +++ b/ao-tools/lib/cc-telemetry.c @@ -0,0 +1,62 @@ +/* + * Copyright © 2011 Keith Packard + * + * 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 + +static int +parse_byte(char *data, uint8_t *byte) +{ + char d[3]; + int x; + d[0] = data[0]; + d[1] = data[1]; + d[2] = '\0'; + + if (sscanf(d, "%x", &x) != 1) + return FALSE; + *byte = x; + return TRUE; +} + +int +cc_telemetry_parse(const char *input_line, union ao_telemetry_all *telemetry) +{ + uint8_t *byte; + char *data; + uint8_t hex[35]; + int i; + + if (strncmp(input_line, "TELEM", 5) != 0) + return FALSE; + + data = strchr (input_line, ' '); + if (!data) + return FALSE; + data++; + byte = hex; + for (i = 0; i < 35; i++) { + if (!parse_byte(data, byte)) + return FALSE; + data += 2; + byte++; + } + if (hex[0] != 34) + return FALSE; + memcpy(telemetry, hex+1, 32); + return TRUE; +} diff --git a/ao-tools/lib/cc-telemetry.h b/ao-tools/lib/cc-telemetry.h new file mode 100644 index 00000000..5a66b971 --- /dev/null +++ b/ao-tools/lib/cc-telemetry.h @@ -0,0 +1,188 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _CC_TELEMETRY_H_ +#define _CC_TELEMETRY_H_ +/* + * ao_telemetry.c + */ +#define AO_MAX_CALLSIGN 8 +#define AO_MAX_VERSION 8 +#define AO_MAX_TELEMETRY 128 + +struct ao_telemetry_generic { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t payload[27]; /* 5 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 +#define AO_TELEMETRY_SENSOR_TELEMINI 0x02 +#define AO_TELEMETRY_SENSOR_TELENANO 0x03 + +struct ao_telemetry_sensor { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t state; /* 5 flight state */ + int16_t accel; /* 6 accelerometer (TM only) */ + int16_t pres; /* 8 pressure sensor */ + int16_t temp; /* 10 temperature sensor */ + int16_t v_batt; /* 12 battery voltage */ + int16_t sense_d; /* 14 drogue continuity sense (TM/Tm) */ + int16_t sense_m; /* 16 main continuity sense (TM/Tm) */ + + int16_t acceleration; /* 18 m/s² * 16 */ + int16_t speed; /* 20 m/s * 16 */ + int16_t height; /* 22 m */ + + int16_t ground_pres; /* 24 average pres on pad */ + int16_t ground_accel; /* 26 average accel on pad */ + int16_t accel_plus_g; /* 28 accel calibration at +1g */ + int16_t accel_minus_g; /* 30 accel calibration at -1g */ + /* 32 */ +}; + +#define AO_TELEMETRY_CONFIGURATION 0x04 + +struct ao_telemetry_configuration { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t device; /* 5 device type */ + uint16_t flight; /* 6 flight number */ + uint8_t config_major; /* 8 Config major version */ + uint8_t config_minor; /* 9 Config minor version */ + uint16_t apogee_delay; /* 10 Apogee deploy delay in seconds */ + uint16_t main_deploy; /* 12 Main deploy alt in meters */ + uint16_t flight_log_max; /* 14 Maximum flight log size in kB */ + char callsign[AO_MAX_CALLSIGN]; /* 16 Radio operator identity */ + char version[AO_MAX_VERSION]; /* 24 Software version */ + /* 32 */ +}; + +#define AO_TELEMETRY_LOCATION 0x05 + +#define AO_GPS_MODE_NOT_VALID 'N' +#define AO_GPS_MODE_AUTONOMOUS 'A' +#define AO_GPS_MODE_DIFFERENTIAL 'D' +#define AO_GPS_MODE_ESTIMATED 'E' +#define AO_GPS_MODE_MANUAL 'M' +#define AO_GPS_MODE_SIMULATED 'S' + +struct ao_telemetry_location { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t flags; /* 5 Number of sats and other flags */ + int16_t altitude; /* 6 GPS reported altitude (m) */ + int32_t latitude; /* 8 latitude (degrees * 10⁷) */ + int32_t longitude; /* 12 longitude (degrees * 10⁷) */ + uint8_t year; /* 16 (- 2000) */ + uint8_t month; /* 17 (1-12) */ + uint8_t day; /* 18 (1-31) */ + uint8_t hour; /* 19 (0-23) */ + uint8_t minute; /* 20 (0-59) */ + uint8_t second; /* 21 (0-59) */ + uint8_t pdop; /* 22 (m * 5) */ + uint8_t hdop; /* 23 (m * 5) */ + uint8_t vdop; /* 24 (m * 5) */ + uint8_t mode; /* 25 */ + uint16_t ground_speed; /* 26 cm/s */ + int16_t climb_rate; /* 28 cm/s */ + uint8_t course; /* 30 degrees / 2 */ + uint8_t unused[1]; /* 31 */ + /* 32 */ +}; + +#define AO_TELEMETRY_SATELLITE 0x06 + +struct ao_telemetry_satellite_info { + uint8_t svid; + uint8_t c_n_1; +}; + +struct ao_telemetry_satellite { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t channels; /* 5 number of reported sats */ + + struct ao_telemetry_satellite_info sats[12]; /* 6 */ + uint8_t unused[2]; /* 30 */ + /* 32 */ +}; + +#define AO_TELEMETRY_COMPANION 0x07 + +#define AO_COMPANION_MAX_CHANNELS 12 + +struct ao_telemetry_companion { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t board_id; /* 5 */ + + uint8_t update_period; /* 6 */ + uint8_t channels; /* 7 */ + uint16_t companion_data[AO_COMPANION_MAX_CHANNELS]; /* 8 */ + /* 32 */ +}; + +/* #define AO_SEND_ALL_BARO */ + +#define AO_TELEMETRY_BARO 0x80 + +/* + * This packet allows the full sampling rate baro + * data to be captured over the RF link so that the + * flight software can be tested using 'real' data. + * + * Along with this telemetry packet, the flight + * code is modified to send full-rate telemetry all the time + * and never send an RDF tone; this ensure that the full radio + * link is available. + */ +struct ao_telemetry_baro { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + uint8_t samples; /* 5 number samples */ + + int16_t baro[12]; /* 6 samples */ + /* 32 */ +}; + +union ao_telemetry_all { + struct ao_telemetry_generic generic; + struct ao_telemetry_sensor sensor; + struct ao_telemetry_configuration configuration; + struct ao_telemetry_location location; + struct ao_telemetry_satellite satellite; + struct ao_telemetry_companion companion; + struct ao_telemetry_baro baro; +}; + +int +cc_telemetry_parse(const char *input_line, union ao_telemetry_all *telemetry); + +#endif diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index ede46aa0..6257ee44 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -20,6 +20,7 @@ #include #include +#include "cc-telemetry.h" char * cc_fullname (char *dir, char *file); diff --git a/configure.ac b/configure.ac index 9f1921b9..1a2cc813 100644 --- a/configure.ac +++ b/configure.ac @@ -122,6 +122,7 @@ ao-tools/ao-bitbang/Makefile ao-tools/ao-eeprom/Makefile ao-tools/ao-list/Makefile ao-tools/ao-load/Makefile +ao-tools/ao-telem/Makefile ao-utils/Makefile src/Version ]) -- cgit v1.2.3 From 69feb1e3d94a028d04529edb015654bafd06353b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 1 May 2012 18:12:41 -0700 Subject: ao-tools: Add GPS and rssi printing to ao-telem This prints all of the basic telemetrum messages now. Signed-off-by: Keith Packard --- ao-tools/ao-telem/ao-telem.c | 64 +++++++++++++++++++++++++++++++++++++++----- ao-tools/lib/cc-telemetry.c | 2 +- ao-tools/lib/cc-telemetry.h | 4 ++- 3 files changed, 62 insertions(+), 8 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-telem/ao-telem.c b/ao-tools/ao-telem/ao-telem.c index 0f671e1b..6207d433 100644 --- a/ao-tools/ao-telem/ao-telem.c +++ b/ao-tools/ao-telem/ao-telem.c @@ -34,6 +34,8 @@ static void usage(char *program) exit(1); } +#define bool(b) ((b) ? "true" : "false") + int main (int argc, char **argv) { @@ -63,21 +65,28 @@ main (int argc, char **argv) serial = 0; while (fgets(line, sizeof (line), file)) { union ao_telemetry_all telem; - char call[AO_MAX_CALLSIGN+1]; + char call[AO_MAX_CALLSIGN+1]; char version[AO_MAX_VERSION+1]; if (cc_telemetry_parse(line, &telem)) { - printf ("serial %5d tick %5d type %3d ", - telem.generic.serial, telem.generic.tick, telem.generic.type); + 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 ((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 %5d speed %5d height %5d ", - telem.sensor.acceleration, - telem.sensor.speed, + 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, @@ -100,6 +109,49 @@ main (int argc, char **argv) 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", + telem.location.altitude, + 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; default: printf("\n"); } diff --git a/ao-tools/lib/cc-telemetry.c b/ao-tools/lib/cc-telemetry.c index 2cdb9cac..99da2680 100644 --- a/ao-tools/lib/cc-telemetry.c +++ b/ao-tools/lib/cc-telemetry.c @@ -57,6 +57,6 @@ cc_telemetry_parse(const char *input_line, union ao_telemetry_all *telemetry) } if (hex[0] != 34) return FALSE; - memcpy(telemetry, hex+1, 32); + memcpy(telemetry, hex+1, 34); return TRUE; } diff --git a/ao-tools/lib/cc-telemetry.h b/ao-tools/lib/cc-telemetry.h index 5a66b971..71f6844d 100644 --- a/ao-tools/lib/cc-telemetry.h +++ b/ao-tools/lib/cc-telemetry.h @@ -29,7 +29,9 @@ struct ao_telemetry_generic { uint16_t tick; /* 2 */ uint8_t type; /* 4 */ uint8_t payload[27]; /* 5 */ - /* 32 */ + uint8_t rssi; /* 32 */ + uint8_t status; /* 33 */ + /* 34 */ }; #define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 -- cgit v1.2.3 From 9b24f413da0b6d989b32e8654a91c8deee4c81dd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Jun 2012 19:02:50 -0700 Subject: ao-tools: add rudimentary support for MM telemetry to ao-telem Just pretends they're TM packets for now Signed-off-by: Keith Packard --- ao-tools/ao-telem/ao-telem.c | 1 + ao-tools/lib/cc-telemetry.h | 1 + 2 files changed, 2 insertions(+) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-telem/ao-telem.c b/ao-tools/ao-telem/ao-telem.c index 6207d433..384b2fc8 100644 --- a/ao-tools/ao-telem/ao-telem.c +++ b/ao-tools/ao-telem/ao-telem.c @@ -82,6 +82,7 @@ main (int argc, char **argv) case AO_TELEMETRY_SENSOR_TELEMETRUM: case AO_TELEMETRY_SENSOR_TELEMINI: case AO_TELEMETRY_SENSOR_TELENANO: + case AO_TELEMETRY_SENSOR_MEGAMETRUM: 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 ", diff --git a/ao-tools/lib/cc-telemetry.h b/ao-tools/lib/cc-telemetry.h index 71f6844d..4e064a97 100644 --- a/ao-tools/lib/cc-telemetry.h +++ b/ao-tools/lib/cc-telemetry.h @@ -37,6 +37,7 @@ struct ao_telemetry_generic { #define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 #define AO_TELEMETRY_SENSOR_TELEMINI 0x02 #define AO_TELEMETRY_SENSOR_TELENANO 0x03 +#define AO_TELEMETRY_SENSOR_MEGAMETRUM 0x08 struct ao_telemetry_sensor { uint16_t serial; /* 0 */ -- cgit v1.2.3 From 0b5548d6ced67201311e1072d37fbedd3d9929c9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 21 Jun 2012 09:51:17 -0700 Subject: ao-tools: Support MM telemetry packets in ao-telem Parse the new packet formats Signed-off-by: Keith Packard --- ao-tools/ao-telem/ao-telem.c | 38 ++++++++++++++++++++++++++++++- ao-tools/lib/cc-telemetry.h | 54 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 2 deletions(-) (limited to 'ao-tools/lib') diff --git a/ao-tools/ao-telem/ao-telem.c b/ao-tools/ao-telem/ao-telem.c index 384b2fc8..e7fc8e26 100644 --- a/ao-tools/ao-telem/ao-telem.c +++ b/ao-tools/ao-telem/ao-telem.c @@ -82,7 +82,6 @@ main (int argc, char **argv) case AO_TELEMETRY_SENSOR_TELEMETRUM: case AO_TELEMETRY_SENSOR_TELEMINI: case AO_TELEMETRY_SENSOR_TELENANO: - case AO_TELEMETRY_SENSOR_MEGAMETRUM: 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 ", @@ -152,6 +151,43 @@ main (int argc, char **argv) telem.satellite.sats[c].c_n_1); } printf ("\n"); + break; + case AO_TELEMETRY_MEGA_SENSOR: + printf ("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.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_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; default: printf("\n"); diff --git a/ao-tools/lib/cc-telemetry.h b/ao-tools/lib/cc-telemetry.h index 4e064a97..e849cd3b 100644 --- a/ao-tools/lib/cc-telemetry.h +++ b/ao-tools/lib/cc-telemetry.h @@ -37,7 +37,6 @@ struct ao_telemetry_generic { #define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01 #define AO_TELEMETRY_SENSOR_TELEMINI 0x02 #define AO_TELEMETRY_SENSOR_TELENANO 0x03 -#define AO_TELEMETRY_SENSOR_MEGAMETRUM 0x08 struct ao_telemetry_sensor { uint16_t serial; /* 0 */ @@ -151,6 +150,57 @@ struct ao_telemetry_companion { /* 32 */ }; +#define AO_TELEMETRY_MEGA_SENSOR 0x08 + +struct ao_telemetry_mega_sensor { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t pad5; /* 5 */ + int16_t accel; /* 6 Z axis */ + + int32_t pres; /* 8 Pa * 10 */ + int16_t temp; /* 12 °C * 100 */ + + int16_t accel_x; /* 14 */ + int16_t accel_y; /* 16 */ + int16_t accel_z; /* 18 */ + + int16_t gyro_x; /* 20 */ + int16_t gyro_y; /* 22 */ + int16_t gyro_z; /* 24 */ + + int16_t mag_x; /* 26 */ + int16_t mag_y; /* 28 */ + int16_t mag_z; /* 30 */ + /* 32 */ +}; + +#define AO_TELEMETRY_MEGA_DATA 0x09 + +struct ao_telemetry_mega_data { + uint16_t serial; /* 0 */ + uint16_t tick; /* 2 */ + uint8_t type; /* 4 */ + + uint8_t state; /* 5 flight state */ + + int16_t v_batt; /* 6 battery voltage */ + int16_t v_pyro; /* 8 pyro battery voltage */ + int8_t sense[6]; /* 10 continuity sense */ + + int32_t ground_pres; /* 16 average pres on pad */ + int16_t ground_accel; /* 20 average accel on pad */ + int16_t accel_plus_g; /* 22 accel calibration at +1g */ + int16_t accel_minus_g; /* 24 accel calibration at -1g */ + + int16_t acceleration; /* 26 m/s² * 16 */ + int16_t speed; /* 28 m/s * 16 */ + int16_t height; /* 30 m */ + /* 32 */ +}; + /* #define AO_SEND_ALL_BARO */ #define AO_TELEMETRY_BARO 0x80 @@ -182,6 +232,8 @@ union ao_telemetry_all { struct ao_telemetry_location location; struct ao_telemetry_satellite satellite; struct ao_telemetry_companion companion; + struct ao_telemetry_mega_sensor mega_sensor; + struct ao_telemetry_mega_data mega_data; struct ao_telemetry_baro baro; }; -- cgit v1.2.3