diff options
Diffstat (limited to 'vehicle')
-rw-r--r-- | vehicle/Makefile.am | 16 | ||||
-rw-r--r-- | vehicle/demo/Makefile.am | 5 | ||||
-rw-r--r-- | vehicle/demo/vehicle_demo.c | 206 | ||||
-rw-r--r-- | vehicle/file/Makefile.am | 9 | ||||
-rw-r--r-- | vehicle/file/vehicle_file.c | 763 | ||||
-rw-r--r-- | vehicle/file/vehicle_pipe.c | 27 | ||||
-rw-r--r-- | vehicle/gpsd/Makefile.am | 6 | ||||
-rw-r--r-- | vehicle/gpsd/vehicle_gpsd.c | 387 | ||||
-rw-r--r-- | vehicle/gypsy/Makefile.am | 6 | ||||
-rw-r--r-- | vehicle/gypsy/vehicle_gypsy.c | 465 | ||||
-rw-r--r-- | vehicle/wince/Makefile.am | 5 | ||||
-rw-r--r-- | vehicle/wince/vehicle_wince.c | 614 |
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); +} |