diff --git a/examples/log_replay.py b/examples/log_replay.py new file mode 100755 index 0000000..ff73948 --- /dev/null +++ b/examples/log_replay.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +# +# A simple tool for playback of Gypsy NMEA logs via a named pipe. +# +# Author: Tim Savage +# Copyright (C) 2010 +# +# 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. +# +import os, os.path +import stat +import sys +import time +import optparse + + +def work_loop(log, pipe, options): + # Stream data to client + while True: + data = log.readline() + delay = options.delay + if not data: + # Rewind to start of log + log.seek(0) + else: + # Check for a comment + if data.startswith('#'): continue + + # Handle the plain case + if not options.plain: + delay, data = data.split(':', 2) + try: + delay = float(delay) + except ValueError: + continue + + time.sleep(delay) + pipe.write(data) + pipe.flush() + + +def get_options(): + p = optparse.OptionParser(usage="usage: %prog [options] log_file") + p.add_option('-p', '--pipe', default='/tmp/gypsy', + help='path to named pipe') + p.add_option('', '--plain', action='store_true', default=False, + help="file does not contain time deltas") + p.add_option('', '--delay', type='float', default=0.2, + help="delay between plain messages") + + options, args = p.parse_args() + if len(args) != 1: + p.error("incorrect number of arguments") + + return options, args + + +def verify_pipe(pipe_path): + # Check if path exists + if os.path.exists(pipe_path): + if not stat.S_ISFIFO(os.stat(pipe_path).st_mode): + print >> sys.stderr, "File `%s' is not a fifo." % pipe_path + return False + + if not os.access(pipe_path, os.W_OK): + print >> sys.stderr, "Named pipe `%s' is not writable." % pipe_path + return False + else: + os.mkfifo(pipe_path, 0600) + return True + + +def main(): + options, args = get_options() + log_file = args[0] + + # Do checks on pipe to ensure it's valid + if not verify_pipe(options.pipe): + sys.exit(1) + + try: + log = open(log_file, 'r') + except IOError: + print >> sys.stderr, "File not found: ", log_file + sys.exit(1) + + print "Waiting for Gypsy on named pipe:", options.pipe + try: + pipe = open(options.pipe, 'w') + print "Streaming data..." + work_loop(log, pipe, options) + except KeyboardInterrupt: + pass + except IOError: + print >> sys.stderr, "Unable to open pipe." + sys.exit(1) + else: + print "Streaming data..." + try: + work_loop(log, pipe, options) + except KeyboardInterrupt: + pass + except IOError: + print "Gypsy disconnected." + + +if __name__ == '__main__': + main() diff --git a/examples/simple-gps-python.py b/examples/simple-gps-python.py index c68ae92..8d92f9f 100755 --- a/examples/simple-gps-python.py +++ b/examples/simple-gps-python.py @@ -5,6 +5,7 @@ import sys import gobject import dbus, dbus.service, dbus.mainloop.glib +import optparse # Some constants we need GYPSY_DBUS_SERVICE = "org.freedesktop.Gypsy" @@ -20,10 +21,12 @@ GYPSY_POSITION_FIELDS_LONGITUDE = 1 << 1 GYPSY_POSITION_FIELDS_ALTITUDE = 1 << 2 -# Check that the Bluetooth ID of the GPS is specified on the command line -if len(sys.argv) != 2: - print "$ simple-gps-python.py [bluetooh ID]" - sys.exit(1) +# Get options from command line +p = optparse.OptionParser(usage="usage: %prog [options] gps_path") +p.add_option('-b', '--baud', help="set the default baud for serial tty GPS's") +options, args = p.parse_args() +if len(args) != 1: + p.error("incorrect number of arguments") # Hook into the glib main loop dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) @@ -35,7 +38,7 @@ bus = dbus.SystemBus() control = bus.get_object(GYPSY_DBUS_SERVICE, GYPSY_DBUS_PATH) # Create a client for the specified GPS device -path = control.Create(sys.argv[1], dbus_interface=GYPSY_CONTROL_DBUS_INTERFACE) +path = control.Create(args[0], dbus_interface=GYPSY_CONTROL_DBUS_INTERFACE) # Get a proxy to the client gps = bus.get_object(GYPSY_DBUS_SERVICE, path) @@ -52,6 +55,9 @@ position.connect_to_signal("PositionChanged", position_changed) # Get a proxy to the Device interface, and start it up device = dbus.Interface(gps, dbus_interface=GYPSY_DEVICE_DBUS_INTERFACE) +if options.baud: + print "Baud rate set to:", options.baud + device.SetStartOptions({"BaudRate": dbus.UInt32(options.baud)}) device.Start() # Enter the main loop, and let the signals arrive diff --git a/src/gypsy-client.c b/src/gypsy-client.c index 2312d7b..2a38b2a 100644 --- a/src/gypsy-client.c +++ b/src/gypsy-client.c @@ -78,6 +78,7 @@ typedef enum { /* Defined in main.c */ extern char* nmea_log; +extern gboolean log_deltas; #define READ_BUFFER_SIZE 1024 #define SPEED_TIMEOUT 1000 @@ -91,6 +92,8 @@ typedef struct _GypsyClientPrivate { GIOChannel *channel; /* The channel we talk to the GPS on */ GIOChannel *debug_log; /* The channel to write the NMEA to, or NULL if debugging is off */ + GTimer *debug_delta; /* A timer to log deltas between NMEA messages */ + guint32 error_id, connect_id, input_id; @@ -242,6 +245,11 @@ shutdown_connection (GypsyClient *client) priv->debug_log = NULL; } + if (priv->debug_delta) { + g_timer_destroy (priv->debug_delta); + priv->debug_delta = NULL; + } + priv->chars_in_buffer = 0; #ifdef ENABLE_N810 @@ -253,6 +261,21 @@ shutdown_connection (GypsyClient *client) #endif /* ENABLE_N810 */ } +static void +write_log_delta(GypsyClientPrivate *priv) +{ + char delta_buff[10]; + int delta_len; + //gulong microseconds; + + gdouble delta = g_timer_elapsed (priv->debug_delta, NULL); + g_timer_reset (priv->debug_delta); + + delta_len = g_snprintf (delta_buff, 10, "%f:", delta); + g_io_channel_write_chars (priv->debug_log, delta_buff, + delta_len, NULL, NULL); +} + static gboolean gps_channel_error (GIOChannel *channel, GIOCondition condition, @@ -301,6 +324,9 @@ gps_channel_garmin_input (GIOChannel *channel, &error); if (priv->debug_log) { + if (priv->debug_delta) { + write_log_delta(priv); + } g_io_channel_write_chars(priv->debug_log, buf, chars_read, NULL, NULL); } @@ -438,6 +464,9 @@ gps_channel_input (GIOChannel *channel, NULL); if (priv->debug_log) { + if (priv->debug_delta) { + write_log_delta(priv); + } g_io_channel_write_chars (priv->debug_log, buf, chars_read, NULL, NULL); } @@ -812,6 +841,10 @@ gypsy_client_start (GypsyClient *client, } g_io_channel_set_encoding (priv->debug_log, NULL, NULL); g_io_channel_set_buffered (priv->debug_log, FALSE); + + if (log_deltas) { + priv->debug_delta = g_timer_new (); + } } /* Set up the IO Channel */ diff --git a/src/main.c b/src/main.c index 6cc0e26..0f4ba7b 100644 --- a/src/main.c +++ b/src/main.c @@ -47,6 +47,7 @@ static GMainLoop *mainloop; /* This is a bit ugly, but it works */ char* nmea_log = NULL; +gboolean log_deltas = FALSE; static void gypsy_terminate (GObject *object, @@ -101,6 +102,7 @@ main (int argc, GOptionEntry entries[] = { { "nmea-log", 0, 0, G_OPTION_ARG_FILENAME, &nmea_log, "Log NMEA data to FILE.[device]", "FILE" }, + { "log-delta", 0, 0, G_OPTION_ARG_NONE, &log_deltas, "Log a time delta with NMEA data", NULL }, { "no-daemon", 0, 0, G_OPTION_ARG_NONE, &become_daemon, "Don't become a daemon", NULL }, { "pid-file", 0, 0, G_OPTION_ARG_FILENAME, &user_pidfile, "Specify the location of a PID file", "FILE" }, { NULL }