| Charles Curley - Software Engineer, Writer
| << | < | > | >> | Blog | Linked In Profile
+ Larger Font | - Smaller Font
Charles Curley

Valid XHTML 1.0! Valid CSS!


gps

A few items to help with GpsDrive or the GPS receiver.

gpsdate

#! /usr/bin/perl

# Time-stamp: <2006-07-12 15:11:26 ccurley gpsdate.pl>

# OK, I'm lazy; it's one of the reasons I work in Perl. I figure if we
# have these 24 atomic clocks of reasonably acceptable accuracy
# orbiting the planet, I ought to be able to set my system clock from
# them occasionally. So this is a simple script to display the system
# time from GPS. You can also use it to set the system time.

# Options:

# -h sets the host. Default is 'localhost'.

# -p sets the port on the remote host to try. You can give the service
# name (e.g. gpsd) or the port number (e.g. 2947). Or you can give
# both by using the syntax 'name(number)', e.g. 'gpsd(2947)'. If perl
# can't find the name wherever it looks these things up (probably
# /etc/services), it goes for the number. So use both for maximum
# portability. The default value is 'gpsd(2947)'.

# -s indicates that we should spit out the time and date in UTC ready
# for settime to set the system clock. We even provide the -u switch
# for date. E.g:

# date $(gpsdate -s)
# date $(gpsdate -hs gpsbox)

# If -s is not set, we give a more human readable time format.


# All times are in UTC. If you want the time in local time, there
# should be a perl function somewhere to do that. Let me know what you
# find.

# Requires: gpsd (http://gpsd.berlios.de); date, the gnu time setting
# and displaying utility. Oh, and a GPS receiver somewhere would
# probably help.

# gpsdate will block until the GPS receiver has warmed up,
# i.e. acquired enough satellites (or whatever it needs) to have a
# valid time signal.

# For more on the GPSD protocol, see
# http://www.pygps.org/gpsd/protocol.html

# Copyright 2004 through the last date of modification Charles Curley,
# http://www.charlescurley.com/.

# 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

# You can also contact the Free Software Foundation at
# http://www.fsf.org/

# Changes:

# 2006-04-19: Dropped support for telnet in favor of Net::GPSD.

# 2006-03-20: Turns out my new GPS receiver and/or the latest version
# of gpsd don't send a correct mode. I took that out. Also, it looks
# like the change sends the time and date in a different format.

use Net::GPSD;
use Getopt::Std;
use strict;

my %option;

getopts ("h:p:s", \%option);

# $host is the name or IP address of the host. It may be local or
# remote. e.g: localhost. User configurable at the command line with -h.

$option{h} = 'localhost' unless defined $option{h};
my $host = $option{h};

# $port is the port on the remote host to try. User configurable at
# the command line with -p.

$option{p} = 'gpsd(2947)' unless defined $option{p};
my $port = $option{p};

# $settime, if set, indicates that we should spit out the time and
# date in UTC ready for settime to set the system clock. We even
# provide the -u switch for date.

my $settime=$option{s};

my $gps=Net::GPSD->new(host=>$host, port=>$port);
if (!defined($gps)) {
    die("Error: Cannot connect to the gpsd server");
}

# print ("\$gps is $gps.\n");

my $point=$gps->get;
if ($point) {
    while (!$point->fix) {
        print "No fix.\n";
        sleep (4);
    }
    my $td = $point->datetime;

#   print ($point->lat, " ", $point->lon, " at ", $td, "\n");

    (my $date, my $time) = unpack ("A10, x1, A11", $td);

# print "\$date is $date, \$time is $time.\n";

    if ($settime) {
#     @time=split (/:/, $time);
#     @date=split (/\//, $date);
        my @time=split (/:/, $time);
        my @date=split (/-/, $date);
        printf (" -u %02d%02d%02d%02d%04d.%02d\n",
#           $date[0], $date[1], $time[0], $time[1], $date[2], $time[2]);
                $date[1], $date[2], $time[0], $time[1], $date[0], $time[2]);
#     print  ("    MMDDhhmmCCYY.ss\n");
    } else {
        print ("$0: It is $time, $date, UTC.\n");
    }
} else {
    print ("Can't connect to gpsd.\n");
}

