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

Message ID 1380899775-25238-1-git-send-email-andrew@lunn.ch (mailing list archive)
State Accepted, archived
Commit 2b901d69d8fbddb2ed7fbc3cfc5d7115319d0a05
Headers

Commit Message

Andrew Lunn Oct. 4, 2013, 3:16 p.m. UTC
  It can be useful to know where mesh nodes are located. Add an Alfred
server which can get the current location from gpsd, or a static
location from the command line. Add a client which can display this
information distributed by nodes in JSON format.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---

Since v1:
 Remove CHANGELOG entry
 Makefile uses pkg-config, thanks to Sven
 Add man page.

 Makefile               |  24 ++-
 README                 |  52 ++++-
 gpsd/Makefile          |  98 +++++++++
 gpsd/alfred-gpsd.c     | 529 +++++++++++++++++++++++++++++++++++++++++++++++++
 gpsd/alfred-gpsd.h     | 102 ++++++++++
 gpsd/man/alfred-gpsd.8 |  92 +++++++++
 6 files changed, 890 insertions(+), 7 deletions(-)
 create mode 100644 gpsd/Makefile
 create mode 100644 gpsd/alfred-gpsd.c
 create mode 100644 gpsd/alfred-gpsd.h
 create mode 100644 gpsd/man/alfred-gpsd.8
  

Comments

Stephen Thornton Oct. 9, 2013, 4:34 p.m. UTC | #1
I am currently developing a mesh router solution for several clients. I have been using batman-adv in this project for almost a year (using OpenWRT), and it has all worked fantastically. Thanks so much guys.
I now have a requirement for GPS logging functionality, along with passing other data between nodes. I have already written a simple layer3 protocol for this purpose, but this was before ALFRED. ALFRED provides almost all the functionality I need apart from the fact that I really need to embed the alfred code within my own application. I could use it as is via a sys call, but it would be so much better to include the code. What are your feelings regarding splitting the alfred code into a library with can be included in other user applications, and an alfred client program that uses this library? I'm quite prepared to give quite a bit of my own time to doing this if you like the idea.

best regards
Steve Thornton
  
Andrew Lunn Oct. 9, 2013, 9:48 p.m. UTC | #2
On Wed, Oct 09, 2013 at 05:34:00PM +0100, Stephen Thornton wrote:

Hi Stephen

Please could you fix your mail client to keep lines short than around
70 characters.

> I am currently developing a mesh router solution for several clients. I have been using batman-adv in this project for almost a year (using OpenWRT), and it has all worked fantastically. Thanks so much guys.
> I now have a requirement for GPS logging functionality, along with passing other data between nodes. I have already written a simple layer3 protocol for this purpose, but this was before ALFRED. ALFRED provides almost all the functionality I need apart from the fact that I really need to embed the alfred code within my own application. I could use it as is via a sys call, but it would be so much better to include the code. What are your feelings regarding splitting the alfred code into a library with can be included in other user applications, and an alfred client program that uses this library? I'm quite prepared to give quite a bit of my own time to doing this if you like the idea.

Are you interested in using alfred, or vis built on top of alfred?
Would you want a library for accessing alfred, or for accessing vis?

You could pull some of the boilerplate code out of vis and my
alfred-gpsd server/client into a library. e.g. alfred_open_sock(),
_publish_data(), _request_data(), _receive_answer_packet(),
_get_data(). What will cause problems is the globals structure.  It is
a mixture of generic and application specific members. That will
require quite a bit of refactoring.

I'm just not sure it is worth the effort. It took me less than a
mythical man day to get a proof of concept gpsd code working, and
another day to sort out output formatting issues and the odd bug, etc.
Creating a new client/server embedded in some other application is not
particularly difficult, re-using the existing code.

     Andrew
  
Simon Wunderlich Oct. 10, 2013, 12:58 p.m. UTC | #3
Hello Stephen,

On Wed, Oct 09, 2013 at 05:34:00PM +0100, Stephen Thornton wrote:
> I am currently developing a mesh router solution for several clients. I have been using batman-adv in this project for almost a year (using OpenWRT), and it has all worked fantastically. Thanks so much guys.

thank you :)
> I now have a requirement for GPS logging functionality, along with passing other data between nodes. I have already written a simple layer3 protocol for this purpose, but this was before ALFRED. ALFRED provides almost all the functionality I need apart from the fact that I really need to embed the alfred code within my own application. I could use it as is via a sys call, but it would be so much better to include the code. What are your feelings regarding splitting the alfred code into a library with can be included in other user applications, and an alfred client program that uses this library? I'm quite prepared to give quite a bit of my own time to doing this if you like the idea.

Well, the alfred binary does quite a few things and relies on being a process on it's own. I don't think
it's easy to integrate that functionality in a library, and it is not intended.

