338 lines
7.9 KiB
C
338 lines
7.9 KiB
C
/*
|
|
* 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; 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.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;
|
|
}
|
|
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);
|
|
}
|