Add simple post-flight analysis tool (ao-postflight)
[fw/altos] / ao-tools / lib / cc-logfile.c
diff --git a/ao-tools/lib/cc-logfile.c b/ao-tools/lib/cc-logfile.c
new file mode 100644 (file)
index 0000000..444ff08
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "cc.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+timedata_add(struct cc_timedata *data, double time, double value)
+{
+       struct cc_timedataelt   *newdata;
+       int                     newsize;
+       if (data->size == data->num) {
+               if (data->size == 0)
+                       newdata = malloc((newsize = 256) * sizeof (struct cc_timedataelt));
+               else
+                       newdata = realloc (data->data, (newsize = data->size * 2)
+                                          * sizeof (struct cc_timedataelt));
+               if (!newdata)
+                       return 0;
+               data->size = newsize;
+               data->data = newdata;
+       }
+       if (data->num && data->data[data->num-1].time > time)
+               time += 65536;
+       data->data[data->num].time = time;
+       data->data[data->num].value = value;
+       data->num++;
+       return 1;
+}
+
+static void
+timedata_free(struct cc_timedata *data)
+{
+       if (data->data)
+               free(data->data);
+}
+
+static int
+gpsdata_add(struct cc_gpsdata *data, struct cc_gpselt *elt)
+{
+       struct cc_gpselt        *newdata;
+       int                     newsize;
+       if (data->size == data->num) {
+               if (data->size == 0)
+                       newdata = malloc((newsize = 256) * sizeof (struct cc_gpselt));
+               else
+                       newdata = realloc (data->data, (newsize = data->size * 2)
+                                          * sizeof (struct cc_gpselt));
+               if (!newdata)
+                       return 0;
+               data->size = newsize;
+               data->data = newdata;
+       }
+       data->data[data->num] = *elt;
+       data->num++;
+       return 1;
+}
+
+static void
+gpsdata_free(struct cc_gpsdata *data)
+{
+       if (data->data)
+               free(data->data);
+}
+
+#define AO_LOG_FLIGHT          'F'
+#define AO_LOG_SENSOR          'A'
+#define AO_LOG_TEMP_VOLT       'T'
+#define AO_LOG_DEPLOY          'D'
+#define AO_LOG_STATE           'S'
+#define AO_LOG_GPS_TIME                'G'
+#define AO_LOG_GPS_LAT         'N'
+#define AO_LOG_GPS_LON         'W'
+#define AO_LOG_GPS_ALT         'H'
+#define AO_LOG_GPS_SAT         'V'
+
+#define AO_LOG_POS_NONE                (~0UL)
+
+static int
+read_eeprom(const char *line, struct cc_flightraw *f, double *ground_pres, int *ground_pres_count)
+{
+       char    type;
+       int     tick;
+       int     a, b;
+       struct cc_gpselt        gps;
+       int     serial;
+
+       if (sscanf(line, "serial-number %u", &serial) == 1) {
+               f->serial = serial;
+               return 1;
+       }
+       if (sscanf(line, "%c %x %x %x", &type, &tick, &a, &b) != 4)
+               return 0;
+       switch (type) {
+       case AO_LOG_FLIGHT:
+               f->ground_accel = a;
+               f->ground_pres = 0;
+               f->flight = b;
+               *ground_pres = 0;
+               *ground_pres_count = 0;
+               break;
+       case AO_LOG_SENSOR:
+               timedata_add(&f->accel, tick, a);
+               timedata_add(&f->pres, tick, b);
+               if (*ground_pres_count < 20) {
+                       *ground_pres += b;
+                       (*ground_pres_count)++;
+                       if (*ground_pres_count >= 20)
+                               f->ground_pres = *ground_pres / *ground_pres_count;
+               }
+               break;
+       case AO_LOG_TEMP_VOLT:
+               timedata_add(&f->temp, tick, a);
+               timedata_add(&f->volt, tick, b);
+               break;
+       case AO_LOG_DEPLOY:
+               timedata_add(&f->drogue, tick, a);
+               timedata_add(&f->main, tick, b);
+               break;
+       case AO_LOG_STATE:
+               timedata_add(&f->state, tick, a);
+               break;
+       case AO_LOG_GPS_TIME:
+               gps.time = tick;
+               break;
+       case AO_LOG_GPS_LAT:
+               gps.lat = ((int32_t) (a + (b << 16))) / 10000000.0;
+               break;
+       case AO_LOG_GPS_LON:
+               gps.lon = ((int32_t) (a + (b << 16))) / 10000000.0;
+               break;
+       case AO_LOG_GPS_ALT:
+               gps.alt = ((int32_t) (a + (b << 16)));
+               gpsdata_add(&f->gps, &gps);
+               break;
+       case AO_LOG_GPS_SAT:
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static int
+read_telem(const char *line, struct cc_flightraw *f)
+{
+       struct cc_telem         telem;
+       struct cc_gpselt        gps;
+       if (!cc_telem_parse(line, &telem))
+               return 0;
+       f->ground_accel = telem.ground_accel;
+       f->ground_pres = telem.ground_pres;
+       f->flight = 0;
+       timedata_add(&f->accel, telem.tick, telem.flight_accel);
+       timedata_add(&f->pres, telem.tick, telem.flight_pres);
+       timedata_add(&f->temp, telem.tick, telem.temp);
+       timedata_add(&f->volt, telem.tick, telem.batt);
+       timedata_add(&f->drogue, telem.tick, telem.drogue);
+       timedata_add(&f->main, telem.tick, telem.main);
+       if (telem.gps.gps_locked) {
+               gps.time = telem.tick;
+               gps.lat = telem.gps.lat;
+               gps.lon = telem.gps.lon;
+               gps.alt = telem.gps.alt;
+               gpsdata_add(&f->gps, &gps);
+       }
+       return 1;
+}
+
+struct cc_flightraw *
+cc_log_read(FILE *file)
+{
+       struct cc_flightraw     *f;
+       char                    line[8192];
+       double                  ground_pres;
+       int                     ground_pres_count;
+
+       f = calloc(1, sizeof (struct cc_flightraw));
+       if (!f)
+               return NULL;
+       while (fgets(line, sizeof (line), file)) {
+               if (read_eeprom(line, f, &ground_pres, &ground_pres_count))
+                       continue;
+               if (read_telem(line, f))
+                       continue;
+               fprintf (stderr, "invalid line: %s", line);
+       }
+       return f;
+}
+
+void
+cc_flightraw_free(struct cc_flightraw *raw)
+{
+       timedata_free(&raw->accel);
+       timedata_free(&raw->pres);
+       timedata_free(&raw->temp);
+       timedata_free(&raw->volt);
+       timedata_free(&raw->main);
+       timedata_free(&raw->drogue);
+       timedata_free(&raw->state);
+       gpsdata_free(&raw->gps);
+       free(raw);
+}