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