ao-tools: Change ao-eeprom into eeprom analysis tool
[fw/altos] / ao-tools / ao-eeprom / ao-eeprom.c
index b865e298d2e01b6a499c6a7e270e46a682d31e2b..0c0500f9fbec6cdeff4cdd1e4357aea0c47fe598 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;
 }