Subversion Repositories public

Rev

Rev 249 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/***************************************************************************
 *   Copyright (C) 2007, 2008 by Andreas Theofilu                          *
 *   andreas@theosys.at                                                    *
 *                                                                         *
 *   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 version 3 of the License.                *
 *                                                                         *
 *   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-1307, USA.             *
 ***************************************************************************/

#include <time.h>
#include <string.h>
#include <math.h>
#include <boost/concept_check.hpp>
#include "garmin.h"
#include "disassemble.h"

#define Deg2Rad(n)      ((n) * DEG_2_RAD)

disassemble::disassemble()
{
        lap_node = 0;
        run_node = 0;
        point_node = 0;

        totalDistance = 0.0;
        totalTime = 0;
        avgHR = 0.0;
        avgSpeed = 0.0;
        maxSpeed = 0.0;
        ascend = 0.0;
        descend = 0.0;
}

disassemble::~disassemble()
{
        destroy();
}

void disassemble::destroy()
{
LAP_NODE *lakt, *ln;
RUN_NODE *rakt, *rn;
POINT_NODE *pakt, *pn;

        if (lap_node != NULL)           // free allocated laps
        {
           lakt = lap_node;

           while (lakt)
           {
              ln = lakt;
              delete ln->lap;
              lakt = lakt->next;
              delete ln;
           }
        }

        lap_node = NULL;

        if (lap_node != NULL)           // free allocated runs
        {
           rakt = run_node;

           while (rakt)
           {
              rn = rakt;
              delete rn->run;
              rakt = rakt->next;
              delete rn;
           }
        }

        run_node = NULL;

        if (point_node != NULL)         // free allocated points
        {
           pakt = point_node;

           while (pakt)
           {
              pn = pakt;
              delete pn->point;
              pakt = pakt->next;
              delete pn;
           }
        }

        point_node = NULL;

        totalDistance = 0.0;
        totalTime = 0;
        avgHR = 0.0;
        avgSpeed = 0.0;
        maxSpeed = 0.0;
        ascend = 0.0;
        descend = 0.0;

}

LAP_NODE *disassemble::addLap ()
{
LAP_NODE *akt, *n;

        if (lap_node == 0)              // First lap to add
        {
           lap_node = new LAP_NODE;
           lap_node->lap = new LAP;

           memmove (lap_node->lap, &lap, sizeof(LAP));
           lap_node->next = 0;
           akt = lap_node;
        }
        else                            // additional lap to add
        {
           n = lap_node;

           while (n->next)
              n = n->next;

           akt = new LAP_NODE;
           akt->lap = new LAP;
           memmove (akt->lap, &lap, sizeof(LAP));
           akt->next = 0;
           n->next = akt;
        }

        return akt;
}

LAP *disassemble::getLap(int index)
{
LAP_NODE *akt = lap_node;

        while (akt)
        {
           if (akt->lap->index == (uint32)index)
              return akt->lap;

           akt = akt->next;
        }

        return NULL;
}

LAP *disassemble::getLapT(uint32 time)
{
LAP_NODE *akt = lap_node;

        while (akt)
        {
           if ((akt->lap->start_time + akt->lap->total_time / 100) >= time)
              return akt->lap;

           akt = akt->next;
        }

        return NULL;
}

RUN_NODE *disassemble::addRun ()
{
RUN_NODE *akt, *n;

        if (run_node == 0)              // First run to add
        {
           run_node = new RUN_NODE;
           run_node->run = new RUN;

           memmove (run_node->run, &run, sizeof(RUN));
           run_node->next = 0;
           akt = run_node;
        }
        else                            // additional run to add
        {
           n = run_node;

           while (n != NULL && n->next != NULL)
              n = n->next;

           akt = new RUN_NODE;
           akt->run = new RUN;
           memmove (akt->run, &run, sizeof(RUN));
           akt->next = 0;
           n->next = akt;
        }

        return akt;
}

POINT_NODE *disassemble::addPoint ()
{
POINT_NODE *akt, *n;

        if (point_node == 0)            // First point to add
        {
           point_node = new POINT_NODE;
           point_node->point = new POINT;

           memmove (point_node->point, &point, sizeof(POINT));
           point_node->number = 0;
           point_node->next = 0;
           akt = point_node;
        }
        else                            // additional point to add
        {
           n = point_node;

           while (n != NULL && n->next != NULL)
              n = n->next;

           akt = new POINT_NODE;
           akt->point = new POINT;
           memmove (akt->point, &point, sizeof(point));
           akt->number = n->number + 1;
           akt->next = 0;
           n->next = akt;
        }

        return akt;
}

POINT *disassemble::getPoint(int number)
{
POINT_NODE *akt;

        akt = point_node;

        while (akt)
        {
           if (akt->number == number)
              return akt->point;

           akt = akt->next;
        }

        return 0;
}

POINT *disassemble::getPoint(uint32 time)
{
POINT_NODE *akt;

        akt = point_node;

        while (akt)
        {
           if (akt->point->time >= time)
              return akt->point;

           akt = akt->next;
        }

        return 0;
}

/* 
   This file contains functions to get Garmin datatypes.
   The functions aim to reproduce the data losslessly, including
   floating point data, such that the data can be scanned back from the
   output and reconstructed exactly.
*/

