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 %7.3f kPa %7.1f m temp %9u %6.2f °C",
61 ms5607_value.pres / 1000.0,
62 ao_pressure_to_altitude(ms5607_value.pres),
64 ms5607_value.temp / 100.0);
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_adc_to_volts(int16_t value, int16_t max_adc, double ref, double r1, double r2)
111 return ref * ((double) value / max_adc) * (r1 + r2) / r2;
115 ao_volts(const char *name, int16_t value, int16_t max_adc, double ref, double r1, double r2)
120 printf(" %6.3f V", ao_adc_to_volts(value, max_adc, ref, r1, r2));
123 static double lb_to_n(double lb)
125 return lb / 0.22480894;
128 static double psi_to_pa(double psi)
130 return psi * 6894.76;
134 ao_volts_to_newtons(double volts)
136 /* this is a total guess */
137 return lb_to_n(volts * 57.88645 * GRAVITY);
141 ao_thrust(int16_t value, int16_t max_adc, double ref, double r1, double r2)
143 printf(" thrust %5d", value);
144 if (r1 && r2 && ref) {
145 double volts = ao_adc_to_volts(value, max_adc, ref, r1, r2);
146 printf(" %6.3f V %8.1f N", volts, ao_volts_to_newtons(volts));
151 ao_pressure(int16_t value, int16_t max_adc, double ref, double r1, double r2, double sensor_range)
153 printf(" pressure %5d", value);
154 if (r1 && r2 && ref) {
155 double volts = ao_adc_to_volts(value, max_adc, ref, r1, r2);
156 if (volts < 0.5) volts = 0.5;
157 if (volts > 4.5) volts = 4.5;
159 double psi = (volts - 0.5) / 4.0 * sensor_range;
160 double pa = psi_to_pa(psi);
161 printf(" %9.3f kPa", pa / 1000.0);
167 uint16(uint8_t *bytes, int off)
169 return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
173 int16(uint8_t *bytes, int off)
175 return (int16_t) uint16(bytes, off);
179 uint32(uint8_t *bytes, int off)
181 return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
182 (((uint32_t) bytes[off+2]) << 16) |
183 (((uint32_t) bytes[off+3]) << 24);
187 int32(uint8_t *bytes, int off)
189 return (int32_t) uint32(bytes, off);
194 uint24(uint8_t *bytes, int off)
196 return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
197 (((uint32_t) bytes[off+2]) << 16);
201 int24(uint8_t *bytes, int off)
203 return (int32_t) uint24(bytes, off);
207 main (int argc, char **argv)
209 struct ao_eeprom *eeprom;
214 bool verbose = false;
220 while ((c = getopt_long(argc, argv, "rcvl:", options, NULL)) != -1) {
232 arg_len = strtol(optarg, &end, 0);
233 if (!*optarg || *end)
241 for (i = optind; i < argc; i++) {
242 file = fopen(argv[i], "r");
248 eeprom = ao_eeprom_read(file);
256 bool is_ms5611 = false;
258 int64_t current_tick = 0;
259 int64_t first_tick = 0x7fffffffffffffffLL;
261 double sense_r1 = 0.0, sense_r2 = 0.0;
262 double batt_r1 = 0.0, batt_r2 = 0.0;
263 double adc_ref = 0.0;
264 double pressure_sensor = 0.0;
267 switch (eeprom->log_format) {
268 case AO_LOG_FORMAT_TELEMEGA_OLD:
271 case AO_LOG_FORMAT_EASYMINI1:
274 if (eeprom->serial_number < 1000)
278 batt_r1 = sense_r1 = 100e3;
279 batt_r2 = sense_r2 = 27e3;
281 case AO_LOG_FORMAT_TELEMETRUM:
290 case AO_LOG_FORMAT_TELEMINI2:
293 case AO_LOG_FORMAT_TELEGPS:
296 case AO_LOG_FORMAT_TELEMEGA:
305 case AO_LOG_FORMAT_DETHERM:
308 case AO_LOG_FORMAT_TELEMINI3:
317 case AO_LOG_FORMAT_TELEFIRETWO:
319 pressure_sensor = 2500.0;
322 sense_r1 = batt_r1 = 5600;
323 sense_r2 = batt_r2 = 10000;
325 case AO_LOG_FORMAT_EASYMINI2:
329 batt_r1 = sense_r1 = 100e3;
330 batt_r2 = sense_r2 = 27e3;
332 case AO_LOG_FORMAT_TELEMEGA_3:
341 case AO_LOG_FORMAT_EASYMEGA_2:
350 case AO_LOG_FORMAT_TELESTATIC:
353 case AO_LOG_FORMAT_MICROPEAK2:
356 case AO_LOG_FORMAT_TELEMEGA_4:
357 case AO_LOG_FORMAT_TELEMEGA_5:
358 case AO_LOG_FORMAT_TELEMEGA_6:
367 case AO_LOG_FORMAT_EASYMOTOR:
371 pressure_sensor = 1600.0;
381 fprintf(stderr, "Unknown eeprom format %d and no specified length\n",
386 printf("config major %d minor %d log format %d total %u len %d\n",
387 eeprom->config.major,
388 eeprom->config.minor,
394 for (pos = 0; pos < eeprom->len; pos += len) {
398 for (i = 0; i < len; i++)
399 printf(" %02x", eeprom->data[pos + i]);
401 struct ao_log_mega *log_mega;
402 struct ao_log_mini *log_mini;
403 struct ao_log_metrum *log_metrum;
404 struct ao_log_gps *log_gps;
405 struct ao_log_firetwo *log_firetwo;
406 struct ao_log_motor *log_motor;
408 if (!csum && !ao_csum_valid(&eeprom->data[pos], len)) {
410 printf("\tchecksum error at %d\n", pos);
414 struct ao_log_header *log_header = (struct ao_log_header *) &eeprom->data[pos];
416 if (first_tick == 0x7fffffffffffffffLL) {
417 current_tick = first_tick = log_header->tick;
419 int16_t diff = (int16_t) (log_header->tick - (uint16_t) current_tick);
421 current_tick += diff;
423 printf("type %c tick %5u %6.2f S", log_header->type, log_header->tick, (current_tick - first_tick) / 100.0);
425 switch (eeprom->log_format) {
426 case AO_LOG_FORMAT_TELEMEGA_OLD:
427 case AO_LOG_FORMAT_TELEMEGA:
428 case AO_LOG_FORMAT_TELEMEGA_3:
429 case AO_LOG_FORMAT_EASYMEGA_2:
430 case AO_LOG_FORMAT_TELEMEGA_4:
431 case AO_LOG_FORMAT_TELEMEGA_5:
432 case AO_LOG_FORMAT_TELEMEGA_6:
433 log_mega = (struct ao_log_mega *) &eeprom->data[pos];
434 switch (log_mega->type) {
436 printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u kPa %7.1f %7.1f m",
437 eeprom->serial_number,
438 log_mega->u.flight.flight,
439 log_mega->u.flight.ground_accel,
440 log_mega->u.flight.ground_pres,
441 log_mega->u.flight.ground_pres / 1000.0,
442 ao_pressure_to_altitude(log_mega->u.flight.ground_pres));
444 printf(" along %6d aross %6d through %6d",
445 log_mega->u.flight.ground_accel_along,
446 log_mega->u.flight.ground_accel_across,
447 log_mega->u.flight.ground_accel_through);
448 printf(" roll %6d pitch %6d yaw %6d",
449 log_mega->u.flight.ground_roll,
450 log_mega->u.flight.ground_pitch,
451 log_mega->u.flight.ground_yaw);
454 ao_state(log_mega->u.state.state,
455 log_mega->u.state.reason);
458 ao_ms5607(log_mega->u.sensor.pres,
459 log_mega->u.sensor.temp,
461 printf(" accel_x %6d accel_y %6d accel_z %6d",
462 log_mega->u.sensor.accel_x,
463 log_mega->u.sensor.accel_y,
464 log_mega->u.sensor.accel_z);
465 printf (" gyro_x %6d gyro_y %6d gyro_z %6d",
466 log_mega->u.sensor.gyro_x,
467 log_mega->u.sensor.gyro_y,
468 log_mega->u.sensor.gyro_z);
469 printf (" mag_x %6d mag_y %6d mag_z %6d",
470 log_mega->u.sensor.mag_x,
471 log_mega->u.sensor.mag_y,
472 log_mega->u.sensor.mag_z);
473 ao_accel(log_mega->u.sensor.accel, eeprom);
475 case AO_LOG_TEMP_VOLT:
477 log_mega->u.volt.v_batt,
482 log_mega->u.volt.v_pbatt,
486 printf(" n_sense %1d",
487 log_mega->u.volt.n_sense);
488 for (i = 0; i < log_mega->u.volt.n_sense; i++) {
490 sprintf(name, "sense%d", i);
492 log_mega->u.volt.sense[i],
497 printf(" pyro %04x", log_mega->u.volt.pyro);
499 case AO_LOG_GPS_TIME:
500 printf(" lat %10.7f ° lon %10.7f ° alt %8d m",
501 log_mega->u.gps.latitude / 10000000.0,
502 log_mega->u.gps.longitude/ 10000000.0,
503 (int32_t) (log_mega->u.gps.altitude_low |
504 (log_mega->u.gps.altitude_high << 16)));
505 printf(" time %02d:%02d:%02d %04d-%02d-%02d flags %02x",
506 log_mega->u.gps.hour,
507 log_mega->u.gps.minute,
508 log_mega->u.gps.second,
509 log_mega->u.gps.year + 2000,
510 log_mega->u.gps.month,
512 log_mega->u.gps.flags);
513 printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d",
514 log_mega->u.gps.course,
515 log_mega->u.gps.ground_speed,
516 log_mega->u.gps.climb_rate,
517 log_mega->u.gps.pdop,
518 log_mega->u.gps.hdop,
519 log_mega->u.gps.vdop,
520 log_mega->u.gps.mode);
523 printf(" channels %2d",
524 log_mega->u.gps_sat.channels);
525 for (i = 0; i < 12; i++) {
526 printf(" svid %3d c_n %2d",
527 log_mega->u.gps_sat.sats[i].svid,
528 log_mega->u.gps_sat.sats[i].c_n);
533 case AO_LOG_FORMAT_EASYMINI1:
534 case AO_LOG_FORMAT_EASYMINI2:
535 case AO_LOG_FORMAT_TELEMINI2:
536 case AO_LOG_FORMAT_TELEMINI3:
537 log_mini = (struct ao_log_mini *) &eeprom->data[pos];
538 switch (log_mini->type) {
540 printf(" serial %5u flight %5u ground_pres %9u kPa %7.1f %7.1f m",
541 eeprom->serial_number,
542 log_mini->u.flight.flight,
543 log_mini->u.flight.ground_pres,
544 log_mini->u.flight.ground_pres / 1000.0,
545 ao_pressure_to_altitude(log_mini->u.flight.ground_pres));
548 ao_state(log_mini->u.state.state,
549 log_mini->u.state.reason);
552 ao_ms5607(int24(log_mini->u.sensor.pres, 0),
553 int24(log_mini->u.sensor.temp, 0),
556 log_mini->u.sensor.sense_a, max_adc,
557 adc_ref, sense_r1, sense_r2);
559 log_mini->u.sensor.sense_m, max_adc,
560 adc_ref, sense_r1, sense_r2);
562 log_mini->u.sensor.v_batt, max_adc,
563 adc_ref, batt_r1, batt_r2);
567 case AO_LOG_FORMAT_TELEMETRUM:
568 log_metrum = (struct ao_log_metrum *) &eeprom->data[pos];
569 switch (log_metrum->type) {
571 printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u kPa %7.1f %7.1f m ground_temp %9u",
572 eeprom->serial_number,
573 log_metrum->u.flight.flight,
574 log_metrum->u.flight.ground_accel,
575 log_metrum->u.flight.ground_pres,
576 log_metrum->u.flight.ground_pres / 1000.0,
577 ao_pressure_to_altitude(log_metrum->u.flight.ground_pres),
578 log_metrum->u.flight.ground_temp);
581 ao_ms5607(log_metrum->u.sensor.pres,
582 log_metrum->u.sensor.temp,
584 ao_accel(log_metrum->u.sensor.accel, eeprom);
586 case AO_LOG_TEMP_VOLT:
588 log_metrum->u.volt.v_batt, max_adc,
589 adc_ref, batt_r1, batt_r2);
591 log_metrum->u.volt.sense_a, max_adc,
592 adc_ref, sense_r1, sense_r2);
594 log_metrum->u.volt.sense_m, max_adc,
595 adc_ref, sense_r1, sense_r2);
600 ao_state(log_metrum->u.state.state,
601 log_metrum->u.state.reason);
603 case AO_LOG_GPS_TIME:
604 printf(" time %02d:%02d:%02d 20%02d-%02d-%02d flags %02x pdop %3u",
605 log_metrum->u.gps_time.hour,
606 log_metrum->u.gps_time.minute,
607 log_metrum->u.gps_time.second,
608 log_metrum->u.gps_time.year,
609 log_metrum->u.gps_time.month,
610 log_metrum->u.gps_time.day,
611 log_metrum->u.gps_time.flags,
612 log_metrum->u.gps_time.pdop);
615 printf(" channels %2d more %1d",
616 log_metrum->u.gps_sat.channels,
617 log_metrum->u.gps_sat.more);
618 for (i = 0; i < 4; i++) {
619 printf(" svid %3d c_n %2d",
620 log_metrum->u.gps_sat.sats[i].svid,
621 log_metrum->u.gps_sat.sats[i].c_n);
625 printf(" lat %10.7f° lon %10.7f° alt %8d m",
626 log_metrum->u.gps.latitude / 10000000.0,
627 log_metrum->u.gps.longitude/ 10000000.0,
628 (int32_t) (log_metrum->u.gps.altitude_low |
629 (log_metrum->u.gps.altitude_high << 16)));
635 case AO_LOG_FORMAT_TELEFIRETWO:
636 log_firetwo = (struct ao_log_firetwo *) &eeprom->data[pos];
637 switch (log_firetwo->type) {
639 printf(" serial %5u flight %5u",
640 eeprom->serial_number,
641 log_firetwo->u.flight.flight);
644 ao_state(log_firetwo->u.state.state,
645 log_firetwo->u.state.reason);
648 ao_pressure(log_firetwo->u.sensor.pressure,
652 ao_thrust(log_firetwo->u.sensor.thrust,
655 for (i = 0; i < 4; i++) {
657 sprintf(name, "thermistor%d", i);
659 log_firetwo->u.sensor.thermistor[i],
666 case AO_LOG_FORMAT_TELEGPS:
667 log_gps = (struct ao_log_gps *) &eeprom->data[pos];
668 switch (log_gps->type) {
669 case AO_LOG_GPS_TIME:
670 printf(" lat %10.7f ° lon %10.7f ° alt %8d m",
671 log_gps->u.gps.latitude / 10000000.0,
672 log_gps->u.gps.longitude/ 10000000.0,
673 (int32_t) (log_gps->u.gps.altitude_low |
674 (log_gps->u.gps.altitude_high << 16)));
675 printf(" time %02d:%02d:%02d %04d-%02d-%02d flags %02x",
677 log_gps->u.gps.minute,
678 log_gps->u.gps.second,
679 log_gps->u.gps.year + 2000,
680 log_gps->u.gps.month,
682 log_gps->u.gps.flags);
683 printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d",
684 log_gps->u.gps.course,
685 log_gps->u.gps.ground_speed,
686 log_gps->u.gps.climb_rate,
690 log_gps->u.gps.mode);
693 printf(" channels %2d",
694 log_gps->u.gps_sat.channels);
695 for (i = 0; i < 12; i++) {
696 printf(" svid %3d c_n %2d",
697 log_gps->u.gps_sat.sats[i].svid,
698 log_gps->u.gps_sat.sats[i].c_n);
706 case AO_LOG_FORMAT_EASYMOTOR:
707 log_motor = (struct ao_log_motor *) &eeprom->data[pos];
708 switch (log_motor->type) {
710 printf(" serial %5u flight %5u ground_accel %6d",
711 eeprom->serial_number,
712 log_motor->u.flight.flight,
713 log_motor->u.flight.ground_accel);
714 printf(" along %6d aross %6d through %6d",
715 log_motor->u.flight.ground_accel_along,
716 log_motor->u.flight.ground_accel_across,
717 log_motor->u.flight.ground_accel_through);
718 ao_volts("ground pressure",
719 log_motor->u.flight.ground_motor_pressure,
724 ao_state(log_motor->u.state.state,
725 log_motor->u.state.reason);
729 log_motor->u.sensor.pressure,
733 log_motor->u.sensor.v_batt,
735 adc_ref, batt_r1, batt_r2);
737 log_motor->u.sensor.accel);
738 printf(" along %6d aross %6d through %6d",
739 log_motor->u.sensor.accel_along,
740 log_motor->u.sensor.accel_across,
741 log_motor->u.sensor.accel_through);
745 case AO_LOG_FORMAT_DETHERM: