From 7c790fe859dff062692964338091ffbbcdf63257 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 18 Aug 2009 12:40:24 -0700 Subject: Rename tools to ao- Use a consistent prefix to make it easier to remember which programs belong to this package Signed-off-by: Keith Packard --- ao-view/.gitignore | 4 + ao-view/Makefile.am | 33 ++ ao-view/aoview.glade | 734 ++++++++++++++++++++++++++++++++++++++++++++ ao-view/aoview.h | 311 +++++++++++++++++++ ao-view/aoview_convert.c | 42 +++ ao-view/aoview_dev.c | 208 +++++++++++++ ao-view/aoview_dev_dialog.c | 168 ++++++++++ ao-view/aoview_eeprom.c | 157 ++++++++++ ao-view/aoview_file.c | 236 ++++++++++++++ ao-view/aoview_flite.c | 135 ++++++++ ao-view/aoview_label.c | 73 +++++ ao-view/aoview_log.c | 70 +++++ ao-view/aoview_main.c | 110 +++++++ ao-view/aoview_monitor.c | 196 ++++++++++++ ao-view/aoview_replay.c | 147 +++++++++ ao-view/aoview_serial.c | 270 ++++++++++++++++ ao-view/aoview_state.c | 349 +++++++++++++++++++++ ao-view/aoview_table.c | 83 +++++ ao-view/aoview_util.c | 91 ++++++ ao-view/aoview_voice.c | 122 ++++++++ ao-view/design | 27 ++ 21 files changed, 3566 insertions(+) create mode 100644 ao-view/.gitignore create mode 100644 ao-view/Makefile.am create mode 100644 ao-view/aoview.glade create mode 100644 ao-view/aoview.h create mode 100644 ao-view/aoview_convert.c create mode 100644 ao-view/aoview_dev.c create mode 100644 ao-view/aoview_dev_dialog.c create mode 100644 ao-view/aoview_eeprom.c create mode 100644 ao-view/aoview_file.c create mode 100644 ao-view/aoview_flite.c create mode 100644 ao-view/aoview_label.c create mode 100644 ao-view/aoview_log.c create mode 100644 ao-view/aoview_main.c create mode 100644 ao-view/aoview_monitor.c create mode 100644 ao-view/aoview_replay.c create mode 100644 ao-view/aoview_serial.c create mode 100644 ao-view/aoview_state.c create mode 100644 ao-view/aoview_table.c create mode 100644 ao-view/aoview_util.c create mode 100644 ao-view/aoview_voice.c create mode 100644 ao-view/design (limited to 'ao-view') diff --git a/ao-view/.gitignore b/ao-view/.gitignore new file mode 100644 index 00000000..24fbc596 --- /dev/null +++ b/ao-view/.gitignore @@ -0,0 +1,4 @@ +*.o +aoview +aoview_glade.h +aoview_flite diff --git a/ao-view/Makefile.am b/ao-view/Makefile.am new file mode 100644 index 00000000..e0cd068c --- /dev/null +++ b/ao-view/Makefile.am @@ -0,0 +1,33 @@ +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 + +aoview_glade.h: aoview.glade + sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/"/' $< > $@ diff --git a/ao-view/aoview.glade b/ao-view/aoview.glade new file mode 100644 index 00000000..df08b83c --- /dev/null +++ b/ao-view/aoview.glade @@ -0,0 +1,734 @@ + + + + + + 550 + 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 + + + + + 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 + False + 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 new file mode 100644 index 00000000..62d0640b --- /dev/null +++ b/ao-view/aoview.h @@ -0,0 +1,311 @@ +/* + * 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 */ +}; + +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 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; + + 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); + +#endif /* _AOVIEW_H_ */ diff --git a/ao-view/aoview_convert.c b/ao-view/aoview_convert.c new file mode 100644 index 00000000..02416647 --- /dev/null +++ b/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-view/aoview_dev.c b/ao-view/aoview_dev.c new file mode 100644 index 00000000..9b8cc19e --- /dev/null +++ b/ao-view/aoview_dev.c @@ -0,0 +1,208 @@ +/* + * 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 new file mode 100644 index 00000000..3f92085c --- /dev/null +++ b/ao-view/aoview_dev_dialog.c @@ -0,0 +1,168 @@ +/* + * 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 new file mode 100644 index 00000000..34e2deed --- /dev/null +++ b/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-view/aoview_file.c b/ao-view/aoview_file.c new file mode 100644 index 00000000..5288c2f7 --- /dev/null +++ b/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-view/aoview_flite.c b/ao-view/aoview_flite.c new file mode 100644 index 00000000..e1b75898 --- /dev/null +++ b/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-view/aoview_label.c b/ao-view/aoview_label.c new file mode 100644 index 00000000..24313626 --- /dev/null +++ b/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-view/aoview_log.c b/ao-view/aoview_log.c new file mode 100644 index 00000000..1b89c28c --- /dev/null +++ b/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-view/aoview_main.c b/ao-view/aoview_main.c new file mode 100644 index 00000000..36a82e0e --- /dev/null +++ b/ao-view/aoview_main.c @@ -0,0 +1,110 @@ +/* + * 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; + +int main(int argc, char **argv) +{ + GladeXML *xml = NULL; + GtkWidget *mainwindow; + char *device = NULL; + GtkAboutDialog *about_dialog; + + static struct option long_options[] = { + { "device", 1, 0, 'd'}, + { "sync", 0, 0, 's'}, + { 0, 0, 0, 0 } + }; + for (;;) { + int c, temp; + + c = getopt_long_only(argc, argv, "sd:", long_options, &temp); + if (c == -1) + break; + + switch (c) { + case 'd': + device = 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); + + 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 new file mode 100644 index 00000000..9265a199 --- /dev/null +++ b/ao-view/aoview_monitor.c @@ -0,0 +1,196 @@ +/* + * 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_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; +} + +gboolean +aoview_monitor_parse(const char *input_line) +{ + char *saveptr; + char *words[64]; + int nword; + char line_buf[8192], *line; + struct aodata data; + + /* 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 < 64; 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; + } 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); + } 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; + } + 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; + } + 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 new file mode 100644 index 00000000..da7b5d6a --- /dev/null +++ b/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-view/aoview_serial.c b/ao-view/aoview_serial.c new file mode 100644 index 00000000..29038b79 --- /dev/null +++ b/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-view/aoview_state.c b/ao-view/aoview_state.c new file mode 100644 index 00000000..7efd33b0 --- /dev/null +++ b/ao-view/aoview_state.c @@ -0,0 +1,349 @@ +/* + * 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 (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 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); + } + 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 new file mode 100644 index 00000000..93143009 --- /dev/null +++ b/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 2 + +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 new file mode 100644 index 00000000..6ea62ac9 --- /dev/null +++ b/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-view/aoview_voice.c b/ao-view/aoview_voice.c new file mode 100644 index 00000000..24422df6 --- /dev/null +++ b/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-view/design b/ao-view/design new file mode 100644 index 00000000..6ec2ea70 --- /dev/null +++ b/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 -- cgit v1.2.3 From 9b03d620722dc54630539afba40720c30de69b2d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 18 Aug 2009 12:19:31 -0700 Subject: Use --tty/-T on command line to specify target device Also, use the ALTOS_TTY environment variable in all tools. Note that the magic value of "BITBANG" switches the library to connecting through a CP2103 instead. Signed-off-by: Keith Packard --- .gitignore | 1 + ao-tools/ao-bitbang/ao-bitbang.c | 2 +- ao-tools/ao-dbg/ao-dbg-main.c | 12 ++++++++- ao-tools/ao-dbg/ao-dbg-parse.c | 6 ++--- ao-tools/ao-dbg/ao-dbg.1 | 4 +++ ao-tools/ao-dbg/ao-dbg.h | 1 + ao-tools/ao-eeprom/ao-eeprom.c | 33 ++++++++++++++++++++++-- ao-tools/ao-load/ao-load.c | 54 ++++++++++++++++++++++++++-------------- ao-tools/ao-rawload/ao-rawload.c | 33 +++++++++++++++++++++--- ao-tools/lib/ccdbg-io.c | 19 +++++++++----- ao-tools/lib/ccdbg.h | 2 +- ao-tools/lib/cp-usb-async.c | 1 + ao-view/aoview.glade | 1 - ao-view/aoview.h | 4 +++ ao-view/aoview_main.c | 16 ++++++++---- 15 files changed, 146 insertions(+), 43 deletions(-) (limited to 'ao-view') diff --git a/.gitignore b/.gitignore index 8b83dd3f..b3d2d562 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ *.rst *.sym .deps +TAGS aclocal.m4 src/ao_flight_test src/ao_gps_test diff --git a/ao-tools/ao-bitbang/ao-bitbang.c b/ao-tools/ao-bitbang/ao-bitbang.c index 7090c9a3..e8dff6bf 100644 --- a/ao-tools/ao-bitbang/ao-bitbang.c +++ b/ao-tools/ao-bitbang/ao-bitbang.c @@ -23,7 +23,7 @@ main (int argc, char **argv) { struct ccdbg *dbg; - dbg = ccdbg_open(); + dbg = ccdbg_open("BITBANG"); if (!dbg) exit (1); diff --git a/ao-tools/ao-dbg/ao-dbg-main.c b/ao-tools/ao-dbg/ao-dbg-main.c index 72249a6b..f1e2c111 100644 --- a/ao-tools/ao-dbg/ao-dbg-main.c +++ b/ao-tools/ao-dbg/ao-dbg-main.c @@ -24,6 +24,7 @@ #include #include #include +#include static int s51_port = 0; static char *cpu = "8051"; @@ -32,6 +33,7 @@ char *s51_prompt = "> "; struct ccdbg *s51_dbg; int s51_interrupted = 0; int s51_monitor = 0; +char *s51_tty = NULL; static FILE *s51_input; static FILE *s51_output; @@ -48,6 +50,11 @@ void s51_sigint() s51_interrupted = 1; } +static const struct option options[] = { + { .name = "tty", .has_arg = 1, .val = 'T' }, + { 0, 0, 0, 0 }, +}; + int main(int argc, char **argv) { @@ -55,7 +62,7 @@ main(int argc, char **argv) char *endptr; struct sigvec vec, ovec; - while ((opt = getopt(argc, argv, "PVvHhmt:X:c:r:Z:s:S:p:")) != -1) { + while ((opt = getopt_long(argc, argv, "PVvHhmt:X:c:r:Z:s:S:p:T:", options, NULL)) != -1) { switch (opt) { case 't': cpu = optarg; @@ -104,6 +111,9 @@ main(int argc, char **argv) case 'm': s51_monitor = 1; break; + case 'T': + s51_tty = optarg; + break; } } if (s51_port) { diff --git a/ao-tools/ao-dbg/ao-dbg-parse.c b/ao-tools/ao-dbg/ao-dbg-parse.c index 5db6c01c..825d0e9c 100644 --- a/ao-tools/ao-dbg/ao-dbg-parse.c +++ b/ao-tools/ao-dbg/ao-dbg-parse.c @@ -195,11 +195,9 @@ command_read (void) enum command_result result; struct command_function *func; - s51_dbg = ccdbg_open (); - if (!s51_dbg) { - perror("ccdbg_open"); + s51_dbg = ccdbg_open (s51_tty); + if (!s51_dbg) exit(1); - } ccdbg_debug_mode(s51_dbg); ccdbg_halt(s51_dbg); s51_printf("Welcome to the non-simulated processor\n"); diff --git a/ao-tools/ao-dbg/ao-dbg.1 b/ao-tools/ao-dbg/ao-dbg.1 index f2f59a52..1f544e5b 100644 --- a/ao-tools/ao-dbg/ao-dbg.1 +++ b/ao-tools/ao-dbg/ao-dbg.1 @@ -34,6 +34,7 @@ s51 \- hex debugger for cc1111 processors [\-H] [\-h] [\-m] +[\-T \fItty-device\fP] .SH DESCRIPTION .I s51 connects to a cc1111 processor through a cp1203-based USB-to-serial @@ -78,6 +79,9 @@ This should print a usage message, but does nothing useful currently. .IP "\-m" This option is not present in the original 8051 emulator, and causes s51 to dump all commands and replies that are received from and sent to sdcdb. +.IP "\-T" +This selects which tty device the debugger uses to communicate with +the target device. .SH COMMANDS Once started, s51 connects to the cc1111 via the CP2103 using libusb2 and then reads and executes commands, either from stdin, or the nework diff --git a/ao-tools/ao-dbg/ao-dbg.h b/ao-tools/ao-dbg/ao-dbg.h index f4dcce66..c1789d10 100644 --- a/ao-tools/ao-dbg/ao-dbg.h +++ b/ao-tools/ao-dbg/ao-dbg.h @@ -22,6 +22,7 @@ extern char *s51_prompt; extern struct ccdbg *s51_dbg; extern int s51_interrupted; extern int s51_monitor; +extern char *s51_tty; enum command_result { command_success, command_debug, command_syntax, command_interrupt, command_error, diff --git a/ao-tools/ao-eeprom/ao-eeprom.c b/ao-tools/ao-eeprom/ao-eeprom.c index 399732d9..726cc22c 100644 --- a/ao-tools/ao-eeprom/ao-eeprom.c +++ b/ao-tools/ao-eeprom/ao-eeprom.c @@ -18,10 +18,23 @@ #include #include +#include +#include #include "cc-usb.h" #define NUM_BLOCK 512 +static const struct option options[] = { + { .name = "tty", .has_arg = 1, .val = 'T' }, + { 0, 0, 0, 0}, +}; + +static void usage(char *program) +{ + fprintf(stderr, "usage: %s [--tty ]\n", program); + exit(1); +} + int main (int argc, char **argv) { @@ -31,10 +44,26 @@ main (int argc, char **argv) uint8_t *b; int i, j; uint32_t addr; - char *tty; + char *tty = NULL; + int c; - tty = getenv("CCDBG_TTY"); + while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) { + switch (c) { + case 'T': + tty = optarg; + break; + default: + usage(argv[0]); + break; + } + } + if (!tty) + tty = getenv("ALTOS_TTY"); + if (!tty) + tty="/dev/ttyACM0"; cc = cc_usb_open(tty); + if (!cc) + exit(1); for (block = 0; block < NUM_BLOCK; block++) { cc_queue_read(cc, bytes, sizeof (bytes)); cc_usb_printf(cc, "e %x\n", block); diff --git a/ao-tools/ao-load/ao-load.c b/ao-tools/ao-load/ao-load.c index b84a88a6..c27fcbe9 100644 --- a/ao-tools/ao-load/ao-load.c +++ b/ao-tools/ao-load/ao-load.c @@ -19,17 +19,12 @@ #include #include #include +#include +#include #include "ccdbg.h" #define AO_USB_DESC_STRING 3 -void -usage(char *program) -{ - fprintf(stderr, "usage: %s \n", program); - exit(1); -} - struct sym { unsigned addr; char *name; @@ -94,6 +89,17 @@ rewrite(struct hex_image *image, unsigned addr, char *data, int len) memcpy(image->data + addr - image->address, data, len); } +static const struct option options[] = { + { .name = "tty", .has_arg = 1, .val = 'T' }, + { 0, 0, 0, 0}, +}; + +static void usage(char *program) +{ + fprintf(stderr, "usage: %s [--tty ] file.ihx serial-number\n", program); + exit(1); +} + int main (int argc, char **argv) { @@ -102,12 +108,12 @@ main (int argc, char **argv) uint16_t pc; struct hex_file *hex; struct hex_image *image; - char *filename; - FILE *file; - FILE *map; - char *serial_string; - unsigned int serial; - char *mapname, *dot; + char *filename; + FILE *file; + FILE *map; + char *serial_string; + unsigned int serial; + char *mapname, *dot; char *serial_ucs2; int serial_ucs2_len; char serial_int[2]; @@ -115,8 +121,20 @@ main (int argc, char **argv) int i; unsigned usb_descriptors; int string_num; - - filename = argv[1]; + char *tty = NULL; + int c; + + while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) { + switch (c) { + case 'T': + tty = optarg; + break; + default: + usage(argv[0]); + break; + } + } + filename = argv[optind]; if (filename == NULL) usage(argv[0]); mapname = strdup(filename); @@ -125,7 +143,7 @@ main (int argc, char **argv) usage(argv[0]); strcpy(dot, ".map"); - serial_string = argv[2]; + serial_string = argv[optind + 1]; if (serial_string == NULL) usage(argv[0]); @@ -160,7 +178,7 @@ main (int argc, char **argv) serial = strtoul(serial_string, NULL, 0); if (!serial) - usage(argv[0]); +(argv[0]); serial_int[0] = serial & 0xff; serial_int[1] = (serial >> 8) & 0xff; @@ -201,7 +219,7 @@ main (int argc, char **argv) if (!rewrite(image, usb_descriptors + 2 + image->address, serial_ucs2, serial_ucs2_len)) usage(argv[0]); - dbg = ccdbg_open(); + dbg = ccdbg_open(tty); if (!dbg) exit (1); diff --git a/ao-tools/ao-rawload/ao-rawload.c b/ao-tools/ao-rawload/ao-rawload.c index 5f7708fd..1f1537b9 100644 --- a/ao-tools/ao-rawload/ao-rawload.c +++ b/ao-tools/ao-rawload/ao-rawload.c @@ -16,8 +16,21 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include +#include #include "ccdbg.h" +static const struct option options[] = { + { .name = "tty", .has_arg = 1, .val = 'T' }, + { 0, 0, 0, 0}, +}; + +static void usage(char *program) +{ + fprintf(stderr, "usage: %s [--tty ] file.ihx\n", program); + exit(1); +} + int main (int argc, char **argv) { @@ -26,10 +39,22 @@ main (int argc, char **argv) uint16_t pc; struct hex_file *hex; struct hex_image *image; - char *filename; - FILE *file; + char *filename; + FILE *file; + char *tty = NULL; + int c; - filename = argv[1]; + while ((c = getopt_long(argc, argv, "T:", options, NULL)) != -1) { + switch (c) { + case 'T': + tty = optarg; + break; + default: + usage(argv[0]); + break; + } + } + filename = argv[optind]; if (filename == NULL) { fprintf(stderr, "usage: %s \n", argv[0]); exit(1); @@ -50,7 +75,7 @@ main (int argc, char **argv) } ccdbg_hex_file_free(hex); - dbg = ccdbg_open(); + dbg = ccdbg_open(tty); if (!dbg) exit (1); diff --git a/ao-tools/lib/ccdbg-io.c b/ao-tools/lib/ccdbg-io.c index 9c6693cd..d3f87274 100644 --- a/ao-tools/lib/ccdbg-io.c +++ b/ao-tools/lib/ccdbg-io.c @@ -22,25 +22,32 @@ #include "cc-bitbang.h" struct ccdbg * -ccdbg_open(void) +ccdbg_open(char *tty) { struct ccdbg *dbg; - char *tty; dbg = calloc(sizeof (struct ccdbg), 1); if (!dbg) { perror("calloc"); return NULL; } - tty = getenv("CCDBG_TTY"); - if (!tty || tty[0] == '/') - dbg->usb = cc_usb_open(tty); - if (!dbg->usb) { + if (!tty) + tty = getenv("ALTOS_TTY"); + if (!tty) + tty="/dev/ttyACM0"; + + if (!strcmp(tty, "BITBANG")) { dbg->bb = cc_bitbang_open(); if (!dbg->bb) { free(dbg); return NULL; } + } else { + dbg->usb = cc_usb_open(tty); + if (!dbg->usb) { + free(dbg); + return NULL; + } } return dbg; } diff --git a/ao-tools/lib/ccdbg.h b/ao-tools/lib/ccdbg.h index 4a2e3b9f..ca596143 100644 --- a/ao-tools/lib/ccdbg.h +++ b/ao-tools/lib/ccdbg.h @@ -258,7 +258,7 @@ ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b); /* ccdbg-io.c */ struct ccdbg * -ccdbg_open(void); +ccdbg_open(char *tty); void ccdbg_close(struct ccdbg *dbg); diff --git a/ao-tools/lib/cp-usb-async.c b/ao-tools/lib/cp-usb-async.c index 6539394b..3e75b507 100644 --- a/ao-tools/lib/cp-usb-async.c +++ b/ao-tools/lib/cp-usb-async.c @@ -60,6 +60,7 @@ cp_usb_async_open(void) 0x10c4, 0xea60); cp->ack = -1; if (!cp->handle) { + fprintf(stderr, "Cannot find USB device 10c4:ea60\n"); libusb_exit(cp->ctx); free(cp); return NULL; diff --git a/ao-view/aoview.glade b/ao-view/aoview.glade index df08b83c..3481a779 100644 --- a/ao-view/aoview.glade +++ b/ao-view/aoview.glade @@ -651,7 +651,6 @@ You should have received a copy of the GNU General Public License along with AoV normal True aoview - False close Saving EEPROM data as <filename> diff --git a/ao-view/aoview.h b/ao-view/aoview.h index 62d0640b..e8334e5b 100644 --- a/ao-view/aoview.h +++ b/ao-view/aoview.h @@ -308,4 +308,8 @@ 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_main.c b/ao-view/aoview_main.c index 36a82e0e..64c1c027 100644 --- a/ao-view/aoview_main.c +++ b/ao-view/aoview_main.c @@ -32,29 +32,29 @@ static void destroy_event(GtkWidget *widget, gpointer data) } extern int _Xdebug; +char *aoview_tty = NULL; int main(int argc, char **argv) { GladeXML *xml = NULL; GtkWidget *mainwindow; - char *device = NULL; GtkAboutDialog *about_dialog; static struct option long_options[] = { - { "device", 1, 0, 'd'}, + { "tty", 1, 0, 'T'}, { "sync", 0, 0, 's'}, { 0, 0, 0, 0 } }; for (;;) { int c, temp; - c = getopt_long_only(argc, argv, "sd:", long_options, &temp); + c = getopt_long_only(argc, argv, "sT:", long_options, &temp); if (c == -1) break; switch (c) { - case 'd': - device = optarg; + case 'T': + aoview_tty = optarg; break; case 's': _Xdebug = 1; @@ -102,6 +102,12 @@ int main(int argc, char **argv) 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(); -- cgit v1.2.3 From c29275b72438637d46d7a50742882d2736eb176a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 18 Aug 2009 15:21:57 -0700 Subject: Add manual pages for remaining commands. Manuals written for ao-bitbang, ao-eeprom, ao-load, ao-rawload and ao-view. Manual for ao-dbg updated to reflect program name change. Signed-off-by: Keith Packard --- ao-tools/ao-bitbang/Makefile.am | 2 + ao-tools/ao-bitbang/ao-bitbang.1 | 196 +++++++++++++++++++++++++++++++++++++++ ao-tools/ao-dbg/ao-dbg.1 | 52 ++++++----- ao-tools/ao-eeprom/Makefile.am | 2 + ao-tools/ao-eeprom/ao-eeprom.1 | 33 +++++++ ao-tools/ao-load/Makefile.am | 2 + ao-tools/ao-load/ao-load.1 | 38 ++++++++ ao-tools/ao-rawload/Makefile.am | 2 + ao-tools/ao-rawload/ao-rawload.1 | 36 +++++++ ao-view/Makefile.am | 2 + ao-view/ao-view.1 | 50 ++++++++++ 11 files changed, 390 insertions(+), 25 deletions(-) create mode 100644 ao-tools/ao-bitbang/ao-bitbang.1 create mode 100644 ao-tools/ao-eeprom/ao-eeprom.1 create mode 100644 ao-tools/ao-load/ao-load.1 create mode 100644 ao-tools/ao-rawload/ao-rawload.1 create mode 100644 ao-view/ao-view.1 (limited to 'ao-view') diff --git a/ao-tools/ao-bitbang/Makefile.am b/ao-tools/ao-bitbang/Makefile.am index f094c7bd..b27c4090 100644 --- a/ao-tools/ao-bitbang/Makefile.am +++ b/ao-tools/ao-bitbang/Makefile.am @@ -8,3 +8,5 @@ ao_bitbang_DEPENDENCIES = $(AO_BITBANG_LIBS) ao_bitbang_LDADD=$(AO_BITBANG_LIBS) $(LIBUSB_LIBS) ao_bitbang_SOURCES = ao-bitbang.c + +man_MANS=ao-bitbang.1 \ No newline at end of file diff --git a/ao-tools/ao-bitbang/ao-bitbang.1 b/ao-tools/ao-bitbang/ao-bitbang.1 new file mode 100644 index 00000000..44eea1ec --- /dev/null +++ b/ao-tools/ao-bitbang/ao-bitbang.1 @@ -0,0 +1,196 @@ +.\" +.\" 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-BITBANG 1 "ao-bitbang" "" +.SH NAME +ao-bitbang \- Low-level cc1111 interface diagnostic tool +.SH SYNOPSIS +.B "ao-bitbang" +.SH DESCRIPTION +.I ao-bitbang +connects through a CP2103 usb-to-serial converter and uses the GPIO +pins to communicate with the debug port on a cc1111 device. It +provides raw access to the debug pins to help debug the lowest level +communication path. +.SH USAGE +.I ao-bitbang +reads a sequence of bit manipulations from stdin, sends them to the +device and reports status on stdout. +.P +Each line on stdin should contain a single letter command for each of +the three debug lines on the cc1111 -- clock, data and reset. Each bit +can be in one of three states -- on (C, D or R), off (.) or tri-state +(-) for input. Empty lines, or lines starting with '#' are +ignored. Anything beyond the last bit in a line is also ignored. The +bits must be listed in the correct order, and the 'on' values must +match the desired bit. +.SH EXAMPLE +.IP "Reset the target device" +# reset +.br +C D R +.br +C D R +.br +C D R +.br +C D R +.IP "Get Chip ID" +# +.br +# Debug mode - drive RESET_N low for two clock cycles +.br +# +.br +C D R +.br +. D . +.br +C D . +.br +. D . +.br +C D . +.br +. D R +.br + +.br +# +.br +# GET_CHIP_ID +.br + +.br +C . R 0 +.br +. . R +.br +C D R 1 +.br +. D R +.br +C D R 1 +.br +. D R +.br +C . R 0 +.br +. . R +.br + +.br +C D R 1 +.br +. D R +.br +C . R 0 +.br +. . R +.br +C . R 0 +.br +. . R +.br +C . R 0 +.br +. . R +.br + +.br +# +.br +# start reading again +.br + +.br +C D R +.br +. - R +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br + +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br + +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br + +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br +C - R +.br +. - R +.br + +.br +C D R +.SH AUTHOR +Keith Packard diff --git a/ao-tools/ao-dbg/ao-dbg.1 b/ao-tools/ao-dbg/ao-dbg.1 index 1f544e5b..a850c454 100644 --- a/ao-tools/ao-dbg/ao-dbg.1 +++ b/ao-tools/ao-dbg/ao-dbg.1 @@ -16,11 +16,11 @@ .\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. .\" .\" -.TH S51 1 "s51" "" +.TH AO-DBG 1 "ao-dbg" "" .SH NAME -s51 \- hex debugger for cc1111 processors +ao-dbg \- hex debugger for cc1111 processors .SH SYNOPSIS -.B "s51" +.B "ao-dbg" [\-t \fIcpu-type\fP] [\-X \fIfrequency\fP] [\-c] @@ -36,13 +36,14 @@ s51 \- hex debugger for cc1111 processors [\-m] [\-T \fItty-device\fP] .SH DESCRIPTION -.I s51 -connects to a cc1111 processor through a cp1203-based USB-to-serial -converter board, using the GPIO pins available on that chip. It provides an -interface compatible with the 8051 emulator of the same name (s51), but -communicating with the real chip instead of an emulation. Using a modified -version of the SDCC debugger (sdcdb), you can control program execution -on the target machine at source-level. +.I ao-dbg +connects to a cc1111 processor through either a suitable cc1111 board +or a cp2103 usb to serial converter board, using the GPIO pins +available on that chip. It provides an interface compatible with the +8051 emulator from sdcc called s51, but communicating with the real +chip instead of an emulation. Using a modified version of the SDCC +debugger (sdcdb), you can control program execution on the target +machine at source-level. .SH OPTIONS The command line options are designed to be compatible with the 8051 @@ -65,9 +66,9 @@ The emulator and sdcdb communicate through a network socket. This option switches the debugger from communicating through stdin/stdout to listening on a specific network port instead. Once a connection is made, the debugger continues on, using that network port for command input and output. The -debugger uses port 9756, and attempts to connect before launching s51, so if -s51 is listening on this port before sdcdb is started, sdcdb will end up -talking to the existing s51 instance. That's often useful for debugging s51 +debugger uses port 9756, and attempts to connect before launching ao-dbg, so if +ao-dbg is listening on this port before sdcdb is started, sdcdb will end up +talking to the existing ao-dbg instance. That's often useful for debugging ao-dbg itself. .IP "\-p \fIprompt\fP" This sets the command prompt to the specified string. @@ -77,17 +78,19 @@ sdcdb. .IP "\-h" This should print a usage message, but does nothing useful currently. .IP "\-m" -This option is not present in the original 8051 emulator, and causes s51 to +This option is not present in the original 8051 emulator, and causes ao-dbg to dump all commands and replies that are received from and sent to sdcdb. .IP "\-T" This selects which tty device the debugger uses to communicate with -the target device. +the target device. The special name 'BITBANG' directs ao-dbg to use +the cp2103 connection, otherwise this should be a usb serial port +connected to a suitable cc1111 debug node. .SH COMMANDS -Once started, s51 connects to the cc1111 via the CP2103 using libusb2 and -then reads and executes commands, either from stdin, or the nework -connection to sdcdb. +Once started, ao-dbg connects to the cc1111 and then reads and +executes commands, either from stdin, or the nework connection to +sdcdb. .PP -Unlike the command line, s51 contains built-in help for each of these +Unlike the command line, ao-dbg contains built-in help for each of these commands, via the 'help' command. Most of the commands are available in a long form and a single character short form. Below, the short form follows the long form after a comma. @@ -159,13 +162,12 @@ the original 8051 emulator. While the original purpose for this program was to connect the source debugger with the hardware, it can also be used as a low-level hex debugger all on its own. In particular, all of the cc1111 peripherals can be -manipulated directly from the s51 command line. -.IP "Starting s51" -If the CP2103 is plugged in, and the CC1111 is connected correctly, the -\'s51\' command itself should connect to the device without trouble. -Note that the CP2103 must have the GPIO pins configured correctly as well. +manipulated directly from the ao-dbg command line. +.IP "Starting ao-dbg" +First ensure that the target cc1111 device and intermediate cp2103 or +cc111 board are all hooked up correctly. .IP -$ s51 +$ ao-dbg .br Welcome to the non-simulated processor .br diff --git a/ao-tools/ao-eeprom/Makefile.am b/ao-tools/ao-eeprom/Makefile.am index 587acee7..ffd437e8 100644 --- a/ao-tools/ao-eeprom/Makefile.am +++ b/ao-tools/ao-eeprom/Makefile.am @@ -8,3 +8,5 @@ ao_eeprom_DEPENDENCIES = $(AO_EEPROM_LIBS) ao_eeprom_LDADD=$(AO_EEPROM_LIBS) $(LIBUSB_LIBS) ao_eeprom_SOURCES = ao-eeprom.c + +man_MANS = ao-eeprom.1 \ No newline at end of file diff --git a/ao-tools/ao-eeprom/ao-eeprom.1 b/ao-tools/ao-eeprom/ao-eeprom.1 new file mode 100644 index 00000000..8caff9d1 --- /dev/null +++ b/ao-tools/ao-eeprom/ao-eeprom.1 @@ -0,0 +1,33 @@ +.\" +.\" 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-EEPROM 1 "ao-eeprom" "" +.SH NAME +ao-eeprom \- Fetch eeprom contents from TeleMetrum device +.SH SYNOPSIS +.B "ao-eeprom" +[\-tty \fItty-device\fP] +.SH DESCRIPTION +.I ao-eeprom +downloads the eeprom contents from a connected TeleMetrum device. +.SH USAGE +.I ao-eeprom +connects to the specified target device and dumps each block of the +eeprom to stdout in hexidecimal bytes. +.SH AUTHOR +Keith Packard diff --git a/ao-tools/ao-load/Makefile.am b/ao-tools/ao-load/Makefile.am index 8a8392af..e8fed8b0 100644 --- a/ao-tools/ao-load/Makefile.am +++ b/ao-tools/ao-load/Makefile.am @@ -8,3 +8,5 @@ ao_load_DEPENDENCIES = $(AO_LOAD_LIBS) ao_load_LDADD=$(AO_LOAD_LIBS) $(LIBUSB_LIBS) ao_load_SOURCES = ao-load.c + +man_MANS = ao-load.1 \ No newline at end of file diff --git a/ao-tools/ao-load/ao-load.1 b/ao-tools/ao-load/ao-load.1 new file mode 100644 index 00000000..10484f3b --- /dev/null +++ b/ao-tools/ao-load/ao-load.1 @@ -0,0 +1,38 @@ +.\" +.\" 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-LOAD 1 "ao-load" "" +.SH NAME +ao-load \- flash a program to a AltOS device +.SH SYNOPSIS +.B "ao-load" +[\-tty \fItty-device\fP] +\fIfile.ihx\fP +\fIdevice serial number\fP +.SH DESCRIPTION +.I ao-load +loads the specified .ihx file into the target device flash memory, +customizing the AltOS image with the specified serial number. +.SH USAGE +.I ao-load +reads the specified .ihx file into memory, locates the matching .map +file and edits the image to customize it using the specified serial +number. It then connects to the specified target device and writes the +program to the target device flash memory. +.SH AUTHOR +Keith Packard diff --git a/ao-tools/ao-rawload/Makefile.am b/ao-tools/ao-rawload/Makefile.am index 24013a85..c157d3d9 100644 --- a/ao-tools/ao-rawload/Makefile.am +++ b/ao-tools/ao-rawload/Makefile.am @@ -8,3 +8,5 @@ ao_rawload_DEPENDENCIES = $(AO_RAWLOAD_LIBS) ao_rawload_LDADD=$(AO_RAWLOAD_LIBS) $(LIBUSB_LIBS) ao_rawload_SOURCES = ao-rawload.c + +man_MANS=ao-rawload.1 \ No newline at end of file diff --git a/ao-tools/ao-rawload/ao-rawload.1 b/ao-tools/ao-rawload/ao-rawload.1 new file mode 100644 index 00000000..e79645f1 --- /dev/null +++ b/ao-tools/ao-rawload/ao-rawload.1 @@ -0,0 +1,36 @@ +.\" +.\" 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-RAWLOAD 1 "ao-rawload" "" +.SH NAME +ao-rawload \- flash a program to a AltOS device +.SH SYNOPSIS +.B "ao-rawload" +[\-tty \fItty-device\fP] +\fIfile.ihx\fP +.SH DESCRIPTION +.I ao-rawload +loads the specified .ihx file, without modification, into the target +device flash memory. +.SH USAGE +.I ao-rawload +reads the specified .ihx file into memory. It then connects to the +specified target device and writes the program to the target device +flash memory. +.SH AUTHOR +Keith Packard diff --git a/ao-view/Makefile.am b/ao-view/Makefile.am index e0cd068c..17661c8e 100644 --- a/ao-view/Makefile.am +++ b/ao-view/Makefile.am @@ -29,5 +29,7 @@ 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 new file mode 100644 index 00000000..99834c4e --- /dev/null +++ b/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 -- cgit v1.2.3