void disassemble::garmin_print_dlist (garmin_list *l)
{
garmin_list_node *n;
POINT_NODE *akt;
uint32 time = 0;
int countHR = 0;
int countCD = 0;
bool pause = false;
bool edTime = false;
uint32 stTime, pTime;
int arrDist[20];
uint32 arrTime[20];
float32 oldAlt, arrAlt[20];
int distPos;

        if (!l || !l->head)
                return;

        for (n = l->head; n != NULL; n = n->next)
        {
           garmin_print_data(n->data);
        }

        // Here all data is into the struct and now we
        // figure out some statistics
        akt = point_node;
        pTime = 0;
        stTime = 0;
        distPos = 0;
        oldAlt = 0;
        descend = 99999;

        if (akt && akt->point)
           time = akt->point->time;     // Save the time code of the first point
        else
           time = 0;

        while (akt)
        {
           // Find out the pause and detect how much seconds it is.
           if (!pause && akt->point->distance >= 0x7fffffff)
           {
              pause = true;
              stTime = akt->point->time;
              akt = akt->next;
              continue;
           }

           if (pause && akt->point->distance >= 0x7fffffff)
           {
              pause = false;
              edTime = true;
              akt = akt->next;
              continue;
           }

           if (pause && akt->point->distance < 0x7fffffff)
           {
              pause = false;
              edTime = true;
           }

           if (edTime)
           {
              pTime += (akt->point->time - stTime);
              edTime = false;
           }

           // If we have a normal point, use it!
           if (akt->point->distance < 0x7fffffff)
           {
              totalDistance = akt->point->distance;
              arrDist[distPos] = akt->point->distance;
              arrTime[distPos] = akt->point->time;
              arrAlt[distPos] = akt->point->alt;
              distPos++;

              if (distPos > 19)
              {
              double speed, alt, sumDist = 0.0;
              int secs = arrTime[19] - arrTime[0];

                 for (int i = 0; i < 19; i++)
                    sumDist += arrDist[i];

                 speed = sumDist / secs * 3.6;

                 if (speed > maxSpeed)
                    maxSpeed = speed;

                 alt = 0.0;

                 for (int i = 0; i < 19; i++)
                    alt += arrAlt[i];

                 alt /= 20.0;

                 if (oldAlt < alt)
                 {
                    ascend += (alt - oldAlt);
                    oldAlt = alt;
                 }

                 if (descend > alt)
                    descend = akt->point->alt;

                 distPos = 0;
              }

              if (akt->point->heart_rate > 0x00 && akt->point->heart_rate < 0xff)
              {
                 avgHR += akt->point->heart_rate;
                 countHR++;
              }

              if (akt->point->cadence > 0 && akt->point->cadence != 0xff)
              {
                 avgCadence += akt->point->cadence;
                 countCD++;
              }
           }

           totalTime = akt->point->time;
           akt = akt->next;
        }

        if (countHR > 0)
           avgHR /= countHR;

        if (countCD > 0)
           avgCadence /= countCD;

        if (point_node)
        {
           totalTime -= time;           // We need the number of seconds
           totalTime -= pTime;          // Subtract the seconds of pause
        }
        else
           totalTime = 0;

        if (totalTime > 0)
           avgSpeed = (totalDistance / 100.0) / totalTime * 3.6;

        pauseTime = pTime;
}

POINT *disassemble::getLastPoint()
{
POINT_NODE *old, *akt = point_node;

        if (!akt)
           return 0;

        old = 0;

        while (akt)
        {
           old = akt;

           if (!akt->next && akt->point)
           {
              if (akt->point->distance >= 0x7fffffff && old)
                 return old->point;

              return akt->point;
           }

           akt = akt->next;
        }

        return 0;       // This should never happen!
}

/* Support function to print a time value in ISO 8601 compliant format */

char *disassemble::garmin_print_dtime (uint32 t)
{
time_t     tval;
struct tm  tmval;
char       buf[128], hv0[128];
int        len;

        /* 
                                        012345678901234567890123
           This will make, for example, 2007-04-20T23:55:01-0700, but that date
           isn't quite ISO 8601 compliant.  We need to stick a ':' in the time
           zone between the hours and the minutes.
        */

        tval = t + TIME_OFFSET;
        localtime_r(&tval,&tmval);
        strftime(buf,sizeof(buf)-1,"%FT%T%z",&tmval);

        /* 
           If the last character is a 'Z', don't do anything.  Otherwise, we 
           need to move the last two characters out one and stick a colon in 
           the vacated spot.  Let's not forget the trailing '\0' that needs to 
           be moved as well.
        */

        len = strlen(buf);

        if ( len > 0 && buf[len-1] != 'Z' )
        {
           memmove(buf+len-1,buf+len-2,3);
           buf[len-2] = ':';
        }

        /* OK.  Done. */

        sprintf(hv0,"%s", buf);
        return (char *)strdup(hv0);
}


/* Support function to print a position type */

void disassemble::garmin_print_dpos (position_type *pos, double *lat, double *lon)
{
        if (!pos || !lat || !lon)
                return;

        if ( pos->lat != 0x7fffffff )
           *lat = SEMI2DEG(pos->lat);

        if ( pos->lon != 0x7fffffff )
           *lon = SEMI2DEG(pos->lon);
}


/* 
   Print a float32 with enough precision such that it can be reconstructed
   exactly from its decimal representation.
*/

char *disassemble::garmin_print_float32 (float32 f, char *ret)
{
        if (!ret)
           return 0;

        if ( f > 100000000.0 || f < -100000000.0 )
            sprintf(ret, "%.9e",f);
        else if ( f > 10000000.0 || f < -10000000.0 )
           sprintf(ret, "%.1f",f);
        else if ( f > 1000000.0 || f < -1000000.0 )
           sprintf(ret, "%.2f",f);
        else if ( f > 100000.0 || f < -100000.0 )
           sprintf(ret, "%.3f",f);
        else if ( f > 10000.0 || f < -10000.0 )
           sprintf(ret, "%.4f",f);
        else if ( f > 1000.0 || f < -1000.0 )
           sprintf(ret, "%.5f",f);
        else if ( f > 100.0 || f < -100.0 )
           sprintf(ret, "%.6f",f);
        else if ( f > 10.0 || f < -10.0 )
           sprintf(ret, "%.7f",f);
        else if ( f > 1.0 || f < -1.0 )
           sprintf(ret, "%.8f",f);
        else if ( f > 0.1 || f < -0.1 )
           sprintf(ret, "%.9f",f);
        else if ( f != 0 )
           sprintf(ret, "%.9e",f);
        else
           sprintf(ret, "%.8f",f);

        return ret;
}


/* 
   Print a float64 with enough precision such that it can be reconstructed
   exactly from its decimal representation.
*/

char *disassemble::garmin_print_float64 (float64 f, char *ret)
{
        if (!ret)
                return 0;

        if ( f > 10000000000000000.0 || f < -10000000000000000.0 )
           sprintf(ret,"%.17e",f);
        else if ( f > 1000000000000000.0 || f < -1000000000000000.0 )
           sprintf(ret,"%.1f",f);
        else if ( f > 100000000000000.0 || f < -100000000000000.0 )
           sprintf(ret,"%.2f",f);
        else if ( f > 10000000000000.0 || f < -10000000000000.0 )
           sprintf(ret,"%.3f",f);
        else if ( f > 1000000000000.0 || f < -1000000000000.0 )
           sprintf(ret,"%.4f",f);
        else if ( f > 100000000000.0 || f < -100000000000.0 )
           sprintf(ret,"%.5f",f);
        else if ( f > 10000000000.0 || f < -10000000000.0 )
           sprintf(ret,"%.6f",f);
        else if ( f > 1000000000.0 || f < -1000000000.0 )
           sprintf(ret,"%.7f",f);
        else if ( f > 100000000.0 || f < -100000000.0 )
           sprintf(ret,"%.8f",f);
        else if ( f > 10000000.0 || f < -10000000.0 )
           sprintf(ret,"%.9f",f);
        else if ( f > 1000000.0 || f < -1000000.0 )
           sprintf(ret,"%.10f",f);
        else if ( f > 100000.0 || f < -100000.0 )
           sprintf(ret,"%.11f",f);
        else if ( f > 10000.0 || f < -10000.0 )
           sprintf(ret,"%.12f",f);
        else if ( f > 1000.0 || f < -1000.0 )
           sprintf(ret,"%.13f",f);
        else if ( f > 100.0 || f < -100.0 )
           sprintf(ret,"%.14f",f);
        else if ( f > 10.0 || f < -10.0 )
           sprintf(ret,"%.15f",f);
        else if ( f > 1.0 || f < -1.0 )
           sprintf(ret,"%.16f",f);
        else if ( f > 0.1 || f < -0.1 )
           sprintf(ret,"%.17f",f);
        else if ( f != 0 )
           sprintf(ret,"%.17e",f);
        else
           sprintf(ret,"%.16f",f);

        return ret;
}


/* 
   Print a float32 whose value is invalid (and should not be printed) if 
   greater than 1.0e24 
*/

char *disassemble::garmin_print_dfloat32 (float32 f, char *ret)
{
        if (!ret)
           return NULL;

        if ( f < 1.0e24 )
           garmin_print_float32(f, ret);

        return ret;
}


/* Print a duration and distance. */

char *disassemble::garmin_print_ddist (uint32 dur, char *ret)
{
int  hun;
int  sec;
int  min;
int  hrs;

        if (!ret)
           return NULL;

        hun  = dur % 100;
        dur -= hun;
        dur /= 100;
        sec  = dur % 60;
        dur -= sec;
        dur /= 60;
        min  = dur % 60;
        dur -= min;
        dur /= 60;
        hrs  = dur;

        sprintf(ret,"%d:%02d:%02d.%02d", hrs, min, sec, hun);
        return ret;
}


/* --------------------------------------------------------------------------*/
/* 7.4.1  D100                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d100 (D100 *x)
{
        memset (&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 100;
        strncpy (waypoint.ident, x->ident, 5);
        waypoint.posn = x->posn;
        strncpy(waypoint.cmnt, x->cmnt, 40);
}


/* --------------------------------------------------------------------------*/
/* 7.4.2  D101                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d101 (D101 *x)
{
        memset (&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 101;
        strncpy (waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
        waypoint.posn = x->posn;
        strncpy (waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
        waypoint.dst = x->dst;
        waypoint.smbl = x->smbl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.3  D102                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d102 (D102 *x)
{
        garmin_print_d101 ((D101 *)x);
        waypoint.type = 102;
}


/* --------------------------------------------------------------------------*/
/* 7.4.4  D103                                                               */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d103 (D103 *x)
{
        garmin_print_d101((D101 *)x);
        waypoint.type = 103;
//      GARMIN_TAGSTR(1,"symbol",garmin_d103_smbl(x->smbl));
//      GARMIN_TAGSTR(1,"display",garmin_d103_dspl(x->dspl));
}


/* --------------------------------------------------------------------------*/
/* 7.4.5  D104                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d104 (D104 *x)
{
        garmin_print_d101((D101 *)x);
        waypoint.dspl = x->dspl;
        waypoint.type = 104;
//      GARMIN_TAGF32(1,"proximity_distance",x->dst);
//      GARMIN_TAGSTR(1,"display",garmin_d104_dspl(x->dspl));
}


/* --------------------------------------------------------------------------*/
/* 7.4.6  D105                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d105 (D105 *x)
{
        memset (&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 105;
        waypoint.wpt_ident = x->wpt_ident;
        waypoint.posn = x->posn;
        waypoint.smbl = x->smbl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.7  D106                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d106 (D106 *x)
{
        memset (&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 106;
        waypoint.wpt_class = x->wpt_class;
        waypoint.subclass[0] = 0;

        if ( x->wpt_class != 0 )
        {
           strncpy ((char *)waypoint.subclass, (char *)x->subclass, 13);
           waypoint.subclass[13] = 0;
        }

        waypoint.wpt_ident = x->wpt_ident;
        waypoint.posn = x->posn;
        waypoint.smbl = x->smbl;
        waypoint.lnk_ident = x->lnk_ident;
}


/* --------------------------------------------------------------------------*/
/* 7.4.8  D107                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d107 (D107 *x)
{
        memset (&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 107;
        strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
        waypoint.posn = x->posn;
        strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
        waypoint.dst = x->dst;
        waypoint.smbl = x->smbl;
        waypoint.dspl = x->dspl;
        waypoint.color = x->color;
}


/* --------------------------------------------------------------------------*/
/* 7.4.9  D108                                                               */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d108 (D108 *x)
{
        memset(&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 108;
        waypoint.identity = x->ident;
        waypoint.posn = x->posn;
        waypoint.comment = x->comment;
        waypoint.smbl = x->smbl;
        waypoint.dspl = x->dspl;
        waypoint.wpt_class = x->wpt_class;
        strncpy((char *)waypoint.subclass, (char *)x->subclass, 18);
        waypoint.attr = x->attr;
        waypoint.color = x->color;
        waypoint.alt = x->alt;
        waypoint.dpth = x->dpth;
        waypoint.dst = x->dist;
        waypoint.facility = x->facility;
        waypoint.city = x->city;
        waypoint.addr = x->addr;
        waypoint.cross_road = x->cross_road;
}


/* --------------------------------------------------------------------------*/
/* 7.4.10  D109                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d109 (D109 *x)
{
uint8 color = x->dspl_color & 0x1f;

        if (color == 0x1f)
           color = D108_default_color;

        memset(&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 109;
        waypoint.identity = x->ident;
        waypoint.posn = x->posn;
        waypoint.comment = x->comment;
        waypoint.smbl = x->smbl;
        waypoint.wpt_class = x->wpt_class;
        strncpy((char *)waypoint.subclass, (char *)x->subclass, 18);
        waypoint.attr = x->attr;
        waypoint.color = color;
        waypoint.alt = x->alt;
        waypoint.dtyp = x->dtyp;
        waypoint.ete = x->ete;
        waypoint.dpth = x->dpth;
        waypoint.dst = x->dist;
        waypoint.facility = x->facility;
        waypoint.city = x->city;
        waypoint.addr = x->addr;
        waypoint.cross_road = x->cross_road;
}


/* --------------------------------------------------------------------------*/
/* 7.4.11  D110                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d110 (D110 *x)
{
        memset(&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 110;
        waypoint.identity = x->ident;
        waypoint.posn = x->posn;
        waypoint.comment = x->comment;
        waypoint.smbl = x->smbl;
        waypoint.wpt_class = x->wpt_class;
        strncpy((char *)waypoint.subclass, (char *)x->subclass, 18);
        waypoint.attr = x->attr;
        waypoint.alt = x->alt;
        waypoint.dtyp = x->dtyp;
        waypoint.ete = x->ete;
        waypoint.dpth = x->dpth;
        waypoint.dst = x->dist;
        waypoint.facility = x->facility;
        waypoint.city = x->city;
        waypoint.addr = x->addr;
        waypoint.cross_road = x->cross_road;

/*  GARMIN_TAGSTR(1,"wpt_class",garmin_d110_wpt_class(x->wpt_class));
  GARMIN_TAGSTR(1,"color",garmin_d110_color((x->dspl_color) & 0x1f));
  GARMIN_TAGSTR(1,"display",garmin_d110_dspl((x->dspl_color >> 5) & 0x03));
  GARMIN_TAGSYM(1,"symbol",x->smbl);
  if ( x->temp < 1.0e24 ) GARMIN_TAGF32(1,"temperature",x->temp);
  GARMIN_TAGSTR(1,"state",x->state);
  GARMIN_TAGSTR(1,"country_code",x->cc);
  if ( x->time != 0xffffffff ) GARMIN_TAGU32(1,"time",x->time);
  GARMIN_TAGHEX(1,"category",x->wpt_cat); */
}


