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>
26 static const struct option options[] = {
27 { .name = "raw", .has_arg = 0, .val = 'r' },
28 { .name = "csum", .has_arg = 0, .val = 'c' },
29 { .name = "verbose", .has_arg = 0, .val = 'v' },
30 { .name = "len", .has_arg = 1, .val = 'l' },
34 static void usage(char *program)
36 fprintf(stderr, "usage: %s [--raw] [--csum] [--verbose] [--len <record-len>] {flight.eeprom} ...\n", program);
41 ao_csum_valid(uint8_t *d, int len)
45 for (i = 0; i < len; i++)
51 ao_ms5607(uint32_t pres, uint32_t temp, struct ao_eeprom *eeprom, bool is_ms5611)
53 struct ao_ms5607_sample ms5607_sample = { .pres = pres, .temp = temp };
54 struct ao_ms5607_value ms5607_value;
56 ao_ms5607_convert(&ms5607_sample, &ms5607_value,
57 &eeprom->ms5607_prom, is_ms5611);
58 printf(" pres %9u temp %9u (%7.3f kPa %6.2f°C)",
61 ms5607_value.pres / 1000.0,
62 ms5607_value.temp / 100.0);
65 #define GRAVITY 9.80665
68 ao_accel(int16_t accel, struct ao_eeprom *eeprom)
70 double accel_2g = eeprom->config.accel_minus_g - eeprom->config.accel_plus_g;
71 double accel_scale = GRAVITY * 2.0 / accel_2g;
72 printf(" accel %6d (%7.2f m/s²)",
73 accel, (eeprom->config.accel_plus_g - accel) * accel_scale);
76 static const char *state_names[] = {
89 #define NUM_STATE (sizeof state_names/sizeof state_names[0])
92 ao_state_name(uint16_t state)
94 if (state < NUM_STATE)
95 return state_names[state];
100 ao_state(uint16_t state, uint16_t reason)
102 printf(" state %5u %s reason %5u",
103 state, ao_state_name(state), reason);
107 ao_volts(const char *name, int16_t value, int16_t max_adc, double ref, double r1, double r2)
113 ref * ((double) value / max_adc) * (r1 + r2) / r2);
118 uint16(uint8_t *bytes, int off)
120 return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
124 int16(uint8_t *bytes, int off)
126 return (int16_t) uint16(bytes, off);
130 uint32(uint8_t *bytes, int off)
132 return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
133 (((uint32_t) bytes[off+2]) << 16) |
134 (((uint32_t) bytes[off+3]) << 24);
138 int32(uint8_t *bytes, int off)
140 return (int32_t) uint32(bytes, off);
145 uint24(uint8_t *bytes, int off)
147 return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
148 (((uint32_t) bytes[off+2]) << 16);
152 int24(uint8_t *bytes, int off)
154 return (int32_t) uint24(bytes, off);
158 main (int argc, char **argv)
160 struct ao_eeprom *eeprom;
165 bool verbose = false;
171 while ((c = getopt_long(argc, argv, "rcvl:", options, NULL)) != -1) {
183 arg_len = strtol(optarg, &end, 0);
184 if (!*optarg || *end)
192 for (i = optind; i < argc; i++) {
193 file = fopen(argv[i], "r");
199 eeprom = ao_eeprom_read(file);
207 bool is_ms5611 = false;
209 double sense_r1 = 0.0, sense_r2 = 0.0;
210 double batt_r1 = 0.0, batt_r2 = 0.0;
211 double adc_ref = 0.0;
214 switch (eeprom->log_format) {
215 case AO_LOG_FORMAT_TELEMEGA_OLD:
218 case AO_LOG_FORMAT_EASYMINI1:
221 if (eeprom->serial_number < 1000)
225 batt_r1 = sense_r1 = 100e3;
226 batt_r2 = sense_r2 = 27e3;
228 case AO_LOG_FORMAT_TELEMETRUM:
237 case AO_LOG_FORMAT_TELEMINI2:
240 case AO_LOG_FORMAT_TELEGPS:
243 case AO_LOG_FORMAT_TELEMEGA:
252 case AO_LOG_FORMAT_DETHERM:
255 case AO_LOG_FORMAT_TELEMINI3:
264 case AO_LOG_FORMAT_TELEFIRETWO:
267 case AO_LOG_FORMAT_EASYMINI2:
271 batt_r1 = sense_r1 = 100e3;
272 batt_r2 = sense_r2 = 27e3;
274 case AO_LOG_FORMAT_TELEMEGA_3:
283 case AO_LOG_FORMAT_EASYMEGA_2:
292 case AO_LOG_FORMAT_TELESTATIC:
295 case AO_LOG_FORMAT_MICROPEAK2:
301 printf("config major %d minor %d log format %d total %u len %d\n",
302 eeprom->config.major,
303 eeprom->config.minor,
308 for (pos = 0; pos < eeprom->len; pos += len) {
312 for (i = 0; i < len; i++)
313 printf(" %02x", eeprom->data[pos + i]);
315 struct ao_log_mega *log_mega;
316 struct ao_log_mini *log_mini;
317 struct ao_log_metrum *log_metrum;
318 struct ao_log_gps *log_gps;
320 if (!csum && !ao_csum_valid(&eeprom->data[pos], len)) {
322 printf("\tchecksum error at %d\n", pos);
326 struct ao_log_header *log_header = (struct ao_log_header *) &eeprom->data[pos];
328 printf("type %c tick %5u", log_header->type, log_header->tick);
330 switch (eeprom->log_format) {
331 case AO_LOG_FORMAT_TELEMEGA_OLD:
332 case AO_LOG_FORMAT_TELEMEGA:
333 case AO_LOG_FORMAT_TELEMEGA_3:
334 case AO_LOG_FORMAT_EASYMEGA_2:
335 log_mega = (struct ao_log_mega *) &eeprom->data[pos];
336 switch (log_mega->type) {
338 printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u",
339 eeprom->serial_number,
340 log_mega->u.flight.flight,
341 log_mega->u.flight.ground_accel,
342 log_mega->u.flight.ground_pres);
343 printf(" along %6d aross %6d through %6d",
344 log_mega->u.flight.ground_accel_along,
345 log_mega->u.flight.ground_accel_across,
346 log_mega->u.flight.ground_accel_through);
347 printf(" roll %6d pitch %6d yaw %6d",
348 log_mega->u.flight.ground_roll,
349 log_mega->u.flight.ground_pitch,
350 log_mega->u.flight.ground_yaw);
353 ao_state(log_mega->u.state.state,
354 log_mega->u.state.reason);
357 ao_ms5607(log_mega->u.sensor.pres,
358 log_mega->u.sensor.temp,
360 printf(" accel_x %6d accel_y %6d accel_z %6d",
361 log_mega->u.sensor.accel_x,
362 log_mega->u.sensor.accel_y,
363 log_mega->u.sensor.accel_z);
364 printf (" gyro_x %6d gyro_y %6d gyro_z %6d",
365 log_mega->u.sensor.gyro_x,
366 log_mega->u.sensor.gyro_y,
367 log_mega->u.sensor.gyro_z);
368 printf (" mag_x %6d mag_y %6d mag_z %6d",
369 log_mega->u.sensor.mag_x,
370 log_mega->u.sensor.mag_y,
371 log_mega->u.sensor.mag_z);
372 ao_accel(log_mega->u.sensor.accel, eeprom);
374 case AO_LOG_TEMP_VOLT:
376 log_mega->u.volt.v_batt,
381 log_mega->u.volt.v_pbatt,
385 printf(" n_sense %1d",
386 log_mega->u.volt.n_sense);
387 for (i = 0; i < log_mega->u.volt.n_sense; i++) {
389 sprintf(name, "sense%d", i);
391 log_mega->u.volt.sense[i],
396 printf(" pyro %04x", log_mega->u.volt.pyro);
398 case AO_LOG_GPS_TIME:
399 printf(" lat %10.7f° lon %10.7f° alt %8d m",
400 log_mega->u.gps.latitude / 10000000.0,
401 log_mega->u.gps.longitude/ 10000000.0,
402 (int32_t) (log_mega->u.gps.altitude_low |
403 (log_mega->u.gps.altitude_high << 16)));
404 printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x",
405 log_mega->u.gps.hour,
406 log_mega->u.gps.minute,
407 log_mega->u.gps.second,
408 log_mega->u.gps.year,
409 log_mega->u.gps.month,
411 log_mega->u.gps.flags);
412 printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d",
413 log_mega->u.gps.course,
414 log_mega->u.gps.ground_speed,
415 log_mega->u.gps.climb_rate,
416 log_mega->u.gps.pdop,
417 log_mega->u.gps.hdop,
418 log_mega->u.gps.vdop,
419 log_mega->u.gps.mode);
422 printf(" channels %2d",
423 log_mega->u.gps_sat.channels);
424 for (i = 0; i < 12; i++) {
425 printf(" svid %3d c_n %2d",
426 log_mega->u.gps_sat.sats[i].svid,
427 log_mega->u.gps_sat.sats[i].c_n);
432 case AO_LOG_FORMAT_EASYMINI1:
433 case AO_LOG_FORMAT_EASYMINI2:
434 case AO_LOG_FORMAT_TELEMINI2:
435 case AO_LOG_FORMAT_TELEMINI3:
436 log_mini = (struct ao_log_mini *) &eeprom->data[pos];
437 switch (log_mini->type) {
439 printf(" serial %5u flight %5u ground_pres %9u",
440 eeprom->serial_number,
441 log_mini->u.flight.flight,
442 log_mini->u.flight.ground_pres);
445 ao_state(log_mini->u.state.state,
446 log_mini->u.state.reason);
449 ao_ms5607(int24(log_mini->u.sensor.pres, 0),
450 int24(log_mini->u.sensor.temp, 0),
453 log_mini->u.sensor.sense_a, max_adc,
454 adc_ref, sense_r1, sense_r2);
456 log_mini->u.sensor.sense_m, max_adc,
457 adc_ref, sense_r1, sense_r2);
459 log_mini->u.sensor.v_batt, max_adc,
460 adc_ref, batt_r1, batt_r2);
464 case AO_LOG_FORMAT_TELEMETRUM:
465 log_metrum = (struct ao_log_metrum *) &eeprom->data[pos];
466 switch (log_metrum->type) {
468 printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u ground_temp %9u",
469 eeprom->serial_number,
470 log_metrum->u.flight.flight,
471 log_metrum->u.flight.ground_accel,
472 log_metrum->u.flight.ground_pres,
473 log_metrum->u.flight.ground_temp);
476 ao_ms5607(log_metrum->u.sensor.pres,
477 log_metrum->u.sensor.temp,
479 ao_accel(log_metrum->u.sensor.accel, eeprom);
481 case AO_LOG_TEMP_VOLT:
483 log_metrum->u.volt.v_batt, max_adc,
484 adc_ref, batt_r1, batt_r2);
486 log_metrum->u.volt.sense_a, max_adc,
487 adc_ref, sense_r1, sense_r2);
489 log_metrum->u.volt.sense_m, max_adc,
490 adc_ref, sense_r1, sense_r2);
495 ao_state(log_metrum->u.state.state,
496 log_metrum->u.state.reason);
498 case AO_LOG_GPS_TIME:
499 printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x pdop %3u",
500 log_metrum->u.gps_time.hour,
501 log_metrum->u.gps_time.minute,
502 log_metrum->u.gps_time.second,
503 log_metrum->u.gps_time.year,
504 log_metrum->u.gps_time.month,
505 log_metrum->u.gps_time.day,
506 log_metrum->u.gps_time.flags,
507 log_metrum->u.gps_time.pdop);
510 printf(" channels %2d more %1d",
511 log_metrum->u.gps_sat.channels,
512 log_metrum->u.gps_sat.more);
513 for (i = 0; i < 4; i++) {
514 printf(" svid %3d c_n %2d",
515 log_metrum->u.gps_sat.sats[i].svid,
516 log_metrum->u.gps_sat.sats[i].c_n);
520 printf(" lat %10.7f° lon %10.7f° alt %8d m",
521 log_metrum->u.gps.latitude / 10000000.0,
522 log_metrum->u.gps.longitude/ 10000000.0,
523 (int32_t) (log_metrum->u.gps.altitude_low |
524 (log_metrum->u.gps.altitude_high << 16)));
530 case AO_LOG_FORMAT_TELEGPS:
531 log_gps = (struct ao_log_gps *) &eeprom->data[pos];
534 case AO_LOG_FORMAT_DETHERM: