summaryrefslogtreecommitdiff
path: root/vehicle
diff options
context:
space:
mode:
Diffstat (limited to 'vehicle')
-rw-r--r--vehicle/Makefile.am16
-rw-r--r--vehicle/demo/Makefile.am5
-rw-r--r--vehicle/demo/vehicle_demo.c206
-rw-r--r--vehicle/file/Makefile.am9
-rw-r--r--vehicle/file/vehicle_file.c763
-rw-r--r--vehicle/file/vehicle_pipe.c27
-rw-r--r--vehicle/gpsd/Makefile.am6
-rw-r--r--vehicle/gpsd/vehicle_gpsd.c387
-rw-r--r--vehicle/gypsy/Makefile.am6
-rw-r--r--vehicle/gypsy/vehicle_gypsy.c465
-rw-r--r--vehicle/wince/Makefile.am5
-rw-r--r--vehicle/wince/vehicle_wince.c614
12 files changed, 2509 insertions, 0 deletions
diff --git a/vehicle/Makefile.am b/vehicle/Makefile.am
new file mode 100644
index 00000000..08a9da9d
--- /dev/null
+++ b/vehicle/Makefile.am
@@ -0,0 +1,16 @@
+SUBDIRS=
+if VEHICLE_DEMO
+ SUBDIRS += demo
+endif
+if VEHICLE_FILE
+ SUBDIRS += file
+endif
+if VEHICLE_GPSD
+ SUBDIRS += gpsd
+endif
+if VEHICLE_GYPSY
+ SUBDIRS += gypsy
+endif
+if VEHICLE_WINCE
+ SUBDIRS += wince
+endif
diff --git a/vehicle/demo/Makefile.am b/vehicle/demo/Makefile.am
new file mode 100644
index 00000000..608e9d0b
--- /dev/null
+++ b/vehicle/demo/Makefile.am
@@ -0,0 +1,5 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=vehicle_demo
+modulevehicle_LTLIBRARIES = libvehicle_demo.la
+libvehicle_demo_la_SOURCES = vehicle_demo.c
+libvehicle_demo_la_LDFLAGS = -module -avoid-version
diff --git a/vehicle/demo/vehicle_demo.c b/vehicle/demo/vehicle_demo.c
new file mode 100644
index 00000000..ebc72d6a
--- /dev/null
+++ b/vehicle/demo/vehicle_demo.c
@@ -0,0 +1,206 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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 <glib.h>
+#include <string.h>
+#include "config.h"
+#include "debug.h"
+#include "coord.h"
+#include "item.h"
+#include "navit.h"
+#include "map.h"
+#include "route.h"
+#include "callback.h"
+#include "transform.h"
+#include "plugin.h"
+#include "vehicle.h"
+#include "event.h"
+#include "util.h"
+
+struct vehicle_priv {
+ int interval;
+ int position_set;
+ struct callback_list *cbl;
+ struct navit *navit;
+ struct coord_geo geo;
+ struct coord last;
+ double config_speed;
+ double speed;
+ double direction;
+ struct callback *timer_callback;
+ struct event_timeout *timer;
+ char *timep;
+
+};
+
+static void
+vehicle_demo_destroy(struct vehicle_priv *priv)
+{
+ g_free(priv);
+}
+
+static int
+vehicle_demo_position_attr_get(struct vehicle_priv *priv,
+ enum attr_type type, struct attr *attr)
+{
+ switch (type) {
+ case attr_position_speed:
+ attr->u.numd = &priv->speed;
+ break;
+ case attr_position_direction:
+ attr->u.numd = &priv->direction;
+ break;
+ case attr_position_coord_geo:
+ attr->u.coord_geo = &priv->geo;
+ break;
+ case attr_position_time_iso8601:
+ g_free(priv->timep);
+ priv->timep=current_to_iso8601();
+ attr->u.str=priv->timep;
+ break;
+ default:
+ return 0;
+ }
+ attr->type = type;
+ return 1;
+}
+
+static int
+vehicle_demo_set_attr(struct vehicle_priv *priv, struct attr *attr,
+ struct attr **attrs)
+{
+ if (attr->type == attr_navit)
+ priv->navit = attr->u.navit;
+ return 1;
+}
+
+struct vehicle_methods vehicle_demo_methods = {
+ vehicle_demo_destroy,
+ vehicle_demo_position_attr_get,
+ vehicle_demo_set_attr,
+};
+
+static void
+vehicle_demo_timer(struct vehicle_priv *priv)
+{
+ struct coord c, c2, pos, ci;
+ int slen, len, dx, dy;
+ struct route *route=NULL;
+ struct map *route_map=NULL;
+ struct map_rect *mr=NULL;
+ struct item *item=NULL;
+
+ len = (priv->config_speed * priv->interval / 1000)/ 3.6;
+ dbg(1, "###### Entering simulation loop\n");
+ if (priv->navit)
+ route=navit_get_route(priv->navit);
+ if (route)
+ route_map=route_get_map(route);
+ if (route_map)
+ mr=map_rect_new(route_map, NULL);
+ if (mr)
+ item=map_rect_get_item(mr);
+ if (item && item->type == type_route_start)
+ item=map_rect_get_item(mr);
+ if (item && item_coord_get(item, &pos, 1)) {
+ priv->position_set=0;
+ dbg(1, "current pos=0x%x,0x%x\n", pos.x, pos.y);
+ dbg(1, "last pos=0x%x,0x%x\n", priv->last.x, priv->last.y);
+ if (priv->last.x == pos.x && priv->last.y == pos.y) {
+ dbg(1, "endless loop\n");
+ }
+ priv->last = pos;
+ while (item && priv->config_speed) {
+ if (!item_coord_get(item, &c, 1)) {
+ item=map_rect_get_item(mr);
+ continue;
+ }
+ dbg(1, "next pos=0x%x,0x%x\n", c.x, c.y);
+ slen = transform_distance(projection_mg, &pos, &c);
+ dbg(1, "len=%d slen=%d\n", len, slen);
+ if (slen < len) {
+ len -= slen;
+ pos = c;
+ } else {
+ if (item_coord_get(item, &c2, 1) || map_rect_get_item(mr)) {
+ dx = c.x - pos.x;
+ dy = c.y - pos.y;
+ ci.x = pos.x + dx * len / slen;
+ ci.y = pos.y + dy * len / slen;
+ priv->direction =
+ transform_get_angle_delta(&pos, &c, 0);
+ priv->speed=priv->config_speed;
+ } else {
+ ci.x = pos.x;
+ ci.y = pos.y;
+ priv->speed=0;
+ dbg(0,"destination reached\n");
+ }
+ dbg(1, "ci=0x%x,0x%x\n", ci.x, ci.y);
+ transform_to_geo(projection_mg, &ci,
+ &priv->geo);
+ callback_list_call_0(priv->cbl);
+ break;
+ }
+ }
+ } else {
+ if (priv->position_set)
+ callback_list_call_0(priv->cbl);
+ }
+ if (mr)
+ map_rect_destroy(mr);
+}
+
+
+
+static struct vehicle_priv *
+vehicle_demo_new(struct vehicle_methods
+ *meth, struct callback_list
+ *cbl, struct attr **attrs)
+{
+ struct vehicle_priv *ret;
+ struct attr *interval,*speed,*position_coord_geo;
+
+ dbg(1, "enter\n");
+ ret = g_new0(struct vehicle_priv, 1);
+ ret->cbl = cbl;
+ ret->interval=1000;
+ ret->config_speed=40;
+ if ((speed=attr_search(attrs, NULL, attr_speed))) {
+ ret->config_speed=speed->u.num;
+ }
+ if ((interval=attr_search(attrs, NULL, attr_interval)))
+ ret->interval=interval->u.num;
+ if ((position_coord_geo=attr_search(attrs, NULL, attr_position_coord_geo))) {
+ ret->geo=*(position_coord_geo->u.coord_geo);
+ ret->position_set=1;
+ dbg(0,"position_set %f %f\n", ret->geo.lat, ret->geo.lng);
+ }
+ *meth = vehicle_demo_methods;
+ ret->timer_callback=callback_new_1(callback_cast(vehicle_demo_timer), ret);
+ ret->timer=event_add_timeout(ret->interval, 1, ret->timer_callback);
+ return ret;
+}
+
+void
+plugin_init(void)
+{
+ dbg(1, "enter\n");
+ plugin_register_vehicle_type("demo", vehicle_demo_new);
+}
diff --git a/vehicle/file/Makefile.am b/vehicle/file/Makefile.am
new file mode 100644
index 00000000..a5518696
--- /dev/null
+++ b/vehicle/file/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit
+modulevehicle_LTLIBRARIES = libvehicle_file.la libvehicle_pipe.la
+libvehicle_file_la_CFLAGS=-DMODULE=vehicle_file
+libvehicle_file_la_SOURCES = vehicle_file.c
+libvehicle_file_la_LDFLAGS = -module -avoid-version
+libvehicle_pipe_la_CFLAGS=-DMODULE=vehicle_pipe
+libvehicle_pipe_la_SOURCES = vehicle_pipe.c
+libvehicle_pipe_la_LDFLAGS = -module -avoid-version
diff --git a/vehicle/file/vehicle_file.c b/vehicle/file/vehicle_file.c
new file mode 100644
index 00000000..88c5af2e
--- /dev/null
+++ b/vehicle/file/vehicle_file.c
@@ -0,0 +1,763 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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 <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <glib.h>
+#include <sys/stat.h>
+#ifdef _WIN32
+ #include <serial_io.h>
+#else
+#include <termios.h>
+#endif
+#include <math.h>
+#include "config.h"
+#include "debug.h"
+#include "callback.h"
+#include "plugin.h"
+#include "coord.h"
+#include "item.h"
+#include "event.h"
+#include "vehicle.h"
+
+static void vehicle_file_disable_watch(struct vehicle_priv *priv);
+static void vehicle_file_enable_watch(struct vehicle_priv *priv);
+static int vehicle_file_parse(struct vehicle_priv *priv, char *buffer);
+static int vehicle_file_open(struct vehicle_priv *priv);
+static void vehicle_file_close(struct vehicle_priv *priv);
+
+
+enum file_type {
+ file_type_pipe = 1, file_type_device, file_type_file
+};
+
+static int buffer_size = 1024;
+
+struct gps_sat {
+ int prn;
+ int elevation;
+ int azimuth;
+ int snr;
+};
+
+
+struct vehicle_priv {
+ char *source;
+ enum file_type file_type;
+ struct callback_list *cbl;
+ int fd;
+ FILE *file;
+ struct callback *cb,*cbt;
+ struct event_watch *watch;
+ char *buffer;
+ int buffer_pos;
+ char *nmea_data;
+ char *nmea_data_buf;
+
+ struct coord_geo geo;
+ double speed;
+ double direction;
+ double height;
+ double hdop;
+ double vdop;
+ char fixtime[20];
+ int fixyear;
+ int fixmonth;
+ int fixday;
+ int status;
+ int sats_used;
+ int sats_visible;
+ int sats_signal;
+ int time;
+ int on_eof;
+#ifdef _WIN32
+ int no_data_count;
+#endif
+ speed_t baudrate;
+ struct attr ** attrs;
+ char fixiso8601[128];
+ int checksum_ignore;
+ int magnetic_direction;
+ int current_count;
+ struct gps_sat current[24];
+ int next_count;
+ struct gps_sat next[24];
+ struct item sat_item;
+ int valid;
+};
+
+#ifdef _WIN32
+static int vehicle_win32_serial_track(struct vehicle_priv *priv)
+{
+
+ static char buffer[2048] = {0,};
+ static int current_index = 0;
+ const int chunk_size = 1024;
+ int rc = 0;
+
+ if ( priv->no_data_count > 5 )
+ {
+ vehicle_file_close( priv );
+ priv->no_data_count = 0;
+ }
+
+ if ( priv->fd <= 0 )
+ {
+ vehicle_file_open( priv );
+ }
+
+ if ( current_index >= ( sizeof( buffer ) - chunk_size ) )
+ {
+ // discard
+ current_index = 0;
+ memset( buffer, 0 , sizeof( buffer ) );
+ }
+
+ int dwBytes = serial_io_read( priv->fd, &buffer[ current_index ], chunk_size );
+ if ( dwBytes > 0 )
+ {
+ current_index += dwBytes;
+
+ char* return_pos = NULL;
+ while ( ( return_pos = strchr( buffer, '\n' ) ) != NULL )
+ {
+ char return_buffer[1024];
+ int bytes_to_copy = return_pos - buffer + 1;
+ memcpy( return_buffer, buffer, bytes_to_copy );
+ return_buffer[ bytes_to_copy + 1 ] = '\0';
+
+ // printf( "received %d : '%s' bytes to copy\n", bytes_to_copy, return_buffer );
+ rc += vehicle_file_parse( priv, return_buffer );
+
+ current_index -= bytes_to_copy;
+ memmove( buffer, &buffer[ bytes_to_copy ] , sizeof( buffer ) - bytes_to_copy );
+ }
+ if (rc) {
+ callback_list_call_0(priv->cbl);
+ if (rc > 1)
+ dbg(0, "Can not keep with gps data delay is %d seconds\n",
+ rc - 1);
+ }
+
+
+ }
+ else
+ {
+ priv->no_data_count++;
+ }
+ return 1;
+}
+#endif
+
+static int
+vehicle_file_open(struct vehicle_priv *priv)
+{
+#ifdef _WIN32
+ dbg(1, "enter vehicle_file_open, priv->source='%s'\n", priv->source);
+
+ if ( priv->source )
+ {
+ char* raw_setting_str = g_strdup( priv->source );
+
+ char* strport = strchr(raw_setting_str, ':' );
+ char* strsettings = strchr(raw_setting_str, ' ' );
+
+ if ( strport && strsettings )
+ {
+ strport++;
+ *strsettings = '\0';
+ strsettings++;
+
+ dbg(1, "calling serial_io_init('%s', '%s')\n", strport, strsettings );
+ priv->fd=serial_io_init( strport, strsettings );
+ }
+ g_free( raw_setting_str );
+ }
+#else
+ char *name;
+ struct stat st;
+ struct termios tio;
+
+ name = priv->source + 5;
+ if (!strncmp(priv->source, "file:", 5)) {
+ priv->fd = open(name, O_RDONLY | O_NDELAY);
+ if (priv->fd < 0)
+ return 0;
+ stat(name, &st);
+ if (S_ISREG(st.st_mode)) {
+ priv->file_type = file_type_file;
+ } else {
+ tcgetattr(priv->fd, &tio);
+ cfmakeraw(&tio);
+ cfsetispeed(&tio, priv->baudrate);
+ cfsetospeed(&tio, priv->baudrate);
+ tio.c_cc[VMIN] = 0;
+ tio.c_cc[VTIME] = 200;
+ tcsetattr(priv->fd, TCSANOW, &tio);
+ priv->file_type = file_type_device;
+ }
+ } else {
+ priv->file = popen(name, "r");
+ if (!priv->file)
+ return 0;
+ priv->fd = fileno(priv->file);
+ priv->file_type = file_type_pipe;
+ }
+#endif
+ return 1;
+}
+
+static void
+vehicle_file_close(struct vehicle_priv *priv)
+{
+#ifdef _WIN32
+ serial_io_shutdown( priv->fd );
+#else
+ vehicle_file_disable_watch(priv);
+ if (priv->file)
+ pclose(priv->file);
+ else if (priv->fd >= 0)
+ close(priv->fd);
+#endif
+ priv->file = NULL;
+ priv->fd = -1;
+}
+
+static int
+vehicle_file_enable_watch_timer(struct vehicle_priv *priv)
+{
+ dbg(1, "enter\n");
+ vehicle_file_enable_watch(priv);
+
+ return FALSE;
+}
+
+
+static int
+vehicle_file_parse(struct vehicle_priv *priv, char *buffer)
+{
+ char *nmea_data_buf, *p, *item[32];
+ double lat, lng;
+ int i, j, bcsum;
+ int len = strlen(buffer);
+ unsigned char csum = 0;
+ int valid=0;
+ int ret = 0;
+
+ dbg(1, "buffer='%s'\n", buffer);
+ for (;;) {
+ if (len < 4) {
+ dbg(0, "'%s' too short\n", buffer);
+ return ret;
+ }
+ if (buffer[len - 1] == '\r' || buffer[len - 1] == '\n')
+ buffer[--len] = '\0';
+ else
+ break;
+ }
+ if (buffer[0] != '$') {
+ dbg(0, "no leading $ in '%s'\n", buffer);
+ return ret;
+ }
+ if (buffer[len - 3] != '*') {
+ dbg(0, "no *XX in '%s'\n", buffer);
+ return ret;
+ }
+ for (i = 1; i < len - 3; i++) {
+ csum ^= (unsigned char) (buffer[i]);
+ }
+ if (!sscanf(buffer + len - 2, "%x", &bcsum) && priv->checksum_ignore != 2) {
+ dbg(0, "no checksum in '%s'\n", buffer);
+ return ret;
+ }
+ if (bcsum != csum && priv->checksum_ignore == 0) {
+ dbg(0, "wrong checksum in '%s'\n", buffer);
+ return ret;
+ }
+
+ if (!priv->nmea_data_buf || strlen(priv->nmea_data_buf) < 65536) {
+ nmea_data_buf=g_strconcat(priv->nmea_data_buf ? priv->nmea_data_buf : "", buffer, "\n", NULL);
+ g_free(priv->nmea_data_buf);
+ priv->nmea_data_buf=nmea_data_buf;
+ } else {
+ dbg(0, "nmea buffer overflow, discarding '%s'\n", buffer);
+ }
+ i = 0;
+ p = buffer;
+ while (i < 31) {
+ item[i++] = p;
+ while (*p && *p != ',')
+ p++;
+ if (!*p)
+ break;
+ *p++ = '\0';
+ }
+
+ if (!strncmp(buffer, "$GPGGA", 6)) {
+ /* 1 1111
+ 0 1 2 3 4 5 6 7 8 9 0 1234
+ $GPGGA,184424.505,4924.2811,N,01107.8846,E,1,05,2.5,408.6,M,,,,0000*0C
+ UTC of Fix[1],Latitude[2],N/S[3],Longitude[4],E/W[5],Quality(0=inv,1=gps,2=dgps)[6],Satelites used[7],
+ HDOP[8],Altitude[9],"M"[10],height of geoid[11], "M"[12], time since dgps update[13], dgps ref station [14]
+ */
+ if (*item[2] && *item[3] && *item[4] && *item[5]) {
+ lat = g_ascii_strtod(item[2], NULL);
+ priv->geo.lat = floor(lat / 100);
+ lat -= priv->geo.lat * 100;
+ priv->geo.lat += lat / 60;
+
+ if (!strcasecmp(item[3],"S"))
+ priv->geo.lat=-priv->geo.lat;
+
+ lng = g_ascii_strtod(item[4], NULL);
+ priv->geo.lng = floor(lng / 100);
+ lng -= priv->geo.lng * 100;
+ priv->geo.lng += lng / 60;
+
+ if (!strcasecmp(item[5],"W"))
+ priv->geo.lng=-priv->geo.lng;
+ priv->valid=attr_position_valid_valid;
+ } else
+ priv->valid=attr_position_valid_invalid;
+ if (*item[6])
+ sscanf(item[6], "%d", &priv->status);
+ if (*item[7])
+ sscanf(item[7], "%d", &priv->sats_used);
+ if (*item[8])
+ sscanf(item[8], "%lf", &priv->hdop);
+ if (*item[1])
+ strcpy(priv->fixtime, item[1]);
+ if (*item[9])
+ sscanf(item[9], "%lf", &priv->height);
+
+ g_free(priv->nmea_data);
+ priv->nmea_data=priv->nmea_data_buf;
+ priv->nmea_data_buf=NULL;
+#ifndef _WIN32
+ if (priv->file_type == file_type_file) {
+ if (priv->watch) {
+ vehicle_file_disable_watch(priv);
+ event_add_timeout(priv->time, 0, priv->cbt);
+ }
+ }
+#endif
+ }
+ if (!strncmp(buffer, "$GPVTG", 6)) {
+ /* 0 1 2 34 5 6 7 8
+ $GPVTG,143.58,T,,M,0.26,N,0.5,K*6A
+ Course Over Ground Degrees True[1],"T"[2],Course Over Ground Degrees Magnetic[3],"M"[4],
+ Speed in Knots[5],"N"[6],"Speed in KM/H"[7],"K"[8]
+ */
+ if (item[1] && item[7])
+ valid = 1;
+ if (i >= 10 && (*item[9] == 'A' || *item[9] == 'D'))
+ valid = 1;
+ if (valid) {
+ priv->direction = g_ascii_strtod( item[1], NULL );
+ priv->speed = g_ascii_strtod( item[7], NULL );
+ }
+ }
+ if (!strncmp(buffer, "$GPRMC", 6)) {
+ /* 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1
+ $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
+ Time[1],Active/Void[2],lat[3],N/S[4],long[5],W/E[6],speed in knots[7],track angle[8],date[9],
+ magnetic variation[10],magnetic variation direction[11]
+ */
+ if (*item[2] == 'A')
+ valid = 1;
+ if (i >= 13 && (*item[12] == 'A' || *item[12] == 'D'))
+ valid = 1;
+ if (valid) {
+ priv->direction = g_ascii_strtod( item[8], NULL );
+ priv->speed = g_ascii_strtod( item[7], NULL );
+ priv->speed *= 1.852;
+ sscanf(item[9], "%02d%02d%02d",
+ &priv->fixday,
+ &priv->fixmonth,
+ &priv->fixyear);
+ priv->fixyear += 2000;
+ }
+ ret = 1;
+ }
+ if (!strncmp(buffer, "$GPGSV", 6) && i >= 4) {
+ /*
+ 0 GSV Satellites in view
+ 1 2 Number of sentences for full data
+ 2 1 sentence 1 of 2
+ 3 08 Number of satellites in view
+
+ 4 01 Satellite PRN number
+ 5 40 Elevation, degrees
+ 6 083 Azimuth, degrees
+ 7 46 SNR - higher is better
+ for up to 4 satellites per sentence
+ *75 the checksum data, always begins with *
+ */
+ if (item[3]) {
+ sscanf(item[3], "%d", &priv->sats_visible);
+ }
+ j=4;
+ while (j+4 <= i && priv->current_count < 24) {
+ struct gps_sat *sat=&priv->next[priv->next_count++];
+ sat->prn=atoi(item[j]);
+ sat->elevation=atoi(item[j+1]);
+ sat->azimuth=atoi(item[j+2]);
+ sat->snr=atoi(item[j+3]);
+ j+=4;
+ }
+ if (!strcmp(item[1], item[2])) {
+ priv->sats_signal=0;
+ for (i = 0 ; i < priv->next_count ; i++) {
+ priv->current[i]=priv->next[i];
+ if (priv->current[i].snr)
+ priv->sats_signal++;
+ }
+ priv->current_count=priv->next_count;
+ priv->next_count=0;
+ }
+ }
+ if (!strncmp(buffer, "$GPZDA", 6)) {
+ /*
+ 0 1 2 3 4 5 6
+ $GPZDA,hhmmss.ss,dd,mm,yyyy,xx,yy*CC
+ hhmmss HrMinSec(UTC)
+ dd,mm,yyy Day,Month,Year
+ xx local zone hours -13..13
+ yy local zone minutes 0..59
+ */
+ if (item[1] && item[2] && item[3] && item[4]) {
+ // priv->fixtime = atof(item[1]);
+ strcpy(priv->fixtime, item[1]);
+ priv->fixday = atoi(item[2]);
+ priv->fixmonth = atoi(item[3]);
+ priv->fixyear = atoi(item[4]);
+ }
+ }
+ if (!strncmp(buffer, "$IISMD", 6)) {
+ /*
+ 0 1 2 3 4
+ $IISMD,dir,press,height,temp*CC"
+ dir Direction (0-359)
+ press Pressure (hpa, i.e. 1032)
+ height Barometric height above ground (meter)
+ temp Temperature (Degree Celsius)
+ */
+ if (item[1]) {
+ priv->magnetic_direction = g_ascii_strtod( item[1], NULL );
+ dbg(1,"magnetic %d\n", priv->magnetic_direction);
+ }
+ }
+ return ret;
+}
+
+#ifndef _WIN32
+static void
+vehicle_file_io(struct vehicle_priv *priv)
+{
+ int size, rc = 0;
+ char *str, *tok;
+
+ dbg(1, "enter\n");
+ size = read(priv->fd, priv->buffer + priv->buffer_pos, buffer_size - priv->buffer_pos - 1);
+ if (size <= 0) {
+ switch (priv->on_eof) {
+ case 0:
+ vehicle_file_close(priv);
+ vehicle_file_open(priv);
+ break;
+ case 1:
+ vehicle_file_disable_watch(priv);
+ break;
+ case 2:
+ exit(0);
+ break;
+ }
+ return;
+ }
+ priv->buffer_pos += size;
+ priv->buffer[priv->buffer_pos] = '\0';
+ dbg(1, "size=%d pos=%d buffer='%s'\n", size,
+ priv->buffer_pos, priv->buffer);
+ str = priv->buffer;
+ while ((tok = strchr(str, '\n'))) {
+ *tok++ = '\0';
+ dbg(1, "line='%s'\n", str);
+ rc +=vehicle_file_parse(priv, str);
+ str = tok;
+ }
+
+ if (str != priv->buffer) {
+ size = priv->buffer + priv->buffer_pos - str;
+ memmove(priv->buffer, str, size + 1);
+ priv->buffer_pos = size;
+ dbg(1, "now pos=%d buffer='%s'\n",
+ priv->buffer_pos, priv->buffer);
+ } else if (priv->buffer_pos == buffer_size - 1) {
+ dbg(0,
+ "Overflow. Most likely wrong baud rate or no nmea protocol\n");
+ priv->buffer_pos = 0;
+ }
+ if (rc)
+ callback_list_call_0(priv->cbl);
+}
+#endif
+
+static void
+vehicle_file_enable_watch(struct vehicle_priv *priv)
+{
+#ifdef _WIN32
+ g_timeout_add(500, vehicle_win32_serial_track, priv);
+#else
+ if (! priv->watch)
+ priv->watch = event_add_watch((void *)priv->fd, event_watch_cond_read, priv->cb);
+#endif
+}
+
+static void
+vehicle_file_disable_watch(struct vehicle_priv *priv)
+{
+#ifndef _WIN32
+ if (priv->watch)
+ event_remove_watch(priv->watch);
+ priv->watch = NULL;
+#endif
+}
+
+
+static void
+vehicle_file_destroy(struct vehicle_priv *priv)
+{
+ vehicle_file_close(priv);
+ callback_destroy(priv->cb);
+ callback_destroy(priv->cbt);
+ if (priv->source)
+ g_free(priv->source);
+ if (priv->buffer)
+ g_free(priv->buffer);
+ g_free(priv);
+}
+
+static int
+vehicle_file_position_attr_get(struct vehicle_priv *priv,
+ enum attr_type type, struct attr *attr)
+{
+ switch (type) {
+ case attr_position_fix_type:
+ attr->u.num = priv->status;
+ break;
+ case attr_position_height:
+ attr->u.numd = &priv->height;
+ break;
+ case attr_position_speed:
+ attr->u.numd = &priv->speed;
+ break;
+ case attr_position_direction:
+ attr->u.numd = &priv->direction;
+ break;
+ case attr_position_magnetic_direction:
+ attr->u.num = priv->magnetic_direction;
+ break;
+ case attr_position_hdop:
+ attr->u.numd = &priv->hdop;
+ break;
+ case attr_position_qual:
+ attr->u.num = priv->sats_visible;
+ break;
+ case attr_position_sats_signal:
+ attr->u.num = priv->sats_signal;
+ break;
+ case attr_position_sats_used:
+ attr->u.num = priv->sats_used;
+ break;
+ case attr_position_coord_geo:
+ attr->u.coord_geo = &priv->geo;
+ break;
+ case attr_position_nmea:
+ attr->u.str=priv->nmea_data;
+ if (! attr->u.str)
+ return 0;
+ break;
+ case attr_position_time_iso8601:
+ if (!priv->fixyear || !priv->fixtime[0])
+ return 0;
+ sprintf(priv->fixiso8601, "%04d-%02d-%02dT%.2s:%.2s:%sZ",
+ priv->fixyear, priv->fixmonth, priv->fixday,
+ priv->fixtime, (priv->fixtime+2), (priv->fixtime+4));
+ attr->u.str=priv->fixiso8601;
+ break;
+ case attr_position_sat_item:
+ dbg(0,"at here\n");
+ priv->sat_item.id_lo++;
+ if (priv->sat_item.id_lo > priv->current_count) {
+ priv->sat_item.id_lo=0;
+ return 0;
+ }
+ attr->u.item=&priv->sat_item;
+ break;
+ case attr_position_valid:
+ attr->u.num=priv->valid;
+ break;
+ default:
+ return 0;
+ }
+ if (type != attr_position_sat_item)
+ priv->sat_item.id_lo=0;
+ attr->type = type;
+ return 1;
+}
+
+static int
+vehicle_file_sat_attr_get(void *priv_data, enum attr_type type, struct attr *attr)
+{
+ struct vehicle_priv *priv=priv_data;
+ if (priv->sat_item.id_lo < 1)
+ return 0;
+ if (priv->sat_item.id_lo > priv->current_count)
+ return 0;
+ struct gps_sat *sat=&priv->current[priv->sat_item.id_lo-1];
+ switch (type) {
+ case attr_sat_prn:
+ attr->u.num=sat->prn;
+ break;
+ case attr_sat_elevation:
+ attr->u.num=sat->elevation;
+ break;
+ case attr_sat_azimuth:
+ attr->u.num=sat->azimuth;
+ break;
+ case attr_sat_snr:
+ attr->u.num=sat->snr;
+ break;
+ default:
+ return 0;
+ }
+ attr->type = type;
+ return 1;
+}
+
+static struct item_methods vehicle_file_sat_methods = {
+ NULL,
+ NULL,
+ NULL,
+ vehicle_file_sat_attr_get,
+};
+
+static struct vehicle_methods vehicle_file_methods = {
+ vehicle_file_destroy,
+ vehicle_file_position_attr_get,
+};
+
+static struct vehicle_priv *
+vehicle_file_new_file(struct vehicle_methods
+ *meth, struct callback_list
+ *cbl, struct attr **attrs)
+{
+ struct vehicle_priv *ret;
+ struct attr *source;
+ struct attr *time;
+ struct attr *on_eof;
+ struct attr *baudrate;
+ struct attr *checksum_ignore;
+
+ dbg(1, "enter\n");
+ source = attr_search(attrs, NULL, attr_source);
+ if(source == NULL){
+ dbg(0,"Missing source attribute");
+ return NULL;
+ }
+ ret = g_new0(struct vehicle_priv, 1);
+ ret->fd = -1;
+ ret->cbl = cbl;
+ ret->source = g_strdup(source->u.str);
+ ret->buffer = g_malloc(buffer_size);
+ ret->time=1000;
+ ret->baudrate=B4800;
+ time = attr_search(attrs, NULL, attr_time);
+ if (time)
+ ret->time=time->u.num;
+ baudrate = attr_search(attrs, NULL, attr_baudrate);
+ if (baudrate) {
+ switch (baudrate->u.num) {
+ case 4800:
+ ret->baudrate=B4800;
+ break;
+ case 9600:
+ ret->baudrate=B9600;
+ break;
+ case 19200:
+ ret->baudrate=B19200;
+ break;
+#ifdef B38400
+ case 38400:
+ ret->baudrate=B38400;
+ break;
+#endif
+#ifdef B57600
+ case 57600:
+ ret->baudrate=B57600;
+ break;
+#endif
+#ifdef B115200
+ case 115200:
+ ret->baudrate=B115200;
+ break;
+#endif
+ }
+ }
+ checksum_ignore = attr_search(attrs, NULL, attr_checksum_ignore);
+ if (checksum_ignore)
+ ret->checksum_ignore=checksum_ignore->u.num;
+ ret->attrs = attrs;
+ on_eof = attr_search(attrs, NULL, attr_on_eof);
+ if (on_eof && !strcasecmp(on_eof->u.str, "stop"))
+ ret->on_eof=1;
+ if (on_eof && !strcasecmp(on_eof->u.str, "exit"))
+ ret->on_eof=2;
+ dbg(0,"on_eof=%d\n", ret->on_eof);
+ *meth = vehicle_file_methods;
+ ret->cb=callback_new_1(callback_cast(vehicle_file_io), ret);
+ ret->cbt=callback_new_1(callback_cast(vehicle_file_enable_watch_timer), ret);
+ ret->sat_item.type=type_position_sat;
+ ret->sat_item.id_hi=ret->sat_item.id_lo=0;
+ ret->sat_item.priv_data=ret;
+ ret->sat_item.meth=&vehicle_file_sat_methods;
+ if (vehicle_file_open(ret)) {
+ vehicle_file_enable_watch(ret);
+ return ret;
+ }
+
+#ifdef _WIN32
+ ret->no_data_count = 0;
+#endif
+ dbg(0, "Failed to open '%s'\n", ret->source);
+ vehicle_file_destroy(ret);
+ return NULL;
+}
+
+void
+plugin_init(void)
+{
+ dbg(1, "enter\n");
+ plugin_register_vehicle_type("file", vehicle_file_new_file);
+ plugin_register_vehicle_type("pipe", vehicle_file_new_file);
+}
diff --git a/vehicle/file/vehicle_pipe.c b/vehicle/file/vehicle_pipe.c
new file mode 100644
index 00000000..0750edef
--- /dev/null
+++ b/vehicle/file/vehicle_pipe.c
@@ -0,0 +1,27 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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 "config.h"
+#include "plugin.h"
+
+void
+plugin_init(void)
+{
+ plugin_get_vehicle_type("file");
+}
diff --git a/vehicle/gpsd/Makefile.am b/vehicle/gpsd/Makefile.am
new file mode 100644
index 00000000..1c47ccc5
--- /dev/null
+++ b/vehicle/gpsd/Makefile.am
@@ -0,0 +1,6 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ @GPSBT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=vehicle_gpsd
+modulevehicle_LTLIBRARIES = libvehicle_gpsd.la
+libvehicle_gpsd_la_SOURCES = vehicle_gpsd.c
+libvehicle_gpsd_la_LIBADD = @GPSD_LIBS@ @GPSBT_LIBS@
+libvehicle_gpsd_la_LDFLAGS = -module -avoid-version
diff --git a/vehicle/gpsd/vehicle_gpsd.c b/vehicle/gpsd/vehicle_gpsd.c
new file mode 100644
index 00000000..88a50a41
--- /dev/null
+++ b/vehicle/gpsd/vehicle_gpsd.c
@@ -0,0 +1,387 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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 <config.h>
+#include <gps.h>
+#include <string.h>
+#include <glib.h>
+#include <math.h>
+#ifdef HAVE_GPSBT
+#include <gpsbt.h>
+#include <errno.h>
+#endif
+#include "debug.h"
+#include "callback.h"
+#include "plugin.h"
+#include "coord.h"
+#include "item.h"
+#include "vehicle.h"
+#include "event.h"
+
+static struct vehicle_priv {
+ char *source;
+ char *gpsd_query;
+ struct callback_list *cbl;
+ struct callback *cb;
+ struct event_watch *evwatch;
+ guint retry_interval;
+ struct gps_data_t *gps;
+ struct coord_geo geo;
+ double speed;
+ double direction;
+ double height;
+ double hdop;
+ int status;
+ int fix_type;
+ time_t fix_time;
+ int sats;
+ int sats_signal;
+ int sats_used;
+ char *nmea_data;
+ char *nmea_data_buf;
+ guint retry_timer;
+ struct attr ** attrs;
+ char fixiso8601[128];
+#ifdef HAVE_GPSBT
+ gpsbt_t context;
+#endif
+} *vehicle_last;
+
+#define DEFAULT_RETRY_INTERVAL 10 // seconds
+#define MIN_RETRY_INTERVAL 1 // seconds
+
+static void vehicle_gpsd_io(struct vehicle_priv *priv);
+
+static void
+vehicle_gpsd_callback(struct gps_data_t *data, char *buf, size_t len,
+ int level)
+{
+ char *pos,*nmea_data_buf;
+ int i=0,sats_signal=0;
+
+ struct vehicle_priv *priv = vehicle_last;
+ if( len > 0 && buf[0] == '$' ) {
+ char buffer[len+2];
+ buffer[len+1]='\0';
+ memcpy(buffer, buf, len);
+ pos=strchr(buffer,'\n');
+ if (pos) {
+ *++pos='\0';
+ if (!priv->nmea_data_buf || strlen(priv->nmea_data_buf) < 65536) {
+ nmea_data_buf=g_strconcat(priv->nmea_data_buf ? priv->nmea_data_buf : "", buffer, NULL);
+ g_free(priv->nmea_data_buf);
+ priv->nmea_data_buf=nmea_data_buf;
+ } else {
+ dbg(0, "nmea buffer overflow, discarding '%s'\n", buffer);
+ }
+ }
+ }
+ dbg(1,"data->set=0x%x\n", data->set);
+ if (data->set & SPEED_SET) {
+ priv->speed = data->fix.speed * 3.6;
+ if(!isnan(data->fix.speed))
+ callback_list_call_attr_0(priv->cbl, attr_position_speed);
+ data->set &= ~SPEED_SET;
+ }
+ if (data->set & TRACK_SET) {
+ priv->direction = data->fix.track;
+ data->set &= ~TRACK_SET;
+ }
+ if (data->set & ALTITUDE_SET) {
+ priv->height = data->fix.altitude;
+ data->set &= ~ALTITUDE_SET;
+ }
+ if (data->set & SATELLITE_SET) {
+ if(data->satellites > 0) {
+ sats_signal=0;
+ for( i=0;i<data->satellites;i++) {
+ if (data->ss[i] > 0)
+ sats_signal++;
+ }
+ }
+ if (priv->sats_used != data->satellites_used || priv->sats != data->satellites || priv->sats_signal != sats_signal ) {
+ priv->sats_used = data->satellites_used;
+ priv->sats = data->satellites;
+ priv->sats_signal = sats_signal;
+ callback_list_call_attr_0(priv->cbl, attr_position_sats);
+ }
+ data->set &= ~SATELLITE_SET;
+ }
+ if (data->set & STATUS_SET) {
+ priv->status = data->status;
+ data->set &= ~STATUS_SET;
+ }
+ if (data->set & MODE_SET) {
+ priv->fix_type = data->fix.mode - 1;
+ data->set &= ~MODE_SET;
+ }
+ if (data->set & TIME_SET) {
+ priv->fix_time = data->fix.time;
+ data->set &= ~TIME_SET;
+ }
+ if (data->set & PDOP_SET) {
+ dbg(1, "pdop : %g\n", data->pdop);
+ priv->hdop = data->hdop;
+ data->set &= ~PDOP_SET;
+ }
+ if (data->set & LATLON_SET) {
+ priv->geo.lat = data->fix.latitude;
+ priv->geo.lng = data->fix.longitude;
+ dbg(1,"lat=%f lng=%f\n", priv->geo.lat, priv->geo.lng);
+ g_free(priv->nmea_data);
+ priv->nmea_data=priv->nmea_data_buf;
+ priv->nmea_data_buf=NULL;
+ data->set &= ~LATLON_SET;
+ }
+ // If data->fix.speed is NAN, then the drawing gets jumpy.
+ if (! isnan(data->fix.speed) && priv->fix_type > 0) {
+ callback_list_call_0(priv->cbl);
+ }
+ dbg(2,"speed ok\n");
+}
+
+/**
+ * Attempt to open the gps device.
+ * Return FALSE if retry not required
+ * Return TRUE to try again
+ */
+static gboolean
+vehicle_gpsd_try_open(gpointer *data)
+{
+ struct vehicle_priv *priv = (struct vehicle_priv *)data;
+ char *source = g_strdup(priv->source);
+ char *colon = index(source + 7, ':');
+ if (colon) {
+ *colon = '\0';
+ priv->gps = gps_open(source + 7, colon + 1);
+ } else
+ priv->gps = gps_open(source + 7, NULL);
+ g_free(source);
+
+ if (!priv->gps){
+ dbg(0,"gps_open failed for '%s'. Retrying in %d seconds. Have you started gpsd?\n", priv->source, priv->retry_interval);
+ return TRUE;
+ }
+ gps_query(priv->gps, priv->gpsd_query);
+ gps_set_raw_hook(priv->gps, vehicle_gpsd_callback);
+ priv->cb = callback_new_1(callback_cast(vehicle_gpsd_io), priv);
+ priv->evwatch = event_add_watch((void *)priv->gps->gps_fd, event_watch_cond_read, priv->cb);
+ if (!priv->gps->gps_fd) {
+ dbg(0,"Warning: gps_fd is 0, most likely you have used a gps.h incompatible to libgps");
+ }
+ dbg(0,"Connected to gpsd fd=%d evwatch=%p\n", priv->gps->gps_fd, priv->evwatch);
+ return FALSE;
+}
+
+/**
+ * Open a connection to gpsd. Will re-try the connection if it fails
+ */
+static void
+vehicle_gpsd_open(struct vehicle_priv *priv)
+{
+#ifdef HAVE_GPSBT
+ char errstr[256] = "";
+ /* We need to start gpsd (via gpsbt) first. */
+ errno = 0;
+ memset(&priv->context, 0, sizeof(gpsbt_t));
+ if(gpsbt_start(NULL, 0, 0, 0, errstr, sizeof(errstr),
+ 0, &priv->context) < 0) {
+ dbg(0,"Error connecting to GPS with gpsbt: (%d) %s (%s)\n",
+ errno, strerror(errno), errstr);
+ }
+ sleep(1); /* give gpsd time to start */
+ dbg(1,"gpsbt_start: completed\n");
+#endif
+ priv->retry_timer=0;
+ if (vehicle_gpsd_try_open((gpointer *)priv)) {
+ priv->retry_timer = g_timeout_add(priv->retry_interval*1000, (GSourceFunc)vehicle_gpsd_try_open, (gpointer *)priv);
+ }
+}
+
+static void
+vehicle_gpsd_close(struct vehicle_priv *priv)
+{
+#ifdef HAVE_GPSBT
+ int err;
+#endif
+
+ if (priv->retry_timer) {
+ g_source_remove(priv->retry_timer);
+ priv->retry_timer=0;
+ }
+ if (priv->evwatch) {
+ event_remove_watch(priv->evwatch);
+ priv->evwatch = NULL;
+ }
+ if (priv->cb) {
+ callback_destroy(priv->cb);
+ priv->cb = NULL;
+ }
+ if (priv->gps) {
+ gps_close(priv->gps);
+ priv->gps = NULL;
+ }
+#ifdef HAVE_GPSBT
+ err = gpsbt_stop(&priv->context);
+ if (err < 0) {
+ dbg(0,"Error %d while gpsbt_stop", err);
+ }
+ dbg(1,"gpsbt_stop: completed, (%d)",err);
+#endif
+}
+
+static void
+vehicle_gpsd_io(struct vehicle_priv *priv)
+{
+ dbg(1, "enter\n");
+ if (priv->gps) {
+ vehicle_last = priv;
+ if (gps_poll(priv->gps)) {
+ g_warning("gps_poll failed\n");
+ vehicle_gpsd_close(priv);
+ vehicle_gpsd_open(priv);
+ }
+ }
+}
+
+static void
+vehicle_gpsd_destroy(struct vehicle_priv *priv)
+{
+ vehicle_gpsd_close(priv);
+ if (priv->source)
+ g_free(priv->source);
+ if (priv->gpsd_query)
+ g_free(priv->gpsd_query);
+ g_free(priv);
+}
+
+static int
+vehicle_gpsd_position_attr_get(struct vehicle_priv *priv,
+ enum attr_type type, struct attr *attr)
+{
+ struct attr * active=NULL;
+ switch (type) {
+ case attr_position_fix_type:
+ attr->u.num = priv->fix_type;
+ break;
+ case attr_position_height:
+ attr->u.numd = &priv->height;
+ break;
+ case attr_position_speed:
+ attr->u.numd = &priv->speed;
+ break;
+ case attr_position_direction:
+ attr->u.numd = &priv->direction;
+ break;
+ case attr_position_hdop:
+ attr->u.numd = &priv->hdop;
+ break;
+ case attr_position_qual:
+ attr->u.num = priv->sats;
+ break;
+ case attr_position_sats_signal:
+ attr->u.num = priv->sats_signal;
+ break;
+ case attr_position_sats_used:
+ attr->u.num = priv->sats_used;
+ break;
+ case attr_position_coord_geo:
+ attr->u.coord_geo = &priv->geo;
+ break;
+ case attr_position_nmea:
+ attr->u.str=priv->nmea_data;
+ if (! attr->u.str)
+ return 0;
+ break;
+ case attr_position_time_iso8601:
+ {
+ struct tm tm;
+ if (!priv->fix_time)
+ return 0;
+ if (gmtime_r(&priv->fix_time, &tm)) {
+ strftime(priv->fixiso8601, sizeof(priv->fixiso8601),
+ "%Y-%m-%dT%TZ", &tm);
+ attr->u.str=priv->fixiso8601;
+ } else
+ return 0;
+ }
+ break;
+ case attr_active:
+ active = attr_search(priv->attrs,NULL,attr_active);
+ if(active != NULL) {
+ attr->u.num=active->u.num;
+ return 1;
+ } else
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ attr->type = type;
+ return 1;
+}
+
+struct vehicle_methods vehicle_gpsd_methods = {
+ vehicle_gpsd_destroy,
+ vehicle_gpsd_position_attr_get,
+};
+
+static struct vehicle_priv *
+vehicle_gpsd_new_gpsd(struct vehicle_methods
+ *meth, struct callback_list
+ *cbl, struct attr **attrs)
+{
+ struct vehicle_priv *ret;
+ struct attr *source, *query, *retry_int;
+
+ dbg(1, "enter\n");
+ source = attr_search(attrs, NULL, attr_source);
+ ret = g_new0(struct vehicle_priv, 1);
+ ret->source = g_strdup(source->u.str);
+ query = attr_search(attrs, NULL, attr_gpsd_query);
+ if (query) {
+ ret->gpsd_query = g_strconcat(query->u.str, "\n", NULL);
+ } else {
+ ret->gpsd_query = g_strdup("w+x\n");
+ }
+ dbg(1,"Format string for gpsd_query: %s\n",ret->gpsd_query);
+ retry_int = attr_search(attrs, NULL, attr_retry_interval);
+ if (retry_int) {
+ ret->retry_interval = retry_int->u.num;
+ if (ret->retry_interval < MIN_RETRY_INTERVAL) {
+ dbg(0, "Retry interval %d too small, setting to %d\n", ret->retry_interval, MIN_RETRY_INTERVAL);
+ ret->retry_interval = MIN_RETRY_INTERVAL;
+ }
+ } else {
+ dbg(1, "Retry interval not defined, setting to %d\n", DEFAULT_RETRY_INTERVAL);
+ ret->retry_interval = DEFAULT_RETRY_INTERVAL;
+ }
+ ret->cbl = cbl;
+ *meth = vehicle_gpsd_methods;
+ ret->attrs = attrs;
+ vehicle_gpsd_open(ret);
+ return ret;
+}
+
+void
+plugin_init(void)
+{
+ dbg(1, "enter\n");
+ plugin_register_vehicle_type("gpsd", vehicle_gpsd_new_gpsd);
+}
diff --git a/vehicle/gypsy/Makefile.am b/vehicle/gypsy/Makefile.am
new file mode 100644
index 00000000..ed6aba4a
--- /dev/null
+++ b/vehicle/gypsy/Makefile.am
@@ -0,0 +1,6 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=vehicle_gypsy
+modulevehicle_LTLIBRARIES = libvehicle_gypsy.la
+libvehicle_gypsy_la_SOURCES = vehicle_gypsy.c
+libvehicle_gypsy_la_LIBADD = @GYPSY_LIBS@
+libvehicle_gypsy_la_LDFLAGS = -module -avoid-version
diff --git a/vehicle/gypsy/vehicle_gypsy.c b/vehicle/gypsy/vehicle_gypsy.c
new file mode 100644
index 00000000..a1967c69
--- /dev/null
+++ b/vehicle/gypsy/vehicle_gypsy.c
@@ -0,0 +1,465 @@
+/** @file vehicle_gypsy.c
+ * @brief gypsy uses dbus signals
+ *
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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.
+ *
+ * @Author Tim Niemeyer <reddog@mastersword.de>
+ * @date 2008-2009
+ */
+
+#include <config.h>
+#include <gypsy/gypsy-device.h>
+#include <gypsy/gypsy-control.h>
+#include <gypsy/gypsy-course.h>
+#include <gypsy/gypsy-position.h>
+#include <gypsy/gypsy-satellite.h>
+#include <string.h>
+#include <glib.h>
+#include <math.h>
+#include "debug.h"
+#include "callback.h"
+#include "plugin.h"
+#include "coord.h"
+#include "item.h"
+#include "vehicle.h"
+
+static struct vehicle_priv {
+ char *source;
+ GypsyControl *control;
+ GypsyPosition *position;
+ GypsyDevice *device;
+ GypsyCourse *course;
+ GypsySatellite *satellite;
+ char *path;
+ struct callback_list *cbl;
+ guint retry_interval;
+ struct coord_geo geo;
+ double speed;
+ double direction;
+ double height;
+ int fix_type;
+ time_t fix_time;
+ char fixiso8601[128];
+ int sats;
+ int sats_used;
+ guint retry_timer;
+ struct attr ** attrs;
+ int have_cords;
+} *vehicle_last;
+
+#define DEFAULT_RETRY_INTERVAL 10 // seconds
+#define MIN_RETRY_INTERVAL 1 // seconds
+
+/**
+ * @brief When the fixstatus has changed, this function get called
+ *
+ * fixstatus can be one of this:
+ * GYPSY_DEVICE_FIX_STATUS_INVALID = 0
+ * GYPSY_DEVICE_FIX_STATUS_NONE = 1
+ * GYPSY_DEVICE_FIX_STATUS_2D = 2
+ * GYPSY_DEVICE_FIX_STATUS_3D = 3
+ *
+ * Anytime this functions get called, we have to call the global
+ * callback.
+ *
+ * @param device The GypsyDevice
+ * @param fixstatus The fisstatus 0, 1, 2 or 3
+ * @param userdata
+ * @returns nothing
+ */
+static void
+vehicle_gypsy_fixstatus_changed(GypsyDevice *device,
+ gint fixstatus,
+ gpointer userdata)
+{
+ struct vehicle_priv *priv = vehicle_last;
+
+ if (fixstatus==GYPSY_DEVICE_FIX_STATUS_3D)
+ priv->fix_type = 3;
+ else if (fixstatus==GYPSY_DEVICE_FIX_STATUS_2D)
+ priv->fix_type = 1;
+ else
+ priv->fix_type = 0;
+
+ callback_list_call_0(priv->cbl);
+}
+
+/**
+ * @brief When the position has changed, this function get called
+ *
+ * The fields_set can hold:
+ * GYPSY_POSITION_FIELDS_NONE = 1 << 0,
+ * GYPSY_POSITION_FIELDS_LATITUDE = 1 << 1,
+ * GYPSY_POSITION_FIELDS_LONGITUDE = 1 << 2,
+ * GYPSY_POSITION_FIELDS_ALTITUDE = 1 << 3
+ *
+ * If we get any new information, we have to call the global
+ * callback.
+ *
+ * @param position The GypsyPosition
+ * @param fields_set Bitmask indicating what field was set
+ * @param timestamp the time since Unix Epoch
+ * @param latitude
+ * @param longitude
+ * @param altitude
+ * @param userdata
+ * @returns nothing
+ */
+static void
+vehicle_gypsy_position_changed(GypsyPosition *position,
+ GypsyPositionFields fields_set, int timestamp,
+ double latitude, double longitude, double altitude,
+ gpointer userdata)
+{
+ struct vehicle_priv *priv = vehicle_last;
+ int cb = FALSE;
+
+ if (timestamp > 0)
+ priv->fix_time = timestamp;
+
+ if (fields_set & GYPSY_POSITION_FIELDS_LATITUDE)
+ {
+ cb = TRUE;
+ priv->geo.lat = latitude;
+ }
+ if (fields_set & GYPSY_POSITION_FIELDS_LONGITUDE)
+ {
+ cb = TRUE;
+ priv->geo.lng = longitude;
+ }
+ if (fields_set & GYPSY_POSITION_FIELDS_ALTITUDE)
+ {
+ cb = TRUE;
+ priv->height = altitude;
+ }
+
+ if (cb)
+ {
+ priv->have_cords = 1;
+ callback_list_call_0(priv->cbl);
+ }
+}
+
+/**
+ * @brief Everytime any Sat-Details are changed, this function get called
+ *
+ * Going through all Sats, counting those wich are in use.
+ *
+ * Anytime this functions get called, we have to call the global
+ * callback.
+ *
+ * @param satellite The GypsySatellite
+ * @param satellites An GPtrArray wich hold information of all sats
+ * @param userdata
+ * @returns nothing
+ */
+static void
+vehicle_gypsy_satellite_changed(GypsySatellite *satellite,
+ GPtrArray *satellites,
+ gpointer userdata)
+{
+ struct vehicle_priv *priv = vehicle_last;
+
+ int i, sats, used=0;
+
+ sats = satellites->len;
+ for (i = 0; i < sats; i++) {
+ GypsySatelliteDetails *details = satellites->pdata[i];
+ if (details->in_use)
+ used++;
+ }
+
+ priv->sats_used = used;
+ priv->sats = sats;
+
+ callback_list_call_0(priv->cbl);
+}
+
+/**
+ * @brief When the course or speed has changed, this function get called
+ *
+ * Only speed and direction are used!
+ *
+ * If we get any new information, we have to call the global
+ * callback.
+ *
+ * @param course The GypsyCourse
+ * @param fields Bitmask indicating what field was set
+ * @param timestamp the time since Unix Epoch
+ * @param speed
+ * @param direction
+ * @param climb
+ * @param userdata
+ * @returns nothing
+ */
+static void
+vehicle_gypsy_course_changed (GypsyCourse *course,
+ GypsyCourseFields fields,
+ int timestamp,
+ double speed,
+ double direction,
+ double climb,
+ gpointer userdata)
+{
+ struct vehicle_priv *priv = vehicle_last;
+ int cb = FALSE;
+
+ if (fields & GYPSY_COURSE_FIELDS_SPEED)
+ {
+ priv->speed = speed;
+ cb = TRUE;
+ }
+ if (fields & GYPSY_COURSE_FIELDS_DIRECTION)
+ {
+ priv->direction = direction;
+ cb = TRUE;
+ }
+
+ if (cb)
+ callback_list_call_0(priv->cbl);
+}
+
+/**
+ * @brief Attempt to open the gypsy device.
+ *
+ * Tells gypsy wich functions to call when anything occours.
+ *
+ * @param data
+ * @returns TRUE to try again; FALSE if retry not required
+ */
+static gboolean
+vehicle_gypsy_try_open(gpointer *data)
+{
+ struct vehicle_priv *priv = (struct vehicle_priv *)data;
+ char *source = g_strdup(priv->source);
+
+ GError *error = NULL;
+
+ g_type_init();
+ priv->control = gypsy_control_get_default();
+ priv->path = gypsy_control_create(priv->control, source+8, &error);
+ if (priv->path == NULL) {
+ g_warning ("Error creating gypsy conrtol path for %s: %s", source+8, error->message);
+ return TRUE;
+ }
+
+ priv->position = gypsy_position_new(priv->path);
+ g_signal_connect(priv->position, "position-changed", G_CALLBACK (vehicle_gypsy_position_changed), NULL);
+
+ priv->satellite = gypsy_satellite_new(priv->path);
+ g_signal_connect(priv->satellite, "satellites-changed", G_CALLBACK (vehicle_gypsy_satellite_changed), NULL);
+
+ priv->course = gypsy_course_new(priv->path);
+ g_signal_connect(priv->course, "course-changed", G_CALLBACK (vehicle_gypsy_course_changed), NULL);
+
+ priv->device = gypsy_device_new(priv->path);
+ g_signal_connect(priv->device, "fix-status-changed", G_CALLBACK (vehicle_gypsy_fixstatus_changed), NULL);
+
+ gypsy_device_start(priv->device, &error);
+ if (error != NULL) {
+ g_warning ("Error starting gypsy for %s: %s", source+8, error->message);
+ return TRUE;
+ }
+
+ vehicle_last = priv;
+ dbg(0,"gypsy connected to %d\n", source+8);
+ g_free(source);
+ return FALSE;
+}
+
+/**
+ * @brief Open a connection to gypsy. Will re-try the connection if it fails
+ *
+ * @param priv
+ * @returns nothing
+ */
+static void
+vehicle_gypsy_open(struct vehicle_priv *priv)
+{
+ priv->retry_timer=0;
+ if (vehicle_gypsy_try_open((gpointer *)priv)) {
+ priv->retry_timer = g_timeout_add(priv->retry_interval*1000, (GSourceFunc)vehicle_gypsy_try_open, (gpointer *)priv);
+ }
+}
+
+/**
+ * @brief Stop retry timer; Free alloced memory
+ *
+ * @param priv
+ * @returns nothing
+ */
+static void
+vehicle_gypsy_close(struct vehicle_priv *priv)
+{
+ if (priv->retry_timer) {
+ g_source_remove(priv->retry_timer);
+ priv->retry_timer=0;
+ }
+ if (priv->path)
+ g_free(priv->path);
+
+ if (priv->position)
+ g_free(priv->position);
+
+ if (priv->satellite)
+ g_free(priv->satellite);
+
+ if (priv->course)
+ g_free(priv->course);
+
+ if (priv->device)
+ g_free(priv->device);
+
+ if (priv->control)
+ g_object_unref(G_OBJECT (priv->control));
+}
+
+/**
+ * @brief Free the gypsy_vehicle
+ *
+ * @param priv
+ * @returns nothing
+ */
+static void
+vehicle_gypsy_destroy(struct vehicle_priv *priv)
+{
+ vehicle_gypsy_close(priv);
+ if (priv->source)
+ g_free(priv->source);
+ g_free(priv);
+}
+
+/**
+ * @brief Provide the outside with information
+ *
+ * @param priv
+ * @param type TODO: What can this be?
+ * @param attr
+ * @returns true/false
+ */
+static int
+vehicle_gypsy_position_attr_get(struct vehicle_priv *priv,
+ enum attr_type type, struct attr *attr)
+{
+ struct attr * active=NULL;
+ switch (type) {
+ case attr_position_fix_type:
+ attr->u.num = priv->fix_type;
+ break;
+ case attr_position_height:
+ attr->u.numd = &priv->height;
+ break;
+ case attr_position_speed:
+ attr->u.numd = &priv->speed;
+ break;
+ case attr_position_direction:
+ attr->u.numd = &priv->direction;
+ break;
+ case attr_position_qual:
+ attr->u.num = priv->sats;
+ break;
+ case attr_position_sats_used:
+ attr->u.num = priv->sats_used;
+ break;
+ case attr_position_coord_geo:
+ attr->u.coord_geo = &priv->geo;
+ if (!priv->have_cords)
+ return 0;
+ break;
+ case attr_position_time_iso8601:
+ {
+ struct tm tm;
+ if (!priv->fix_time)
+ return 0;
+ if (gmtime_r(&priv->fix_time, &tm)) {
+ strftime(priv->fixiso8601, sizeof(priv->fixiso8601),
+ "%Y-%m-%dT%TZ", &tm);
+ attr->u.str=priv->fixiso8601;
+ } else
+ return 0;
+ }
+ case attr_active:
+ active = attr_search(priv->attrs,NULL,attr_active);
+ if(active != NULL && active->u.num == 1)
+ return 1;
+ else
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+ attr->type = type;
+ return 1;
+}
+
+struct vehicle_methods vehicle_gypsy_methods = {
+ vehicle_gypsy_destroy,
+ vehicle_gypsy_position_attr_get,
+};
+
+/**
+ * @brief Create gypsy_vehicle
+ *
+ * @param meth
+ * @param cbl
+ * @param attrs
+ * @returns vehicle_priv
+ */
+static struct vehicle_priv *
+vehicle_gypsy_new_gypsy(struct vehicle_methods *meth,
+ struct callback_list *cbl,
+ struct attr **attrs)
+{
+ struct vehicle_priv *ret;
+ struct attr *source, *retry_int;
+
+ dbg(1, "enter\n");
+ source = attr_search(attrs, NULL, attr_source);
+ ret = g_new0(struct vehicle_priv, 1);
+ ret->have_cords = 0;
+ ret->source = g_strdup(source->u.str);
+ ret->attrs = attrs;
+ retry_int = attr_search(attrs, NULL, attr_retry_interval);
+ if (retry_int) {
+ ret->retry_interval = retry_int->u.num;
+ if (ret->retry_interval < MIN_RETRY_INTERVAL) {
+ dbg(0, "Retry interval %d too small, setting to %d\n", ret->retry_interval, MIN_RETRY_INTERVAL);
+ ret->retry_interval = MIN_RETRY_INTERVAL;
+ }
+ } else {
+ dbg(0, "Retry interval not defined, setting to %d\n", DEFAULT_RETRY_INTERVAL);
+ ret->retry_interval = DEFAULT_RETRY_INTERVAL;
+ }
+ ret->cbl = cbl;
+ *meth = vehicle_gypsy_methods;
+ vehicle_gypsy_open(ret);
+ return ret;
+}
+
+/**
+ * @brief register vehicle_gypsy
+ *
+ * @returns nothing
+ */
+void
+plugin_init(void)
+{
+ dbg(1, "enter\n");
+ plugin_register_vehicle_type("gypsy", vehicle_gypsy_new_gypsy);
+}
diff --git a/vehicle/wince/Makefile.am b/vehicle/wince/Makefile.am
new file mode 100644
index 00000000..df96e0b6
--- /dev/null
+++ b/vehicle/wince/Makefile.am
@@ -0,0 +1,5 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=vehicle_wince
+modulevehicle_LTLIBRARIES = libvehicle_wince.la
+libvehicle_wince_la_SOURCES = vehicle_wince.c
+libvehicle_wince_la_LDFLAGS = -module -avoid-version
diff --git a/vehicle/wince/vehicle_wince.c b/vehicle/wince/vehicle_wince.c
new file mode 100644
index 00000000..2b835448
--- /dev/null
+++ b/vehicle/wince/vehicle_wince.c
@@ -0,0 +1,614 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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 <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <math.h>
+#include "config.h"
+#include "debug.h"
+#include "callback.h"
+#include "plugin.h"
+#include "coord.h"
+#include "item.h"
+#include "vehicle.h"
+#include "event.h"
+#include <windows.h>
+#include <windowsx.h>
+#include <io.h>
+#include <winioctl.h>
+#include <winbase.h>
+#include "support/win32/ConvertUTF.h"
+
+#define SwitchToThread() Sleep(0)
+
+static void vehicle_wince_disable_watch(struct vehicle_priv *priv);
+static void vehicle_wince_enable_watch(struct vehicle_priv *priv);
+static int vehicle_wince_parse(struct vehicle_priv *priv, char *buffer);
+static int vehicle_wince_open(struct vehicle_priv *priv);
+static void vehicle_wince_close(struct vehicle_priv *priv);
+
+static int buffer_size = 256;
+
+struct vehicle_priv {
+ char *source;
+ struct callback_list *cbl;
+ int is_running;
+ int thread_up;
+ int fd;
+ HANDLE m_hGPSDevice; // Handle to the device
+ HANDLE m_hGPSThread; // Handle to the thread
+ DWORD m_dwGPSThread; // Thread id
+ HANDLE m_hEventPosition; // Handle to the position event
+ HANDLE m_hEventState; // Handle to the state event
+ HANDLE m_hEventStop; // Handle to the stop event
+ DWORD m_dwError; // Last error code
+
+ char *buffer;
+ int buffer_pos;
+ char *nmea_data;
+ char *nmea_data_buf;
+
+ struct coord_geo geo;
+ double speed;
+ double direction;
+ double height;
+ double hdop;
+ double vdop;
+ char fixtime[20];
+ int fixyear;
+ int fixmonth;
+ int fixday;
+ int status;
+ int sats_used;
+ int sats_visible;
+ int time;
+ int on_eof;
+ int no_data_count;
+ int baudrate;
+ struct attr ** attrs;
+ char fixiso8601[128];
+ int checksum_ignore;
+};
+
+static DWORD WINAPI wince_port_reader_thread (LPVOID lParam)
+{
+ struct vehicle_priv *pvt = lParam;
+ COMMTIMEOUTS commTiming;
+ BOOL status;
+ static char buffer[10*82*4] = {0,};
+ static int current_index = 0;
+ const int chunk_size = 3*82;
+ char* return_pos;
+ DWORD dwBytes;
+ char return_buffer[1024];
+ int havedata;
+ HANDLE hGPS;
+ // Com ports above 9 should be prefixed - $device/COM123
+ wchar_t portname[64];
+ mbstowcs(portname, pvt->source, strlen(pvt->source)+1);
+ dbg(0, "GPS Port:[%s]\n", pvt->source);
+ pvt->thread_up = 1;
+reconnect_port:
+ /* GPD0 is the control port for the GPS driver */
+ hGPS = CreateFile(L"GPD0:", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (hGPS != INVALID_HANDLE_VALUE) {
+#ifndef IOCTL_SERVICE_REFRESH
+#define IOCTL_SERVICE_REFRESH 0x4100000C
+#endif
+ DeviceIoControl(hGPS,IOCTL_SERVICE_REFRESH,0,0,0,0,0,0);
+#ifndef IOCTL_SERVICE_START
+#define IOCTL_SERVICE_START 0x41000004
+#endif
+ DeviceIoControl(hGPS,IOCTL_SERVICE_START,0,0,0,0,0,0);
+ CloseHandle(hGPS);
+ }
+
+ while (pvt->is_running &&
+ (pvt->m_hGPSDevice = CreateFile(portname,
+ GENERIC_READ, 0,
+ NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
+ Sleep(1000);
+ dbg(0, "Waiting to connect to %s\n", pvt->source);
+ }
+ GetCommTimeouts (pvt->m_hGPSDevice, &commTiming);
+ commTiming.ReadIntervalTimeout = 20;
+ commTiming.ReadTotalTimeoutMultiplier = 0;
+ commTiming.ReadTotalTimeoutConstant = 200;
+
+ commTiming.WriteTotalTimeoutMultiplier=5;
+ commTiming.WriteTotalTimeoutConstant=5;
+ SetCommTimeouts (pvt->m_hGPSDevice, &commTiming);
+
+ if (pvt->baudrate) {
+ DCB portState;
+ if (!GetCommState(pvt->m_hGPSDevice, &portState)) {
+ MessageBox (NULL, TEXT ("GetCommState Error"), TEXT (""),
+ MB_APPLMODAL|MB_OK);
+ pvt->thread_up = 0;
+ return(1);
+ }
+ portState.BaudRate = pvt->baudrate;
+ if (!SetCommState(pvt->m_hGPSDevice, &portState)) {
+ MessageBox (NULL, TEXT ("SetCommState Error"), TEXT (""),
+ MB_APPLMODAL|MB_OK);
+ pvt->thread_up = 0;
+ return(1);
+ }
+ }
+ while (pvt->is_running) {
+ havedata = 0;
+ if (current_index + chunk_size >= sizeof(buffer)) {
+ // reset buffer
+ dbg(0, "GPS buffer reset\n");
+ current_index = 0;
+ memset(buffer, 0, sizeof(buffer));
+ }
+ status = ReadFile(pvt->m_hGPSDevice,
+ &buffer[current_index], chunk_size,
+ &dwBytes, NULL);
+ if (!status) {
+ CloseHandle(pvt->m_hGPSDevice);
+ pvt->m_hGPSDevice = NULL;
+ goto reconnect_port;
+ }
+ if (dwBytes > 0) {
+ int pos;
+ int consumed;
+ return_pos = NULL;
+ current_index += dwBytes;
+ buffer[current_index+1] = '\0';
+ //dbg(0, "buffer[%s]\n", buffer);
+ while (buffer[0]) {
+ pos = strcspn(buffer, "\r\n");
+ if (pos >= sizeof(return_buffer)) {
+ current_index = 0;
+ break;
+ }
+ if (pos) {
+ if (!buffer[pos])
+ break;
+ memcpy(return_buffer, buffer, pos);
+ return_buffer[pos] = '\0';
+ // dbg(0, "received %d : '%s' bytes to copy\n", bytes_to_copy, return_buffer );
+ havedata += vehicle_wince_parse(pvt, return_buffer);
+ }
+ consumed = pos + strspn(buffer+pos, "\r\n");
+ current_index -= consumed;
+ memmove(buffer,&buffer[consumed] ,
+ sizeof(buffer) - consumed);
+ buffer[current_index] = '\0';
+ }
+ if (havedata) {
+ // post a message so we can callback from
+ // the ui thread
+ event_call_callback(pvt->cbl);
+ }
+ } else {
+ pvt->no_data_count++;
+ }
+ }
+ CloseHandle(pvt->m_hGPSDevice);
+ pvt->m_hGPSDevice = NULL;
+ pvt->thread_up = 0;
+ return 0;
+}
+
+
+static int
+vehicle_wince_open(struct vehicle_priv *priv)
+{
+ dbg(1, "enter vehicle_wince_open, priv->source='%s'\n", priv->source);
+
+ if (priv->source ) {
+ char* raw_setting_str = g_strdup( priv->source );
+ char* strport = strchr(raw_setting_str, ':' );
+ char* strsettings = strchr(raw_setting_str, ' ' );
+
+ if (raw_setting_str && strport&&strsettings ) {
+ strport++;
+ *strsettings = '\0';
+ strsettings++;
+
+ dbg(0, "serial('%s', '%s')\n", strport, strsettings );
+ }
+ if (raw_setting_str)
+ g_free( raw_setting_str );
+ }
+ return 1;
+}
+
+static void
+vehicle_wince_close(struct vehicle_priv *priv)
+{
+ vehicle_wince_disable_watch(priv);
+}
+
+static int
+vehicle_wince_parse(struct vehicle_priv *priv, char *buffer)
+{
+ char *nmea_data_buf, *p, *item[16];
+ double lat, lng;
+ int i, bcsum;
+ int len;
+ unsigned char csum = 0;
+ int ret = 0;
+ int valid = 0;
+
+ len = strlen(buffer);
+ //dbg(0, "buffer='%s'\n", buffer);
+ for (;;) {
+ if (len < 4) {
+ dbg(0, "'%s' too short\n", buffer);
+ return ret;
+ }
+ if (buffer[len - 1] == '\r' || buffer[len - 1] == '\n')
+ buffer[--len] = '\0';
+ else
+ break;
+ }
+ if (buffer[0] != '$') {
+ dbg(0, "no leading $ in '%s'\n", buffer);
+ return ret;
+ }
+ if (buffer[len - 3] != '*') {
+ dbg(0, "no *XX in '%s'\n", buffer);
+ return ret;
+ }
+ for (i = 1; i < len - 3; i++) {
+ csum ^= (unsigned char) (buffer[i]);
+ }
+ if (!sscanf(buffer + len - 2, "%x", &bcsum)&& priv->checksum_ignore != 2) {
+ dbg(0, "no checksum in '%s'\n", buffer);
+ return ret;
+ }
+ if (bcsum != csum && priv->checksum_ignore == 0) {
+ dbg(0, "wrong checksum in '%s' %x vs %x\n", buffer, bcsum, csum);
+ return ret;
+ }
+// RMC, RMB, VTG, and GLL in nmea 2.3 have status
+// A=autonomous, D=differential, E=Estimated, N=not valid, S=Simulator.
+// Only A and D are valid
+ if (!priv->nmea_data_buf || strlen(priv->nmea_data_buf) < 65536) {
+ nmea_data_buf=g_strconcat(priv->nmea_data_buf ? priv->nmea_data_buf : "", buffer, "\n", NULL);
+ g_free(priv->nmea_data_buf);
+ priv->nmea_data_buf=nmea_data_buf;
+ } else {
+ dbg(0, "nmea buffer overflow, discarding '%s'\n", buffer);
+ }
+ i = 0;
+ p = buffer;
+ while (i < 16) {
+ item[i++] = p;
+ while (*p && *p != ',')
+ p++;
+ if (!*p)
+ break;
+ *p++ = '\0';
+ }
+ if (0) {
+ int j = 0;
+ for (j=0; j < i; j++)
+ dbg(0,"[%d] = %s\n", j, item[j]);
+ }
+
+ if (!strncmp(buffer, "$GPGGA", 6)) {
+ /* 1 1111
+ 0 1 2 3 4 5 6 7 8 9 0 1234
+ $GPGGA,184424.505,4924.2811,N,01107.8846,E,1,05,2.5,408.6,M,,,,0000*0C
+ UTC of Fix[1],Latitude[2],N/S[3],Longitude[4],E/W[5],Quality(0=inv,1=gps,2=dgps)[6],Satelites used[7],
+ HDOP[8],Altitude[9],"M"[10],height of geoid[11], "M"[12], time since dgps update[13], dgps ref station [14]
+ */
+ lat = strtod(item[2], NULL);
+ priv->geo.lat = floor(lat / 100);
+ lat -= priv->geo.lat * 100;
+ priv->geo.lat += lat / 60;
+
+ if (!strcasecmp(item[3],"S"))
+ priv->geo.lat=-priv->geo.lat;
+
+ lng = strtod(item[4], NULL);
+ priv->geo.lng = floor(lng / 100);
+ lng -= priv->geo.lng * 100;
+ priv->geo.lng += lng / 60;
+
+ if (!strcasecmp(item[5],"W"))
+ priv->geo.lng=-priv->geo.lng;
+
+ sscanf(item[6], "%d", &priv->status);
+ sscanf(item[7], "%d", &priv->sats_used);
+ sscanf(item[8], "%lf", &priv->hdop);
+ strcpy(priv->fixtime, item[1]);
+ sscanf(item[9], "%lf", &priv->height);
+ g_free(priv->nmea_data);
+ priv->nmea_data=priv->nmea_data_buf;
+ priv->nmea_data_buf=NULL;
+
+ // callback_list_call_0(priv->cbl);
+ return 1;
+ }
+ if (!strncmp(buffer, "$GPVTG", 6)) {
+
+ /* 0 1 2 34 5 6 7 8
+ $GPVTG,143.58,T,,M,0.26,N,0.5,K*6A
+ Course Over Ground Degrees True[1],"T"[2],Course Over Ground Degrees Magnetic[3],"M"[4],
+ Speed in Knots[5],"N"[6],"Speed in KM/H"[7],"K"[8]
+ */
+ if (item[1] && item[7])
+ valid = 1;
+ if (i == 9 && (*item[9] == 'A' || *item[9] == 'D'))
+ valid = 1;
+ if (valid) {
+ priv->direction = g_ascii_strtod( item[1], NULL );
+ priv->speed = g_ascii_strtod( item[7], NULL );
+ }
+ }
+ if (!strncmp(buffer, "$GPRMC", 6)) {
+ /* 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1
+ $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
+ Time[1],Active/Void[2],lat[3],N/S[4],long[5],W/E[6],speed in knots[7],track angle[8],date[9],
+ magnetic variation[10],magnetic variation direction[11]
+ */
+ if (*item[2] == 'A')
+ valid = 1;
+ if (i == 12 && (*item[12] == 'A' || *item[12] == 'D'))
+ valid = 1;
+ if (valid) {
+ priv->direction = g_ascii_strtod( item[8], NULL );
+ priv->speed = g_ascii_strtod( item[7], NULL );
+ priv->speed *= 1.852;
+ sscanf(item[9], "%02d%02d%02d",
+ &priv->fixday,
+ &priv->fixmonth,
+ &priv->fixyear);
+ priv->fixyear += 2000;
+ }
+ }
+ if (!strncmp(buffer, "$GPGSA", 6)) {
+ /*
+ GSA Satellite status
+ A Auto selection of 2D or 3D fix (M = manual)
+ 3 3D fix - values include: 1 = no fix
+ 2 = 2D fix
+ 3 = 3D fix
+ 04,05... PRNs of satellites used for fix (space for 12)
+ 2.5 PDOP (dilution of precision)
+ 1.3 Horizontal dilution of precision (HDOP)
+ 2.1 Vertical dilution of precision (VDOP)
+ *39 the checksum data, always begins with *
+ */
+ }
+ if (!strncmp(buffer, "$GPGSV", 6)) {
+ /*
+ 0 GSV Satellites in view
+ 1 2 Number of sentences for full data
+ 2 1 sentence 1 of 2
+ 3 08 Number of satellites in view
+
+ 4 01 Satellite PRN number
+ 5 40 Elevation, degrees
+ 6 083 Azimuth, degrees
+ 7 46 SNR - higher is better
+ for up to 4 satellites per sentence
+ *75 the checksum data, always begins with *
+ */
+ if (item[3]) {
+ sscanf(item[3], "%d", &priv->sats_visible);
+ }
+ }
+ if (!strncmp(buffer, "$GPZDA", 6)) {
+ /*
+ 0 1 2 3 4 5 6
+ $GPZDA,hhmmss.ss,dd,mm,yyyy,xx,yy*CC
+ hhmmss HrMinSec(UTC)
+ dd,mm,yyy Day,Month,Year
+ xx local zone hours -13..13
+ yy local zone minutes 0..59
+ */
+ if (item[1] && item[2] && item[3] && item[4]) {
+ // priv->fixtime = atof(item[1]);
+ strcpy(priv->fixtime, item[1]);
+ priv->fixday = atoi(item[2]);
+ priv->fixmonth = atoi(item[3]);
+ priv->fixyear = atoi(item[4]);
+ }
+ }
+ return ret;
+}
+
+static void
+vehicle_wince_enable_watch(struct vehicle_priv *priv)
+{
+ vehicle_wince_disable_watch(priv);
+ priv->is_running = 1;
+ priv->m_hGPSThread = CreateThread(NULL, 0, wince_port_reader_thread,
+ priv, 0, &priv->m_dwGPSThread);
+ if (!priv->m_hGPSThread) {
+ priv->is_running = 0;
+ // error creating thread
+ MessageBox (NULL, TEXT ("Can not create GPS reader thread"), TEXT (""),
+ MB_APPLMODAL|MB_OK);
+ }
+}
+
+static void
+vehicle_wince_disable_watch(struct vehicle_priv *priv)
+{
+ int wait = 5000;
+ priv->is_running = 0;
+// DWORD res;
+// res = WaitForSingleObject(priv->m_hGPSThread, 2000);
+//
+ while (wait-- > 0 && priv->thread_up) {
+ SwitchToThread();
+ }
+ if (priv->m_hGPSThread) {
+ // Terminate reader, sorry
+ TerminateThread(priv->m_hGPSThread, -1);
+ }
+}
+
+
+static void
+vehicle_wince_destroy(struct vehicle_priv *priv)
+{
+ vehicle_wince_close(priv);
+ if (priv->source)
+ g_free(priv->source);
+ if (priv->buffer)
+ g_free(priv->buffer);
+ g_free(priv);
+}
+
+static int
+vehicle_wince_position_attr_get(struct vehicle_priv *priv,
+ enum attr_type type, struct attr *attr)
+{
+ struct attr * active=NULL;
+ int check_status = 0;
+
+ switch (type) {
+ case attr_position_fix_type:
+ attr->u.num = priv->status;
+ break;
+ case attr_position_height:
+ check_status = 1;
+ attr->u.numd = &priv->height;
+ break;
+ case attr_position_speed:
+ check_status = 1;
+ attr->u.numd = &priv->speed;
+ break;
+ case attr_position_direction:
+ check_status = 1;
+ attr->u.numd = &priv->direction;
+ break;
+ case attr_position_hdop:
+ attr->u.numd = &priv->hdop;
+ break;
+ case attr_position_qual:
+ attr->u.num = priv->sats_visible;
+ break;
+ case attr_position_sats_used:
+ attr->u.num = priv->sats_used;
+ break;
+ case attr_position_coord_geo:
+ check_status = 1;
+ attr->u.coord_geo = &priv->geo;
+ break;
+ case attr_position_nmea:
+ attr->u.str=priv->nmea_data;
+ if (!attr->u.str)
+ return 0;
+ break;
+ case attr_position_time_iso8601:
+ if (!priv->fixyear || !priv->fixtime[0])
+ return 0;
+ sprintf(priv->fixiso8601, "%04d-%02d-%02dT%sZ",
+ priv->fixyear, priv->fixmonth, priv->fixday,
+ priv->fixtime);
+ attr->u.str=priv->fixiso8601;
+ break;
+ case attr_active:
+ if (active != NULL && active->u.num == 1)
+ return 1;
+ else
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ attr->type = type;
+ if (check_status && 0 == priv->status)
+ return 0;
+ return 1;
+}
+
+struct vehicle_methods vehicle_wince_methods = {
+ vehicle_wince_destroy,
+ vehicle_wince_position_attr_get,
+};
+
+static struct vehicle_priv *
+vehicle_wince_new(struct vehicle_methods
+ *meth, struct callback_list
+ *cbl, struct attr **attrs)
+{
+ struct vehicle_priv *ret;
+ struct attr *source;
+ struct attr *time;
+ struct attr *on_eof;
+ struct attr *baudrate;
+ struct attr *checksum_ignore;
+ char *cp;
+
+ dbg(1, "enter\n");
+ source = attr_search(attrs, NULL, attr_source);
+ ret = g_new0(struct vehicle_priv, 1);
+ ret->fd = -1;
+ ret->cbl = cbl;
+ cp = strchr(source->u.str,':');
+ if (cp)
+ cp++;
+ else
+ cp = source->u.str;
+ ret->source = g_strdup(cp);
+ ret->buffer = g_malloc(buffer_size);
+ ret->time=1000;
+ ret->baudrate=0; // do not change the rate if not configured
+ // ret->fixtime = 0.0f;
+ time = attr_search(attrs, NULL, attr_time);
+ if (time)
+ ret->time=time->u.num;
+ baudrate = attr_search(attrs, NULL, attr_baudrate);
+ if (baudrate) {
+ ret->baudrate = baudrate->u.num;
+ }
+ ret->attrs = attrs;
+ checksum_ignore = attr_search(attrs, NULL, attr_checksum_ignore);
+ if (checksum_ignore)
+ ret->checksum_ignore=checksum_ignore->u.num;
+ on_eof = attr_search(attrs, NULL, attr_on_eof);
+ if (on_eof && !strcasecmp(on_eof->u.str, "stop"))
+ ret->on_eof=1;
+ if (on_eof && !strcasecmp(on_eof->u.str, "exit"))
+ ret->on_eof=2;
+ dbg(0,"on_eof=%d\n", ret->on_eof);
+ *meth = vehicle_wince_methods;
+ if (vehicle_wince_open(ret)) {
+ vehicle_wince_enable_watch(ret);
+ return ret;
+ }
+ ret->no_data_count = 0;
+ dbg(0, "Failed to open '%s'\n", ret->source);
+ vehicle_wince_destroy(ret);
+ return NULL;
+}
+
+void
+plugin_init(void)
+{
+ dbg(1, "enter\n");
+ plugin_register_vehicle_type("wince", vehicle_wince_new);
+}