/* --------------------------------------------------------------------------*/
/* 7.4.12  D120                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d120 (D120 *x)
{
        memset(&wpcategory, 0, sizeof(WPCATEGORY));
        strncpy(wpcategory.name, x->name, 17);
}

 
/* --------------------------------------------------------------------------*/
/* 7.4.13  D150                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d150 (D150 *x)
{
        memset(&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 150;
        strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
        waypoint.wpt_class = x->wpt_class;
        waypoint.posn = x->posn;
        strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);

        if (x->wpt_class != D150_usr_wpt_class)
        {
           waypoint.city = x->city;
           strncpy(waypoint.state, x->state, 2);
           waypoint.facility = x->name;
           strncpy(waypoint.cc, x->cc, 2);
        }

        if (x->wpt_class == D150_apt_wpt_class)
           waypoint.alt = x->alt;
}


/* --------------------------------------------------------------------------*/
/* 7.4.14  D151                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d151 (D151 *x)
{
        memset(&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 151;
        strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
        waypoint.wpt_class = x->wpt_class;
        waypoint.posn = x->posn;
        strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
        waypoint.dst = x->dst;

        if (x->wpt_class != D150_usr_wpt_class)
        {
           waypoint.city = x->city;
           strncpy(waypoint.state, x->state, 2);
           waypoint.facility = x->name;
           strncpy(waypoint.cc, x->cc, 2);
        }

        if (x->wpt_class == D150_apt_wpt_class)
           waypoint.alt = x->alt;
}


/* --------------------------------------------------------------------------*/
/* 7.4.15  D152                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d152 (D152 *x)
{
        memset(&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 152;
        strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
        waypoint.wpt_class = x->wpt_class;
        waypoint.posn = x->posn;
        strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
        waypoint.dst = x->dst;

        if (x->wpt_class != D152_usr_wpt_class)
        {
           waypoint.city = x->city;
           strncpy(waypoint.state, x->state, 2);
           waypoint.facility = x->name;
           strncpy(waypoint.cc, x->cc, 2);
        }

        if (x->wpt_class == D152_apt_wpt_class)
           waypoint.alt = x->alt;
}


/* --------------------------------------------------------------------------*/
/* 7.4.16  D154                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d154 (D154 *x)
{
        memset(&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 154;
        strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
        waypoint.wpt_class = x->wpt_class;
        waypoint.posn = x->posn;
        strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
        waypoint.dst = x->dst;

        if (x->wpt_class != D154_usr_wpt_class)
        {
           waypoint.city = x->city;
           strncpy(waypoint.state, x->state, 2);
           waypoint.facility = x->name;
           strncpy(waypoint.cc, x->cc, 2);
        }

        if (x->wpt_class == D154_apt_wpt_class)
           waypoint.alt = x->alt;

        waypoint.smbl = x->smbl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.17  D155                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d155 (D155 *x)
{
        memset(&waypoint, 0, sizeof(WAYPOINT));
        waypoint.type = 155;
        strncpy(waypoint.ident, x->ident, sizeof(waypoint.ident)-1);
        waypoint.wpt_class = x->wpt_class;
        waypoint.posn = x->posn;
        strncpy(waypoint.cmnt, x->cmnt, sizeof(waypoint.cmnt)-1);
        waypoint.dst = x->dst;

        if (x->wpt_class != D155_usr_wpt_class)
        {
           waypoint.city = x->city;
           strncpy(waypoint.state, x->state, 2);
           waypoint.facility = x->name;
           strncpy(waypoint.cc, x->cc, 2);
        }

        if (x->wpt_class == D155_apt_wpt_class)
           waypoint.alt = x->alt;

        waypoint.smbl = x->smbl;
        waypoint.dspl = x->dspl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.18  D200                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d200 (D200 *x)
{
        route_header = *x;
}


/* --------------------------------------------------------------------------*/
/* 7.4.19  D201                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d201 (D201 *x)
{
        memset(&route, 0, sizeof(ROUTE));
        route.type = 201;
        route.nmbr = x->nmbr;
        strncpy(route.cmnt, x->cmnt, 20);
}


/* --------------------------------------------------------------------------*/
/* 7.4.20  D202                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d202 (D202 *x)
{
        memset(&route, 0, sizeof(ROUTE));
        route.type = 202;
        route.rte_ident = x->rte_ident;
}


/* --------------------------------------------------------------------------*/
/* 7.4.21  D210                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d210 (D210 *x)
{
        memset(&route_link, 0, sizeof(ROUTE_LINK));
        route_link.type = 210;
        route_link.klasse = x->klasse;
        route_link.ident = x->ident;
        strncpy((char *)route_link.subclass, (char *)x->subclass, 18);
}


/* --------------------------------------------------------------------------*/
/* 7.4.22  D300                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d300 (D300 *p)
{
        memset(&point, 0, sizeof(POINT));
        point.type = 300;
        point.time = p->time;
        point.posn = p->posn;
        point.new_trk = p->new_trk;
        addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.23  D301                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d301 (D301 *p)
{
        memset(&point, 0, sizeof(POINT));
        point.type = 301;
        point.time = p->time;
        point.posn = p->posn;
        point.new_trk = p->new_trk;
        point.alt = p->alt;
        point.dpth = p->dpth;
        addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.24  D302                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d302 (D302 *p)
{
        memset(&point, 0, sizeof(POINT));
        point.type = 302;
        point.time = p->time;
        point.posn = p->posn;
        point.new_trk = p->new_trk;
        point.alt = p->alt;
        point.dpth = p->dpth;
        point.temp = p->temp;
        addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.25  D303                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d303 (D303 *p)
{
        memset(&point, 0, sizeof(POINT));
        point.type = 303;
        point.time = p->time;
        point.posn = p->posn;
        point.alt = p->alt;
        point.heart_rate = p->heart_rate;
        addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.26  D304                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d304 (D304 *p)
{
        memset(&point, 0, sizeof(POINT));
        point.type = 304;
        point.time = p->time;
        point.posn = p->posn;
        point.alt = p->alt;
        point.heart_rate = p->heart_rate;
        point.distance = p->distance;
        point.cadence = p->cadence;
        point.sensor = p->sensor;
        addPoint();
}


/* --------------------------------------------------------------------------*/
/* 7.4.27  D310                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d310 (D310 *x)
{
        memset(&track, 0, sizeof(TRACK));
        track.type = 310;
        track.trk_ident = x->trk_ident;
        track.color = x->color;
        track.dspl = x->dspl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.28  D311                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d311 (D311 *h)
{
        memset(&track, 0, sizeof(TRACK));
        track.type = 311;
        track.index = h->index;
}


/* --------------------------------------------------------------------------*/
/* 7.4.29  D312                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d312 (D312 *h)
{
        memset(&track, 0, sizeof(TRACK));
        track.type = 312;
        track.trk_ident = h->trk_ident;
        track.color = h->color;
        track.dspl = h->dspl;
}


/* --------------------------------------------------------------------------*/
/* 7.4.30  D400                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d400 (D400 *x)
{
        garmin_print_d400((D400 *)&x->wpt);
        waypoint.type = 400;
        waypoint.dst = x->dst;
}


/* --------------------------------------------------------------------------*/
/* 7.4.31  D403                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d403 (D403 *x)
{
        garmin_print_d103(&x->wpt);
        waypoint.type = 403;
        waypoint.dst = x->dst;
}


/* --------------------------------------------------------------------------*/
/* 7.4.32  D450                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d450 (D450 *x)
{
        garmin_print_d150(&x->wpt);
        waypoint.type = 450;
        waypoint.dst = x->dst;
        waypoint.idx = x->idx;
}


/* --------------------------------------------------------------------------*/
/* 7.4.33  D500                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d500 (D500 *x)
{
        memset(&almanac, 0, sizeof(ALMANAC));
        almanac.type = 500;
        almanac.wn = x->wn;
        almanac.toa = x->toa;
        almanac.af0 = x->af0;
        almanac.af1 = x->af1;
        almanac.e = x->e;
        almanac.sqrta = x->sqrta;
        almanac.m0 = x->m0;
        almanac.w = x->w;
        almanac.omg0 = x->omg0;
        almanac.odot = x->odot;
        almanac.i = x->i;
}


/* --------------------------------------------------------------------------*/
/* 7.4.34  D501                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d501 (D501 *x)
{
        memset(&almanac, 0, sizeof(ALMANAC));
        almanac.type = 501;
        almanac.wn = x->wn;
        almanac.toa = x->toa;
        almanac.af0 = x->af0;
        almanac.af1 = x->af1;
        almanac.e = x->e;
        almanac.sqrta = x->sqrta;
        almanac.m0 = x->m0;
        almanac.w = x->w;
        almanac.omg0 = x->omg0;
        almanac.odot = x->odot;
        almanac.i = x->i;
        almanac.hlth = x->hlth;
}


/* --------------------------------------------------------------------------*/
/* 7.4.35  D550                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d550 (D550 *x)
{
        memset(&almanac, 0, sizeof(ALMANAC));
        almanac.type = 550;
        almanac.wn = x->wn;
        almanac.toa = x->toa;
        almanac.af0 = x->af0;
        almanac.af1 = x->af1;
        almanac.e = x->e;
        almanac.sqrta = x->sqrta;
        almanac.m0 = x->m0;
        almanac.w = x->w;
        almanac.omg0 = x->omg0;
        almanac.odot = x->odot;
        almanac.i = x->i;
        almanac.svid = x->svid;
}


/* --------------------------------------------------------------------------*/
/* 7.4.36  D551                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d551 (D551 *x)
{
        memset(&almanac, 0, sizeof(ALMANAC));
        almanac.type = 551;
        almanac.wn = x->wn;
        almanac.toa = x->toa;
        almanac.af0 = x->af0;
        almanac.af1 = x->af1;
        almanac.e = x->e;
        almanac.sqrta = x->sqrta;
        almanac.m0 = x->m0;
        almanac.w = x->w;
        almanac.omg0 = x->omg0;
        almanac.odot = x->odot;
        almanac.i = x->i;
        almanac.svid = x->svid;
        almanac.hlth = x->hlth;
}


/* --------------------------------------------------------------------------*/
/* 7.4.37  D600                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d600 (D600 *x)
{
        datetime.year = x->year;
        datetime.month = x->month;
        datetime.day = x->day;
        datetime.hour = x->hour;
        datetime.minute = x->minute;
        datetime.second = x->second;
}


/* --------------------------------------------------------------------------*/
/* 7.4.38  D650                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d650 (D650 *x)
{
        memset(&flightbook, 0, sizeof(FLIGHTBOOK));
        flightbook.type = 650;
        flightbook.takeoff_time = x->takeoff_time;
        flightbook.landing_time = x->landing_time;
        flightbook.takeoff_posn = x->takeoff_posn;
        flightbook.landing_posn = x->landing_posn;
        flightbook.night_time = x->night_time;
        flightbook.num_landings = x->num_landings;
        flightbook.max_speed = x->max_speed;
        flightbook.max_alt = x->max_alt;
        flightbook.distance = x->distance;
        flightbook.cross_country_flag = x->cross_country_flag;
        flightbook.departure_name = x->departure_name;
        flightbook.departure_ident = x->departure_ident;
        flightbook.arrival_name = x->arrival_name;
        flightbook.arrival_ident = x->arrival_ident;
        flightbook.ac_id = x->ac_id;
}


/* ------------------------------------------------------------------------- */
/* 7.4.39  D700                                                              */
/* ------------------------------------------------------------------------- */