sa2gpsdrive

sa2gpsdrive is a program for converting the route lat/long export from DeLorme's Street Atlas 8 to waypoints for GpsDrive's MySQL database. You create a route in SA8, then export it, convert it with this, then import it into MySQL, and you see the route as a series of waypoints. It will probably handle exports from other programs as well.

#! /usr/bin/perl

# A program to convert DeLorme Street Atlas 8 route files to a file
# ready to import into MySQL for GpsDrive.

# Time-stamp: <2005-09-13 12:20:49 ccurley sa2gpsdrive>

# Copyright 2005 through the last date of modification, Charles Curley.

# 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

# You can also contact the Free Software Foundation at
# http://www.fsf.org/

# You can export a route from DeLorme Street Atlas 8 (and possibly
# other versions) with "File-> Export Route as Lat/Long File". The
# default file name is rpoints.txt. The result is a point per line,
# latitude followed by longitude, with a space and a comma in
# between. Really simple. This program massages that format into a
# MySQL import script, ready to import into MySQL for GpsDrive.

# The default waypoint type is 'DeLorme', but you can change that with
# a command line option, -t. The resulting script will first delete
# all waypoints of that type, so you can make corrections and try as
# you go. This also means you should NOT make any other waypoints this
# type.

# You can set a value for filtering waypoints with the -n option,
# where n is an integer from 1 on up. The program will send the first,
# last and every nth waypoint to the output file.

# In addition, you may use a text editor to add an optional third
# column to any line. The script uses this field for the name for that
# waypoint, and any line with a name added will also be sent to the
# output file, even if it is not one of the -nth entries. Use a comma
# for the delimiter, so commas in the name are verboten. Single quotes
# are escaped, so that MySQL won't choke on them.

# The default waypoint name is the waypoint count, followed by the
# type. So if you set N to 1 (the default) the waypoint's name on the
# screen gives you the line in the source file to which to add a
# name. You can then re-filter the source file with a larger N, which
# will give you a sparser set of waypoints. Use this to force
# inclusion of important waypoints like intersections.

# The default input file is rpoints.txt (How's that for user friendly?
# :-). You may specify another with the -i option. The output file is
# the base name of the file (i.e. without any extension) plus the
# extension .sql. So the default output file is rpoints.sql. The
# output file is delivered to your maps directory as specified in your
# gpsdrive configuration file, .gpsdrive/gpsdriverc.

# In addition, this program generates another file you may use when
# you are done using the waypoints to delete them from the
# database. That file has the extension .del.sql, and is also
# delivered to your maps directory.

use strict;
use Getopt::Std;
use File::Basename;

# Get the name of the database, and user name and password to log in
# to MySQL from the gpsdrive config file.

my $input = $ENV{HOME} . '/.gpsdrive/gpsdriverc';

my $dbname;
my $dbuser;
my $dbpass;
my $dbtable;
my $dbhostname;
my $mapdir;

open (SOURCE, "< $input")
    or die "Couldn't open input file $input.\n";
while (<SOURCE>) {
    chop ();
    my @line = split ('=');
    chop ($line[0]);
    if ($line[0] eq 'dbname') {
#   print "Examining $line[0] is set to $line[1].\n";
    $dbname = $line[1];
    $dbname =~ s/^\s+//;    # strip leading spaces.
    $dbname =~ s/\s+$//;    # strip trailing spaces.
    } elsif ($line[0] eq 'dbuser') {
#   print "Examining $line[0] is set to $line[1].\n";
    $dbuser = $line[1];
    $dbuser =~ s/^\s+//;    # strip leading spaces.
    $dbuser =~ s/\s+$//;    # strip trailing spaces.
    } elsif ($line[0] eq 'dbpass') {
#   print "Examining $line[0] is set to $line[1].\n";
    $dbpass = $line[1];
    $dbpass =~ s/^\s+//;    # strip leading spaces.
    $dbpass =~ s/\s+$//;    # strip trailing spaces.
    } elsif ($line[0] eq 'dbtable') {
#   print "Examining $line[0] is set to $line[1].\n";
    $dbtable = $line[1];
    $dbtable =~ s/^\s+//;   # strip leading spaces.
    $dbtable =~ s/\s+$//;   # strip trailing spaces.
    } elsif ($line[0] eq 'dbhostname') {
#   print "Examining $line[0] is set to $line[1].\n";
    $dbhostname = $line[1];
    $dbhostname =~ s/^\s+//;    # strip leading spaces.
    $dbhostname =~ s/\s+$//;    # strip trailing spaces.
    } elsif ($line[0] eq 'mapdir') {
#   print "Examining $line[0] is set to $line[1].\n";
    $mapdir = $line[1];
    $mapdir =~ s/^\s+//;    # strip leading spaces.
    $mapdir =~ s/\s+$//;    # strip trailing spaces.
    }
}