What we'd like to encourage however is to interface directly with alfred by talking to it through
the unix socket - have a look at vis (already implemented) or the gpsd support andrew recently
proposed. You could do the same for your application - talk to alfred directly. That should also
be the best solution in regard of long term maintainance, license issues (alfred is GPL after all), ...

If you feel that alfred really needs to be binary-integrated in your application, I'd like to know why. :)

Cheers,
	Simon
  
Simon Wunderlich Oct. 13, 2013, 9:51 p.m. UTC | #4
On Fri, Oct 04, 2013 at 05:16:15PM +0200, Andrew Lunn wrote:
> It can be useful to know where mesh nodes are located. Add an Alfred
> server which can get the current location from gpsd, or a static
> location from the command line. Add a client which can display this
> information distributed by nodes in JSON format.
> 
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>

Applied in revision 2b901d6.

Thanks,
	Simon
  

Patch

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 4a494a4..dbcc44a 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..eaf390b
--- /dev/null
+++ b/gpsd/Makefile
@@ -0,0 +1,98 @@ 
+#!/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-gpsd build
+BINARY_NAME = alfred-gpsd
+OBJ = alfred-gpsd.o
+
+# alfred flags and options
+CFLAGS += -pedantic -Wall -W -std=gnu99 -fno-strict-aliasing -MD -MP
+
+# 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
+
+ifeq ($(origin PKG_CONFIG), undefined)
+  PKG_CONFIG = pkg-config
+  ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),)
+    $(error $(PKG_CONFIG) not found)
+  endif
+endif
+
+ifeq ($(origin LIBGPS_CFLAGS) $(origin LIBGPS_LDLIBS), undefined undefined)
+  LIBGPS_NAME ?= libgps
+  ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBGPS_NAME) 2>/dev/null),)
+    $(error No $(LIBGPS_NAME) development libraries found!)
+  endif
+  LIBGPS_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBGPS_NAME))
+  LIBGPS_LDLIBS +=  $(shell $(PKG_CONFIG) --libs $(LIBGPS_NAME))
+endif
+CFLAGS += $(LIBGPS_CFLAGS)
+LDLIBS += $(LIBGPS_LDLIBS)
+
+# 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;
+};
diff --git a/gpsd/man/alfred-gpsd.8 b/gpsd/man/alfred-gpsd.8
new file mode 100644
index 0000000..fa5cb1f
--- /dev/null
+++ b/gpsd/man/alfred-gpsd.8
@@ -0,0 +1,92 @@ 
+.\"                                      Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH "ALFRED-GPSD" "8" "Oct 04, 2013" "Linux" "Alfred GPS distribution server"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.\" --------------------------------------------------------------------------
+.\" Process this file with
+.\" groff -man batadv-vis.8 -Tutf8
+.\" Retrieve format warnings with
+.\" man --warnings batadv-vis.8 > /dev/null
+.\" --------------------------------------------------------------------------
+.ad l
+.SH NAME
+alfred\-gpsd \- Alfred GPS distribution server
+.SH SYNOPSIS
+.B alfred\-gpsd [\fIoptions\fP]
+.br
+.SH DESCRIPTION
+alfred\-gpsd can be used to distribute GPS location information over
+your batman-adv mesh network. It reads the current location from gpsd,
+or a fixed location from the command line, and distributes this
+information via alfred. By gathering this local information, any
+alfred-gpsd node can get location information about other nodes.
+.PP
+.PP
+.SH OPTIONS
+.TP
+\fB\-v\fP, \fB\-\-version\fP
+Print the version
+.TP
+\fB\-h\fP, \fB\-\-help\fP
+Display a brief help message.
+.TP
+\fB\-s\fP, \fB\-\-server\fP
+Start up in server mode. This server will read the current location
+from gpsd and set it in alfred via unix socket. The alfred server must
+run too to get this information set.
+.TP
+\fB\-l\fP, \fB\-\-location <lat>,<lon>,<alt>\fP
+Rather than read the current location from gpsd, use a fixed location.
+.TP
+\fB\-g\fP, \fB\-\-gpsd server[:port[:device]]\fP
+Specify the server hostname and optional port of where gpsd is
+listening. Additionally, a specific device connected to gpsd can be specified.
+.
+.SH EXAMPLES
+Start an alfred\-gpsd server which is fetching GPS data from the local gpsd.
+.br
+\fB     alfred\-gpsd \-s\fP
+.br
+
+Start an alfred\-gpsd server with a fixed location
+.br
+\fB     alfred\-gpsd \-s \-l 48.858222,2.2945,358\fP
+.br
+
+To get a list of GPS locations, in JSON format:
+.br
+\fB     alfred-gpsd\fP
+.nf
+[
+  { "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}
+  }
+]
+.fi
+.br
+.
+.SH SEE ALSO
+.BR alfred (8),
+.BR gpsd (8)
+.BR gpsd_json(5)
+.SH AUTHOR
+alfred\-gpsd and this Manual page was written by Andrew Lunn <andrew@lunn.ch>