/* * Copyright © 2009 Keith Packard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "cc.h" #include #include #include static int timedata_add(struct cc_timedata *data, double time, double value) { struct cc_timedataelt *newdata; int newsize; if (data->size == data->num) { if (data->size == 0) newdata = malloc((newsize = 256) * sizeof (struct cc_timedataelt)); else newdata = realloc (data->data, (newsize = data->size * 2) * sizeof (struct cc_timedataelt)); if (!newdata) return 0; data->size = newsize; data->data = newdata; } time += data->time_offset; if (data->num && data->data[data->num-1].time > time) { data->time_offset += 65536; time += 65536; } data->data[data->num].time = time; data->data[data->num].value = value; data->num++; return 1; } static void timedata_free(struct cc_timedata *data) { if (data->data) free(data->data); } static int gpsdata_add(struct cc_gpsdata *data, struct cc_gpselt *elt) { struct cc_gpselt *newdata; int newsize; if (data->size == data->num) { if (data->size == 0) newdata = malloc((newsize = 256) * sizeof (struct cc_gpselt)); else newdata = realloc (data->data, (newsize = data->size * 2) * sizeof (struct cc_gpselt)); if (!newdata) return 0; data->size = newsize; data->data = newdata; } elt->time += data->time_offset; if (data->num && data->data[data->num-1].time > elt->time) { data->time_offset += 65536; elt->time += 65536; } data->data[data->num] = *elt; data->num++; return 1; } static int gpssat_add(struct cc_gpsdata *data, struct cc_gpssat *sat) { int i, j; int reuse = 0; int newsizesats; struct cc_gpssats *newsats; for (i = data->numsats; --i >= 0;) { if (data->sats[i].sat[0].time == sat->time) { reuse = 1; break; } if (data->sats[i].sat[0].time < sat->time) break; } if (!reuse) { if (data->numsats == data->sizesats) { if (data->sizesats == 0) newsats = malloc((newsizesats = 256) * sizeof (struct cc_gpssats)); else newsats = realloc (data->sats, (newsizesats = data->sizesats * 2) * sizeof (struct cc_gpssats)); if (!newsats) return 0; data->sats = newsats; data->sizesats = newsizesats; } i = data->numsats++; data->sats[i].nsat = 0; } j = data->sats[i].nsat; if (j < 12) { data->sats[i].sat[j] = *sat; data->sats[i].nsat = j + 1; } return 1; } static void gpsdata_free(struct cc_gpsdata *data) { 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_GPS_DATE 'Y' #define AO_LOG_POS_NONE (~0UL) #define GPS_TIME 1 #define GPS_LAT 2 #define GPS_LON 4 #define GPS_ALT 8 static int read_eeprom(const char *line, struct cc_flightraw *f, double *ground_pres, int *ground_pres_count) { char type; int tick; int a, b; static struct cc_gpselt gps; static int gps_valid; struct cc_gpssat sat; 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: /* the flight computer writes TIME first, so reset * any stale data before adding this record */ gps.time = tick; gps.hour = (a & 0xff); gps.minute = (a >> 8) & 0xff; gps.second = (b & 0xff); gps.flags = (b >> 8) & 0xff; gps_valid = GPS_TIME; break; case AO_LOG_GPS_LAT: gps.lat = ((int32_t) (a + (b << 16))) / 10000000.0; gps_valid |= GPS_LAT; break; case AO_LOG_GPS_LON: gps.lon = ((int32_t) (a + (b << 16))) / 10000000.0; gps_valid |= GPS_LON; break; case AO_LOG_GPS_ALT: gps.alt = (int16_t) a; gps_valid |= GPS_ALT; break; case AO_LOG_GPS_SAT: sat.time = tick; sat.svid = a; sat.c_n = (b >> 8) & 0xff; gpssat_add(&f->gps, &sat); break; case AO_LOG_GPS_DATE: f->year = 2000 + (a & 0xff); f->month = (a >> 8) & 0xff; f->day = (b & 0xff); break; default: return 0; } if (gps_valid == 0xf) { gps_valid = 0; gpsdata_add(&f->gps, &gps); } return 1; } static const char *state_names[] = { "startup", "idle", "pad", "boost", "fast", "coast", "drogue", "main", "landed", "invalid" }; static enum ao_flight_state state_name_to_state(char *state_name) { enum ao_flight_state state; for (state = ao_flight_startup; state < ao_flight_invalid; state++) if (!strcmp(state_names[state], state_name)) return state; return ao_flight_invalid; } static int read_telem(const char *line, struct cc_flightraw *f) { struct cc_telem telem; struct cc_gpselt gps; struct cc_gpssat sat; int s; if (!cc_telem_parse(line, &telem)) return 0; f->ground_accel = telem.ground_accel; f->ground_pres = telem.ground_pres; f->flight = 0; timedata_add(&f->accel, telem.tick, telem.flight_accel); timedata_add(&f->pres, telem.tick, telem.flight_pres); timedata_add(&f->temp, telem.tick, telem.temp); timedata_add(&f->volt, telem.tick, telem.batt); timedata_add(&f->drogue, telem.tick, telem.drogue); timedata_add(&f->main, telem.tick, telem.main); timedata_add(&f->state, telem.tick, state_name_to_state(telem.state)); if (telem.gps.gps_locked) { f->year = telem.gps.gps_time.year; f->month = telem.gps.gps_time.month; f->day = telem.gps.gps_time.day; gps.time = telem.tick; gps.lat = telem.gps.lat; gps.lon = telem.gps.lon; gps.alt = telem.gps.alt; gps.hour = telem.gps.gps_time.hour; gps.minute = telem.gps.gps_time.minute; gps.second = telem.gps.gps_time.second; gpsdata_add(&f->gps, &gps); } for (s = 0; s < telem.gps_tracking.channels; s++) { sat.time = telem.tick; sat.svid = telem.gps_tracking.sats[s].svid; sat.c_n = telem.gps_tracking.sats[s].c_n0; gpssat_add(&f->gps, &sat); } return 1; } struct cc_flightraw * cc_log_read(FILE *file) { struct cc_flightraw *f; char line[8192]; double ground_pres = 0.0; int ground_pres_count = 0; 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); }