ao-tools: Change ao-eeprom into eeprom analysis tool
authorKeith Packard <keithp@keithp.com>
Mon, 15 Jul 2019 20:22:15 +0000 (13:22 -0700)
committerKeith Packard <keithp@keithp.com>
Mon, 15 Jul 2019 20:22:15 +0000 (13:22 -0700)
ao-eeprom used to be a TeleMetrum v0.2 specific tool for fetching
eeprom contents from that device. ao-dumpflash handles that case now.

ao-eeprom now parses .eeprom files and displays their contents.

Signed-off-by: Keith Packard <keithp@keithp.com>
ao-tools/ao-eeprom/Makefile.am
ao-tools/ao-eeprom/ao-eeprom.1
ao-tools/ao-eeprom/ao-eeprom.c
ao-tools/lib/Makefile.am
ao-tools/lib/ao-eeprom-read.c [new file with mode: 0644]
ao-tools/lib/ao-eeprom-read.h [new file with mode: 0644]
ao-tools/lib/ao-ms5607-convert.c [new file with mode: 0644]
ao-tools/lib/ao-ms5607.h [new file with mode: 0644]

index 6c5e038..d4aca00 100644 (file)
@@ -5,7 +5,7 @@ AO_EEPROM_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
 
 ao_eeprom_DEPENDENCIES = $(AO_EEPROM_LIBS)
 
-ao_eeprom_LDADD=$(AO_EEPROM_LIBS) $(LIBUSB_LIBS)
+ao_eeprom_LDADD=$(AO_EEPROM_LIBS) -ljson-c
 
 ao_eeprom_SOURCES = ao-eeprom.c
 
index 728f11e..6257e12 100644 (file)
 .\"
 .TH AO-EEPROM 1 "ao-eeprom" ""
 .SH NAME
-ao-eeprom \- Fetch eeprom contents from TeleMetrum device
+ao-eeprom \- Analyze an eeprom log
 .SH SYNOPSIS
 .B "ao-eeprom"
-[\-T \fItty-device\fP]
-[\--tty \fItty-device\fP]
-[\-D \fIaltos-device\fP]
-[\--device \fIaltos-device\fP]
+[\--raw]
+[\--csum]
+[\--verbose]
+[\--len <record-len>]
+{flight.eeprom} ...
 .SH OPTIONS
 .TP
-\-T tty-device | --tty tty-device
-This selects which tty device the debugger uses to communicate with
-the target device. The special name 'BITBANG' directs ao-dbg to use
-the cp2103 connection, otherwise this should be a usb serial port
-connected to a suitable cc1111 debug node.
+\-r | --raw
+This option makes ao-eeprom dump the raw bytes of each
+log record in hex format.
 .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.
+\-c | --csum
+This option makes ao-eeprom dump records that have checksum errors. By default,
+ao-eeprom skips such records.
+\-v | --verbose
+This option makes ao-eeprom report when records are skipped due to
+checksum errors.
+\-l <record-len> | --len <record-len
+Specify the eeprom record length rather than letting ao-eeprom
+automatically determine it based on the file contents.
 .SH DESCRIPTION
 .I ao-eeprom
-downloads the eeprom contents from a connected TeleMetrum device.
-.SH USAGE
-.I ao-eeprom
-connects to the specified target device and dumps each block of the
-eeprom to stdout in hexadecimal bytes.
+reads the specified eeprom log and display the contents of each
+record.
 .SH AUTHOR
 Keith Packard
index b865e29..0c0500f 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <getopt.h>
-#include "cc-usb.h"
-#include "cc.h"
-
-#define NUM_BLOCK      512
+#include <ao-eeprom-read.h>
 
 static const struct option options[] = {
-       { .name = "tty", .has_arg = 1, .val = 'T' },
-       { .name = "device", .has_arg = 1, .val = 'D' },
+       { .name = "raw", .has_arg = 0, .val = 'r' },
+       { .name = "csum", .has_arg = 0, .val = 'c' },
+       { .name = "verbose", .has_arg = 0, .val = 'v' },
+       { .name = "len", .has_arg = 1, .val = 'l' },
        { 0, 0, 0, 0},
 };
 
 static void usage(char *program)
 {
-       fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>\n", program);
+       fprintf(stderr, "usage: %s [--raw] [--csum] [--verbose] [--len <record-len>] {flight.eeprom} ...\n", program);
        exit(1);
 }
 
