From: Keith Packard Date: Fri, 4 Sep 2009 20:00:02 +0000 (-0700) Subject: Move usb scanning code to ao-tools library X-Git-Tag: debian/0.5+77+gc57bd7f~29 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=0c771d999914f9d17c723900f2987acc45fd0fbb Move usb scanning code to ao-tools library This will allow the scanning code to be used by the command line tools as well as the ao-view GUI. Now that ao-view depends on the ao-tools library, it has been moved to the ao-tools directory as well. Signed-off-by: Keith Packard --- diff --git a/INSTALL b/INSTALL index 8b82ade0..2550dab7 100644 --- a/INSTALL +++ b/INSTALL @@ -2,7 +2,7 @@ Installation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, -2006, 2007, 2008 Free Software Foundation, Inc. +2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. @@ -159,7 +159,7 @@ Particular systems CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: - ./configure CC="cc -Ae" + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. @@ -174,6 +174,16 @@ and if that doesn't work, try ./configure CC="cc -nodtk" + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + Specifying the System Type ========================== @@ -189,7 +199,8 @@ type, such as `sun4', or a canonical name which has the form: where SYSTEM can have one of these forms: - OS KERNEL-OS + OS + KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't diff --git a/Makefile.am b/Makefile.am index 96b9dea9..39e7c244 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=src ao-view ao-tools ao-utils +SUBDIRS=src ao-tools ao-utils EXTRA_DIST = ChangeLog diff --git a/ao-tools/Makefile.am b/ao-tools/Makefile.am index 98b88f38..02b4785e 100644 --- a/ao-tools/Makefile.am +++ b/ao-tools/Makefile.am @@ -1 +1 @@ -SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-load +SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-load ao-view diff --git a/ao-tools/ao-view/.gitignore b/ao-tools/ao-view/.gitignore new file mode 100644 index 00000000..24fbc596 --- /dev/null +++ b/ao-tools/ao-view/.gitignore @@ -0,0 +1,4 @@ +*.o +aoview +aoview_glade.h +aoview_flite diff --git a/ao-tools/ao-view/Makefile.am b/ao-tools/ao-view/Makefile.am new file mode 100644 index 00000000..7b274a40 --- /dev/null +++ b/ao-tools/ao-view/Makefile.am @@ -0,0 +1,37 @@ +VERSION=$(shell git describe) + +AO_VIEW_CFLAGS=-I$(top_srcdir)/ao-tools/lib +AO_VIEW_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a +AM_CFLAGS=$(AO_VIEW_CFLAGS) $(GNOME_CFLAGS) $(ALSA_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\" @FLITE_INCS@ + +bin_PROGRAMS=ao-view + +ao_view_DEPENDENCIES=$(AO_VIEW_LIBS) +ao_view_LDADD=$(GNOME_LIBS) $(FLITE_LIBS) $(ALSA_LIBS) $(AO_VIEW_LIBS) $(LIBUSB_LIBS) + +ao_view_SOURCES = \ + aoview_main.c \ + aoview_dev_dialog.c \ + aoview_serial.c \ + aoview_monitor.c \ + aoview_state.c \ + aoview_convert.c \ + aoview_log.c \ + aoview_table.c \ + aoview_util.c \ + aoview_file.c \ + aoview_eeprom.c \ + aoview_voice.c \ + aoview_replay.c \ + aoview_label.c \ + aoview_flite.c \ + aoview.h + +BUILT_SOURCES = aoview_glade.h + +CLEANFILES = aoview_glade.h + +man_MANS=ao-view.1 + +aoview_glade.h: aoview.glade + sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/"/' $< > $@ diff --git a/ao-tools/ao-view/ao-view.1 b/ao-tools/ao-view/ao-view.1 new file mode 100644 index 00000000..99834c4e --- /dev/null +++ b/ao-tools/ao-view/ao-view.1 @@ -0,0 +1,50 @@ +.\" +.\" Copyright © 2009 Keith Packard +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, but +.\" WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +.\" General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License along +.\" with this program; if not, write to the Free Software Foundation, Inc., +.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +.\" +.\" +.TH AO-VIEW 1 "ao-view" "" +.SH NAME +ao-view \- Rocket flight monitor +.SH SYNOPSIS +.B "ao-view" +[\--tty \fItty-device\fP] +.SH DESCRIPTION +.I ao-view +connects to a TeleDongle or TeleMetrum device through a USB serial device. +It provides a user interface to monitor, record and review rocket flight data. +.SH OPTIONS +The usual Gtk+ command line options can be used, along with +.IP "\--tty" +This selects a target device to connect at startup time to. +The target device may also be selected through the user interface. +.SH USAGE +When connected to a TeleDongle device, ao-view turns on the radio +receiver and listens for telemetry packets. It displays the received +telemetry data, and reports flight status via voice synthesis. All +received telemetry information is recorded to a file. +.P +When connected to a TeleMetrum device, ao-view downloads the eeprom +data and stores it in a file. +.SH FILES +All data log files are recorded into a user-specified directory +(default ~/AltOS). Files are named using the current date, the serial +number of the reporting device, the flight number recorded in the data +and either '.telem' for telemetry data or '.eeprom' for eeprom data. +.SH "SEE ALSO" +ao-load(1), ao-eeprom(1) +.SH AUTHOR +Keith Packard diff --git a/ao-tools/ao-view/aoview.glade b/ao-tools/ao-view/aoview.glade new file mode 100644 index 00000000..9a746110 --- /dev/null +++ b/ao-tools/ao-view/aoview.glade @@ -0,0 +1,744 @@ + + + + + + 900 + 700 + True + AltOS View + + + True + vertical + + + True + + + True + _File + True + + + True + + + gtk-new + True + True + True + + + + + gtk-open + True + True + True + + + + + gtk-save + True + True + True + + + + + gtk-save-as + True + True + True + + + + + True + + + + + gtk-quit + True + True + True + + + + + + + + + + True + _Edit + True + + + True + + + gtk-cut + True + True + True + + + + + gtk-copy + True + True + True + + + + + gtk-paste + True + True + True + + + + + gtk-delete + True + True + True + + + + + + + + + True + _Device + True + + + True + + + _Connect to device + True + True + False + + + + + True + gtk-connect + + + + + + + _Disconnect + True + True + False + + + True + gtk-disconnect + + + + + + + True + False + + + + + _Save EEPROM data + True + True + False + + + + + True + gtk-save + + + + + + + _Replay + True + True + False + + + + + True + gtk-media-play + + + + + + + + + + + True + _Log + True + + + True + + + _New log + True + True + False + + + True + gtk-new + + + + + + + _Configure Log + True + True + False + + + + True + gtk-preferences + + + + + + + + + + + True + _Voice + True + + + True + + + True + Enable _Voice + True + True + + + + + + + + + True + _Help + True + + + True + + + gtk-about + True + True + True + + + + + + + + + + False + 0 + + + + + True + 2 + 4 + 3 + True + + + True + Height (m) + center + + + + + True + State + + + 1 + 2 + + + + + True + RSSI (dBm) + + + 2 + 3 + + + + + True + 2 + 0 + True + + + 1 + 2 + + + + + True + 2 + pad + True + + + 1 + 2 + 1 + 2 + + + + + True + 2 + -50 + True + + + 2 + 3 + 1 + 2 + + + + + True + Speed (m/s) + + + 3 + 4 + + + + + True + 0 + True + + + 3 + 4 + 1 + 2 + + + + + False + 1 + + + + + True + + + True + True + False + both + + + 0 + + + + + True + True + False + both + + + 1 + + + + + True + True + False + both + + + 2 + + + + + 2 + + + + + + + 5 + normal + False + + + True + vertical + 2 + + + 300 + 100 + True + True + False + True + 0 + False + 1 + both + True + + + 1 + + + + + True + end + + + gtk-cancel + 1 + True + True + True + True + True + + + + False + False + 0 + + + + + gtk-connect + True + True + True + True + True + True + + + False + False + 1 + + + + + False + end + 0 + + + + + + + 5 + Configure Log Directory + dialog + False + select-folder + + + True + vertical + 2 + + + True + end + + + gtk-cancel + True + True + True + True + + + + False + False + 0 + + + + + gtk-ok + True + True + True + True + True + True + + + False + False + 1 + + + + + False + end + 0 + + + + + + + 5 + Failed to create log + normal + True + aoview + error + close + Cannot create log file + + + True + vertical + 2 + + + True + end + + + False + end + 0 + + + + + + + 5 + Failed to open device + normal + True + aoview + error + close + Cannot open device + + + True + vertical + 2 + + + True + end + + + False + end + 0 + + + + + + + 5 + About AoView + False + normal + aoview + False + AoView + Copyright © 2009 Keith Packard + AltOS data capture and display. + http://altusmetrum.org + AoView is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. + +AoView is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with AoView; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + Keith Packard <keithp@keithp.com> + True + + + + + True + vertical + 2 + + + True + end + + + False + end + 0 + + + + + + + 5 + EEPROM save complete + normal + True + aoview + close + Saving EEPROM data as + <filename> + + + + + True + vertical + 2 + + + True + end + + + False + end + 0 + + + + + + + 5 + True + dialog + True + aoview + False + + + True + vertical + 2 + + + True + end + + + gtk-cancel + True + True + True + True + + + + False + False + 0 + + + + + gtk-ok + True + True + True + True + + + False + False + 1 + + + + + False + end + 0 + + + + + + diff --git a/ao-tools/ao-view/aoview.h b/ao-tools/ao-view/aoview.h new file mode 100644 index 00000000..6a4753ac --- /dev/null +++ b/ao-tools/ao-view/aoview.h @@ -0,0 +1,323 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AOVIEW_H_ +#define _AOVIEW_H_ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cc.h" + +#include +#include +#include + +struct aogps_time { + int hour; + int minute; + int second; +}; + +struct aogps { + int nsat; + int gps_locked; + int gps_connected; + struct aogps_time gps_time; + double lat; /* degrees (+N -S) */ + double lon; /* degrees (+E -W) */ + int alt; /* m */ + + int gps_extended; /* has extra data */ + double ground_speed; /* m/s */ + int course; /* degrees */ + double climb_rate; /* m/s */ + double hdop; /* unitless? */ + int h_error; /* m */ + int v_error; /* m */ +}; + +#define SIRF_SAT_STATE_ACQUIRED (1 << 0) +#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1) +#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2) +#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3) +#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4) +#define SIRF_SAT_CODE_LOCKED (1 << 5) +#define SIRF_SAT_ACQUISITION_FAILED (1 << 6) +#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7) + +struct aogps_sat { + int svid; + int state; + int c_n0; +}; + +struct aogps_tracking { + int channels; + struct aogps_sat sats[12]; +}; + +struct aodata { + char callsign[16]; + int serial; + int rssi; + char state[16]; + int tick; + int accel; + int pres; + int temp; + int batt; + int drogue; + int main; + int flight_accel; + int ground_accel; + int flight_vel; + int flight_pres; + int ground_pres; + struct aogps gps; + struct aogps_tracking gps_tracking; +}; + +struct aostate { + struct aodata data; + + /* derived data */ + + struct aodata prev_data; + + double report_time; + + gboolean ascent; /* going up? */ + + int ground_altitude; + int height; + double speed; + double acceleration; + double battery; + double temperature; + double main_sense; + double drogue_sense; + double baro_speed; + + int max_height; + double max_acceleration; + double max_speed; + + struct aogps gps; + struct aogps_tracking gps_tracking; + + int gps_valid; + double pad_lat; + double pad_lon; + double pad_alt; + double pad_lat_total; + double pad_lon_total; + double pad_alt_total; + int npad; + int prev_npad; + + double distance; + double bearing; + int gps_height; + + int speak_tick; + int speak_altitude; +}; + +extern struct aostate aostate; + +/* GPS is 'stable' when we've seen at least this many samples */ +#define MIN_PAD_SAMPLES 10 + +void +aoview_monitor_disconnect(void); + +gboolean +aoview_monitor_connect(char *tty); + +gboolean +aoview_monitor_parse(const char *line); + +void +aoview_monitor_reset(void); + +struct aoview_serial * +aoview_serial_open(const char *tty); + +void +aoview_serial_close(struct aoview_serial *serial); + +typedef void (*aoview_serial_callback)(gpointer user_data, struct aoview_serial *serial, gint revents); + +void +aoview_serial_set_callback(struct aoview_serial *serial, + aoview_serial_callback func); + +void +aoview_serial_printf(struct aoview_serial *serial, char *format, ...); + +int +aoview_serial_read(struct aoview_serial *serial, char *buf, int len); + +int +aoview_serial_getc(struct aoview_serial *serial); + +void +aoview_dev_dialog_init(GladeXML *xml); + +void +aoview_state_notify(struct aodata *data); + +void +aoview_state_new(void); + +void +aoview_state_init(GladeXML *xml); + +int16_t +aoview_pres_to_altitude(int16_t pres); + +int16_t +aoview_altitude_to_pres(int16_t alt); + +char * +aoview_fullname (char *dir, char *file); + +char * +aoview_basename(char *file); + +GtkTreeViewColumn * +aoview_add_plain_text_column (GtkTreeView *view, const gchar *title, gint model_column, gint width); + +int +aoview_mkdir(char *dir); + +void +aoview_log_init(GladeXML *xml); + +void +aoview_log_set_serial(int serial); + +int +aoview_log_get_serial(void); + +void +aoview_log_printf(char *format, ...); + +void +aoview_log_new(void); + +void +aoview_table_start(void); + +void +aoview_table_add_row(int column, char *label, char *format, ...); + +void +aoview_table_finish(void); + +void +aoview_table_init(GladeXML *xml); + +void +aoview_table_clear(void); + +struct aoview_file; + +extern char *aoview_file_dir; + +void +aoview_file_finish(struct aoview_file *file); + +gboolean +aoview_file_start(struct aoview_file *file); + +const char * +aoview_file_name(struct aoview_file *file); + +void +aoview_file_set_serial(struct aoview_file *file, int serial); + +int +aoview_file_get_serial(struct aoview_file *file); + +void +aoview_file_printf(struct aoview_file *file, char *format, ...); + +void +aoview_file_vprintf(struct aoview_file *file, char *format, va_list ap); + +struct aoview_file * +aoview_file_new(char *ext); + +void +aoview_file_destroy(struct aoview_file *file); + +void +aoview_file_init(GladeXML *xml); + +/* aoview_eeprom.c */ + +gboolean +aoview_eeprom_save(const char *device); + +void +aoview_eeprom_init(GladeXML *xml); + +/* aoview_voice.c */ +void aoview_voice_open(void); + +void aoview_voice_close(void); + +void aoview_voice_speak(char *format, ...); + +/* aoview_label.c */ + +void aoview_label_init(GladeXML *xml); + +void +aoview_label_show(struct aostate *state); + +/* aoview_flite.c */ + +FILE * +aoview_flite_start(void); + +void +aoview_flite_stop(void); + +/* aoview_main.c */ + +extern char *aoview_tty; + +#endif /* _AOVIEW_H_ */ diff --git a/ao-tools/ao-view/aoview_convert.c b/ao-tools/ao-view/aoview_convert.c new file mode 100644 index 00000000..02416647 --- /dev/null +++ b/ao-tools/ao-view/aoview_convert.c @@ -0,0 +1,42 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +static int16_t altitude_table[2048] = { +#include "altitude.h" +}; + +int16_t +aoview_pres_to_altitude(int16_t pres) +{ + pres = pres >> 4; + if (pres < 0) pres = 0; + if (pres > 2047) pres = 2047; + return altitude_table[pres]; +} + +int16_t +aoview_altitude_to_pres(int16_t alt) +{ + int16_t pres; + + for (pres = 0; pres < 2047; pres++) + if (altitude_table[pres] <= alt) + break; + return pres << 4; +} diff --git a/ao-tools/ao-view/aoview_dev_dialog.c b/ao-tools/ao-view/aoview_dev_dialog.c new file mode 100644 index 00000000..87396c1f --- /dev/null +++ b/ao-tools/ao-view/aoview_dev_dialog.c @@ -0,0 +1,173 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +static void +aoview_dev_dialog_map(GtkWidget *widget, gpointer data) +{ + GtkTreeView *dev_list = data; + GtkListStore *list_store; + GtkTreeIter iter; + int ndev, n; + struct cc_usbdevs *devs; + struct cc_usbdev *dev; + + list_store = gtk_list_store_new(3, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING); + + devs = cc_usbdevs_scan(); + if (devs) { + for (n = 0; n < devs->ndev; n++) { + dev = devs->dev[n]; + gtk_list_store_append(list_store, &iter); + gtk_list_store_set(list_store, &iter, + 0, dev->product, + 1, dev->serial, + 2, dev->tty, + -1); + } + } + gtk_tree_view_set_model (dev_list, GTK_TREE_MODEL(list_store)); + g_object_unref(G_OBJECT(list_store)); + gtk_tree_view_columns_autosize(dev_list); + cc_usbdevs_free(devs); +} + +static GtkMessageDialog *dev_open_fail_dialog; + +static void +aoview_dev_open_failed(char *name) +{ + char *utf8_file; + utf8_file = g_filename_to_utf8(name, -1, NULL, NULL, NULL); + if (!utf8_file) + utf8_file = name; + gtk_message_dialog_format_secondary_text(dev_open_fail_dialog, + "\"%s\"", utf8_file); + if (utf8_file != name) + g_free(utf8_file); + gtk_dialog_run(GTK_DIALOG(dev_open_fail_dialog)); + gtk_widget_hide(GTK_WIDGET(dev_open_fail_dialog)); +} + +gboolean dialog_save_log; + +static void +aoview_dev_selected(GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + gchar *string; + gtk_tree_model_get(model, iter, + 2, &string, + -1); + if (dialog_save_log) { + dialog_save_log = FALSE; + if (!aoview_eeprom_save(string)) + aoview_dev_open_failed(string); + } else { + if (!aoview_monitor_connect(string)) + aoview_dev_open_failed(string); + } +} + +static GtkWidget *dialog; + +static void +aoview_dev_dialog_connect(GtkWidget *widget, gpointer data) +{ + GtkTreeView *dev_list = data; + GtkListStore *list_store; + GtkTreeSelection *tree_selection; + + list_store = GTK_LIST_STORE(gtk_tree_view_get_model(dev_list)); + tree_selection = gtk_tree_view_get_selection(dev_list); + gtk_tree_selection_selected_foreach(tree_selection, + aoview_dev_selected, + data); + gtk_widget_hide(dialog); +} + +static void +aoview_dev_disconnect(GtkWidget *widget) +{ + aoview_monitor_disconnect(); +} + +static void +aoview_dev_savelog(GtkWidget *widget, gpointer data) +{ + dialog_save_log = TRUE; + gtk_widget_show(dialog); +} + +#define _(a) a + +void +aoview_dev_dialog_init(GladeXML *xml) +{ + GtkTreeView *dev_list; + GtkWidget *connect_button; + GtkTreeSelection *dev_selection; + GtkWidget *ao_disconnect; + GtkWidget *ao_savelog; + + dialog = glade_xml_get_widget(xml, "device_connect_dialog"); + assert(dialog); + + dev_list = GTK_TREE_VIEW(glade_xml_get_widget(xml, "dev_list")); + assert(dev_list); + + aoview_add_plain_text_column(dev_list, _("Product"), 0, 16); + aoview_add_plain_text_column(dev_list, _("Serial"), 1, 8); + aoview_add_plain_text_column(dev_list, _("Device"), 2, 13); + + dev_selection = gtk_tree_view_get_selection(dev_list); + gtk_tree_selection_set_mode(dev_selection, GTK_SELECTION_SINGLE); + + g_signal_connect(G_OBJECT(dialog), "map", + G_CALLBACK(aoview_dev_dialog_map), + dev_list); + + connect_button = glade_xml_get_widget(xml, "connect_button"); + assert(connect_button); + + g_signal_connect(G_OBJECT(connect_button), "clicked", + G_CALLBACK(aoview_dev_dialog_connect), + dev_list); + + + ao_disconnect = glade_xml_get_widget(xml, "ao_disconnect"); + assert(ao_disconnect); + + g_signal_connect(G_OBJECT(ao_disconnect), "activate", + G_CALLBACK(aoview_dev_disconnect), + ao_disconnect); + + ao_savelog = glade_xml_get_widget(xml, "ao_savelog"); + assert(ao_savelog); + + g_signal_connect(G_OBJECT(ao_savelog), "activate", + G_CALLBACK(aoview_dev_savelog), + dialog); + dev_open_fail_dialog = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "dev_open_fail_dialog")); + assert(dev_open_fail_dialog); +} diff --git a/ao-tools/ao-view/aoview_eeprom.c b/ao-tools/ao-view/aoview_eeprom.c new file mode 100644 index 00000000..34e2deed --- /dev/null +++ b/ao-tools/ao-view/aoview_eeprom.c @@ -0,0 +1,157 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +#define EEPROM_LEN 1024 + +static struct aoview_file *eeprom_file; +static char eeprom_line[EEPROM_LEN + 1]; +static int eeprom_pos; +static GtkMessageDialog *eeprom_save_done; +static GtkWidget *eeprom_save_close; +static gboolean eeprom_save_shown; + +static void +aoview_eeprom_disconnect(struct aoview_serial *serial) +{ + aoview_file_finish(eeprom_file); +} + +static void +aoview_eeprom_done(struct aoview_serial *serial) +{ + gtk_window_set_title(GTK_WINDOW(eeprom_save_done), + "EEPROM data saved"); + gtk_message_dialog_set_markup(eeprom_save_done, + "EEPROM data saved as"); + if (!eeprom_save_shown) + gtk_widget_show(GTK_WIDGET(eeprom_save_done)); + eeprom_save_close = gtk_window_get_default_widget(GTK_WINDOW(eeprom_save_done)); + if (eeprom_save_close) + gtk_widget_set_sensitive(eeprom_save_close, TRUE); + aoview_eeprom_disconnect(serial); +} + +static gboolean +aoview_eeprom_parse(struct aoview_serial *serial, + char *line) +{ + char cmd; + int tick; + int a; + int b; + int serial_number; + const char *name; + char *utf8_name; + + if (!strcmp(line, "end")) { + aoview_eeprom_done(serial); + return FALSE; + } + if (sscanf(line, "serial-number %u", &serial_number) == 1) { + aoview_file_set_serial(eeprom_file, serial_number); + } else if (sscanf(line, "%c %x %x %x", &cmd, &tick, &a, &b) == 4) { + aoview_file_printf(eeprom_file, "%s\n", line); + if (cmd == 'S' && a == 8) { + aoview_eeprom_done(serial); + return FALSE; + } + + if (!eeprom_save_shown) + { + name = aoview_file_name(eeprom_file); + if (name) { + utf8_name = g_filename_to_utf8(name, -1, NULL, NULL, NULL); + if (!utf8_name) + utf8_name = (char *) name; + gtk_widget_set_sensitive(eeprom_save_close, FALSE); + gtk_window_set_title(GTK_WINDOW(eeprom_save_done), + "Saving EEPROM data"); + gtk_message_dialog_set_markup(eeprom_save_done, + "Saving EEPROM data as"); + gtk_message_dialog_format_secondary_text(eeprom_save_done, "%s", + utf8_name); + if (utf8_name != name) + g_free(utf8_name); + gtk_container_check_resize(GTK_CONTAINER(eeprom_save_done)); + gtk_widget_show(GTK_WIDGET(eeprom_save_done)); + eeprom_save_shown = TRUE; + eeprom_save_close = gtk_window_get_default_widget(GTK_WINDOW(eeprom_save_done)); + if (eeprom_save_close) + gtk_widget_set_sensitive(eeprom_save_close, FALSE); + } + } + } + return TRUE; +} + +static void +aoview_eeprom_callback(gpointer user_data, + struct aoview_serial *serial, + gint revents) +{ + int c; + + if (revents & (G_IO_HUP|G_IO_ERR)) { + aoview_eeprom_disconnect(serial); + return; + } + if (revents & G_IO_IN) { + for (;;) { + c = aoview_serial_getc(serial); + if (c == -1) + break; + if (c == '\r') + continue; + if (c == '\n') { + eeprom_line[eeprom_pos] = '\0'; + if (eeprom_pos) + if (!aoview_eeprom_parse(serial, eeprom_line)) + break; + eeprom_pos = 0; + } else if (eeprom_pos < EEPROM_LEN) + eeprom_line[eeprom_pos++] = c; + } + } +} + +gboolean +aoview_eeprom_save(const char *device) +{ + struct aoview_serial *serial; + + gtk_widget_hide(GTK_WIDGET(eeprom_save_done)); + eeprom_save_shown = FALSE; + serial = aoview_serial_open(device); + if (!serial) + return FALSE; + aoview_serial_set_callback(serial, aoview_eeprom_callback); + aoview_serial_printf(serial, "v\nl\n"); + return TRUE; +} + +void +aoview_eeprom_init(GladeXML *xml) +{ + eeprom_file = aoview_file_new("eeprom"); + assert(eeprom_file); + + eeprom_save_done = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "ao_save_done")); + assert(eeprom_save_done); + +} diff --git a/ao-tools/ao-view/aoview_file.c b/ao-tools/ao-view/aoview_file.c new file mode 100644 index 00000000..5288c2f7 --- /dev/null +++ b/ao-tools/ao-view/aoview_file.c @@ -0,0 +1,236 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +char *aoview_file_dir; + +#define ALTOS_DIR_PATH "/apps/aoview/log_dir" +#define DEFAULT_DIR "AltOS" + +struct aoview_file { + char *ext; + FILE *file; + char *name; + int failed; + int serial; + int sequence; +}; + +static void +aoview_file_save_conf(void) +{ + GConfClient *gconf_client; + + gconf_client = gconf_client_get_default(); + if (gconf_client) + { + gconf_client_set_string(gconf_client, + ALTOS_DIR_PATH, + aoview_file_dir, + NULL); + g_object_unref(G_OBJECT(gconf_client)); + } +} + +static void +aoview_file_configure(GtkWidget *widget, gpointer data) +{ + GtkFileChooser *chooser = data; + aoview_file_dir = gtk_file_chooser_get_filename(chooser); + aoview_file_save_conf(); + gtk_widget_hide(GTK_WIDGET(chooser)); +} + +void +aoview_file_finish(struct aoview_file *file) +{ + if (file->file) { + fclose(file->file); + file->file = NULL; + free(file->name); + file->name = NULL; + } + file->failed = 0; +} + +const char * +aoview_file_name(struct aoview_file *file) +{ + return file->name; +} + +static GtkMessageDialog *file_fail_dialog; + +static void +aoview_file_open_failed(char *name) +{ + char *utf8_file; + utf8_file = g_filename_to_utf8(name, -1, NULL, NULL, NULL); + if (!utf8_file) + utf8_file = name; + gtk_message_dialog_format_secondary_text(file_fail_dialog, + "\"%s\"", utf8_file); + if (utf8_file != name) + g_free(utf8_file); + gtk_widget_show(GTK_WIDGET(file_fail_dialog)); +} + +gboolean +aoview_file_start(struct aoview_file *file) +{ + char base[50]; + struct tm tm; + time_t now; + char *full; + int r; + + if (file->file) + return TRUE; + + if (file->failed) + return FALSE; + + now = time(NULL); + (void) localtime_r(&now, &tm); + aoview_mkdir(aoview_file_dir); + for (;;) { + snprintf(base, sizeof (base), "%04d-%02d-%02d-serial-%03d-flight-%03d.%s", + tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + file->serial, + file->sequence, + file->ext); + full = aoview_fullname(aoview_file_dir, base); + r = access(full, F_OK); + if (r < 0) { + file->file = fopen(full, "w"); + if (!file->file) { + aoview_file_open_failed(full); + free(full); + file->failed = 1; + return FALSE; + } else { + setlinebuf(file->file); + file->name = full; + return TRUE; + } + } + free(full); + file->sequence++; + } +} + +void +aoview_file_vprintf(struct aoview_file *file, char *format, va_list ap) +{ + if (!aoview_file_start(file)) + return; + vfprintf(file->file, format, ap); +} + +void +aoview_file_printf(struct aoview_file *file, char *format, ...) +{ + va_list ap; + + va_start(ap, format); + aoview_file_vprintf(file, format, ap); + va_end(ap); +} + +struct aoview_file * +aoview_file_new(char *ext) +{ + struct aoview_file *file; + + file = calloc (1, sizeof (struct aoview_file)); + if (!file) + return NULL; + file->ext = strdup(ext); + if (!file->ext) { + free(file); + return NULL; + } + return file; +} + +void +aoview_file_destroy(struct aoview_file *file) +{ + if (file->file) + fclose(file->file); + if (file->name) + free(file->name); + free(file->ext); + free(file); +} + +void +aoview_file_set_serial(struct aoview_file *file, int serial) +{ + if (serial != file->serial) + aoview_file_finish(file); + file->serial = serial; +} + +int +aoview_file_get_serial(struct aoview_file *file) +{ + return file->serial; +} + +void +aoview_file_init(GladeXML *xml) +{ + GConfClient *gconf_client; + char *file_dir = NULL; + GtkFileChooser *file_chooser_dialog; + GtkWidget *file_configure_ok; + + g_type_init(); + gconf_client = gconf_client_get_default(); + if (gconf_client) + { + file_dir = gconf_client_get_string(gconf_client, + ALTOS_DIR_PATH, + NULL); + g_object_unref(G_OBJECT(gconf_client)); + } + if (!file_dir) { + aoview_file_dir = aoview_fullname(getenv("HOME"), DEFAULT_DIR); + aoview_file_save_conf(); + } else { + aoview_file_dir = strdup(file_dir); + } + + file_chooser_dialog = GTK_FILE_CHOOSER(glade_xml_get_widget(xml, "file_chooser_dialog")); + assert(file_chooser_dialog); + gtk_file_chooser_set_filename(file_chooser_dialog, aoview_file_dir); + + file_configure_ok = glade_xml_get_widget(xml, "file_configure_ok"); + assert(file_configure_ok); + + g_signal_connect(G_OBJECT(file_configure_ok), "clicked", + G_CALLBACK(aoview_file_configure), + file_chooser_dialog); + + + file_fail_dialog = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "file_fail_dialog")); + assert(file_fail_dialog); +} diff --git a/ao-tools/ao-view/aoview_flite.c b/ao-tools/ao-view/aoview_flite.c new file mode 100644 index 00000000..e1b75898 --- /dev/null +++ b/ao-tools/ao-view/aoview_flite.c @@ -0,0 +1,135 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include "aoview.h" +#include + +cst_voice *register_cmu_us_kal(); +static cst_voice *voice; + +static FILE *pipe_write; +static GThread *aoview_flite_thread; + +static snd_pcm_t *alsa_handle; + +gpointer +aoview_flite_task(gpointer data) +{ + FILE *input = data; + char line[1024]; + cst_wave *wave; + int rate; + int channels; + int err; + char *samples; + int num_samples; + + err = snd_pcm_open(&alsa_handle, "default", + SND_PCM_STREAM_PLAYBACK, 0); + if (err >= 0) + { + if (err < 0) { + snd_pcm_close(alsa_handle); + alsa_handle = 0; + } + } + rate = 0; + channels = 0; + while (fgets(line, sizeof (line) - 1, input) != NULL) { + if (!alsa_handle) + continue; + wave = flite_text_to_wave(line, voice); + if (wave->sample_rate != rate || + wave->num_channels != channels) + { + rate = wave->sample_rate; + channels = wave->num_channels; + err = snd_pcm_set_params(alsa_handle, + SND_PCM_FORMAT_S16, + SND_PCM_ACCESS_RW_INTERLEAVED, + channels, + rate, + 1, + 100000); + if (err < 0) + fprintf(stderr, "alsa set_params error %s\n", + strerror(-err)); + } + err = snd_pcm_prepare(alsa_handle); + if (err < 0) + fprintf(stderr, "alsa pcm_prepare error %s\n", + strerror(-err)); + samples = (char *) wave->samples; + num_samples = wave->num_samples; + while (num_samples > 0) { + err = snd_pcm_writei(alsa_handle, + samples, num_samples); + if (err <= 0) { + fprintf(stderr, "alsa write error %s\n", + strerror(-err)); + break; + } + num_samples -= err; + samples += err * 2 * channels; + } + snd_pcm_drain(alsa_handle); + delete_wave(wave); + } + snd_pcm_close(alsa_handle); + alsa_handle = 0; + 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; + } +} + +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); + } + } + 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; +} diff --git a/ao-tools/ao-view/aoview_label.c b/ao-tools/ao-view/aoview_label.c new file mode 100644 index 00000000..24313626 --- /dev/null +++ b/ao-tools/ao-view/aoview_label.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +static struct { + char *name; + char *initial_value; + GtkLabel *widget; +} label_widgets[] = { + { "height_label", "Height (m)", NULL }, + { "state_label", "State", NULL }, + { "rssi_label", "RSSI (dBm)", NULL }, + { "speed_label", "Speed (m/s)", NULL }, + { "height_value", "0", NULL }, + { "state_value", "pad", NULL }, + { "rssi_value", "-50", NULL }, + { "speed_value", "0", NULL }, +}; + +static void +aoview_label_assign(GtkLabel *widget, char *value) +{ + char *markup; + + markup = g_markup_printf_escaped("%s", value); + gtk_label_set_markup(widget, markup); + g_free(markup); +} + +void +aoview_label_show(struct aostate *state) +{ + char line[1024]; + sprintf(line, "%d", state->height); + aoview_label_assign(label_widgets[4].widget, line); + + aoview_label_assign(label_widgets[5].widget, state->data.state); + + sprintf(line, "%d", state->data.rssi); + aoview_label_assign(label_widgets[6].widget, line); + + if (state->ascent) + sprintf(line, "%6.0f", fabs(state->speed)); + else + sprintf(line, "%6.0f", fabs(state->baro_speed)); + aoview_label_assign(label_widgets[7].widget, line); +} + +void +aoview_label_init(GladeXML *xml) +{ + int i; + for (i = 0; i < sizeof(label_widgets)/sizeof(label_widgets[0]); i++) { + label_widgets[i].widget = GTK_LABEL(glade_xml_get_widget(xml, label_widgets[i].name)); + aoview_label_assign(label_widgets[i].widget, label_widgets[i].initial_value); + assert(label_widgets[i].widget); + } +} diff --git a/ao-tools/ao-view/aoview_log.c b/ao-tools/ao-view/aoview_log.c new file mode 100644 index 00000000..1b89c28c --- /dev/null +++ b/ao-tools/ao-view/aoview_log.c @@ -0,0 +1,70 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +static struct aoview_file *aoview_log; + +void +aoview_log_new(void) +{ + aoview_file_finish(aoview_log); + aoview_state_new(); +} + +void +aoview_log_set_serial(int serial) +{ + aoview_file_set_serial(aoview_log, serial); +} + +int +aoview_log_get_serial(void) +{ + return aoview_file_get_serial(aoview_log); +} + +void +aoview_log_printf(char *format, ...) +{ + va_list ap; + + va_start(ap, format); + aoview_file_vprintf(aoview_log, format, ap); + va_end(ap); +} + +static void +aoview_log_new_item(GtkWidget *widget, gpointer data) +{ + aoview_file_finish(aoview_log); +} + +void +aoview_log_init(GladeXML *xml) +{ + GtkWidget *log_new; + + aoview_log = aoview_file_new("telem"); + assert(aoview_log); + + log_new = glade_xml_get_widget(xml, "log_new"); + assert(log_new); + g_signal_connect(G_OBJECT(log_new), "activate", + G_CALLBACK(aoview_log_new_item), + NULL); +} diff --git a/ao-tools/ao-view/aoview_main.c b/ao-tools/ao-view/aoview_main.c new file mode 100644 index 00000000..64c1c027 --- /dev/null +++ b/ao-tools/ao-view/aoview_main.c @@ -0,0 +1,116 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +static const char aoview_glade[] = { +#include "aoview_glade.h" +}; + +static void usage(void) { + printf("aoview [--device|-d device_file]"); + exit(1); +} + +static void destroy_event(GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} + +extern int _Xdebug; +char *aoview_tty = NULL; + +int main(int argc, char **argv) +{ + GladeXML *xml = NULL; + GtkWidget *mainwindow; + GtkAboutDialog *about_dialog; + + static struct option long_options[] = { + { "tty", 1, 0, 'T'}, + { "sync", 0, 0, 's'}, + { 0, 0, 0, 0 } + }; + for (;;) { + int c, temp; + + c = getopt_long_only(argc, argv, "sT:", long_options, &temp); + if (c == -1) + break; + + switch (c) { + case 'T': + aoview_tty = optarg; + break; + case 's': + _Xdebug = 1; + break; + default: + usage(); + } + } + + g_thread_init(NULL); + gtk_init(&argc, &argv); + glade_init(); + + xml = glade_xml_new_from_buffer(aoview_glade, sizeof (aoview_glade), NULL, NULL); + + /* connect the signals in the interface */ + glade_xml_signal_autoconnect(xml); + + /* Hook up the close button. */ + mainwindow = glade_xml_get_widget(xml, "aoview"); + assert(mainwindow); + + g_signal_connect (G_OBJECT(mainwindow), "destroy", + G_CALLBACK(destroy_event), NULL); + + about_dialog = GTK_ABOUT_DIALOG(glade_xml_get_widget(xml, "about_dialog")); + assert(about_dialog); + gtk_about_dialog_set_version(about_dialog, AOVIEW_VERSION); + + aoview_voice_init(xml); + + aoview_dev_dialog_init(xml); + + aoview_state_init(xml); + + aoview_file_init(xml); + + aoview_log_init(xml); + + aoview_table_init(xml); + + aoview_eeprom_init(xml); + + aoview_replay_init(xml); + + aoview_label_init(xml); + + if (aoview_tty) { + if (!aoview_monitor_connect(aoview_tty)) { + perror(aoview_tty); + exit(1); + } + } + aoview_voice_speak("rocket flight monitor ready\n"); + + gtk_main(); + + return 0; +} diff --git a/ao-tools/ao-view/aoview_monitor.c b/ao-tools/ao-view/aoview_monitor.c new file mode 100644 index 00000000..8564014b --- /dev/null +++ b/ao-tools/ao-view/aoview_monitor.c @@ -0,0 +1,229 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +static struct aoview_serial *monitor_serial; + +#define MONITOR_LEN 1024 + +static char monitor_line[MONITOR_LEN + 1]; +static int monitor_pos; + +void +aoview_monitor_disconnect(void) +{ + if (monitor_serial) { + aoview_serial_close(monitor_serial); + monitor_serial = NULL; + } + aoview_log_new(); +} + +static void +aoview_parse_string(char *target, int len, char *source) +{ + strncpy(target, source, len-1); + target[len-1] = '\0'; +} + +static void +aoview_parse_int(int *target, char *source) +{ + *target = strtol(source, NULL, 0); +} + +static void +aoview_parse_hex(int *target, char *source) +{ + *target = strtol(source, NULL, 16); +} + +static void +aoview_parse_pos(double *target, char *source) +{ + int deg; + double min; + char dir; + double r; + + if (sscanf(source, "%d°%lf'%c", °, &min, &dir) != 3) { + *target = 0; + return; + } + r = deg + min / 60.0; + if (dir == 'S' || dir == 'W') + r = -r; + *target = r; +} + +#define PARSE_MAX_WORDS 256 + +gboolean +aoview_monitor_parse(const char *input_line) +{ + char *saveptr; + char *words[PARSE_MAX_WORDS]; + int nword; + char line_buf[8192], *line; + struct aodata data; + int tracking_pos; + + /* avoid smashing our input parameter */ + strncpy (line_buf, input_line, sizeof (line_buf)-1); + line_buf[sizeof(line_buf) - 1] = '\0'; + line = line_buf; + for (nword = 0; nword < PARSE_MAX_WORDS; nword++) { + words[nword] = strtok_r(line, " \t\n", &saveptr); + line = NULL; + if (words[nword] == NULL) + break; + } + if (nword < 36) + return FALSE; + if (strcmp(words[0], "CALL") != 0) + return FALSE; + aoview_parse_string(data.callsign, sizeof (data.callsign), words[1]); + aoview_parse_int(&data.serial, words[3]); + + aoview_parse_int(&data.rssi, words[5]); + aoview_parse_string(data.state, sizeof (data.state), words[9]); + aoview_parse_int(&data.tick, words[10]); + aoview_parse_int(&data.accel, words[12]); + aoview_parse_int(&data.pres, words[14]); + aoview_parse_int(&data.temp, words[16]); + aoview_parse_int(&data.batt, words[18]); + aoview_parse_int(&data.drogue, words[20]); + aoview_parse_int(&data.main, words[22]); + aoview_parse_int(&data.flight_accel, words[24]); + aoview_parse_int(&data.ground_accel, words[26]); + aoview_parse_int(&data.flight_vel, words[28]); + aoview_parse_int(&data.flight_pres, words[30]); + aoview_parse_int(&data.ground_pres, words[32]); + aoview_parse_int(&data.gps.nsat, words[34]); + if (strcmp (words[36], "unlocked") == 0) { + data.gps.gps_connected = 1; + data.gps.gps_locked = 0; + data.gps.gps_time.hour = data.gps.gps_time.minute = data.gps.gps_time.second = 0; + data.gps.lat = data.gps.lon = 0; + data.gps.alt = 0; + tracking_pos = 37; + } else if (nword >= 40) { + data.gps.gps_locked = 1; + data.gps.gps_connected = 1; + sscanf(words[36], "%d:%d:%d", &data.gps.gps_time.hour, &data.gps.gps_time.minute, &data.gps.gps_time.second); + aoview_parse_pos(&data.gps.lat, words[37]); + aoview_parse_pos(&data.gps.lon, words[38]); + sscanf(words[39], "%dm", &data.gps.alt); + tracking_pos = 46; + } else { + data.gps.gps_connected = 0; + data.gps.gps_locked = 0; + data.gps.gps_time.hour = data.gps.gps_time.minute = data.gps.gps_time.second = 0; + data.gps.lat = data.gps.lon = 0; + data.gps.alt = 0; + tracking_pos = -1; + } + if (nword >= 46) { + data.gps.gps_extended = 1; + sscanf(words[40], "%lfm/s", &data.gps.ground_speed); + sscanf(words[41], "%d", &data.gps.course); + sscanf(words[42], "%lfm/s", &data.gps.climb_rate); + sscanf(words[43], "%lf", &data.gps.hdop); + sscanf(words[44], "%d", &data.gps.h_error); + sscanf(words[45], "%d", &data.gps.v_error); + } else { + data.gps.gps_extended = 0; + data.gps.ground_speed = 0; + data.gps.course = 0; + data.gps.climb_rate = 0; + data.gps.hdop = 0; + data.gps.h_error = 0; + data.gps.v_error = 0; + } + if (tracking_pos >= 0 && nword >= tracking_pos + 2 && strcmp(words[tracking_pos], "SAT") == 0) { + int c, n, pos; + aoview_parse_int(&n, words[tracking_pos + 1]); + pos = tracking_pos + 2; + if (nword >= pos + n * 3) { + data.gps_tracking.channels = n; + for (c = 0; c < n; c++) { + aoview_parse_int(&data.gps_tracking.sats[c].svid, + words[pos + 0]); + aoview_parse_hex(&data.gps_tracking.sats[c].state, + words[pos + 1]); + aoview_parse_int(&data.gps_tracking.sats[c].c_n0, + words[pos + 2]); + pos += 3; + } + } else { + data.gps_tracking.channels = 0; + } + } else { + data.gps_tracking.channels = 0; + } + aoview_state_notify(&data); + return TRUE; +} + +static void +aoview_monitor_callback(gpointer user_data, + struct aoview_serial *serial, + gint revents) +{ + int c; + + if (revents & (G_IO_HUP|G_IO_ERR)) { + aoview_monitor_disconnect(); + return; + } + if (revents & G_IO_IN) { + for (;;) { + c = aoview_serial_getc(serial); + if (c == -1) + break; + if (c == '\r') + continue; + if (c == '\n') { + monitor_line[monitor_pos] = '\0'; + if (monitor_pos) { + if (aoview_monitor_parse(monitor_line)) { + aoview_log_set_serial(aostate.data.serial); + if (aoview_log_get_serial()) + aoview_log_printf ("%s\n", monitor_line); + } + } + monitor_pos = 0; + } else if (monitor_pos < MONITOR_LEN) + monitor_line[monitor_pos++] = c; + } + } +} + +gboolean +aoview_monitor_connect(char *tty) +{ + aoview_monitor_disconnect(); + monitor_serial = aoview_serial_open(tty); + if (!monitor_serial) + return FALSE; + aoview_table_clear(); + aoview_state_reset(); + aoview_serial_set_callback(monitor_serial, + aoview_monitor_callback); + return TRUE; +} diff --git a/ao-tools/ao-view/aoview_replay.c b/ao-tools/ao-view/aoview_replay.c new file mode 100644 index 00000000..da7b5d6a --- /dev/null +++ b/ao-tools/ao-view/aoview_replay.c @@ -0,0 +1,147 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +static GtkFileChooser *replay_dialog; +static GtkWidget *replay_ok; +static FILE *replay_file; +static int replay_tick; + +static int +find_tick(char *line, gboolean *is_pad) +{ + char *state = strstr(line, "STATE"); + if (!state) + return -1; + state = strchr(state, ' '); + if (!state) + return -1; + while (*state == ' ') + state++; + *is_pad = strncmp(state, "pad", 3) == 0; + while (*state && !isdigit(*state)) + state++; + return atoi(state); +} + +static void +aoview_replay_close(void) +{ + if (replay_file) { + fclose(replay_file); + replay_file = NULL; + } +} + +static char replay_line[1024]; + +static gboolean +aoview_replay_read(gpointer data); + +static gboolean +aoview_replay_execute(gpointer data) +{ + aoview_monitor_parse(replay_line); + g_idle_add(aoview_replay_read, NULL); + return FALSE; +} + +static gboolean +aoview_replay_read(gpointer data) +{ + int tick; + gboolean is_pad; + + if (!replay_file) + return FALSE; + if (fgets(replay_line, sizeof (replay_line), replay_file)) { + tick = find_tick(replay_line, &is_pad); + if (tick >= 0 && replay_tick >= 0 && !is_pad) { + while (tick < replay_tick) + tick += 65536; + g_timeout_add((tick - replay_tick) * 10, + aoview_replay_execute, + NULL); + } else { + aoview_replay_execute(NULL); + } + replay_tick = tick; + } else { + aoview_replay_close(); + } + return FALSE; +} + +static void +aoview_replay_open(GtkWidget *widget, gpointer data) +{ + char *replay_file_name; + GtkWidget *dialog; + + aoview_replay_close(); + replay_file_name = gtk_file_chooser_get_filename(replay_dialog); + replay_file = fopen(replay_file_name, "r"); + if (!replay_file) { + dialog = gtk_message_dialog_new(GTK_WINDOW(replay_dialog), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Error loading file '%s': %s", + replay_file_name, g_strerror(errno)); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + } else { + replay_tick = -1; + aoview_state_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); + g_signal_connect(G_OBJECT(replay_ok), "clicked", + G_CALLBACK(aoview_replay_open), + replay_dialog); +} diff --git a/ao-tools/ao-view/aoview_serial.c b/ao-tools/ao-view/aoview_serial.c new file mode 100644 index 00000000..29038b79 --- /dev/null +++ b/ao-tools/ao-view/aoview_serial.c @@ -0,0 +1,270 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" +#include + +#define AOVIEW_SERIAL_IN_BUF 64 +#define AOVIEW_SERIAL_OUT_BUF 64 + +struct aoview_buf { + char *buf; + int off; + int count; + int size; +}; + +static int +aoview_buf_write(struct aoview_buf *buf, char *data, int len) +{ + if (buf->count + len > buf->size) { + int new_size = buf->size * 2; + if (new_size == 0) + new_size = 1024; + if (buf->buf) + buf->buf = realloc (buf->buf, new_size); + else + buf->buf = malloc (new_size); + buf->size = new_size; + } + memcpy(buf->buf + buf->count, data, len); + buf->count += len; + return len; +} + +static int +aoview_buf_read(struct aoview_buf *buf, char *data, int len) +{ + if (len > buf->count - buf->off) + len = buf->count - buf->off; + memcpy (data, buf->buf + buf->off, len); + buf->off += len; + if (buf->off == buf->count) + buf->off = buf->count = 0; + return len; +} + +static int +aoview_buf_getc(struct aoview_buf *buf) +{ + char b; + int r; + + r = aoview_buf_read(buf, &b, 1); + if (r == 1) + return (int) b; + return -1; +} + +static void +aoview_buf_flush(struct aoview_buf *buf, int fd) +{ + int ret; + + if (buf->count > buf->off) { + ret = write(fd, buf->buf + buf->off, buf->count - buf->off); + if (ret > 0) { + buf->off += ret; + if (buf->off == buf->count) + buf->off = buf->count = 0; + } + } +} + +static void +aoview_buf_fill(struct aoview_buf *buf, int fd) +{ + int ret; + + while (buf->count >= buf->size) { + int new_size = buf->size * 2; + buf->buf = realloc (buf->buf, new_size); + buf->size = new_size; + } + + ret = read(fd, buf->buf + buf->count, buf->size - buf->count); + if (ret > 0) + buf->count += ret; +} + +static void +aoview_buf_init(struct aoview_buf *buf) +{ + buf->buf = malloc (buf->size = 1024); + buf->count = 0; +} + +static void +aoview_buf_fini(struct aoview_buf *buf) +{ + free(buf->buf); +} + +struct aoview_serial { + GSource source; + int fd; + struct termios save_termios; + struct aoview_buf in_buf; + struct aoview_buf out_buf; + GPollFD poll_fd; +}; + + +void +aoview_serial_printf(struct aoview_serial *serial, char *format, ...) +{ + char buf[1024]; + va_list ap; + int ret; + + /* sprintf to a local buffer */ + va_start(ap, format); + ret = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + if (ret > sizeof(buf)) { + fprintf(stderr, "printf overflow for format %s\n", + format); + } + + /* flush local buffer to the wire */ + aoview_buf_write(&serial->out_buf, buf, ret); + aoview_buf_flush(&serial->out_buf, serial->fd); +} + +int +aoview_serial_read(struct aoview_serial *serial, char *buf, int len) +{ + return aoview_buf_read(&serial->in_buf, buf, len); +} + +int +aoview_serial_getc(struct aoview_serial *serial) +{ + return aoview_buf_getc(&serial->in_buf); +} + +static gboolean +serial_prepare(GSource *source, gint *timeout) +{ + struct aoview_serial *serial = (struct aoview_serial *) source; + *timeout = -1; + + if (serial->out_buf.count) + serial->poll_fd.events |= G_IO_OUT; + else + serial->poll_fd.events &= ~G_IO_OUT; + return FALSE; +} + +static gboolean +serial_check(GSource *source) +{ + struct aoview_serial *serial = (struct aoview_serial *) source; + gint revents = serial->poll_fd.revents; + + if (revents & G_IO_NVAL) + return FALSE; + if (revents & G_IO_IN) + return TRUE; + if (revents & G_IO_OUT) + return TRUE; + return FALSE; +} + +static gboolean +serial_dispatch(GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + struct aoview_serial *serial = (struct aoview_serial *) source; + aoview_serial_callback func = (aoview_serial_callback) callback; + gint revents = serial->poll_fd.revents; + + if (revents & G_IO_IN) + aoview_buf_fill(&serial->in_buf, serial->fd); + + if (revents & G_IO_OUT) + aoview_buf_flush(&serial->out_buf, serial->fd); + + if (func) + (*func)(user_data, serial, revents); + return TRUE; +} + +static void +serial_finalize(GSource *source) +{ + struct aoview_serial *serial = (struct aoview_serial *) source; + + aoview_buf_fini(&serial->in_buf); + aoview_buf_fini(&serial->out_buf); + tcsetattr(serial->fd, TCSAFLUSH, &serial->save_termios); + close (serial->fd); +} + +static GSourceFuncs serial_funcs = { + serial_prepare, + serial_check, + serial_dispatch, + serial_finalize +}; + +struct aoview_serial * +aoview_serial_open(const char *tty) +{ + struct aoview_serial *serial; + struct termios termios; + + serial = (struct aoview_serial *) g_source_new(&serial_funcs, sizeof (struct aoview_serial)); + aoview_buf_init(&serial->in_buf); + aoview_buf_init(&serial->out_buf); + serial->fd = open (tty, O_RDWR | O_NONBLOCK); + if (serial->fd < 0) { + g_source_destroy(&serial->source); + return NULL; + } + tcgetattr(serial->fd, &termios); + serial->save_termios = termios; + cfmakeraw(&termios); + tcsetattr(serial->fd, TCSAFLUSH, &termios); + + aoview_serial_printf(serial, "E 0\n"); + tcdrain(serial->fd); + usleep(15*1000); + tcflush(serial->fd, TCIFLUSH); + serial->poll_fd.fd = serial->fd; + serial->poll_fd.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR; + g_source_attach(&serial->source, NULL); + g_source_add_poll(&serial->source,&serial->poll_fd); + aoview_serial_set_callback(serial, NULL); + return serial; +} + +void +aoview_serial_close(struct aoview_serial *serial) +{ + g_source_remove_poll(&serial->source, &serial->poll_fd); + close(serial->fd); + g_source_destroy(&serial->source); +} + +void +aoview_serial_set_callback(struct aoview_serial *serial, + aoview_serial_callback func) +{ + g_source_set_callback(&serial->source, (GSourceFunc) func, serial, NULL); +} diff --git a/ao-tools/ao-view/aoview_state.c b/ao-tools/ao-view/aoview_state.c new file mode 100644 index 00000000..f75066dd --- /dev/null +++ b/ao-tools/ao-view/aoview_state.c @@ -0,0 +1,373 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" +#include + +static inline double sqr(double a) { return a * a; }; + +static void +aoview_great_circle (double start_lat, double start_lon, + double end_lat, double end_lon, + double *dist, double *bearing) +{ + const double rad = M_PI / 180; + const double earth_radius = 6371.2 * 1000; /* in meters */ + double lat1 = rad * start_lat; + double lon1 = rad * -start_lon; + double lat2 = rad * end_lat; + double lon2 = rad * -end_lon; + + double d_lat = lat2 - lat1; + double d_lon = lon2 - lon1; + + /* From http://en.wikipedia.org/wiki/Great-circle_distance */ + double vdn = sqrt(sqr(cos(lat2) * sin(d_lon)) + + sqr(cos(lat1) * sin(lat2) - + sin(lat1) * cos(lat2) * cos(d_lon))); + double vdd = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(d_lon); + double d = atan2(vdn,vdd); + double course; + + if (cos(lat1) < 1e-20) { + if (lat1 > 0) + course = M_PI; + else + course = -M_PI; + } else { + if (d < 1e-10) + course = 0; + else + course = acos((sin(lat2)-sin(lat1)*cos(d)) / + (sin(d)*cos(lat1))); + if (sin(lon2-lon1) > 0) + course = 2 * M_PI-course; + } + *dist = d * earth_radius; + *bearing = course * 180/M_PI; +} + +static void +aoview_state_add_deg(int column, char *label, double deg, char pos, char neg) +{ + double int_part; + double min; + char sign = pos; + + if (deg < 0) { + deg = -deg; + sign = neg; + } + int_part = floor (deg); + min = (deg - int_part) * 60.0; + aoview_table_add_row(column, label, "%d°%lf'%c", + (int) int_part, min, sign); + +} + +static char *ascent_states[] = { + "boost", + "fast", + "coast", + 0, +}; + +static double +aoview_time(void) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + return (double) now.tv_sec + (double) now.tv_nsec / 1.0e9; +} + +/* + * Fill out the derived data fields + */ +static void +aoview_state_derive(struct aodata *data, struct aostate *state) +{ + int i; + double new_height; + double height_change; + double time_change; + int tick_count; + + state->report_time = aoview_time(); + + state->prev_data = state->data; + state->prev_npad = state->npad; + state->data = *data; + tick_count = data->tick; + if (tick_count < state->prev_data.tick) + tick_count += 65536; + time_change = (tick_count - state->prev_data.tick) / 100.0; + + state->ground_altitude = aoview_pres_to_altitude(data->ground_pres); + new_height = aoview_pres_to_altitude(data->flight_pres) - state->ground_altitude; + height_change = new_height - state->height; + state->height = new_height; + if (time_change) + state->baro_speed = (state->baro_speed * 3 + (height_change / time_change)) / 4.0; + state->acceleration = (data->ground_accel - data->flight_accel) / 27.0; + state->speed = data->flight_vel / 2700.0; + state->temperature = ((data->temp / 32767.0 * 3.3) - 0.5) / 0.01; + state->drogue_sense = data->drogue / 32767.0 * 15.0; + state->main_sense = data->main / 32767.0 * 15.0; + state->battery = data->batt / 32767.0 * 5.0; + if (!strcmp(data->state, "pad")) { + if (data->gps.gps_locked && data->gps.nsat >= 4) { + state->npad++; + state->pad_lat_total += data->gps.lat; + state->pad_lon_total += data->gps.lon; + state->pad_alt_total += data->gps.alt; + if (state->npad > 1) { + state->pad_lat = (state->pad_lat * 31 + data->gps.lat) / 32.0; + state->pad_lon = (state->pad_lon * 31 + data->gps.lon) / 32.0; + state->pad_alt = (state->pad_alt * 31 + data->gps.alt) / 32.0; + } else { + state->pad_lat = data->gps.lat; + state->pad_lon = data->gps.lon; + state->pad_alt = data->gps.alt; + } + } + } + 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; + state->gps.gps_locked = data->gps.gps_locked; + state->gps.gps_connected = data->gps.gps_connected; + if (data->gps.gps_locked) { + state->gps = data->gps; + state->gps_valid = 1; + if (state->npad) + aoview_great_circle(state->pad_lat, state->pad_lon, state->gps.lat, state->gps.lon, + &state->distance, &state->bearing); + } + if (data->gps_tracking.channels) + state->gps_tracking = data->gps_tracking; + if (state->npad) { + state->gps_height = state->gps.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); + } + if (state->prev_npad < MIN_PAD_SAMPLES && state->npad >= MIN_PAD_SAMPLES) + aoview_voice_speak("g p s ready\n"); +} + +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); + } + } + aostate_timeout = 0; + return FALSE; + } + return TRUE; +} + +void +aoview_state_reset(void) +{ + memset(&aostate, '\0', sizeof (aostate)); +} + +void +aoview_state_notify(struct aodata *data) +{ + struct aostate *state = &aostate; + aoview_state_derive(data, state); + aoview_table_start(); + + if (state->npad >= MIN_PAD_SAMPLES) + aoview_table_add_row(0, "Ground state", "ready"); + else + aoview_table_add_row(0, "Ground state", "waiting for gps (%d)", + MIN_PAD_SAMPLES - state->npad); + aoview_table_add_row(0, "Rocket state", "%s", state->data.state); + aoview_table_add_row(0, "Callsign", "%s", state->data.callsign); + aoview_table_add_row(0, "Rocket serial", "%d", state->data.serial); + + aoview_table_add_row(0, "RSSI", "%6ddBm", state->data.rssi); + aoview_table_add_row(0, "Height", "%6dm", state->height); + aoview_table_add_row(0, "Max height", "%6dm", state->max_height); + aoview_table_add_row(0, "Acceleration", "%7.1fm/s²", state->acceleration); + aoview_table_add_row(0, "Max acceleration", "%7.1fm/s²", state->max_acceleration); + aoview_table_add_row(0, "Speed", "%7.1fm/s", state->ascent ? state->speed : state->baro_speed); + aoview_table_add_row(0, "Max Speed", "%7.1fm/s", state->max_speed); + aoview_table_add_row(0, "Temperature", "%6.2f°C", state->temperature); + aoview_table_add_row(0, "Battery", "%5.2fV", state->battery); + aoview_table_add_row(0, "Drogue", "%5.2fV", state->drogue_sense); + aoview_table_add_row(0, "Main", "%5.2fV", state->main_sense); + aoview_table_add_row(0, "Pad altitude", "%dm", state->ground_altitude); + aoview_table_add_row(1, "Satellites", "%d", state->gps.nsat); + if (state->gps.gps_locked) { + aoview_table_add_row(1, "GPS", "locked"); + } else if (state->gps.gps_connected) { + aoview_table_add_row(1, "GPS", "unlocked"); + } else { + aoview_table_add_row(1, "GPS", "not available"); + } + if (state->gps_valid) { + aoview_state_add_deg(1, "Latitude", state->gps.lat, 'N', 'S'); + aoview_state_add_deg(1, "Longitude", state->gps.lon, 'E', 'W'); + aoview_table_add_row(1, "GPS altitude", "%d", state->gps.alt); + aoview_table_add_row(1, "GPS height", "%d", state->gps_height); + aoview_table_add_row(1, "GPS time", "%02d:%02d:%02d", + state->gps.gps_time.hour, + state->gps.gps_time.minute, + state->gps.gps_time.second); + } + if (state->gps.gps_extended) { + aoview_table_add_row(1, "GPS ground speed", "%7.1fm/s %d°", + state->gps.ground_speed, + state->gps.course); + aoview_table_add_row(1, "GPS climb rate", "%7.1fm/s", + state->gps.climb_rate); + aoview_table_add_row(1, "GPS precision", "%4.1f(hdop) %3dm(h) %3dm(v)", + state->gps.hdop, state->gps.h_error, state->gps.v_error); + } + if (state->npad) { + aoview_table_add_row(1, "Distance from pad", "%5.0fm", state->distance); + aoview_table_add_row(1, "Direction from pad", "%4.0f°", state->bearing); + aoview_state_add_deg(1, "Pad latitude", state->pad_lat, 'N', 'S'); + aoview_state_add_deg(1, "Pad longitude", state->pad_lon, 'E', 'W'); + aoview_table_add_row(1, "Pad GPS alt", "%gm", state->pad_alt); + } + if (state->gps.gps_connected) { + int nsat_vis = 0; + int nsat_locked = 0; + int c; + + for (c = 0; c < state->gps_tracking.channels; c++) { + if ((state->gps_tracking.sats[c].state & 0xff) == 0xbf) + nsat_locked++; + } + aoview_table_add_row(2, "Satellites Visible", "%d", state->gps_tracking.channels); + aoview_table_add_row(2, "Satellites Locked", "%d", nsat_locked); + for (c = 0; c < state->gps_tracking.channels; c++) { + aoview_table_add_row(2, "Satellite id,state,C/N0", + "%3d,%02x,%2d%s", + state->gps_tracking.sats[c].svid, + state->gps_tracking.sats[c].state, + state->gps_tracking.sats[c].c_n0, + (state->gps_tracking.sats[c].state & 0xff) == 0xbf ? + " LOCKED" : ""); + } + } + aoview_table_finish(); + aoview_label_show(state); + aoview_speak_state(state); + if (!aostate_timeout && strcmp(state->data.state, "pad") != 0) + aostate_timeout = g_timeout_add_seconds(10, aoview_state_timeout, NULL); +} + +void +aoview_state_new(void) +{ +} + +void +aoview_state_init(GladeXML *xml) +{ + aoview_state_new(); +} diff --git a/ao-tools/ao-view/aoview_table.c b/ao-tools/ao-view/aoview_table.c new file mode 100644 index 00000000..e75ae670 --- /dev/null +++ b/ao-tools/ao-view/aoview_table.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +#define NCOL 3 + +static GtkTreeView *dataview[NCOL]; +static GtkListStore *datalist[NCOL]; + +void +aoview_table_start(void) +{ + int col; + for (col = 0; col < NCOL; col++) + datalist[col] = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); +} + +void +aoview_table_add_row(int col, char *label, char *format, ...) +{ + char buf[1024]; + va_list ap; + GtkTreeIter iter; + + va_start(ap, format); + vsnprintf(buf, sizeof (buf), format, ap); + va_end(ap); + gtk_list_store_append(datalist[col], &iter); + gtk_list_store_set(datalist[col], &iter, + 0, label, + 1, buf, + -1); +} + +void +aoview_table_finish(void) +{ + int col; + for (col = 0; col < NCOL; col++) { + gtk_tree_view_set_model(dataview[col], GTK_TREE_MODEL(datalist[col])); + g_object_unref(G_OBJECT(datalist[col])); + gtk_tree_view_columns_autosize(dataview[col]); + } +} + +void +aoview_table_clear(void) +{ + int col; + for (col = 0; col < NCOL; col++) + gtk_tree_view_set_model(dataview[col], NULL); +} + +void +aoview_table_init(GladeXML *xml) +{ + int col; + + for (col = 0; col < NCOL; col++) { + char name[32]; + sprintf(name, "dataview_%d", col); + dataview[col] = GTK_TREE_VIEW(glade_xml_get_widget(xml, name)); + assert(dataview[col]); + + aoview_add_plain_text_column(dataview[col], "Field", 0, 20); + aoview_add_plain_text_column(dataview[col], "Value", 1, 32); + } +} diff --git a/ao-tools/ao-view/aoview_util.c b/ao-tools/ao-view/aoview_util.c new file mode 100644 index 00000000..6ea62ac9 --- /dev/null +++ b/ao-tools/ao-view/aoview_util.c @@ -0,0 +1,91 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +char * +aoview_fullname (char *dir, char *file) +{ + char *new; + int dlen = strlen (dir); + int flen = strlen (file); + int slen = 0; + + if (dir[dlen-1] != '/') + slen = 1; + new = malloc (dlen + slen + flen + 1); + if (!new) + return 0; + strcpy(new, dir); + if (slen) + strcat (new, "/"); + strcat(new, file); + return new; +} + +char * +aoview_basename(char *file) +{ + char *b; + + b = strrchr(file, '/'); + if (!b) + return file; + return b + 1; +} + +int +aoview_mkdir(char *dir) +{ + char *slash; + char *d; + char *part; + + d = dir; + for (;;) { + slash = strchr (d, '/'); + if (!slash) + slash = d + strlen(d); + if (!*slash) + break; + part = strndup(dir, slash - dir); + if (!access(part, F_OK)) + if (mkdir(part, 0777) < 0) + return -errno; + free(part); + d = slash + 1; + } + return 0; +} + +GtkTreeViewColumn * +aoview_add_plain_text_column (GtkTreeView *view, const gchar *title, gint model_column, gint width) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + renderer = gtk_cell_renderer_text_new (); + g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_NONE, NULL); + g_object_set(renderer, "width-chars", width, NULL); + column = gtk_tree_view_column_new_with_attributes (title, renderer, + "text", model_column, + NULL); + gtk_tree_view_column_set_resizable (column, FALSE); + gtk_tree_view_append_column (view, column); + + return column; +} diff --git a/ao-tools/ao-view/aoview_voice.c b/ao-tools/ao-view/aoview_voice.c new file mode 100644 index 00000000..24422df6 --- /dev/null +++ b/ao-tools/ao-view/aoview_voice.c @@ -0,0 +1,122 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "aoview.h" + +#if HAVE_FLITE +#include + +FILE *aoview_flite; + +void aoview_voice_open(void) +{ + int err; + + if (!aoview_flite) + aoview_flite = aoview_flite_start(); +} + +void aoview_voice_close(void) +{ + if (aoview_flite) { + aoview_flite_stop(); + aoview_flite = NULL; + } +} + +void aoview_voice_speak(char *format, ...) +{ + va_list ap; + + if (aoview_flite) { + va_start(ap, format); + vfprintf(aoview_flite, format, ap); + fflush(aoview_flite); + va_end(ap); + } +} + +#else +void aoview_voice_open(void) +{ +} + +void aoview_voice_close(void) +{ +} + +void aoview_voice_speak(char *format, ...) +{ +} +#endif + + +static GtkCheckMenuItem *voice_enable; + +#define ALTOS_VOICE_PATH "/apps/aoview/voice" + +static void +aoview_voice_enable(GtkWidget *widget, gpointer data) +{ + 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\n"); + } else { + 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) +{ + 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); +} diff --git a/ao-tools/ao-view/design b/ao-tools/ao-view/design new file mode 100644 index 00000000..6ec2ea70 --- /dev/null +++ b/ao-tools/ao-view/design @@ -0,0 +1,27 @@ +Requirements: + real-time display of telemetry + off-line display of logged data + Logging of telemetry + Capture of logged data to disk + +Input data: + accelerometer + barometer + thermometer + gps + drogue and main continuity + battery voltage + time + reported flight state + reported events + +Computed data: + velocity (from accelerometer) + altitude + range + direction + +Displays: + numeric display of current rocket status + (graphics come later) + text message log diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index 9584e216..f66ee0a9 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -16,6 +16,9 @@ libao_tools_a_SOURCES = \ ccdbg-state.c \ cc-usb.c \ cc-usb.h \ + cc.h \ + cc-usbdev.c \ + cc-util.c \ cc-bitbang.c \ cc-bitbang.h \ cp-usb-async.c \ diff --git a/ao-tools/lib/cc-usbdev.c b/ao-tools/lib/cc-usbdev.c new file mode 100644 index 00000000..d8bb8b11 --- /dev/null +++ b/ao-tools/lib/cc-usbdev.c @@ -0,0 +1,228 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "cc.h" + +#include +#include +#include +#include +#include + +static char * +load_string(char *dir, char *file) +{ + char *full = cc_fullname(dir, file); + char line[4096]; + char *r; + FILE *f; + int rlen; + + f = fopen(full, "r"); + free(full); + if (!f) + return NULL; + r = fgets(line, sizeof (line), f); + fclose(f); + if (!r) + return NULL; + rlen = strlen(r); + if (r[rlen-1] == '\n') + r[rlen-1] = '\0'; + return strdup(r); +} + +static int +load_hex(char *dir, char *file) +{ + char *line; + char *end; + long i; + + line = load_string(dir, file); + if (!line) + return -1; + i = strtol(line, &end, 16); + free(line); + if (end == line) + return -1; + return i; +} + +static int +dir_filter_tty_colon(const struct dirent *d) +{ + return strncmp(d->d_name, "tty:", 4) == 0; +} + +static int +dir_filter_tty(const struct dirent *d) +{ + return strncmp(d->d_name, "tty", 3) == 0; +} + +static char * +usb_tty(char *sys) +{ + char *base; + int num_configs; + int config; + struct dirent **namelist; + int interface; + int num_interfaces; + char endpoint_base[20]; + char *endpoint_full; + char *tty_dir; + int ntty; + char *tty; + + base = cc_basename(sys); + num_configs = load_hex(sys, "bNumConfigurations"); + num_interfaces = load_hex(sys, "bNumInterfaces"); + for (config = 1; config <= num_configs; config++) { + for (interface = 0; interface < num_interfaces; interface++) { + sprintf(endpoint_base, "%s:%d.%d", + base, config, interface); + endpoint_full = cc_fullname(sys, endpoint_base); + + /* Check for tty:ttyACMx style names + */ + ntty = scandir(endpoint_full, &namelist, + dir_filter_tty_colon, + alphasort); + if (ntty > 0) { + free(endpoint_full); + tty = cc_fullname("/dev", namelist[0]->d_name + 4); + free(namelist); + return tty; + } + + /* Check for tty/ttyACMx style names + */ + tty_dir = cc_fullname(endpoint_full, "tty"); + free(endpoint_full); + ntty = scandir(tty_dir, &namelist, + dir_filter_tty, + alphasort); + free (tty_dir); + if (ntty > 0) { + tty = cc_fullname("/dev", namelist[0]->d_name); + free(namelist); + return tty; + } + } + } + return NULL; +} + +static struct cc_usbdev * +usb_scan_device(char *sys) +{ + struct cc_usbdev *usbdev; + + usbdev = calloc(1, sizeof (struct cc_usbdev)); + if (!usbdev) + return NULL; + usbdev->sys = strdup(sys); + usbdev->manufacturer = load_string(sys, "manufacturer"); + usbdev->product = load_string(sys, "product"); + usbdev->serial = load_string(sys, "serial"); + usbdev->idProduct = load_hex(sys, "idProduct"); + usbdev->idVendor = load_hex(sys, "idVendor"); + usbdev->tty = usb_tty(sys); + return usbdev; +} + +static void +usbdev_free(struct cc_usbdev *usbdev) +{ + free(usbdev->sys); + free(usbdev->manufacturer); + free(usbdev->product); + free(usbdev->serial); + free(usbdev->tty); + free(usbdev); +} + +#define USB_DEVICES "/sys/bus/usb/devices" + +static int +dir_filter_dev(const struct dirent *d) +{ + const char *n = d->d_name; + char c; + + while ((c = *n++)) { + if (isdigit(c)) + continue; + if (c == '-') + continue; + if (c == '.' && n != d->d_name + 1) + continue; + return 0; + } + return 1; +} + +struct cc_usbdevs * +cc_usbdevs_scan(void) +{ + int e; + struct dirent **ents; + char *dir; + struct cc_usbdev *dev; + struct cc_usbdevs *devs; + int n; + + devs = calloc(1, sizeof (struct cc_usbdevs)); + if (!devs) + return NULL; + + n = scandir (USB_DEVICES, &ents, + dir_filter_dev, + alphasort); + if (!n) + return 0; + for (e = 0; e < n; e++) { + dir = cc_fullname(USB_DEVICES, ents[e]->d_name); + dev = usb_scan_device(dir); + free(dir); + if (dev->idVendor == 0xfffe && dev->tty) { + if (devs->dev) + devs->dev = realloc(devs->dev, + devs->ndev + 1 * sizeof (struct usbdev *)); + else + devs->dev = malloc (sizeof (struct usbdev *)); + devs->dev[devs->ndev++] = dev; + } + } + free(ents); + return devs; +} + +void +cc_usbdevs_free(struct cc_usbdevs *usbdevs) +{ + int i; + + if (!usbdevs) + return; + for (i = 0; i < usbdevs->ndev; i++) + usbdev_free(usbdevs->dev[i]); + free(usbdevs); +} diff --git a/ao-tools/lib/cc-util.c b/ao-tools/lib/cc-util.c new file mode 100644 index 00000000..7104470c --- /dev/null +++ b/ao-tools/lib/cc-util.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "cc.h" +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +char * +cc_fullname (char *dir, char *file) +{ + char *new; + int dlen = strlen (dir); + int flen = strlen (file); + int slen = 0; + + if (dir[dlen-1] != '/') + slen = 1; + new = malloc (dlen + slen + flen + 1); + if (!new) + return 0; + strcpy(new, dir); + if (slen) + strcat (new, "/"); + strcat(new, file); + return new; +} + +char * +cc_basename(char *file) +{ + char *b; + + b = strrchr(file, '/'); + if (!b) + return file; + return b + 1; +} + +int +cc_mkdir(char *dir) +{ + char *slash; + char *d; + char *part; + + d = dir; + for (;;) { + slash = strchr (d, '/'); + if (!slash) + slash = d + strlen(d); + if (!*slash) + break; + part = strndup(dir, slash - dir); + if (!access(part, F_OK)) + if (mkdir(part, 0777) < 0) + return -errno; + free(part); + d = slash + 1; + } + return 0; +} diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h new file mode 100644 index 00000000..dad11bf3 --- /dev/null +++ b/ao-tools/lib/cc.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _CC_H_ +#define _CC_H_ + +char * +cc_fullname (char *dir, char *file); + +char * +cc_basename(char *file); + +int +cc_mkdir(char *dir); + +struct cc_usbdev { + char *sys; + char *tty; + char *manufacturer; + char *product; + char *serial; + int idProduct; + int idVendor; +}; + +struct cc_usbdevs { + struct cc_usbdev **dev; + int ndev; +}; + +void +cc_usbdevs_free(struct cc_usbdevs *usbdevs); + +struct cc_usbdevs * +cc_usbdevs_scan(void); + +#endif /* _CC_H_ */ diff --git a/ao-view/.gitignore b/ao-view/.gitignore deleted file mode 100644 index 24fbc596..00000000 --- a/ao-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.o -aoview -aoview_glade.h -aoview_flite diff --git a/ao-view/Makefile.am b/ao-view/Makefile.am deleted file mode 100644 index 17661c8e..00000000 --- a/ao-view/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -VERSION=$(shell git describe) - -AM_CFLAGS=$(GNOME_CFLAGS) $(ALSA_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\" @FLITE_INCS@ - -bin_PROGRAMS=ao-view - -ao_view_LDADD=$(GNOME_LIBS) $(FLITE_LIBS) $(ALSA_LIBS) - -ao_view_SOURCES = \ - aoview_main.c \ - aoview_dev.c \ - aoview_dev_dialog.c \ - aoview_serial.c \ - aoview_monitor.c \ - aoview_state.c \ - aoview_convert.c \ - aoview_log.c \ - aoview_table.c \ - aoview_util.c \ - aoview_file.c \ - aoview_eeprom.c \ - aoview_voice.c \ - aoview_replay.c \ - aoview_label.c \ - aoview_flite.c \ - aoview.h - -BUILT_SOURCES = aoview_glade.h - -CLEANFILES = aoview_glade.h - -man_MANS=ao-view.1 - -aoview_glade.h: aoview.glade - sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/"/' $< > $@ diff --git a/ao-view/ao-view.1 b/ao-view/ao-view.1 deleted file mode 100644 index 99834c4e..00000000 --- a/ao-view/ao-view.1 +++ /dev/null @@ -1,50 +0,0 @@ -.\" -.\" Copyright © 2009 Keith Packard -.\" -.\" This program is free software; you can redistribute it and/or modify -.\" it under the terms of the GNU General Public License as published by -.\" the Free Software Foundation; either version 2 of the License, or -.\" (at your option) any later version. -.\" -.\" This program is distributed in the hope that it will be useful, but -.\" WITHOUT ANY WARRANTY; without even the implied warranty of -.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -.\" General Public License for more details. -.\" -.\" You should have received a copy of the GNU General Public License along -.\" with this program; if not, write to the Free Software Foundation, Inc., -.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -.\" -.\" -.TH AO-VIEW 1 "ao-view" "" -.SH NAME -ao-view \- Rocket flight monitor -.SH SYNOPSIS -.B "ao-view" -[\--tty \fItty-device\fP] -.SH DESCRIPTION -.I ao-view -connects to a TeleDongle or TeleMetrum device through a USB serial device. -It provides a user interface to monitor, record and review rocket flight data. -.SH OPTIONS -The usual Gtk+ command line options can be used, along with -.IP "\--tty" -This selects a target device to connect at startup time to. -The target device may also be selected through the user interface. -.SH USAGE -When connected to a TeleDongle device, ao-view turns on the radio -receiver and listens for telemetry packets. It displays the received -telemetry data, and reports flight status via voice synthesis. All -received telemetry information is recorded to a file. -.P -When connected to a TeleMetrum device, ao-view downloads the eeprom -data and stores it in a file. -.SH FILES -All data log files are recorded into a user-specified directory -(default ~/AltOS). Files are named using the current date, the serial -number of the reporting device, the flight number recorded in the data -and either '.telem' for telemetry data or '.eeprom' for eeprom data. -.SH "SEE ALSO" -ao-load(1), ao-eeprom(1) -.SH AUTHOR -Keith Packard diff --git a/ao-view/aoview.glade b/ao-view/aoview.glade deleted file mode 100644 index 9a746110..00000000 --- a/ao-view/aoview.glade +++ /dev/null @@ -1,744 +0,0 @@ - - - - - - 900 - 700 - True - AltOS View - - - True - vertical - - - True - - - True - _File - True - - - True - - - gtk-new - True - True - True - - - - - gtk-open - True - True - True - - - - - gtk-save - True - True - True - - - - - gtk-save-as - True - True - True - - - - - True - - - - - gtk-quit - True - True - True - - - - - - - - - - True - _Edit - True - - - True - - - gtk-cut - True - True - True - - - - - gtk-copy - True - True - True - - - - - gtk-paste - True - True - True - - - - - gtk-delete - True - True - True - - - - - - - - - True - _Device - True - - - True - - - _Connect to device - True - True - False - - - - - True - gtk-connect - - - - - - - _Disconnect - True - True - False - - - True - gtk-disconnect - - - - - - - True - False - - - - - _Save EEPROM data - True - True - False - - - - - True - gtk-save - - - - - - - _Replay - True - True - False - - - - - True - gtk-media-play - - - - - - - - - - - True - _Log - True - - - True - - - _New log - True - True - False - - - True - gtk-new - - - - - - - _Configure Log - True - True - False - - - - True - gtk-preferences - - - - - - - - - - - True - _Voice - True - - - True - - - True - Enable _Voice - True - True - - - - - - - - - True - _Help - True - - - True - - - gtk-about - True - True - True - - - - - - - - - - False - 0 - - - - - True - 2 - 4 - 3 - True - - - True - Height (m) - center - - - - - True - State - - - 1 - 2 - - - - - True - RSSI (dBm) - - - 2 - 3 - - - - - True - 2 - 0 - True - - - 1 - 2 - - - - - True - 2 - pad - True - - - 1 - 2 - 1 - 2 - - - - - True - 2 - -50 - True - - - 2 - 3 - 1 - 2 - - - - - True - Speed (m/s) - - - 3 - 4 - - - - - True - 0 - True - - - 3 - 4 - 1 - 2 - - - - - False - 1 - - - - - True - - - True - True - False - both - - - 0 - - - - - True - True - False - both - - - 1 - - - - - True - True - False - both - - - 2 - - - - - 2 - - - - - - - 5 - normal - False - - - True - vertical - 2 - - - 300 - 100 - True - True - False - True - 0 - False - 1 - both - True - - - 1 - - - - - True - end - - - gtk-cancel - 1 - True - True - True - True - True - - - - False - False - 0 - - - - - gtk-connect - True - True - True - True - True - True - - - False - False - 1 - - - - - False - end - 0 - - - - - - - 5 - Configure Log Directory - dialog - False - select-folder - - - True - vertical - 2 - - - True - end - - - gtk-cancel - True - True - True - True - - - - False - False - 0 - - - - - gtk-ok - True - True - True - True - True - True - - - False - False - 1 - - - - - False - end - 0 - - - - - - - 5 - Failed to create log - normal - True - aoview - error - close - Cannot create log file - - - True - vertical - 2 - - - True - end - - - False - end - 0 - - - - - - - 5 - Failed to open device - normal - True - aoview - error - close - Cannot open device - - - True - vertical - 2 - - - True - end - - - False - end - 0 - - - - - - - 5 - About AoView - False - normal - aoview - False - AoView - Copyright © 2009 Keith Packard - AltOS data capture and display. - http://altusmetrum.org - AoView is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. - -AoView is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with AoView; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Keith Packard <keithp@keithp.com> - True - - - - - True - vertical - 2 - - - True - end - - - False - end - 0 - - - - - - - 5 - EEPROM save complete - normal - True - aoview - close - Saving EEPROM data as - <filename> - - - - - True - vertical - 2 - - - True - end - - - False - end - 0 - - - - - - - 5 - True - dialog - True - aoview - False - - - True - vertical - 2 - - - True - end - - - gtk-cancel - True - True - True - True - - - - False - False - 0 - - - - - gtk-ok - True - True - True - True - - - False - False - 1 - - - - - False - end - 0 - - - - - - diff --git a/ao-view/aoview.h b/ao-view/aoview.h deleted file mode 100644 index 9ca65298..00000000 --- a/ao-view/aoview.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#ifndef _AOVIEW_H_ -#define _AOVIEW_H_ - -#define _GNU_SOURCE - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -struct usbdev { - char *sys; - char *tty; - char *manufacturer; - char *product; - char *serial; - int idProduct; - int idVendor; -}; - -struct aogps_time { - int hour; - int minute; - int second; -}; - -struct aogps { - int nsat; - int gps_locked; - int gps_connected; - struct aogps_time gps_time; - double lat; /* degrees (+N -S) */ - double lon; /* degrees (+E -W) */ - int alt; /* m */ - - int gps_extended; /* has extra data */ - double ground_speed; /* m/s */ - int course; /* degrees */ - double climb_rate; /* m/s */ - double hdop; /* unitless? */ - int h_error; /* m */ - int v_error; /* m */ -}; - -#define SIRF_SAT_STATE_ACQUIRED (1 << 0) -#define SIRF_SAT_STATE_CARRIER_PHASE_VALID (1 << 1) -#define SIRF_SAT_BIT_SYNC_COMPLETE (1 << 2) -#define SIRF_SAT_SUBFRAME_SYNC_COMPLETE (1 << 3) -#define SIRF_SAT_CARRIER_PULLIN_COMPLETE (1 << 4) -#define SIRF_SAT_CODE_LOCKED (1 << 5) -#define SIRF_SAT_ACQUISITION_FAILED (1 << 6) -#define SIRF_SAT_EPHEMERIS_AVAILABLE (1 << 7) - -struct aogps_sat { - int svid; - int state; - int c_n0; -}; - -struct aogps_tracking { - int channels; - struct aogps_sat sats[12]; -}; - -struct aodata { - char callsign[16]; - int serial; - int rssi; - char state[16]; - int tick; - int accel; - int pres; - int temp; - int batt; - int drogue; - int main; - int flight_accel; - int ground_accel; - int flight_vel; - int flight_pres; - int ground_pres; - struct aogps gps; - struct aogps_tracking gps_tracking; -}; - -struct aostate { - struct aodata data; - - /* derived data */ - - struct aodata prev_data; - - double report_time; - - gboolean ascent; /* going up? */ - - int ground_altitude; - int height; - double speed; - double acceleration; - double battery; - double temperature; - double main_sense; - double drogue_sense; - double baro_speed; - - int max_height; - double max_acceleration; - double max_speed; - - struct aogps gps; - struct aogps_tracking gps_tracking; - - int gps_valid; - double pad_lat; - double pad_lon; - double pad_alt; - double pad_lat_total; - double pad_lon_total; - double pad_alt_total; - int npad; - int prev_npad; - - double distance; - double bearing; - int gps_height; - - int speak_tick; - int speak_altitude; -}; - -extern struct aostate aostate; - -/* GPS is 'stable' when we've seen at least this many samples */ -#define MIN_PAD_SAMPLES 10 - -void -aoview_monitor_disconnect(void); - -gboolean -aoview_monitor_connect(char *tty); - -gboolean -aoview_monitor_parse(const char *line); - -void -aoview_monitor_reset(void); - -struct aoview_serial * -aoview_serial_open(const char *tty); - -void -aoview_serial_close(struct aoview_serial *serial); - -typedef void (*aoview_serial_callback)(gpointer user_data, struct aoview_serial *serial, gint revents); - -void -aoview_serial_set_callback(struct aoview_serial *serial, - aoview_serial_callback func); - -void -aoview_serial_printf(struct aoview_serial *serial, char *format, ...); - -int -aoview_serial_read(struct aoview_serial *serial, char *buf, int len); - -int -aoview_serial_getc(struct aoview_serial *serial); - -void -aoview_dev_dialog_init(GladeXML *xml); - -int -aoview_usb_scan(struct usbdev ***devs_ret); - -void -aoview_usbdev_free(struct usbdev *usbdev); - -void -aoview_state_notify(struct aodata *data); - -void -aoview_state_new(void); - -void -aoview_state_init(GladeXML *xml); - -int16_t -aoview_pres_to_altitude(int16_t pres); - -int16_t -aoview_altitude_to_pres(int16_t alt); - -char * -aoview_fullname (char *dir, char *file); - -char * -aoview_basename(char *file); - -GtkTreeViewColumn * -aoview_add_plain_text_column (GtkTreeView *view, const gchar *title, gint model_column, gint width); - -int -aoview_mkdir(char *dir); - -void -aoview_log_init(GladeXML *xml); - -void -aoview_log_set_serial(int serial); - -int -aoview_log_get_serial(void); - -void -aoview_log_printf(char *format, ...); - -void -aoview_log_new(void); - -void -aoview_table_start(void); - -void -aoview_table_add_row(int column, char *label, char *format, ...); - -void -aoview_table_finish(void); - -void -aoview_table_init(GladeXML *xml); - -void -aoview_table_clear(void); - -struct aoview_file; - -extern char *aoview_file_dir; - -void -aoview_file_finish(struct aoview_file *file); - -gboolean -aoview_file_start(struct aoview_file *file); - -const char * -aoview_file_name(struct aoview_file *file); - -void -aoview_file_set_serial(struct aoview_file *file, int serial); - -int -aoview_file_get_serial(struct aoview_file *file); - -void -aoview_file_printf(struct aoview_file *file, char *format, ...); - -void -aoview_file_vprintf(struct aoview_file *file, char *format, va_list ap); - -struct aoview_file * -aoview_file_new(char *ext); - -void -aoview_file_destroy(struct aoview_file *file); - -void -aoview_file_init(GladeXML *xml); - -/* aoview_eeprom.c */ - -gboolean -aoview_eeprom_save(const char *device); - -void -aoview_eeprom_init(GladeXML *xml); - -/* aoview_voice.c */ -void aoview_voice_open(void); - -void aoview_voice_close(void); - -void aoview_voice_speak(char *format, ...); - -/* aoview_label.c */ - -void aoview_label_init(GladeXML *xml); - -void -aoview_label_show(struct aostate *state); - -/* aoview_flite.c */ - -FILE * -aoview_flite_start(void); - -void -aoview_flite_stop(void); - -/* aoview_main.c */ - -extern char *aoview_tty; - -#endif /* _AOVIEW_H_ */ diff --git a/ao-view/aoview_convert.c b/ao-view/aoview_convert.c deleted file mode 100644 index 02416647..00000000 --- a/ao-view/aoview_convert.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -static int16_t altitude_table[2048] = { -#include "altitude.h" -}; - -int16_t -aoview_pres_to_altitude(int16_t pres) -{ - pres = pres >> 4; - if (pres < 0) pres = 0; - if (pres > 2047) pres = 2047; - return altitude_table[pres]; -} - -int16_t -aoview_altitude_to_pres(int16_t alt) -{ - int16_t pres; - - for (pres = 0; pres < 2047; pres++) - if (altitude_table[pres] <= alt) - break; - return pres << 4; -} diff --git a/ao-view/aoview_dev.c b/ao-view/aoview_dev.c deleted file mode 100644 index 9b8cc19e..00000000 --- a/ao-view/aoview_dev.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" -#include -#include - -static char * -load_string(char *dir, char *file) -{ - char *full = aoview_fullname(dir, file); - char line[4096]; - char *r; - FILE *f; - int rlen; - - f = fopen(full, "r"); - free(full); - if (!f) - return NULL; - r = fgets(line, sizeof (line), f); - fclose(f); - if (!r) - return NULL; - rlen = strlen(r); - if (r[rlen-1] == '\n') - r[rlen-1] = '\0'; - return strdup(r); -} - -static int -load_hex(char *dir, char *file) -{ - char *line; - char *end; - long i; - - line = load_string(dir, file); - if (!line) - return -1; - i = strtol(line, &end, 16); - free(line); - if (end == line) - return -1; - return i; -} - -static int -dir_filter_tty_colon(const struct dirent *d) -{ - return strncmp(d->d_name, "tty:", 4) == 0; -} - -static int -dir_filter_tty(const struct dirent *d) -{ - return strncmp(d->d_name, "tty", 3) == 0; -} - -static char * -usb_tty(char *sys) -{ - char *base; - int num_configs; - int config; - struct dirent **namelist; - int interface; - int num_interfaces; - char endpoint_base[20]; - char *endpoint_full; - char *tty_dir; - int ntty; - char *tty; - - base = aoview_basename(sys); - num_configs = load_hex(sys, "bNumConfigurations"); - num_interfaces = load_hex(sys, "bNumInterfaces"); - for (config = 1; config <= num_configs; config++) { - for (interface = 0; interface < num_interfaces; interface++) { - sprintf(endpoint_base, "%s:%d.%d", - base, config, interface); - endpoint_full = aoview_fullname(sys, endpoint_base); - - /* Check for tty:ttyACMx style names - */ - ntty = scandir(endpoint_full, &namelist, - dir_filter_tty_colon, - alphasort); - if (ntty > 0) { - free(endpoint_full); - tty = aoview_fullname("/dev", namelist[0]->d_name + 4); - free(namelist); - return tty; - } - - /* Check for tty/ttyACMx style names - */ - tty_dir = aoview_fullname(endpoint_full, "tty"); - free(endpoint_full); - ntty = scandir(tty_dir, &namelist, - dir_filter_tty, - alphasort); - free (tty_dir); - if (ntty > 0) { - tty = aoview_fullname("/dev", namelist[0]->d_name); - free(namelist); - return tty; - } - } - } - return NULL; -} - -static struct usbdev * -usb_scan_device(char *sys) -{ - struct usbdev *usbdev; - - usbdev = calloc(1, sizeof (struct usbdev)); - if (!usbdev) - return NULL; - usbdev->sys = strdup(sys); - usbdev->manufacturer = load_string(sys, "manufacturer"); - usbdev->product = load_string(sys, "product"); - usbdev->serial = load_string(sys, "serial"); - usbdev->idProduct = load_hex(sys, "idProduct"); - usbdev->idVendor = load_hex(sys, "idVendor"); - usbdev->tty = usb_tty(sys); - return usbdev; -} - -void -aoview_usbdev_free(struct usbdev *usbdev) -{ - free(usbdev->sys); - free(usbdev->manufacturer); - free(usbdev->product); - free(usbdev->serial); - free(usbdev->tty); - free(usbdev); -} - -#define USB_DEVICES "/sys/bus/usb/devices" - -static int -dir_filter_dev(const struct dirent *d) -{ - const char *n = d->d_name; - char c; - - while ((c = *n++)) { - if (isdigit(c)) - continue; - if (c == '-') - continue; - if (c == '.' && n != d->d_name + 1) - continue; - return 0; - } - return 1; -} - -int -aoview_usb_scan(struct usbdev ***devs_ret) -{ - int n; - int ndev = 0; - int e; - struct dirent **ents; - char *dir; - struct usbdev **devs = NULL; - struct usbdev *dev; - - n = scandir (USB_DEVICES, &ents, - dir_filter_dev, - alphasort); - if (!n) - return 0; - for (e = 0; e < n; e++) { - dir = aoview_fullname(USB_DEVICES, ents[e]->d_name); - dev = usb_scan_device(dir); - free(dir); - if (dev->idVendor == 0xfffe && dev->tty) { - if (devs) - devs = realloc(devs, ndev + 1 * sizeof (struct usbdev *)); - else - devs = malloc (sizeof (struct usbdev *)); - devs[ndev++] = dev; - } - } - free(ents); - *devs_ret = devs; - return ndev; -} diff --git a/ao-view/aoview_dev_dialog.c b/ao-view/aoview_dev_dialog.c deleted file mode 100644 index 3f92085c..00000000 --- a/ao-view/aoview_dev_dialog.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -static void -aoview_dev_dialog_map(GtkWidget *widget, gpointer data) -{ - GtkTreeView *dev_list = data; - GtkListStore *list_store; - GtkTreeIter iter; - int ndev, n; - struct usbdev **devs; - - list_store = gtk_list_store_new(3, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_STRING); - - ndev = aoview_usb_scan(&devs); - for (n = 0; n < ndev; n++) { - gtk_list_store_append(list_store, &iter); - gtk_list_store_set(list_store, &iter, - 0, devs[n]->product, - 1, devs[n]->serial, - 2, devs[n]->tty, - -1); - } - gtk_tree_view_set_model (dev_list, GTK_TREE_MODEL(list_store)); - g_object_unref(G_OBJECT(list_store)); - gtk_tree_view_columns_autosize(dev_list); -} - -static GtkMessageDialog *dev_open_fail_dialog; - -static void -aoview_dev_open_failed(char *name) -{ - char *utf8_file; - utf8_file = g_filename_to_utf8(name, -1, NULL, NULL, NULL); - if (!utf8_file) - utf8_file = name; - gtk_message_dialog_format_secondary_text(dev_open_fail_dialog, - "\"%s\"", utf8_file); - if (utf8_file != name) - g_free(utf8_file); - gtk_dialog_run(GTK_DIALOG(dev_open_fail_dialog)); - gtk_widget_hide(GTK_WIDGET(dev_open_fail_dialog)); -} - -gboolean dialog_save_log; - -static void -aoview_dev_selected(GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) -{ - gchar *string; - gtk_tree_model_get(model, iter, - 2, &string, - -1); - if (dialog_save_log) { - dialog_save_log = FALSE; - if (!aoview_eeprom_save(string)) - aoview_dev_open_failed(string); - } else { - if (!aoview_monitor_connect(string)) - aoview_dev_open_failed(string); - } -} - -static GtkWidget *dialog; - -static void -aoview_dev_dialog_connect(GtkWidget *widget, gpointer data) -{ - GtkTreeView *dev_list = data; - GtkListStore *list_store; - GtkTreeSelection *tree_selection; - - list_store = GTK_LIST_STORE(gtk_tree_view_get_model(dev_list)); - tree_selection = gtk_tree_view_get_selection(dev_list); - gtk_tree_selection_selected_foreach(tree_selection, - aoview_dev_selected, - data); - gtk_widget_hide(dialog); -} - -static void -aoview_dev_disconnect(GtkWidget *widget) -{ - aoview_monitor_disconnect(); -} - -static void -aoview_dev_savelog(GtkWidget *widget, gpointer data) -{ - dialog_save_log = TRUE; - gtk_widget_show(dialog); -} - -#define _(a) a - -void -aoview_dev_dialog_init(GladeXML *xml) -{ - GtkTreeView *dev_list; - GtkWidget *connect_button; - GtkTreeSelection *dev_selection; - GtkWidget *ao_disconnect; - GtkWidget *ao_savelog; - - dialog = glade_xml_get_widget(xml, "device_connect_dialog"); - assert(dialog); - - dev_list = GTK_TREE_VIEW(glade_xml_get_widget(xml, "dev_list")); - assert(dev_list); - - aoview_add_plain_text_column(dev_list, _("Product"), 0, 16); - aoview_add_plain_text_column(dev_list, _("Serial"), 1, 8); - aoview_add_plain_text_column(dev_list, _("Device"), 2, 13); - - dev_selection = gtk_tree_view_get_selection(dev_list); - gtk_tree_selection_set_mode(dev_selection, GTK_SELECTION_SINGLE); - - g_signal_connect(G_OBJECT(dialog), "map", - G_CALLBACK(aoview_dev_dialog_map), - dev_list); - - connect_button = glade_xml_get_widget(xml, "connect_button"); - assert(connect_button); - - g_signal_connect(G_OBJECT(connect_button), "clicked", - G_CALLBACK(aoview_dev_dialog_connect), - dev_list); - - - ao_disconnect = glade_xml_get_widget(xml, "ao_disconnect"); - assert(ao_disconnect); - - g_signal_connect(G_OBJECT(ao_disconnect), "activate", - G_CALLBACK(aoview_dev_disconnect), - ao_disconnect); - - ao_savelog = glade_xml_get_widget(xml, "ao_savelog"); - assert(ao_savelog); - - g_signal_connect(G_OBJECT(ao_savelog), "activate", - G_CALLBACK(aoview_dev_savelog), - dialog); - dev_open_fail_dialog = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "dev_open_fail_dialog")); - assert(dev_open_fail_dialog); -} diff --git a/ao-view/aoview_eeprom.c b/ao-view/aoview_eeprom.c deleted file mode 100644 index 34e2deed..00000000 --- a/ao-view/aoview_eeprom.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -#define EEPROM_LEN 1024 - -static struct aoview_file *eeprom_file; -static char eeprom_line[EEPROM_LEN + 1]; -static int eeprom_pos; -static GtkMessageDialog *eeprom_save_done; -static GtkWidget *eeprom_save_close; -static gboolean eeprom_save_shown; - -static void -aoview_eeprom_disconnect(struct aoview_serial *serial) -{ - aoview_file_finish(eeprom_file); -} - -static void -aoview_eeprom_done(struct aoview_serial *serial) -{ - gtk_window_set_title(GTK_WINDOW(eeprom_save_done), - "EEPROM data saved"); - gtk_message_dialog_set_markup(eeprom_save_done, - "EEPROM data saved as"); - if (!eeprom_save_shown) - gtk_widget_show(GTK_WIDGET(eeprom_save_done)); - eeprom_save_close = gtk_window_get_default_widget(GTK_WINDOW(eeprom_save_done)); - if (eeprom_save_close) - gtk_widget_set_sensitive(eeprom_save_close, TRUE); - aoview_eeprom_disconnect(serial); -} - -static gboolean -aoview_eeprom_parse(struct aoview_serial *serial, - char *line) -{ - char cmd; - int tick; - int a; - int b; - int serial_number; - const char *name; - char *utf8_name; - - if (!strcmp(line, "end")) { - aoview_eeprom_done(serial); - return FALSE; - } - if (sscanf(line, "serial-number %u", &serial_number) == 1) { - aoview_file_set_serial(eeprom_file, serial_number); - } else if (sscanf(line, "%c %x %x %x", &cmd, &tick, &a, &b) == 4) { - aoview_file_printf(eeprom_file, "%s\n", line); - if (cmd == 'S' && a == 8) { - aoview_eeprom_done(serial); - return FALSE; - } - - if (!eeprom_save_shown) - { - name = aoview_file_name(eeprom_file); - if (name) { - utf8_name = g_filename_to_utf8(name, -1, NULL, NULL, NULL); - if (!utf8_name) - utf8_name = (char *) name; - gtk_widget_set_sensitive(eeprom_save_close, FALSE); - gtk_window_set_title(GTK_WINDOW(eeprom_save_done), - "Saving EEPROM data"); - gtk_message_dialog_set_markup(eeprom_save_done, - "Saving EEPROM data as"); - gtk_message_dialog_format_secondary_text(eeprom_save_done, "%s", - utf8_name); - if (utf8_name != name) - g_free(utf8_name); - gtk_container_check_resize(GTK_CONTAINER(eeprom_save_done)); - gtk_widget_show(GTK_WIDGET(eeprom_save_done)); - eeprom_save_shown = TRUE; - eeprom_save_close = gtk_window_get_default_widget(GTK_WINDOW(eeprom_save_done)); - if (eeprom_save_close) - gtk_widget_set_sensitive(eeprom_save_close, FALSE); - } - } - } - return TRUE; -} - -static void -aoview_eeprom_callback(gpointer user_data, - struct aoview_serial *serial, - gint revents) -{ - int c; - - if (revents & (G_IO_HUP|G_IO_ERR)) { - aoview_eeprom_disconnect(serial); - return; - } - if (revents & G_IO_IN) { - for (;;) { - c = aoview_serial_getc(serial); - if (c == -1) - break; - if (c == '\r') - continue; - if (c == '\n') { - eeprom_line[eeprom_pos] = '\0'; - if (eeprom_pos) - if (!aoview_eeprom_parse(serial, eeprom_line)) - break; - eeprom_pos = 0; - } else if (eeprom_pos < EEPROM_LEN) - eeprom_line[eeprom_pos++] = c; - } - } -} - -gboolean -aoview_eeprom_save(const char *device) -{ - struct aoview_serial *serial; - - gtk_widget_hide(GTK_WIDGET(eeprom_save_done)); - eeprom_save_shown = FALSE; - serial = aoview_serial_open(device); - if (!serial) - return FALSE; - aoview_serial_set_callback(serial, aoview_eeprom_callback); - aoview_serial_printf(serial, "v\nl\n"); - return TRUE; -} - -void -aoview_eeprom_init(GladeXML *xml) -{ - eeprom_file = aoview_file_new("eeprom"); - assert(eeprom_file); - - eeprom_save_done = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "ao_save_done")); - assert(eeprom_save_done); - -} diff --git a/ao-view/aoview_file.c b/ao-view/aoview_file.c deleted file mode 100644 index 5288c2f7..00000000 --- a/ao-view/aoview_file.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -char *aoview_file_dir; - -#define ALTOS_DIR_PATH "/apps/aoview/log_dir" -#define DEFAULT_DIR "AltOS" - -struct aoview_file { - char *ext; - FILE *file; - char *name; - int failed; - int serial; - int sequence; -}; - -static void -aoview_file_save_conf(void) -{ - GConfClient *gconf_client; - - gconf_client = gconf_client_get_default(); - if (gconf_client) - { - gconf_client_set_string(gconf_client, - ALTOS_DIR_PATH, - aoview_file_dir, - NULL); - g_object_unref(G_OBJECT(gconf_client)); - } -} - -static void -aoview_file_configure(GtkWidget *widget, gpointer data) -{ - GtkFileChooser *chooser = data; - aoview_file_dir = gtk_file_chooser_get_filename(chooser); - aoview_file_save_conf(); - gtk_widget_hide(GTK_WIDGET(chooser)); -} - -void -aoview_file_finish(struct aoview_file *file) -{ - if (file->file) { - fclose(file->file); - file->file = NULL; - free(file->name); - file->name = NULL; - } - file->failed = 0; -} - -const char * -aoview_file_name(struct aoview_file *file) -{ - return file->name; -} - -static GtkMessageDialog *file_fail_dialog; - -static void -aoview_file_open_failed(char *name) -{ - char *utf8_file; - utf8_file = g_filename_to_utf8(name, -1, NULL, NULL, NULL); - if (!utf8_file) - utf8_file = name; - gtk_message_dialog_format_secondary_text(file_fail_dialog, - "\"%s\"", utf8_file); - if (utf8_file != name) - g_free(utf8_file); - gtk_widget_show(GTK_WIDGET(file_fail_dialog)); -} - -gboolean -aoview_file_start(struct aoview_file *file) -{ - char base[50]; - struct tm tm; - time_t now; - char *full; - int r; - - if (file->file) - return TRUE; - - if (file->failed) - return FALSE; - - now = time(NULL); - (void) localtime_r(&now, &tm); - aoview_mkdir(aoview_file_dir); - for (;;) { - snprintf(base, sizeof (base), "%04d-%02d-%02d-serial-%03d-flight-%03d.%s", - tm.tm_year + 1900, - tm.tm_mon + 1, - tm.tm_mday, - file->serial, - file->sequence, - file->ext); - full = aoview_fullname(aoview_file_dir, base); - r = access(full, F_OK); - if (r < 0) { - file->file = fopen(full, "w"); - if (!file->file) { - aoview_file_open_failed(full); - free(full); - file->failed = 1; - return FALSE; - } else { - setlinebuf(file->file); - file->name = full; - return TRUE; - } - } - free(full); - file->sequence++; - } -} - -void -aoview_file_vprintf(struct aoview_file *file, char *format, va_list ap) -{ - if (!aoview_file_start(file)) - return; - vfprintf(file->file, format, ap); -} - -void -aoview_file_printf(struct aoview_file *file, char *format, ...) -{ - va_list ap; - - va_start(ap, format); - aoview_file_vprintf(file, format, ap); - va_end(ap); -} - -struct aoview_file * -aoview_file_new(char *ext) -{ - struct aoview_file *file; - - file = calloc (1, sizeof (struct aoview_file)); - if (!file) - return NULL; - file->ext = strdup(ext); - if (!file->ext) { - free(file); - return NULL; - } - return file; -} - -void -aoview_file_destroy(struct aoview_file *file) -{ - if (file->file) - fclose(file->file); - if (file->name) - free(file->name); - free(file->ext); - free(file); -} - -void -aoview_file_set_serial(struct aoview_file *file, int serial) -{ - if (serial != file->serial) - aoview_file_finish(file); - file->serial = serial; -} - -int -aoview_file_get_serial(struct aoview_file *file) -{ - return file->serial; -} - -void -aoview_file_init(GladeXML *xml) -{ - GConfClient *gconf_client; - char *file_dir = NULL; - GtkFileChooser *file_chooser_dialog; - GtkWidget *file_configure_ok; - - g_type_init(); - gconf_client = gconf_client_get_default(); - if (gconf_client) - { - file_dir = gconf_client_get_string(gconf_client, - ALTOS_DIR_PATH, - NULL); - g_object_unref(G_OBJECT(gconf_client)); - } - if (!file_dir) { - aoview_file_dir = aoview_fullname(getenv("HOME"), DEFAULT_DIR); - aoview_file_save_conf(); - } else { - aoview_file_dir = strdup(file_dir); - } - - file_chooser_dialog = GTK_FILE_CHOOSER(glade_xml_get_widget(xml, "file_chooser_dialog")); - assert(file_chooser_dialog); - gtk_file_chooser_set_filename(file_chooser_dialog, aoview_file_dir); - - file_configure_ok = glade_xml_get_widget(xml, "file_configure_ok"); - assert(file_configure_ok); - - g_signal_connect(G_OBJECT(file_configure_ok), "clicked", - G_CALLBACK(aoview_file_configure), - file_chooser_dialog); - - - file_fail_dialog = GTK_MESSAGE_DIALOG(glade_xml_get_widget(xml, "file_fail_dialog")); - assert(file_fail_dialog); -} diff --git a/ao-view/aoview_flite.c b/ao-view/aoview_flite.c deleted file mode 100644 index e1b75898..00000000 --- a/ao-view/aoview_flite.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include -#include -#include "aoview.h" -#include - -cst_voice *register_cmu_us_kal(); -static cst_voice *voice; - -static FILE *pipe_write; -static GThread *aoview_flite_thread; - -static snd_pcm_t *alsa_handle; - -gpointer -aoview_flite_task(gpointer data) -{ - FILE *input = data; - char line[1024]; - cst_wave *wave; - int rate; - int channels; - int err; - char *samples; - int num_samples; - - err = snd_pcm_open(&alsa_handle, "default", - SND_PCM_STREAM_PLAYBACK, 0); - if (err >= 0) - { - if (err < 0) { - snd_pcm_close(alsa_handle); - alsa_handle = 0; - } - } - rate = 0; - channels = 0; - while (fgets(line, sizeof (line) - 1, input) != NULL) { - if (!alsa_handle) - continue; - wave = flite_text_to_wave(line, voice); - if (wave->sample_rate != rate || - wave->num_channels != channels) - { - rate = wave->sample_rate; - channels = wave->num_channels; - err = snd_pcm_set_params(alsa_handle, - SND_PCM_FORMAT_S16, - SND_PCM_ACCESS_RW_INTERLEAVED, - channels, - rate, - 1, - 100000); - if (err < 0) - fprintf(stderr, "alsa set_params error %s\n", - strerror(-err)); - } - err = snd_pcm_prepare(alsa_handle); - if (err < 0) - fprintf(stderr, "alsa pcm_prepare error %s\n", - strerror(-err)); - samples = (char *) wave->samples; - num_samples = wave->num_samples; - while (num_samples > 0) { - err = snd_pcm_writei(alsa_handle, - samples, num_samples); - if (err <= 0) { - fprintf(stderr, "alsa write error %s\n", - strerror(-err)); - break; - } - num_samples -= err; - samples += err * 2 * channels; - } - snd_pcm_drain(alsa_handle); - delete_wave(wave); - } - snd_pcm_close(alsa_handle); - alsa_handle = 0; - 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; - } -} - -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); - } - } - 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; -} diff --git a/ao-view/aoview_label.c b/ao-view/aoview_label.c deleted file mode 100644 index 24313626..00000000 --- a/ao-view/aoview_label.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -static struct { - char *name; - char *initial_value; - GtkLabel *widget; -} label_widgets[] = { - { "height_label", "Height (m)", NULL }, - { "state_label", "State", NULL }, - { "rssi_label", "RSSI (dBm)", NULL }, - { "speed_label", "Speed (m/s)", NULL }, - { "height_value", "0", NULL }, - { "state_value", "pad", NULL }, - { "rssi_value", "-50", NULL }, - { "speed_value", "0", NULL }, -}; - -static void -aoview_label_assign(GtkLabel *widget, char *value) -{ - char *markup; - - markup = g_markup_printf_escaped("%s", value); - gtk_label_set_markup(widget, markup); - g_free(markup); -} - -void -aoview_label_show(struct aostate *state) -{ - char line[1024]; - sprintf(line, "%d", state->height); - aoview_label_assign(label_widgets[4].widget, line); - - aoview_label_assign(label_widgets[5].widget, state->data.state); - - sprintf(line, "%d", state->data.rssi); - aoview_label_assign(label_widgets[6].widget, line); - - if (state->ascent) - sprintf(line, "%6.0f", fabs(state->speed)); - else - sprintf(line, "%6.0f", fabs(state->baro_speed)); - aoview_label_assign(label_widgets[7].widget, line); -} - -void -aoview_label_init(GladeXML *xml) -{ - int i; - for (i = 0; i < sizeof(label_widgets)/sizeof(label_widgets[0]); i++) { - label_widgets[i].widget = GTK_LABEL(glade_xml_get_widget(xml, label_widgets[i].name)); - aoview_label_assign(label_widgets[i].widget, label_widgets[i].initial_value); - assert(label_widgets[i].widget); - } -} diff --git a/ao-view/aoview_log.c b/ao-view/aoview_log.c deleted file mode 100644 index 1b89c28c..00000000 --- a/ao-view/aoview_log.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -static struct aoview_file *aoview_log; - -void -aoview_log_new(void) -{ - aoview_file_finish(aoview_log); - aoview_state_new(); -} - -void -aoview_log_set_serial(int serial) -{ - aoview_file_set_serial(aoview_log, serial); -} - -int -aoview_log_get_serial(void) -{ - return aoview_file_get_serial(aoview_log); -} - -void -aoview_log_printf(char *format, ...) -{ - va_list ap; - - va_start(ap, format); - aoview_file_vprintf(aoview_log, format, ap); - va_end(ap); -} - -static void -aoview_log_new_item(GtkWidget *widget, gpointer data) -{ - aoview_file_finish(aoview_log); -} - -void -aoview_log_init(GladeXML *xml) -{ - GtkWidget *log_new; - - aoview_log = aoview_file_new("telem"); - assert(aoview_log); - - log_new = glade_xml_get_widget(xml, "log_new"); - assert(log_new); - g_signal_connect(G_OBJECT(log_new), "activate", - G_CALLBACK(aoview_log_new_item), - NULL); -} diff --git a/ao-view/aoview_main.c b/ao-view/aoview_main.c deleted file mode 100644 index 64c1c027..00000000 --- a/ao-view/aoview_main.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -static const char aoview_glade[] = { -#include "aoview_glade.h" -}; - -static void usage(void) { - printf("aoview [--device|-d device_file]"); - exit(1); -} - -static void destroy_event(GtkWidget *widget, gpointer data) -{ - gtk_main_quit(); -} - -extern int _Xdebug; -char *aoview_tty = NULL; - -int main(int argc, char **argv) -{ - GladeXML *xml = NULL; - GtkWidget *mainwindow; - GtkAboutDialog *about_dialog; - - static struct option long_options[] = { - { "tty", 1, 0, 'T'}, - { "sync", 0, 0, 's'}, - { 0, 0, 0, 0 } - }; - for (;;) { - int c, temp; - - c = getopt_long_only(argc, argv, "sT:", long_options, &temp); - if (c == -1) - break; - - switch (c) { - case 'T': - aoview_tty = optarg; - break; - case 's': - _Xdebug = 1; - break; - default: - usage(); - } - } - - g_thread_init(NULL); - gtk_init(&argc, &argv); - glade_init(); - - xml = glade_xml_new_from_buffer(aoview_glade, sizeof (aoview_glade), NULL, NULL); - - /* connect the signals in the interface */ - glade_xml_signal_autoconnect(xml); - - /* Hook up the close button. */ - mainwindow = glade_xml_get_widget(xml, "aoview"); - assert(mainwindow); - - g_signal_connect (G_OBJECT(mainwindow), "destroy", - G_CALLBACK(destroy_event), NULL); - - about_dialog = GTK_ABOUT_DIALOG(glade_xml_get_widget(xml, "about_dialog")); - assert(about_dialog); - gtk_about_dialog_set_version(about_dialog, AOVIEW_VERSION); - - aoview_voice_init(xml); - - aoview_dev_dialog_init(xml); - - aoview_state_init(xml); - - aoview_file_init(xml); - - aoview_log_init(xml); - - aoview_table_init(xml); - - aoview_eeprom_init(xml); - - aoview_replay_init(xml); - - aoview_label_init(xml); - - if (aoview_tty) { - if (!aoview_monitor_connect(aoview_tty)) { - perror(aoview_tty); - exit(1); - } - } - aoview_voice_speak("rocket flight monitor ready\n"); - - gtk_main(); - - return 0; -} diff --git a/ao-view/aoview_monitor.c b/ao-view/aoview_monitor.c deleted file mode 100644 index 8564014b..00000000 --- a/ao-view/aoview_monitor.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -static struct aoview_serial *monitor_serial; - -#define MONITOR_LEN 1024 - -static char monitor_line[MONITOR_LEN + 1]; -static int monitor_pos; - -void -aoview_monitor_disconnect(void) -{ - if (monitor_serial) { - aoview_serial_close(monitor_serial); - monitor_serial = NULL; - } - aoview_log_new(); -} - -static void -aoview_parse_string(char *target, int len, char *source) -{ - strncpy(target, source, len-1); - target[len-1] = '\0'; -} - -static void -aoview_parse_int(int *target, char *source) -{ - *target = strtol(source, NULL, 0); -} - -static void -aoview_parse_hex(int *target, char *source) -{ - *target = strtol(source, NULL, 16); -} - -static void -aoview_parse_pos(double *target, char *source) -{ - int deg; - double min; - char dir; - double r; - - if (sscanf(source, "%d°%lf'%c", °, &min, &dir) != 3) { - *target = 0; - return; - } - r = deg + min / 60.0; - if (dir == 'S' || dir == 'W') - r = -r; - *target = r; -} - -#define PARSE_MAX_WORDS 256 - -gboolean -aoview_monitor_parse(const char *input_line) -{ - char *saveptr; - char *words[PARSE_MAX_WORDS]; - int nword; - char line_buf[8192], *line; - struct aodata data; - int tracking_pos; - - /* avoid smashing our input parameter */ - strncpy (line_buf, input_line, sizeof (line_buf)-1); - line_buf[sizeof(line_buf) - 1] = '\0'; - line = line_buf; - for (nword = 0; nword < PARSE_MAX_WORDS; nword++) { - words[nword] = strtok_r(line, " \t\n", &saveptr); - line = NULL; - if (words[nword] == NULL) - break; - } - if (nword < 36) - return FALSE; - if (strcmp(words[0], "CALL") != 0) - return FALSE; - aoview_parse_string(data.callsign, sizeof (data.callsign), words[1]); - aoview_parse_int(&data.serial, words[3]); - - aoview_parse_int(&data.rssi, words[5]); - aoview_parse_string(data.state, sizeof (data.state), words[9]); - aoview_parse_int(&data.tick, words[10]); - aoview_parse_int(&data.accel, words[12]); - aoview_parse_int(&data.pres, words[14]); - aoview_parse_int(&data.temp, words[16]); - aoview_parse_int(&data.batt, words[18]); - aoview_parse_int(&data.drogue, words[20]); - aoview_parse_int(&data.main, words[22]); - aoview_parse_int(&data.flight_accel, words[24]); - aoview_parse_int(&data.ground_accel, words[26]); - aoview_parse_int(&data.flight_vel, words[28]); - aoview_parse_int(&data.flight_pres, words[30]); - aoview_parse_int(&data.ground_pres, words[32]); - aoview_parse_int(&data.gps.nsat, words[34]); - if (strcmp (words[36], "unlocked") == 0) { - data.gps.gps_connected = 1; - data.gps.gps_locked = 0; - data.gps.gps_time.hour = data.gps.gps_time.minute = data.gps.gps_time.second = 0; - data.gps.lat = data.gps.lon = 0; - data.gps.alt = 0; - tracking_pos = 37; - } else if (nword >= 40) { - data.gps.gps_locked = 1; - data.gps.gps_connected = 1; - sscanf(words[36], "%d:%d:%d", &data.gps.gps_time.hour, &data.gps.gps_time.minute, &data.gps.gps_time.second); - aoview_parse_pos(&data.gps.lat, words[37]); - aoview_parse_pos(&data.gps.lon, words[38]); - sscanf(words[39], "%dm", &data.gps.alt); - tracking_pos = 46; - } else { - data.gps.gps_connected = 0; - data.gps.gps_locked = 0; - data.gps.gps_time.hour = data.gps.gps_time.minute = data.gps.gps_time.second = 0; - data.gps.lat = data.gps.lon = 0; - data.gps.alt = 0; - tracking_pos = -1; - } - if (nword >= 46) { - data.gps.gps_extended = 1; - sscanf(words[40], "%lfm/s", &data.gps.ground_speed); - sscanf(words[41], "%d", &data.gps.course); - sscanf(words[42], "%lfm/s", &data.gps.climb_rate); - sscanf(words[43], "%lf", &data.gps.hdop); - sscanf(words[44], "%d", &data.gps.h_error); - sscanf(words[45], "%d", &data.gps.v_error); - } else { - data.gps.gps_extended = 0; - data.gps.ground_speed = 0; - data.gps.course = 0; - data.gps.climb_rate = 0; - data.gps.hdop = 0; - data.gps.h_error = 0; - data.gps.v_error = 0; - } - if (tracking_pos >= 0 && nword >= tracking_pos + 2 && strcmp(words[tracking_pos], "SAT") == 0) { - int c, n, pos; - aoview_parse_int(&n, words[tracking_pos + 1]); - pos = tracking_pos + 2; - if (nword >= pos + n * 3) { - data.gps_tracking.channels = n; - for (c = 0; c < n; c++) { - aoview_parse_int(&data.gps_tracking.sats[c].svid, - words[pos + 0]); - aoview_parse_hex(&data.gps_tracking.sats[c].state, - words[pos + 1]); - aoview_parse_int(&data.gps_tracking.sats[c].c_n0, - words[pos + 2]); - pos += 3; - } - } else { - data.gps_tracking.channels = 0; - } - } else { - data.gps_tracking.channels = 0; - } - aoview_state_notify(&data); - return TRUE; -} - -static void -aoview_monitor_callback(gpointer user_data, - struct aoview_serial *serial, - gint revents) -{ - int c; - - if (revents & (G_IO_HUP|G_IO_ERR)) { - aoview_monitor_disconnect(); - return; - } - if (revents & G_IO_IN) { - for (;;) { - c = aoview_serial_getc(serial); - if (c == -1) - break; - if (c == '\r') - continue; - if (c == '\n') { - monitor_line[monitor_pos] = '\0'; - if (monitor_pos) { - if (aoview_monitor_parse(monitor_line)) { - aoview_log_set_serial(aostate.data.serial); - if (aoview_log_get_serial()) - aoview_log_printf ("%s\n", monitor_line); - } - } - monitor_pos = 0; - } else if (monitor_pos < MONITOR_LEN) - monitor_line[monitor_pos++] = c; - } - } -} - -gboolean -aoview_monitor_connect(char *tty) -{ - aoview_monitor_disconnect(); - monitor_serial = aoview_serial_open(tty); - if (!monitor_serial) - return FALSE; - aoview_table_clear(); - aoview_state_reset(); - aoview_serial_set_callback(monitor_serial, - aoview_monitor_callback); - return TRUE; -} diff --git a/ao-view/aoview_replay.c b/ao-view/aoview_replay.c deleted file mode 100644 index da7b5d6a..00000000 --- a/ao-view/aoview_replay.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -static GtkFileChooser *replay_dialog; -static GtkWidget *replay_ok; -static FILE *replay_file; -static int replay_tick; - -static int -find_tick(char *line, gboolean *is_pad) -{ - char *state = strstr(line, "STATE"); - if (!state) - return -1; - state = strchr(state, ' '); - if (!state) - return -1; - while (*state == ' ') - state++; - *is_pad = strncmp(state, "pad", 3) == 0; - while (*state && !isdigit(*state)) - state++; - return atoi(state); -} - -static void -aoview_replay_close(void) -{ - if (replay_file) { - fclose(replay_file); - replay_file = NULL; - } -} - -static char replay_line[1024]; - -static gboolean -aoview_replay_read(gpointer data); - -static gboolean -aoview_replay_execute(gpointer data) -{ - aoview_monitor_parse(replay_line); - g_idle_add(aoview_replay_read, NULL); - return FALSE; -} - -static gboolean -aoview_replay_read(gpointer data) -{ - int tick; - gboolean is_pad; - - if (!replay_file) - return FALSE; - if (fgets(replay_line, sizeof (replay_line), replay_file)) { - tick = find_tick(replay_line, &is_pad); - if (tick >= 0 && replay_tick >= 0 && !is_pad) { - while (tick < replay_tick) - tick += 65536; - g_timeout_add((tick - replay_tick) * 10, - aoview_replay_execute, - NULL); - } else { - aoview_replay_execute(NULL); - } - replay_tick = tick; - } else { - aoview_replay_close(); - } - return FALSE; -} - -static void -aoview_replay_open(GtkWidget *widget, gpointer data) -{ - char *replay_file_name; - GtkWidget *dialog; - - aoview_replay_close(); - replay_file_name = gtk_file_chooser_get_filename(replay_dialog); - replay_file = fopen(replay_file_name, "r"); - if (!replay_file) { - dialog = gtk_message_dialog_new(GTK_WINDOW(replay_dialog), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - "Error loading file '%s': %s", - replay_file_name, g_strerror(errno)); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - } else { - replay_tick = -1; - aoview_state_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); - g_signal_connect(G_OBJECT(replay_ok), "clicked", - G_CALLBACK(aoview_replay_open), - replay_dialog); -} diff --git a/ao-view/aoview_serial.c b/ao-view/aoview_serial.c deleted file mode 100644 index 29038b79..00000000 --- a/ao-view/aoview_serial.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" -#include - -#define AOVIEW_SERIAL_IN_BUF 64 -#define AOVIEW_SERIAL_OUT_BUF 64 - -struct aoview_buf { - char *buf; - int off; - int count; - int size; -}; - -static int -aoview_buf_write(struct aoview_buf *buf, char *data, int len) -{ - if (buf->count + len > buf->size) { - int new_size = buf->size * 2; - if (new_size == 0) - new_size = 1024; - if (buf->buf) - buf->buf = realloc (buf->buf, new_size); - else - buf->buf = malloc (new_size); - buf->size = new_size; - } - memcpy(buf->buf + buf->count, data, len); - buf->count += len; - return len; -} - -static int -aoview_buf_read(struct aoview_buf *buf, char *data, int len) -{ - if (len > buf->count - buf->off) - len = buf->count - buf->off; - memcpy (data, buf->buf + buf->off, len); - buf->off += len; - if (buf->off == buf->count) - buf->off = buf->count = 0; - return len; -} - -static int -aoview_buf_getc(struct aoview_buf *buf) -{ - char b; - int r; - - r = aoview_buf_read(buf, &b, 1); - if (r == 1) - return (int) b; - return -1; -} - -static void -aoview_buf_flush(struct aoview_buf *buf, int fd) -{ - int ret; - - if (buf->count > buf->off) { - ret = write(fd, buf->buf + buf->off, buf->count - buf->off); - if (ret > 0) { - buf->off += ret; - if (buf->off == buf->count) - buf->off = buf->count = 0; - } - } -} - -static void -aoview_buf_fill(struct aoview_buf *buf, int fd) -{ - int ret; - - while (buf->count >= buf->size) { - int new_size = buf->size * 2; - buf->buf = realloc (buf->buf, new_size); - buf->size = new_size; - } - - ret = read(fd, buf->buf + buf->count, buf->size - buf->count); - if (ret > 0) - buf->count += ret; -} - -static void -aoview_buf_init(struct aoview_buf *buf) -{ - buf->buf = malloc (buf->size = 1024); - buf->count = 0; -} - -static void -aoview_buf_fini(struct aoview_buf *buf) -{ - free(buf->buf); -} - -struct aoview_serial { - GSource source; - int fd; - struct termios save_termios; - struct aoview_buf in_buf; - struct aoview_buf out_buf; - GPollFD poll_fd; -}; - - -void -aoview_serial_printf(struct aoview_serial *serial, char *format, ...) -{ - char buf[1024]; - va_list ap; - int ret; - - /* sprintf to a local buffer */ - va_start(ap, format); - ret = vsnprintf(buf, sizeof(buf), format, ap); - va_end(ap); - if (ret > sizeof(buf)) { - fprintf(stderr, "printf overflow for format %s\n", - format); - } - - /* flush local buffer to the wire */ - aoview_buf_write(&serial->out_buf, buf, ret); - aoview_buf_flush(&serial->out_buf, serial->fd); -} - -int -aoview_serial_read(struct aoview_serial *serial, char *buf, int len) -{ - return aoview_buf_read(&serial->in_buf, buf, len); -} - -int -aoview_serial_getc(struct aoview_serial *serial) -{ - return aoview_buf_getc(&serial->in_buf); -} - -static gboolean -serial_prepare(GSource *source, gint *timeout) -{ - struct aoview_serial *serial = (struct aoview_serial *) source; - *timeout = -1; - - if (serial->out_buf.count) - serial->poll_fd.events |= G_IO_OUT; - else - serial->poll_fd.events &= ~G_IO_OUT; - return FALSE; -} - -static gboolean -serial_check(GSource *source) -{ - struct aoview_serial *serial = (struct aoview_serial *) source; - gint revents = serial->poll_fd.revents; - - if (revents & G_IO_NVAL) - return FALSE; - if (revents & G_IO_IN) - return TRUE; - if (revents & G_IO_OUT) - return TRUE; - return FALSE; -} - -static gboolean -serial_dispatch(GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - struct aoview_serial *serial = (struct aoview_serial *) source; - aoview_serial_callback func = (aoview_serial_callback) callback; - gint revents = serial->poll_fd.revents; - - if (revents & G_IO_IN) - aoview_buf_fill(&serial->in_buf, serial->fd); - - if (revents & G_IO_OUT) - aoview_buf_flush(&serial->out_buf, serial->fd); - - if (func) - (*func)(user_data, serial, revents); - return TRUE; -} - -static void -serial_finalize(GSource *source) -{ - struct aoview_serial *serial = (struct aoview_serial *) source; - - aoview_buf_fini(&serial->in_buf); - aoview_buf_fini(&serial->out_buf); - tcsetattr(serial->fd, TCSAFLUSH, &serial->save_termios); - close (serial->fd); -} - -static GSourceFuncs serial_funcs = { - serial_prepare, - serial_check, - serial_dispatch, - serial_finalize -}; - -struct aoview_serial * -aoview_serial_open(const char *tty) -{ - struct aoview_serial *serial; - struct termios termios; - - serial = (struct aoview_serial *) g_source_new(&serial_funcs, sizeof (struct aoview_serial)); - aoview_buf_init(&serial->in_buf); - aoview_buf_init(&serial->out_buf); - serial->fd = open (tty, O_RDWR | O_NONBLOCK); - if (serial->fd < 0) { - g_source_destroy(&serial->source); - return NULL; - } - tcgetattr(serial->fd, &termios); - serial->save_termios = termios; - cfmakeraw(&termios); - tcsetattr(serial->fd, TCSAFLUSH, &termios); - - aoview_serial_printf(serial, "E 0\n"); - tcdrain(serial->fd); - usleep(15*1000); - tcflush(serial->fd, TCIFLUSH); - serial->poll_fd.fd = serial->fd; - serial->poll_fd.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR; - g_source_attach(&serial->source, NULL); - g_source_add_poll(&serial->source,&serial->poll_fd); - aoview_serial_set_callback(serial, NULL); - return serial; -} - -void -aoview_serial_close(struct aoview_serial *serial) -{ - g_source_remove_poll(&serial->source, &serial->poll_fd); - close(serial->fd); - g_source_destroy(&serial->source); -} - -void -aoview_serial_set_callback(struct aoview_serial *serial, - aoview_serial_callback func) -{ - g_source_set_callback(&serial->source, (GSourceFunc) func, serial, NULL); -} diff --git a/ao-view/aoview_state.c b/ao-view/aoview_state.c deleted file mode 100644 index f75066dd..00000000 --- a/ao-view/aoview_state.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" -#include - -static inline double sqr(double a) { return a * a; }; - -static void -aoview_great_circle (double start_lat, double start_lon, - double end_lat, double end_lon, - double *dist, double *bearing) -{ - const double rad = M_PI / 180; - const double earth_radius = 6371.2 * 1000; /* in meters */ - double lat1 = rad * start_lat; - double lon1 = rad * -start_lon; - double lat2 = rad * end_lat; - double lon2 = rad * -end_lon; - - double d_lat = lat2 - lat1; - double d_lon = lon2 - lon1; - - /* From http://en.wikipedia.org/wiki/Great-circle_distance */ - double vdn = sqrt(sqr(cos(lat2) * sin(d_lon)) + - sqr(cos(lat1) * sin(lat2) - - sin(lat1) * cos(lat2) * cos(d_lon))); - double vdd = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(d_lon); - double d = atan2(vdn,vdd); - double course; - - if (cos(lat1) < 1e-20) { - if (lat1 > 0) - course = M_PI; - else - course = -M_PI; - } else { - if (d < 1e-10) - course = 0; - else - course = acos((sin(lat2)-sin(lat1)*cos(d)) / - (sin(d)*cos(lat1))); - if (sin(lon2-lon1) > 0) - course = 2 * M_PI-course; - } - *dist = d * earth_radius; - *bearing = course * 180/M_PI; -} - -static void -aoview_state_add_deg(int column, char *label, double deg, char pos, char neg) -{ - double int_part; - double min; - char sign = pos; - - if (deg < 0) { - deg = -deg; - sign = neg; - } - int_part = floor (deg); - min = (deg - int_part) * 60.0; - aoview_table_add_row(column, label, "%d°%lf'%c", - (int) int_part, min, sign); - -} - -static char *ascent_states[] = { - "boost", - "fast", - "coast", - 0, -}; - -static double -aoview_time(void) -{ - struct timespec now; - - clock_gettime(CLOCK_MONOTONIC, &now); - return (double) now.tv_sec + (double) now.tv_nsec / 1.0e9; -} - -/* - * Fill out the derived data fields - */ -static void -aoview_state_derive(struct aodata *data, struct aostate *state) -{ - int i; - double new_height; - double height_change; - double time_change; - int tick_count; - - state->report_time = aoview_time(); - - state->prev_data = state->data; - state->prev_npad = state->npad; - state->data = *data; - tick_count = data->tick; - if (tick_count < state->prev_data.tick) - tick_count += 65536; - time_change = (tick_count - state->prev_data.tick) / 100.0; - - state->ground_altitude = aoview_pres_to_altitude(data->ground_pres); - new_height = aoview_pres_to_altitude(data->flight_pres) - state->ground_altitude; - height_change = new_height - state->height; - state->height = new_height; - if (time_change) - state->baro_speed = (state->baro_speed * 3 + (height_change / time_change)) / 4.0; - state->acceleration = (data->ground_accel - data->flight_accel) / 27.0; - state->speed = data->flight_vel / 2700.0; - state->temperature = ((data->temp / 32767.0 * 3.3) - 0.5) / 0.01; - state->drogue_sense = data->drogue / 32767.0 * 15.0; - state->main_sense = data->main / 32767.0 * 15.0; - state->battery = data->batt / 32767.0 * 5.0; - if (!strcmp(data->state, "pad")) { - if (data->gps.gps_locked && data->gps.nsat >= 4) { - state->npad++; - state->pad_lat_total += data->gps.lat; - state->pad_lon_total += data->gps.lon; - state->pad_alt_total += data->gps.alt; - if (state->npad > 1) { - state->pad_lat = (state->pad_lat * 31 + data->gps.lat) / 32.0; - state->pad_lon = (state->pad_lon * 31 + data->gps.lon) / 32.0; - state->pad_alt = (state->pad_alt * 31 + data->gps.alt) / 32.0; - } else { - state->pad_lat = data->gps.lat; - state->pad_lon = data->gps.lon; - state->pad_alt = data->gps.alt; - } - } - } - 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; - state->gps.gps_locked = data->gps.gps_locked; - state->gps.gps_connected = data->gps.gps_connected; - if (data->gps.gps_locked) { - state->gps = data->gps; - state->gps_valid = 1; - if (state->npad) - aoview_great_circle(state->pad_lat, state->pad_lon, state->gps.lat, state->gps.lon, - &state->distance, &state->bearing); - } - if (data->gps_tracking.channels) - state->gps_tracking = data->gps_tracking; - if (state->npad) { - state->gps_height = state->gps.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); - } - if (state->prev_npad < MIN_PAD_SAMPLES && state->npad >= MIN_PAD_SAMPLES) - aoview_voice_speak("g p s ready\n"); -} - -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); - } - } - aostate_timeout = 0; - return FALSE; - } - return TRUE; -} - -void -aoview_state_reset(void) -{ - memset(&aostate, '\0', sizeof (aostate)); -} - -void -aoview_state_notify(struct aodata *data) -{ - struct aostate *state = &aostate; - aoview_state_derive(data, state); - aoview_table_start(); - - if (state->npad >= MIN_PAD_SAMPLES) - aoview_table_add_row(0, "Ground state", "ready"); - else - aoview_table_add_row(0, "Ground state", "waiting for gps (%d)", - MIN_PAD_SAMPLES - state->npad); - aoview_table_add_row(0, "Rocket state", "%s", state->data.state); - aoview_table_add_row(0, "Callsign", "%s", state->data.callsign); - aoview_table_add_row(0, "Rocket serial", "%d", state->data.serial); - - aoview_table_add_row(0, "RSSI", "%6ddBm", state->data.rssi); - aoview_table_add_row(0, "Height", "%6dm", state->height); - aoview_table_add_row(0, "Max height", "%6dm", state->max_height); - aoview_table_add_row(0, "Acceleration", "%7.1fm/s²", state->acceleration); - aoview_table_add_row(0, "Max acceleration", "%7.1fm/s²", state->max_acceleration); - aoview_table_add_row(0, "Speed", "%7.1fm/s", state->ascent ? state->speed : state->baro_speed); - aoview_table_add_row(0, "Max Speed", "%7.1fm/s", state->max_speed); - aoview_table_add_row(0, "Temperature", "%6.2f°C", state->temperature); - aoview_table_add_row(0, "Battery", "%5.2fV", state->battery); - aoview_table_add_row(0, "Drogue", "%5.2fV", state->drogue_sense); - aoview_table_add_row(0, "Main", "%5.2fV", state->main_sense); - aoview_table_add_row(0, "Pad altitude", "%dm", state->ground_altitude); - aoview_table_add_row(1, "Satellites", "%d", state->gps.nsat); - if (state->gps.gps_locked) { - aoview_table_add_row(1, "GPS", "locked"); - } else if (state->gps.gps_connected) { - aoview_table_add_row(1, "GPS", "unlocked"); - } else { - aoview_table_add_row(1, "GPS", "not available"); - } - if (state->gps_valid) { - aoview_state_add_deg(1, "Latitude", state->gps.lat, 'N', 'S'); - aoview_state_add_deg(1, "Longitude", state->gps.lon, 'E', 'W'); - aoview_table_add_row(1, "GPS altitude", "%d", state->gps.alt); - aoview_table_add_row(1, "GPS height", "%d", state->gps_height); - aoview_table_add_row(1, "GPS time", "%02d:%02d:%02d", - state->gps.gps_time.hour, - state->gps.gps_time.minute, - state->gps.gps_time.second); - } - if (state->gps.gps_extended) { - aoview_table_add_row(1, "GPS ground speed", "%7.1fm/s %d°", - state->gps.ground_speed, - state->gps.course); - aoview_table_add_row(1, "GPS climb rate", "%7.1fm/s", - state->gps.climb_rate); - aoview_table_add_row(1, "GPS precision", "%4.1f(hdop) %3dm(h) %3dm(v)", - state->gps.hdop, state->gps.h_error, state->gps.v_error); - } - if (state->npad) { - aoview_table_add_row(1, "Distance from pad", "%5.0fm", state->distance); - aoview_table_add_row(1, "Direction from pad", "%4.0f°", state->bearing); - aoview_state_add_deg(1, "Pad latitude", state->pad_lat, 'N', 'S'); - aoview_state_add_deg(1, "Pad longitude", state->pad_lon, 'E', 'W'); - aoview_table_add_row(1, "Pad GPS alt", "%gm", state->pad_alt); - } - if (state->gps.gps_connected) { - int nsat_vis = 0; - int nsat_locked = 0; - int c; - - for (c = 0; c < state->gps_tracking.channels; c++) { - if ((state->gps_tracking.sats[c].state & 0xff) == 0xbf) - nsat_locked++; - } - aoview_table_add_row(2, "Satellites Visible", "%d", state->gps_tracking.channels); - aoview_table_add_row(2, "Satellites Locked", "%d", nsat_locked); - for (c = 0; c < state->gps_tracking.channels; c++) { - aoview_table_add_row(2, "Satellite id,state,C/N0", - "%3d,%02x,%2d%s", - state->gps_tracking.sats[c].svid, - state->gps_tracking.sats[c].state, - state->gps_tracking.sats[c].c_n0, - (state->gps_tracking.sats[c].state & 0xff) == 0xbf ? - " LOCKED" : ""); - } - } - aoview_table_finish(); - aoview_label_show(state); - aoview_speak_state(state); - if (!aostate_timeout && strcmp(state->data.state, "pad") != 0) - aostate_timeout = g_timeout_add_seconds(10, aoview_state_timeout, NULL); -} - -void -aoview_state_new(void) -{ -} - -void -aoview_state_init(GladeXML *xml) -{ - aoview_state_new(); -} diff --git a/ao-view/aoview_table.c b/ao-view/aoview_table.c deleted file mode 100644 index e75ae670..00000000 --- a/ao-view/aoview_table.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -#define NCOL 3 - -static GtkTreeView *dataview[NCOL]; -static GtkListStore *datalist[NCOL]; - -void -aoview_table_start(void) -{ - int col; - for (col = 0; col < NCOL; col++) - datalist[col] = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); -} - -void -aoview_table_add_row(int col, char *label, char *format, ...) -{ - char buf[1024]; - va_list ap; - GtkTreeIter iter; - - va_start(ap, format); - vsnprintf(buf, sizeof (buf), format, ap); - va_end(ap); - gtk_list_store_append(datalist[col], &iter); - gtk_list_store_set(datalist[col], &iter, - 0, label, - 1, buf, - -1); -} - -void -aoview_table_finish(void) -{ - int col; - for (col = 0; col < NCOL; col++) { - gtk_tree_view_set_model(dataview[col], GTK_TREE_MODEL(datalist[col])); - g_object_unref(G_OBJECT(datalist[col])); - gtk_tree_view_columns_autosize(dataview[col]); - } -} - -void -aoview_table_clear(void) -{ - int col; - for (col = 0; col < NCOL; col++) - gtk_tree_view_set_model(dataview[col], NULL); -} - -void -aoview_table_init(GladeXML *xml) -{ - int col; - - for (col = 0; col < NCOL; col++) { - char name[32]; - sprintf(name, "dataview_%d", col); - dataview[col] = GTK_TREE_VIEW(glade_xml_get_widget(xml, name)); - assert(dataview[col]); - - aoview_add_plain_text_column(dataview[col], "Field", 0, 20); - aoview_add_plain_text_column(dataview[col], "Value", 1, 32); - } -} diff --git a/ao-view/aoview_util.c b/ao-view/aoview_util.c deleted file mode 100644 index 6ea62ac9..00000000 --- a/ao-view/aoview_util.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -char * -aoview_fullname (char *dir, char *file) -{ - char *new; - int dlen = strlen (dir); - int flen = strlen (file); - int slen = 0; - - if (dir[dlen-1] != '/') - slen = 1; - new = malloc (dlen + slen + flen + 1); - if (!new) - return 0; - strcpy(new, dir); - if (slen) - strcat (new, "/"); - strcat(new, file); - return new; -} - -char * -aoview_basename(char *file) -{ - char *b; - - b = strrchr(file, '/'); - if (!b) - return file; - return b + 1; -} - -int -aoview_mkdir(char *dir) -{ - char *slash; - char *d; - char *part; - - d = dir; - for (;;) { - slash = strchr (d, '/'); - if (!slash) - slash = d + strlen(d); - if (!*slash) - break; - part = strndup(dir, slash - dir); - if (!access(part, F_OK)) - if (mkdir(part, 0777) < 0) - return -errno; - free(part); - d = slash + 1; - } - return 0; -} - -GtkTreeViewColumn * -aoview_add_plain_text_column (GtkTreeView *view, const gchar *title, gint model_column, gint width) -{ - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - renderer = gtk_cell_renderer_text_new (); - g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_NONE, NULL); - g_object_set(renderer, "width-chars", width, NULL); - column = gtk_tree_view_column_new_with_attributes (title, renderer, - "text", model_column, - NULL); - gtk_tree_view_column_set_resizable (column, FALSE); - gtk_tree_view_append_column (view, column); - - return column; -} diff --git a/ao-view/aoview_voice.c b/ao-view/aoview_voice.c deleted file mode 100644 index 24422df6..00000000 --- a/ao-view/aoview_voice.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright © 2009 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "aoview.h" - -#if HAVE_FLITE -#include - -FILE *aoview_flite; - -void aoview_voice_open(void) -{ - int err; - - if (!aoview_flite) - aoview_flite = aoview_flite_start(); -} - -void aoview_voice_close(void) -{ - if (aoview_flite) { - aoview_flite_stop(); - aoview_flite = NULL; - } -} - -void aoview_voice_speak(char *format, ...) -{ - va_list ap; - - if (aoview_flite) { - va_start(ap, format); - vfprintf(aoview_flite, format, ap); - fflush(aoview_flite); - va_end(ap); - } -} - -#else -void aoview_voice_open(void) -{ -} - -void aoview_voice_close(void) -{ -} - -void aoview_voice_speak(char *format, ...) -{ -} -#endif - - -static GtkCheckMenuItem *voice_enable; - -#define ALTOS_VOICE_PATH "/apps/aoview/voice" - -static void -aoview_voice_enable(GtkWidget *widget, gpointer data) -{ - 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\n"); - } else { - 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) -{ - 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); -} diff --git a/ao-view/design b/ao-view/design deleted file mode 100644 index 6ec2ea70..00000000 --- a/ao-view/design +++ /dev/null @@ -1,27 +0,0 @@ -Requirements: - real-time display of telemetry - off-line display of logged data - Logging of telemetry - Capture of logged data to disk - -Input data: - accelerometer - barometer - thermometer - gps - drogue and main continuity - battery voltage - time - reported flight state - reported events - -Computed data: - velocity (from accelerometer) - altitude - range - direction - -Displays: - numeric display of current rocket status - (graphics come later) - text message log diff --git a/configure.ac b/configure.ac index b52bb6e9..dfbae71d 100644 --- a/configure.ac +++ b/configure.ac @@ -73,7 +73,6 @@ PKG_CHECK_MODULES([ALSA], [alsa]) AC_OUTPUT([ Makefile -ao-view/Makefile ao-tools/Makefile ao-tools/lib/Makefile ao-tools/ao-rawload/Makefile @@ -81,5 +80,6 @@ ao-tools/ao-dbg/Makefile ao-tools/ao-bitbang/Makefile ao-tools/ao-eeprom/Makefile ao-tools/ao-load/Makefile +ao-tools/ao-view/Makefile ao-utils/Makefile ])