# The input file default value

$input = "rpoints.txt";

# The default type value

my $type = 'DeLorme';

# Increment for filtering waypoints. Use only every nth point.

my $nth = 1;

# Shall we determine our extreme points?

my $points = 0;

my $i = 0;              # generic counter

sub oops {
    print "$0: a script to convert DeLorme route points files to GspDrive waypoints.\n";
    print "options: -i: input file; -t: waypoint type; -n: use every nth point.\n";
    print "-p: print the extremes of north/south/east/west travel.\n";
}

my %option = ();
getopts ("hi:n:pt:", \%option);

if ($option{h}) {
    &oops ();
    exit (0);
}

if ($option{i}) {
    $input = $option{i};
}

if ($option{n}) {
    $nth = $option{n};
}

if ($option{t}) {
    $type = $option{t};
}

if ($option{p}) {
    $points = $option{p};
}

# print "Filtering file $input\n";
# print "Waypoint type is $type\n";

# Get rid of any path and prepend that of the map directory.
my $output = $mapdir . basename($input);

# remove the extension, if any.
my @output = split (/./, $output);

if ($#output) {
    $#output--;
    $output = join ('.', @output);
}

# print ("file base name is $output\n");

# Open read only & count the lines, so we can get the last
# one. Initialize to the extreme of travel on the planet.

my $total = my $lines = 0;
my $north = -90;
my $south = 90;
my $east = -180;
my $west = 180;
my ($nl, $sl, $el, $wl);

open (SOURCE, "< $input")
    or die "Couldn't open input file $input.\n";
while (<SOURCE>) {
    # split the line.
    if ($points) {
    $lines++;

    chop ();
    chop ();
    my @line = split (',');

    $line[0] =~ s/^\s+//;
    $line[0] =~ s/\s+$//;

    $line[1] =~ s/^\s+//;
    $line[1] =~ s/\s+$//;

    if ($north < $line[0]) {
        $north = $line[0];
        $nl = $lines;
    }

    if ($south > $line[0]) {
        $south = $line[0];
        $sl = $lines;
    }

    if ($east < $line[1]) {
        $east = $line[1];
        $el = $lines;
    }

    if ($west > $line[1]) {
        $west = $line[1];
        $wl = $lines;
    }
    }
}
$total = $.;            # The total count of lines.

# print ("$nl, $sl, $el, $wl\n$north, $south, $east, $west");

# Open for read only.
open (SOURCE, "< $input")
    or die "Couldn't open input file $input.\n";

# Open for write, create and truncate
open (SINK, "> $output.del.sql")
    or die "Couldn't open output file $output.del.sql\n";

print SINK "use $dbname;\n";
print SINK "delete from $dbtable where type='$type';\n";

# Open for write, create and truncate
open (SINK, "> $output.sql")
    or die "Couldn't open output file $output.sql.\n";

print SINK "use $dbname;\n";
print SINK "delete from $dbtable where type='$type';\n";

my $count = $lines = 0;
my $name = '';

