2 * Copyright © 2011 Keith Packard <keithp@keithp.com>
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.
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.
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.
27 static const struct option options[] = {
28 { .name = "tty", .has_arg = 1, .val = 'T' },
29 { .name = "device", .has_arg = 1, .val = 'D' },
30 { .name = "frequency", .has_arg = 1, .val = 'F' },
31 { .name = "realtime", .has_arg = 0, .val = 'R' },
35 static void usage(char *program)
37 fprintf(stderr, "usage: %s [--tty <tty-name>] [--device <device-name>] [--frequency <kHz>] [--realtime] file.telem ...\n", program);
41 #define bool(b) ((b) ? "true" : "false")
43 struct ao_telem_list {
44 struct ao_telem_list *next;
45 union ao_telemetry_all telem;
48 static struct ao_telem_list *telem_list, **telem_last;
51 trim_telem(uint16_t time)
53 while (telem_list && (int16_t) (time - telem_list->telem.generic.tick) > 0) {
54 struct ao_telem_list *next = telem_list->next;
59 telem_last = &telem_list;
63 add_telem(union ao_telemetry_all *telem)
65 struct ao_telem_list *new = malloc (sizeof (struct ao_telem_list));
66 trim_telem((uint16_t) (telem->generic.tick - 20 * 100));
70 telem_last = &new->next;
73 static enum ao_flight_state cur_state = ao_flight_invalid;
74 static enum ao_flight_state last_state = ao_flight_invalid;
76 static enum ao_flight_state
77 packet_state(union ao_telemetry_all *telem)
79 switch (telem->generic.type) {
80 case AO_TELEMETRY_SENSOR_TELEMETRUM:
81 case AO_TELEMETRY_SENSOR_TELEMINI:
82 case AO_TELEMETRY_SENSOR_TELENANO:
83 cur_state = telem->sensor.state;
85 case AO_TELEMETRY_MEGA_DATA:
86 cur_state = telem->mega_data.state;
88 case AO_TELEMETRY_METRUM_SENSOR:
89 cur_state = telem->metrum_sensor.state;
91 case AO_TELEMETRY_MINI:
92 cur_state = telem->mini.state;
98 static const char *state_names[] = {
112 send_telem(struct cc_usb *cc, union ao_telemetry_all *telem)
114 int rssi = (int8_t) telem->generic.rssi / 2 - 74;
119 if (cur_state != last_state) {
120 if (0 <= cur_state && cur_state < sizeof(state_names) / sizeof (state_names[0]))
121 printf ("%s\n", state_names[cur_state]);
122 last_state = cur_state;
124 cc_usb_printf(cc, "S 20\n");
125 b = (uint8_t *) telem;
126 for (i = 0; i < 0x20; i++)
127 cc_usb_printf(cc, "%02x", b[i]);
132 do_delay(uint16_t now, uint16_t then)
134 int16_t delay = (int16_t) (now - then);
136 if (delay > 0 && delay < 1000)
137 usleep(delay * 10 * 1000);
141 send_queued(struct cc_usb *cc, int pause)
143 struct ao_telem_list *next;
148 if (started && pause)
149 do_delay(telem_list->telem.generic.tick, tick);
150 tick = telem_list->telem.generic.tick;
152 send_telem(cc, &telem_list->telem);
154 next = telem_list->next;
162 main (int argc, char **argv)
178 while ((c = getopt_long(argc, argv, "RT:D:F:", options, NULL)) != -1) {
198 tty = cc_usbdevs_find_by_arg(device, "TeleDongle");
200 tty = getenv("ALTOS_TTY");
203 cc = cc_usb_open(tty);
207 cc_usb_printf(cc, "m 0\n");
208 cc_usb_printf(cc, "c F %d\n", freq);
209 for (i = optind; i < argc; i++) {
210 file = fopen(argv[i], "r");
218 while (fgets(line, sizeof (line), file)) {
219 union ao_telemetry_all telem;
221 if (cc_telemetry_parse(line, &telem)) {
223 * Skip packets with CRC errors.
225 if ((telem.generic.status & (1 << 7)) == 0)
229 do_delay(telem.generic.tick, last_tick);
230 last_tick = telem.generic.tick;
231 send_telem(cc, &telem);
233 enum ao_flight_state state = packet_state(&telem);
235 if (ao_flight_pad < state && state < ao_flight_landed) {
236 printf ("started\n");
238 last_tick = send_queued(cc, realtime);