Rev 142 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include "garmin.h"
/* ------------------------------------------------------------------------- */
/* Assign an application protocol to the Garmin unit. */
/* ------------------------------------------------------------------------- */
static void
garmin_assign_protocol ( garmin_unit * garmin,
uint16 protocol,
uint16 * datatypes )
{
if (!garmin)
return;
/* Unknown protocols and their data types are ignored. */
switch ( protocol ) {
case appl_A010:
case appl_A011:
garmin->protocol.command = protocol;
break;
case appl_A100:
garmin->protocol.waypoint.waypoint = protocol;
garmin->datatype.waypoint.waypoint = datatypes[0];
break;
case appl_A101:
garmin->protocol.waypoint.category = protocol;
garmin->datatype.waypoint.category = datatypes[0];
break;
case appl_A200:
garmin->protocol.route = protocol;
garmin->datatype.route.header = datatypes[0];
garmin->datatype.route.waypoint = datatypes[1];
case appl_A201:
garmin->protocol.route = protocol;
garmin->datatype.route.header = datatypes[0];
garmin->datatype.route.waypoint = datatypes[1];
garmin->datatype.route.link = datatypes[2];
break;
case appl_A300:
garmin->protocol.track = protocol;
garmin->datatype.track.data = datatypes[0];
break;
case appl_A301:
case appl_A302:
garmin->protocol.track = protocol;
garmin->datatype.track.header = datatypes[0];
garmin->datatype.track.data = datatypes[1];
break;
case appl_A400:
garmin->protocol.waypoint.proximity = protocol;
garmin->datatype.waypoint.proximity = datatypes[0];
break;
case appl_A500:
garmin->protocol.almanac = protocol;
garmin->datatype.almanac = datatypes[0];
break;
case appl_A600:
garmin->protocol.date_time = protocol;
garmin->datatype.date_time = datatypes[0];
break;
case appl_A601:
/* --- UNDOCUMENTED --- */
break;
case appl_A650:
garmin->protocol.flightbook = protocol;
garmin->datatype.flightbook = datatypes[0];
break;
case appl_A700:
garmin->protocol.position = protocol;
garmin->datatype.position = datatypes[0];
break;
case appl_A800:
garmin->protocol.pvt = protocol;
garmin->datatype.pvt = datatypes[0];
break;
case appl_A801:
/* --- UNDOCUMENTED --- */
break;
case appl_A902:
/* --- UNDOCUMENTED --- */
break;
case appl_A903:
/* --- UNDOCUMENTED --- */
break;
case appl_A906:
garmin->protocol.lap = protocol;
garmin->datatype.lap = datatypes[0];
break;
case appl_A907:
/* --- UNDOCUMENTED --- */
break;
case appl_A1000:
garmin->protocol.run = protocol;
garmin->datatype.run = datatypes[0];
break;
case appl_A1002:
garmin->protocol.workout.workout = protocol;
garmin->datatype.workout.workout = datatypes[0];
break;
case appl_A1003:
garmin->protocol.workout.occurrence = protocol;
garmin->datatype.workout.occurrence = datatypes[0];
break;
case appl_A1004:
garmin->protocol.fitness = protocol;
garmin->datatype.fitness = datatypes[0];
break;
case appl_A1005:
garmin->protocol.workout.limits = protocol;
garmin->datatype.workout.limits = datatypes[0];
break;
case appl_A1006:
garmin->protocol.course.course = protocol;
garmin->datatype.course.course = datatypes[0];
break;
case appl_A1007:
garmin->protocol.course.lap = protocol;
garmin->datatype.course.lap = datatypes[0];
break;
case appl_A1008:
garmin->protocol.course.point = protocol;
garmin->datatype.course.point = datatypes[0];
case appl_A1009:
garmin->protocol.course.limits = protocol;
garmin->datatype.course.limits = datatypes[0];
break;
case appl_A1012:
garmin->protocol.course.track = protocol;
garmin->datatype.course.track.header = datatypes[0];
garmin->datatype.course.track.data = datatypes[1];
break;
default:
break;
}
}
static char **
merge_strings ( char ** one, char ** two )
{
int i;
int n1;
int n2;
char ** pos;
char ** ret = NULL;
if (!one || !two) return ret;
for ( pos = one, n1 = 0; pos && *pos; pos++, n1++ );
for ( pos = two, n2 = 0; pos && *pos; pos++, n2++ );
if ( n1 + n2 > 0 ) {
ret = calloc(n1+n2+1,sizeof(char *));
for ( i = 0; i < n1; i++ ) ret[i] = one[i];
for ( i = 0; i < n2; i++ ) ret[n1+i] = two[i];
if ( one != NULL ) free(one);
if ( two != NULL ) free(two);
}
return ret;
}
/* Read a single packet with an expected packet ID and data type. */
static garmin_data *
garmin_read_singleton ( garmin_unit * garmin,
garmin_pid pid,
garmin_datatype type )
{
garmin_data * d = NULL;
garmin_packet p;
link_protocol link;
garmin_pid ppid;
char hv0[256];
if (!garmin) return NULL;
link = garmin->protocol.link;
if ( garmin_read(garmin,&p) > 0 ) {
ppid = garmin_gpid(link,garmin_packet_id(&p));
if ( ppid == pid ) {
d = garmin_unpack_packet(&p,type);
} else {
/* Expected pid but got something else. */
sprintf(hv0, "garmin_read_singleton: expected %d, got %d!",pid,ppid);
garmin_queue_error(hv0, err_warning);
}
} else {
/* Failed to read the packet off the link. */
sprintf(hv0, "garmin_read_singleton: failed to read Pid_Records packet!");
garmin_queue_error(hv0, err_warning);
}
return d;
}
/* Read a Pid_Records, (pid)+, Pid_Xfer_Cmplt sequence. */
static garmin_data *
garmin_read_records ( garmin_unit * garmin,
garmin_pid pid,
garmin_datatype type )
{
garmin_data * d = NULL;
garmin_list * l = NULL;
garmin_packet p;
link_protocol link;
int done = 0;
int expected = 0;
int got = 0;
garmin_pid ppid;
char hv0[256];
if (!garmin) return NULL;
link = garmin->protocol.link;
if ( garmin_read(garmin,&p) > 0 ) {
ppid = garmin_gpid(link,garmin_packet_id(&p));
if ( ppid == Pid_Records ) {
expected = get_uint16(p.packet.data);
if ( garmin->verbose != 0 ) {
sprintf(hv0, "[garmin] Pid_Records indicates %d packets to follow!",
expected);
garmin_queue_error(hv0, err_info);
}
/* Allocate a list for the records. */
d = garmin_alloc_data(data_Dlist);
l = (garmin_list *)d->data;
/*
Now we expect packets with the given packet_id and datatype, up
until the final packet, which is a Pid_Xfer_Cmplt.
*/
while ( !done && garmin_read(garmin,&p) > 0 ) {
ppid = garmin_gpid(link,garmin_packet_id(&p));
if ( ppid == Pid_Xfer_Cmplt ) {
if ( got != expected ) {
/* Incorrect number of packets received. */
sprintf(hv0, "garmin_read_records: expected %d packets, got %d!",
expected,got);
garmin_queue_error(hv0, err_error);
} else if ( garmin->verbose != 0 ) {
sprintf(hv0, "[garmin] all %d expected packets received!",got);
garmin_queue_error(hv0, err_info);
}
done = 1;
} else if ( ppid == pid ) {
garmin_list_append(l,garmin_unpack_packet(&p,type));
got++;
} else {
/* Unexpected packet ID! */
done = 1;
}
}
} else {
/* Expected Pid_Records but got something else. */
sprintf(hv0, "garmin_read_records: expected Pid_Records, got %d!",ppid);
garmin_queue_error(hv0, err_error);
}
} else {
/* Failed to read the Pid_Records packet off the link. */
sprintf(hv0, "garmin_read_records: failed to read Pid_Records packet!");
garmin_queue_error(hv0, err_error);
}
garmin_callback("read_records");
return d;
}
/* Read a Pid_Records, (pid1, (pid2)+)+, Pid_Xfer_Cmplt sequence. */
static garmin_data *
garmin_read_records2 ( garmin_unit * garmin,
garmin_pid pid1,
garmin_datatype type1,
garmin_pid pid2,
garmin_datatype type2 )
{
garmin_data * d = NULL;
garmin_list * l = NULL;
garmin_packet p;
link_protocol link;
int expected = 0;
int got = 0;
int state = 0;
garmin_pid ppid;
char hv0[256];
if (!garmin) return NULL;
link = garmin->protocol.link;
if ( garmin_read(garmin,&p) > 0 ) {
ppid = garmin_gpid(link,garmin_packet_id(&p));
if ( ppid == Pid_Records ) {
expected = get_uint16(p.packet.data);
if ( garmin->verbose != 0 ) {
sprintf(hv0, "[garmin] Pid_Records indicates %d packets to follow!",
expected);
garmin_queue_error(hv0, err_info);
}
/* Allocate a list for the records. */
d = garmin_alloc_data(data_Dlist);
l = (garmin_list *)d->data;
while ( state >= 0 && garmin_read(garmin,&p) > 0 ) {
ppid = garmin_gpid(link,garmin_packet_id(&p));
if ( ppid == Pid_Xfer_Cmplt ) {
/* transfer complete! */
if ( got != expected ) {
/* wrong number of packets received! */
sprintf(hv0, "garmin_read_records2: expected %d packets, got %d!",
expected,got);
garmin_queue_error(hv0, err_error);
} else if ( garmin->verbose != 0 ) {
sprintf(hv0, "[garmin] all %d expected packets received!",got);
garmin_queue_error(hv0, err_info);
}
break;
}
switch ( state ) {
case 0: /* want pid1 */
if ( ppid == pid1 ) {
garmin_list_append(l,garmin_unpack_packet(&p,type1));
state = 1;
got++;
} else {
state = -1;
}
break;
case 1: /* want pid2 */
if ( ppid == pid2 ) {
garmin_list_append(l,garmin_unpack_packet(&p,type2));
state = 2;
got++;
} else {
state = -1;
}
break;
case 2: /* want pid2 or pid1 */
if ( ppid == pid1 ) {
garmin_list_append(l,garmin_unpack_packet(&p,type1));
state = 1;
got++;
} else if ( ppid == pid2 ) {
garmin_list_append(l,garmin_unpack_packet(&p,type2));
state = 2;
got++;
} else {
state = -1;
}
break;
default:
state = -1;
break;
}
}
if ( state < 0 ) {
/* Unexpected packet received. */
sprintf(hv0, "garmin_read_records2: unexpected packet %d received!",ppid);
garmin_queue_error(hv0, err_error);
}
} else {
/* Expected Pid_Records but got something else. */
sprintf(hv0, "garmin_read_records2: expected Pid_Records, got %d!",ppid);
garmin_queue_error(hv0, err_error);
}
} else {
/* Failed to read the Pid_Records packet off the link. */
sprintf(hv0, "garmin_read_records2: failed to read Pid_Records packet!");
garmin_queue_error(hv0, err_error);
}
garmin_callback("read_records2");
return d;
}
/* Read a Pid_Records, (pid1, (pid2, pid3)+)+, Pid_Xfer_Cmplt sequence. */
static garmin_data *
garmin_read_records3 ( garmin_unit * garmin,
garmin_pid pid1,
garmin_datatype type1,
garmin_pid pid2,
garmin_datatype type2,
garmin_pid pid3,
garmin_datatype type3 )
{
garmin_data * d = NULL;
garmin_list * l = NULL;
garmin_packet p;
link_protocol link;
int expected = 0;
int got = 0;
garmin_pid ppid;
int state = 0;
char hv0[256];
if (!garmin) return NULL;
link = garmin->protocol.link;
if ( garmin_read(garmin,&p) > 0 ) {
ppid = garmin_gpid(link,garmin_packet_id(&p));
if ( ppid == Pid_Records ) {
expected = get_uint16(p.packet.data);
if ( garmin->verbose != 0 ) {
sprintf(hv0, "[garmin] Pid_Records indicates %d packets to follow!",
expected);
garmin_queue_error(hv0, err_info);
}
/* Allocate a list for the records. */
d = garmin_alloc_data(data_Dlist);
l = (garmin_list *)d->data;
while ( state >= 0 && garmin_read(garmin,&p) > 0 ) {
ppid = garmin_gpid(link,garmin_packet_id(&p));
if ( ppid == Pid_Xfer_Cmplt ) {
/* transfer complete! */
if ( got != expected ) {
/* wrong number of packets received! */
sprintf(hv0, "garmin_read_records3: expected %d packets, got %d!",
expected,got);
garmin_queue_error(hv0, err_error);
} else if ( garmin->verbose != 0 ) {
sprintf(hv0, "[garmin] all %d expected packets received!",got);
garmin_queue_error(hv0, err_info);
}
break;
}
switch ( state ) {
case 0: /* want pid1 */
if ( ppid == pid1 ) {
garmin_list_append(l,garmin_unpack_packet(&p,type1));
state = 1;
got++;
} else {
state = -1;
}
break;
case 1: /* want pid2 */
if ( ppid == pid2 ) {
garmin_list_append(l,garmin_unpack_packet(&p,type2));
state = 2;
got++;
} else {
state = -1;
}
break;
case 2: /* want pid3 */
if ( ppid == pid3 ) {
garmin_list_append(l,garmin_unpack_packet(&p,type3));
state = 3;
got++;
} else {
state = -1;
}
break;
case 3: /* want pid2 or pid1 */
if ( ppid == pid1 ) {
garmin_list_append(l,garmin_unpack_packet(&p,type1));
state = 1;
got++;
} else if ( ppid == pid2 ) {
garmin_list_append(l,garmin_unpack_packet(&p,type2));
state = 2;
got++;
} else {
state = -1;
}
break;
default:
state = -1;
break;
}
}
if ( state < 0 ) {
/* Unexpected packet received. */
sprintf(hv0, "garmin_read_records3: unexpected packet %d received!",ppid);
garmin_queue_error(hv0, err_error);
}
} else {
/* Expected Pid_Records but got something else. */
sprintf(hv0, "garmin_read_records3: expected Pid_Records, got %d!",ppid);
garmin_queue_error(hv0, err_error);
}
} else {
/* Failed to read the Pid_Records packet off the link. */
sprintf(hv0, "garmin_read_records3: failed to read Pid_Records packet!");
garmin_queue_error(hv0, err_error);
}
garmin_callback("read_records3");
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.1 A000 - Product Data Protocol */
/* 6.2 A001 - Protocol Capability Protocol */
/* ------------------------------------------------------------------------- */
void
garmin_read_a000_a001 ( garmin_unit * garmin )
{
garmin_packet p;
garmin_product * r;
garmin_extended_data * e;
int done = 0;
int pos;
int size;
int i;
int j;
uint8 tag;
uint16 data;
uint16 * datatypes;
if (!garmin) return;
/* Send the product request */
garmin_packetize(&p,L000_Pid_Product_Rqst,0,NULL);
garmin_write(garmin,&p);
/* Read the response. */
while ( !done && garmin_read(garmin,&p) > 0 ) {
switch ( garmin_packet_id(&p) ) {
case L000_Pid_Product_Data:
r = &garmin->product;
/* product ID, software version, product description, additional data. */
r->product_id = get_uint16(p.packet.data);
r->software_version = get_sint16(p.packet.data+2);
pos = 4;
if ( r->product_description != NULL ) {
free(r->product_description);
}
r->product_description = get_string(&p,&pos);
r->additional_data = merge_strings(r->additional_data,
get_strings(&p,&pos));
break;
case L000_Pid_Ext_Product_Data:
e = &garmin->extended;
/* These strings should be ignored, but we save them anyway. */
pos = 0;
e->ext_data = merge_strings(e->ext_data,get_strings(&p,&pos));
break;
case L000_Pid_Protocol_Array:
/* This is the A001 protocol, initiated by the device. */
size = garmin_packet_size(&p) / 3;
datatypes = calloc(size,sizeof(uint16));
for ( i = 0; i < size; i++ ) {
tag = p.packet.data[3*i];
data = get_uint16(p.packet.data + 3*i + 1);
switch ( tag ) {
case Tag_Phys_Prot_Id:
garmin->protocol.physical = data;
break;
case Tag_Link_Prot_Id:
garmin->protocol.link = data;
break;
case Tag_Appl_Prot_Id:
memset(datatypes,0,size * sizeof(uint16));
for ( j = i+1; p.packet.data[3*j] == Tag_Data_Type_Id; j++ ) {
datatypes[j-i-1] = get_uint16(p.packet.data + 3*j + 1);
}
garmin_assign_protocol(garmin,data,datatypes);
break;
case Tag_Data_Type_Id:
/* Skip, since we should already have handled them. */
default:
break;
}
}
free(datatypes);
done = 1;
break;
default:
/* Ignore any other packets sent from the device. */
break;
}
}
garmin_callback("product_request");
}
/* ------------------------------------------------------------------------- */
/* 6.4 A100 - Waypoint Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a100 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Wpt) != 0 ) {
d = garmin_read_records(garmin,
Pid_Wpt_Data,
garmin->datatype.waypoint.waypoint);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.5 A101 - Waypoint Category Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a101 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Wpt_Cats) != 0 ) {
d = garmin_read_records(garmin,
Pid_Wpt_Cat,
garmin->datatype.waypoint.category);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.6.2 A200 - Route Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a200 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Rte) != 0 ) {
d = garmin_read_records2(garmin,
Pid_Rte_Hdr,
garmin->datatype.route.header,
Pid_Rte_Wpt_Data,
garmin->datatype.waypoint.waypoint);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.6.3 A201 - Route Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a201 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Rte) != 0 ) {
d = garmin_read_records3(garmin,
Pid_Rte_Hdr,
garmin->datatype.route.header,
Pid_Rte_Wpt_Data,
garmin->datatype.route.waypoint,
Pid_Rte_Link_Data,
garmin->datatype.route.link);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.7.2 A300 - Track Log Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a300 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Trk) != 0 ) {
d = garmin_read_records(garmin,
Pid_Trk_Data,
garmin->datatype.track.data);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.7.3 A301 - Track Log Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a301 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Trk) != 0 ) {
d = garmin_read_records2(garmin,
Pid_Trk_Hdr,
garmin->datatype.track.header,
Pid_Trk_Data,
garmin->datatype.track.data);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.7.4 A302 - Track Log Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a302 ( garmin_unit * garmin )
{
return garmin_read_a301(garmin);
}
/* ------------------------------------------------------------------------- */
/* 6.8 A400 - Proximity Waypoint Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a400 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Prx) != 0 ) {
d = garmin_read_records(garmin,
Pid_Prx_Wpt_Data,
garmin->datatype.waypoint.proximity);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.9 A500 - Almanac Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a500 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Alm) != 0 ) {
d = garmin_read_records(garmin,
Pid_Almanac_Data,
garmin->datatype.almanac);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.10 A600 - Date and Time Initialization Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a600 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
d = garmin_read_singleton(garmin,
Pid_Date_Time_Data,
garmin->datatype.date_time);
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.11 A650 - FlightBook Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a650 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_FlightBook_Transfer) ) {
d = garmin_read_records(garmin,
Pid_FlightBook_Record,
garmin->datatype.flightbook);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.12 A700 - Position Initialization Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a700 ( garmin_unit * garmin )
{
garmin_data * d;
if (!garmin) return NULL;
d = garmin_read_singleton(garmin,
Pid_Position_Data,
garmin->datatype.position);
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.13 A800 - PVT Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a800 ( garmin_unit * garmin )
{
garmin_data * d;
if (!garmin) return NULL;
d = garmin_read_singleton(garmin,
Pid_Pvt_Data,
garmin->datatype.pvt);
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.14 A906 - Lap Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a906 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Laps) != 0 ) {
d = garmin_read_records(garmin,Pid_Lap,garmin->datatype.lap);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.15 A1000 - Run Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1000 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
garmin_list * l = NULL;
if (!garmin) return NULL;
/* Read the runs, then the laps, then the track log. */
if ( garmin_send_command(garmin,Cmnd_Transfer_Runs) != 0 ) {
d = garmin_alloc_data(data_Dlist);
l = d->data;
garmin_list_append(l,garmin_read_records(garmin,Pid_Run,
garmin->datatype.run));
garmin_list_append(l,garmin_read_a906(garmin));
garmin_list_append(l,garmin_read_a302(garmin));
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.16 A1002 - Workout Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1002 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
garmin_list * l = NULL;
if (!garmin) return NULL;
/* Read the workouts, then the workout occurrences */
if ( garmin_send_command(garmin,Cmnd_Transfer_Workouts) != 0 ) {
d = garmin_alloc_data(data_Dlist);
l = d->data;
garmin_list_append(l,
garmin_read_records(garmin,
Pid_Workout,
garmin->datatype.workout.workout));
garmin_list_append(l,garmin_read_a1003(garmin));
}
return d;
}
/* ------------------------------------------------------------------------- */
/* --- UNDOCUMENTED --- A1003 - Workout Occurrence Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1003 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
/* Read the workouts, then the workout occurrences */
if ( garmin_send_command(garmin,Cmnd_Transfer_Workout_Occurrences) != 0 ) {
d = garmin_read_records(garmin,
Pid_Workout_Occurrence,
garmin->datatype.workout.occurrence);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.17 A1004 - Fitness User Profile Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1004 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Fitness_User_Profile) != 0 ) {
d = garmin_read_singleton(garmin,
Pid_Fitness_User_Profile,
garmin->datatype.fitness);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.18 A1005 - Workout Limits Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1005 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Workout_Limits) != 0 ) {
d = garmin_read_singleton(garmin,
Pid_Workout_Limits,
garmin->datatype.workout.limits);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.19 A1006 - Course Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1006 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
garmin_list * l = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Courses) != 0 ) {
d = garmin_alloc_data(data_Dlist);
l = d->data;
garmin_list_append(l,garmin_read_records(garmin,
Pid_Course,
garmin->datatype.course.course));
garmin_list_append(l,garmin_read_a1007(garmin));
garmin_list_append(l,garmin_read_a1012(garmin));
garmin_list_append(l,garmin_read_a1008(garmin));
}
return d;
}
/* ------------------------------------------------------------------------- */
/* --- UNDOCUMENTED --- A1007 - Course Lap Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1007 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Course_Laps) != 0 ) {
d = garmin_read_records(garmin,
Pid_Course_Lap,
(garmin->datatype.course.lap != data_Dnil) ?
garmin->datatype.course.lap :
garmin->datatype.lap);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* --- UNDOCUMENTED --- A1008 - Course Point Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1008 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Course_Points) != 0 ) {
d = garmin_read_records(garmin,
Pid_Course_Point,
garmin->datatype.course.point);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* 6.20 A1009 - Course Limits Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1009 ( garmin_unit * garmin )
{
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Course_Limits) != 0 ) {
d = garmin_read_singleton(garmin,
Pid_Course_Limits,
garmin->datatype.course.limits);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* --- UNDOCUMENTED --- A1012 - Course Track Transfer Protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_a1012 ( garmin_unit * garmin )
{
garmin_datatype header;
garmin_datatype data;
garmin_data * d = NULL;
if (!garmin) return NULL;
if ( garmin_send_command(garmin,Cmnd_Transfer_Course_Tracks) != 0 ) {
if ( garmin->datatype.course.track.header != data_Dnil ) {
header = garmin->datatype.course.track.header;
} else {
header = garmin->datatype.track.header;
}
if ( garmin->datatype.course.track.data != data_Dnil ) {
data = garmin->datatype.course.track.data;
} else {
data = garmin->datatype.track.data;
}
d = garmin_read_records2(garmin,
Pid_Course_Trk_Hdr,
header,
Pid_Course_Trk_Data,
data);
}
return d;
}
/* ------------------------------------------------------------------------- */
/* Get data from the Garmin unit via a particular top-level protocol */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_read_via ( garmin_unit * garmin, appl_protocol protocol )
{
garmin_data * data = NULL;
if (!garmin) return NULL;
#define CASE_PROTOCOL(x) \
case appl_A##x: \
if ( garmin->verbose != 0 ) { \
fprintf(stderr, "[garmin] -> garmin_read_a" #x "\n"); \
} \
data = garmin_read_a##x(garmin); \
if ( garmin->verbose != 0 ) { \
fprintf(stderr, "[garmin] <- garmin_read_a" #x "\n"); \
} \
break
switch ( protocol ) {
CASE_PROTOCOL(100); /* waypoints */
CASE_PROTOCOL(101); /* waypoint categories */
CASE_PROTOCOL(200); /* routes */
CASE_PROTOCOL(201); /* routes */
CASE_PROTOCOL(300); /* track log */
CASE_PROTOCOL(301); /* track log */
CASE_PROTOCOL(302); /* track log */
CASE_PROTOCOL(400); /* proximity waypoints */
CASE_PROTOCOL(500); /* almanac */
CASE_PROTOCOL(650); /* flightbook */
CASE_PROTOCOL(1000); /* runs */
CASE_PROTOCOL(1002); /* workouts */
CASE_PROTOCOL(1004); /* fitness user profile */
CASE_PROTOCOL(1005); /* workout limits */
CASE_PROTOCOL(1006); /* courses */
CASE_PROTOCOL(1009); /* course limits */
default:
/* invalid top-level read protocol */
break;
}
garmin_callback("read_via");
return data;
}
/* ------------------------------------------------------------------------- */
/* Get data from the Garmin unit */
/* ------------------------------------------------------------------------- */
garmin_data *
garmin_get ( garmin_unit * garmin, garmin_get_type what )
{
garmin_data * data = NULL;
if (!garmin) return NULL;
#define CASE_WHAT(x,y) \
case GET_##x: data = garmin_read_via(garmin,garmin->protocol.y); break
switch ( what ) {
CASE_WHAT(WAYPOINTS,waypoint.waypoint);
CASE_WHAT(WAYPOINT_CATEGORIES,waypoint.category);
CASE_WHAT(ROUTES,route);
CASE_WHAT(TRACKLOG,track);
CASE_WHAT(PROXIMITY_WAYPOINTS,waypoint.proximity);
CASE_WHAT(ALMANAC,almanac);
CASE_WHAT(FLIGHTBOOK,flightbook);
CASE_WHAT(RUNS,run);
CASE_WHAT(WORKOUTS,workout.workout);
CASE_WHAT(FITNESS_USER_PROFILE,fitness);
CASE_WHAT(WORKOUT_LIMITS,workout.limits);
CASE_WHAT(COURSES,course.course);
CASE_WHAT(COURSE_LIMITS,course.limits);
default:
/* invalid garmin_get_type */
break;
}
return data;
}
/* Initialize a connection with a Garmin unit. */
int garmin_init(garmin_unit *garmin, int verbose)
{
if (!garmin) return 0;
memset(garmin, 0, sizeof(garmin_unit));
garmin->verbose = verbose;
garmin->usb.fd = -1;
if ( garmin_open(garmin) != 0 )
{
garmin_start_session(garmin);
garmin_read_a000_a001(garmin);
return 1;
}
else
{
return 0;
}
}