void disassemble::garmin_print_d700 (D700 *x)
{
        rpt.lat = x->lat;
        rpt.lon = x->lon;
}


/* --------------------------------------------------------------------------*/
/* 7.4.40  D800                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d800 (D800 *x)
{
        memset(&pvt, 0, sizeof(PVT));
        pvt.alt = x->alt;
        pvt.epe = x->epe;
        pvt.eph = x->eph;
        pvt.epv = x->epv;
        pvt.fix = x->fix;
        pvt.posn.lat = x->posn.lat;
        pvt.posn.lon = x->posn.lon;
        pvt.east = x->east;
        pvt.north = x->north;
        pvt.up = x->up;
        pvt.msl_hght = x->msl_hght;
        pvt.leap_scnds = x->leap_scnds;
        pvt.wn_days = x->wn_days;
        pvt.tow = x->tow;
}


/* --------------------------------------------------------------------------*/
/* 7.4.41  D906                                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d906 (D906 *x)
{
        memset (&lap, 0, sizeof(LAP));
        lap.type = 906;
        lap.start_time = x->start_time;
        lap.total_time = x->total_time;
        lap.total_distance = x->total_distance;
        lap.begin.lat = x->begin.lat;
        lap.begin.lon = x->begin.lon;
        lap.end.lat = x->end.lat;
        lap.end.lon = x->end.lon;
        lap.calories = x->calories;
        lap.track_index = x->track_index;
        addLap();
}


/* --------------------------------------------------------------------------*/
/* 7.4.42  D1000                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1000 (D1000 *x)
{
        memset(&run, 0, sizeof(RUN));
        garmin_print_d1002((D1002 *)&x->workout);
        run.type = 1000;
        run.track_index = x->track_index;
        run.sport_type = x->sport_type;
        run.first_lap_index = x->first_lap_index;
        run.last_lap_index = x->last_lap_index;
        run.program_type = x->program_type;
        run.virtual_partner.time = x->virtual_partner.time;
        run.virtual_partner.distance = x->virtual_partner.distance;
        addRun();
}


/* --------------------------------------------------------------------------*/
/* 7.4.43  D1001                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1001 (D1001 *x)
{
        memset(&lap, 0, sizeof(LAP));
        lap.type = 1001;
        lap.start_time = x->start_time;
        lap.total_time = x->total_time;
        lap.total_distance = x->total_dist;
        lap.begin.lat = x->begin.lat;
        lap.begin.lon = x->begin.lon;
        lap.end.lat = x->end.lat;
        lap.end.lon = x->end.lon;
        lap.calories = x->calories;
        lap.index = x->index;
        lap.max_speed = x->max_speed;
        lap.avg_heart_rate = x->avg_heart_rate;
        lap.max_heart_rate = x->max_heart_rate;
        lap.intensity = x->intensity;
        addLap();
}


/* --------------------------------------------------------------------------*/
/* 7.4.44  D1002                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1002 (D1002 *x)
{
unsigned int i;

        memset (&workout, 0, sizeof(WORKOUT));
        workout.type = 1002;
        strncpy (workout.name, x->name, 16);
        workout.num_valid_steps = x->num_valid_steps;

        if (x->num_valid_steps > 0)
        {
           for (i = 0; i < x->num_valid_steps; i++)
           {
              if (i >= 20)
                 break;

              strncpy (workout.steps[i].custom_name, x->steps[i].custom_name, 16);
              workout.steps[i].intensity = x->steps[i].intensity;
              workout.steps[i].duration_type = x->steps[i].duration_type;
              workout.steps[i].duration_value = x->steps[i].duration_value;
              workout.steps[i].target_type = x->steps[i].target_type;
              workout.steps[i].target_value = x->steps[i].target_value;
              workout.steps[i].target_custom_zone_low = x->steps[i].target_custom_zone_low;
              workout.steps[i].target_custom_zone_high = x->steps[i].target_custom_zone_high;
           }
        }
}


/* --------------------------------------------------------------------------*/
/* 7.4.45  D1003                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1003 (D1003 *x)
{
        memset (&workout, 0, sizeof(WORKOUT));
        workout.type = 1003;
        strncpy (workout.workout_name, x->workout_name, 16);
        workout.day = x->day;
}


/* --------------------------------------------------------------------------*/
/* 7.4.46  D1004                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1004 (D1004 *d)
{
int i;
int j;

        memset (&fitness, 0, sizeof(FITNESS));
        fitness.type = 1004;
        fitness.weight = d->weight;
        fitness.birth_year = d->birth_year;
        fitness.birth_month = d->birth_month;
        fitness.birth_day = d->birth_day;
        fitness.gender = d->gender;

        for (i = 0; i < 3; i++)
        {
           fitness.activities[i].gear_weight = d->activities[i].gear_weight;
           fitness.activities[i].max_heart_rate = d->activities[i].max_heart_rate;

           for (j = 0; j < 5; j++)
           {
              fitness.activities[i].heart_rate_zones[j].low_heart_rate = d->activities[i].heart_rate_zones[j].low_heart_rate;
              fitness.activities[i].heart_rate_zones[j].high_heart_rate = d->activities[i].heart_rate_zones[j].high_heart_rate;
           }

           for (j = 0; j < 10; j++)
           {
              fitness.activities[i].speed_zones[j].low_speed = d->activities[i].speed_zones[j].low_speed;
              fitness.activities[i].speed_zones[j].high_speed = d->activities[i].speed_zones[j].high_speed;
              strncpy (fitness.activities[i].speed_zones[j].name, d->activities[i].speed_zones[j].name, 16);
           }
        }
}


/* --------------------------------------------------------------------------*/
/* 7.4.47  D1005                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1005 (D1005 *limits)
{
        memset (&workout, 0, sizeof(WORKOUT));
        workout.type = 1005;
        workout.max_workouts = limits->max_workouts;
        workout.max_unscheduled_workouts = limits->max_unscheduled_workouts;
        workout.max_occurrences = limits->max_occurrences;
}


/* --------------------------------------------------------------------------*/
/* 7.4.48  D1006                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1006 (D1006 *x)
{
        memset (&course, 0, sizeof(COURSE));
        course.type = 1006;
        course.index = x->index;
        strncpy(course.course_name, x->course_name, 16);
        course.track_index = x->track_index;
}


/* --------------------------------------------------------------------------*/
/* 7.4.49  D1007                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1007 (D1007 *x)
{
        memset (&course, 0, sizeof(COURSE));
        course.type = 1007;
        course.course_index = x->course_index;
        course.lap_index = x->lap_index;
        course.total_time = x->total_time;
        course.total_dist = x->total_dist;
        course.begin.lat = x->begin.lat;
        course.begin.lon = x->begin.lon;
        course.end.lat = x->end.lat;
        course.end.lon = x->end.lon;
        course.avg_heart_rate = x->avg_heart_rate;
        course.max_heart_rate = x->max_heart_rate;
        course.avg_cadence = x->avg_cadence;
        course.intensity = x->intensity;
}


/* --------------------------------------------------------------------------*/
/* 7.4.50  D1008                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1008 (D1008 *w)
{
        /* For some reason, D1008 is identical to D1002. */
        garmin_print_d1002((D1002 *)w);
        workout.type = 1008;
}


/* --------------------------------------------------------------------------*/
/* 7.4.51  D1009                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1009 (D1009 *x)
{
        memset(&run, 0, sizeof(RUN));
        garmin_print_d1002((D1002 *)&x->workout);
        memmove (&run.workout, &workout, sizeof (WORKOUT));
        run.type = 1009;
        run.track_index = x->track_index;
        run.sport_type = x->sport_type;
        run.first_lap_index = x->first_lap_index;
        run.last_lap_index = x->last_lap_index;
        run.program_type = x->program_type;
        run.virtual_partner.time = x->quick_workout.time;
        run.virtual_partner.distance = x->quick_workout.distance;
        run.multisport = x->multisport;
        addRun();
}


/* --------------------------------------------------------------------------*/
/* 7.4.52  D1010                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1010 (D1010 *x)
{
        memset(&run, 0, sizeof(RUN));
        garmin_print_d1002((D1002 *)&x->workout);
        run.type = 1010;
        run.track_index = x->track_index;
        run.sport_type = x->sport_type;
        run.first_lap_index = x->first_lap_index;
        run.last_lap_index = x->last_lap_index;
        run.program_type = x->program_type;
        run.virtual_partner.time = x->virtual_partner.time;
        run.virtual_partner.distance = x->virtual_partner.distance;
        run.multisport = x->multisport;
        addRun();
}


/* --------------------------------------------------------------------------*/
/* 7.4.53  D1011                                                             */
/* --------------------------------------------------------------------------*/


void disassemble::garmin_print_d1011 (D1011 *x)
{
        memset(&lap, 0, sizeof(LAP));
        lap.type = 1011;
        lap.start_time = x->start_time;
        lap.total_time = x->total_time;
        lap.total_distance = x->total_dist;
        lap.begin.lat = x->begin.lat;
        lap.begin.lon = x->begin.lon;
        lap.end.lat = x->end.lat;
        lap.end.lon = x->end.lon;
        lap.calories = x->calories;
        lap.index = x->index;
        lap.max_speed = x->max_speed;
        lap.avg_heart_rate = x->avg_heart_rate;
        lap.max_heart_rate = x->max_heart_rate;
        lap.intensity = x->intensity;
        lap.avg_cadence = x->avg_cadence;
        lap.trigger_method = x->trigger_method;
        addLap();
}


/* --------------------------------------------------------------------------*/
/* 7.4.54  D1012                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1012 (D1012 *x)
{
        memset (&course, 0, sizeof(COURSE));
        course.type = 1012;
        course.course_index = x->course_index;
        strncpy (course.course_name, x->name, 11);
        course.track_point_time = x->track_point_time;
        course.point_type = x->point_type;
}


/* --------------------------------------------------------------------------*/
/* 7.4.55  D1013                                                             */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1013 (D1013 *x)
{
        memset (&course, 0, sizeof(COURSE));
        course.type = 1012;
        course.max_courses = x->max_courses;
        course.max_course_laps = x->max_course_laps;
        course.max_course_pnt = x->max_course_pnt;
        course.max_course_trk_pnt = x->max_course_trk_pnt;
}


