Use a separate thread for flite rather than a separate program.
Save voice state to gconf.
Add filters for replay file selection
Signed-off-by: Keith Packard <keithp@keithp.com>
VERSION=$(shell git describe)
AM_CFLAGS=$(GNOME_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\" @FLITE_INCS@
-if USE_FLITE
-FLITE_PROG=aoview_flite
-endif
+bin_PROGRAMS=aoview
-bin_PROGRAMS=aoview $(FLITE_PROG) aoview_slowtelem
-
-aoview_LDADD=$(GNOME_LIBS)
+aoview_LDADD=$(GNOME_LIBS) $(FLITE_LIBS)
aoview_SOURCES = \
aoview_main.c \
aoview_voice.c \
aoview_replay.c \
aoview_label.c \
+ aoview_flite.c \
aoview.h
-aoview_flite_SOURCES = \
- aoview_flite.c
-
-aoview_slowtelem_SOURCES = \
- aoview_slowtelem.c
-
-aoview_flite_LDADD=@FLITE_LIBS@
-
BUILT_SOURCES = aoview_glade.h
CLEANFILES = aoview_glade.h
double distance;
double bearing;
+ int gps_height;
};
/* GPS is 'stable' when we've seen at least this many samples */
gboolean
aoview_monitor_parse(char *line);
+void
+aoview_monitor_reset(void);
+
struct aoview_serial *
aoview_serial_open(const char *tty);
void
aoview_label_show(struct aostate *state);
+/* aoview_flite.c */
+
+FILE *
+aoview_flite_start(void);
+
+void
+aoview_flite_stop(void);
+
#endif /* _AOVIEW_H_ */
#include <stdio.h>
#include <flite/flite.h>
+#include "aoview.h"
cst_voice *register_cmu_us_kal();
+static cst_voice *voice;
-int
-main(int argc, char **argv)
+static FILE *pipe_write;
+static GThread *aoview_flite_thread;
+
+gpointer
+aoview_flite_task(gpointer data)
{
+ FILE *input = data;
char line[1024];
- cst_voice *v;
- flite_init();
- v = register_cmu_us_kal();
- if (!v) {
- perror("register voice");
- exit(1);
+ while (fgets(line, sizeof (line) - 1, input) != NULL)
+ flite_text_to_speech(line, voice, "play");
+ return NULL;
+}
+
+void
+aoview_flite_stop(void)
+{
+ int status;
+ if (pipe_write) {
+ fclose(pipe_write);
+ pipe_write = NULL;
+ }
+ if (aoview_flite_thread) {
+ g_thread_join(aoview_flite_thread);
+ aoview_flite_thread = NULL;
}
- while (fgets(line, sizeof (line) - 1, stdin) != NULL) {
- flite_text_to_speech(line, v, "play");
+}
+
+FILE *
+aoview_flite_start(void)
+{
+ static once;
+ int p[2];
+ GError *error;
+ FILE *pipe_read;
+
+ if (!once) {
+ flite_init();
+ voice = register_cmu_us_kal();
+ if (!voice) {
+ perror("register voice");
+ exit(1);
+ }
}
- exit (0);
+ aoview_flite_stop();
+ pipe(p);
+ pipe_read = fdopen(p[0], "r");
+ pipe_write = fdopen(p[1], "w");
+ g_thread_create(aoview_flite_task, pipe_read, TRUE, &error);
+ return pipe_write;
}
gtk_main_quit();
}
+extern int _Xdebug;
+
int main(int argc, char **argv)
{
GladeXML *xml = NULL;
static struct option long_options[] = {
{ "device", 1, 0, 'd'},
+ { "sync", 0, 0, 's'},
{ 0, 0, 0, 0 }
};
for (;;) {
int c, temp;
- c = getopt_long_only(argc, argv, "d:", long_options, &temp);
+ c = getopt_long_only(argc, argv, "sd:", long_options, &temp);
if (c == -1)
break;
case 'd':
device = optarg;
break;
+ case 's':
+ _Xdebug = 1;
+ break;
default:
usage();
}
}
+ g_thread_init(NULL);
gtk_init(&argc, &argv);
glade_init();
aoview_label_init(xml);
+ aoview_voice_speak("rocket flight monitor ready\n");
+
gtk_main();
return 0;
aoview_serial_close(monitor_serial);
monitor_serial = NULL;
}
- aoview_table_clear();
aoview_log_new();
}
return TRUE;
}
+void
+aoview_monitor_reset(void)
+{
+ memset(&state, '\0', sizeof (state));
+}
+
static void
aoview_monitor_callback(gpointer user_data,
struct aoview_serial *serial,
monitor_serial = aoview_serial_open(tty);
if (!monitor_serial)
return FALSE;
+ aoview_table_clear();
+ aoview_monitor_reset();
aoview_serial_set_callback(monitor_serial,
aoview_monitor_callback,
monitor_serial,
gtk_widget_destroy(dialog);
} else {
replay_tick = -1;
+ aoview_monitor_reset();
aoview_replay_read(NULL);
}
gtk_widget_hide(GTK_WIDGET(replay_dialog));
void
aoview_replay_init(GladeXML *xml)
{
+ GtkFileFilter *telem_filter;
+ GtkFileFilter *all_filter;
+ GtkFileFilter *log_filter;
+
+ telem_filter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(telem_filter, "*.telem");
+ gtk_file_filter_set_name(telem_filter, "Telemetry Files");
+
+ log_filter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(log_filter, "*.log");
+ gtk_file_filter_set_name(log_filter, "Log Files");
+
+ all_filter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(all_filter, "*");
+ gtk_file_filter_set_name(all_filter, "All Files");
+
replay_dialog = GTK_FILE_CHOOSER(glade_xml_get_widget(xml, "ao_replay_dialog"));
assert(replay_dialog);
gtk_file_chooser_set_current_folder(replay_dialog, aoview_file_dir);
+ gtk_file_chooser_add_filter(replay_dialog, telem_filter);
+ gtk_file_chooser_add_filter(replay_dialog, log_filter);
+ gtk_file_chooser_add_filter(replay_dialog, all_filter);
replay_ok = glade_xml_get_widget(xml, "ao_replay_ok");
assert(replay_ok);
#include "aoview.h"
#include <math.h>
-static inline double sqr(a) { return a * a; };
+static inline double sqr(double a) { return a * a; };
static void
aoview_great_circle (double start_lat, double start_lon,
state->main_sense = state->main / 32767.0 * 15.0;
state->battery = state->batt / 32767.0 * 5.0;
if (!strcmp(state->state, "pad")) {
- if (state->locked) {
+ if (state->locked && state->nsat > 4) {
state->npad++;
state->pad_lat_total += state->lat;
state->pad_lon_total += state->lon;
state->max_height = state->height;
aoview_great_circle(state->pad_lat, state->pad_lon, state->lat, state->lon,
&state->distance, &state->bearing);
+ if (state->npad) {
+ state->gps_height = state->alt - state->pad_alt;
+ } else {
+ state->gps_height = 0;
+ }
}
void
state->flight_vel / 2700);
last_tick = state->tick;
last_altitude = this_altitude;
- printf ("report at tick %d height %d\n",
- state->tick, this_altitude);
}
}
if (state->locked) {
aoview_state_add_deg("Latitude", state->lat, 'N', 'S');
aoview_state_add_deg("Longitude", state->lon, 'E', 'W');
- aoview_table_add_row("GPS alt", "%d", state->alt);
+ aoview_table_add_row("GPS height", "%d", state->gps_height);
aoview_table_add_row("GPS time", "%02d:%02d:%02d",
state->gps_time.hour,
state->gps_time.minute,
aoview_state_init(GladeXML *xml)
{
aoview_state_new();
- aoview_voice_speak("initializing rocket flight monitoring system\n");
}
void aoview_voice_open(void)
{
if (!aoview_flite)
- aoview_flite = popen("aoview_flite", "w");
+ aoview_flite = aoview_flite_start();
}
void aoview_voice_close(void)
{
if (aoview_flite) {
- pclose(aoview_flite);
+ aoview_flite_stop();
aoview_flite = NULL;
}
}
static GtkCheckMenuItem *voice_enable;
+#define ALTOS_VOICE_PATH "/apps/aoview/voice"
+
static void
aoview_voice_enable(GtkWidget *widget, gpointer data)
{
- if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
+ gboolean enabled = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
+ GError *error;
+ GConfClient *gconf_client;
+
+ if (enabled) {
aoview_voice_open();
- aoview_voice_speak("enable voice system\n");
+ aoview_voice_speak("enable voice\n");
} else {
- aoview_voice_speak("disable voice system\n");
+ aoview_voice_speak("disable voice\n");
aoview_voice_close();
}
+ gconf_client = gconf_client_get_default();
+ gconf_client_set_bool(gconf_client,
+ ALTOS_VOICE_PATH,
+ enabled,
+ &error);
}
void
aoview_voice_init(GladeXML *xml)
{
- aoview_voice_open();
+ gboolean enabled;
+ GConfClient *gconf_client;
voice_enable = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(xml, "voice_enable"));
assert(voice_enable);
+ gconf_client = gconf_client_get_default();
+ enabled = TRUE;
+ if (gconf_client)
+ {
+ GError *error;
+
+ error = NULL;
+ enabled = gconf_client_get_bool(gconf_client,
+ ALTOS_VOICE_PATH,
+ &error);
+ if (error)
+ enabled = TRUE;
+ }
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(voice_enable), enabled);
+ if (enabled)
+ aoview_voice_open();
+
g_signal_connect(G_OBJECT(voice_enable), "toggled",
G_CALLBACK(aoview_voice_enable),
voice_enable);