altos/micropeak-v2: Erase log space at end of BOOST_DELAY
[fw/altos] / src / micropeak-v2.0 / ao_micropeak.c
1 /*
2  * Copyright © 2017 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20 #include <ao_exti.h>
21 #include <ao_micropeak.h>
22 #include <ao_report_micro.h>
23 #include <ao_log_micro.h>
24 #include <ao_storage.h>
25
26 static struct ao_ms5607_value   value;
27
28 alt_t           ground_alt, max_alt;
29 alt_t           ao_max_height;
30
31 void
32 ao_pa_get(void)
33 {
34         ao_ms5607_sample(&ao_ms5607_current);
35         ao_ms5607_convert(&ao_ms5607_current, &value);
36         pa = value.pres;
37 }
38
39 static void
40 ao_compute_height(void)
41 {
42         ground_alt = ao_pa_to_altitude(pa_ground);
43         max_alt = ao_pa_to_altitude(pa_min);
44         ao_max_height = max_alt - ground_alt;
45 }
46
47 static void
48 ao_pips(void)
49 {
50         uint8_t i;
51         for (i = 0; i < 10; i++) {
52                 ao_led_toggle(AO_LED_REPORT);
53                 ao_delay(AO_MS_TO_TICKS(80));
54         }
55         ao_delay(AO_MS_TO_TICKS(200));
56 }
57
58 void
59 ao_delay_until(uint16_t target) {
60         int16_t delay = target - ao_time();
61         if (delay > 0) {
62                 ao_sleep_for(ao_delay_until, delay);
63         }
64 }
65
66 static struct ao_task mp_task;
67
68 static void
69 ao_battery_disable(void)
70 {
71         /* Disable */
72         if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) {
73                 stm_adc.cr |= (1 << STM_ADC_CR_ADDIS);
74                 while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS))
75                         ;
76         }
77
78         /* Turn off everything */
79         stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) |
80                         (1 << STM_ADC_CR_ADSTP) |
81                         (1 << STM_ADC_CR_ADSTART) |
82                         (1 << STM_ADC_CR_ADEN));
83 }
84
85 static void
86 ao_battery_init(void)
87 {
88         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADCEN);
89
90         ao_battery_disable();
91
92         /* Configure */
93         stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) |                             /* analog watchdog channel 0 */
94                          (0 << STM_ADC_CFGR1_AWDEN) |                             /* Disable analog watchdog */
95                          (0 << STM_ADC_CFGR1_AWDSGL) |                            /* analog watchdog on all channels */
96                          (0 << STM_ADC_CFGR1_DISCEN) |                            /* Not discontinuous mode. All channels converted with one trigger */
97                          (0 << STM_ADC_CFGR1_AUTOOFF) |                           /* Leave ADC running */
98                          (1 << STM_ADC_CFGR1_WAIT) |                              /* Wait for data to be read before next conversion */
99                          (0 << STM_ADC_CFGR1_CONT) |                              /* only one set of conversions per trigger */
100                          (1 << STM_ADC_CFGR1_OVRMOD) |                            /* overwrite on overrun */
101                          (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) |   /* SW trigger */
102                          (0 << STM_ADC_CFGR1_ALIGN) |                             /* Align to LSB */
103                          (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) |            /* 12 bit resolution */
104                          (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) |    /* scan 0 .. n */
105                          (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */
106                          (1 << STM_ADC_CFGR1_DMAEN));                             /* enable DMA */
107
108         /* Set the clock */
109         stm_adc.cfgr2 = STM_ADC_CFGR2_CKMODE_PCLK_2 << STM_ADC_CFGR2_CKMODE;
110
111         /* Shortest sample time */
112         stm_adc.smpr = STM_ADC_SMPR_SMP_71_5 << STM_ADC_SMPR_SMP;
113
114         /* Select Vref */
115         stm_adc.chselr = 1 << 17;
116
117         stm_adc.ccr = ((0 << STM_ADC_CCR_VBATEN) |
118                        (0 << STM_ADC_CCR_TSEN) |
119                        (1 << STM_ADC_CCR_VREFEN));
120
121         /* Calibrate */
122         stm_adc.cr |= (1 << STM_ADC_CR_ADCAL);
123         while ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) != 0)
124                 ;
125
126         /* Enable */
127         stm_adc.cr |= (1 << STM_ADC_CR_ADEN);
128         while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0)
129                 ;
130
131         /* Clear any stale status bits */
132         stm_adc.isr = 0;
133
134         /* Turn on syscfg */
135         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN);
136 }
137
138 static void
139 ao_battery_fini(void)
140 {
141         /* Disable */
142         ao_battery_disable();
143
144         /* Power down */
145         stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_ADCEN);
146 }
147
148 static uint16_t
149 ao_battery_voltage(void)
150 {
151         uint16_t        vrefint;
152
153         ao_battery_init();
154
155         stm_adc.cr |= (1 << STM_ADC_CR_ADSTART);
156
157         while ((stm_adc.isr & (1 << STM_ADC_ISR_EOC)) == 0)
158                 ao_arch_nop();
159
160         vrefint = stm_adc.dr;
161
162         ao_battery_fini();
163
164         return 330 * stm_cal.vrefint_cal / vrefint;
165 }
166
167 static void
168 ao_log_erase(void)
169 {
170         uint32_t        pos;
171         for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
172                 ao_storage_erase(pos);
173 }
174
175 uint8_t ao_on_battery;
176
177 static void
178 ao_micropeak(void)
179 {
180         ao_ms5607_setup();
181
182         /* Give the person a second to get their finger out of the way */
183         ao_delay(AO_MS_TO_TICKS(1000));
184
185         ao_log_micro_restore();
186         ao_compute_height();
187         ao_report_altitude();
188
189         ao_pips();
190
191         ao_log_micro_dump();
192
193 #if BOOST_DELAY
194         ao_delay(BOOST_DELAY);
195 #endif
196         ao_log_erase();
197
198         ao_microflight();
199
200         ao_log_micro_save();
201         ao_compute_height();
202         ao_report_altitude();
203
204         ao_sleep_mode();
205         ao_sleep(&ao_on_battery);
206 }
207
208 static void
209 ao_show_bat(void)
210 {
211         printf("battery: %u\n", ao_battery_voltage());
212 }
213
214 uint8_t
215 ao_log_present(void)
216 {
217         uint16_t        n_samples;
218
219         ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
220
221         return n_samples != 0xffff;
222 }
223
224 static void
225 ao_log_list(void)
226 {
227         if (ao_log_present())
228                 printf ("flight %d start %x end %x\n",
229                         1,
230                         0, MAX_LOG_OFFSET >> 8);
231         printf ("done\n");
232 }
233
234 static void
235 ao_log_delete(void)
236 {
237         int16_t cmd_flight = 1;
238
239         ao_cmd_white();
240         if (ao_cmd_lex_c == '-') {
241                 cmd_flight = -1;
242                 ao_cmd_lex();
243         }
244         cmd_flight *= ao_cmd_decimal();
245         if (ao_cmd_status != ao_cmd_success)
246                 return;
247
248         /* Look for the flight log matching the requested flight */
249         if (cmd_flight == 1 && ao_log_present()) {
250                 ao_log_erase();
251                 puts("Erased");
252                 return;
253         }
254         printf("No such flight: %d\n", cmd_flight);
255 }
256
257 static struct ao_cmds mp_cmd[] = {
258         { ao_log_list,  "l\0List logs" },
259         { ao_log_delete,        "d <flight-number>\0Delete flight" },
260         { ao_show_bat, "b\0Show battery voltage" },
261         { 0 }
262 };
263
264 static void
265 ao_hsi_init(void)
266 {
267         uint32_t        cfgr;
268
269         /* Disable all interrupts */
270         stm_rcc.cir = 0;
271
272         /* Enable prefetch */
273         stm_flash.acr |= (1 << STM_FLASH_ACR_PRFTBE);
274
275         /* Enable power interface clock */
276         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
277
278         /* HCLK to 48MHz -> AHB prescaler = /1 */
279         cfgr = stm_rcc.cfgr;
280         cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE);
281         cfgr |= (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE);
282         stm_rcc.cfgr = cfgr;
283         while ((stm_rcc.cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) !=
284                (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE))
285                 ao_arch_nop();
286
287         /* APB Prescaler = AO_APB_PRESCALER */
288         cfgr = stm_rcc.cfgr;
289         cfgr &= ~(STM_RCC_CFGR_PPRE_MASK << STM_RCC_CFGR_PPRE);
290         cfgr |= (AO_RCC_CFGR_PPRE_DIV << STM_RCC_CFGR_PPRE);
291         stm_rcc.cfgr = cfgr;
292
293         /* Clear reset flags */
294         stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF);
295 }
296
297 void
298 main(void)
299 {
300         int i;
301
302         for (i = 0; i < 100000; i++)
303                 ao_arch_nop();
304
305         if (ao_battery_voltage() < 320)
306                 ao_on_battery = 1;
307
308         /* Leave the system running on the HSI if we're on battery */
309         if (!ao_on_battery)
310                 ao_clock_init();
311         else
312                 ao_hsi_init();
313
314         ao_led_init();
315         ao_task_init();
316         ao_timer_init();
317         ao_serial_init();
318         stm_moder_set(&stm_gpioa, 2, STM_MODER_OUTPUT);
319         ao_dma_init();
320         ao_spi_init();
321         ao_exti_init();
322
323         ao_storage_setup();
324
325         ao_ms5607_init();
326         ao_storage_init();
327
328         if (ao_on_battery) {
329                 /* On battery power, run the flight code */
330                 ao_add_task(&mp_task, ao_micropeak, "micropeak");
331         } else {
332                 /* otherwise, turn on USB and run the command processor */
333                 ao_usb_init();
334                 ao_cmd_init();
335                 ao_cmd_register(mp_cmd);
336                 ao_config_init();
337         }
338         ao_start_scheduler();
339 }