[v1] alfred: Add support for passing location information over alfred.

Message ID 1380659032-14488-2-git-send-email-andrew@lunn.ch (mailing list archive)
State Superseded, archived
Headers

Commit Message

Andrew Lunn Oct. 1, 2013, 8:23 p.m. UTC
  ---
 CHANGELOG          |   3 +
 Makefile           |  24 ++-
 README             |  52 +++++-
 gpsd/Makefile      |  81 ++++++++
 gpsd/alfred-gpsd.c | 529 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gpsd/alfred-gpsd.h | 102 +++++++++++
 6 files changed, 784 insertions(+), 7 deletions(-)
 create mode 100644 gpsd/Makefile
 create mode 100644 gpsd/alfred-gpsd.c
 create mode 100644 gpsd/alfred-gpsd.h
  

Comments

Thijs van Veen Oct. 2, 2013, 7:25 a.m. UTC | #1
Hello Andrew (and the rest of the list),

On Tue, Oct 1, 2013, at 22:23, Andrew Lunn wrote:
> +Alfred-gpsd
> +-----------
> +
> +Alfred-gpsd can be used to distibute GPS location information about
> +your batman-adv mesh network. This information could be, for example,
> +combined with Vis to visualize your mesh topology with true geographic
> +layout. For mobile or nomadic nodes, Alfred-gpsd, can get location
> +information from gpsd.  Alternatively, a static location can be passed
> +on the command line, which is useful for static nodes without a GPS.
> +
> +Alfred-gpsd, similar to to alfred, combines server (daemon) and client
> +functionality in the 'alfred-gpsd' binary. The alfred-gpsd server must
> +be started to distribute location information. When retrieving
> +location information from gpsd, it should be started with:
> +
> + $ alfred-gpsd -s
> +
> +For a static location, use:
> +
> + $ alfred-gpsd -s -l 48.858222,2.2945,358
> +
> +This server will set the location in alfred via unix
> +socket. Obviously, the alfred server must run too to get this
> +information set. When using gpsd, it updates alfred every 2
> +seconds. With a static location, the update it made every 5 minutes.
> +
> +To get JSON formatted output, use:
> +
> + $ alfred-gpsd
> +[
> +  { "source" : "f6:00:48:13:d3:1e", "tpv" :
> {"class":"TPV","tag":"RMC","device":"/dev/ttyACM0","mode":3,"time":"2013-10-01T10:43:20.000Z","ept":0.005,"lat":52.575485000,"lon":-1.339716667,"alt":122.500,"epx":10.199,"epy":15.720,"epv":31.050,"track":0.0000,"speed":0.010,"climb":0.000,"eps":31.44}
> },
> +  { "source" : "8e:4c:77:b3:65:b4", "tpv" :
> {"class":"TPV","device":"command
> line","time":"2013-10-01T10:43:05.129Z","lat":48.858222,"lon":2.2945,"alt":358.000000,"mode":3}
> }
> +]
> +
> +See gpsd_json(5) for documentation of the tpv object. 

As there are many different ways to display GPS coordinates, I suggest
adding the format in which the data will be reported to the
documentation.
In my time playing with gps positioning (just a couple of weeks), I've
run into at least 4 different latitude/longitude formats, most of which
look very much alike, but all of which are incompatible with each other,
so it's important to know which format is used.

Specifically, gpsd parses (standard) NMEA messages, which give position
as hybrid of integer degrees and decimal arc minutes (ddmm.mmmm)
followed by a direction (NSEW).
When displayed in raw mode, gpsd will return these NMEA formatted
values; the JSON output however (which is used) returns pure decimal
degrees (dd.dddddd), with the sign specifying direction (NW are
positive, SE are negative if I'm not mistaking).

I know the format is specified in the gpsd_json man page (which is
referenced), but it seems more user-friendly to me to have the output
format described here as well.
Seeing as there is a member gpsd_format, I'm assuming this is meant to
allow for different formatting in the future, which makes it even more
important to explicitly state how the values are formatted.

Other than that, this looks very promising.
  
Andrew Lunn Oct. 2, 2013, 8:28 a.m. UTC | #2
On Wed, Oct 02, 2013 at 09:25:31AM +0200, Thijs van Veen wrote:
> Hello Andrew (and the rest of the list),
> 
> On Tue, Oct 1, 2013, at 22:23, Andrew Lunn wrote:
> > +Alfred-gpsd
> > +-----------
> > +
> > +Alfred-gpsd can be used to distibute GPS location information about
> > +your batman-adv mesh network. This information could be, for example,
> > +combined with Vis to visualize your mesh topology with true geographic
> > +layout. For mobile or nomadic nodes, Alfred-gpsd, can get location
> > +information from gpsd.  Alternatively, a static location can be passed
> > +on the command line, which is useful for static nodes without a GPS.
> > +
> > +Alfred-gpsd, similar to to alfred, combines server (daemon) and client
> > +functionality in the 'alfred-gpsd' binary. The alfred-gpsd server must
> > +be started to distribute location information. When retrieving
> > +location information from gpsd, it should be started with:
> > +
> > + $ alfred-gpsd -s
> > +
> > +For a static location, use:
> > +
> > + $ alfred-gpsd -s -l 48.858222,2.2945,358
> > +
> > +This server will set the location in alfred via unix
> > +socket. Obviously, the alfred server must run too to get this
> > +information set. When using gpsd, it updates alfred every 2
> > +seconds. With a static location, the update it made every 5 minutes.
> > +
> > +To get JSON formatted output, use:
> > +
> > + $ alfred-gpsd
> > +[
> > +  { "source" : "f6:00:48:13:d3:1e", "tpv" :
> > {"class":"TPV","tag":"RMC","device":"/dev/ttyACM0","mode":3,"time":"2013-10-01T10:43:20.000Z","ept":0.005,"lat":52.575485000,"lon":-1.339716667,"alt":122.500,"epx":10.199,"epy":15.720,"epv":31.050,"track":0.0000,"speed":0.010,"climb":0.000,"eps":31.44}
> > },
> > +  { "source" : "8e:4c:77:b3:65:b4", "tpv" :
> > {"class":"TPV","device":"command
> > line","time":"2013-10-01T10:43:05.129Z","lat":48.858222,"lon":2.2945,"alt":358.000000,"mode":3}
> > }
> > +]
> > +
> > +See gpsd_json(5) for documentation of the tpv object. 
> 
> As there are many different ways to display GPS coordinates, I suggest
> adding the format in which the data will be reported to the
> documentation.

This would be quite a bit of information, so i would probably put in
into an alfred-gpsd specific README, not the Alfred README.

> In my time playing with gps positioning (just a couple of weeks), I've
> run into at least 4 different latitude/longitude formats, most of which
> look very much alike, but all of which are incompatible with each other,
> so it's important to know which format is used.
> 
> Specifically, gpsd parses (standard) NMEA messages, which give position
> as hybrid of integer degrees and decimal arc minutes (ddmm.mmmm)
> followed by a direction (NSEW).
> When displayed in raw mode, gpsd will return these NMEA formatted
> values; the JSON output however (which is used) returns pure decimal
> degrees (dd.dddddd), with the sign specifying direction (NW are
> positive, SE are negative if I'm not mistaking).
> 
> I know the format is specified in the gpsd_json man page (which is
> referenced), but it seems more user-friendly to me to have the output
> format described here as well.

The gpsd_json documentation is not very specific:

           ├───────┼─────────┼─────────┼────────────────────────┤
           │lat    │ No      │ numeric │ Latitude in degrees:   │
           │       │         │         │ +/- signifies          │
           │       │         │         │ West/East.  Present    │
           │       │         │         │         when mode is 2 │
           │       │         │         │ or 3.                  │
           ├───────┼─────────┼─────────┼────────────────────────┤
           │lon    │ No      │ numeric │ Longitude in degrees:  │
           │       │         │         │ +/- signifies          │
           │       │         │         │ North/South. Present   │
           │       │         │         │         when mode is 2 │
           │       │         │         │ or 3.                  │
           ├───────┼─────────┼─────────┼────────────────────────┤

It just says degrees, not "pure" degrees, "not hybrid" degrees, etc.
So importing the gpsd documentation does not really clarify it more.
I'm also hesitant to add additional documentation, above what
gpsd_json says. I've just implemented a "dumb pipe". I don't interpret
the data in any way, i don't guarantee that the format will never
change etc.

> Seeing as there is a member gpsd_format, I'm assuming this is meant to
> allow for different formatting in the future, which makes it even more
> important to explicitly state how the values are formatted.

No, that is not why i added the tpv gpsd_format. I will probably need
the ATT, the vehicle-attitude report, to report what direction my
directional antennae are pointing. I've no intentional of adding other
location formats, eg raw NMEA. That just added complexity i don't want
to handle.
 
> Other than that, this looks very promising.

Thanks
	Andrew
  
Simon Wunderlich Oct. 2, 2013, 1:19 p.m. UTC | #3
On Tue, Oct 01, 2013 at 10:23:52PM +0200, Andrew Lunn wrote:
> ---
>  CHANGELOG          |   3 +
>  Makefile           |  24 ++-
>  README             |  52 +++++-
>  gpsd/Makefile      |  81 ++++++++
>  gpsd/alfred-gpsd.c | 529 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  gpsd/alfred-gpsd.h | 102 +++++++++++
>  6 files changed, 784 insertions(+), 7 deletions(-)
>  create mode 100644 gpsd/Makefile
>  create mode 100644 gpsd/alfred-gpsd.c
>  create mode 100644 gpsd/alfred-gpsd.h
> 
> diff --git a/CHANGELOG b/CHANGELOG
> index aa0371f..404f3f3 100644
> --- a/CHANGELOG
> +++ b/CHANGELOG
> @@ -11,3 +11,6 @@ alfred 2013.3.0:
>   * exchanges data via IPv6 unicast/multicast
>  
>   -- Sun, 28 Jul 2013 18:56:52 +0200
> +
> + * Add support for distributing geographic location information, 
> +   either fixed, or read from gpsd.

I'd like to do the CHANGELOG the other way around, e.g. newest entries come
first - and your changes will not be released in 2013.3.0 or before. :)

Please just drop this change as I'll compile the CHANGELOG when releasing
myself anyway. No need to bother. :)

> \ No newline at end of file
> [...]
> --- /dev/null
> +++ b/gpsd/Makefile
> @@ -0,0 +1,81 @@
> +#!/usr/bin/make -f
> +# -*- makefile -*-
> +#
> +# Copyright (C) 2013 B.A.T.M.A.N. contributors
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of version 2 of the GNU General Public
> +# License as published by the Free Software Foundation.
> +#
> +# 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., 51 Franklin Street, Fifth Floor, Boston, MA
> +# 02110-1301, USA
> +#
> +
> +# alfred build
> +BINARY_NAME = alfred-gpsd
> +OBJ = alfred-gpsd.o
> +
> +# alfred flags and options
> +CFLAGS += -pedantic -Wall -W -std=gnu99 -fno-strict-aliasing -MD -MP
> +LDLIBS += -lgps

I have no idea if we need some special handling for this to let it work
for crosscompiling, OpenWRT etc? 
> +
> +# disable verbose output
> +ifneq ($(findstring $(MAKEFLAGS),s),s)
> +ifndef V
> +	Q_CC = @echo '   ' CC $@;
> +	Q_LD = @echo '   ' LD $@;
> +	export Q_CC
> +	export Q_LD
> +endif
> +endif
> [...]
> +
> +	if ((alt < -1000) || (lon > 9000)) {
> +		/* No support for aircraft or submarines! */

Too bad :D

I haven't tested this, but I like the idea to transport the gpsd information.
We will probably seperate the package to let OpenWRT users choose if they
want to have this feature (because it comes with gpsd dependency), just as
we have done with vis. TBH I didn't expect to fill the alfred repository
with feature daemons, but as long as it is maintained, why not. :)

Thanks,
	Simon
  
Sven Eckelmann Oct. 2, 2013, 4:34 p.m. UTC | #4
On Wednesday 02 October 2013 06:19:15 Simon Wunderlich wrote:
> > +# alfred build
> > +BINARY_NAME = alfred-gpsd
> > +OBJ = alfred-gpsd.o
> > +
> > +# alfred flags and options
> > +CFLAGS += -pedantic -Wall -W -std=gnu99 -fno-strict-aliasing -MD -MP
> > +LDLIBS += -lgps
> 
> I have no idea if we need some special handling for this to let it work
> for crosscompiling, OpenWRT etc?

Please use pkg-config for things like this. An example Makefile is attached.

@Simon: Please fix your e-mail adress inside the README file.

Kind regards,
	Sven
  
Andrew Lunn Oct. 2, 2013, 4:47 p.m. UTC | #5
On Wed, Oct 02, 2013 at 06:34:15PM +0200, Sven Eckelmann wrote:
> On Wednesday 02 October 2013 06:19:15 Simon Wunderlich wrote:
> > > +# alfred build
> > > +BINARY_NAME = alfred-gpsd
> > > +OBJ = alfred-gpsd.o
> > > +
> > > +# alfred flags and options
> > > +CFLAGS += -pedantic -Wall -W -std=gnu99 -fno-strict-aliasing -MD -MP
> > > +LDLIBS += -lgps
> > 
> > I have no idea if we need some special handling for this to let it work
> > for crosscompiling, OpenWRT etc?
> 
> Please use pkg-config for things like this. An example Makefile is attached.

Hi Sven

Thanks for the Makefile. Works on my Debian system.

       Andrew
  
Simon Wunderlich Oct. 3, 2013, 2:21 p.m. UTC | #6
On Wed, Oct 02, 2013 at 06:34:15PM +0200, Sven Eckelmann wrote:
> On Wednesday 02 October 2013 06:19:15 Simon Wunderlich wrote:
> > > +# alfred build
> > > +BINARY_NAME = alfred-gpsd
> > > +OBJ = alfred-gpsd.o
> > > +
> > > +# alfred flags and options
> > > +CFLAGS += -pedantic -Wall -W -std=gnu99 -fno-strict-aliasing -MD -MP
> > > +LDLIBS += -lgps
> > 
> > I have no idea if we need some special handling for this to let it work
> > for crosscompiling, OpenWRT etc?
> 
> Please use pkg-config for things like this. An example Makefile is attached.
> 
> @Simon: Please fix your e-mail adress inside the README file.

Done, applied in 9021511.

Thanks for pointing that out.
	Simon
  

Patch

diff --git a/CHANGELOG b/CHANGELOG
index aa0371f..404f3f3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,3 +11,6 @@  alfred 2013.3.0:
  * exchanges data via IPv6 unicast/multicast
 
  -- Sun, 28 Jul 2013 18:56:52 +0200
+
+ * Add support for distributing geographic location information, 
+   either fixed, or read from gpsd.
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 7b13d7b..5bc24d8 100644
--- a/Makefile
+++ b/Makefile
@@ -64,9 +64,15 @@  ifneq ($(CONFIG_ALFRED_VIS),n)
 	VIS_INSTALL=vis-install
 endif
 
+ifneq ($(CONFIG_ALFRED_GPSD),n)
+	GPSD_ALL=gpsd-all
+	GPSD_CLEAN=gpsd-clean
+	GPSD_INSTALL=gpsd-install
+endif
+
 
 # default target
-all: $(BINARY_NAME) $(VIS_ALL)
+all: $(BINARY_NAME) $(VIS_ALL) $(GPSD_ALL)
 
 # standard build rules
 .SUFFIXES: .o .c
@@ -76,10 +82,10 @@  all: $(BINARY_NAME) $(VIS_ALL)
 $(BINARY_NAME): $(OBJ)
 	$(LINK.o) $^ $(LDLIBS) -o $@
 
-clean:	$(VIS_CLEAN)
+clean:	$(VIS_CLEAN) $(GPSD_CLEAN)
 	$(RM) $(BINARY_NAME) $(OBJ) $(DEP)
 
-install: $(BINARY_NAME) $(VIS_INSTALL)
+install: $(BINARY_NAME) $(VIS_INSTALL) $(GPSD_INSTALL)
 	$(MKDIR) $(DESTDIR)$(SBINDIR)
 	$(MKDIR) $(DESTDIR)$(MANDIR)/man8
 	$(INSTALL) -m 0755 $(BINARY_NAME) $(DESTDIR)$(SBINDIR)
@@ -94,8 +100,18 @@  vis-all:
 vis-clean:
 	$(MAKE) -C vis clean
 
+gpsd-install:
+	$(MAKE) -C gpsd install
+
+gpsd-all:
+	$(MAKE) -C gpsd all
+
+gpsd-clean:
+	$(MAKE) -C gpsd clean
+
 # load dependencies
 DEP = $(OBJ:.o=.d)
 -include $(DEP)
 
-.PHONY: all clean install vis-install vis-all vis-clean
+.PHONY: all clean install vis-install vis-all vis-clean \
+	gpsd-install gpsd-all gpsd-clean
diff --git a/README b/README
index 50c36ad..3e1001f 100644
--- a/README
+++ b/README
@@ -29,11 +29,14 @@  alfred depends on:
  * librt (usually part of libc)
  * IPv6 support in the kernel/host system
 
+and if distributing GPS information:
+ * libgps
+
 To compile alfred, simply type:
 
  $ make
 
-This will compile both alfred and batadv-vis. To install, use
+This will compile alfred, batadv-vis & alfred-gpsd. To install, use
 
  $ make install
 
@@ -44,6 +47,13 @@  If you don't want to compile batadv-vis, add the directive CONFIG_ALFRED_VIS=n:
  $ make CONFIG_ALFRED_VIS=n 
  $ make CONFIG_ALFRED_VIS=n install
 
+If you don't want to compile alfred-gpsd, add the directive
+CONFIG_ALFRED_GPSD=n:
+
+ $ make CONFIG_ALFRED_GPSD=n 
+ $ make CONFIG_ALFRED_GPSD=n install
+
+
 Usage
 -----
 
@@ -169,11 +179,47 @@  For a json formatted output, use:
 { "primary" : "fe:f0:00:00:08:01" }
 [...]
 
+Alfred-gpsd
+-----------
+
+Alfred-gpsd can be used to distibute GPS location information about
+your batman-adv mesh network. This information could be, for example,
+combined with Vis to visualize your mesh topology with true geographic
+layout. For mobile or nomadic nodes, Alfred-gpsd, can get location
+information from gpsd.  Alternatively, a static location can be passed
+on the command line, which is useful for static nodes without a GPS.
+
+Alfred-gpsd, similar to to alfred, combines server (daemon) and client
+functionality in the 'alfred-gpsd' binary. The alfred-gpsd server must
+be started to distribute location information. When retrieving
+location information from gpsd, it should be started with:
+
+ $ alfred-gpsd -s
+
+For a static location, use:
+
+ $ alfred-gpsd -s -l 48.858222,2.2945,358
+
+This server will set the location in alfred via unix
+socket. Obviously, the alfred server must run too to get this
+information set. When using gpsd, it updates alfred every 2
+seconds. With a static location, the update it made every 5 minutes.
+
+To get JSON formatted output, use:
+
+ $ alfred-gpsd
+[
+  { "source" : "f6:00:48:13:d3:1e", "tpv" : {"class":"TPV","tag":"RMC","device":"/dev/ttyACM0","mode":3,"time":"2013-10-01T10:43:20.000Z","ept":0.005,"lat":52.575485000,"lon":-1.339716667,"alt":122.500,"epx":10.199,"epy":15.720,"epv":31.050,"track":0.0000,"speed":0.010,"climb":0.000,"eps":31.44} },
+  { "source" : "8e:4c:77:b3:65:b4", "tpv" : {"class":"TPV","device":"command line","time":"2013-10-01T10:43:05.129Z","lat":48.858222,"lon":2.2945,"alt":358.000000,"mode":3} }
+]
+
+See gpsd_json(5) for documentation of the tpv object. 
+
 License
 -------
 
-alfred and batadv-vis are licensed under the terms of version 2 of the GNU
-General Public License (GPL). Please see the LICENSE file.
+alfred, batadv-vis and alfred-gpsd are licensed under the terms of version 2
+of the GNU General Public License (GPL). Please see the LICENSE file.
 
 The file "packet.h" is an exception and not licensed with the GPL. Instead,
 it is licensed using ISC license (see the head of this file). This allows
diff --git a/gpsd/Makefile b/gpsd/Makefile
new file mode 100644
index 0000000..69add9c
--- /dev/null
+++ b/gpsd/Makefile
@@ -0,0 +1,81 @@ 
+#!/usr/bin/make -f
+# -*- makefile -*-
+#
+# Copyright (C) 2013 B.A.T.M.A.N. contributors
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA
+#
+
+# alfred build
+BINARY_NAME = alfred-gpsd
+OBJ = alfred-gpsd.o
+
+# alfred flags and options
+CFLAGS += -pedantic -Wall -W -std=gnu99 -fno-strict-aliasing -MD -MP
+LDLIBS += -lgps
+
+# disable verbose output
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+	Q_CC = @echo '   ' CC $@;
+	Q_LD = @echo '   ' LD $@;
+	export Q_CC
+	export Q_LD
+endif
+endif
+
+# standard build tools
+CC ?= gcc
+RM ?= rm -f
+INSTALL ?= install
+MKDIR ?= mkdir -p
+COMPILE.c = $(Q_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
+LINK.o = $(Q_LD)$(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_ARCH)
+
+# standard install paths
+PREFIX = /usr/local
+SBINDIR = $(PREFIX)/sbin
+
+# try to generate revision
+REVISION= $(shell	if [ -d ../.git ]; then \
+				echo $$(git describe --always --dirty --match "v*" |sed 's/^v//' 2> /dev/null || echo "[unknown]"); \
+			fi)
+ifneq ($(REVISION),)
+CPPFLAGS += -DSOURCE_VERSION=\"$(REVISION)\"
+endif
+
+# default target
+all: $(BINARY_NAME)
+
+# standard build rules
+.SUFFIXES: .o .c
+.c.o:
+	$(COMPILE.c) -o $@ $<
+
+$(BINARY_NAME): $(OBJ)
+	$(LINK.o) $^ $(LDLIBS) -o $@
+
+clean:
+	$(RM) $(BINARY_NAME) $(OBJ) $(DEP)
+
+install: $(BINARY_NAME)
+	$(MKDIR) $(DESTDIR)$(SBINDIR)
+	$(INSTALL) -m 0755 $(BINARY_NAME) $(DESTDIR)$(SBINDIR)
+
+# load dependencies
+DEP = $(OBJ:.o=.d)
+-include $(DEP)
+
+.PHONY: all clean install
diff --git a/gpsd/alfred-gpsd.c b/gpsd/alfred-gpsd.c
new file mode 100644
index 0000000..e8f1125
--- /dev/null
+++ b/gpsd/alfred-gpsd.c
@@ -0,0 +1,529 @@ 
+/*
+ * Copyright (C) 2013 B.A.T.M.A.N. contributors:
+ *
+ * Andrew Lunn, Simon Wunderlich
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "alfred-gpsd.h"
+
+static int alfred_open_sock(struct globals *globals)
+{
+	struct sockaddr_un addr;
+
+	globals->unix_sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (globals->unix_sock < 0) {
+		fprintf(stderr, "can't create unix socket: %s\n",
+			strerror(errno));
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_LOCAL;
+	strcpy(addr.sun_path, ALFRED_SOCK_PATH);
+
+	if (connect(globals->unix_sock, (struct sockaddr *)&addr,
+		    sizeof(addr)) < 0) {
+		fprintf(stderr, "can't connect to unix socket: %s\n",
+			strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int gpsd_publish_data(struct globals *globals)
+{
+	int len, ret;
+
+	/* to push data we have to add a push header, the header for the data
+	 * and our own data type.
+	 */
+	globals->push->tx.id = htons(ntohs(globals->push->tx.id) + 1);
+
+	len = GPSD_DATA_SIZE(globals->gpsd_data);
+	globals->push->data->header.length = htons(len);
+	len += sizeof(*globals->push) - sizeof(globals->push->header);
+	len += sizeof(*globals->push->data);
+	globals->push->header.length = htons(len);
+	len +=  sizeof(globals->push->header);
+
+	alfred_open_sock(globals);
+	if (globals->unix_sock < 0)
+		return globals->unix_sock;
+
+	ret = write(globals->unix_sock, globals->buf, len);
+	close(globals->unix_sock);
+	if (ret < len)
+		return -1;
+
+	return 0;
+}
+
+static void gpsd_get_location(struct globals *globals)
+{
+	if (globals->source == SOURCE_CMDLINE) {
+		char tbuf[JSON_DATE_MAX+1];
+		timestamp_t now = timestamp();
+
+		sprintf(globals->gpsd_data->tpv,
+			"{\"class\":\"TPV\",\"device\":\"command line\","
+			"\"time\":\"%s\","
+			"\"lat\":%f,\"lon\":%f,\"alt\":%f,"
+			"\"mode\":3}",
+			unix_to_iso8601(now, tbuf, sizeof(tbuf)),
+			globals->lat, globals->lon, globals->alt);
+		globals->gpsd_data->tpv_len =
+			htonl(strlen(globals->gpsd_data->tpv) + 1);
+	}
+}
+
+static int gpsd_update_data(struct globals *globals)
+{
+	gpsd_get_location(globals);
+	gpsd_publish_data(globals);
+
+	return 0;
+}
+
+static int gpsd_request_data(struct globals *globals)
+{
+	int ret;
+
+	globals->request = (struct alfred_request_v0 *) globals->buf;
+
+	globals->request->header.type = ALFRED_REQUEST;
+	globals->request->header.version = ALFRED_VERSION;
+	globals->request->header.length =
+		htons(sizeof(*globals->request) - 
+		      sizeof(globals->request->header));
+	globals->request->requested_type = GPSD_PACKETTYPE;
+	globals->request->tx_id = htons(random());
+
+	alfred_open_sock(globals);
+	if (globals->unix_sock < 0)
+		return globals->unix_sock;
+
+	ret = write(globals->unix_sock, globals->request,
+		    sizeof(*globals->request));
+	if (ret < (int)sizeof(*globals->request)) {
+		close(globals->unix_sock);
+		return -1;
+	}
+
+	return globals->unix_sock;
+}
+
+static struct gpsd_v1 *gpsd_receive_answer_packet(int sock, uint16_t *len,
+						  uint8_t *source)
+{
+	static uint8_t buf[65536];
+	struct alfred_tlv *tlv;
+	struct alfred_push_data_v0 *push;
+	struct alfred_data *data;
+	int l, ret;
+
+	ret = read(sock, buf, sizeof(*tlv));
+	if (ret < 0)
+		return NULL;
+
+	if (ret < (int)sizeof(*tlv))
+		return NULL;
+
+	tlv = (struct alfred_tlv *)buf;
+	/* TODO: might return an ALFRED_STATUS_ERROR too, handle it */
+	if (tlv->type != ALFRED_PUSH_DATA)
+		return NULL;
+
+	l = ntohs(tlv->length);
+	/* exceed the buffer? don't read */
+	if (l > (int)(sizeof(buf) - sizeof(push->header)))
+		return NULL;
+
+	/* not enough for even the push packet and header? don't bother. */
+	if (l < (int)(sizeof(*push) - sizeof(push->header) + sizeof(*data)))
+		return NULL;
+
+	/* read the rest of the packet */
+	ret = read(sock, buf + sizeof(*tlv), l);
+	if (ret < l)
+		return NULL;
+
+	push = (struct alfred_push_data_v0 *)buf;
+	data = push->data;
+	*len = ntohs(data->header.length);
+
+	if (data->header.type != GPSD_PACKETTYPE)
+		return NULL;
+
+	if (data->header.version != GPSD_PACKETVERSION)
+		return NULL;
+
+	memcpy(source, data->source, ETH_ALEN);
+	return (struct gpsd_v1 *) data->data;
+}
+
+static int gpsd_read_answer(struct globals *globals)
+{
+	struct gpsd_v1 *gpsd_data;
+	uint16_t len;
+	uint8_t source[ETH_ALEN];
+	bool first_line = true;
+
+	printf("[\n");
+
+	while ((gpsd_data = gpsd_receive_answer_packet(globals->unix_sock,
+						       &len,
+						       source)) != NULL) {
+		if (len < sizeof(*gpsd_data))
+			break;
+
+		/* check size and skip bogus packets */
+		if (len != GPSD_DATA_SIZE(gpsd_data))
+			continue;
+
+		if (first_line)
+			first_line = false;
+		else
+			printf(",\n");
+
+		printf("  { \"source\" : \"%02x:%02x:%02x:%02x:%02x:%02x\", "
+		       "\"tpv\" : %s }",
+		       source[0], source[1], source[2],
+		       source[3], source[4], source[5],
+		       gpsd_data->tpv);
+	}
+	printf("\n]\n");
+
+
+	return 0;
+}
+
+/* Standard parsing of a GPS data source spec. Taken from gpsdclient.c */
+static void gpsd_source_spec(const char *arg, struct fixsource_t *source)
+{
+	/* the casts attempt to head off a -Wwrite-strings warning */
+	source->server = (char *)"localhost";
+	source->port = (char *)DEFAULT_GPSD_PORT;
+	source->device = NULL;
+
+	if (arg != NULL) {
+		char *colon1, *skipto, *rbrk;
+		source->spec = strdup(arg);
+		assert(source->spec != NULL);
+
+		skipto = source->spec;
+		if (*skipto == '[' && (rbrk = strchr(skipto, ']')) != NULL) {
+			skipto = rbrk;
+		}
+		colon1 = strchr(skipto, ':');
+
+		if (colon1 != NULL) {
+			char *colon2;
+			*colon1 = '\0';
+			if (colon1 != source->spec) {
+				source->server = source->spec;
+			}
+			source->port = colon1 + 1;
+			colon2 = strchr(source->port, ':');
+			if (colon2 != NULL) {
+				*colon2 = '\0';
+				source->device = colon2 + 1;
+			}
+		} else if (strchr(source->spec, '/') != NULL) {
+			source->device = source->spec;
+		} else {
+			source->server = source->spec;
+		}
+	}
+
+	if (*source->server == '[') {
+		char *rbrk = strchr(source->server, ']');
+		++source->server;
+		if (rbrk != NULL)
+			*rbrk = '\0';
+	}
+}
+
+static int gpsd_get_data(struct globals *globals)
+{
+	globals->unix_sock = gpsd_request_data(globals);
+	if (globals->unix_sock < 0)
+		return -1;
+
+	gpsd_read_answer(globals);
+	close(globals->unix_sock);
+
+	return 0;
+}
+
+static void gpsd_connect_gpsd(struct globals *globals)
+{
+	unsigned int flags = WATCH_ENABLE | WATCH_JSON;
+	int ret;
+
+	ret = gps_open(globals->gpsdsource.server, globals->gpsdsource.port,
+		       &globals->gpsdata);
+
+	if (ret) {
+		/* Could not connect to gpsd. Set the fd so we don't
+		   try to perform select(2) on it. */
+		globals->gpsdata.gps_fd = -1;
+		return;
+	}
+
+	if (globals->gpsdsource.device != NULL)
+		flags |= WATCH_DEVICE;
+
+	gps_stream(&globals->gpsdata, flags, globals->gpsdsource.device);
+}
+
+static void gpsd_read_gpsd(struct globals *globals)
+{
+	ssize_t ret;
+	size_t cnt;
+	bool eol = false;
+	char buf[4096];
+
+	cnt = 0;
+	do {
+		ret = read(globals->gpsdata.gps_fd, &buf[cnt], 1);
+		if (ret != 1) {
+			gps_close(&globals->gpsdata);
+			globals->gpsdata.gps_fd = -1;
+			return;
+		}
+
+		if (buf[cnt] == '\r')
+			cnt--;
+
+		if (buf[cnt] == '\n') {
+			eol = true;
+			buf[cnt] = '\0';
+			break;
+		}
+	} while (cnt++ < sizeof(buf) - 1);
+
+	if (!eol) {
+		gps_close(&globals->gpsdata);
+		globals->gpsdata.gps_fd = -1;
+		return;
+	}
+
+#define STARTSWITH(str, prefix)	strncmp(str, prefix, sizeof(prefix)-1)==0
+	if (STARTSWITH(buf, "{\"class\":\"TPV\"")) {
+		strcpy(globals->gpsd_data->tpv, buf);
+		globals->gpsd_data->tpv_len =
+			htonl(strlen(globals->gpsd_data->tpv) + 1);
+	}
+}
+
+static void gpsd_usage(void)
+{
+	printf("Usage: alfred-gpsd [options]\n");
+	printf("  -s, --server                start up in server mode, which regularly updates gpsd data from batman-adv\n");
+	printf("  -l <lat>,<lon>,<alt>        Static location\n");
+	printf("  -g server[:port[:device]]   GPSD source\n");
+	printf("  -v, --version               print the version\n");
+	printf("  -h, --help                  this help\n");
+	printf("\n");
+}
+
+static void gpsd_parse_location(struct globals *globals,
+				const char * optarg)
+{
+	int n;
+	float lat, lon, alt;
+
+	n = sscanf(optarg, "%f,%f,%f", &lat, &lon, &alt);
+	if (n != 3) {
+		printf("Unable to parse location\n");
+		gpsd_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	if ((lat < -90) || (lat > 90)) {
+		printf("Invalid latitude\n");
+		gpsd_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	if ((lon < -180) || (lon > 180)) {
+		printf("Invalid longitude\n");
+		gpsd_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	if ((alt < -1000) || (lon > 9000)) {
+		/* No support for aircraft or submarines! */
+		printf("Invalid altitude\n");
+		gpsd_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	globals->lat = lat;
+	globals->lon = lon;
+	globals->alt = alt;
+}
+
+static struct globals *gpsd_init(int argc, char *argv[])
+{
+	bool have_source = false;
+	int opt, opt_ind;
+	struct globals *globals;
+	struct option long_options[] = {
+		{"server",	no_argument,		NULL,	's'},
+		{"location",    required_argument,	NULL,	'l'},
+		{"gpsd",	required_argument,	NULL,	'g'},
+		{"help",	no_argument,		NULL,	'h'},
+		{"version",	no_argument,		NULL,	'v'},
+		{NULL,		0,			NULL,	0},
+	};
+
+	globals = malloc(sizeof(*globals));
+	if (!globals)
+		return NULL;
+
+	memset(globals, 0, sizeof(*globals));
+
+	globals->opmode = OPMODE_CLIENT;
+	globals->source = SOURCE_GPSD;
+	globals->gpsd_format = FORMAT_JSON;
+
+	while ((opt = getopt_long(argc, argv, "shl:g:v", long_options,
+				  &opt_ind)) != -1) {
+		switch (opt) {
+		case 's':
+			globals->opmode = OPMODE_SERVER;
+			break;
+		case 'l':
+			globals->source = SOURCE_CMDLINE;
+			gpsd_parse_location(globals, optarg);
+			break;
+		case 'g':
+			gpsd_source_spec(optarg, &globals->gpsdsource);
+			have_source = true;
+			break;
+		case 'v':
+			printf("%s %s\n", argv[0], SOURCE_VERSION);
+			printf("GPSD alfred client\n");
+			return NULL;
+		case 'h':
+		default:
+			gpsd_usage();
+			return NULL;
+		}
+	}
+
+	if (globals->source == SOURCE_GPSD && !have_source)
+		gpsd_source_spec(NULL, &globals->gpsdsource);
+
+	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+		fprintf(stderr, "could not register SIGPIPE handler\n");
+	return globals;
+}
+
+static int gpsd_server(struct globals *globals)
+{
+	struct timeval tv;
+	fd_set fds;
+	int max_fd, ret;
+	const size_t overhead = sizeof(*globals->push) +
+		sizeof(struct alfred_data);
+	long interval;
+
+	globals->push = (struct alfred_push_data_v0 *) globals->buf;
+	globals->gpsd_data = (struct gpsd_v1 *)
+		(globals->buf + overhead);
+
+	globals->push->header.type = ALFRED_PUSH_DATA;
+	globals->push->header.version = ALFRED_VERSION;
+	globals->push->tx.id = 0;
+	globals->push->tx.seqno = 0;
+	globals->push->data->header.type = GPSD_PACKETTYPE;
+	globals->push->data->header.version = GPSD_PACKETVERSION;
+
+	strcpy(globals->gpsd_data->tpv, GPSD_INIT_TPV);
+	globals->gpsd_data->tpv_len =
+		htonl(strlen(globals->gpsd_data->tpv) + 1);
+
+	/* If we have a static location, we don't need to update very
+	   often. */
+	if (globals->source == SOURCE_GPSD) {
+		globals->gpsdata.gps_fd = -1;
+		interval = 2;
+	} else
+		interval = 60 * 5;
+
+	while (1) {
+		gpsd_update_data(globals);
+
+		/* If we are not connected to gpsd, try to connect. */
+		if (globals->source == SOURCE_GPSD &&
+		    globals->gpsdata.gps_fd == -1) {
+			gpsd_connect_gpsd(globals);
+		}
+
+		/* Use linux's select(2) behaviour of setting
+		   tv to the remaining time when it exists */
+		tv.tv_sec = interval;
+		tv.tv_usec = 0;
+
+		do {
+			FD_ZERO(&fds);
+
+			if (globals->source == SOURCE_GPSD &&
+				globals->gpsdata.gps_fd != -1) {
+				FD_SET(globals->gpsdata.gps_fd, &fds);
+				max_fd = globals->gpsdata.gps_fd + 1;
+			} else {
+				max_fd = 0;
+			}
+
+			errno = 0;
+			ret = select(max_fd, &fds, NULL, NULL, &tv);
+			if (ret == -1 && errno != EINTR)
+				printf("select error %s(%d)\n",
+				       strerror(errno), errno);
+
+			if (ret == 1)
+				gpsd_read_gpsd(globals);
+		} while (ret != 0);
+	}
+	return EXIT_FAILURE;
+}
+
+int main(int argc, char *argv[])
+{
+	struct globals *globals;
+
+	globals = gpsd_init(argc, argv);
+
+	if (!globals)
+		return EXIT_FAILURE;
+
+	switch (globals->opmode) {
+	case OPMODE_SERVER:
+		return gpsd_server(globals);
+		break;
+	case OPMODE_CLIENT:
+		return gpsd_get_data(globals);
+		break;
+	}
+
+	return EXIT_FAILURE;
+}
diff --git a/gpsd/alfred-gpsd.h b/gpsd/alfred-gpsd.h
new file mode 100644
index 0000000..206561e
--- /dev/null
+++ b/gpsd/alfred-gpsd.h
@@ -0,0 +1,102 @@ 
+/*
+ * Copyright (C) 2013 B.A.T.M.A.N. contributors:
+ *
+ * Andrew Lunn, Simon Wunderlich
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/ether.h>
+#include <netinet/in.h>
+#include <gps.h>
+#include "../packet.h"
+#include "../list.h"
+
+#ifndef SOURCE_VERSION
+#define SOURCE_VERSION				"2013.4.0"
+#endif
+
+#define ALFRED_SOCK_PATH			"/var/run/alfred.sock"
+#define PATH_BUFF_LEN				200
+#define GPSD_PACKETTYPE				2
+#define	GPSD_PACKETVERSION			1
+#define UPDATE_INTERVAL				10
+
+enum opmode {
+	OPMODE_SERVER,
+	OPMODE_CLIENT
+};
+
+enum source {
+	SOURCE_CMDLINE,
+	SOURCE_GPSD
+};
+
+enum gpsd_format {
+	FORMAT_JSON
+};
+
+#define JSON_DATE_MAX   24      /* ISO8601 timestamp with 2 decimal places */
+
+struct gpsd_v1 {
+	uint32_t tpv_len;
+	__extension__ char tpv[0];
+} __packed;
+
+#define GPSD_INIT_TPV "{\"class\":\"TPV\",\"mode\":0}"
+
+#define GPSD_DATA_SIZE(gpsd_data)	\
+	(sizeof(*gpsd_data) + (ntohl(gpsd_data->tpv_len)))
+
+/* struct taken from gpsdclient.h */
+struct fixsource_t
+{
+	char *spec;         /* pointer to actual storage */
+	char *server;
+	char *port;
+	char *device;
+};
+
+struct globals {
+	enum opmode opmode;
+	enum source source;
+	enum gpsd_format gpsd_format;
+	uint8_t buf[65536];
+
+	/* internal pointers into buf */
+	struct alfred_request_v0 *request;
+	struct alfred_push_data_v0 *push;
+	struct gpsd_v1 *gpsd_data;
+
+	float lat, lon, alt;
+	int unix_sock;
+
+	struct fixsource_t gpsdsource;
+	struct gps_data_t gpsdata;
+	char * tpv;
+};