/* --------------------------------------------------------------------------*/
/* 7.4.XX  D1015 (Undocumented)                                              */
/* --------------------------------------------------------------------------*/

void disassemble::garmin_print_d1015 (D1015 *x)
{
        memset(&lap, 0, sizeof(LAP));
        lap.type = 1011;
        lap.start_time = x->start_time;
        lap.total_time = x->total_time;
        lap.total_distance = x->total_dist;
        lap.begin.lat = x->begin.lat;
        lap.begin.lon = x->begin.lon;
        lap.end.lat = x->end.lat;
        lap.end.lon = x->end.lon;
        lap.calories = x->calories;
        lap.index = x->index;
        lap.max_speed = x->max_speed;
        lap.avg_heart_rate = x->avg_heart_rate;
        lap.max_heart_rate = x->max_heart_rate;
        lap.intensity = x->intensity;
        lap.avg_cadence = x->avg_cadence;
        lap.trigger_method = x->trigger_method;
        addLap();
}


/* ========================================================================= */
/* garmin_print_data                                                         */
/* ========================================================================= */

void disassemble::garmin_print_data (garmin_data *d)
{
        if (!d || !d->data)
           return;

#define CASE_PRINT(x) \
  case data_D##x: garmin_print_d##x((D##x *)d->data); break

        switch (d->type)
        {
           case data_Dlist:
              garmin_print_dlist ((garmin_list *)d->data);
           break;

           CASE_PRINT(100);
           CASE_PRINT(101);
           CASE_PRINT(102);
           CASE_PRINT(103);
           CASE_PRINT(104);
           CASE_PRINT(105);
           CASE_PRINT(106);
           CASE_PRINT(107);
           CASE_PRINT(108);
           CASE_PRINT(109);
           CASE_PRINT(110);
           CASE_PRINT(120);
           CASE_PRINT(150);
           CASE_PRINT(151);
           CASE_PRINT(152);
           CASE_PRINT(154);
           CASE_PRINT(155);
           CASE_PRINT(200);
           CASE_PRINT(201);
           CASE_PRINT(202);
           CASE_PRINT(210);
           CASE_PRINT(300);
           CASE_PRINT(301);
           CASE_PRINT(302);
           CASE_PRINT(303);
           CASE_PRINT(304);
           CASE_PRINT(310);
           CASE_PRINT(311);
           CASE_PRINT(312);
           CASE_PRINT(400);
           CASE_PRINT(403);
           CASE_PRINT(450);
           CASE_PRINT(500);
           CASE_PRINT(501);
           CASE_PRINT(550);
           CASE_PRINT(551);
           CASE_PRINT(600);
           CASE_PRINT(650);
           CASE_PRINT(700);
           CASE_PRINT(800);
           CASE_PRINT(906);
           CASE_PRINT(1000);
           CASE_PRINT(1001);
           CASE_PRINT(1002);
           CASE_PRINT(1003);
           CASE_PRINT(1004);
           CASE_PRINT(1005);
           CASE_PRINT(1006);
           CASE_PRINT(1007);
           CASE_PRINT(1008);
           CASE_PRINT(1009);
           CASE_PRINT(1010);
           CASE_PRINT(1011);
           CASE_PRINT(1012);
           CASE_PRINT(1013);
           CASE_PRINT(1015);
           default: break;
        }

#undef CASE_PRINT
}

/*
 * The following functions are to calculate some GPS related parameters.
 * Base is the WGS84 date.
 *
 * This functions are not needed tho handle the files and data out of
 * the GPS-device!
 */
double disassemble::CalcRad(double lat)
/* earth's radius of curvature in meters at specified latitude.*/
{
const double a = 6378.137;
const double e2 = 0.081082 * 0.081082;

        /*
         * the radius of curvature of an ellipsoidal Earth in the plane of a
         * meridian of latitude is given by
         *
         * R' = a * (1 - e^2) / (1 - e^2 * (sin(lat))^2)^(3/2)
         *
         * where a is the equatorial radius,
         * b is the polar radius, and
         * e is the eccentricity of the ellipsoid = sqrt(1 - b^2/a^2)
         *
         * a = 6378 km (3963 mi) Equatorial radius (surface to center distance)
         * b = 6356.752 km (3950 mi) Polar radius (surface to center distance)
         * e = 0.081082 Eccentricity
         */
        double sc = sin(Deg2Rad(lat));
        double x = a * (1.0 - e2);
        double z = 1.0 - e2 * sc * sc;
        double y = pow(z, 1.5);
        double r = x / y;

        return r * 1000.0; // Convert to meters
}

double disassemble::earth_distance(double lat1, double lon1, double lat2, double lon2)
/* distance in meters between two points specified in degrees. */
{
double x1 = CalcRad(lat1) * cos(Deg2Rad(lon1)) * sin(Deg2Rad(90-lat1));
double x2 = CalcRad(lat2) * cos(Deg2Rad(lon2)) * sin(Deg2Rad(90-lat2));
double y1 = CalcRad(lat1) * sin(Deg2Rad(lon1)) * sin(Deg2Rad(90-lat1));
double y2 = CalcRad(lat2) * sin(Deg2Rad(lon2)) * sin(Deg2Rad(90-lat2));
double z1 = CalcRad(lat1) * cos(Deg2Rad(90-lat1));
double z2 = CalcRad(lat2) * cos(Deg2Rad(90-lat2));
double a = (x1*x2 + y1*y2 + z1*z2)/pow(CalcRad((lat1+lat2)/2),2);

        // a should be in [1, -1] but can sometimes fall outside it by
        // a very small amount due to rounding errors in the preceding
        // calculations (this is prone to happen when the argument points
        // are very close together). Thus we constrain it here.
        if (abs(a) > 1)
           a = 1;
        else if (a < -1)
           a = -1;

        return CalcRad((lat1+lat2) / 2) * acos(a);
}