32a0967c9808c7dcd4087b76c58178630baa30c2
[fw/altos] / src / kernel / ao_config.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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19 #include "ao_log.h"
20 #include <ao_config.h>
21 #if HAS_FLIGHT
22 #include <ao_sample.h>
23 #include <ao_data.h>
24 #endif
25 #if HAS_BEEP
26 #include <ao_beep.h>
27 #endif
28 #if HAS_TRACKER
29 #include <ao_tracker.h>
30 #endif
31
32 __xdata struct ao_config ao_config;
33 __pdata uint8_t ao_config_loaded;
34 __pdata uint8_t ao_config_dirty;
35 __xdata uint8_t ao_config_mutex;
36
37 #ifndef AO_CONFIG_DEFAULT_APRS_INTERVAL
38 #define AO_CONFIG_DEFAULT_APRS_INTERVAL 0
39 #endif
40 #define AO_CONFIG_DEFAULT_MAIN_DEPLOY   250
41 #define AO_CONFIG_DEFAULT_RADIO_CHANNEL 0
42 #define AO_CONFIG_DEFAULT_CALLSIGN      "N0CALL"
43 #define AO_CONFIG_DEFAULT_ACCEL_ZERO_G  16000
44 #define AO_CONFIG_DEFAULT_APOGEE_DELAY  0
45 #define AO_CONFIG_DEFAULT_IGNITE_MODE   AO_IGNITE_MODE_DUAL
46 #define AO_CONFIG_DEFAULT_PAD_ORIENTATION       AO_PAD_ORIENTATION_ANTENNA_UP
47 #define AO_CONFIG_DEFAULT_PYRO_TIME     AO_MS_TO_TICKS(50)
48 #if HAS_EEPROM
49 #ifndef USE_INTERNAL_FLASH
50 #error Please define USE_INTERNAL_FLASH
51 #endif
52 #endif
53 #ifndef AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX
54 #if USE_INTERNAL_FLASH
55 #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX        ao_storage_config
56 #else
57 #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX        ((uint32_t) 192 * (uint32_t) 1024)
58 #endif
59 #endif
60 #ifndef AO_CONFIG_DEFAULT_RADIO_POWER
61 #define AO_CONFIG_DEFAULT_RADIO_POWER           0x60
62 #endif
63 #define AO_CONFIG_DEFAULT_RADIO_AMP             0
64 #define AO_CONFIG_DEFAULT_APRS_SSID             (ao_serial_number % 10)
65 #define AO_CONFIG_DEFAULT_RADIO_RATE            AO_RADIO_RATE_38400
66
67 #if HAS_EEPROM
68 static void
69 _ao_config_put(void)
70 {
71         ao_config_setup();
72         ao_config_erase();
73         ao_config_write(0, &ao_config, sizeof (ao_config));
74 #if HAS_FLIGHT
75         ao_log_write_erase(0);
76 #endif
77         ao_config_flush();
78 }
79
80 void
81 ao_config_put(void)
82 {
83         ao_mutex_get(&ao_config_mutex);
84         _ao_config_put();
85         ao_mutex_put(&ao_config_mutex);
86 }
87 #endif
88
89 #if HAS_RADIO
90 void
91 ao_config_set_radio(void)
92 {
93         ao_config.radio_setting = ao_freq_to_set(ao_config.frequency, ao_config.radio_cal);
94 }
95 #endif /* HAS_RADIO */
96
97 static void
98 _ao_config_get(void)
99 {
100         uint8_t minor;
101
102         if (ao_config_loaded)
103                 return;
104 #if HAS_EEPROM
105         /* Yes, I know ao_storage_read calls ao_storage_setup,
106          * but ao_storage_setup *also* sets ao_storage_config, which we
107          * need before calling ao_storage_read here
108          */
109         ao_config_setup();
110         ao_config_read(0, &ao_config, sizeof (ao_config));
111 #endif
112         if (ao_config.major != AO_CONFIG_MAJOR) {
113                 ao_config.major = AO_CONFIG_MAJOR;
114                 ao_config.minor = 0;
115
116                 /* Version 0 stuff */
117                 ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY;
118                 ao_xmemset(&ao_config.callsign, '\0', sizeof (ao_config.callsign));
119                 ao_xmemcpy(&ao_config.callsign, CODE_TO_XDATA(AO_CONFIG_DEFAULT_CALLSIGN),
120                        sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
121                 ao_config._legacy_radio_channel = 0;
122         }
123         minor = ao_config.minor;
124         if (minor != AO_CONFIG_MINOR) {
125                 /* Fixups for minor version 1 */
126                 if (minor < 1)
127                         ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY;
128                 /* Fixups for minor version 2 */
129                 if (minor < 2) {
130                         ao_config.accel_plus_g = 0;
131                         ao_config.accel_minus_g = 0;
132                 }
133                 /* Fixups for minor version 3 */
134 #if HAS_RADIO
135                 if (minor < 3)
136                         ao_config.radio_cal = ao_radio_cal;
137 #endif
138                 /* Fixups for minor version 4 */
139 #if HAS_LOG
140                 if (minor < 4)
141                         ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX;
142 #endif
143                 /* Fixupes for minor version 5 */
144                 if (minor < 5)
145                         ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE;
146                 if (minor < 6)
147                         ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION;
148                 if (minor < 8)
149                         ao_config.radio_enable = AO_RADIO_ENABLE_CORE;
150                 if (minor < 9)
151                         ao_xmemset(&ao_config.aes_key, '\0', AO_AES_LEN);
152                 if (minor < 10)
153                         ao_config.frequency = 434550 + ao_config._legacy_radio_channel * 100;
154                 if (minor < 11)
155                         ao_config.apogee_lockout = 0;
156 #if AO_PYRO_NUM
157                 if (minor < 12)
158                         memset(&ao_config.pyro, '\0', sizeof (ao_config.pyro));
159 #endif
160                 if (minor < 13)
161                         ao_config.aprs_interval = AO_CONFIG_DEFAULT_APRS_INTERVAL;
162 #if HAS_RADIO_POWER
163                 if (minor < 14)
164                         ao_config.radio_power = AO_CONFIG_DEFAULT_RADIO_POWER;
165                 #endif
166 #if HAS_RADIO_AMP
167                 if (minor  < 14)
168                         ao_config.radio_amp = AO_CONFIG_DEFAULT_RADIO_AMP;
169 #endif
170 #if HAS_GYRO
171                 if (minor < 15) {
172                         ao_config.accel_zero_along = 0;
173                         ao_config.accel_zero_across = 0;
174                         ao_config.accel_zero_through = 0;
175
176                         /* Reset the main accel offsets to force
177                          * re-calibration
178                          */
179                         ao_config.accel_plus_g = 0;
180                         ao_config.accel_minus_g = 0;
181                 }
182 #endif
183 #if HAS_BEEP_CONFIG
184                 if (minor < 16)
185                         ao_config.mid_beep = AO_BEEP_MID_DEFAULT;
186 #endif
187 #if HAS_TRACKER
188                 if (minor < 17) {
189                         ao_config.tracker_motion = AO_TRACKER_MOTION_DEFAULT;
190                         ao_config.tracker_interval = AO_TRACKER_INTERVAL_DEFAULT;
191                 }
192 #endif
193 #if AO_PYRO_NUM
194                 if (minor < 18)
195                         ao_config.pyro_time = AO_CONFIG_DEFAULT_PYRO_TIME;
196 #endif
197 #if HAS_APRS
198                 if (minor < 19)
199                         ao_config.aprs_ssid = AO_CONFIG_DEFAULT_APRS_SSID;
200 #endif
201 #if HAS_RADIO_RATE
202                 if (minor < 20)
203                         ao_config.radio_rate = AO_CONFIG_DEFAULT_RADIO_RATE;
204 #endif
205                 ao_config.minor = AO_CONFIG_MINOR;
206                 ao_config_dirty = 1;
207         }
208 #if HAS_RADIO
209 #if HAS_FORCE_FREQ
210         if (ao_force_freq) {
211                 ao_config.frequency = 434550;
212                 ao_config.radio_cal = ao_radio_cal;
213                 ao_xmemcpy(&ao_config.callsign, CODE_TO_XDATA(AO_CONFIG_DEFAULT_CALLSIGN),
214                        sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
215         }
216 #endif
217         ao_config_set_radio();
218 #endif
219         ao_config_loaded = 1;
220 }
221
222 void
223 _ao_config_edit_start(void)
224 {
225         ao_mutex_get(&ao_config_mutex);
226         _ao_config_get();
227 }
228
229 void
230 _ao_config_edit_finish(void)
231 {
232         ao_config_dirty = 1;
233         ao_mutex_put(&ao_config_mutex);
234 }
235
236 void
237 ao_config_get(void)
238 {
239         _ao_config_edit_start();
240         ao_mutex_put(&ao_config_mutex);
241 }
242
243 void
244 ao_config_callsign_show(void)
245 {
246         printf ("Callsign: \"%s\"\n", ao_config.callsign);
247 }
248
249 void
250 ao_config_callsign_set(void) __reentrant
251 {
252         uint8_t c;
253         static __xdata char callsign[AO_MAX_CALLSIGN + 1];
254
255         ao_xmemset(callsign, '\0', sizeof callsign);
256         ao_cmd_white();
257         c = 0;
258         while (ao_cmd_lex_c != '\n') {
259                 if (c < AO_MAX_CALLSIGN)
260                         callsign[c++] = ao_cmd_lex_c;
261                 else
262                         ao_cmd_status = ao_cmd_lex_error;
263                 ao_cmd_lex();
264         }
265         if (ao_cmd_status != ao_cmd_success)
266                 return;
267         _ao_config_edit_start();
268         ao_xmemcpy(&ao_config.callsign, &callsign,
269                AO_MAX_CALLSIGN + 1);
270         _ao_config_edit_finish();
271 }
272
273 #if HAS_RADIO
274
275 void
276 ao_config_frequency_show(void) __reentrant
277 {
278         printf("Frequency: %ld\n",
279                ao_config.frequency);
280 }
281
282 void
283 ao_config_frequency_set(void) __reentrant
284 {
285         ao_cmd_decimal();
286         if (ao_cmd_status != ao_cmd_success)
287                 return;
288         _ao_config_edit_start();
289         ao_config.frequency = ao_cmd_lex_u32;
290         ao_config_set_radio();
291         _ao_config_edit_finish();
292 #if HAS_RADIO_RECV
293         ao_radio_recv_abort();
294 #endif
295 }
296
297 #endif
298
299 #if HAS_FLIGHT
300
301 void
302 ao_config_main_deploy_show(void) __reentrant
303 {
304         printf("Main deploy: %d meters\n",
305                ao_config.main_deploy);
306 }
307
308 void
309 ao_config_main_deploy_set(void) __reentrant
310 {
311         ao_cmd_decimal();
312         if (ao_cmd_status != ao_cmd_success)
313                 return;
314         _ao_config_edit_start();
315         ao_config.main_deploy = ao_cmd_lex_i;
316         _ao_config_edit_finish();
317 }
318
319 #if HAS_ACCEL
320 void
321 ao_config_accel_calibrate_show(void) __reentrant
322 {
323         printf("Accel cal +1g: %d -1g: %d\n",
324                ao_config.accel_plus_g, ao_config.accel_minus_g);
325 #if HAS_GYRO
326         printf ("IMU cal along %d across %d through %d\n",
327                 ao_config.accel_zero_along,
328                 ao_config.accel_zero_across,
329                 ao_config.accel_zero_through);
330 #endif
331 }
332
333 #define ACCEL_CALIBRATE_SAMPLES 1024
334 #define ACCEL_CALIBRATE_SHIFT   10
335
336 #if HAS_GYRO
337 static int16_t accel_cal_along;
338 static int16_t accel_cal_across;
339 static int16_t accel_cal_through;
340 #endif
341
342 static int16_t
343 ao_config_accel_calibrate_auto(char *orientation) __reentrant
344 {
345         uint16_t        i;
346         int32_t         accel_total;
347         uint8_t         cal_data_ring;
348 #if HAS_GYRO
349         int32_t         accel_along_total = 0;
350         int32_t         accel_across_total = 0;
351         int32_t         accel_through_total = 0;
352 #endif
353
354         printf("Orient antenna %s and press a key...", orientation);
355         flush();
356         (void) getchar();
357         puts("\r\n"); flush();
358         puts("Calibrating..."); flush();
359         i = ACCEL_CALIBRATE_SAMPLES;
360         accel_total = 0;
361         cal_data_ring = ao_sample_data;
362         while (i) {
363                 ao_sleep(DATA_TO_XDATA(&ao_sample_data));
364                 while (i && cal_data_ring != ao_sample_data) {
365                         accel_total += (int32_t) ao_data_accel(&ao_data_ring[cal_data_ring]);
366 #if HAS_GYRO
367                         accel_along_total += (int32_t) ao_data_along(&ao_data_ring[cal_data_ring]);
368                         accel_across_total += (int32_t) ao_data_across(&ao_data_ring[cal_data_ring]);
369                         accel_through_total += (int32_t) ao_data_through(&ao_data_ring[cal_data_ring]);
370 #endif
371                         cal_data_ring = ao_data_ring_next(cal_data_ring);
372                         i--;
373                 }
374         }
375 #if HAS_GYRO
376         accel_cal_along = accel_along_total >> ACCEL_CALIBRATE_SHIFT;
377         accel_cal_across = accel_across_total >> ACCEL_CALIBRATE_SHIFT;
378         accel_cal_through = accel_through_total >> ACCEL_CALIBRATE_SHIFT;
379 #endif
380         return accel_total >> ACCEL_CALIBRATE_SHIFT;
381 }
382
383 void
384 ao_config_accel_calibrate_set(void) __reentrant
385 {
386         int16_t up, down;
387 #if HAS_GYRO
388         int16_t accel_along_up = 0, accel_along_down = 0;
389         int16_t accel_across_up = 0, accel_across_down = 0;
390         int16_t accel_through_up = 0, accel_through_down = 0;
391 #endif
392
393         ao_cmd_decimal();
394         if (ao_cmd_status != ao_cmd_success)
395                 return;
396         if (ao_cmd_lex_i == 0) {
397                 up = ao_config_accel_calibrate_auto("up");
398 #if HAS_GYRO
399                 accel_along_up = accel_cal_along;
400                 accel_across_up = accel_cal_across;
401                 accel_through_up = accel_cal_through;
402 #endif
403                 down = ao_config_accel_calibrate_auto("down");
404 #if HAS_GYRO
405                 accel_along_down = accel_cal_along;
406                 accel_across_down = accel_cal_across;
407                 accel_through_down = accel_cal_through;
408 #endif
409         } else {
410                 up = ao_cmd_lex_i;
411                 ao_cmd_decimal();
412                 if (ao_cmd_status != ao_cmd_success)
413                         return;
414                 down = ao_cmd_lex_i;
415         }
416         if (up >= down) {
417                 printf("Invalid accel: up (%d) down (%d)\n",
418                        up, down);
419                 return;
420         }
421         _ao_config_edit_start();
422         ao_config.accel_plus_g = up;
423         ao_config.accel_minus_g = down;
424 #if HAS_GYRO
425         if (ao_cmd_lex_i == 0) {
426                 ao_config.accel_zero_along = (accel_along_up + accel_along_down) / 2;
427                 ao_config.accel_zero_across = (accel_across_up + accel_across_down) / 2;
428                 ao_config.accel_zero_through = (accel_through_up + accel_through_down) / 2;
429         }
430 #endif
431         _ao_config_edit_finish();
432 }
433 #endif /* HAS_ACCEL */
434
435 void
436 ao_config_apogee_delay_show(void) __reentrant
437 {
438         printf("Apogee delay: %d seconds\n",
439                ao_config.apogee_delay);
440 }
441
442 void
443 ao_config_apogee_delay_set(void) __reentrant
444 {
445         ao_cmd_decimal();
446         if (ao_cmd_status != ao_cmd_success)
447                 return;
448         _ao_config_edit_start();
449         ao_config.apogee_delay = ao_cmd_lex_i;
450         _ao_config_edit_finish();
451 }
452
453 void
454 ao_config_apogee_lockout_show(void) __reentrant
455 {
456         printf ("Apogee lockout: %d seconds\n",
457                 ao_config.apogee_lockout);
458 }
459
460 void
461 ao_config_apogee_lockout_set(void) __reentrant
462 {
463         ao_cmd_decimal();
464         if (ao_cmd_status != ao_cmd_success)
465                 return;
466         _ao_config_edit_start();
467         ao_config.apogee_lockout = ao_cmd_lex_i;
468         _ao_config_edit_finish();
469 }
470
471 #endif /* HAS_FLIGHT */
472
473 #if HAS_RADIO
474 void
475 ao_config_radio_cal_show(void) __reentrant
476 {
477         printf("Radio cal: %ld\n", ao_config.radio_cal);
478 }
479
480 void
481 ao_config_radio_cal_set(void) __reentrant
482 {
483         ao_cmd_decimal();
484         if (ao_cmd_status != ao_cmd_success)
485                 return;
486         _ao_config_edit_start();
487         ao_config.radio_cal = ao_cmd_lex_u32;
488         ao_config_set_radio();
489         _ao_config_edit_finish();
490 }
491
492 #endif
493
494 #if HAS_RADIO_RATE
495 #ifndef HAS_TELEMETRY
496 #error Please define HAS_TELEMETRY
497 #endif
498
499 void
500 ao_config_radio_rate_show(void) __reentrant
501 {
502         printf("Telemetry rate: %d\n", ao_config.radio_rate);
503 }
504
505 void
506 ao_config_radio_rate_set(void) __reentrant
507 {
508         ao_cmd_decimal();
509         if (ao_cmd_status != ao_cmd_success)
510                 return;
511         if (AO_RADIO_RATE_MAX < ao_cmd_lex_i) {
512                 ao_cmd_status = ao_cmd_lex_error;
513                 return;
514         }
515         _ao_config_edit_start();
516         ao_config.radio_rate = ao_cmd_lex_i;
517 #if HAS_TELEMETRY
518         ao_telemetry_reset_interval();
519 #endif
520         _ao_config_edit_finish();
521 }
522 #endif
523
524 #if HAS_LOG
525 void
526 ao_config_log_show(void) __reentrant
527 {
528         printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10));
529 }
530
531 void
532 ao_config_log_set(void) __reentrant
533 {
534         uint16_t        block = (uint16_t) (ao_storage_block >> 10);
535         uint16_t        log_max = (uint16_t) (ao_storage_log_max >> 10);
536
537         ao_cmd_decimal();
538         if (ao_cmd_status != ao_cmd_success)
539                 return;
540         if (ao_log_present())
541                 printf("Storage must be empty before changing log size\n");
542         else if (block > 1024 && (ao_cmd_lex_i & (block - 1)))
543                 printf("Flight log size must be multiple of %d kB\n", block);
544         else if (ao_cmd_lex_i > log_max)
545                 printf("Flight log max %d kB\n", log_max);
546         else {
547                 _ao_config_edit_start();
548                 ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10;
549                 _ao_config_edit_finish();
550         }
551 }
552 #endif /* HAS_LOG */
553
554 #if HAS_IGNITE
555 void
556 ao_config_ignite_mode_show(void) __reentrant
557 {
558         printf("Ignite mode: %d\n", ao_config.ignite_mode);
559 }
560
561 void
562 ao_config_ignite_mode_set(void) __reentrant
563 {
564         ao_cmd_decimal();
565         if (ao_cmd_status != ao_cmd_success)
566                 return;
567         _ao_config_edit_start();
568         ao_config.ignite_mode = ao_cmd_lex_i;
569         _ao_config_edit_finish();
570 }
571 #endif
572
573 #if HAS_ACCEL
574 void
575 ao_config_pad_orientation_show(void) __reentrant
576 {
577         printf("Pad orientation: %d\n", ao_config.pad_orientation);
578 }
579
580 #ifndef AO_ACCEL_INVERT
581 #define AO_ACCEL_INVERT 0x7fff
582 #endif
583
584 void
585 ao_config_pad_orientation_set(void) __reentrant
586 {
587         ao_cmd_decimal();
588         if (ao_cmd_status != ao_cmd_success)
589                 return;
590         _ao_config_edit_start();
591         ao_cmd_lex_i &= 1;
592         if (ao_config.pad_orientation != ao_cmd_lex_i) {
593                 int16_t t;
594                 t = ao_config.accel_plus_g;
595                 ao_config.accel_plus_g = AO_ACCEL_INVERT - ao_config.accel_minus_g;
596                 ao_config.accel_minus_g = AO_ACCEL_INVERT - t;
597         }
598         ao_config.pad_orientation = ao_cmd_lex_i;
599         _ao_config_edit_finish();
600 }
601 #endif
602
603 #if HAS_RADIO
604 void
605 ao_config_radio_enable_show(void) __reentrant
606 {
607         printf("Radio enable: %d\n", ao_config.radio_enable);
608 }
609
610 void
611 ao_config_radio_enable_set(void) __reentrant
612 {
613         ao_cmd_decimal();
614         if (ao_cmd_status != ao_cmd_success)
615                 return;
616         _ao_config_edit_start();
617         ao_config.radio_enable = ao_cmd_lex_i;
618         _ao_config_edit_finish();
619 }
620 #endif /* HAS_RADIO */
621
622 #if HAS_AES
623
624 __xdata uint8_t ao_config_aes_seq = 1;
625
626 void
627 ao_config_key_show(void) __reentrant
628 {
629         uint8_t i;
630         printf("AES key: ");
631         for (i = 0; i < AO_AES_LEN; i++)
632                 printf ("%02x", ao_config.aes_key[i]);
633         printf("\n");
634 }
635
636 void
637 ao_config_key_set(void) __reentrant
638 {
639         uint8_t i;
640
641         _ao_config_edit_start();
642         for (i = 0; i < AO_AES_LEN; i++) {
643                 ao_cmd_hexbyte();
644                 if (ao_cmd_status != ao_cmd_success)
645                         break;
646                 ao_config.aes_key[i] = ao_cmd_lex_i;
647         }
648         ++ao_config_aes_seq;
649         _ao_config_edit_finish();
650 }
651 #endif
652
653 #if HAS_APRS
654
655 void
656 ao_config_aprs_show(void)
657 {
658         printf ("APRS interval: %d\n", ao_config.aprs_interval);
659 }
660
661 void
662 ao_config_aprs_set(void)
663 {
664         ao_cmd_decimal();
665         if (ao_cmd_status != ao_cmd_success)
666                 return;
667         _ao_config_edit_start();
668         ao_config.aprs_interval = ao_cmd_lex_i;
669         _ao_config_edit_finish();
670 }
671
672 #endif /* HAS_APRS */
673
674 #if HAS_RADIO_AMP
675
676 void
677 ao_config_radio_amp_show(void)
678 {
679         printf ("Radio amp setting: %d\n", ao_config.radio_amp);
680 }
681
682 void
683 ao_config_radio_amp_set(void)
684 {
685         ao_cmd_decimal();
686         if (ao_cmd_status != ao_cmd_success)
687                 return;
688         _ao_config_edit_start();
689         ao_config.radio_amp = ao_cmd_lex_i;
690         _ao_config_edit_finish();
691 }
692
693 #endif
694
695 #if HAS_RADIO_POWER
696
697 void
698 ao_config_radio_power_show(void)
699 {
700         printf ("Radio power setting: %d\n", ao_config.radio_power);
701 }
702
703 void
704 ao_config_radio_power_set(void)
705 {
706         ao_cmd_decimal();
707         if (ao_cmd_status != ao_cmd_success)
708                 return;
709         _ao_config_edit_start();
710         ao_config.radio_power = ao_cmd_lex_i;
711         _ao_config_edit_finish();
712 }
713
714 #endif
715
716 #if HAS_BEEP_CONFIG
717 void
718 ao_config_beep_show(void)
719 {
720         printf ("Beeper setting: %d\n", ao_config.mid_beep);
721 }
722
723 void
724 ao_config_beep_set(void)
725 {
726         ao_cmd_decimal();
727         if (ao_cmd_status != ao_cmd_success)
728                 return;
729         _ao_config_edit_start();
730         ao_config.mid_beep = ao_cmd_lex_i;
731         _ao_config_edit_finish();
732 }
733 #endif
734
735 #if HAS_TRACKER
736 void
737 ao_config_tracker_show(void)
738 {
739         printf ("Tracker setting: %d %d\n",
740                 ao_config.tracker_motion,
741                 ao_config.tracker_interval);
742 }
743
744 void
745 ao_config_tracker_set(void)
746 {
747         uint16_t        m, i;
748         ao_cmd_decimal();
749         if (ao_cmd_status != ao_cmd_success)
750                 return;
751         m = ao_cmd_lex_i;
752         ao_cmd_decimal();
753         if (ao_cmd_status != ao_cmd_success)
754                 return;
755         i = ao_cmd_lex_i;
756         _ao_config_edit_start();
757         ao_config.tracker_motion = m;
758         ao_config.tracker_interval = i;
759         _ao_config_edit_finish();
760 }
761 #endif /* HAS_TRACKER */
762
763 #if AO_PYRO_NUM
764 void
765 ao_config_pyro_time_show(void)
766 {
767         printf ("Pyro time: %d\n", ao_config.pyro_time);
768 }
769
770 void
771 ao_config_pyro_time_set(void)
772 {
773         ao_cmd_decimal();
774         if (ao_cmd_status != ao_cmd_success)
775                 return;
776         _ao_config_edit_start();
777         ao_config.pyro_time = ao_cmd_lex_i;
778         _ao_config_edit_finish();
779 }
780 #endif
781
782 #if HAS_APRS
783 void
784 ao_config_aprs_ssid_show(void)
785 {
786         printf ("APRS SSID: %d\n",
787                 ao_config.aprs_ssid);
788 }
789
790 void
791 ao_config_aprs_ssid_set(void)
792 {
793         ao_cmd_decimal();
794         if (ao_cmd_status != ao_cmd_success)
795                 return;
796         if (15 < ao_cmd_lex_i) {
797                 ao_cmd_status = ao_cmd_lex_error;
798                 return;
799         }
800         _ao_config_edit_start();
801         ao_config.aprs_ssid = ao_cmd_lex_i;
802         _ao_config_edit_finish();
803 }
804 #endif /* HAS_APRS */
805
806 struct ao_config_var {
807         __code char     *str;
808         void            (*set)(void) __reentrant;
809         void            (*show)(void) __reentrant;
810 };
811
812 static void
813 ao_config_help(void) __reentrant;
814
815 static void
816 ao_config_show(void) __reentrant;
817
818 #if HAS_EEPROM
819 static void
820 ao_config_save(void) __reentrant;
821 #endif
822
823 __code struct ao_config_var ao_config_vars[] = {
824 #if HAS_FLIGHT
825         { "m <meters>\0Main deploy (m)",
826           ao_config_main_deploy_set,    ao_config_main_deploy_show, },
827         { "d <delay>\0Apogee delay (s)",
828           ao_config_apogee_delay_set,   ao_config_apogee_delay_show },
829         { "L <seconds>\0Apogee detect lockout (s)",
830           ao_config_apogee_lockout_set, ao_config_apogee_lockout_show, },
831 #endif /* HAS_FLIGHT */
832 #if HAS_RADIO
833         { "F <freq>\0Frequency (kHz)",
834           ao_config_frequency_set, ao_config_frequency_show },
835         { "c <call>\0Callsign (8 char max)",
836           ao_config_callsign_set,       ao_config_callsign_show },
837         { "e <0 disable, 1 enable>\0Enable telemetry and RDF",
838           ao_config_radio_enable_set, ao_config_radio_enable_show },
839         { "f <cal>\0Radio calib (cal = rf/(xtal/2^16))",
840           ao_config_radio_cal_set,      ao_config_radio_cal_show },
841 #if HAS_RADIO_RATE
842         { "T <rate>\0Telemetry rate (0=38.4, 1=9.6, 2=2.4)",
843           ao_config_radio_rate_set,     ao_config_radio_rate_show },
844 #endif
845 #if HAS_RADIO_POWER
846         { "p <setting>\0Radio power setting (0-255)",
847           ao_config_radio_power_set,    ao_config_radio_power_show },
848 #endif
849 #if HAS_RADIO_AMP
850         { "d <setting>\0Radio amplifier setting (0-3)",
851           ao_config_radio_amp_set,      ao_config_radio_amp_show },
852 #endif
853 #endif /* HAS_RADIO */
854 #if HAS_ACCEL
855         { "a <+g> <-g>\0Accel calib (0 for auto)",
856           ao_config_accel_calibrate_set,ao_config_accel_calibrate_show },
857         { "o <0 antenna up, 1 antenna down>\0Pad orientation",
858           ao_config_pad_orientation_set,ao_config_pad_orientation_show },
859 #endif /* HAS_ACCEL */
860 #if HAS_LOG
861         { "l <size>\0Flight log size (kB)",
862           ao_config_log_set,            ao_config_log_show },
863 #endif
864 #if HAS_IGNITE
865         { "i <0 dual, 1 apogee, 2 main>\0Igniter mode",
866           ao_config_ignite_mode_set,    ao_config_ignite_mode_show },
867 #endif
868 #if HAS_AES
869         { "k <32 hex digits>\0AES encryption key",
870           ao_config_key_set, ao_config_key_show },
871 #endif
872 #if AO_PYRO_NUM
873         { "P <n,?>\0Pyro channels",
874           ao_pyro_set, ao_pyro_show },
875         { "I <ticks>\0Pyro firing time",
876           ao_config_pyro_time_set, ao_config_pyro_time_show },
877 #endif
878 #if HAS_APRS
879         { "A <secs>\0APRS packet interval (0 disable)",
880           ao_config_aprs_set, ao_config_aprs_show },
881 #endif
882 #if HAS_BEEP_CONFIG
883         { "b <val>\0Beeper tone (freq = 1/2 (24e6/32) / beep",
884           ao_config_beep_set, ao_config_beep_show },
885 #endif
886 #if HAS_TRACKER
887         { "t <motion> <interval>\0Tracker configuration",
888           ao_config_tracker_set, ao_config_tracker_show },
889 #endif
890 #if HAS_APRS
891         { "S <ssid>\0Set APRS SSID (0-15)",
892           ao_config_aprs_ssid_set, ao_config_aprs_ssid_show },
893 #endif
894         { "s\0Show",
895           ao_config_show,               0 },
896 #if HAS_EEPROM
897         { "w\0Write to eeprom",
898           ao_config_save,               0 },
899 #endif
900         { "?\0Help",
901           ao_config_help,               0 },
902         { 0, 0, 0 }
903 };
904
905 void
906 ao_config_set(void)
907 {
908         char    c;
909         uint8_t cmd;
910
911         ao_cmd_white();
912         c = ao_cmd_lex_c;
913         ao_cmd_lex();
914         for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
915                 if (ao_config_vars[cmd].str[0] == c) {
916                         (*ao_config_vars[cmd].set)();
917                         return;
918                 }
919         ao_cmd_status = ao_cmd_syntax_error;
920 }
921
922 static void
923 ao_config_help(void) __reentrant
924 {
925         uint8_t cmd;
926         for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
927                 printf("%-20s %s\n",
928                        ao_config_vars[cmd].str,
929                        ao_config_vars[cmd].str+1+
930                        strlen(ao_config_vars[cmd].str));
931 }
932
933 static void
934 ao_config_show(void) __reentrant
935 {
936         uint8_t cmd;
937         ao_config_get();
938         printf("Config version: %d.%d\n",
939                ao_config.major, ao_config.minor);
940         for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
941                 if (ao_config_vars[cmd].show)
942                         (*ao_config_vars[cmd].show)();
943 #if HAS_MS5607
944         ao_ms5607_info();
945 #endif
946 }
947
948 #if HAS_EEPROM
949 static void
950 ao_config_save(void) __reentrant
951 {
952         uint8_t saved = 0;
953         ao_mutex_get(&ao_config_mutex);
954         if (ao_config_dirty) {
955                 _ao_config_put();
956                 ao_config_dirty = 0;
957                 saved = 1;
958         }
959         ao_mutex_put(&ao_config_mutex);
960         if (saved)
961                 puts("Saved");
962         else
963                 puts("Nothing to save");
964 }
965 #endif
966
967 __code struct ao_cmds ao_config_cmds[] = {
968         { ao_config_set,        "c <var> <value>\0Set config (? for help, s to show)" },
969         { 0, NULL },
970 };
971
972 void
973 ao_config_init(void)
974 {
975         ao_cmd_register(&ao_config_cmds[0]);
976 }