ao-tools/ao-eeprom: Add altitude data for baro values
[fw/altos] / ao-tools / ao-eeprom / ao-eeprom.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <ao-eeprom-read.h>
25 #include <ao-atmosphere.h>
26
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' },
32         { 0, 0, 0, 0},
33 };
34
35 static void usage(char *program)
36 {
37         fprintf(stderr, "usage: %s [--raw] [--csum] [--verbose] [--len <record-len>] {flight.eeprom} ...\n", program);
38         exit(1);
39 }
40
41 static bool
42 ao_csum_valid(uint8_t *d, int len)
43 {
44         uint8_t sum = 0x5a;
45         int i;
46         for (i = 0; i < len; i++)
47                 sum += d[i];
48         return sum == 0;
49 }
50
51 static void
52 ao_ms5607(uint32_t pres, uint32_t temp, struct ao_eeprom *eeprom, bool is_ms5611)
53 {
54         struct ao_ms5607_sample ms5607_sample = { .pres = pres, .temp = temp };
55         struct ao_ms5607_value ms5607_value;
56
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)",
60                pres,
61                temp,
62                ms5607_value.pres / 1000.0,
63                ms5607_value.temp / 100.0,
64                ao_pressure_to_altitude(ms5607_value.pres));
65 }
66
67 #define GRAVITY 9.80665
68
69 static void
70 ao_accel(int16_t accel, struct ao_eeprom *eeprom)
71 {
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);
76 }
77
78 static const char *state_names[] = {
79         "startup",
80         "idle",
81         "pad",
82         "boost",
83         "fast",
84         "coast",
85         "drogue",
86         "main",
87         "landed",
88         "invalid"
89 };
90
91 #define NUM_STATE       (sizeof state_names/sizeof state_names[0])
92
93 static const char *
94 ao_state_name(uint16_t state)
95 {
96         if (state < NUM_STATE)
97                 return state_names[state];
98         return "UNKNOWN";
99 }
100
101 static void
102 ao_state(uint16_t state, uint16_t reason)
103 {
104         printf(" state %5u %s reason %5u",
105                state, ao_state_name(state), reason);
106 }
107
108 static void
109 ao_volts(const char *name, int16_t value, int16_t max_adc, double ref, double r1, double r2)
110 {
111         printf(" %s %5d",
112                name, value);
113         if (r1 && r2 && ref)
114                printf("(%6.3f V)",
115                       ref * ((double) value / max_adc) * (r1 + r2) / r2);
116 }
117
118 #if 0
119 static uint16_t
120 uint16(uint8_t *bytes, int off)
121 {
122         return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
123 }
124
125 static int16_t
126 int16(uint8_t *bytes, int off)
127 {
128         return (int16_t) uint16(bytes, off);
129 }
130
131 static uint32_t
132 uint32(uint8_t *bytes, int off)
133 {
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);
137 }
138
139 static int32_t
140 int32(uint8_t *bytes, int off)
141 {
142         return (int32_t) uint32(bytes, off);
143 }
144 #endif
145
146 static uint32_t
147 uint24(uint8_t *bytes, int off)
148 {
149         return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
150                 (((uint32_t) bytes[off+2]) << 16);
151 }
152
153 static int32_t
154 int24(uint8_t *bytes, int off)
155 {
156         return (int32_t) uint24(bytes, off);
157 }
158
159 int
160 main (int argc, char **argv)
161 {
162         struct ao_eeprom        *eeprom;
163         FILE                    *file;
164         int                     c;
165         bool                    raw = false;
166         bool                    csum = false;
167         bool                    verbose = false;
168         int                     arg_len = 0;
169         char                    *end;
170         int                     ret = 0;
171         int                     i;
172
173         while ((c = getopt_long(argc, argv, "rcvl:", options, NULL)) != -1) {
174                 switch (c) {
175                 case 'r':
176                         raw = true;
177                         break;
178                 case 'c':
179                         csum = true;
180                         break;
181                 case 'v':
182                         verbose = true;
183                         break;
184                 case 'l':
185                         arg_len = strtol(optarg, &end, 0);
186                         if (!*optarg || *end)
187                                 usage(argv[0]);
188                         break;
189                 default:
190                         usage(argv[0]);
191                         break;
192                 }
193         }
194         for (i = optind; i < argc; i++) {
195                 file = fopen(argv[i], "r");
196                 if (!file) {
197                         perror(argv[i]);
198                         ret++;
199                         continue;
200                 }
201                 eeprom = ao_eeprom_read(file);
202                 fclose(file);
203                 if (!eeprom) {
204                         perror(argv[i]);
205                         ret++;
206                         continue;
207                 }
208                 int     len = 0;
209                 bool    is_ms5611 = false;
210
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;
214                 int16_t max_adc = 0;
215
216                 switch (eeprom->log_format) {
217                 case AO_LOG_FORMAT_TELEMEGA_OLD:
218                         len = 32;
219                         break;
220                 case AO_LOG_FORMAT_EASYMINI1:
221                         len = 16;
222                         max_adc = 32767;
223                         if (eeprom->serial_number < 1000)
224                                 adc_ref = 3.0;
225                         else
226                                 adc_ref = 3.3;
227                         batt_r1 = sense_r1 = 100e3;
228                         batt_r2 = sense_r2 = 27e3;
229                         break;
230                 case AO_LOG_FORMAT_TELEMETRUM:
231                         len = 16;
232                         max_adc = 4095;
233                         adc_ref = 3.3;
234                         batt_r1 = 5600;
235                         batt_r2 = 10000;
236                         sense_r1 = 100e3;
237                         sense_r2 = 27e3;
238                         break;
239                 case AO_LOG_FORMAT_TELEMINI2:
240                         len = 16;
241                         break;
242                 case AO_LOG_FORMAT_TELEGPS:
243                         len = 32;
244                         break;
245                 case AO_LOG_FORMAT_TELEMEGA:
246                         len = 32;
247                         max_adc = 4095;
248                         adc_ref = 3.3;
249                         batt_r1 = 5600;
250                         batt_r2 = 10000;
251                         sense_r1 = 100e3;
252                         sense_r2 = 27e3;
253                         break;
254                 case AO_LOG_FORMAT_DETHERM:
255                         len = 16;
256                         break;
257                 case AO_LOG_FORMAT_TELEMINI3:
258                         len = 16;
259                         max_adc = 4095;
260                         adc_ref = 3.3;
261                         batt_r1 = 5600;
262                         batt_r2 = 10000;
263                         sense_r1 = 100e3;
264                         sense_r2 = 27e3;
265                         break;
266                 case AO_LOG_FORMAT_TELEFIRETWO:
267                         len = 32;
268                         break;
269                 case AO_LOG_FORMAT_EASYMINI2:
270                         len = 16;
271                         max_adc = 4095;
272                         adc_ref = 3.3;
273                         batt_r1 = sense_r1 = 100e3;
274                         batt_r2 = sense_r2 = 27e3;
275                         break;
276                 case AO_LOG_FORMAT_TELEMEGA_3:
277                         len = 32;
278                         max_adc = 4095;
279                         adc_ref = 3.3;
280                         batt_r1 = 5600;
281                         batt_r2 = 10000;
282                         sense_r1 = 100e3;
283                         sense_r2 = 27e3;
284                         break;
285                 case AO_LOG_FORMAT_EASYMEGA_2:
286                         len = 32;
287                         max_adc = 4095;
288                         adc_ref = 3.3;
289                         batt_r1 = 5600;
290                         batt_r2 = 10000;
291                         sense_r1 = 100e3;
292                         sense_r2 = 27e3;
293                         break;
294                 case AO_LOG_FORMAT_TELESTATIC:
295                         len = 32;
296                         break;
297                 case AO_LOG_FORMAT_MICROPEAK2:
298                         len = 2;
299                         break;
300                 }
301                 if (arg_len)
302                         len = arg_len;
303                 printf("config major %d minor %d log format %d total %u len %d\n",
304                        eeprom->config.major,
305                        eeprom->config.minor,
306                        eeprom->log_format,
307                        eeprom->len,
308                        len);
309                 uint32_t        pos;
310                 for (pos = 0; pos < eeprom->len; pos += len) {
311                         int i;
312                         if (raw) {
313                                 printf("%9u", pos);
314                                 for (i = 0; i < len; i++)
315                                         printf(" %02x", eeprom->data[pos + i]);
316                         } else {
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;
321
322                                 if (!csum && !ao_csum_valid(&eeprom->data[pos], len)) {
323                                         if (verbose)
324                                                 printf("\tchecksum error at %d\n", pos);
325                                         continue;
326                                 }
327
328                                 struct ao_log_header *log_header = (struct ao_log_header *) &eeprom->data[pos];
329
330                                 printf("type %c tick %5u", log_header->type, log_header->tick);
331
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) {
339                                         case AO_LOG_FLIGHT:
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);
353                                                 break;
354                                         case AO_LOG_STATE:
355                                                 ao_state(log_mega->u.state.state,
356                                                          log_mega->u.state.reason);
357                                                 break;
358                                         case AO_LOG_SENSOR:
359                                                 ao_ms5607(log_mega->u.sensor.pres,
360                                                           log_mega->u.sensor.temp,
361                                                           eeprom, is_ms5611);
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);
375                                                 break;
376                                         case AO_LOG_TEMP_VOLT:
377                                                 ao_volts("v_batt",
378                                                          log_mega->u.volt.v_batt,
379                                                          max_adc,
380                                                          adc_ref,
381                                                          batt_r1, batt_r2);
382                                                 ao_volts("v_pbatt",
383                                                          log_mega->u.volt.v_pbatt,
384                                                          max_adc,
385                                                          adc_ref,
386                                                          sense_r1, sense_r2);
387                                                 printf(" n_sense %1d",
388                                                        log_mega->u.volt.n_sense);
389                                                 for (i = 0; i < log_mega->u.volt.n_sense; i++) {
390                                                         char name[10];
391                                                         sprintf(name, "sense%d", i);
392                                                         ao_volts(name,
393                                                                  log_mega->u.volt.sense[i],
394                                                                  max_adc,
395                                                                  adc_ref,
396                                                                  sense_r1, sense_r2);
397                                                 }
398                                                 printf(" pyro %04x", log_mega->u.volt.pyro);
399                                                 break;
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,
412                                                        log_mega->u.gps.day,
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);
422                                                 break;
423                                         case AO_LOG_GPS_SAT:
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);
430                                                 }
431                                                 break;
432                                         }
433                                         break;
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) {
440                                         case AO_LOG_FLIGHT:
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);
445                                                 break;
446                                         case AO_LOG_STATE:
447                                                 ao_state(log_mini->u.state.state,
448                                                          log_mini->u.state.reason);
449                                                 break;
450                                         case AO_LOG_SENSOR:
451                                                 ao_ms5607(int24(log_mini->u.sensor.pres, 0),
452                                                           int24(log_mini->u.sensor.temp, 0),
453                                                           eeprom, is_ms5611);
454                                                 ao_volts("sense_a",
455                                                          log_mini->u.sensor.sense_a, max_adc,
456                                                          adc_ref, sense_r1, sense_r2);
457                                                 ao_volts("sense_m",
458                                                          log_mini->u.sensor.sense_m, max_adc,
459                                                          adc_ref, sense_r1, sense_r2);
460                                                 ao_volts("v_batt",
461                                                          log_mini->u.sensor.v_batt, max_adc,
462                                                          adc_ref, batt_r1, batt_r2);
463                                                 break;
464                                         } /*  */
465                                         break;
466                                 case AO_LOG_FORMAT_TELEMETRUM:
467                                         log_metrum = (struct ao_log_metrum *) &eeprom->data[pos];
468                                         switch (log_metrum->type) {
469                                         case AO_LOG_FLIGHT:
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);
476                                                 break;
477                                         case AO_LOG_SENSOR:
478                                                 ao_ms5607(log_metrum->u.sensor.pres,
479                                                           log_metrum->u.sensor.temp,
480                                                           eeprom, is_ms5611);
481                                                 ao_accel(log_metrum->u.sensor.accel, eeprom);
482                                                 break;
483                                         case AO_LOG_TEMP_VOLT:
484                                                 ao_volts("v_batt",
485                                                          log_metrum->u.volt.v_batt, max_adc,
486                                                          adc_ref, batt_r1, batt_r2);
487                                                 ao_volts("sense_a",
488                                                          log_metrum->u.volt.sense_a, max_adc,
489                                                          adc_ref, sense_r1, sense_r2);
490                                                 ao_volts("sense_m",
491                                                          log_metrum->u.volt.sense_m, max_adc,
492                                                          adc_ref, sense_r1, sense_r2);
493                                                 break;
494                                         case AO_LOG_DEPLOY:
495                                                 break;
496                                         case AO_LOG_STATE:
497                                                 ao_state(log_metrum->u.state.state,
498                                                          log_metrum->u.state.reason);
499                                                 break;
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);
510                                                 break;
511                                         case AO_LOG_GPS_SAT:
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);
519                                                 }
520                                                 break;
521                                         case AO_LOG_GPS_POS:
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)));
527                                                 break;
528                                         default:
529                                                 printf(" unknown");
530                                         }
531                                         break;
532                                 case AO_LOG_FORMAT_TELEGPS:
533                                         log_gps = (struct ao_log_gps *) &eeprom->data[pos];
534                                         (void) log_gps;
535                                         break;
536                                 case AO_LOG_FORMAT_DETHERM:
537                                         break;
538                                 }
539                         }
540                         printf("\n");
541                 }
542         }
543         return ret;
544 }