Switch from GPLv2 to GPLv2+
[fw/altos] / src / kernel / ao_log_tiny.c
1 /*
2  * Copyright © 2011 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
21 static __data uint16_t  ao_log_tiny_interval;
22
23 #define AO_LOG_TINY_INTERVAL_DEFAULT    AO_MS_TO_TICKS(1000)
24 #if USE_FAST_ASCENT_LOG
25 #define AO_LOG_TINY_INTERVAL_ASCENT     AO_MS_TO_TICKS(100)
26 #define AO_PAD_RING     8
27 #else
28 #define AO_LOG_TINY_INTERVAL_ASCENT     AO_LOG_TINY_INTERVAL_DEFAULT
29 #define AO_PAD_RING     2
30 #endif
31
32 __code uint8_t ao_log_format = AO_LOG_FORMAT_TINY;
33
34 void
35 ao_log_tiny_set_interval(uint16_t ticks)
36 {
37         ao_log_tiny_interval = ticks;
38 }
39
40
41 static void ao_log_tiny_data(uint16_t d)
42 {
43         if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
44                 ao_log_stop();
45         if (ao_log_running) {
46                 ao_storage_write(ao_log_current_pos, DATA_TO_XDATA(&d), 2);
47                 ao_log_current_pos += 2;
48         }
49 }
50
51 static __xdata uint16_t ao_log_pad_ring[AO_PAD_RING];
52 static __pdata uint8_t ao_log_pad_ring_pos;
53
54 #define ao_pad_ring_next(n)     (((n) + 1) & (AO_PAD_RING - 1))
55
56 static void ao_log_tiny_queue(uint16_t d)
57 {
58         ao_log_pad_ring[ao_log_pad_ring_pos] = d;
59         ao_log_pad_ring_pos = ao_pad_ring_next(ao_log_pad_ring_pos);
60 }
61
62 static void ao_log_tiny_start(void)
63 {
64         uint8_t         p;
65         uint16_t        d;
66
67         ao_log_tiny_data(ao_flight_number);
68         ao_log_tiny_data(ao_ground_pres);
69         p = ao_log_pad_ring_pos;
70         do {
71                 d = ao_log_pad_ring[p];
72                 /*
73                  * ignore unwritten slots
74                  */
75                 if (d)
76                         ao_log_tiny_data(d);
77                 p = ao_pad_ring_next(p);
78         } while (p != ao_log_pad_ring_pos);
79 }
80
81 void
82 ao_log(void)
83 {
84         uint16_t                last_time;
85         uint16_t                now;
86         enum ao_flight_state    ao_log_tiny_state;
87         int32_t                 sum;
88         int16_t                 count;
89         uint8_t                 ao_log_data;
90         uint8_t                 ao_log_started = 0;
91
92         ao_storage_setup();
93
94         ao_log_scan();
95
96         ao_log_tiny_state = ao_flight_invalid;
97         ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
98         sum = 0;
99         count = 0;
100         ao_log_data = ao_sample_data;
101         last_time = ao_time();
102         for (;;) {
103
104                 /*
105                  * Add in pending sample data
106                  */
107                 ao_sleep(DATA_TO_XDATA(&ao_sample_data));
108                 while (ao_log_data != ao_sample_data) {
109                         sum += ao_data_pres(&ao_data_ring[ao_log_data]);
110                         count++;
111                         ao_log_data = ao_data_ring_next(ao_log_data);
112                 }
113                 if (ao_log_running) {
114                         if (!ao_log_started) {
115                                 ao_log_tiny_start();
116                                 ao_log_started = 1;
117                         }
118                         if (ao_flight_state != ao_log_tiny_state) {
119                                 ao_log_tiny_data(ao_flight_state | 0x8000);
120                                 ao_log_tiny_state = ao_flight_state;
121                                 ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_DEFAULT;
122 #if AO_LOG_TINY_INTERVAL_ASCENT != AO_LOG_TINY_INTERVAL_DEFAULT
123                                 if (ao_log_tiny_state <= ao_flight_coast)
124                                         ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
125 #endif
126                                 if (ao_log_tiny_state == ao_flight_landed)
127                                         ao_log_stop();
128                         }
129                 }
130
131                 /* Stop logging when told to */
132                 if (!ao_log_running && ao_log_started)
133                         ao_exit();
134
135                 /*
136                  * Write out the sample when finished
137                  */
138                 now = ao_time();
139                 if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) {
140                         count = sum / count;
141                         if (ao_log_started)
142                                 ao_log_tiny_data(count);
143                         else
144                                 ao_log_tiny_queue(count);
145                         sum = 0;
146                         count = 0;
147                         last_time = now;
148                 }
149         }
150 }
151
152 uint16_t
153 ao_log_flight(uint8_t slot)
154 {
155         static __xdata uint16_t flight;
156
157         (void) slot;
158         ao_storage_read(0, &flight, 2);
159         if (flight == 0xffff)
160                 flight = 0;
161         return flight;
162 }