while (<SOURCE>) {
    chomp;
    $lines++;

    # split the line.
    my @line = split (',');

    if ($points) {

    # If there's no name and this line is one of the extreme
    # travel points, add a name.

    if ($lines == $nl && !length ($line[2])) {
        $line[2] = 'Northernmost Point.';
    }

    if ($lines == $sl && !length ($line[2])) {
        $line[2] = 'Southernmost Point.';
    }

    if ($lines == $el && !length ($line[2])) {
        $line[2] = 'Easternmost Point.';
    }

    if ($lines == $wl && !length ($line[2])) {
        $line[2] = 'Westernmost Point.';
    }
    }

    # On every nth line, any line with a comment, the last line, or the first line...
    $i++;
    if ($i == $nth || length ($line[2]) || $lines == $total || $lines == 1) {
    if ($i == $nth) {
        $i=0;
        $count++;
    }

    if (length ($line[2])) {
        $name = $line[2];

        # Trim leading & trailing whitespace

        $name =~ s/^\s+//;
        $name =~ s/\s+$//;

        # Escape single quotes.

        $name =~ s/\'/\\\'/g;
    } elsif ($lines == 1) {
        $name = 'Start';
    } elsif ($lines == $total) {
        $name = 'Finish';
    } else {
        $name = "$count $type waypoint";
    }

    # Turn spaces into underscores for GpsDrive's benefit.

    $name =~ s/ /\_/g;

    print SINK "INSERT INTO $dbtable VALUES ('$name', '$type', '0', '$line[0]', '$line[1]', '', 0, '0', 0, NULL);\n";

    $line[2] = '';
    }

    undef (@line);
}

print ("Feed the output file into MySQL like so:\n\n\$ mysql -u$dbuser -p$dbpass < $output.sql\n");


exit (0);

The next trick: a shell script that watches the output from sa2gpsdrive, and every time it changes, stuffs it into MySQL. GpsDrive will pick up the results when it refreshes waypoints. Then you will have a (near) real-time GUI while you edit the lat/long file.

gpsd

Oddly enough, the gpsd package for Fedora Core does not come equipped with a script for the init scripts that launch most services in Fedora. Here's my solution. This launches gpsd as user "nobody", rather than as your regular user or root. This means you can toggle gpsd "on" and "off" in GpsDrive and it will reset GpsDrive's connection to gpsd but not gpsd itself. This is makes for faster recovery time.

#!/bin/sh
#
# gpsd:
#
# chkconfig: 345 96 99
# description: controls the gpsd daemon for reading gps NMEA receivers.
#
#

# Copyright 2005 through the last date of modification, Charles Curley.

# 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

# You can also contact the Free Software Foundation at
# http://www.fsf.org/

# We now refuse to start gpsd if the device file is not present,
# i.e. no gps. 2007-04-17 -- C^2

# Added stop function. We now save a pid file on startup. 2006-07-29  -- C^2

# re-worked for gpsd-2.30-1. 2006-03-18  -- C^2

device=/dev/ttyUSB0

pidfile=/var/run/gpsd.pid

gpsd=/usr/sbin/gpsd
# gpsd=/usr/local/bin/gpsd

# Sanity checks.
[ -x $gpsd ] || exit 0

# Source function library.
. /etc/rc.d/init.d/functions

start() {
    [ -c $device ] || exit 0    # Don't start unless we have the device file.
    echo -n $"Starting background gps daemon: "
    daemon $gpsd -P $pidfile $device &
}

stop() {
   if [ -e $pidfile ] ; then
       pid=$(cat $pidfile)
       rm $pidfile
       daemon kill $pid
       RETVAL=$?
       if [ $RETVAL != "0" ]; then
       echo "Kill Failed!"
       fi
   fi
}

status () {
   echo $"Sorry, $0 status has not been implemented. "
}

# See how we were called.
case "$1" in
    start)
    start
    ;;
    stop)
    stop
    ;;
    status)
        status
        ;;
    restart)
    stop
    start
    ;;
    condrestart)
    ;;
    reload)
        ;;
    *)
    echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
    ;;
esac
exit $RETVAL

Install it as /etc/rc.d/init.d/gpsd and make it executable by root only. You may have to change the name of the serial device; this script is set up for a USB serial device. Then run chkconfig --add gpsd to integrate it into the system. That will set it up to run in run levels three, four and five.


Copyright © 1996 through 2010 by Charles Curley
Last Modified: 11 Mar, 2010
100% Microsoft-free web site.