altos/test: Get test code working again after restructuring
[fw/altos] / src / test / ao_flight_test.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 #define log ao_log_data
29
30 #define GRAVITY 9.80665
31
32 #define AO_HERTZ        100
33
34 #define HAS_ADC 1
35 #define AO_DATA_RING    64
36 #define ao_data_ring_next(n)    (((n) + 1) & (AO_DATA_RING - 1))
37 #define ao_data_ring_prev(n)    (((n) - 1) & (AO_DATA_RING - 1))
38
39 #if 0
40 #define AO_M_TO_HEIGHT(m)       ((int16_t) (m))
41 #define AO_MS_TO_SPEED(ms)      ((int16_t) ((ms) * 16))
42 #define AO_MSS_TO_ACCEL(mss)    ((int16_t) ((mss) * 16))
43 #endif
44
45 #define AO_GPS_NEW_DATA         1
46 #define AO_GPS_NEW_TRACKING     2
47
48 int ao_gps_new;
49
50 #if !defined(TELEMEGA) && !defined(TELEMETRUM_V2) && !defined(EASYMINI)
51 #define TELEMETRUM_V1 1
52 #endif
53
54 #if TELEMEGA
55 #define AO_ADC_NUM_SENSE        6
56 #define HAS_MS5607              1
57 #define HAS_MPU6000             1
58 #define HAS_MMA655X             1
59 #define HAS_HMC5883             1
60 #define HAS_BEEP                1
61 #define AO_CONFIG_MAX_SIZE      1024
62 #define AO_MMA655X_INVERT       0
63
64 struct ao_adc {
65         int16_t                 sense[AO_ADC_NUM_SENSE];
66         int16_t                 v_batt;
67         int16_t                 v_pbatt;
68         int16_t                 temp;
69 };
70 #endif
71
72 #if TELEMETRUM_V2
73 #define AO_ADC_NUM_SENSE        2
74 #define HAS_MS5607              1
75 #define HAS_MMA655X             1
76 #define AO_MMA655X_INVERT       0
77 #define HAS_BEEP                1
78 #define AO_CONFIG_MAX_SIZE      1024
79
80 struct ao_adc {
81         int16_t                 sense_a;
82         int16_t                 sense_m;
83         int16_t                 v_batt;
84         int16_t                 temp;
85 };
86 #endif
87
88 #if EASYMINI
89 #define AO_ADC_NUM_SENSE        2
90 #define HAS_MS5607              1
91 #define HAS_BEEP                1
92 #define AO_CONFIG_MAX_SIZE      1024
93
94 struct ao_adc {
95         int16_t                 sense_a;
96         int16_t                 sense_m;
97         int16_t                 v_batt;
98 };
99 #endif
100
101 #if TELEMETRUM_V1
102 /*
103  * One set of samples read from the A/D converter
104  */
105 struct ao_adc {
106         int16_t         accel;          /* accelerometer */
107         int16_t         pres;           /* pressure sensor */
108         int16_t         pres_real;      /* unclipped */
109         int16_t         temp;           /* temperature sensor */
110         int16_t         v_batt;         /* battery voltage */
111         int16_t         sense_d;        /* drogue continuity sense */
112         int16_t         sense_m;        /* main continuity sense */
113 };
114
115 #ifndef HAS_ACCEL
116 #define HAS_ACCEL 1
117 #define HAS_ACCEL_REF 0
118 #endif
119
120 #endif
121
122 #define const
123
124 #define HAS_FLIGHT 1
125 #define HAS_IGNITE 1
126 #define HAS_USB 1
127 #define HAS_GPS 1
128
129 int16_t
130 ao_time(void);
131
132 void
133 ao_dump_state(void);
134
135 #define ao_tick_count   (ao_time())
136 #define ao_wakeup(wchan) ao_dump_state()
137
138 #include <ao_data.h>
139 #include <ao_log.h>
140 #include <ao_telemetry.h>
141 #include <ao_sample.h>
142
143 #if TELEMEGA
144 int ao_gps_count;
145 struct ao_telemetry_location ao_gps_first;
146 struct ao_telemetry_location ao_gps_prev;
147 struct ao_telemetry_location ao_gps_static;
148
149 struct ao_telemetry_satellite ao_gps_tracking;
150
151 static inline double sqr(double a) { return a * a; }
152
153 void
154 cc_great_circle (double start_lat, double start_lon,
155                  double end_lat, double end_lon,
156                  double *dist, double *bearing)
157 {
158         const double rad = M_PI / 180;
159         const double earth_radius = 6371.2 * 1000;      /* in meters */
160         double lat1 = rad * start_lat;
161         double lon1 = rad * -start_lon;
162         double lat2 = rad * end_lat;
163         double lon2 = rad * -end_lon;
164
165 //      double d_lat = lat2 - lat1;
166         double d_lon = lon2 - lon1;
167
168         /* From http://en.wikipedia.org/wiki/Great-circle_distance */
169         double vdn = sqrt(sqr(cos(lat2) * sin(d_lon)) +
170                           sqr(cos(lat1) * sin(lat2) -
171                               sin(lat1) * cos(lat2) * cos(d_lon)));
172         double vdd = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(d_lon);
173         double d = atan2(vdn,vdd);
174         double course;
175
176         if (cos(lat1) < 1e-20) {
177                 if (lat1 > 0)
178                         course = M_PI;
179                 else
180                         course = -M_PI;
181         } else {
182                 if (d < 1e-10)
183                         course = 0;
184                 else
185                         course = acos((sin(lat2)-sin(lat1)*cos(d)) /
186                                       (sin(d)*cos(lat1)));
187                 if (sin(lon2-lon1) > 0)
188                         course = 2 * M_PI-course;
189         }
190         *dist = d * earth_radius;
191         *bearing = course * 180/M_PI;
192 }
193
194 double
195 ao_distance_from_pad(void)
196 {
197         double  dist, bearing;
198         if (!ao_gps_count)
199                 return 0;
200
201         cc_great_circle(ao_gps_first.latitude / 1e7,
202                         ao_gps_first.longitude / 1e7,
203                         ao_gps_static.latitude / 1e7,
204                         ao_gps_static.longitude / 1e7,
205                         &dist, &bearing);
206         return dist;
207 }
208
209 double
210 ao_gps_angle(void)
211 {
212         double  dist, bearing;
213         double  height;
214         double  angle;
215
216         if (ao_gps_count < 2)
217                 return 0;
218
219         cc_great_circle(ao_gps_prev.latitude / 1e7,
220                         ao_gps_prev.longitude / 1e7,
221                         ao_gps_static.latitude / 1e7,
222                         ao_gps_static.longitude / 1e7,
223                         &dist, &bearing);
224         height = AO_TELEMETRY_LOCATION_ALTITUDE(&ao_gps_static) - AO_TELEMETRY_LOCATION_ALTITUDE(&ao_gps_prev);
225
226         angle = atan2(dist, height);
227         return angle * 180/M_PI;
228 }
229 #endif
230
231 #define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
232 #define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
233 #define from_fix(x)     ((x) >> 16)
234
235 #define ACCEL_NOSE_UP   (ao_accel_2g >> 2)
236
237 extern enum ao_flight_state ao_flight_state;
238
239 #define false 0
240 #define true 1
241
242 volatile struct ao_data ao_data_ring[AO_DATA_RING];
243 volatile uint8_t ao_data_head;
244 int     ao_summary = 0;
245
246 #define ao_led_on(l)
247 #define ao_led_off(l)
248 #define ao_timer_set_adc_interval(i)
249 #define ao_cmd_register(c)
250 #define ao_usb_disable()
251 #define ao_telemetry_set_interval(x)
252 #define ao_rdf_set(rdf)
253 #define ao_packet_slave_start()
254 #define ao_packet_slave_stop()
255 #define flush()
256
257 enum ao_igniter {
258         ao_igniter_drogue = 0,
259         ao_igniter_main = 1
260 };
261
262 struct ao_data ao_data_static;
263
264 int     drogue_height;
265 double  drogue_time;
266 int     main_height;
267 double  main_time;
268
269 int     tick_offset;
270
271 static ao_k_t   ao_k_height;
272 static double   simple_speed;
273
274 int16_t
275 ao_time(void)
276 {
277         return ao_data_static.tick;
278 }
279
280 void
281 ao_delay(int16_t interval)
282 {
283         return;
284 }
285
286 void
287 ao_ignite(enum ao_igniter igniter)
288 {
289         double time = (double) (ao_data_static.tick + tick_offset) / 100;
290
291         if (igniter == ao_igniter_drogue) {
292                 drogue_time = time;
293                 drogue_height = ao_k_height >> 16;
294         } else {
295                 main_time = time;
296                 main_height = ao_k_height >> 16;
297         }
298 }
299
300 struct ao_task {
301         int dummy;
302 };
303
304 #define ao_add_task(t,f,n) ((void) (t))
305
306 #define ao_log_start()
307 #define ao_log_stop()
308
309 #define AO_MS_TO_TICKS(ms)      ((ms) / 10)
310 #define AO_SEC_TO_TICKS(s)      ((s) * 100)
311
312 #define AO_FLIGHT_TEST  1
313
314 int     ao_flight_debug;
315
316 struct ao_eeprom        *eeprom;
317 uint32_t                eeprom_offset;
318
319 FILE *emulator_in;
320 char *emulator_app;
321 char *emulator_name;
322 char *emulator_info;
323 double emulator_error_max = 4;
324 double emulator_height_error_max = 20;  /* noise in the baro sensor */
325
326 void
327 ao_sleep(void *wchan);
328
329 const char * const ao_state_names[] = {
330         "startup", "idle", "pad", "boost", "fast",
331         "coast", "drogue", "main", "landed", "invalid"
332 };
333
334 struct ao_cmds {
335         void            (*func)(void);
336         const char      *help;
337 };
338
339 #define AO_NEED_ALTITUDE_TO_PRES 1
340 #if TELEMEGA || TELEMETRUM_V2 || EASYMINI
341 #include "ao_convert_pa.c"
342 #include <ao_ms5607.h>
343 struct ao_ms5607_prom   ao_ms5607_prom;
344 #include "ao_ms5607_convert.c"
345 #if TELEMEGA
346 #define AO_PYRO_NUM     4
347 #include <ao_pyro.h>
348 #endif
349 #else
350 #include "ao_convert.c"
351 #endif
352
353 #include <ao_config.h>
354 #include <ao_fake_flight.h>
355 #include <ao_eeprom_read.h>
356 #include <ao_log.h>
357
358 #define ao_config_get()
359
360 struct ao_config ao_config;
361
362 extern int16_t ao_ground_accel, ao_flight_accel;
363 extern int16_t ao_accel_2g;
364
365 typedef int16_t accel_t;
366
367 uint16_t        ao_serial_number;
368 int16_t         ao_flight_number;
369
370 extern uint16_t ao_sample_tick;
371
372 extern alt_t    ao_sample_height;
373 extern accel_t  ao_sample_accel;
374 extern int32_t  ao_accel_scale;
375 extern alt_t    ao_ground_height;
376 extern alt_t    ao_sample_alt;
377
378 double ao_sample_qangle;
379
380 int ao_sample_prev_tick;
381 uint16_t        prev_tick;
382
383
384 #include "ao_kalman.c"
385 #include "ao_sqrt.c"
386 #include "ao_sample.c"
387 #include "ao_flight.c"
388 #if TELEMEGA
389 #define AO_PYRO_NUM     4
390
391 #define AO_PYRO_0       0
392 #define AO_PYRO_1       1
393 #define AO_PYRO_2       2
394 #define AO_PYRO_3       3
395
396 #define PYRO_DBG        1
397
398 static void
399 ao_pyro_pin_set(uint8_t pin, uint8_t value)
400 {
401         printf ("set pyro %d %d\n", pin, value);
402 }
403
404 #include "ao_pyro.c"
405 #endif
406 #include "ao_eeprom_read.c"
407 #include "ao_eeprom_read_old.c"
408
409 #define to_double(f)    ((f) / 65536.0)
410
411 static int      ao_records_read = 0;
412 static int      ao_eof_read = 0;
413 #if !EASYMINI
414 static int      ao_flight_ground_accel;
415 #endif
416 static int      ao_flight_started = 0;
417 static int      ao_test_max_height;
418 static double   ao_test_max_height_time;
419 static int      ao_test_main_height;
420 static double   ao_test_main_height_time;
421 static double   ao_test_landed_time;
422 static double   ao_test_landed_height;
423 static double   ao_test_landed_time;
424 static int      landed_set;
425 static double   landed_time;
426 static double   landed_height;
427 #if AO_PYRO_NUM
428 static uint16_t pyros_fired;
429 #endif
430
431 #if HAS_MPU6000
432 static struct ao_mpu6000_sample ao_ground_mpu6000;
433 #endif
434
435 void
436 ao_test_exit(void)
437 {
438         double  drogue_error;
439         double  main_error;
440         double  landed_error;
441         double  landed_time_error;
442
443         if (!ao_test_main_height_time) {
444                 ao_test_main_height_time = ao_test_max_height_time;
445                 ao_test_main_height = ao_test_max_height;
446         }
447         drogue_error = fabs(ao_test_max_height_time - drogue_time);
448         main_error = fabs(ao_test_main_height_time - main_time);
449         landed_error = fabs(ao_test_landed_height - landed_height);
450         landed_time_error = ao_test_landed_time - landed_time;
451         if (drogue_error > emulator_error_max || main_error > emulator_error_max) {
452                 printf ("%s %s\n",
453                         emulator_app, emulator_name);
454                 if (emulator_info)
455                         printf ("\t%s\n", emulator_info);
456                 printf ("\tApogee error %g\n", drogue_error);
457                 printf ("\tMain error %g\n", main_error);
458                 printf ("\tLanded height error %g\n", landed_error);
459                 printf ("\tLanded time error %g\n", landed_time_error);
460                 printf ("\tActual: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n",
461                         ao_test_max_height, ao_test_max_height_time,
462                         ao_test_main_height, ao_test_main_height_time,
463                         ao_test_landed_height, ao_test_landed_time);
464                 printf ("\tComputed: apogee: %d at %7.2f main: %d at %7.2f landed %7.2f at %7.2f\n",
465                         drogue_height, drogue_time, main_height, main_time,
466                         landed_height, landed_time);
467                 exit (1);
468         }
469         exit(0);
470 }
471
472 #ifdef TELEMEGA
473 struct ao_azel {
474         int     az;
475         int     el;
476 };
477
478 static void
479 azel (struct ao_azel *r, struct ao_quaternion *q)
480 {
481         double  v;
482
483         r->az = floor (atan2(q->y, q->x) * 180/M_PI + 0.5);
484         v = sqrt (q->x*q->x + q->y*q->y);
485         r->el = floor (atan2(q->z, v) * 180/M_PI + 0.5);
486 }
487 #endif
488
489 void
490 ao_insert(void)
491 {
492         double  time;
493
494         ao_data_ring[ao_data_head] = ao_data_static;
495         if (ao_flight_state != ao_flight_startup) {
496 #if HAS_ACCEL
497                 double  accel = ((ao_flight_ground_accel - ao_data_accel(&ao_data_static)) * GRAVITY * 2.0) /
498                         (ao_config.accel_minus_g - ao_config.accel_plus_g);
499 #else
500                 double  accel = 0.0;
501 #endif
502
503                 (void) accel;
504                 if (!tick_offset)
505                         tick_offset = -ao_data_static.tick;
506                 if ((prev_tick - ao_data_static.tick) > 0x400)
507                         tick_offset += 65536;
508                 if (prev_tick) {
509                         int ticks = ao_data_static.tick - prev_tick;
510                         if (ticks < 0)
511                                 ticks += 65536;
512                         simple_speed += accel * ticks / 100.0;
513                 }
514                 prev_tick = ao_data_static.tick;
515                 time = (double) (ao_data_static.tick + tick_offset) / 100;
516
517 #if TELEMEGA || TELEMETRUM_V2 || EASYMINI
518                 ao_ms5607_convert(&ao_data_static.ms5607_raw, &ao_data_static.ms5607_cooked);
519                 double height = ao_pa_to_altitude(ao_data_static.ms5607_cooked.pres) - ao_ground_height;
520
521                 /* Hack to skip baro spike at accidental drogue charge
522                  * firing in 2015-09-26-serial-2093-flight-0012.eeprom
523                  * so we can test the kalman filter with this data. Just
524                  * keep reporting the same baro value across the pressure spike
525                  */
526                 {
527                         static struct ao_ms5607_sample save;
528                         if (ao_serial_number == 2093 && ao_flight_number == 12 && 32.5 < time && time < 33.7) {
529                                 ao_data_ring[ao_data_head].ms5607_raw = save;
530                         } else {
531                                 save = ao_data_static.ms5607_raw;
532                         }
533                 }
534 #else
535                 double  height = ao_pres_to_altitude(ao_data_static.adc.pres_real) - ao_ground_height;
536 #endif
537
538                 if (ao_test_max_height < height) {
539                         ao_test_max_height = height;
540                         ao_test_max_height_time = time;
541                         ao_test_landed_height = height;
542                         ao_test_landed_time = time;
543                 }
544                 if (height > ao_config.main_deploy) {
545                         ao_test_main_height_time = time;
546                         ao_test_main_height = height;
547                 }
548
549                 if (ao_test_landed_height > height) {
550                         ao_test_landed_height = height;
551                         ao_test_landed_time = time;
552                 }
553
554                 if (ao_flight_state == ao_flight_landed && !landed_set) {
555                         landed_set = 1;
556                         landed_time = time;
557                         landed_height = height;
558                 }
559
560                 if (!ao_summary) {
561 #if TELEMEGA
562                         static struct ao_quaternion     ao_ground_mag;
563                         static int                      ao_ground_mag_set;
564
565                         if (!ao_ground_mag_set) {
566                                 ao_quaternion_init_vector (&ao_ground_mag,
567                                                            ao_data_mag_across(&ao_data_static),
568                                                            ao_data_mag_through(&ao_data_static),
569                                                            ao_data_mag_along(&ao_data_static));
570                                 ao_quaternion_normalize(&ao_ground_mag, &ao_ground_mag);
571                                 ao_quaternion_rotate(&ao_ground_mag, &ao_ground_mag, &ao_rotation);
572                                 ao_ground_mag_set = 1;
573                         }
574
575                         struct ao_quaternion            ao_mag, ao_mag_rot;
576
577                         ao_quaternion_init_vector(&ao_mag,
578                                                   ao_data_mag_across(&ao_data_static),
579                                                   ao_data_mag_through(&ao_data_static),
580                                                   ao_data_mag_along(&ao_data_static));
581
582                         ao_quaternion_normalize(&ao_mag, &ao_mag);
583                         ao_quaternion_rotate(&ao_mag_rot, &ao_mag, &ao_rotation);
584
585                         float                           ao_dot;
586                         int                             ao_mag_angle;
587
588                         ao_dot = ao_quaternion_dot(&ao_mag_rot, &ao_ground_mag);
589
590                         struct ao_azel                  ground_azel, mag_azel, rot_azel;
591
592                         azel(&ground_azel, &ao_ground_mag);
593                         azel(&mag_azel, &ao_mag);
594                         azel(&rot_azel, &ao_mag_rot);
595
596                         ao_mag_angle = floor (acos(ao_dot) * 180 / M_PI + 0.5);
597
598                         (void) ao_mag_angle;
599
600                         static struct ao_quaternion     ao_x = { .r = 0, .x = 1, .y = 0, .z = 0 };
601                         struct ao_quaternion            ao_out;
602
603                         ao_quaternion_rotate(&ao_out, &ao_x, &ao_rotation);
604
605 #if 0
606                         int     out = floor (atan2(ao_out.y, ao_out.x) * 180 / M_PI);
607
608                         printf ("%7.2f state %-8.8s height %8.4f tilt %4d rot %4d mag_tilt %4d mag_rot %4d\n",
609                                 time,
610                                 ao_state_names[ao_flight_state],
611                                 ao_k_height / 65536.0,
612                                 ao_sample_orient, out,
613                                 mag_azel.el,
614                                 mag_azel.az);
615 #endif
616 #if 0
617                         printf ("%7.2f state %-8.8s height %8.4f tilt %4d rot %4d dist %12.2f gps_tilt %4d gps_sats %2d\n",
618                                 time,
619                                 ao_state_names[ao_flight_state],
620                                 ao_k_height / 65536.0,
621                                 ao_sample_orient, out,
622                                 ao_distance_from_pad(),
623                                 (int) floor (ao_gps_angle() + 0.5),
624                                 (ao_gps_static.flags & 0xf) * 10);
625
626 #endif
627 #if 0
628                         printf ("\t\tstate %-8.8s ground az: %4d el %4d mag az %4d el %4d rot az %4d el %4d el_diff %4d az_diff %4d angle %4d tilt %4d ground %8.5f %8.5f %8.5f cur %8.5f %8.5f %8.5f rot %8.5f %8.5f %8.5f\n",
629                                 ao_state_names[ao_flight_state],
630                                 ground_azel.az, ground_azel.el,
631                                 mag_azel.az, mag_azel.el,
632                                 rot_azel.az, rot_azel.el,
633                                 ground_azel.el - rot_azel.el,
634                                 ground_azel.az - rot_azel.az,
635                                 ao_mag_angle,
636                                 ao_sample_orient,
637                                 ao_ground_mag.x,
638                                 ao_ground_mag.y,
639                                 ao_ground_mag.z,
640                                 ao_mag.x,
641                                 ao_mag.y,
642                                 ao_mag.z,
643                                 ao_mag_rot.x,
644                                 ao_mag_rot.y,
645                                 ao_mag_rot.z);
646 #endif
647 #endif
648
649 #if 1
650                         printf("%7.2f height %8.2f accel %8.3f accel_speed %8.3f "
651                                "state %d k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d"
652 #if TELEMEGA
653                                " angle %5d "
654                                "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f mag_x %8d mag_y %8d, mag_z %8d mag_angle %4d "
655                                "avg_accel %8.3f "
656 #endif
657                                "\n",
658                                time,
659                                height,
660                                accel,
661                                simple_speed > -100.0 ? simple_speed : -100.0,
662                                ao_flight_state * 10,
663                                ao_k_height / 65536.0,
664                                ao_k_speed / 65536.0 / 16.0,
665                                ao_k_accel / 65536.0 / 16.0,
666                                ao_avg_height,
667                                drogue_height,
668                                main_height,
669                                ao_error_h_sq_avg
670 #if TELEMEGA
671                                , ao_sample_orient,
672
673                                ao_mpu6000_accel(ao_data_static.mpu6000.accel_x),
674                                ao_mpu6000_accel(ao_data_static.mpu6000.accel_y),
675                                ao_mpu6000_accel(ao_data_static.mpu6000.accel_z),
676                                ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x),
677                                ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y),
678                                ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z),
679                                ao_data_static.hmc5883.x,
680                                ao_data_static.hmc5883.y,
681                                ao_data_static.hmc5883.z,
682                                ao_mag_angle,
683                                ao_coast_avg_accel / 16.0
684 #endif
685                                 );
686 #endif
687
688 //                      if (ao_flight_state == ao_flight_landed)
689 //                              ao_test_exit();
690                 }
691         }
692         ao_data_head = ao_data_ring_next(ao_data_head);
693 }
694
695
696 uint16_t
697 uint16(uint8_t *bytes, int off)
698 {
699         return (uint16_t) bytes[off] | (((uint16_t) bytes[off+1]) << 8);
700 }
701
702 int16_t
703 int16(uint8_t *bytes, int off)
704 {
705         return (int16_t) uint16(bytes, off);
706 }
707
708 uint32_t
709 uint32(uint8_t *bytes, int off)
710 {
711         return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
712                 (((uint32_t) bytes[off+2]) << 16) |
713                 (((uint32_t) bytes[off+3]) << 24);
714 }
715
716 int32_t
717 int32(uint8_t *bytes, int off)
718 {
719         return (int32_t) uint32(bytes, off);
720 }
721
722 uint32_t
723 uint24(uint8_t *bytes, int off)
724 {
725         return (uint32_t) bytes[off] | (((uint32_t) bytes[off+1]) << 8) |
726                 (((uint32_t) bytes[off+2]) << 16);
727 }
728
729 int32_t
730 int24(uint8_t *bytes, int off)
731 {
732         return (int32_t) uint24(bytes, off);
733 }
734
735 static int log_format;
736
737 void
738 ao_sleep(void *wchan)
739 {
740         if (wchan == &ao_data_head) {
741 #if TELEMEGA
742                 if (ao_flight_state >= ao_flight_boost && ao_flight_state < ao_flight_landed)
743                         ao_pyro_check();
744 #endif
745                 for (;;) {
746                         if (ao_records_read > 2 && ao_flight_state == ao_flight_startup)
747                         {
748
749 #if TELEMEGA
750                                 ao_data_static.mpu6000 = ao_ground_mpu6000;
751 #endif
752 #if TELEMETRUM_V1
753                                 ao_data_static.adc.accel = ao_flight_ground_accel;
754 #endif
755
756                                 ao_insert();
757                                 return;
758                         }
759
760                         if (eeprom) {
761 #if TELEMEGA
762                                 struct ao_log_mega      *log_mega;
763 #endif
764 #if TELEMETRUM_V2
765                                 struct ao_log_metrum    *log_metrum;
766 #endif
767 #if EASYMINI
768                                 struct ao_log_mini      *log_mini;
769 #endif
770 #if TELEMETRUM_V1
771                                 struct ao_log_record    *log_record;
772 #endif
773
774                                 if (eeprom_offset >= eeprom->len) {
775                                         if (++ao_eof_read >= 1000)
776                                                 if (!ao_summary)
777                                                         printf ("no more data, exiting simulation\n");
778                                         ao_test_exit();
779                                         ao_data_static.tick += 10;
780                                         ao_insert();
781                                         return;
782                                 }
783                                 switch (eeprom->log_format) {
784 #if TELEMEGA
785                                 case AO_LOG_FORMAT_TELEMEGA_OLD:
786                                 case AO_LOG_FORMAT_TELEMEGA:
787                                         log_mega = (struct ao_log_mega *) &eeprom->data[eeprom_offset];
788                                         eeprom_offset += sizeof (*log_mega);
789                                         switch (log_mega->type) {
790                                         case AO_LOG_FLIGHT:
791                                                 ao_flight_number = log_mega->u.flight.flight;
792                                                 ao_flight_ground_accel = log_mega->u.flight.ground_accel;
793                                                 ao_flight_started = 1;
794                                                 ao_ground_pres = log_mega->u.flight.ground_pres;
795                                                 ao_ground_height = ao_pa_to_altitude(ao_ground_pres);
796                                                 ao_ground_accel_along = log_mega->u.flight.ground_accel_along;
797                                                 ao_ground_accel_across = log_mega->u.flight.ground_accel_across;
798                                                 ao_ground_accel_through = log_mega->u.flight.ground_accel_through;
799                                                 ao_ground_roll = log_mega->u.flight.ground_roll;
800                                                 ao_ground_pitch = log_mega->u.flight.ground_pitch;
801                                                 ao_ground_yaw = log_mega->u.flight.ground_yaw;
802                                                 ao_ground_mpu6000.accel_x = ao_ground_accel_across;
803                                                 ao_ground_mpu6000.accel_y = ao_ground_accel_along;
804                                                 ao_ground_mpu6000.accel_z = ao_ground_accel_through;
805                                                 ao_ground_mpu6000.gyro_x = ao_ground_pitch >> 9;
806                                                 ao_ground_mpu6000.gyro_y = ao_ground_roll >> 9;
807                                                 ao_ground_mpu6000.gyro_z = ao_ground_yaw >> 9;
808                                                 break;
809                                         case AO_LOG_STATE:
810                                                 break;
811                                         case AO_LOG_SENSOR:
812                                                 ao_data_static.tick = log_mega->tick;
813                                                 ao_data_static.ms5607_raw.pres = log_mega->u.sensor.pres;
814                                                 ao_data_static.ms5607_raw.temp = log_mega->u.sensor.temp;
815                                                 ao_data_static.mpu6000.accel_x = log_mega->u.sensor.accel_x;
816                                                 ao_data_static.mpu6000.accel_y = log_mega->u.sensor.accel_y;
817                                                 ao_data_static.mpu6000.accel_z = log_mega->u.sensor.accel_z;
818                                                 ao_data_static.mpu6000.gyro_x = log_mega->u.sensor.gyro_x;
819                                                 ao_data_static.mpu6000.gyro_y = log_mega->u.sensor.gyro_y;
820                                                 ao_data_static.mpu6000.gyro_z = log_mega->u.sensor.gyro_z;
821                                                 ao_data_static.hmc5883.x = log_mega->u.sensor.mag_x;
822                                                 ao_data_static.hmc5883.y = log_mega->u.sensor.mag_y;
823                                                 ao_data_static.hmc5883.z = log_mega->u.sensor.mag_z;
824                                                 ao_data_static.mma655x = log_mega->u.sensor.accel;
825                                                 if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
826                                                         ao_data_static.mma655x = ao_data_accel_invert(ao_data_static.mma655x);
827                                                 ao_records_read++;
828                                                 ao_insert();
829                                                 return;
830                                         case AO_LOG_TEMP_VOLT:
831                                                 if (pyros_fired != log_mega->u.volt.pyro) {
832                                                         printf("pyro changed %x -> %x\n", pyros_fired, log_mega->u.volt.pyro);
833                                                         pyros_fired = log_mega->u.volt.pyro;
834                                                 }
835                                                 break;
836                                         case AO_LOG_GPS_TIME:
837                                                 ao_gps_prev = ao_gps_static;
838                                                 ao_gps_static.tick = log_mega->tick;
839                                                 ao_gps_static.latitude = log_mega->u.gps.latitude;
840                                                 ao_gps_static.longitude = log_mega->u.gps.longitude;
841                                                 {
842                                                         int16_t altitude_low = log_mega->u.gps.altitude_low;
843                                                         int16_t altitude_high = log_mega->u.gps.altitude_high;
844                                                         int32_t altitude = altitude_low | ((int32_t) altitude_high << 16);
845
846                                                         AO_TELEMETRY_LOCATION_SET_ALTITUDE(&ao_gps_static, altitude);
847                                                 }
848                                                 ao_gps_static.flags = log_mega->u.gps.flags;
849                                                 if (!ao_gps_count)
850                                                         ao_gps_first = ao_gps_static;
851                                                 ao_gps_count++;
852                                                 break;
853                                         case AO_LOG_GPS_SAT:
854                                                 break;
855                                         }
856                                         break;
857 #endif
858 #if TELEMETRUM_V2
859                                 case AO_LOG_FORMAT_TELEMETRUM:
860                                         log_metrum = (struct ao_log_metrum *) &eeprom->data[eeprom_offset];
861                                         eeprom_offset += sizeof (*log_metrum);
862                                         switch (log_metrum->type) {
863                                         case AO_LOG_FLIGHT:
864                                                 ao_flight_started = 1;
865                                                 ao_flight_number = log_metrum->u.flight.flight;
866                                                 ao_flight_ground_accel = log_metrum->u.flight.ground_accel;
867                                                 ao_ground_pres = log_metrum->u.flight.ground_pres;
868                                                 ao_ground_height = ao_pa_to_altitude(ao_ground_pres);
869                                                 break;
870                                         case AO_LOG_SENSOR:
871                                                 ao_data_static.tick = log_metrum->tick;
872                                                 ao_data_static.ms5607_raw.pres = log_metrum->u.sensor.pres;
873                                                 ao_data_static.ms5607_raw.temp = log_metrum->u.sensor.temp;
874                                                 ao_data_static.mma655x = log_metrum->u.sensor.accel;
875                                                 ao_records_read++;
876                                                 ao_insert();
877                                                 return;
878                                         }
879                                         break;
880 #endif
881 #if EASYMINI
882                                 case AO_LOG_FORMAT_EASYMINI1:
883                                 case AO_LOG_FORMAT_EASYMINI2:
884                                 case AO_LOG_FORMAT_TELEMINI3:
885                                         log_mini = (struct ao_log_mini *) &eeprom->data[eeprom_offset];
886                                         eeprom_offset += sizeof (*log_mini);
887                                         switch (log_mini->type) {
888                                         case AO_LOG_FLIGHT:
889                                                 ao_flight_started = 1;
890                                                 ao_flight_number = log_mini->u.flight.flight;
891                                                 ao_ground_pres = log_mini->u.flight.ground_pres;
892                                                 ao_ground_height = ao_pa_to_altitude(ao_ground_pres);
893                                                 break;
894                                         case AO_LOG_SENSOR:
895                                                 ao_data_static.tick = log_mini->tick;
896                                                 ao_data_static.ms5607_raw.pres = int24(log_mini->u.sensor.pres, 0);
897                                                 ao_data_static.ms5607_raw.temp = int24(log_mini->u.sensor.temp, 0);
898                                                 ao_records_read++;
899                                                 ao_insert();
900                                                 return;
901                                         }
902                                         break;
903 #endif
904 #if TELEMETRUM_V1
905                                 case AO_LOG_FORMAT_FULL:
906                                 case AO_LOG_FORMAT_TINY:
907                                         log_record = (struct ao_log_record *) &eeprom->data[eeprom_offset];
908                                         eeprom_offset += sizeof (*log_record);
909                                         switch (log_record->type) {
910                                         case AO_LOG_FLIGHT:
911                                                 ao_flight_started = 1;
912                                                 ao_flight_ground_accel = log_record->u.flight.ground_accel;
913                                                 ao_flight_number = log_record->u.flight.flight;
914                                                 break;
915                                         case AO_LOG_SENSOR:
916                                         case 'P':       /* ancient telemini */
917                                                 ao_data_static.tick = log_record->tick;
918                                                 ao_data_static.adc.accel = log_record->u.sensor.accel;
919                                                 ao_data_static.adc.pres_real = log_record->u.sensor.pres;
920                                                 ao_data_static.adc.pres = log_record->u.sensor.pres;
921                                                 ao_records_read++;
922                                                 ao_insert();
923                                                 return;
924                                         case AO_LOG_TEMP_VOLT:
925                                                 ao_data_static.tick = log_record->tick;;
926                                                 ao_data_static.adc.temp = log_record->u.temp_volt.temp;
927                                                 ao_data_static.adc.v_batt = log_record->u.temp_volt.v_batt;
928                                                 break;
929                                         }
930                                         break;
931 #endif
932                                 default:
933                                         printf ("invalid log format %d\n", log_format);
934                                         ao_test_exit();
935                                 }
936                         }
937                 }
938
939         }
940 }
941 #define COUNTS_PER_G 264.8
942
943 void
944 ao_dump_state(void)
945 {
946 }
947
948 static const struct option options[] = {
949         { .name = "summary", .has_arg = 0, .val = 's' },
950         { .name = "debug", .has_arg = 0, .val = 'd' },
951         { .name = "info", .has_arg = 1, .val = 'i' },
952         { 0, 0, 0, 0},
953 };
954
955 void run_flight_fixed(char *name, FILE *f, int summary, char *info)
956 {
957         emulator_name = name;
958         emulator_in = f;
959         emulator_info = info;
960         ao_summary = summary;
961
962         if (strstr(name, ".eeprom") != NULL) {
963                 char    c;
964
965                 c = getc(f);
966                 ungetc(c, f);
967                 if (c == '{')
968                         eeprom = ao_eeprom_read(f);
969                 else
970                         eeprom = ao_eeprom_read_old(f);
971
972                 if (eeprom) {
973 #if HAS_MS5607
974                         ao_ms5607_prom = eeprom->ms5607_prom;
975 #endif
976                         ao_config = eeprom->config;
977                         ao_serial_number = eeprom->serial_number;
978                         log_format = eeprom->log_format;
979                 }
980         }
981
982         ao_flight_init();
983         ao_flight();
984 }
985
986 int
987 main (int argc, char **argv)
988 {
989         int     summary = 0;
990         int     c;
991         int     i;
992         char    *info = NULL;
993
994 #if HAS_ACCEL
995         emulator_app="full";
996 #else
997         emulator_app="baro";
998 #endif
999         while ((c = getopt_long(argc, argv, "sdpi:", options, NULL)) != -1) {
1000                 switch (c) {
1001                 case 's':
1002                         summary = 1;
1003                         break;
1004                 case 'd':
1005                         ao_flight_debug = 1;
1006                         break;
1007                 case 'p':
1008 #if PYRO_DBG
1009                         pyro_dbg = 1;
1010 #endif
1011                         break;
1012                 case 'i':
1013                         info = optarg;
1014                         break;
1015                 }
1016         }
1017
1018         if (optind == argc)
1019                 run_flight_fixed("<stdin>", stdin, summary, info);
1020         else
1021                 for (i = optind; i < argc; i++) {
1022                         FILE    *f = fopen(argv[i], "r");
1023                         if (!f) {
1024                                 perror(argv[i]);
1025                                 continue;
1026                         }
1027                         run_flight_fixed(argv[i], f, summary, info);
1028                         fclose(f);
1029                 }
1030         exit(0);
1031 }