Hi list,
attached (I hope) you will find the files to patch gpsbabel to support
the logging format of GoPal powered gps navigation devices.
Any comments are welcome!
Regards Juergen
This is the first try to implement the GoPal track log format into gpsbabel.
It was developed using MSVC2005, but was also tested on a Suse10.3 linux using gcc.
The main reason to implement this easy format were 3 points:
- I did'nt found a way to tell gpsbabel a starting date, from wich the internal timestamps count up
- it would be better to leave the filename parsing do a program ...
- in my logs are annoying position errors I want to sort out
Questions & bug reports are welcome @
Juergen.Neumann (ät) online.com
Good luck
Jürgen
/*
Copyright (C) 2008 Jürgen Neumann,
Juergen.Neumann@...
Copyright (C) 2005 Robert Lipe,
robertlipe@... (based on nmea.c)
Copyright (C) 20XX probably many others from the gpsbabel development team ;-)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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., 59 Temple Place - Suite 330, Boston, MA 02111 USA
=====================================================================================
This file allows gpsbabel to read and write the internal track log format used by
GoPal navigation systems. They produce a simple line-oriented format with one point per
second. Unfortunately the the data does not contain a valid date, only some kind of timetick,
together with each point (perhaps by mistake ??). So we have to parse the filename for a valid starting
date and add the timeoffset. Second problem (at least to me) was that irregularly stupid errors were
in the data, i.e. only one data point shows a totally wrong longitude or latitude. Everything else in
the dataset seems ok, so I needed a way to sort out these errors. My solution is to calculate the speed
between successive points and drop points not between minspeed and maxspeed. This way I can sort out most
of this annoying bugs, a side effect is that if a minimum speed > 0 is set points with the same coodinates are also
dropped.
Fileformat GoPal
TICK; TIME UTC; LONG; LAT; HEIGHT; SPEED km/h; FIX; HDOP; SAT
3801444, 080558, 2.944362, 43.262117, 295.28, 0.12964, 2, 2.900000, 3
Filenames:
trackYYYYMMDD_HHMMSS.trk
A_YYYYMMDD_HHMMSS.trk
with HHMMSS local time (not UTC)
History
2008-07-18 initial release of Version 0.1
*/
#include "defs.h"
#include <ctype.h>
#include "csv_util.h"
#include <time.h>
#include "strptime.h"
#include "jeeps/gpsmath.h"
#include "grtcirc.h"
#define MYNAME "gopal"
static gbfile *fin, *fout;
static struct tm tm,filenamedate, trackdate;
time_t tx;
char tmp[64];
char routename[64];
static char *optdate=NULL;
static char *optmaxspeed=NULL;
static char *optminspeed=NULL;
static char *optclean= NULL;
static double minspeed,maxspeed;
static struct tm opt_tm; /* converted "date" parameter */
static
arglist_t gopal_args[] = {
{"date", &optdate, "Complete date-free tracks with given date (YYYYMMDD).", NULL, ARGTYPE_INT, ARG_NOMINMAX },
{"maxspeed", &optmaxspeed, "The maximum speed traveling from waypoint to waypoint.", "200", ARGTYPE_INT, "1", "1000" },
{"minspeed", &optminspeed, "The minimum speed traveling from waypoint to waypoint.\nset >0 to remove duplicate waypoints", "0", ARGTYPE_INT, "0", "999" },
{"clean", &optclean, "Cleanup common errors in trackdata", "1", ARGTYPE_BOOL, ARG_NOMINMAX },
ARG_TERMINATOR
};
#define CHECK_BOOL(a) if (a && (*a == '0')) a = NULL
int gopal_check_line(char *line)
{
char *c = line;
int i = 0;
while ((c = strchr(c, ',')))
{
c++;
i++;
}
if ((i != 8)&& (global_opts.debug_level > 1))
{
snprintf(tmp,sizeof(tmp),MYNAME " Warning:\"%s\"\n",line);
fprintf(stderr,tmp);
}
return i;
}
/*******************************************************************************
* %%% global callbacks called by gpsbabel main process %%% *
*******************************************************************************/
static void
gopal_rd_init(const char *fname)
{char buff[32];
char *ck;
char filename[255];
char *delim;
CHECK_BOOL(optclean);
if (optminspeed)
{
minspeed=atof(optminspeed);
if (global_opts.debug_level > 1) fprintf(stderr,"options from command line : gopal minspeed = %s\n",optminspeed);
}
else
minspeed=0;
if (optmaxspeed)
{
maxspeed=atof(optmaxspeed);
if (global_opts.debug_level > 1) fprintf(stderr,"options from command line : gopal maxspeed = %s\n",optmaxspeed);
}
else
maxspeed=200;
if (global_opts.debug_level > 1) fprintf(stderr,"setting minspeed to %5.1lf km/h and maxspeed to %5.1lf km/h\n",minspeed,maxspeed);
fin = gbfopen(fname, "r", MYNAME);
memset(buff,0,sizeof(buff));
if (optdate)
{
memset(&opt_tm, 0, sizeof(opt_tm));
ck = (char *)strptime(optdate, "%Y%m%d", &opt_tm);
if ((ck == NULL) || (*ck != '\0') || (strlen(optdate) != 8))
fatal(MYNAME ": Invalid date \"%s\"!\n", optdate);
else if (opt_tm.tm_year < 70)
fatal(MYNAME ": Date \"%s\" is out of range (have to be 19700101 or later)!\n", optdate);
tx = mkgmtime(&opt_tm);
}
else
{
/* remove path */
delim = strrchr(fname, '/');
delim = strrchr(fname, '\\');
if ((delim)&&(strlen(delim)>8) )
sprintf((char*)&filename, "%s", delim+1); //copy only filename without path
else
sprintf((char*)&filename, "%s", fname); // copy original filename (probably without path)
if ((strncmp(filename,"track",5)==0)&&(strlen(filename)>13)) // we need at least 13 letters: trackYYYYMMDD...
{
strncpy(&buff[0],&filename[5],8);
}
else
if ((strncmp(filename,"A_",2)==0)&&(strlen(filename)>10))// here we expect at least 10 letters: A_YYYYMMDD...
{
strncpy(&buff[0],&filename[2],8);
}
// in buff we should now have something wich looks like a valid date starting with YYYYMMDD
ck = (char *)strptime(buff, "%Y%m%d", &filenamedate);
if (((ck == NULL) || (*ck != '\0') )&&!(optdate))
fatal(MYNAME ": Invalid date in filename \"%s\", try to set manually using \"optdate\" switch!\n", buff);
else if (filenamedate.tm_year < 70)
fatal(MYNAME ": Date \"%s\" is out of range (have to be 19700101 or later)!\n", buff);
tx= mkgmtime(&filenamedate);
}
}
static void
gopal_rd_deinit(void)
{
gbfclose(fin);
}
static void
gopal_read(void)
{
char *buff;
char *str, *c;
int column;
long line;
double hmsd,speed;
int fix, hms;
route_head *route;
waypoint *wpt, *lastwpt=NULL;
double long_old,lat_old;
char tbuffer[64];
long_old=0;lat_old=0;
strftime(routename,sizeof(routename),"Tracklog %c",localtime(&tx));
route = route_head_alloc();
route->rte_name=xstrdup(routename);
route_add_head(route);
line=0;
while ((buff = gbfgetstr(fin)))
{
str = buff = lrtrim(buff);
if (*buff == '\0') continue;
if (gopal_check_line(buff)!=8)continue;
wpt = waypt_new();
column = -1;
// the format of gopal is quite simple. Unfortunately the developers forgot the date as the first element...
//TICK; TIME; LONG; LAT; HEIGHT; SPEED; Fix; HDOP; SAT
//3801444, 080558, 2.944362, 43.262117, 295.28, 0.12964, 2, 2.900000, 3
c = csv_lineparse(str, ",", "", column++);
while (c != NULL)
{
switch(column)
{
case 0: /* "-" */ /* unknown fields for the moment */
//sscanf(c, "%llu", &wpt->microseconds);
break;
case 1: /* Time UTC */
sscanf(c,"%lf",&hmsd);
hms = (int) hmsd;
tm.tm_sec = hms % 100;
hms = hms / 100;
tm.tm_min = hms % 100;
hms = hms / 100;
tm.tm_hour = hms % 100;
tm.tm_year=trackdate.tm_year;
tm.tm_mon=trackdate.tm_mon;
tm.tm_mday=trackdate.tm_mday;
wpt->creation_time = tx+((((time_t)tm.tm_hour * 60) + tm.tm_min) * 60) + tm.tm_sec;
strftime(tbuffer, sizeof(tbuffer), "%H:%M:%S", gmtime(&wpt->creation_time));
break;
case 2: /* longitude */
sscanf(c, "%lf", &wpt->longitude);
break;
case 3: /* latitude */
sscanf(c, "%lf", &wpt->latitude);
break;
case 4: /* altitude */
sscanf(c, "%lf", &wpt->altitude);
break;
case 5: /* speed */
//sscanf(c, "%lf", &wpt->speed);
wpt->speed=atof(c);
break;
case 6: /* type of fix */
sscanf(c, "%d", &fix);
//my device shows only 0 or 2
//should i guess from no of sats if 2d or 3d?
switch (fix) {
case 0: wpt->fix = fix_none;break;
case 2: wpt->fix = fix_2d;break;
//case 3: wpt->fix = fix_3d;break;
//case 4: wpt->fix = fix_dgps;break; /* 2D_diff */
//case 5: wpt->fix = fix_dgps;break; /* 3D_diff */
default:
wpt->fix = fix_unknown;
break;
}
break;
case 7: /* hdop */
wpt->hdop = atof(c);
//sscanf(c, "%lf", &wpt->hdop); does not work ???
//wpt->vdop=0;wpt->hdop=0;
break;
case 8: /* number of sats */
sscanf(c, "%d", &wpt->sat);
break;
}
c = csv_lineparse(NULL, ",", "", column++);
}
line++;
if ((wpt->fix != fix_none)&&(lat_old==0)){ //first-time init
lat_old=wpt->latitude;
long_old=wpt->longitude;
//route_add_wpt(route, wpt);
lastwpt=wpt;
}
//calculate the speed to reach this waypoint from the last. This way I try to sort out invalid waypoints
speed=0;
if (lastwpt !=NULL)
{
speed=3.6*radtometers(gcdist(RAD(lastwpt->latitude), RAD(lastwpt->longitude), RAD(wpt->latitude), RAD(wpt->longitude))) / abs(wpt->creation_time - lastwpt->creation_time);
//printf("speed line %d %lf \n",line,speed);
}
/* Error handling: in the tracklog of my device sometimes "jump" waypoints ;-) */
if ((optclean) &&
(((wpt->longitude==0.0)|| (wpt->latitude==0.0)||(abs(wpt->latitude)>90)||(abs(wpt->longitude)>180))||
((speed>maxspeed)||(speed<minspeed)))
)
{
if (global_opts.debug_level > 1) fprintf(stderr,"Problem in or around line %5lu: \"%s\" %lf km/h\n",line,buff,speed);
}
else
{
if (global_opts.debug_level > 1) fprintf(stderr,"valid line %5lu: \"%s\" %lf km/h\n",line,buff,speed);
lastwpt=wpt;
long_old=wpt->longitude;
lat_old=wpt->latitude;
route_add_wpt(route,wpt);
waypt_add(waypt_dupe( wpt));
}
}
}
static void
gopal_route_hdr(const route_head *route)
{
}
static void
gopal_route_tlr(const route_head *rte)
{
}
static void
gopal_write_waypt(const waypoint *wpt)
{
char tbuffer[64];
int fix=fix_unknown;
//TICK; TIME; LONG; LAT; HEIGHT; SPEED; UN; HDOP; SAT
//3801444, 080558, 2.944362, 43.262117, 295.28, 0.12964, 2, 2.900000, 3
strftime(tbuffer, sizeof(tbuffer), "%H%M%S", gmtime(&wpt->creation_time));
if (wpt->fix!=fix_unknown) {
switch (wpt->fix)
{
case fix_none: fix = 0; break;
case fix_2d: fix = 2; break;
default: fix = 0; break;
}
}
gbfprintf(fout, "%llu, %s, %lf, %lf, %5.1lf, %5.4lf, %d, %lf, %d\n",wpt->creation_time,tbuffer, wpt->longitude, wpt->latitude,wpt->altitude,
wpt->speed,fix,wpt->hdop,wpt->sat);
}
static void
gopal_wr_init(const char *fname)
{
fout = gbfopen(fname, "w", MYNAME);
}
static void
gopal_wr_deinit(void)
{
gbfclose(fout);
}
static void
gopal_write(void)
{
//route_disp_all(gopal_route_hdr, gopal_route_tlr, gopal_write_waypt);
if (global_opts.objective == wptdata)
{
waypt_disp_all(gopal_write_waypt);
} else
//if (global_opts.objective == rtedata)
{
route_disp_all(gopal_route_hdr, gopal_route_tlr, gopal_write_waypt);
}
}
static void
gopal_exit(void) /* optional */
{
}
/**************************************************************************/
// capabilities below means: we can only read and write waypoints
//
ff_vecs_t gopal_vecs = {
ff_type_file,
{
ff_cap_read | ff_cap_write /* waypoints */,
ff_cap_none /* tracks */,
ff_cap_read | ff_cap_write /* routes */
},
gopal_rd_init,
gopal_wr_init,
gopal_rd_deinit,
gopal_wr_deinit,
gopal_read,
gopal_write,
gopal_exit,
gopal_args,
CET_CHARSET_ASCII, 0 /* ascii is the expected character set */
/* not fixed, can be changed through command line parameter */
};
/**************************************************************************/
Index: Makefile.in
===================================================================
RCS file: /cvsroot/gpsbabel/gpsbabel/Makefile.in,v
retrieving revision 1.120
diff -u -r1.120 Makefile.in
--- Makefile.in 25 Jun 2008 04:03:32 -0000 1.120
+++ Makefile.in 20 Jul 2008 11:40:20 -0000
@@ -59,7 +59,7 @@
wbt-200.o stmsdf.o gtrnctr.o dmtlog.o raymarine.o alan.o vitovtt.o \
ggv_log.o g7towin.o garmin_gpi.o lmx.o random.o xol.o dg-100.o \
navilink.o mtk_logger.o ik3d.o osm.o destinator.o exif.o vidaone.o \
- igo8.o
+ igo8.o gopal.o
FMTS=@FMTS@
Index: vecs.c
===================================================================
RCS file: /cvsroot/gpsbabel/gpsbabel/vecs.c,v
retrieving revision 1.172
diff -u -r1.172 vecs.c
--- vecs.c 19 Jun 2008 02:26:30 -0000 1.172
+++ vecs.c 20 Jul 2008 11:41:00 -0000
@@ -140,6 +140,7 @@
extern ff_vecs_t destinator_itn_vecs;
extern ff_vecs_t exif_vecs;
extern ff_vecs_t vidaone_vecs;
+extern ff_vecs_t gopal_vecs;
static
vecs_t vec_list[] = {
@@ -795,6 +796,12 @@
"IGO8 .trk",
"trk"
},
+ {
+ &gopal_vecs,
+ "gopal",
+ "GoPal GPS track log (.trk)",
+ "trk"
+ },
#endif // MAXIMAL_ENABLED
{
NULL,
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/_______________________________________________
Gpsbabel-code mailing list
http://www.gpsbabel.orgGpsbabel-code@...
https://lists.sourceforge.net/lists/listinfo/gpsbabel-code