2 * Copyright © 2009 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 #include <ao-eeprom-read.h>
25 #include <ao-atmosphere.h>
27 static const struct option options[] = {
28 { .name = "raw", .has_arg = 0, .val = 'r' },
29 { .name = "csum", .has_arg = 0, .val = 'c' },
30 { .name = "verbose", .has_arg = 0, .val = 'v' },
31 { .name = "len", .has_arg = 1, .val = 'l' },
35 static void usage(char *program)
37 fprintf(stderr, "usage: %s [--raw] [--csum] [--verbose] [--len <record-len>] {flight.eeprom} ...\n", program);
42 ao_csum_valid(uint8_t *d, int len)
46 for (i = 0; i < len; i++)
52 ao_ms5607(uint32_t pres, uint32_t temp, struct ao_eeprom *eeprom, bool is_ms5611)
54 struct ao_ms5607_sample ms5607_sample = { .pres = pres, .temp = temp };
55 struct ao_ms5607_value ms5607_value;
57 ao_ms5607_convert(&ms5607_sample, &ms5607_value,
58 &eeprom->ms5607_prom, is_ms5611);
59 printf(" pres %9u temp %9u (%7.3f kPa %6.2f°C %7.1f m)",
62 ms5607_value.pres / 1000.0,
63 ms5607_value.temp / 100.0,
64 ao_pressure_to_altitude(ms5607_value.pres));
67 #define GRAVITY 9.80665
70 ao_accel(int16_t accel, struct ao_eeprom *eeprom)
72 double accel_2g = eeprom->config.accel_minus_g - eeprom->config.accel_plus_g;
73 double accel_scale = GRAVITY * 2.0 / accel_2g;
74 printf(" accel %6d (%7.2f m/s²)",
75 accel, (eeprom->config.accel_plus_g - accel) * accel_scale);
78 static const char *state_names[] = {
91 #define NUM_STATE (sizeof state_names/sizeof state_names[0])
94 ao_state_name(uint16_t state)
96 if (state < NUM_STATE)
97 return state_names[state];
102 ao_state(uint16_t state, uint16_t reason)
104 printf(" state %5u %s reason %5u",
105 state, ao_state_name(state), reason);
109 ao_volts(const char *name, int16_t value, int16_t max_adc, double ref, double r1, double r2)
115 ref * ((double) value / max_adc) * (r1 + r2) / r2);
120 uint16(uint8_t *bytes, int off)
122 return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
126 int16(uint8_t *bytes, int off)
128 return (int16_t) uint16(bytes, off);
132 uint32(uint8_t *bytes, int off)
134 return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
135 (((uint32_t) bytes[off+2]) << 16) |
136 (((uint32_t) bytes[off+3]) << 24);
140 int32(uint8_t *bytes, int off)
142 return (int32_t) uint32(bytes, off);
147 uint24(uint8_t *bytes, int off)
149 return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
150 (((uint32_t) bytes[off+2]) << 16);
154 int24(uint8_t *bytes, int off)
156 return (int32_t) uint24(bytes, off);
160 main (int argc, char **argv)
162 struct ao_eeprom *eeprom;
167 bool verbose = false;
173 while ((c = getopt_long(argc, argv, "rcvl:", options, NULL)) != -1) {
185 arg_len = strtol(optarg, &end, 0);
186 if (!*optarg || *end)
194 for (i = optind; i < argc; i++) {
195 file = fopen(argv[i], "r");
201 eeprom = ao_eeprom_read(file);
209 bool is_ms5611 = false;
211 double sense_r1 = 0.0, sense_r2 = 0.0;
212 double batt_r1 = 0.0, batt_r2 = 0.0;
213 double adc_ref = 0.0;
216 switch (eeprom->log_format) {
217 case AO_LOG_FORMAT_TELEMEGA_OLD:
220 case AO_LOG_FORMAT_EASYMINI1:
223 if (eeprom->serial_number < 1000)
227 batt_r1 = sense_r1 = 100e3;
228 batt_r2 = sense_r2 = 27e3;
230 case AO_LOG_FORMAT_TELEMETRUM:
239 case AO_LOG_FORMAT_TELEMINI2:
242 case AO_LOG_FORMAT_TELEGPS:
245 case AO_LOG_FORMAT_TELEMEGA:
254 case AO_LOG_FORMAT_DETHERM:
257 case AO_LOG_FORMAT_TELEMINI3:
266 case AO_LOG_FORMAT_TELEFIRETWO:
269 case AO_LOG_FORMAT_EASYMINI2:
273 batt_r1 = sense_r1 = 100e3;
274 batt_r2 = sense_r2 = 27e3;
276 case AO_LOG_FORMAT_TELEMEGA_3:
285 case AO_LOG_FORMAT_EASYMEGA_2:
294 case AO_LOG_FORMAT_TELESTATIC:
297 case AO_LOG_FORMAT_MICROPEAK2:
303 printf("config major %d minor %d log format %d total %u len %d\n",
304 eeprom->config.major,
305 eeprom->config.minor,
310 for (pos = 0; pos < eeprom->len; pos += len) {
314 for (i = 0; i < len; i++)
315 printf(" %02x", eeprom->data[pos + i]);
317 struct ao_log_mega *log_mega;
318 struct ao_log_mini *log_mini;
319 struct ao_log_metrum *log_metrum;
320 struct ao_log_gps *log_gps;
322 if (!csum && !ao_csum_valid(&eeprom->data[pos], len)) {
324 printf("\tchecksum error at %d\n", pos);
328 struct ao_log_header *log_header = (struct ao_log_header *) &eeprom->data[pos];
330 printf("type %c tick %5u", log_header->type, log_header->tick);
332 switch (eeprom->log_format) {
333 case AO_LOG_FORMAT_TELEMEGA_OLD:
334 case AO_LOG_FORMAT_TELEMEGA:
335 case AO_LOG_FORMAT_TELEMEGA_3:
336 case AO_LOG_FORMAT_EASYMEGA_2:
337 log_mega = (struct ao_log_mega *) &eeprom->data[pos];
338 switch (log_mega->type) {
340 printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u",
341 eeprom->serial_number,
342 log_mega->u.flight.flight,
343 log_mega->u.flight.ground_accel,
344 log_mega->u.flight.ground_pres);
345 printf(" along %6d aross %6d through %6d",
346 log_mega->u.flight.ground_accel_along,
347 log_mega->u.flight.ground_accel_across,
348 log_mega->u.flight.ground_accel_through);
349 printf(" roll %6d pitch %6d yaw %6d",
350 log_mega->u.flight.ground_roll,
351 log_mega->u.flight.ground_pitch,
352 log_mega->u.flight.ground_yaw);
355 ao_state(log_mega->u.state.state,
356 log_mega->u.state.reason);
359 ao_ms5607(log_mega->u.sensor.pres,
360 log_mega->u.sensor.temp,
362 printf(" accel_x %6d accel_y %6d accel_z %6d",
363 log_mega->u.sensor.accel_x,
364 log_mega->u.sensor.accel_y,
365 log_mega->u.sensor.accel_z);
366 printf (" gyro_x %6d gyro_y %6d gyro_z %6d",
367 log_mega->u.sensor.gyro_x,
368 log_mega->u.sensor.gyro_y,
369 log_mega->u.sensor.gyro_z);
370 printf (" mag_x %6d mag_y %6d mag_z %6d",
371 log_mega->u.sensor.mag_x,
372 log_mega->u.sensor.mag_y,
373 log_mega->u.sensor.mag_z);
374 ao_accel(log_mega->u.sensor.accel, eeprom);
376 case AO_LOG_TEMP_VOLT:
378 log_mega->u.volt.v_batt,
383 log_mega->u.volt.v_pbatt,
387 printf(" n_sense %1d",
388 log_mega->u.volt.n_sense);
389 for (i = 0; i < log_mega->u.volt.n_sense; i++) {
391 sprintf(name, "sense%d", i);
393 log_mega->u.volt.sense[i],
398 printf(" pyro %04x", log_mega->u.volt.pyro);
400 case AO_LOG_GPS_TIME:
401 printf(" lat %10.7f° lon %10.7f° alt %8d m",
402 log_mega->u.gps.latitude / 10000000.0,
403 log_mega->u.gps.longitude/ 10000000.0,
404 (int32_t) (log_mega->u.gps.altitude_low |
405 (log_mega->u.gps.altitude_high << 16)));
406 printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x",
407 log_mega->u.gps.hour,
408 log_mega->u.gps.minute,
409 log_mega->u.gps.second,
410 log_mega->u.gps.year,
411 log_mega->u.gps.month,
413 log_mega->u.gps.flags);
414 printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d",
415 log_mega->u.gps.course,
416 log_mega->u.gps.ground_speed,
417 log_mega->u.gps.climb_rate,
418 log_mega->u.gps.pdop,
419 log_mega->u.gps.hdop,
420 log_mega->u.gps.vdop,
421 log_mega->u.gps.mode);
424 printf(" channels %2d",
425 log_mega->u.gps_sat.channels);
426 for (i = 0; i < 12; i++) {
427 printf(" svid %3d c_n %2d",
428 log_mega->u.gps_sat.sats[i].svid,
429 log_mega->u.gps_sat.sats[i].c_n);
434 case AO_LOG_FORMAT_EASYMINI1:
435 case AO_LOG_FORMAT_EASYMINI2:
436 case AO_LOG_FORMAT_TELEMINI2:
437 case AO_LOG_FORMAT_TELEMINI3:
438 log_mini = (struct ao_log_mini *) &eeprom->data[pos];
439 switch (log_mini->type) {
441 printf(" serial %5u flight %5u ground_pres %9u",
442 eeprom->serial_number,
443 log_mini->u.flight.flight,
444 log_mini->u.flight.ground_pres);
447 ao_state(log_mini->u.state.state,
448 log_mini->u.state.reason);
451 ao_ms5607(int24(log_mini->u.sensor.pres, 0),
452 int24(log_mini->u.sensor.temp, 0),
455 log_mini->u.sensor.sense_a, max_adc,
456 adc_ref, sense_r1, sense_r2);
458 log_mini->u.sensor.sense_m, max_adc,
459 adc_ref, sense_r1, sense_r2);
461 log_mini->u.sensor.v_batt, max_adc,
462 adc_ref, batt_r1, batt_r2);
466 case AO_LOG_FORMAT_TELEMETRUM:
467 log_metrum = (struct ao_log_metrum *) &eeprom->data[pos];
468 switch (log_metrum->type) {
470 printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u ground_temp %9u",
471 eeprom->serial_number,
472 log_metrum->u.flight.flight,
473 log_metrum->u.flight.ground_accel,
474 log_metrum->u.flight.ground_pres,
475 log_metrum->u.flight.ground_temp);
478 ao_ms5607(log_metrum->u.sensor.pres,
479 log_metrum->u.sensor.temp,
481 ao_accel(log_metrum->u.sensor.accel, eeprom);
483 case AO_LOG_TEMP_VOLT:
485 log_metrum->u.volt.v_batt, max_adc,
486 adc_ref, batt_r1, batt_r2);
488 log_metrum->u.volt.sense_a, max_adc,
489 adc_ref, sense_r1, sense_r2);
491 log_metrum->u.volt.sense_m, max_adc,
492 adc_ref, sense_r1, sense_r2);
497 ao_state(log_metrum->u.state.state,
498 log_metrum->u.state.reason);
500 case AO_LOG_GPS_TIME:
501 printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x pdop %3u",
502 log_metrum->u.gps_time.hour,
503 log_metrum->u.gps_time.minute,
504 log_metrum->u.gps_time.second,
505 log_metrum->u.gps_time.year,
506 log_metrum->u.gps_time.month,
507 log_metrum->u.gps_time.day,
508 log_metrum->u.gps_time.flags,
509 log_metrum->u.gps_time.pdop);
512 printf(" channels %2d more %1d",
513 log_metrum->u.gps_sat.channels,
514 log_metrum->u.gps_sat.more);
515 for (i = 0; i < 4; i++) {
516 printf(" svid %3d c_n %2d",
517 log_metrum->u.gps_sat.sats[i].svid,
518 log_metrum->u.gps_sat.sats[i].c_n);
522 printf(" lat %10.7f° lon %10.7f° alt %8d m",
523 log_metrum->u.gps.latitude / 10000000.0,
524 log_metrum->u.gps.longitude/ 10000000.0,
525 (int32_t) (log_metrum->u.gps.altitude_low |
526 (log_metrum->u.gps.altitude_high << 16)));
532 case AO_LOG_FORMAT_TELEGPS:
533 log_gps = (struct ao_log_gps *) &eeprom->data[pos];
536 case AO_LOG_FORMAT_DETHERM: