GoPal tracklog patch

View: New views
2 Messages — Rating Filter:   Alert me  

GoPal tracklog patch

by "Dr. Jürgen Neumann" :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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.org
Gpsbabel-code@...
https://lists.sourceforge.net/lists/listinfo/gpsbabel-code

Re: GoPal tracklog patch

by Robert Lipe-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello.

This basically looks pretty good to me.

Can you please offer an entry for our test suite (testo) and some kind of doc on what a "GoPal" is and how one would use the resulting files with it?

I'll commit this change once it's documented and testable.  It looks like good stuff!

Thanx,
RJL


On Sun, Jul 20, 2008 at 8:10 AM, "Dr. Jürgen Neumann" <Juergen.Neumann@...> wrote:
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 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.org
Gpsbabel-code@...
https://lists.sourceforge.net/lists/listinfo/gpsbabel-code
LightInTheBox - Buy quality products at wholesale price