+ }
+ state->ascent = FALSE;
+ for (i = 0; ascent_states[i]; i++)
+ if (!strcmp(data->state, ascent_states[i]))
+ state->ascent = TRUE;
+
+ /* Only look at accelerometer data on the way up */
+ if (state->ascent && state->acceleration > state->max_acceleration)
+ state->max_acceleration = state->acceleration;
+ if (state->ascent && state->speed > state->max_speed)
+ state->max_speed = state->speed;
+
+ if (state->height > state->max_height)
+ state->max_height = state->height;
+ if (data->locked) {
+ state->lat = data->lat;
+ state->lon = data->lon;
+ aoview_great_circle(state->pad_lat, state->pad_lon, data->lat, data->lon,
+ &state->distance, &state->bearing);
+ state->gps_valid = 1;
+ }
+ if (state->npad) {
+ state->gps_height = data->alt - state->pad_alt;
+ } else {
+ state->gps_height = 0;
+ }
+}
+
+void
+aoview_speak_state(struct aostate *state)
+{
+ if (strcmp(state->data.state, state->prev_data.state)) {
+ aoview_voice_speak("%s\n", state->data.state);
+ if (!strcmp(state->data.state, "drogue"))
+ aoview_voice_speak("apogee %d meters\n",
+ (int) state->max_height);
+ if (!strcmp(state->prev_data.state, "boost"))
+ aoview_voice_speak("max speed %d meters per second\n",
+ (int) state->max_speed);
+ }
+}
+
+void
+aoview_speak_height(struct aostate *state)
+{
+ aoview_voice_speak("%d meters\n", state->height);
+}
+
+struct aostate aostate;
+
+static guint aostate_timeout;
+
+#define COMPASS_LIMIT(n) ((n * 22.5) + 22.5/2)
+
+static char *compass_points[] = {
+ "north",
+ "north north east",
+ "north east",
+ "east north east",
+ "east",
+ "east south east",
+ "south east",
+ "south south east",
+ "south",
+ "south south west",
+ "south west",
+ "west south west",
+ "west",
+ "west north west",
+ "north west",
+ "north north west",
+};
+
+static char *
+aoview_compass_point(double bearing)
+{
+ int i;
+ while (bearing < 0)
+ bearing += 360.0;
+ while (bearing >= 360.0)
+ bearing -= 360.0;
+
+ i = floor ((bearing - 22.5/2) / 22.5 + 0.5);
+ if (i < 0) i = 0;
+ if (i >= sizeof (compass_points) / sizeof (compass_points[0]))
+ i = 0;
+ return compass_points[i];
+}
+
+static gboolean
+aoview_state_timeout(gpointer data)
+{
+ double now = aoview_time();
+
+ if (strlen(aostate.data.state) > 0 && strcmp(aostate.data.state, "pad") != 0)
+ aoview_speak_height(&aostate);
+ if (now - aostate.report_time >= 20 || !strcmp(aostate.data.state, "landed")) {
+ if (!aostate.ascent) {
+ if (fabs(aostate.baro_speed) < 20 && aostate.height < 100)
+ aoview_voice_speak("rocket landed safely\n");
+ else
+ aoview_voice_speak("rocket may have crashed\n");
+ if (aostate.gps_valid) {
+ aoview_voice_speak("rocket reported %s of pad distance %d meters\n",
+ aoview_compass_point(aostate.bearing),
+ (int) aostate.distance);
+ }