+static bool
+ao_csum_valid(uint8_t *d, int len)
+{
+       uint8_t sum = 0x5a;
+       int i;
+       for (i = 0; i < len; i++)
+               sum += d[i];
+       return sum == 0;
+}
+
+static void
+ao_ms5607(uint32_t pres, uint32_t temp, struct ao_eeprom *eeprom, bool is_ms5611)
+{
+       struct ao_ms5607_sample ms5607_sample = { .pres = pres, .temp = temp };
+       struct ao_ms5607_value ms5607_value;
+
+       ao_ms5607_convert(&ms5607_sample, &ms5607_value,
+                         &eeprom->ms5607_prom, is_ms5611);
+       printf(" pres %9u temp %9u (%7.3f kPa %6.2f°C)",
+              pres,
+              temp,
+              ms5607_value.pres / 1000.0,
+              ms5607_value.temp / 100.0);
+}
+
+#define GRAVITY 9.80665
+
+static void
+ao_accel(int16_t accel, struct ao_eeprom *eeprom)
+{
+       double accel_2g = eeprom->config.accel_minus_g - eeprom->config.accel_plus_g;
+       double accel_scale = GRAVITY * 2.0 / accel_2g;
+       printf(" accel %6d (%7.2f m/s²)",
+              accel, (eeprom->config.accel_plus_g - accel) * accel_scale);
+}
+
+static const char *state_names[] = {
+       "startup",
+       "idle",
+       "pad",
+       "boost",
+       "fast",
+       "coast",
+       "drogue",
+       "main",
+       "landed",
+       "invalid"
+};
+
+#define NUM_STATE      (sizeof state_names/sizeof state_names[0])
+
+static const char *
+ao_state_name(uint16_t state)
+{
+       if (state < NUM_STATE)
+               return state_names[state];
+       return "UNKNOWN";
+}
+
+static void
+ao_state(uint16_t state, uint16_t reason)
+{
+       printf(" state %5u %s reason %5u",
+              state, ao_state_name(state), reason);
+}
+
+static void
+ao_volts(const char *name, int16_t value, int16_t max_adc, double ref, double r1, double r2)
+{
+       printf(" %s %5d",
+              name, value);
+       if (r1 && r2 && ref)
+              printf("(%6.3f V)",
+                     ref * ((double) value / max_adc) * (r1 + r2) / r2);
+}
+
+#if 0
+static uint16_t
+uint16(uint8_t *bytes, int off)
+{
+       return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
+}
+
+static int16_t
+int16(uint8_t *bytes, int off)
+{
+       return (int16_t) uint16(bytes, off);
+}
+
+static uint32_t
+uint32(uint8_t *bytes, int off)
+{
+       return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
+               (((uint32_t) bytes[off+2]) << 16) |
+               (((uint32_t) bytes[off+3]) << 24);
+}
+
+static int32_t
+int32(uint8_t *bytes, int off)
+{
+       return (int32_t) uint32(bytes, off);
+}
+#endif
+
+static uint32_t
+uint24(uint8_t *bytes, int off)
+{
+       return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
+               (((uint32_t) bytes[off+2]) << 16);
+}
+
+static int32_t
+int24(uint8_t *bytes, int off)
+{
+       return (int32_t) uint24(bytes, off);
+}
+
 int
 main (int argc, char **argv)
 {
-       struct cc_usb   *cc;
-       int             block;
-       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:D:", options, NULL)) != -1) {
+       struct ao_eeprom        *eeprom;
+       FILE                    *file;
+       int                     c;
+       bool                    raw = false;
+       bool                    csum = false;
+       bool                    verbose = false;
+       int                     arg_len = 0;
+       char                    *end;
+       int                     ret = 0;
+       int                     i;
+
+       while ((c = getopt_long(argc, argv, "rcvl:", options, NULL)) != -1) {
                switch (c) {
-               case 'T':
-                       tty = optarg;
+               case 'r':
+                       raw = true;
                        break;
-               case 'D':
-                       device = optarg;
+               case 'c':
+                       csum = true;
+                       break;
+               case 'v':
+                       verbose = true;
+                       break;
+               case 'l':
+                       arg_len = strtol(optarg, &end, 0);
+                       if (!*optarg || *end)
+                               usage(argv[0]);
                        break;
                default:
                        usage(argv[0]);
                        break;
                }
        }
-       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);
-       for (block = 0; block < NUM_BLOCK; block += 2) {
-               cc_queue_read(cc, bytes, sizeof (bytes));
-               cc_usb_printf(cc, "e %x\ne %x\n", block, block + 1);
-               cc_usb_sync(cc);
-               for (i = 0; i < 32 * 2; i++) {
-                       b = bytes + (i * 10);
-                       addr = block * 256 + i * 8;
-                       printf ("%06x", addr);
-                       for (j = 0; j < 8; j++) {
-                               printf (" %02x", b[j+2]);
+       for (i = optind; i < argc; i++) {
+               file = fopen(argv[i], "r");
+               if (!file) {
+                       perror(argv[i]);
+                       ret++;
+                       continue;
+               }
+               eeprom = ao_eeprom_read(file);
+               fclose(file);
+               if (!eeprom) {
+                       perror(argv[i]);
+                       ret++;
+                       continue;
+               }
+               int     len = 0;
+               bool    is_ms5611 = false;
+
+               double  sense_r1 = 0.0, sense_r2 = 0.0;
+               double  batt_r1 = 0.0, batt_r2 = 0.0;
+               double  adc_ref = 0.0;
+               int16_t max_adc = 0;
+
+               switch (eeprom->log_format) {
+               case AO_LOG_FORMAT_TELEMEGA_OLD:
+                       len = 32;
+                       break;
+               case AO_LOG_FORMAT_EASYMINI1:
+                       len = 16;
+                       max_adc = 32767;
+                       if (eeprom->serial_number < 1000)
+                               adc_ref = 3.0;
+                       else
+                               adc_ref = 3.3;
+                       batt_r1 = sense_r1 = 100e3;
+                       batt_r2 = sense_r2 = 27e3;
+                       break;
+               case AO_LOG_FORMAT_TELEMETRUM:
+                       len = 16;
+                       max_adc = 4095;
+                       adc_ref = 3.3;
+                       batt_r1 = 5600;
+                       batt_r2 = 10000;
+                       sense_r1 = 100e3;
+                       sense_r2 = 27e3;
+                       break;
+               case AO_LOG_FORMAT_TELEMINI2:
+                       len = 16;
+                       break;
+               case AO_LOG_FORMAT_TELEGPS:
+                       len = 32;
+                       break;
+               case AO_LOG_FORMAT_TELEMEGA:
+                       len = 32;
+                       max_adc = 4095;
+                       adc_ref = 3.3;
+                       batt_r1 = 5600;
+                       batt_r2 = 10000;
+                       sense_r1 = 100e3;
+                       sense_r2 = 27e3;
+                       break;
+               case AO_LOG_FORMAT_DETHERM:
+                       len = 16;
+                       break;
+               case AO_LOG_FORMAT_TELEMINI3:
+                       len = 16;
+                       max_adc = 4095;
+                       adc_ref = 3.3;
+                       batt_r1 = 5600;
+                       batt_r2 = 10000;
+                       sense_r1 = 100e3;
+                       sense_r2 = 27e3;
+                       break;
+               case AO_LOG_FORMAT_TELEFIRETWO:
+                       len = 32;
+                       break;
+               case AO_LOG_FORMAT_EASYMINI2:
+                       len = 16;
+                       max_adc = 4095;
+                       adc_ref = 3.3;
+                       batt_r1 = sense_r1 = 100e3;
+                       batt_r2 = sense_r2 = 27e3;
+                       break;
+               case AO_LOG_FORMAT_TELEMEGA_3:
+                       len = 32;
+                       max_adc = 4095;
+                       adc_ref = 3.3;
+                       batt_r1 = 5600;
+                       batt_r2 = 10000;
+                       sense_r1 = 100e3;
+                       sense_r2 = 27e3;
+                       break;
+               case AO_LOG_FORMAT_EASYMEGA_2:
+                       len = 32;
+                       max_adc = 4095;
+                       adc_ref = 3.3;
+                       batt_r1 = 5600;
+                       batt_r2 = 10000;
+                       sense_r1 = 100e3;
+                       sense_r2 = 27e3;
+                       break;
+               case AO_LOG_FORMAT_TELESTATIC:
+                       len = 32;
+                       break;
+               case AO_LOG_FORMAT_MICROPEAK2:
+                       len = 2;
+                       break;
+               }
+               if (arg_len)
+                       len = arg_len;
+               printf("config major %d minor %d log format %d total %u len %d\n",
+                      eeprom->config.major,
+                      eeprom->config.minor,
+                      eeprom->log_format,
+                      eeprom->len,
+                      len);
+               uint32_t        pos;
+               for (pos = 0; pos < eeprom->len; pos += len) {
+                       int i;
+                       if (raw) {
+                               printf("%9u", pos);
+                               for (i = 0; i < len; i++)
+                                       printf(" %02x", eeprom->data[pos + i]);
+                       } else {
+                               struct ao_log_mega *log_mega;
+                               struct ao_log_mini *log_mini;
+                               struct ao_log_metrum *log_metrum;
+                               struct ao_log_gps *log_gps;
+
+                               if (!csum && !ao_csum_valid(&eeprom->data[pos], len)) {
+                                       if (verbose)
+                                               printf("\tchecksum error at %d\n", pos);
+                                       continue;
+                               }
+
+                               struct ao_log_header *log_header = (struct ao_log_header *) &eeprom->data[pos];
+
+                               printf("type %c tick %5u", log_header->type, log_header->tick);
+
+                               switch (eeprom->log_format) {
+                               case AO_LOG_FORMAT_TELEMEGA_OLD:
+                               case AO_LOG_FORMAT_TELEMEGA:
+                               case AO_LOG_FORMAT_TELEMEGA_3:
+                               case AO_LOG_FORMAT_EASYMEGA_2:
+                                       log_mega = (struct ao_log_mega *) &eeprom->data[pos];
+                                       switch (log_mega->type) {
+                                       case AO_LOG_FLIGHT:
+                                               printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u",
+                                                      eeprom->serial_number,
+                                                      log_mega->u.flight.flight,
+                                                      log_mega->u.flight.ground_accel,
+                                                      log_mega->u.flight.ground_pres);
+                                               printf(" along %6d aross %6d through %6d",
+                                                      log_mega->u.flight.ground_accel_along,
+                                                      log_mega->u.flight.ground_accel_across,
+                                                      log_mega->u.flight.ground_accel_through);
+                                               printf(" roll %6d pitch %6d yaw %6d",
+                                                      log_mega->u.flight.ground_roll,
+                                                      log_mega->u.flight.ground_pitch,
+                                                      log_mega->u.flight.ground_yaw);
+                                               break;
+                                       case AO_LOG_STATE:
+                                               ao_state(log_mega->u.state.state,
+                                                        log_mega->u.state.reason);
+                                               break;
+                                       case AO_LOG_SENSOR:
+                                               ao_ms5607(log_mega->u.sensor.pres,
+                                                         log_mega->u.sensor.temp,
+                                                         eeprom, is_ms5611);
+                                               printf(" accel_x %6d accel_y %6d accel_z %6d",
+                                                      log_mega->u.sensor.accel_x,
+                                                      log_mega->u.sensor.accel_y,
+                                                      log_mega->u.sensor.accel_z);
+                                               printf (" gyro_x %6d gyro_y %6d gyro_z %6d",
+                                                      log_mega->u.sensor.gyro_x,
+                                                      log_mega->u.sensor.gyro_y,
+                                                      log_mega->u.sensor.gyro_z);
+                                               printf (" mag_x %6d mag_y %6d mag_z %6d",
+                                                      log_mega->u.sensor.mag_x,
+                                                      log_mega->u.sensor.mag_y,
+                                                      log_mega->u.sensor.mag_z);
+                                               ao_accel(log_mega->u.sensor.accel, eeprom);
+                                               break;
+                                       case AO_LOG_TEMP_VOLT:
+                                               ao_volts("v_batt",
+                                                        log_mega->u.volt.v_batt,
+                                                        max_adc,
+                                                        adc_ref,
+                                                        batt_r1, batt_r2);
+                                               ao_volts("v_pbatt",
+                                                        log_mega->u.volt.v_pbatt,
+                                                        max_adc,
+                                                        adc_ref,
+                                                        sense_r1, sense_r2);
+                                               printf(" n_sense %1d",
+                                                      log_mega->u.volt.n_sense);
+                                               for (i = 0; i < log_mega->u.volt.n_sense; i++) {
+                                                       char name[10];
+                                                       sprintf(name, "sense%d", i);
+                                                       ao_volts(name,
+                                                                log_mega->u.volt.sense[i],
+                                                                max_adc,
+                                                                adc_ref,
+                                                                sense_r1, sense_r2);
+                                               }
+                                               printf(" pyro %04x", log_mega->u.volt.pyro);
+                                               break;
+                                       case AO_LOG_GPS_TIME:
+                                               printf(" lat %10.7f° lon %10.7f° alt %8d m",
+                                                      log_mega->u.gps.latitude / 10000000.0,
+                                                      log_mega->u.gps.longitude/ 10000000.0,
+                                                      (int32_t) (log_mega->u.gps.altitude_low |
+                                                                 (log_mega->u.gps.altitude_high << 16)));
+                                               printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x",
+                                                      log_mega->u.gps.hour,
+                                                      log_mega->u.gps.minute,
+                                                      log_mega->u.gps.second,
+                                                      log_mega->u.gps.year,
+                                                      log_mega->u.gps.month,
+                                                      log_mega->u.gps.day,
+                                                      log_mega->u.gps.flags);
+                                               printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d",
+                                                      log_mega->u.gps.course,
+                                                      log_mega->u.gps.ground_speed,
+                                                      log_mega->u.gps.climb_rate,
+                                                      log_mega->u.gps.pdop,
+                                                      log_mega->u.gps.hdop,
+                                                      log_mega->u.gps.vdop,
+                                                      log_mega->u.gps.mode);
+                                               break;
+                                       case AO_LOG_GPS_SAT:
+                                               printf(" channels %2d",
+                                                      log_mega->u.gps_sat.channels);
+                                               for (i = 0; i < 12; i++) {
+                                                       printf(" svid %3d c_n %2d",
+                                                              log_mega->u.gps_sat.sats[i].svid,
+                                                              log_mega->u.gps_sat.sats[i].c_n);
+                                               }
+                                               break;
+                                       }
+                                       break;
+                               case AO_LOG_FORMAT_EASYMINI1:
+                               case AO_LOG_FORMAT_EASYMINI2:
+                               case AO_LOG_FORMAT_TELEMINI2:
+                               case AO_LOG_FORMAT_TELEMINI3:
+                                       log_mini = (struct ao_log_mini *) &eeprom->data[pos];
+                                       switch (log_mini->type) {
+                                       case AO_LOG_FLIGHT:
+                                               printf(" serial %5u flight %5u ground_pres %9u",
+                                                      eeprom->serial_number,
+                                                      log_mini->u.flight.flight,
+                                                      log_mini->u.flight.ground_pres);
+                                               break;
+                                       case AO_LOG_STATE:
+                                               ao_state(log_mini->u.state.state,
+                                                        log_mini->u.state.reason);
+                                               break;
+                                       case AO_LOG_SENSOR:
+                                               ao_ms5607(int24(log_mini->u.sensor.pres, 0),
+                                                         int24(log_mini->u.sensor.temp, 0),
+                                                         eeprom, is_ms5611);
+                                               ao_volts("sense_a",
+                                                        log_mini->u.sensor.sense_a, max_adc,
+                                                        adc_ref, sense_r1, sense_r2);
+                                               ao_volts("sense_m",
+                                                        log_mini->u.sensor.sense_m, max_adc,
+                                                        adc_ref, sense_r1, sense_r2);
+                                               ao_volts("v_batt",
+                                                        log_mini->u.sensor.v_batt, max_adc,
+                                                        adc_ref, batt_r1, batt_r2);
+                                               break;
+                                       } /*  */
+                                       break;
+                               case AO_LOG_FORMAT_TELEMETRUM:
+                                       log_metrum = (struct ao_log_metrum *) &eeprom->data[pos];
+                                       switch (log_metrum->type) {
+                                       case AO_LOG_FLIGHT:
+                                               printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u ground_temp %9u",
+                                                      eeprom->serial_number,
+                                                      log_metrum->u.flight.flight,
+                                                      log_metrum->u.flight.ground_accel,
+                                                      log_metrum->u.flight.ground_pres,
+                                                      log_metrum->u.flight.ground_temp);
+                                               break;
+                                       case AO_LOG_SENSOR:
+                                               ao_ms5607(log_metrum->u.sensor.pres,
+                                                         log_metrum->u.sensor.temp,
+                                                         eeprom, is_ms5611);
+                                               ao_accel(log_metrum->u.sensor.accel, eeprom);
+                                               break;
+                                       case AO_LOG_TEMP_VOLT:
+                                               ao_volts("v_batt",
+                                                        log_metrum->u.volt.v_batt, max_adc,
+                                                        adc_ref, batt_r1, batt_r2);
+                                               ao_volts("sense_a",
+                                                        log_metrum->u.volt.sense_a, max_adc,
+                                                        adc_ref, sense_r1, sense_r2);
+                                               ao_volts("sense_m",
+                                                        log_metrum->u.volt.sense_m, max_adc,
+                                                        adc_ref, sense_r1, sense_r2);
+                                               break;
+                                       case AO_LOG_DEPLOY:
+                                               break;
+                                       case AO_LOG_STATE:
+                                               ao_state(log_metrum->u.state.state,
+                                                        log_metrum->u.state.reason);
+                                               break;
+                                       case AO_LOG_GPS_TIME:
+                                               printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x pdop %3u",
+                                                      log_metrum->u.gps_time.hour,
+                                                      log_metrum->u.gps_time.minute,
+                                                      log_metrum->u.gps_time.second,
+                                                      log_metrum->u.gps_time.year,
+                                                      log_metrum->u.gps_time.month,
+                                                      log_metrum->u.gps_time.day,
+                                                      log_metrum->u.gps_time.flags,
+                                                      log_metrum->u.gps_time.pdop);
+                                               break;
+                                       case AO_LOG_GPS_SAT:
+                                               printf(" channels %2d more %1d",
+                                                      log_metrum->u.gps_sat.channels,
+                                                      log_metrum->u.gps_sat.more);
+                                               for (i = 0; i < 4; i++) {
+                                                       printf(" svid %3d c_n %2d",
+                                                              log_metrum->u.gps_sat.sats[i].svid,
+                                                              log_metrum->u.gps_sat.sats[i].c_n);
+                                               }
+                                               break;
+                                       case AO_LOG_GPS_POS:
+                                               printf(" lat %10.7f° lon %10.7f° alt %8d m",
+                                                      log_metrum->u.gps.latitude / 10000000.0,
+                                                      log_metrum->u.gps.longitude/ 10000000.0,
+                                                      (int32_t) (log_metrum->u.gps.altitude_low |
+                                                                 (log_metrum->u.gps.altitude_high << 16)));
+                                               break;
+                                       default:
+                                               printf(" unknown");
+                                       }
+                                       break;
+                               case AO_LOG_FORMAT_TELEGPS:
+                                       log_gps = (struct ao_log_gps *) &eeprom->data[pos];
+                                       (void) log_gps;
+                                       break;
+                               case AO_LOG_FORMAT_DETHERM:
+                                       break;
+                               }
                        }
