altos: Remove debug printf from accel auto-cal
[fw/altos] / src / core / 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_sample.h>
21 #include <ao_data.h>
22
23 __xdata struct ao_config ao_config;
24 __pdata uint8_t ao_config_loaded;
25 __pdata uint8_t ao_config_dirty;
26 __xdata uint8_t ao_config_mutex;
27
28 #define AO_CONFIG_DEFAULT_MAIN_DEPLOY   250
29 #define AO_CONFIG_DEFAULT_RADIO_CHANNEL 0
30 #define AO_CONFIG_DEFAULT_CALLSIGN      "N0CALL"
31 #define AO_CONFIG_DEFAULT_ACCEL_ZERO_G  16000
32 #define AO_CONFIG_DEFAULT_APOGEE_DELAY  0
33 #define AO_CONFIG_DEFAULT_IGNITE_MODE   AO_IGNITE_MODE_DUAL
34 #define AO_CONFIG_DEFAULT_PAD_ORIENTATION       AO_PAD_ORIENTATION_ANTENNA_UP
35 #if HAS_EEPROM
36 #ifndef USE_INTERNAL_FLASH
37 #error Please define USE_INTERNAL_FLASH
38 #endif
39 #endif
40 #ifndef AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX
41 #if USE_INTERNAL_FLASH
42 #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX        ao_storage_config
43 #else
44 #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX        ((uint32_t) 192 * (uint32_t) 1024)
45 #endif
46 #endif
47
48 #if HAS_EEPROM
49 static void
50 _ao_config_put(void)
51 {
52         ao_storage_setup();
53         ao_storage_erase(ao_storage_config);
54         ao_storage_write(ao_storage_config, &ao_config, sizeof (ao_config));
55 #if HAS_FLIGHT
56         ao_log_write_erase(0);
57 #endif
58         ao_storage_flush();
59 }
60
61 void
62 ao_config_put(void)
63 {
64         ao_mutex_get(&ao_config_mutex);
65         _ao_config_put();
66         ao_mutex_put(&ao_config_mutex);
67 }
68 #endif
69
70 #if HAS_RADIO
71 void
72 ao_config_set_radio(void)
73 {
74         ao_config.radio_setting = ao_freq_to_set(ao_config.frequency, ao_config.radio_cal);
75 }
76 #endif /* HAS_RADIO */
77
78 static void
79 _ao_config_get(void)
80 {
81         if (ao_config_loaded)
82                 return;
83 #if HAS_EEPROM
84         ao_storage_setup();
85         ao_storage_read(ao_storage_config, &ao_config, sizeof (ao_config));
86 #endif
87         if (ao_config.major != AO_CONFIG_MAJOR) {
88                 ao_config.major = AO_CONFIG_MAJOR;
89                 ao_config.minor = 0;
90
91                 /* Version 0 stuff */
92                 ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY;
93                 ao_xmemset(&ao_config.callsign, '\0', sizeof (ao_config.callsign));
94                 ao_xmemcpy(&ao_config.callsign, CODE_TO_XDATA(AO_CONFIG_DEFAULT_CALLSIGN),
95                        sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
96                 ao_config_dirty = 1;
97         }
98         if (ao_config.minor != AO_CONFIG_MINOR) {
99                 /* Fixups for minor version 1 */
100                 if (ao_config.minor < 1)
101                         ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY;
102                 /* Fixups for minor version 2 */
103                 if (ao_config.minor < 2) {
104                         ao_config.accel_plus_g = 0;
105                         ao_config.accel_minus_g = 0;
106                 }
107                 /* Fixups for minor version 3 */
108 #if HAS_RADIO
109                 if (ao_config.minor < 3)
110                         ao_config.radio_cal = ao_radio_cal;
111 #endif
112                 /* Fixups for minor version 4 */
113                 if (ao_config.minor < 4)
114                         ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX;
115                 /* Fixupes for minor version 5 */
116                 if (ao_config.minor < 5)
117                         ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE;
118                 if (ao_config.minor < 6)
119                         ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION;
120                 if (ao_config.minor < 8)
121                         ao_config.radio_enable = TRUE;
122                 if (ao_config.minor < 9)
123                         ao_xmemset(&ao_config.aes_key, '\0', AO_AES_LEN);
124                 if (ao_config.minor < 10)
125                         ao_config.frequency = 434550;
126                 if (ao_config.minor < 11)
127                         ao_config.apogee_lockout = 0;
128                 ao_config.minor = AO_CONFIG_MINOR;
129                 ao_config_dirty = 1;
130         }
131 #if HAS_RADIO
132         ao_config_set_radio();
133 #endif
134         ao_config_loaded = 1;
135 }
136
137 static void
138 _ao_config_edit_start(void)
139 {
140         ao_mutex_get(&ao_config_mutex);
141         _ao_config_get();
142 }
143
144 static void
145 _ao_config_edit_finish(void)
146 {
147         ao_config_dirty = 1;
148         ao_mutex_put(&ao_config_mutex);
149 }
150
151 void
152 ao_config_get(void)
153 {
154         _ao_config_edit_start();
155         ao_mutex_put(&ao_config_mutex);
156 }
157
158 void
159 ao_config_callsign_show(void)
160 {
161         printf ("Callsign: \"%s\"\n", ao_config.callsign);
162 }
163
164 void
165 ao_config_callsign_set(void) __reentrant
166 {
167         uint8_t c;
168         static __xdata char callsign[AO_MAX_CALLSIGN + 1];
169
170         ao_xmemset(callsign, '\0', sizeof callsign);
171         ao_cmd_white();
172         c = 0;
173         while (ao_cmd_lex_c != '\n') {
174                 if (c < AO_MAX_CALLSIGN)
175                         callsign[c++] = ao_cmd_lex_c;
176                 else
177                         ao_cmd_status = ao_cmd_lex_error;
178                 ao_cmd_lex();
179         }
180         if (ao_cmd_status != ao_cmd_success)
181                 return;
182         _ao_config_edit_start();
183         ao_xmemcpy(&ao_config.callsign, &callsign,
184                AO_MAX_CALLSIGN + 1);
185         _ao_config_edit_finish();
186 }
187
188 #if HAS_RADIO
189 void
190 ao_config_frequency_show(void) __reentrant
191 {
192         printf("Frequency: %ld\n",
193                ao_config.frequency);
194 }
195
196 void
197 ao_config_frequency_set(void) __reentrant
198 {
199         ao_cmd_decimal();
200         if (ao_cmd_status != ao_cmd_success)
201                 return;
202         _ao_config_edit_start();
203         ao_config.frequency = ao_cmd_lex_u32;
204         ao_config_set_radio();
205         _ao_config_edit_finish();
206         ao_radio_recv_abort();
207 }
208 #endif
209
210 #if HAS_FLIGHT
211
212 void
213 ao_config_main_deploy_show(void) __reentrant
214 {
215         printf("Main deploy: %d meters\n",
216                ao_config.main_deploy);
217 }
218
219 void
220 ao_config_main_deploy_set(void) __reentrant
221 {
222         ao_cmd_decimal();
223         if (ao_cmd_status != ao_cmd_success)
224                 return;
225         _ao_config_edit_start();
226         ao_config.main_deploy = ao_cmd_lex_i;
227         _ao_config_edit_finish();
228 }
229
230 #if HAS_ACCEL
231 void
232 ao_config_accel_calibrate_show(void) __reentrant
233 {
234         printf("Accel cal +1g: %d -1g: %d\n",
235                ao_config.accel_plus_g, ao_config.accel_minus_g);
236 }
237
238 #define ACCEL_CALIBRATE_SAMPLES 1024
239 #define ACCEL_CALIBRATE_SHIFT   10
240
241 static int16_t
242 ao_config_accel_calibrate_auto(char *orientation) __reentrant
243 {
244         uint16_t        i;
245         int32_t         accel_total;
246         uint8_t         cal_data_ring;
247
248         printf("Orient antenna %s and press a key...", orientation);
249         flush();
250         (void) getchar();
251         puts("\r\n"); flush();
252         puts("Calibrating..."); flush();
253         i = ACCEL_CALIBRATE_SAMPLES;
254         accel_total = 0;
255         cal_data_ring = ao_sample_data;
256         while (i) {
257                 ao_sleep(DATA_TO_XDATA(&ao_sample_data));
258                 while (i && cal_data_ring != ao_sample_data) {
259                         accel_total += (int32_t) ao_data_accel(&ao_data_ring[cal_data_ring]);
260                         cal_data_ring = ao_data_ring_next(cal_data_ring);
261                         i--;
262                 }
263         }
264         return accel_total >> ACCEL_CALIBRATE_SHIFT;
265 }
266
267 void
268 ao_config_accel_calibrate_set(void) __reentrant
269 {
270         int16_t up, down;
271         ao_cmd_decimal();
272         if (ao_cmd_status != ao_cmd_success)
273                 return;
274         if (ao_cmd_lex_i == 0) {
275                 up = ao_config_accel_calibrate_auto("up");
276                 down = ao_config_accel_calibrate_auto("down");
277         } else {
278                 up = ao_cmd_lex_i;
279                 ao_cmd_decimal();
280                 if (ao_cmd_status != ao_cmd_success)
281                         return;
282                 down = ao_cmd_lex_i;
283         }
284         if (up >= down) {
285                 printf("Invalid accel: up (%d) down (%d)\n",
286                        up, down);
287                 return;
288         }
289         _ao_config_edit_start();
290         ao_config.accel_plus_g = up;
291         ao_config.accel_minus_g = down;
292         _ao_config_edit_finish();
293 }
294 #endif /* HAS_ACCEL */
295
296 void
297 ao_config_apogee_delay_show(void) __reentrant
298 {
299         printf("Apogee delay: %d seconds\n",
300                ao_config.apogee_delay);
301 }
302
303 void
304 ao_config_apogee_delay_set(void) __reentrant
305 {
306         ao_cmd_decimal();
307         if (ao_cmd_status != ao_cmd_success)
308                 return;
309         _ao_config_edit_start();
310         ao_config.apogee_delay = ao_cmd_lex_i;
311         _ao_config_edit_finish();
312 }
313
314 void
315 ao_config_apogee_lockout_show(void) __reentrant
316 {
317         printf ("Apogee lockout: %d seconds\n",
318                 ao_config.apogee_lockout);
319 }
320
321 void
322 ao_config_apogee_lockout_set(void) __reentrant
323 {
324         ao_cmd_decimal();
325         if (ao_cmd_status != ao_cmd_success)
326                 return;
327         _ao_config_edit_start();
328         ao_config.apogee_lockout = ao_cmd_lex_i;
329         _ao_config_edit_finish();
330 }
331
332 #endif /* HAS_FLIGHT */
333
334 #if HAS_RADIO
335 void
336 ao_config_radio_cal_show(void) __reentrant
337 {
338         printf("Radio cal: %ld\n", ao_config.radio_cal);
339 }
340
341 void
342 ao_config_radio_cal_set(void) __reentrant
343 {
344         ao_cmd_decimal();
345         if (ao_cmd_status != ao_cmd_success)
346                 return;
347         _ao_config_edit_start();
348         ao_config.radio_cal = ao_cmd_lex_u32;
349         ao_config_set_radio();
350         _ao_config_edit_finish();
351 }
352 #endif
353
354 #if HAS_LOG
355 void
356 ao_config_log_show(void) __reentrant
357 {
358         printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10));
359 }
360
361 void
362 ao_config_log_set(void) __reentrant
363 {
364         uint16_t        block = (uint16_t) (ao_storage_block >> 10);
365         uint16_t        config = (uint16_t) (ao_storage_config >> 10);
366
367         ao_cmd_decimal();
368         if (ao_cmd_status != ao_cmd_success)
369                 return;
370         if (ao_log_present())
371                 printf("Storage must be empty before changing log size\n");
372         else if (block > 1024 && (ao_cmd_lex_i & (block - 1)))
373                 printf("Flight log size must be multiple of %d kB\n", block);
374         else if (ao_cmd_lex_i > config)
375                 printf("Flight log max %d kB\n", config);
376         else {
377                 _ao_config_edit_start();
378                 ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10;
379                 _ao_config_edit_finish();
380         }
381 }
382 #endif /* HAS_LOG */
383
384 #if HAS_IGNITE
385 void
386 ao_config_ignite_mode_show(void) __reentrant
387 {
388         printf("Ignite mode: %d\n", ao_config.ignite_mode);
389 }
390
391 void
392 ao_config_ignite_mode_set(void) __reentrant
393 {
394         ao_cmd_decimal();
395         if (ao_cmd_status != ao_cmd_success)
396                 return;
397         _ao_config_edit_start();
398         ao_config.ignite_mode = ao_cmd_lex_i;
399         _ao_config_edit_finish();
400 }
401 #endif
402
403 #if HAS_ACCEL
404 void
405 ao_config_pad_orientation_show(void) __reentrant
406 {
407         printf("Pad orientation: %d\n", ao_config.pad_orientation);
408 }
409
410 void
411 ao_config_pad_orientation_set(void) __reentrant
412 {
413         ao_cmd_decimal();
414         if (ao_cmd_status != ao_cmd_success)
415                 return;
416         _ao_config_edit_start();
417         ao_cmd_lex_i &= 1;
418         if (ao_config.pad_orientation != ao_cmd_lex_i) {
419                 uint16_t t;
420                 t = ao_config.accel_plus_g;
421                 ao_config.accel_plus_g = 0x7fff - ao_config.accel_minus_g;
422                 ao_config.accel_minus_g = 0x7fff - t;
423         }
424         ao_config.pad_orientation = ao_cmd_lex_i;
425         _ao_config_edit_finish();
426 }
427 #endif
428
429 #if HAS_RADIO
430 void
431 ao_config_radio_enable_show(void) __reentrant
432 {
433         printf("Radio enable: %d\n", ao_config.radio_enable);
434 }
435
436 void
437 ao_config_radio_enable_set(void) __reentrant
438 {
439         ao_cmd_decimal();
440         if (ao_cmd_status != ao_cmd_success)
441                 return;
442         _ao_config_edit_start();
443         ao_config.radio_enable = ao_cmd_lex_i;
444         _ao_config_edit_finish();
445 }
446 #endif /* HAS_RADIO */
447         
448 #if HAS_AES
449 void
450 ao_config_key_show(void) __reentrant
451 {
452         uint8_t i;
453         printf("AES key: ");
454         for (i = 0; i < AO_AES_LEN; i++)
455                 printf ("%02x", ao_config.aes_key[i]);
456         printf("\n");
457 }
458
459 void
460 ao_config_key_set(void) __reentrant
461 {
462         uint8_t i;
463
464         _ao_config_edit_start();
465         for (i = 0; i < AO_AES_LEN; i++) {
466                 ao_cmd_hexbyte();
467                 if (ao_cmd_status != ao_cmd_success)
468                         break;
469                 ao_config.aes_key[i] = ao_cmd_lex_i;
470         }
471         _ao_config_edit_finish();
472 }
473 #endif
474
475 struct ao_config_var {
476         __code char     *str;
477         void            (*set)(void) __reentrant;
478         void            (*show)(void) __reentrant;
479 };
480
481 static void
482 ao_config_help(void) __reentrant;
483
484 static void
485 ao_config_show(void) __reentrant;
486
487 static void
488 ao_config_write(void) __reentrant;
489
490 __code struct ao_config_var ao_config_vars[] = {
491 #if HAS_FLIGHT
492         { "m <meters>\0Main deploy (m)",
493           ao_config_main_deploy_set,    ao_config_main_deploy_show, },
494         { "d <delay>\0Apogee delay (s)",
495           ao_config_apogee_delay_set,   ao_config_apogee_delay_show },
496         { "L <seconds>\0Apogee detect lockout (s)",
497           ao_config_apogee_lockout_set, ao_config_apogee_lockout_show, },
498 #endif /* HAS_FLIGHT */
499 #if HAS_RADIO
500         { "F <freq>\0Frequency (kHz)",
501           ao_config_frequency_set, ao_config_frequency_show },
502         { "c <call>\0Callsign (8 char max)",
503           ao_config_callsign_set,       ao_config_callsign_show },
504         { "e <0 disable, 1 enable>\0Enable telemetry and RDF",
505           ao_config_radio_enable_set, ao_config_radio_enable_show },
506 #endif /* HAS_RADIO */
507 #if HAS_ACCEL
508         { "a <+g> <-g>\0Accel calib (0 for auto)",
509           ao_config_accel_calibrate_set,ao_config_accel_calibrate_show },
510 #endif /* HAS_ACCEL */
511 #if HAS_RADIO
512         { "f <cal>\0Radio calib (cal = rf/(xtal/2^16))",
513           ao_config_radio_cal_set,      ao_config_radio_cal_show },
514 #endif /* HAS_RADIO */
515 #if HAS_LOG
516         { "l <size>\0Flight log size (kB)",
517           ao_config_log_set,            ao_config_log_show },
518 #endif
519 #if HAS_IGNITE
520         { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode",
521           ao_config_ignite_mode_set,    ao_config_ignite_mode_show },
522 #endif
523 #if HAS_ACCEL
524         { "o <0 antenna up, 1 antenna down>\0Set pad orientation",
525           ao_config_pad_orientation_set,ao_config_pad_orientation_show },
526 #endif
527 #if HAS_AES
528         { "k <32 hex digits>\0Set AES encryption key",
529           ao_config_key_set, ao_config_key_show },
530 #endif
531         { "s\0Show",
532           ao_config_show,               0 },
533 #if HAS_EEPROM
534         { "w\0Write to eeprom",
535           ao_config_write,              0 },
536 #endif
537         { "?\0Help",
538           ao_config_help,               0 },
539         { 0, 0, 0 }
540 };
541
542 void
543 ao_config_set(void)
544 {
545         char    c;
546         uint8_t cmd;
547         void (*__xdata func)(void) __reentrant;
548
549         ao_cmd_white();
550         c = ao_cmd_lex_c;
551         ao_cmd_lex();
552         func = 0;
553         for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
554                 if (ao_config_vars[cmd].str[0] == c) {
555                         (*ao_config_vars[cmd].set)();
556                         return;
557                 }
558         ao_cmd_status = ao_cmd_syntax_error;
559 }
560
561 static void
562 ao_config_help(void) __reentrant
563 {
564         uint8_t cmd;
565         for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
566                 printf("%-20s %s\n",
567                        ao_config_vars[cmd].str,
568                        ao_config_vars[cmd].str+1+
569                        strlen(ao_config_vars[cmd].str));
570 }
571
572 static void
573 ao_config_show(void) __reentrant
574 {
575         uint8_t cmd;
576         ao_config_get();
577         printf("Config version: %d.%d\n",
578                ao_config.major, ao_config.minor);
579         for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
580                 if (ao_config_vars[cmd].show)
581                         (*ao_config_vars[cmd].show)();
582 }
583
584 #if HAS_EEPROM
585 static void
586 ao_config_write(void) __reentrant
587 {
588         uint8_t saved = 0;
589         ao_mutex_get(&ao_config_mutex);
590         if (ao_config_dirty) {
591                 _ao_config_put();
592                 ao_config_dirty = 0;
593                 saved = 1;
594         }
595         ao_mutex_put(&ao_config_mutex);
596         if (saved)
597                 puts("Saved");
598         else
599                 puts("Nothing to save");
600 }
601 #endif
602
603 __code struct ao_cmds ao_config_cmds[] = {
604         { ao_config_set,        "c <var> <value>\0Set config (? for help, s to show)" },
605         { 0, NULL },
606 };
607
608 void
609 ao_config_init(void)
610 {
611         ao_cmd_register(&ao_config_cmds[0]);
612 }