altos: Remove 8051 address space specifiers
[fw/altos] / src / kernel / ao_monitor.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 #include "ao.h"
20 #include "ao_telem.h"
21 #include "ao_flight.h"
22
23 #if !HAS_MONITOR
24 #error Must define HAS_MONITOR to 1
25 #endif
26
27 #ifndef LEGACY_MONITOR
28 #error Must define LEGACY_MONITOR
29 #endif
30
31 #ifndef HAS_MONITOR_PUT
32 #define HAS_MONITOR_PUT 1
33 #endif
34
35 #ifndef AO_MONITOR_LED
36 #error Must define AO_MONITOR_LED
37 #endif
38
39 uint8_t ao_monitoring_mutex;
40 uint8_t ao_monitoring;
41 static uint8_t ao_monitor_disabled;
42 static uint8_t ao_internal_monitoring;
43 static uint8_t ao_external_monitoring;
44
45 union ao_monitor ao_monitor_ring[AO_MONITOR_RING];
46
47 uint8_t ao_monitor_head;
48
49 static void
50 _ao_monitor_adjust(void)
51 {
52         if (ao_monitoring)
53                 ao_radio_recv_abort();
54         if (ao_monitor_disabled)
55                 ao_monitoring = 0;
56         else {
57                 if (ao_external_monitoring)
58                         ao_monitoring = ao_external_monitoring;
59                 else
60                         ao_monitoring = ao_internal_monitoring;
61         }
62         ao_wakeup(&ao_monitoring);
63 }
64
65 void
66 ao_monitor_get(void)
67 {
68         uint8_t size;
69
70         for (;;) {
71                 switch (ao_monitoring) {
72                 case 0:
73                         ao_sleep(&ao_monitoring);
74                         continue;
75 #if LEGACY_MONITOR
76                 case AO_MONITORING_ORIG:
77                         size = sizeof (struct ao_telemetry_orig_recv);
78                         break;
79 #endif
80                 default:
81                         if (ao_monitoring > AO_MAX_TELEMETRY)
82                                 ao_monitoring = AO_MAX_TELEMETRY;
83                         size = ao_monitoring;
84                         break;
85                 }
86                 if (!ao_radio_recv(&ao_monitor_ring[ao_monitor_head], size + 2, 0))
87                         continue;
88                 ao_monitor_head = ao_monitor_ring_next(ao_monitor_head);
89                 ao_wakeup(&ao_monitor_head);
90         }
91 }
92
93 #if AO_MONITOR_LED
94 struct ao_task ao_monitor_blink_task;
95
96 void
97 ao_monitor_blink(void)
98 {
99 #ifdef AO_MONITOR_BAD
100         uint8_t         *recv;
101 #endif
102         for (;;) {
103                 ao_sleep(&ao_monitor_head);
104 #ifdef AO_MONITOR_BAD
105                 recv = (uint8_t *) &ao_monitor_ring[ao_monitor_ring_prev(ao_monitor_head)];
106                 if (ao_monitoring && !(recv[ao_monitoring + 1] & AO_RADIO_STATUS_CRC_OK))
107                         ao_led_for(AO_MONITOR_BAD, AO_MS_TO_TICKS(100));
108                 else
109 #endif
110                         ao_led_for(AO_MONITOR_LED, AO_MS_TO_TICKS(100));
111         }
112 }
113 #endif
114
115 #if HAS_MONITOR_PUT
116
117 static const char xdigit[16] = {
118         '0', '1', '2', '3', '4', '5', '6', '7',
119         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
120 };
121
122 #define hex(c) do { putchar(xdigit[(c) >> 4]); putchar(xdigit[(c)&0xf]); } while (0)
123
124 void
125 ao_monitor_put(void)
126 {
127 #if LEGACY_MONITOR
128         char callsign[AO_MAX_CALLSIGN+1];
129 #endif
130 #if LEGACY_MONITOR || HAS_RSSI
131         int16_t rssi;
132 #endif
133         uint8_t ao_monitor_tail;
134         uint8_t state;
135         uint8_t sum, byte;
136         union ao_monitor        *m;
137
138 #define recv_raw        ((m->raw))
139 #define recv_orig       ((m->orig))
140 #define recv_tiny       ((m->tiny))
141
142         ao_monitor_tail = ao_monitor_head;
143         for (;;) {
144                 while (!ao_external_monitoring)
145                         ao_sleep(&ao_external_monitoring);
146                 while (ao_monitor_tail == ao_monitor_head && ao_external_monitoring)
147                         ao_sleep(&ao_monitor_head);
148                 if (!ao_external_monitoring)
149                         continue;
150                 m = &ao_monitor_ring[ao_monitor_tail];
151                 ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail);
152                 switch (ao_monitoring) {
153                 case 0:
154                         break;
155 #if LEGACY_MONITOR
156                 case AO_MONITORING_ORIG:
157                         state = recv_orig.telemetry_orig.flight_state;
158
159                         rssi = (int16_t) AO_RSSI_FROM_RADIO(recv_orig.rssi);
160                         ao_xmemcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN);
161                         if (state > ao_flight_invalid)
162                                 state = ao_flight_invalid;
163                         if (recv_orig.status & PKT_APPEND_STATUS_1_CRC_OK) {
164
165                                 /* General header fields */
166                                 printf(AO_TELEM_VERSION " %d "
167                                        AO_TELEM_CALL " %s "
168                                        AO_TELEM_SERIAL " %d "
169                                        AO_TELEM_FLIGHT " %d "
170                                        AO_TELEM_RSSI " %d "
171                                        AO_TELEM_STATE " %s "
172                                        AO_TELEM_TICK " %d ",
173                                        AO_TELEMETRY_VERSION,
174                                        callsign,
175                                        recv_orig.telemetry_orig.serial,
176                                        recv_orig.telemetry_orig.flight,
177                                        rssi,
178                                        ao_state_names[state],
179                                        recv_orig.telemetry_orig.adc.tick);
180
181                                 /* Raw sensor values */
182                                 printf(AO_TELEM_RAW_ACCEL " %d "
183                                        AO_TELEM_RAW_BARO " %d "
184                                        AO_TELEM_RAW_THERMO " %d "
185                                        AO_TELEM_RAW_BATT " %d "
186                                        AO_TELEM_RAW_DROGUE " %d "
187                                        AO_TELEM_RAW_MAIN " %d ",
188                                        recv_orig.telemetry_orig.adc.accel,
189                                        recv_orig.telemetry_orig.adc.pres,
190                                        recv_orig.telemetry_orig.adc.temp,
191                                        recv_orig.telemetry_orig.adc.v_batt,
192                                        recv_orig.telemetry_orig.adc.sense_d,
193                                        recv_orig.telemetry_orig.adc.sense_m);
194
195                                 /* Sensor calibration values */
196                                 printf(AO_TELEM_CAL_ACCEL_GROUND " %d "
197                                        AO_TELEM_CAL_BARO_GROUND " %d "
198                                        AO_TELEM_CAL_ACCEL_PLUS " %d "
199                                        AO_TELEM_CAL_ACCEL_MINUS " %d ",
200                                        recv_orig.telemetry_orig.ground_accel,
201                                        recv_orig.telemetry_orig.ground_pres,
202                                        recv_orig.telemetry_orig.accel_plus_g,
203                                        recv_orig.telemetry_orig.accel_minus_g);
204
205                                 if (recv_orig.telemetry_orig.u.k.unused == 0x8000) {
206                                         /* Kalman state values */
207                                         printf(AO_TELEM_KALMAN_HEIGHT " %d "
208                                                AO_TELEM_KALMAN_SPEED " %d "
209                                                AO_TELEM_KALMAN_ACCEL " %d ",
210                                                recv_orig.telemetry_orig.height,
211                                                recv_orig.telemetry_orig.u.k.speed,
212                                                recv_orig.telemetry_orig.accel);
213                                 } else {
214                                         /* Ad-hoc flight values */
215                                         printf(AO_TELEM_ADHOC_ACCEL " %d "
216                                                AO_TELEM_ADHOC_SPEED " %ld "
217                                                AO_TELEM_ADHOC_BARO " %d ",
218                                                recv_orig.telemetry_orig.accel,
219                                                recv_orig.telemetry_orig.u.flight_vel,
220                                                recv_orig.telemetry_orig.height);
221                                 }
222                                 ao_gps_print(&recv_orig.telemetry_orig.gps);
223                                 ao_gps_tracking_print(&recv_orig.telemetry_orig.gps_tracking);
224                                 putchar('\n');
225 #if HAS_RSSI
226                                 ao_rssi_set(rssi);
227 #endif
228                         } else {
229                                 printf("CRC INVALID RSSI %3d\n", rssi);
230                         }
231                         break;
232 #endif /* LEGACY_MONITOR */
233                 default:
234 #if AO_PROFILE
235                 {
236                         extern uint32_t ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
237                         extern uint32_t ao_fec_decode_start, ao_fec_decode_end;
238
239                         printf ("between packet: %d\n", ao_rx_start_tick - ao_rx_last_done_tick);
240                         printf ("receive start delay: %d\n", ao_rx_packet_tick - ao_rx_start_tick);
241                         printf ("decode time: %d\n", ao_fec_decode_end - ao_fec_decode_start);
242                         printf ("rx cleanup: %d\n", ao_rx_done_tick - ao_fec_decode_end);
243                 }
244 #endif
245                         ao_mutex_get(&ao_monitoring_mutex);
246                         printf("TELEM ");
247                         hex((uint8_t) (ao_monitoring + 2));
248                         sum = 0x5a;
249                         for (state = 0; state < ao_monitoring + 2; state++) {
250                                 byte = recv_raw.packet[state];
251                                 sum += byte;
252                                 hex(byte);
253                         }
254                         hex(sum);
255                         putchar ('\n');
256                         ao_mutex_put(&ao_monitoring_mutex);
257 #if HAS_RSSI
258                         if (recv_raw.packet[ao_monitoring + 1] & AO_RADIO_STATUS_CRC_OK) {
259                                 rssi = AO_RSSI_FROM_RADIO(recv_raw.packet[ao_monitoring]);
260                                 ao_rssi_set(rssi);
261                         }
262 #endif
263                         break;
264                 }
265                 ao_usb_flush();
266         }
267 }
268
269 struct ao_task ao_monitor_put_task;
270 #endif
271
272 struct ao_task ao_monitor_get_task;
273
274 void
275 ao_monitor_set(uint8_t monitoring)
276 {
277         ao_internal_monitoring = monitoring;
278         _ao_monitor_adjust();
279 }
280
281 void
282 ao_monitor_disable(void)
283 {
284         ++ao_monitor_disabled;
285         _ao_monitor_adjust();
286 }
287
288 void
289 ao_monitor_enable(void)
290 {
291         --ao_monitor_disabled;
292         _ao_monitor_adjust();
293 }
294
295 #if HAS_MONITOR_PUT
296 static void
297 set_monitor(void)
298 {
299         ao_cmd_hex();
300         ao_external_monitoring = ao_cmd_lex_i;
301         ao_wakeup(&ao_external_monitoring);
302         ao_wakeup(&ao_monitor_head);
303         _ao_monitor_adjust();
304 }
305
306 const struct ao_cmds ao_monitor_cmds[] = {
307         { set_monitor,  "m <0 off, 1 old, 20 std>\0Set radio monitoring" },
308         { 0,    NULL },
309 };
310 #endif
311
312 void
313 ao_monitor_init(void) 
314 {
315 #if HAS_MONITOR_PUT
316         ao_cmd_register(&ao_monitor_cmds[0]);
317         ao_add_task(&ao_monitor_put_task, ao_monitor_put, "monitor_put");
318 #endif
319         ao_add_task(&ao_monitor_get_task, ao_monitor_get, "monitor_get");
320 #if AO_MONITOR_LED
321         ao_add_task(&ao_monitor_blink_task, ao_monitor_blink, "monitor_blink");
322 #endif
323 }