-                       printf ("\n");
+                       printf("\n");
                }
        }
-       cc_usb_close(cc);
-       exit (0);
+       return ret;
 }
index a33d682..de6c194 100644 (file)
@@ -50,5 +50,9 @@ libao_tools_a_SOURCES = \
        ao-dfu.h \
        ao-selfload.c \
        ao-selfload.h \
+       ao-eeprom-read.c \
+       ao-eeprom-read.h \
+       ao-ms5607-convert.c \
+       ao-ms5607.h \
        ao-verbose.c \
        ao-verbose.h
diff --git a/ao-tools/lib/ao-eeprom-read.c b/ao-tools/lib/ao-eeprom-read.c
new file mode 100644 (file)
index 0000000..7ed4715
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright © 2017 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include "ao-eeprom-read.h"
+#include <json-c/json.h>
+#include <string.h>
+#include <errno.h>
+
+static struct json_object *
+ao_eeprom_read_config(FILE *file)
+{
+       char                    line[1024];
+       struct json_tokener     *tok;
+       struct json_object      *obj = NULL;
+       enum json_tokener_error err;
+
+       tok = json_tokener_new();
+       if (!tok)
+               goto fail_tok;
+
+       for (;;) {
+               if (fgets(line, sizeof(line), file) == NULL)
+                       goto fail_read;
+               obj = json_tokener_parse_ex(tok, line, strlen(line));
+               err = json_tokener_get_error(tok);
+               if (err == json_tokener_success)
+                       break;
+               if (err != json_tokener_continue)
+                       goto fail_read;
+       }
+       json_tokener_free(tok);
+       return obj;
+fail_read:
+       json_tokener_free(tok);
+fail_tok:
+       return NULL;
+}
+
+static int
+ao_eeprom_read_byte(FILE *file)
+{
+       int     byte;
+       if (fscanf(file, "%x", &byte) != 1)
+               return EOF;
+       return byte;
+}
+
+static int
+ao_eeprom_read_data(FILE *file, struct ao_eeprom *eeprom)
+{
+       uint8_t *data = NULL, *ndata;
+       int     len = 0;
+       int     size = 0;
+       int     byte;
+
+       data = malloc(size = 64);
+       if (!data)
+               goto fail_alloc;
+       while ((byte = ao_eeprom_read_byte(file)) != EOF) {
+               if (len == size) {
+                       ndata = realloc(data, size *= 2);
+                       if (!ndata)
+                               goto fail_realloc;
+                       data = ndata;
+               }
+               data[len++] = (uint8_t) byte;
+       }
+       eeprom->data = data;
+       eeprom->len = len;
+       return 1;
+fail_realloc:
+       free(data);
+fail_alloc:
+       return 0;
+}
+
+static int
+ao_json_get_int(struct json_object *obj, const char *key, int def)
+{
+       struct json_object *value;
+       int i;
+
+       if (!json_object_object_get_ex(obj, key, &value))
+               return def;
+       errno = 0;
+       i = (int) json_object_get_int(value);
+       if (errno != 0)
+               return def;
+       return i;
+}
+
+static const char *
+ao_json_get_string(struct json_object *obj, const char *key, const char *def)
+{
+       struct json_object *value;
+       const char *str;
+
+       if (!json_object_object_get_ex(obj, key, &value))
+               return def;
+       errno = 0;
+       str = json_object_get_string(value);
+       if (errno)
+               return def;
+       if (!str)
+               return def;
+       return str;
+}
+
+static int
+ao_eeprom_get_pyro(struct ao_config *config, struct json_object *obj)
+{
+       struct json_object      *pyros;
+       struct json_object      *pyro;
+       int                     i, p;
+
+       if (!json_object_object_get_ex(obj, "pyros", &pyros))
+               return 1;
+
+       if (json_object_get_type(pyros) != json_type_array)
+               return 0;
+
+       for (i = 0; i < json_object_array_length(pyros); i++) {
+               pyro = json_object_array_get_idx(pyros, i);
+               if (pyro) {
+                       p = ao_json_get_int(pyro, "channel", -1);
+                       if (0 <= p && p < AO_PYRO_NUM) {
+                               config->pyro[p].flags           = ao_json_get_int(pyro, "flags", 0);
+                               config->pyro[p].accel_less      = ao_json_get_int(pyro, "accel_less", 0);
+                               config->pyro[p].accel_greater   = ao_json_get_int(pyro, "accel_greater", 0);
+                               config->pyro[p].speed_less      = ao_json_get_int(pyro, "speed_less", 0);
+                               config->pyro[p].speed_greater   = ao_json_get_int(pyro, "speed_greater", 0);
+                               config->pyro[p].height_less     = ao_json_get_int(pyro, "height_less", 0);
+                               config->pyro[p].height_greater  = ao_json_get_int(pyro, "height_greater", 0);
+                               config->pyro[p].orient_less     = ao_json_get_int(pyro, "orient_less", 0);
+                               config->pyro[p].orient_greater  = ao_json_get_int(pyro, "orient_greater", 0);
+                               config->pyro[p].time_less       = ao_json_get_int(pyro, "time_less", 0);
+                               config->pyro[p].time_greater    = ao_json_get_int(pyro, "time_greater", 0);
+                               config->pyro[p].delay           = ao_json_get_int(pyro, "delay", 0);
+                               config->pyro[p].state_less      = ao_json_get_int(pyro, "state_less", 0);
+                               config->pyro[p].state_greater_or_equal  = ao_json_get_int(pyro, "state_greater_or_equal", 0);
+                               config->pyro[p].motor           = ao_json_get_int(pyro, "motor", 0);
+                       }
+               }
+       }
+       return 1;
+}
+
+static int
+ao_eeprom_get_ms5607(struct ao_ms5607_prom *ms5607_prom, struct json_object *obj)
+{
+       struct json_object      *ms5607;
+
+       if (!json_object_object_get_ex(obj, "ms5607", &ms5607))
+               return 1;
+
+       if (json_object_get_type(ms5607) != json_type_object)
+               return 0;
+
+       ms5607_prom->reserved = ao_json_get_int(ms5607, "reserved", 0);
+       ms5607_prom->sens =     ao_json_get_int(ms5607, "sens", 0);
+       ms5607_prom->off =      ao_json_get_int(ms5607, "off", 0);
+       ms5607_prom->tcs =      ao_json_get_int(ms5607, "tcs", 0);
+       ms5607_prom->tco =      ao_json_get_int(ms5607, "tco", 0);
+       ms5607_prom->tref =     ao_json_get_int(ms5607, "tref", 0);
+       ms5607_prom->tempsens = ao_json_get_int(ms5607, "tempsens", 0);
+       ms5607_prom->crc =      ao_json_get_int(ms5607, "crc", 0);
+       return 1;
+}
+
+static int
+ao_eeprom_get_config(struct ao_eeprom *ao_eeprom, struct json_object *obj)
+{
+       struct ao_config        *config = &ao_eeprom->config;
+       const char              *s;
+
+       if (json_object_get_type(obj) != json_type_object)
+               return 0;
+
+       ao_eeprom->log_format =         ao_json_get_int(obj, "log_format", 0);
+       ao_eeprom->serial_number =      ao_json_get_int(obj, "serial", 0);
+
+       config->major =                 ao_json_get_int(obj, "config_major", 0);
+       config->minor =                 ao_json_get_int(obj, "config_minor", 0);
+       if (config->major == 0 || config->minor == 0)
+               return 0;
+
+       config->main_deploy =           ao_json_get_int(obj, "main_deploy", 250);
+       config->accel_plus_g =          ao_json_get_int(obj, "accel_cal_plus", 0);
+
+       s = ao_json_get_string(obj, "callsign", "N0CALL");
+       strncpy(config->callsign, s, sizeof(config->callsign)-1);
+
+       config->apogee_delay =          ao_json_get_int(obj, "apogee_delay", 0);
+       config->accel_minus_g =         ao_json_get_int(obj, "accel_cal_minus", 0);
+       config->radio_cal =             ao_json_get_int(obj, "radio_calibration", 0);
+       config->flight_log_max =        ao_json_get_int(obj, "flight_log_max", 0);
+       config->ignite_mode =           ao_json_get_int(obj, "ignite_mode", 0);
+       config->pad_orientation =       ao_json_get_int(obj, "pad_orientation", 0);
+       config->radio_setting =         ao_json_get_int(obj, "radio_setting", 0);
+       config->radio_enable =          ao_json_get_int(obj, "radio_enable", 1);
+       config->frequency =             ao_json_get_int(obj, "frequency", 434550);
+       config->apogee_lockout =        ao_json_get_int(obj, "apogee_lockout", 0);
+       if (!ao_eeprom_get_pyro(config, obj))
+               return 0;
+       config->ignite_mode =           ao_json_get_int(obj, "ignite_mode", 0);
+       config->ignite_mode =           ao_json_get_int(obj, "ignite_mode", 0);
+       config->ignite_mode =           ao_json_get_int(obj, "ignite_mode", 0);
+       config->ignite_mode =           ao_json_get_int(obj, "ignite_mode", 0);
+       config->ignite_mode =           ao_json_get_int(obj, "ignite_mode", 0);
+       config->ignite_mode =           ao_json_get_int(obj, "ignite_mode", 0);
+
+       if (!ao_eeprom_get_ms5607(&ao_eeprom->ms5607_prom, obj))
+               return 0;
+
+       return 1;
+}
+
+struct ao_eeprom *
+ao_eeprom_read(FILE *file)
+{
+       struct ao_eeprom        *ao_eeprom;
+       struct json_object      *obj;
+       int                     ret;
+
+       ao_eeprom = calloc(1, sizeof (struct ao_eeprom));
+       if (!ao_eeprom)
+               goto fail_ao_eeprom;
+
+       obj = ao_eeprom_read_config(file);
+       if (!obj)
+               goto fail_config;
+
+       ret = ao_eeprom_get_config(ao_eeprom, obj);
+       json_object_put(obj);
+       if (!ret)
+               goto fail_config;
+
+       if (!ao_eeprom_read_data(file, ao_eeprom))
+               goto fail_data;
+
+       return ao_eeprom;
+fail_data:
+fail_config:
+       free(ao_eeprom);
+fail_ao_eeprom:
+       return NULL;
+}
diff --git a/ao-tools/lib/ao-eeprom-read.h b/ao-tools/lib/ao-eeprom-read.h
new file mode 100644 (file)
index 0000000..82893f2
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Copyright © 2017 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _AO_EEPROM_READ_H_
+#define _AO_EEPROM_READ_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <ao-ms5607.h>
+
+#define AO_MAX_CALLSIGN        8
+#define AO_AES_LEN     16
+#define AO_PYRO_NUM    8
+
+/* required functions from the underlying log system */
+
+#define AO_LOG_FORMAT_UNKNOWN          0       /* unknown; altosui will have to guess */
+#define AO_LOG_FORMAT_FULL             1       /* 8 byte typed log records */
+#define AO_LOG_FORMAT_TINY             2       /* two byte state/baro records */
+#define AO_LOG_FORMAT_TELEMETRY                3       /* 32 byte ao_telemetry records */
+#define AO_LOG_FORMAT_TELESCIENCE      4       /* 32 byte typed telescience records */
+#define AO_LOG_FORMAT_TELEMEGA_OLD     5       /* 32 byte typed telemega records */
+#define AO_LOG_FORMAT_EASYMINI1                6       /* 16-byte MS5607 baro only, 3.0V supply */
+#define AO_LOG_FORMAT_TELEMETRUM       7       /* 16-byte typed telemetrum records */
+#define AO_LOG_FORMAT_TELEMINI2                8       /* 16-byte MS5607 baro only, 3.3V supply, cc1111 SoC */
+#define AO_LOG_FORMAT_TELEGPS          9       /* 32 byte telegps records */
+#define AO_LOG_FORMAT_TELEMEGA         10      /* 32 byte typed telemega records with 32 bit gyro cal */
+#define AO_LOG_FORMAT_DETHERM          11      /* 16-byte MS5607 baro only, no ADC */
+#define AO_LOG_FORMAT_TELEMINI3                12      /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */
+#define AO_LOG_FORMAT_TELEFIRETWO      13      /* 32-byte test stand data */
+#define AO_LOG_FORMAT_EASYMINI2                14      /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */
+#define AO_LOG_FORMAT_TELEMEGA_3       15      /* 32 byte typed telemega records with 32 bit gyro cal and mpu9250 */
+#define AO_LOG_FORMAT_EASYMEGA_2       16      /* 32 byte typed telemega records with 32 bit gyro cal, mpu9250 rotated 90° and adxl375 */
+#define AO_LOG_FORMAT_TELESTATIC       17      /* 32 byte typed telestatic records */
+#define AO_LOG_FORMAT_MICROPEAK2       18      /* 2-byte baro values with header */
+#define AO_LOG_FORMAT_NONE             127     /* No log at all */
+
+enum ao_pyro_flag {
+       ao_pyro_none                    = 0x00000000,
+
+       ao_pyro_accel_less              = 0x00000001,
+       ao_pyro_accel_greater           = 0x00000002,
+
+       ao_pyro_speed_less              = 0x00000004,
+       ao_pyro_speed_greater           = 0x00000008,
+
+       ao_pyro_height_less             = 0x00000010,
+       ao_pyro_height_greater          = 0x00000020,
+
+       ao_pyro_orient_less             = 0x00000040,
+       ao_pyro_orient_greater          = 0x00000080,
+
+       ao_pyro_time_less               = 0x00000100,
+       ao_pyro_time_greater            = 0x00000200,
+
+       ao_pyro_ascending               = 0x00000400,
+       ao_pyro_descending              = 0x00000800,
+
+       ao_pyro_after_motor             = 0x00001000,
+
+       ao_pyro_delay                   = 0x00002000,
+
+       ao_pyro_state_less              = 0x00004000,
+       ao_pyro_state_greater_or_equal  = 0x00008000,
+};
+
+struct ao_pyro {
+       enum ao_pyro_flag       flags;
+       int16_t                 accel_less, accel_greater;
+       int16_t                 speed_less, speed_greater;
+       int16_t                 height_less, height_greater;
+       int16_t                 orient_less, orient_greater;
+       int16_t                 time_less, time_greater;
+       int16_t                 delay;
+       uint8_t                 state_less, state_greater_or_equal;
+       int16_t                 motor;
+       uint16_t                delay_done;
+       uint8_t                 _unused;        /* was 'fired' */
+};
+
+struct ao_config {
+       uint8_t         major;
+       uint8_t         minor;
+       uint16_t        main_deploy;
+       int16_t         accel_plus_g;           /* changed for minor version 2 */
+       uint8_t         _legacy_radio_channel;
+       char            callsign[AO_MAX_CALLSIGN + 1];
+       uint8_t         apogee_delay;           /* minor version 1 */
+       int16_t         accel_minus_g;          /* minor version 2 */
+       uint32_t        radio_cal;              /* minor version 3 */
+       uint32_t        flight_log_max;         /* minor version 4 */
+       uint8_t         ignite_mode;            /* minor version 5 */
+       uint8_t         pad_orientation;        /* minor version 6 */
+       uint32_t        radio_setting;          /* minor version 7 */
+       uint8_t         radio_enable;           /* minor version 8 */
+       uint8_t         aes_key[AO_AES_LEN];    /* minor version 9 */
+       uint32_t        frequency;              /* minor version 10 */
+       uint16_t        apogee_lockout;         /* minor version 11 */
+       struct ao_pyro  pyro[AO_PYRO_NUM];      /* minor version 12 */
+       uint16_t        aprs_interval;          /* minor version 13 */
+       uint8_t         radio_power;            /* minor version 14 */
+       uint8_t         radio_amp;              /* minor version 14 */
+       int16_t         accel_zero_along;       /* minor version 15 */
+       int16_t         accel_zero_across;      /* minor version 15 */
+       int16_t         accel_zero_through;     /* minor version 15 */
+       uint8_t         mid_beep;               /* minor version 16 */
+       uint16_t        tracker_motion;         /* minor version 17 */
+       uint8_t         tracker_interval;       /* minor version 17 */
+       uint16_t        pyro_time;              /* minor version 18 */
+       uint8_t         aprs_ssid;              /* minor version 19 */
+       uint8_t         radio_rate;             /* minor version 20 */
+       uint32_t        send_frequency;         /* minor version 21 */
+       uint8_t         aprs_format;            /* minor version 22 */
+       uint8_t         pad_box;                /* minor version 22 */
+       uint8_t         pad_idle;               /* minor version 23 */
+};
+
+/*
+ * ao_log_big.c
+ */
+
+/*
+ * The data log is recorded in the eeprom as a sequence
+ * of data packets.
+ *
+ * Each packet starts with a 4-byte header that has the
+ * packet type, the packet checksum and the tick count. Then
+ * they all contain 2 16 bit values which hold packet-specific
+ * data.
+ *
+ * For each flight, the first packet
+ * is FLIGHT packet, indicating the serial number of the
+ * device and a unique number marking the number of flights
+ * recorded by this device.
+ *
+ * During flight, data from the accelerometer and barometer
+ * are recorded in SENSOR packets, using the raw 16-bit values
+ * read from the A/D converter.
+ *
+ * Also during flight, but at a lower rate, the deployment
+ * sensors are recorded in DEPLOY packets. The goal here is to
+ * detect failure in the deployment circuits.
+ *
+ * STATE packets hold state transitions as the flight computer
+ * transitions through different stages of the flight.
+ */
+#define AO_LOG_FLIGHT          'F'
+#define AO_LOG_SENSOR          'A'
+#define AO_LOG_TEMP_VOLT       'T'
+#define AO_LOG_DEPLOY          'D'
+#define AO_LOG_STATE           'S'
+#define AO_LOG_GPS_TIME                'G'
+#define AO_LOG_GPS_LAT         'N'
+#define AO_LOG_GPS_LON         'W'
+#define AO_LOG_GPS_ALT         'H'
+#define AO_LOG_GPS_SAT         'V'
+#define AO_LOG_GPS_DATE                'Y'
+#define AO_LOG_GPS_POS         'P'
+
+#define AO_LOG_POS_NONE                (~0UL)
+
+/* Common header in all log formats */
+struct ao_log_header {
+       char                    type;                           /* 0 */
+       uint8_t                 csum;                           /* 1 */
+       uint16_t                tick;                           /* 2 */
+};
+
+struct ao_log_record {
+       char                    type;                           /* 0 */
+       uint8_t                 csum;                           /* 1 */
+       uint16_t                tick;                           /* 2 */
+       union {
+               struct {
+                       int16_t         ground_accel;           /* 4 */
+                       uint16_t        flight;                 /* 6 */
+               } flight;
+               struct {
+                       int16_t         accel;                  /* 4 */
+                       int16_t         pres;                   /* 6 */
+               } sensor;
+               struct {
+                       int16_t         temp;
+                       int16_t         v_batt;
+               } temp_volt;
+               struct {
+                       int16_t         drogue;
+                       int16_t         main;
+               } deploy;
+               struct {
+                       uint16_t        state;
+                       uint16_t        reason;
+               } state;
+               struct {
+                       uint8_t         hour;
+                       uint8_t         minute;
+                       uint8_t         second;
+                       uint8_t         flags;
+               } gps_time;
+               int32_t         gps_latitude;
+               int32_t         gps_longitude;
+               struct {
+                       uint16_t        altitude_low;
+                       int16_t         altitude_high;
+               } gps_altitude;
+               struct {
+                       uint16_t        svid;
+                       uint8_t         unused;
+                       uint8_t         c_n;
+               } gps_sat;
+               struct {
+                       uint8_t         year;
+                       uint8_t         month;
+                       uint8_t         day;
+                       uint8_t         extra;
+               } gps_date;
+               struct {
+                       uint16_t        d0;
+                       uint16_t        d1;
+               } anon;
+       } u;
+};
+
+struct ao_log_mega {
+       char                    type;                   /* 0 */
+       uint8_t                 csum;                   /* 1 */
+       uint16_t                tick;                   /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;                 /* 4 */
+                       int16_t         ground_accel;           /* 6 */
+                       uint32_t        ground_pres;            /* 8 */
+                       int16_t         ground_accel_along;     /* 12 */
+                       int16_t         ground_accel_across;    /* 14 */
+                       int16_t         ground_accel_through;   /* 16 */
+                       int16_t         pad_18;                 /* 18 */
+                       int32_t         ground_roll;            /* 20 */
+                       int32_t         ground_pitch;           /* 24 */
+                       int32_t         ground_yaw;             /* 28 */
+               } flight;                                       /* 32 */
+               struct {
+                       uint16_t        flight;                 /* 4 */
+                       int16_t         ground_accel;           /* 6 */
+                       uint32_t        ground_pres;            /* 8 */
+                       int16_t         ground_accel_along;     /* 12 */
+                       int16_t         ground_accel_across;    /* 14 */
+                       int16_t         ground_accel_through;   /* 16 */
+                       int16_t         ground_roll;            /* 18 */
+                       int16_t         ground_pitch;           /* 20 */
+                       int16_t         ground_yaw;             /* 22 */
+               } flight_old;                                   /* 24 */
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;
+                       uint16_t        reason;
+               } state;
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint32_t        pres;           /* 4 */
+                       uint32_t        temp;           /* 8 */
+                       int16_t         accel_x;        /* 12 */
+                       int16_t         accel_y;        /* 14 */
+                       int16_t         accel_z;        /* 16 */
+                       int16_t         gyro_x;         /* 18 */
+                       int16_t         gyro_y;         /* 20 */
+                       int16_t         gyro_z;         /* 22 */
+                       int16_t         mag_x;          /* 24 */
+                       int16_t         mag_z;          /* 26 */
+                       int16_t         mag_y;          /* 28 */
+                       int16_t         accel;          /* 30 */
+               } sensor;       /* 32 */
+               /* AO_LOG_TEMP_VOLT */
+               struct {
+                       int16_t         v_batt;         /* 4 */
+                       int16_t         v_pbatt;        /* 6 */
+                       int16_t         n_sense;        /* 8 */
+                       int16_t         sense[10];      /* 10 */
+                       uint16_t        pyro;           /* 30 */
+               } volt;                                 /* 32 */
+               /* AO_LOG_GPS_TIME */
+               struct {
+                       int32_t         latitude;       /* 4 */
+                       int32_t         longitude;      /* 8 */
+                       uint16_t        altitude_low;   /* 12 */
+                       uint8_t         hour;           /* 14 */
+                       uint8_t         minute;         /* 15 */
+                       uint8_t         second;         /* 16 */
+                       uint8_t         flags;          /* 17 */
+                       uint8_t         year;           /* 18 */
+                       uint8_t         month;          /* 19 */
+                       uint8_t         day;            /* 20 */
+                       uint8_t         course;         /* 21 */
+                       uint16_t        ground_speed;   /* 22 */
+                       int16_t         climb_rate;     /* 24 */
+                       uint8_t         pdop;           /* 26 */
+                       uint8_t         hdop;           /* 27 */
+                       uint8_t         vdop;           /* 28 */
+                       uint8_t         mode;           /* 29 */
+                       int16_t         altitude_high;  /* 30 */
+               } gps;  /* 32 */
+               /* AO_LOG_GPS_SAT */
+               struct {
+                       uint16_t        channels;       /* 4 */
+                       struct {
+                               uint8_t svid;
+                               uint8_t c_n;
+                       } sats[12];                     /* 6 */
+               } gps_sat;                              /* 30 */
+       } u;
+};
+
+#define AO_LOG_MEGA_GPS_ALTITUDE(l)    ((int32_t) ((l)->u.gps.altitude_high << 16) | ((l)->u.gps.altitude_low))
+#define AO_LOG_MEGA_SET_GPS_ALTITUDE(l,a)      (((l)->u.gps.mode |= AO_GPS_MODE_ALTITUDE_24), \
+                                                ((l)->u.gps.altitude_high = (a) >> 16), \
+                                                (l)->u.gps.altitude_low = (a))
+
+struct ao_log_firetwo {
+       char                    type;                   /* 0 */
+       uint8_t                 csum;                   /* 1 */
+       uint16_t                tick;                   /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+               } flight;       /* 6 */
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;          /* 4 */
+                       uint16_t        reason;         /* 6 */
+               } state;        /* 8 */
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint16_t        pressure;       /* 4 */
+                       uint16_t        thrust;         /* 6 */
+                       uint16_t        thermistor[4];  /* 8 */
+               } sensor;       /* 24 */
+               uint8_t         align[28];              /* 4 */
+       } u;    /* 32 */
+};
+
+struct ao_log_telestatic {
+       char                    type;                   /* 0 */
+       uint8_t                 csum;                   /* 1 */
+       uint16_t                tick;                   /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+               } flight;       /* 6 */
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;          /* 4 */
+                       uint16_t        reason;         /* 6 */
+               } state;        /* 8 */
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint32_t        pressure;       /* 4 */
+                       uint32_t        pressure2;      /* 8 */
+                       uint32_t        thrust;         /* 12 */
+                       uint32_t        mass;           /* 16 */
+                       uint16_t        t_low;          /* 20 */
+                       uint16_t        t_high[4];      /* 22 */
+               } sensor;       /* 30 */
+               uint8_t         align[28];              /* 4 */
+       } u;    /* 32 */
+};
+
+struct ao_log_metrum {
+       char                    type;                   /* 0 */
+       uint8_t                 csum;                   /* 1 */
+       uint16_t                tick;                   /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+                       int16_t         ground_accel;   /* 6 */
+                       uint32_t        ground_pres;    /* 8 */
+                       uint32_t        ground_temp;    /* 12 */
+               } flight;       /* 16 */
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;          /* 4 */
+                       uint16_t        reason;         /* 6 */
+               } state;        /* 8 */
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint32_t        pres;           /* 4 */
+                       uint32_t        temp;           /* 8 */
+                       int16_t         accel;          /* 12 */
+               } sensor;       /* 14 */
+               /* AO_LOG_TEMP_VOLT */
+               struct {
+                       int16_t         v_batt;         /* 4 */
+                       int16_t         sense_a;        /* 6 */
+                       int16_t         sense_m;        /* 8 */
+               } volt;         /* 10 */
+               /* AO_LOG_GPS_POS */
+               struct {
+                       int32_t         latitude;       /* 4 */
+                       int32_t         longitude;      /* 8 */
+                       uint16_t        altitude_low;   /* 12 */
+                       int16_t         altitude_high;  /* 14 */
+               } gps;          /* 16 */
+               /* AO_LOG_GPS_TIME */
+               struct {
+                       uint8_t         hour;           /* 4 */
+                       uint8_t         minute;         /* 5 */
+                       uint8_t         second;         /* 6 */
+                       uint8_t         flags;          /* 7 */
+                       uint8_t         year;           /* 8 */
+                       uint8_t         month;          /* 9 */
+                       uint8_t         day;            /* 10 */
+                       uint8_t         pdop;           /* 11 */
+               } gps_time;     /* 12 */
+               /* AO_LOG_GPS_SAT (up to three packets) */
+               struct {
+                       uint8_t channels;               /* 4 */
+                       uint8_t more;                   /* 5 */
+                       struct {
+                               uint8_t svid;
+                               uint8_t c_n;
+                       } sats[4];                      /* 6 */
+               } gps_sat;                              /* 14 */
+               uint8_t         raw[12];                /* 4 */
+       } u;    /* 16 */
+};
+
+struct ao_log_mini {
+       char            type;                           /* 0 */
+       uint8_t         csum;                           /* 1 */
+       uint16_t        tick;                           /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+                       uint16_t        r6;
+                       uint32_t        ground_pres;    /* 8 */
+               } flight;
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;          /* 4 */
+                       uint16_t        reason;         /* 6 */
+               } state;
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint8_t         pres[3];        /* 4 */
+                       uint8_t         temp[3];        /* 7 */
+                       int16_t         sense_a;        /* 10 */
+                       int16_t         sense_m;        /* 12 */
+                       int16_t         v_batt;         /* 14 */
+               } sensor;                               /* 16 */
+       } u;                                            /* 16 */
+};                                                     /* 16 */
+
+#define ao_log_pack24(dst,value) do {          \
+               (dst)[0] = (value);             \
+               (dst)[1] = (value) >> 8;        \
+               (dst)[2] = (value) >> 16;       \
+       } while (0)
+
+struct ao_log_gps {
+       char                    type;                   /* 0 */
+       uint8_t                 csum;                   /* 1 */
+       uint16_t                tick;                   /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;                 /* 4 */
+                       int16_t         start_altitude;         /* 6 */
+                       int32_t         start_latitude;         /* 8 */
+                       int32_t         start_longitude;        /* 12 */
+               } flight;                                       /* 16 */
+               /* AO_LOG_GPS_TIME */
+               struct {
+                       int32_t         latitude;       /* 4 */
+                       int32_t         longitude;      /* 8 */
+                       uint16_t        altitude_low;   /* 12 */
+                       uint8_t         hour;           /* 14 */
+                       uint8_t         minute;         /* 15 */
+                       uint8_t         second;         /* 16 */
+                       uint8_t         flags;          /* 17 */
+                       uint8_t         year;           /* 18 */
+                       uint8_t         month;          /* 19 */
+                       uint8_t         day;            /* 20 */
+                       uint8_t         course;         /* 21 */
+                       uint16_t        ground_speed;   /* 22 */
+                       int16_t         climb_rate;     /* 24 */
+                       uint8_t         pdop;           /* 26 */
+                       uint8_t         hdop;           /* 27 */
+                       uint8_t         vdop;           /* 28 */
+                       uint8_t         mode;           /* 29 */
+                       int16_t         altitude_high;  /* 30 */
+               } gps;  /* 31 */
+               /* AO_LOG_GPS_SAT */
+               struct {
+                       uint16_t        channels;       /* 4 */
+                       struct {
+                               uint8_t svid;
+                               uint8_t c_n;
+                       } sats[12];                     /* 6 */
+               } gps_sat;                              /* 30 */
+       } u;
+};
+
+struct ao_eeprom {
+       struct ao_config        config;
+       struct ao_ms5607_prom   ms5607_prom;
+       int                     log_format;
+       uint16_t                serial_number;
+       uint8_t                 *data;
+       uint32_t                len;
+};
+
+struct ao_eeprom *ao_eeprom_read(FILE *file);
+
+struct ao_eeprom *ao_eeprom_read_old(FILE *file);
+
+void ao_eeprom_free_data(struct ao_eeprom *ao_eeprom);
+
+#endif /* _AO_EEPROM_READ_H_ */
diff --git a/ao-tools/lib/ao-ms5607-convert.c b/ao-tools/lib/ao-ms5607-convert.c
new file mode 100644 (file)
index 0000000..cc0eee3
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao-ms5607.h>
+
+void
+ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value,
+                 struct ao_ms5607_prom *prom, bool is_ms5611)
+{
+       int32_t dT;
+       int32_t TEMP;
+       int64_t OFF;
+       int64_t SENS;
+
+       dT = sample->temp - ((int32_t) prom->tref << 8);
+
+       TEMP = 2000 + (((int64_t) dT * prom->tempsens) >> 23);
+
+       if (is_ms5611) {
+               OFF = ((int64_t) prom->off << 16) + (((int64_t) prom->tco * dT) >> 7);
+               SENS = ((int64_t) prom->sens << 15) + (((int64_t) prom->tcs * dT) >> 8);
+       } else {
+               OFF = ((int64_t) prom->off << 17) + (((int64_t) prom->tco * dT) >> 6);
+               SENS = ((int64_t) prom->sens << 16) + (((int64_t) prom->tcs * dT) >> 7);
+       }
+
+       if (TEMP < 2000) {
+               int32_t T2 = ((int64_t) dT * (int64_t) dT) >> 31;
+               int32_t TEMPM = TEMP - 2000;
+               int64_t OFF2 = (61 * (int64_t) TEMPM * (int64_t) TEMPM) >> 4;
+               int64_t SENS2 = 2 * (int64_t) TEMPM * (int64_t) TEMPM;
+               if (TEMP < -1500) {
+                       int32_t TEMPP = TEMP + 1500;
+                       /* You'd think this would need a 64-bit int, but
+                        * that would imply a temperature below -327.67°C...
+                        */
+                       int32_t TEMPP2 = TEMPP * TEMPP;
+                       OFF2 = OFF2 + (int64_t) 15 * TEMPP2;
+                       SENS2 = SENS2 + (int64_t) 8 * TEMPP2;
+               }
+               TEMP -= T2;
+               OFF -= OFF2;
+               SENS -= SENS2;
+       }
+
+       value->pres = ((((int64_t) sample->pres * SENS) >> 21) - OFF) >> 15;
+       value->temp = TEMP;
+}
diff --git a/ao-tools/lib/ao-ms5607.h b/ao-tools/lib/ao-ms5607.h
new file mode 100644 (file)
index 0000000..a23bb3c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_MS5607_H_
+#define _AO_MS5607_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct ao_ms5607_prom {
+       uint16_t        reserved;
+       uint16_t        sens;
+       uint16_t        off;
+       uint16_t        tcs;
+       uint16_t        tco;
+       uint16_t        tref;
+       uint16_t        tempsens;
+       uint16_t        crc;
+};
+
+struct ao_ms5607_sample {
+       uint32_t        pres;   /* raw 24 bit sensor */
+       uint32_t        temp;   /* raw 24 bit sensor */
+};
+
+struct ao_ms5607_value {
+       int32_t         pres;   /* in Pa * 10 */
+       int32_t         temp;   /* in °C * 100 */
+};
+
+void
+ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value,
+                 struct ao_ms5607_prom *prom, bool is_ms5611);
+
+#endif /* _AO_MS5607_H_ */