altos/test: Add fake flight creation tool
[fw/altos] / src / test / ao_make_fake.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 #define _GNU_SOURCE
20
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <getopt.h>
27 #include <math.h>
28
29 #define GRAVITY 9.80665
30
31 #define AO_HERTZ        100
32
33 #define HAS_ADC 1
34 #define AO_DATA_RING    64
35 #define ao_data_ring_next(n)    (((n) + 1) & (AO_DATA_RING - 1))
36 #define ao_data_ring_prev(n)    (((n) - 1) & (AO_DATA_RING - 1))
37
38 #define AO_GPS_NEW_DATA         1
39 #define AO_GPS_NEW_TRACKING     2
40
41 int ao_gps_new;
42
43 #if !defined(TELEMEGA) && !defined(TELEMETRUM_V2) && !defined(EASYMINI)
44 #define TELEMETRUM_V1 1
45 #endif
46
47 #if TELEMEGA
48 #define AO_ADC_NUM_SENSE        6
49 #define HAS_MS5607              1
50 #define HAS_MPU6000             1
51 #define HAS_MMA655X             1
52 #define HAS_HMC5883             1
53 #define HAS_BEEP                1
54 #define AO_CONFIG_MAX_SIZE      1024
55 #define AO_MMA655X_INVERT       0
56
57 struct ao_adc {
58         int16_t                 sense[AO_ADC_NUM_SENSE];
59         int16_t                 v_batt;
60         int16_t                 v_pbatt;
61         int16_t                 temp;
62 };
63 #endif
64
65 #if TELEMETRUM_V2
66 #define AO_ADC_NUM_SENSE        2
67 #define HAS_MS5607              1
68 #define HAS_MMA655X             1
69 #define AO_MMA655X_INVERT       0
70 #define HAS_BEEP                1
71 #define AO_CONFIG_MAX_SIZE      1024
72
73 struct ao_adc {
74         int16_t                 sense_a;
75         int16_t                 sense_m;
76         int16_t                 v_batt;
77         int16_t                 temp;
78 };
79 #endif
80
81 #if EASYMINI
82 #define AO_ADC_NUM_SENSE        2
83 #define HAS_MS5607              1
84 #define HAS_BEEP                1
85 #define AO_CONFIG_MAX_SIZE      1024
86
87 struct ao_adc {
88         int16_t                 sense_a;
89         int16_t                 sense_m;
90         int16_t                 v_batt;
91 };
92 #endif
93
94 #if TELEMETRUM_V1
95 /*
96  * One set of samples read from the A/D converter
97  */
98 struct ao_adc {
99         int16_t         accel;          /* accelerometer */
100         int16_t         pres;           /* pressure sensor */
101         int16_t         pres_real;      /* unclipped */
102         int16_t         temp;           /* temperature sensor */
103         int16_t         v_batt;         /* battery voltage */
104         int16_t         sense_d;        /* drogue continuity sense */
105         int16_t         sense_m;        /* main continuity sense */
106 };
107
108 #ifndef HAS_ACCEL
109 #define HAS_ACCEL 1
110 #define HAS_ACCEL_REF 0
111 #endif
112
113 #endif
114
115 #define __pdata
116 #define __data
117 #define __xdata
118 #define __code
119 #define __reentrant
120
121 #define HAS_FLIGHT 1
122 #define HAS_IGNITE 1
123 #define HAS_USB 1
124 #define HAS_GPS 1
125
126 #include <ao_data.h>
127 #include <ao_log.h>
128 #include <ao_telemetry.h>
129 #include <ao_sample.h>
130 #include <ao_fake_flight.h>
131
132 #if TELEMEGA
133 int ao_gps_count;
134 struct ao_telemetry_location ao_gps_first;
135 struct ao_telemetry_location ao_gps_prev;
136 struct ao_telemetry_location ao_gps_static;
137
138 struct ao_telemetry_satellite ao_gps_tracking;
139
140 static inline double sqr(double a) { return a * a; }
141
142 void
143 cc_great_circle (double start_lat, double start_lon,
144                  double end_lat, double end_lon,
145                  double *dist, double *bearing)
146 {
147         const double rad = M_PI / 180;
148         const double earth_radius = 6371.2 * 1000;      /* in meters */
149         double lat1 = rad * start_lat;
150         double lon1 = rad * -start_lon;
151         double lat2 = rad * end_lat;
152         double lon2 = rad * -end_lon;
153
154 //      double d_lat = lat2 - lat1;
155         double d_lon = lon2 - lon1;
156
157         /* From http://en.wikipedia.org/wiki/Great-circle_distance */
158         double vdn = sqrt(sqr(cos(lat2) * sin(d_lon)) +
159                           sqr(cos(lat1) * sin(lat2) -
160                               sin(lat1) * cos(lat2) * cos(d_lon)));
161         double vdd = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(d_lon);
162         double d = atan2(vdn,vdd);
163         double course;
164
165         if (cos(lat1) < 1e-20) {
166                 if (lat1 > 0)
167                         course = M_PI;
168                 else
169                         course = -M_PI;
170         } else {
171                 if (d < 1e-10)
172                         course = 0;
173                 else
174                         course = acos((sin(lat2)-sin(lat1)*cos(d)) /
175                                       (sin(d)*cos(lat1)));
176                 if (sin(lon2-lon1) > 0)
177                         course = 2 * M_PI-course;
178         }
179         *dist = d * earth_radius;
180         *bearing = course * 180/M_PI;
181 }
182
183 double
184 ao_distance_from_pad(void)
185 {
186         double  dist, bearing;
187         if (!ao_gps_count)
188                 return 0;
189
190         cc_great_circle(ao_gps_first.latitude / 1e7,
191                         ao_gps_first.longitude / 1e7,
192                         ao_gps_static.latitude / 1e7,
193                         ao_gps_static.longitude / 1e7,
194                         &dist, &bearing);
195         return dist;
196 }
197
198 double
199 ao_gps_angle(void)
200 {
201         double  dist, bearing;
202         double  height;
203         double  angle;
204
205         if (ao_gps_count < 2)
206                 return 0;
207
208         cc_great_circle(ao_gps_prev.latitude / 1e7,
209                         ao_gps_prev.longitude / 1e7,
210                         ao_gps_static.latitude / 1e7,
211                         ao_gps_static.longitude / 1e7,
212                         &dist, &bearing);
213         height = AO_TELEMETRY_LOCATION_ALTITUDE(&ao_gps_static) - AO_TELEMETRY_LOCATION_ALTITUDE(&ao_gps_prev);
214
215         angle = atan2(dist, height);
216         return angle * 180/M_PI;
217 }
218 #endif
219
220 #define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
221 #define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
222 #define from_fix(x)     ((x) >> 16)
223
224 #define ACCEL_NOSE_UP   (ao_accel_2g >> 2)
225
226 #define FALSE 0
227 #define TRUE 1
228
229 volatile struct ao_data ao_data_ring[AO_DATA_RING];
230 volatile uint8_t ao_data_head;
231 int     ao_summary = 0;
232
233 #define ao_led_on(l)
234 #define ao_led_off(l)
235 #define ao_timer_set_adc_interval(i)
236 #define ao_wakeup(wchan) ao_dump_state()
237 #define ao_cmd_register(c)
238 #define ao_usb_disable()
239 #define ao_telemetry_set_interval(x)
240 #define ao_rdf_set(rdf)
241 #define ao_packet_slave_start()
242 #define ao_packet_slave_stop()
243 #define flush()
244
245 enum ao_igniter {
246         ao_igniter_drogue = 0,
247         ao_igniter_main = 1
248 };
249
250 struct ao_data ao_data_static;
251
252 int     drogue_height;
253 double  drogue_time;
254 int     main_height;
255 double  main_time;
256
257 int     tick_offset;
258
259 static ao_k_t   ao_k_height;
260
261 int16_t
262 ao_time(void)
263 {
264         return ao_data_static.tick;
265 }
266
267 void
268 ao_delay(int16_t interval)
269 {
270         return;
271 }
272
273 void
274 ao_ignite(enum ao_igniter igniter)
275 {
276         double time = (double) (ao_data_static.tick + tick_offset) / 100;
277
278         if (igniter == ao_igniter_drogue) {
279                 drogue_time = time;
280                 drogue_height = ao_k_height >> 16;
281         } else {
282                 main_time = time;
283                 main_height = ao_k_height >> 16;
284         }
285 }
286
287 struct ao_task {
288         int dummy;
289 };
290
291 #define ao_add_task(t,f,n) ((void) (t))
292
293 #define ao_log_start()
294 #define ao_log_stop()
295
296 #define AO_MS_TO_TICKS(ms)      ((ms) / 10)
297 #define AO_SEC_TO_TICKS(s)      ((s) * 100)
298
299 #define AO_FLIGHT_TEST
300
301 int     ao_flight_debug;
302
303 struct ao_eeprom        *eeprom;
304 uint32_t                eeprom_offset;
305
306 FILE *emulator_in;
307 FILE *fake_out;
308 char *emulator_app;
309 char *emulator_name;
310 char *emulator_info;
311 double emulator_error_max = 4;
312 double emulator_height_error_max = 20;  /* noise in the baro sensor */
313
314 void
315 ao_dump_state(void);
316
317 void
318 ao_sleep(void *wchan);
319
320 const char * const ao_state_names[] = {
321         "startup", "idle", "pad", "boost", "fast",
322         "coast", "drogue", "main", "landed", "invalid"
323 };
324
325 struct ao_cmds {
326         void            (*func)(void);
327         const char      *help;
328 };
329
330 #define ao_xmemcpy(d,s,c) memcpy(d,s,c)
331 #define ao_xmemset(d,v,c) memset(d,v,c)
332 #define ao_xmemcmp(d,s,c) memcmp(d,s,c)
333
334 #define AO_NEED_ALTITUDE_TO_PRES 1
335 #if TELEMEGA || TELEMETRUM_V2 || EASYMINI
336 #include "ao_convert_pa.c"
337 #include <ao_ms5607.h>
338 struct ao_ms5607_prom   ao_ms5607_prom;
339 #include "ao_ms5607_convert.c"
340 #if TELEMEGA
341 #define AO_PYRO_NUM     4
342 #include <ao_pyro.h>
343 #endif
344 #else
345 #include "ao_convert.c"
346 #endif
347
348 #include <ao_config.h>
349 #include <ao_fake_flight.h>
350 #include <ao_eeprom_read.h>
351 #include <ao_log.h>
352
353 #define ao_config_get()
354
355 struct ao_config ao_config;
356
357 #define DATA_TO_XDATA(x) (x)
358
359
360 extern int16_t ao_ground_accel, ao_flight_accel;
361 extern int16_t ao_accel_2g;
362
363 typedef int16_t accel_t;
364
365 uint16_t        ao_serial_number;
366 uint16_t        ao_flight_number;
367
368 extern uint16_t ao_sample_tick;
369
370 extern alt_t    ao_sample_height;
371 extern accel_t  ao_sample_accel;
372 extern int32_t  ao_accel_scale;
373 extern alt_t    ao_ground_height;
374 extern alt_t    ao_sample_alt;
375
376 double ao_sample_qangle;
377
378 int ao_sample_prev_tick;
379 uint16_t        prev_tick;
380
381 #include "ao_kalman.c"
382 #include "ao_sqrt.c"
383 #include "ao_sample.c"
384 #include "ao_flight.c"
385 #if TELEMEGA
386 #define AO_PYRO_NUM     4
387
388 #define AO_PYRO_0       0
389 #define AO_PYRO_1       1
390 #define AO_PYRO_2       2
391 #define AO_PYRO_3       3
392
393 #define PYRO_DBG        1
394 #endif
395 #include "ao_eeprom_read.c"
396 #include "ao_eeprom_read_old.c"
397
398 #define to_double(f)    ((f) / 65536.0)
399
400 static int      ao_records_read = 0;
401 static int      ao_eof_read = 0;
402 #if !EASYMINI
403 static int      ao_flight_ground_accel;
404 #endif
405 static int      ao_flight_started = 0;
406
407 #if HAS_MPU6000
408 static struct ao_mpu6000_sample ao_ground_mpu6000;
409 #endif
410
411 #if HAS_ACCEL
412 int ao_error_h_sq_avg;
413 #endif
414
415 void
416 ao_test_exit(void)
417 {
418         putc(0, fake_out);
419         fflush(fake_out);
420         exit(0);
421 }
422
423 void
424 ao_insert(void)
425 {
426         putc(1, fake_out);
427         fwrite(&ao_data_static, sizeof (ao_data_static), 1, fake_out);
428 }
429
430
431 uint16_t
432 uint16(uint8_t *bytes, int off)
433 {
434         return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
435 }
436
437 int16_t
438 int16(uint8_t *bytes, int off)
439 {
440         return (int16_t) uint16(bytes, off);
441 }
442
443 uint32_t
444 uint32(uint8_t *bytes, int off)
445 {
446         return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
447                 (((uint32_t) bytes[off+2]) << 16) |
448                 (((uint32_t) bytes[off+3]) << 24);
449 }
450
451 int32_t
452 int32(uint8_t *bytes, int off)
453 {
454         return (int32_t) uint32(bytes, off);
455 }
456
457 uint32_t
458 uint24(uint8_t *bytes, int off)
459 {
460         return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
461                 (((uint32_t) bytes[off+2]) << 16);
462 }
463
464 int32_t
465 int24(uint8_t *bytes, int off)
466 {
467         return (int32_t) uint24(bytes, off);
468 }
469
470 static int log_format;
471
472 void
473 ao_sleep(void *wchan)
474 {
475 }
476
477 void fake_read(void)
478 {
479         if (ao_records_read > 2 && ao_records_read < 500)
480         {
481 #if TELEMEGA
482                 ao_data_static.mpu6000 = ao_ground_mpu6000;
483 #endif
484 #if TELEMETRUM_V1
485                 ao_data_static.adc.accel = ao_flight_ground_accel;
486 #endif
487                 ++ao_records_read;
488                 ao_insert();
489                 return;
490         }
491
492         if (eeprom) {
493 #if TELEMEGA
494                 struct ao_log_mega      *log_mega;
495 #endif
496 #if TELEMETRUM_V2
497                 struct ao_log_metrum    *log_metrum;
498 #endif
499 #if EASYMINI
500                 struct ao_log_mini      *log_mini;
501 #endif
502 #if TELEMETRUM_V1
503                 struct ao_log_record    *log_record;
504 #endif
505
506                 if (eeprom_offset >= eeprom->len) {
507                         if (++ao_eof_read >= 100) {
508                                 ao_test_exit();
509                         }
510                         ao_data_static.tick += 10;
511                         ao_insert();
512                         return;
513                 }
514                 switch (eeprom->log_format) {
515 #if TELEMEGA
516                 case AO_LOG_FORMAT_TELEMEGA_OLD:
517                 case AO_LOG_FORMAT_TELEMEGA:
518                         log_mega = (struct ao_log_mega *) &eeprom->data[eeprom_offset];
519                         eeprom_offset += sizeof (*log_mega);
520                         switch (log_mega->type) {
521                         case AO_LOG_FLIGHT:
522                                 ao_flight_number = log_mega->u.flight.flight;
523                                 ao_flight_ground_accel = log_mega->u.flight.ground_accel;
524                                 ao_flight_started = 1;
525                                 ao_ground_pres = log_mega->u.flight.ground_pres;
526                                 ao_ground_height = ao_pa_to_altitude(ao_ground_pres);
527                                 ao_ground_accel_along = log_mega->u.flight.ground_accel_along;
528                                 ao_ground_accel_across = log_mega->u.flight.ground_accel_across;
529                                 ao_ground_accel_through = log_mega->u.flight.ground_accel_through;
530                                 ao_ground_roll = log_mega->u.flight.ground_roll;
531                                 ao_ground_pitch = log_mega->u.flight.ground_pitch;
532                                 ao_ground_yaw = log_mega->u.flight.ground_yaw;
533                                 ao_ground_mpu6000.accel_x = ao_ground_accel_across;
534                                 ao_ground_mpu6000.accel_y = ao_ground_accel_along;
535                                 ao_ground_mpu6000.accel_z = ao_ground_accel_through;
536                                 ao_ground_mpu6000.gyro_x = ao_ground_pitch >> 9;
537                                 ao_ground_mpu6000.gyro_y = ao_ground_roll >> 9;
538                                 ao_ground_mpu6000.gyro_z = ao_ground_yaw >> 9;
539                                 break;
540                         case AO_LOG_STATE:
541                                 break;
542                         case AO_LOG_SENSOR:
543                                 ao_data_static.tick = log_mega->tick;
544                                 ao_data_static.ms5607_raw.pres = log_mega->u.sensor.pres;
545                                 ao_data_static.ms5607_raw.temp = log_mega->u.sensor.temp;
546                                 ao_data_static.mpu6000.accel_x = log_mega->u.sensor.accel_x;
547                                 ao_data_static.mpu6000.accel_y = log_mega->u.sensor.accel_y;
548                                 ao_data_static.mpu6000.accel_z = log_mega->u.sensor.accel_z;
549                                 ao_data_static.mpu6000.gyro_x = log_mega->u.sensor.gyro_x;
550                                 ao_data_static.mpu6000.gyro_y = log_mega->u.sensor.gyro_y;
551                                 ao_data_static.mpu6000.gyro_z = log_mega->u.sensor.gyro_z;
552                                 ao_data_static.hmc5883.x = log_mega->u.sensor.mag_x;
553                                 ao_data_static.hmc5883.y = log_mega->u.sensor.mag_y;
554                                 ao_data_static.hmc5883.z = log_mega->u.sensor.mag_z;
555                                 ao_data_static.mma655x = log_mega->u.sensor.accel;
556                                 if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
557                                         ao_data_static.mma655x = ao_data_accel_invert(ao_data_static.mma655x);
558                                 ao_records_read++;
559                                 ao_insert();
560                                 return;
561                         case AO_LOG_TEMP_VOLT:
562                                 break;
563                         case AO_LOG_GPS_TIME:
564                                 ao_gps_prev = ao_gps_static;
565                                 ao_gps_static.tick = log_mega->tick;
566                                 ao_gps_static.latitude = log_mega->u.gps.latitude;
567                                 ao_gps_static.longitude = log_mega->u.gps.longitude;
568                                 {
569                                         int16_t altitude_low = log_mega->u.gps.altitude_low;
570                                         int16_t altitude_high = log_mega->u.gps.altitude_high;
571                                         int32_t altitude = altitude_low | ((int32_t) altitude_high << 16);
572
573                                         AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_static, altitude);
574                                 }
575                                 ao_gps_static.flags = log_mega->u.gps.flags;
576                                 if (!ao_gps_count)
577                                         ao_gps_first = ao_gps_static;
578                                 ao_gps_count++;
579                                 break;
580                         case AO_LOG_GPS_SAT:
581                                 break;
582                         }
583                         break;
584 #endif
585 #if TELEMETRUM_V2
586                 case AO_LOG_FORMAT_TELEMETRUM:
587                         log_metrum = (struct ao_log_metrum *) &eeprom->data[eeprom_offset];
588                         eeprom_offset += sizeof (*log_metrum);
589                         switch (log_metrum->type) {
590                         case AO_LOG_FLIGHT:
591                                 ao_flight_started = 1;
592                                 ao_flight_number = log_metrum->u.flight.flight;
593                                 ao_flight_ground_accel = log_metrum->u.flight.ground_accel;
594                                 ao_ground_pres = log_metrum->u.flight.ground_pres;
595                                 ao_ground_height = ao_pa_to_altitude(ao_ground_pres);
596                                 break;
597                         case AO_LOG_SENSOR:
598                                 ao_data_static.tick = log_metrum->tick;
599                                 ao_data_static.ms5607_raw.pres = log_metrum->u.sensor.pres;
600                                 ao_data_static.ms5607_raw.temp = log_metrum->u.sensor.temp;
601                                 ao_data_static.mma655x = log_metrum->u.sensor.accel;
602                                 ao_records_read++;
603                                 ao_insert();
604                                 return;
605                         }
606                         break;
607 #endif
608 #if EASYMINI
609                 case AO_LOG_FORMAT_EASYMINI1:
610                 case AO_LOG_FORMAT_EASYMINI2:
611                 case AO_LOG_FORMAT_TELEMINI3:
612                         log_mini = (struct ao_log_mini *) &eeprom->data[eeprom_offset];
613                         eeprom_offset += sizeof (*log_mini);
614                         switch (log_mini->type) {
615                         case AO_LOG_FLIGHT:
616                                 ao_flight_started = 1;
617                                 ao_flight_number = log_mini->u.flight.flight;
618                                 ao_ground_pres = log_mini->u.flight.ground_pres;
619                                 ao_ground_height = ao_pa_to_altitude(ao_ground_pres);
620                                 break;
621                         case AO_LOG_SENSOR:
622                                 ao_data_static.tick = log_mini->tick;
623                                 ao_data_static.ms5607_raw.pres = int24(log_mini->u.sensor.pres, 0);
624                                 ao_data_static.ms5607_raw.temp = int24(log_mini->u.sensor.temp, 0);
625                                 ao_records_read++;
626                                 ao_insert();
627                                 return;
628                         }
629                         break;
630 #endif
631 #if TELEMETRUM_V1
632                 case AO_LOG_FORMAT_FULL:
633                 case AO_LOG_FORMAT_TINY:
634                         log_record = (struct ao_log_record *) &eeprom->data[eeprom_offset];
635                         eeprom_offset += sizeof (*log_record);
636                         switch (log_record->type) {
637                         case AO_LOG_FLIGHT:
638                                 ao_flight_started = 1;
639                                 ao_flight_ground_accel = log_record->u.flight.ground_accel;
640                                 ao_flight_number = log_record->u.flight.flight;
641                                 break;
642                         case AO_LOG_SENSOR:
643                         case 'P':       /* ancient telemini */
644                                 ao_data_static.tick = log_record->tick;
645                                 ao_data_static.adc.accel = log_record->u.sensor.accel;
646                                 ao_data_static.adc.pres_real = log_record->u.sensor.pres;
647                                 ao_data_static.adc.pres = log_record->u.sensor.pres;
648                                 ao_records_read++;
649                                 ao_insert();
650                                 return;
651                         case AO_LOG_TEMP_VOLT:
652                                 ao_data_static.tick = log_record->tick;;
653                                 ao_data_static.adc.temp = log_record->u.temp_volt.temp;
654                                 ao_data_static.adc.v_batt = log_record->u.temp_volt.v_batt;
655                                 break;
656                         }
657                         break;
658 #endif
659                 default:
660                         fprintf (stderr, "invalid log format %d\n", log_format);
661                         ao_test_exit();
662                 }
663         }
664 }
665 #define COUNTS_PER_G 264.8
666
667 void
668 ao_dump_state(void)
669 {
670 }
671
672 static const struct option options[] = {
673         { .name = "summary", .has_arg = 0, .val = 's' },
674         { .name = "debug", .has_arg = 0, .val = 'd' },
675         { .name = "info", .has_arg = 1, .val = 'i' },
676         { .name = "out", .has_arg = 1, .val = 'o' },
677         { 0, 0, 0, 0},
678 };
679
680 void run_flight_fixed(char *name, FILE *f, int summary, char *info)
681 {
682         char                    c;
683         struct ao_fake_calib    fake_calib;
684
685         emulator_name = name;
686         emulator_in = f;
687         emulator_info = info;
688         ao_summary = summary;
689
690         c = getc(f);
691         ungetc(c, f);
692         if (c == '{')
693                 eeprom = ao_eeprom_read(f);
694         else
695                 eeprom = ao_eeprom_read_old(f);
696
697         if (!eeprom) {
698                 fprintf(stderr, "%s: load failed\n", name);
699                 exit(1);
700         }
701 #if HAS_MS5607
702         ao_ms5607_prom = eeprom->ms5607_prom;
703 #endif
704         ao_config = eeprom->config;
705         ao_serial_number = eeprom->serial_number;
706         log_format = eeprom->log_format;
707
708         fprintf(fake_out, "F %x %x\n",
709                (int) sizeof (struct ao_fake_calib),
710                (int) sizeof (struct ao_data));
711
712         fake_calib.major = AO_FAKE_CALIB_MAJOR;
713         fake_calib.minor = AO_FAKE_CALIB_MINOR;
714         fake_calib.accel_plus_g = eeprom->config.accel_plus_g;
715         fake_calib.accel_minus_g = eeprom->config.accel_minus_g;
716         fake_calib.accel_zero_along = eeprom->config.accel_zero_along;
717         fake_calib.accel_zero_across = eeprom->config.accel_zero_across;
718         fake_calib.accel_zero_through = eeprom->config.accel_zero_through;
719         fake_calib.ms5607_prom = eeprom->ms5607_prom;
720         fwrite(&fake_calib, sizeof (fake_calib), 1, fake_out);
721         for (;;)
722                 fake_read();
723 }
724
725 int
726 main (int argc, char **argv)
727 {
728         int     summary = 0;
729         int     c;
730         int     i;
731         char    *info = NULL;
732         char    *out_name = NULL;
733
734 #if HAS_ACCEL
735         emulator_app="full";
736 #else
737         emulator_app="baro";
738 #endif
739         while ((c = getopt_long(argc, argv, "sdi:o:", options, NULL)) != -1) {
740                 switch (c) {
741                 case 's':
742                         summary = 1;
743                         break;
744                 case 'd':
745                         ao_flight_debug = 1;
746                         break;
747                 case 'i':
748                         info = optarg;
749                         break;
750                 case 'o':
751                         out_name = optarg;
752                         break;
753                 }
754         }
755         if (out_name) {
756                 fake_out = fopen(out_name, "w");
757                 if (!fake_out) {
758                         perror(out_name);
759                         exit(1);
760                 }
761         }
762
763         if (!fake_out)
764                 fake_out = stdout;
765
766         if (optind == argc)
767                 run_flight_fixed("<stdin>", stdin, summary, info);
768         else
769                 for (i = optind; i < argc; i++) {
770                         FILE    *f = fopen(argv[i], "r");
771                         if (!f) {
772                                 perror(argv[i]);
773                                 continue;
774                         }
775                         run_flight_fixed(argv[i], f, summary, info);
776                         fclose(f);
777                 }
778         exit(0);
779 }