diff options
author | martin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220> | 2008-05-18 10:01:53 +0000 |
---|---|---|
committer | martin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220> | 2008-05-18 10:01:53 +0000 |
commit | 0b74d7f4ee6d448ac811e2741e8cb1ed04f5ce76 (patch) | |
tree | be7bb1cb1020f4022e41c004e2fa9d561ea3580d /navit/vehicle | |
parent | f46eb419c46011d6d103b7f06cb2c842a2cbe6c9 (diff) | |
download | navit-0b74d7f4ee6d448ac811e2741e8cb1ed04f5ce76.tar.gz |
Fix:Core:Renamed src to navit for cleanup of includes
git-svn-id: http://svn.code.sf.net/p/navit/code/trunk/navit@1059 ffa7fe5e-494d-0410-b361-a75ebd5db220
Diffstat (limited to 'navit/vehicle')
-rw-r--r-- | navit/vehicle/Makefile.am | 4 | ||||
-rw-r--r-- | navit/vehicle/demo/Makefile.am | 4 | ||||
-rw-r--r-- | navit/vehicle/demo/vehicle_demo.c | 176 | ||||
-rw-r--r-- | navit/vehicle/file/Makefile.am | 4 | ||||
-rw-r--r-- | navit/vehicle/file/vehicle_file.c | 500 | ||||
-rw-r--r-- | navit/vehicle/gpsd/Makefile.am | 5 | ||||
-rw-r--r-- | navit/vehicle/gpsd/vehicle_gpsd.c | 285 |
7 files changed, 978 insertions, 0 deletions
diff --git a/navit/vehicle/Makefile.am b/navit/vehicle/Makefile.am new file mode 100644 index 000000000..8901833f8 --- /dev/null +++ b/navit/vehicle/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS=demo file +if VEHICLE_GPSD + SUBDIRS += gpsd +endif diff --git a/navit/vehicle/demo/Makefile.am b/navit/vehicle/demo/Makefile.am new file mode 100644 index 000000000..3f2f4f369 --- /dev/null +++ b/navit/vehicle/demo/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/Makefile.inc +AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/src -DMODULE=vehicle_demo +modulevehicle_LTLIBRARIES = libvehicle_demo.la +libvehicle_demo_la_SOURCES = vehicle_demo.c diff --git a/navit/vehicle/demo/vehicle_demo.c b/navit/vehicle/demo/vehicle_demo.c new file mode 100644 index 000000000..46b9c68de --- /dev/null +++ b/navit/vehicle/demo/vehicle_demo.c @@ -0,0 +1,176 @@ +#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" + +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; +}; + +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; + 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; + } + return 0; +} + +struct vehicle_methods vehicle_demo_methods = { + vehicle_demo_destroy, + vehicle_demo_position_attr_get, + vehicle_demo_set_attr, +}; + +static int +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 (mr && 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); + return 1; +} + + + +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; + g_timeout_add(ret->interval, (GSourceFunc) vehicle_demo_timer, ret); + return ret; +} + +void +plugin_init(void) +{ + dbg(1, "enter\n"); + plugin_register_vehicle_type("demo", vehicle_demo_new); +} diff --git a/navit/vehicle/file/Makefile.am b/navit/vehicle/file/Makefile.am new file mode 100644 index 000000000..f46da8480 --- /dev/null +++ b/navit/vehicle/file/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/Makefile.inc +AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/src -DMODULE=vehicle_file +modulevehicle_LTLIBRARIES = libvehicle_file.la +libvehicle_file_la_SOURCES = vehicle_file.c diff --git a/navit/vehicle/file/vehicle_file.c b/navit/vehicle/file/vehicle_file.c new file mode 100644 index 000000000..6b20cf6c2 --- /dev/null +++ b/navit/vehicle/file/vehicle_file.c @@ -0,0 +1,500 @@ +#include <stdio.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 "vehicle.h" + +static void vehicle_file_disable_watch(struct vehicle_priv *priv); +static void vehicle_file_enable_watch(struct vehicle_priv *priv); +static void 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 = 256; + +struct vehicle_priv { + char *source; + enum file_type file_type; + struct callback_list *cbl; + int fd; + FILE *file; + guint watch; + GIOChannel *iochan; + char *buffer; + int buffer_pos; + char *nmea_data; + char *nmea_data_buf; + + struct coord_geo geo; + double speed; + double direction; + double height; + int status; + int sats_used; + int time; + int on_eof; +#ifdef _WIN32 + int no_data_count; +#endif +}; + +#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; + + 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 ); + vehicle_file_parse( priv, return_buffer ); + + current_index -= bytes_to_copy; + memmove( buffer, &buffer[ bytes_to_copy ] , sizeof( buffer ) - bytes_to_copy ); + } + + } + 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, B4800); + cfsetospeed(&tio, B4800); + tio.c_cc[VMIN] = 16; + tio.c_cc[VTIME] = 1; + 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; + } + priv->iochan = g_io_channel_unix_new(priv->fd); +#endif + return 1; +} + +static void +vehicle_file_close(struct vehicle_priv *priv) +{ +#ifdef _WIN32 + serial_io_shutdown( priv->fd ); +#else + GError *error = NULL; + if (priv->iochan) { + g_io_channel_shutdown(priv->iochan, 0, &error); + priv->iochan = NULL; + } + 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(gpointer t) +{ + struct vehicle_priv *priv = t; + vehicle_file_enable_watch(priv); + dbg(1, "enter\n"); + + return FALSE; +} + + +static void +vehicle_file_parse(struct vehicle_priv *priv, char *buffer) +{ + char *nmea_data_buf, *p, *item[16]; + double lat, lng; + int i, bcsum; + int len = strlen(buffer); + unsigned char csum = 0; + + dbg(1, "buffer='%s'\n", buffer); + for (;;) { + if (len < 4) { + dbg(0, "'%s' too short\n", buffer); + return; + } + 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; + } + if (buffer[len - 3] != '*') { + dbg(0, "no *XX in '%s'\n", buffer); + return; + } + for (i = 1; i < len - 3; i++) { + csum ^= (unsigned char) (buffer[i]); + } + if (!sscanf(buffer + len - 2, "%x", &bcsum)) { + dbg(0, "no checksum in '%s'\n", buffer); + return; + } + if (bcsum != csum) { + dbg(0, "wrong checksum in '%s'\n", buffer); + return; + } + + 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 (!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 = 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; + + sscanf(item[6], "%d", &priv->status); + sscanf(item[7], "%d", &priv->sats_used); + priv->height = g_ascii_strtod(item[9], NULL); + g_free(priv->nmea_data); + priv->nmea_data=priv->nmea_data_buf; + priv->nmea_data_buf=NULL; + + callback_list_call_0(priv->cbl); + +#ifndef _WIN32 + if (priv->file_type == file_type_file) { + vehicle_file_disable_watch(priv); + g_timeout_add(priv->time, + vehicle_file_enable_watch_timer, + priv); + } +#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] + */ + 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] + */ + priv->direction = g_ascii_strtod( item[8], NULL ); + priv->speed = g_ascii_strtod( item[7], NULL ); + priv->speed *= 1.852; + } +} + +#ifndef _WIN32 +static gboolean +vehicle_file_io(GIOChannel * iochan, GIOCondition condition, gpointer t) +{ + struct vehicle_priv *priv = t; + int size; + char *str, *tok; + + dbg(1, "enter condition=%d\n", condition); + if (condition == G_IO_IN) { + size = + read(g_io_channel_unix_get_fd(iochan), + 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: + break; + case 2: + exit(0); + break; + } + return TRUE; + } + 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 = index(str, '\n'))) { + *tok++ = '\0'; + dbg(1, "line='%s'\n", str); + 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; + } + return TRUE; + } + return FALSE; +} +#endif + +static void +vehicle_file_enable_watch(struct vehicle_priv *priv) +{ +#ifdef _WIN32 + g_timeout_add(500, vehicle_win32_serial_track, priv); +#else + priv->watch = + g_io_add_watch(priv->iochan, G_IO_IN | G_IO_ERR | G_IO_HUP, + vehicle_file_io, priv); +#endif +} + +static void +vehicle_file_disable_watch(struct vehicle_priv *priv) +{ +#ifndef _WIN32 + if (priv->watch) + g_source_remove(priv->watch); + priv->watch = 0; +#endif +} + + +static void +vehicle_file_destroy(struct vehicle_priv *priv) +{ + vehicle_file_close(priv); + 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_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_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; + default: + return 0; + } + attr->type = type; + return 1; +} + +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; + + dbg(1, "enter\n"); + source = attr_search(attrs, NULL, attr_source); + 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; + time = attr_search(attrs, NULL, attr_time); + if (time) + ret->time=time->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_file_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/navit/vehicle/gpsd/Makefile.am b/navit/vehicle/gpsd/Makefile.am new file mode 100644 index 000000000..db7a686d9 --- /dev/null +++ b/navit/vehicle/gpsd/Makefile.am @@ -0,0 +1,5 @@ +include $(top_srcdir)/Makefile.inc +AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/src -DMODULE=vehicle_gpsd +modulevehicle_LTLIBRARIES = libvehicle_gpsd.la +libvehicle_gpsd_la_SOURCES = vehicle_gpsd.c +libvehicle_gpsd_la_LIBADD = @GPSD_LIBS@ diff --git a/navit/vehicle/gpsd/vehicle_gpsd.c b/navit/vehicle/gpsd/vehicle_gpsd.c new file mode 100644 index 000000000..ac7f0c0d9 --- /dev/null +++ b/navit/vehicle/gpsd/vehicle_gpsd.c @@ -0,0 +1,285 @@ +#include <config.h> +#include <gps.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; + char *gpsd_query; + struct callback_list *cbl; + GIOChannel *iochan; + guint retry_interval; + guint watch; + struct gps_data_t *gps; + struct coord_geo geo; + double speed; + double direction; + double height; + int status; + int sats; + int sats_used; + char *nmea_data; + char *nmea_data_buf; + guint retry_timer; +} *vehicle_last; + +#define DEFAULT_RETRY_INTERVAL 10 // seconds +#define MIN_RETRY_INTERVAL 1 // seconds + +static gboolean vehicle_gpsd_io(GIOChannel * iochan, + GIOCondition condition, gpointer t); + + + +static void +vehicle_gpsd_callback(struct gps_data_t *data, char *buf, size_t len, + int level) +{ + char *pos,*nmea_data_buf; + struct vehicle_priv *priv = vehicle_last; + if (buf[0] == '$' && len > 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->fix.speed is NAN, then the drawing gets jumpy. + if (isnan(data->fix.speed)) { + return; + } + dbg(2,"speed ok\n"); + if (data->set & SPEED_SET) { + priv->speed = data->fix.speed * 3.6; + 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) { + priv->sats_used = data->satellites_used; + priv->sats = data->satellites; + data->set &= ~SATELLITE_SET; + } + if (data->set & STATUS_SET) { + priv->status = data->status; + data->set &= ~STATUS_SET; + } + if (data->set & PDOP_SET) { + dbg(0, "pdop : %g\n", data->pdop); + 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; + callback_list_call_0(priv->cbl); + data->set &= ~LATLON_SET; + } +} + +/** + * 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){ + g_warning("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->iochan = g_io_channel_unix_new(priv->gps->gps_fd); + priv->watch = + g_io_add_watch(priv->iochan, G_IO_IN | G_IO_ERR | G_IO_HUP, + vehicle_gpsd_io, priv); + dbg(0,"Connected to gpsd fd=%d iochan=%p watch=%p\n", priv->gps->gps_fd, priv->iochan, priv->watch); + return FALSE; +} + +/** + * Open a connection to gpsd. Will re-try the connection if it fails + */ +static void +vehicle_gpsd_open(struct vehicle_priv *priv) +{ + 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) +{ + GError *error = NULL; + + if (priv->watch) { + g_source_remove(priv->watch); + priv->watch = 0; + } + if (priv->retry_timer) { + g_source_remove(priv->retry_timer); + priv->retry_timer=0; + } + if (priv->iochan) { + g_io_channel_shutdown(priv->iochan, 0, &error); + priv->iochan = NULL; + } + if (priv->gps) { + gps_close(priv->gps); + priv->gps = NULL; + } +} + +static gboolean +vehicle_gpsd_io(GIOChannel * iochan, GIOCondition condition, gpointer t) +{ + struct vehicle_priv *priv = t; + + dbg(1, "enter condition=%d\n", condition); + if (condition == G_IO_IN) { + 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); + } + } + return TRUE; + } + return FALSE; +} + +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) +{ + switch (type) { + 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_sats: + 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; + break; + case attr_position_nmea: + attr->u.str=priv->nmea_data; + if (! attr->u.str) + 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(0, "Retry interval not defined, setting to %d\n", DEFAULT_RETRY_INTERVAL); + ret->retry_interval = DEFAULT_RETRY_INTERVAL; + } + ret->cbl = cbl; + *meth = vehicle_gpsd_methods; + vehicle_gpsd_open(ret); + return ret; +} + +void +plugin_init(void) +{ + dbg(1, "enter\n"); + plugin_register_vehicle_type("gpsd", vehicle_gpsd_new_gpsd); +} |