Running Log - Part Four (Garmin GPS)
Links to other Microsoft Access Running Log screen shots:
Part one (Main Screen, Reports Screen, and Defaults): http://dhartley86.vox.com/library/post/running-log.html
Part two (Defaults Continued): http://dhartley86.vox.com/library/post/running-log---continued.html
Part three (Reports): http://dhartley86.vox.com/library/post/running-log---reports.html
Part four (Garmin GPS): http://dhartley86.vox.com/library/post/running-log---part-four-garmin-gps.html
Part five (Changes): http://dhartley86.vox.com/library/post/running-log---part-five-changes.html
New Screen with Garmin Download and Coordinates buttons:
Comments: Click Garmin Download button and following appears:
Garmin Download:
Comments:
A program written in MS Visual C++ runs to download laps from a Garmin Forerunner 305. Rows can be deleted, but not added or modified. Distance, time, max HR, and Avg HR are calculated, but can be modified. Pace and Zone are calculated and cannot be modified.
Clicking Reload will reset the form and reload from the Garmin. Clicking Save will add the run to the database, and close the screen. Clicking GPS Log will display the log created during the down load. An example is at the end of this post. Clicking Coordinates will display the lat/lon of the run that are saved.
Sample log:
Wed 03/05/2008
12:03 PM
argv[0]: C:\Documents and Settings\User_One\Desktop\Running\GarminTrack.exe
argv[1]: C:\Documents and Settings\User_One\Desktop\Running\lap.txt
argv[2]: C:\Documents and Settings\User_One\Desktop\Running\track.txt
Creating Pactet_t(s) to retrieve laps from Garmin Forerunner 305
Opening USB communication to Garmin Forerunner 305
Sending packet requesting laps from Garmin Forerunner 305
Creating output file C:\Documents and Settings\User_One\Desktop\Running\lap.txt
Writing information to file and screen:
Row, Lap, Meters, Minutes, Avg_heart_rate, Max_heart_rate, Begin_lat, Begin_lon
1, Skipped
2, 0, 0.000000, 389.945333, 0, 0, -119.525668, 57.246580
3, 0, 18802.046875, 63.252333, 0, 0, 44.312413, -69.818161
4, 1, 1609.000000, 9.677500, 124, 137, 44.209266, -69.797438
5, 2, 1609.000000, 9.179000, 123, 142, 44.213686, -69.784345
6, 3, 1609.000000, 9.664833, 136, 155, 44.221295, -69.781064
7, 4, 1609.000000, 9.610333, 140, 159, 44.214022, -69.783854
8, 5, 48.702637, 0.291167, 136, 137, 44.208796, -69.797436
9, Skipped
Closed file C:\Documents and Settings\User_One\Desktop\Running\lap.txt
Close connection to Garmin Forerunner 305
Creating Pactet_t(s) to retrieve tracks from Garmin Forerunner 305
Opening USB communication to Garmin Forerunner 305
Sending packet requesting tracks from Garmin Forerunner 305
Creating output file C:\Documents and Settings\User_One\Desktop\Running\track.txt
Writing information to file and screen:
Lat, Lon, Time, alt, heart_rate
1, Skipped
2, Skipped
3, 1, 44.209270, -69.797442, 572910857.000000, 0
4, 2, 44.209253, -69.797427, 572910859.000000, 31
5, 3, 44.209169, -69.797417, 572910863.000000, 184
6, 4, 44.209077, -69.797435, 572910867.000000, 106
**** Deleted several lines to save space ****
459, 452, 44.208815, -69.797437, 572913147.000000, 171
460, 453, 44.208911, -69.797435, 572913151.000000, 192
461, 454, 44.209044, -69.797437, 572913156.000000, 254
462, 455, 44.209197, -69.797434, 572913162.000000, 159
463, Skipped
464, Skipped
No coordinates - did you reset the Garmin Forerunner 305 after last run?
Closed file C:\Documents and Settings\User_One\Desktop\Running\track.txt
Close connection to Garmin Forerunner 305
Done
Wed 03/05/2008
12:03 PM
Here is the code from the MS Visual C++ program:
#using
#include "stdafx.h"
#include
#include
#include
#include
#include
#include
//SDK Page 4 - Device Interface GUID
DEFINE_GUID(GUID_DEVINTERFACE_GRMNUSB, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81, 0x6b, 0xba, 0xe7, 0x22, 0xc0);
#define IOCTL_ASYNC_IN CTL_CODE (FILE_DEVICE_UNKNOWN, 0x850, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_USB_PACKET_SIZE CTL_CODE (FILE_DEVICE_UNKNOWN, 0x851, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define MAX_BUFFER_SIZE 4096
#define ASYNC_DATA_SIZE 64
#pragma comment (lib,"Setupapi.lib")
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include
#include
#define GARMIN_LAYERID_APPL 20 //3.2.2 USB Packet Format page 3
#define GARMIN_LAYERID_USB 0 //3.2.2 USB Packet Format page 3
#define GARMIN_PKTID_TRANSPORT_START_SESSION_REQ 5 //3.2.3 USB Protocol Layer Packet Ids
//from http://developer.garmin.com/forum/viewtopic.php?t=180
#define PID_COMMAND_DATA 10 //4.2 L001 - Link Protocol 1 page 6
#define CMD_TRANSFER_LAPS 117 //6.3.1 A010 - Device Command Protocol 1 page 12
#define CMD_TRANSFER_TRK 6 //6.3.1 A010 - Device Command Protocol 1 page 12
//-----------------------------------------------------------------------------
HANDLE gHandle;
DWORD gUSBPacketSize;
typedef unsigned char uint8; //1 byte
typedef unsigned short uint16; //2 bytes
typedef unsigned long uint32; //4 bytes
typedef short sint16; //2 bytes
typedef long sint32; //4 bytes
typedef float float32; //4 bytes
typedef double float64; //8 bytes
typedef uint32 time_type; //4 bytes
typedef struct position_type { //8 bytes
sint32 lat; //4 bytes
sint32 lon; //4 bytes
} position_type;
////-----------------------------------------------------------------------------
////SDK - Page 8: Records_Type (from beginning packet)
typedef uint16 Records_Type; //2 bytes
////-----------------------------------------------------------------------------
////SDK - Page 50: Lap Type
////
////Looking through the sdk, D1001_Lap_Type has the attributes I want.
////
typedef struct D1001_Lap_Type
{
//Type Name Description
uint32 index; /* Unique among all laps received from device */
time_type start_time; /* Start of lap time */
uint32 total_time; /* Duration of lap, in hundredths of a second */
float32 total_dist; /* Distance in meters */
float32 max_speed; /* In meters per second */
position_type begin; /* Invalid if both lat and lon are 0x7FFFFFFF */
position_type end; /* Invalid if both lat and lon are 0x7FFFFFFF */
uint16 calories; /* Calories burned this lap */
uint8 avg_heart_rate; /* In beats-per-minute, 0 if invalid */
uint8 max_heart_rate; /* In beats-per-minute, 0 if invalid */
uint8 intensity; /* 0=active; 1=rest*/
} D1001_Lap_Type;
////-----------------------------------------------------------------------------
////SDK - Page 43: Track Type
////
typedef struct D303_Trk_Point_Type
{
//Type Name Description
position_type posn; /* Position */
time_type time; /* Time */
float32 alt; /* altitude in meters */
uint8 heart_rate; /* depth in meters*/
} D303_Trk_Point_Type;
//-----------------------------------------------------------------------------
//SDK - Page 3: Table 3 - USB Packet Format
typedef struct
{
uint8 mPacketType;
uint8 mReserved1;
uint16 mReserved2;
uint16 mPacketId;
uint16 mReserved3;
uint32 mDataSize;
BYTE mData[sizeof(MAX_BUFFER_SIZE)];
} Packet_t;
Packet_t* GetPacket()
{
Packet_t* thePacket = 0;
DWORD theBufferSize = 0;
BYTE* theBuffer = 0;
while(true)
{
BYTE theTempBuffer[ASYNC_DATA_SIZE];
BYTE* theNewBuffer = 0;
DWORD theBytesReturned = 0;
DeviceIoControl( gHandle,
IOCTL_ASYNC_IN,
0,
0,
theTempBuffer,
sizeof( theTempBuffer ),
&theBytesReturned,
NULL );
theBufferSize += ASYNC_DATA_SIZE;
theNewBuffer = (BYTE*) malloc( theBufferSize );
memcpy( theNewBuffer, theBuffer, theBufferSize - ASYNC_DATA_SIZE );
memcpy( theNewBuffer + theBufferSize - ASYNC_DATA_SIZE, theTempBuffer, ASYNC_DATA_SIZE );
free( theBuffer );
theBuffer = theNewBuffer;
if( theBytesReturned != ASYNC_DATA_SIZE )
{
thePacket = (Packet_t*) theBuffer;
break;
}//if( theBytesReturned != ASYNC_DATA_SIZE )
}//while(true)
// If this was a small "signal" packet, read a real
// packet using ReadFile
if (thePacket->mPacketType == 0 && thePacket->mPacketId == 2)
{
BYTE* theNewBuffer = (BYTE*) malloc(MAX_BUFFER_SIZE);
DWORD theBytesReturned = 0;
free (thePacket);
// A full implementation would keep reading (and queueing)
// packets until the driver returns a 0 size buffer.
ReadFile(gHandle, theNewBuffer, MAX_BUFFER_SIZE, &theBytesReturned, NULL);
return (Packet_t*) theNewBuffer;
} //if( thePacket->mPacketType == 0 && thePacket->mPacketId == 2 )
else
{
return thePacket;
}//else
}//GetPacket()
void SendPacket(Packet_t aPacket)
{
DWORD theBytesToWrite = sizeof( aPacket ) - 1 + aPacket.mDataSize;
DWORD theBytesReturned = 0;
WriteFile (gHandle, &aPacket, theBytesToWrite, &theBytesReturned, NULL);
if( theBytesToWrite % gUSBPacketSize == 0 )
{
WriteFile(gHandle, 0, 0, &theBytesReturned, NULL);
} //if( theBytesToWrite % gUSBPacketSize == 0 )
}//SendPacket(Packet_t aPacket)
//-----------------------------------------------------------------------------
void Open_GPS_Communication()
{
DWORD theBytesReturned = 0;
PSP_INTERFACE_DEVICE_DETAIL_DATA theDevDetailData = 0;
SP_DEVINFO_DATA theDevInfoData = {sizeof( SP_DEVINFO_DATA)};
Packet_t theStartSessionPacket = {GARMIN_LAYERID_USB, 0, 0, GARMIN_PKTID_TRANSPORT_START_SESSION_REQ, 0 , 0};
Packet_t* thePacket = 0;
HDEVINFO theDevInfo = SetupDiGetClassDevs((GUID*) &GUID_DEVINTERFACE_GRMNUSB, NULL, NULL,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE );
SP_DEVICE_INTERFACE_DATA theInterfaceData;
theInterfaceData.cbSize = sizeof(theInterfaceData);
if(!SetupDiEnumDeviceInterfaces(theDevInfo, NULL, (GUID*) &GUID_DEVINTERFACE_GRMNUSB, 0, &theInterfaceData ) &&
GetLastError() == ERROR_NO_MORE_ITEMS)
{
gHandle = 0;
return;
} //if( !SetupDiEnumDeviceInterfaces( theDevInfo, ...
SetupDiGetDeviceInterfaceDetail (theDevInfo, &theInterfaceData, NULL, 0, &theBytesReturned, NULL);
theDevDetailData = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc(theBytesReturned);
theDevDetailData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
SetupDiGetDeviceInterfaceDetail (theDevInfo, &theInterfaceData, theDevDetailData, theBytesReturned, NULL,
&theDevInfoData );
gHandle = CreateFile (theDevDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
free (theDevDetailData);
DeviceIoControl (gHandle, IOCTL_USB_PACKET_SIZE, 0, 0, &gUSBPacketSize, sizeof(gUSBPacketSize), &theBytesReturned,
NULL);
SendPacket (theStartSessionPacket);
for( ; ; )
{
thePacket = GetPacket();
if (thePacket->mPacketType == 0 && thePacket->mPacketId == 6)
{
break;
}//if (thePacket->mPacketType == 0 && thePacket->mPacketId == 6)
free( thePacket );
}//for( ; ; )
free( thePacket );
} //void Open_GPS_Communication()
//-----------------------------------------------------------------------------
void getLapData(const char* strFileName)
{
printf ("%s", "Creating Pactet_t(s) to retrieve laps from Garmin Forerunner 305 \n");
Packet_t theDataPacket = {GARMIN_LAYERID_APPL, 0, 0, PID_COMMAND_DATA, 0 , 2, CMD_TRANSFER_LAPS};
Packet_t* thePacket = 0; //packet used to retrieve the data from device
printf ("%s", "Opening USB communication to Garmin Forerunner 305 \n");
Open_GPS_Communication();
if( gHandle == 0 )
{
printf ("%s", "Garmin Forerunner 305 not found\n");
}//if( gHandle == 0 )
else
{
// Tell the device to send data.
printf ("%s", "Sending packet requesting laps from Garmin Forerunner 305 \n");
SendPacket( theDataPacket );
printf ("%s", "Creating output file ");
printf ("%s", strFileName);
printf ("%s", "\n");
FILE* stream;
stream = freopen( strFileName, "w", stderr );
if( stream == NULL )
{
printf ("%s", "Error creating ");
printf ("%s", strFileName);
printf ("%s", "\n");
}//if( stream == NULL )
else
{
printf ("%s", "Writing information to file and screen: \n");
fprintf (stream, "%s", "Lap, Meters, Minutes, Avg_heart_rate, Max_heart_rate \n");
int intLapNumber = 0;
int intRowNumber = 0;
bool blnSkip;
for( ; ; )
{
thePacket = GetPacket();
D1001_Lap_Type *lappvt = NULL;
blnSkip = true;
intRowNumber++;
if (intRowNumber==1) //"header"
{
printf ("%s", "Row, Lap, Meters, Minutes, Avg_heart_rate, Max_heart_rate, Begin_lat, Begin_lon");
printf ("%s", "\n");
}//if ( intRowNumber = 1) //"header"
else if (thePacket->mData[0] == CMD_TRANSFER_LAPS)
{
//ignore
}//else if (thePacket->mData[0] == CMD_TRANSFER_LAPS)
else
{
lappvt = (D1001_Lap_Type*) thePacket->mData;
blnSkip = false;
if (intRowNumber > 3) //no idea what is up with row two and three??
{
intLapNumber++;
fprintf (stream, "%d", intLapNumber);
fprintf (stream, "%s", ", ");
fprintf (stream, "%f", lappvt->total_dist);
fprintf (stream, "%s", ", ");
fprintf (stream, "%f", (float) lappvt->total_time/6000);
fprintf (stream, "%s", ", ");
fprintf (stream, "%d", lappvt->avg_heart_rate);
fprintf (stream, "%s", ", ");
fprintf (stream, "%d", lappvt->max_heart_rate);
fprintf (stream, "%s", "\n");
}//if (intRowNumber > 3) //no idea what is up with row two and three??
}//else {
//output to screen
printf ("%d", intRowNumber);
printf ("%s", ", ");
if (blnSkip)
{
printf ("%s", "Skipped");
}//if (blnSkip)
else
{
printf ("%d", intLapNumber);
printf ("%s", ", ");
printf ("%f", lappvt->total_dist);
printf ("%s", ", ");
printf ("%f", (float) lappvt->total_time/6000);
printf ("%s", ", ");
printf ("%d", lappvt->avg_heart_rate);
printf ("%s", ", ");
printf ("%d", lappvt->max_heart_rate);
printf ("%s", ", ");
printf ("%f", (float) lappvt->begin.lat * 8.3819E-08); //convert "semicircles" to degrees
printf ("%s", ", ");
printf ("%f", (float) lappvt->begin.lon * 8.3819E-08); //convert "semicircles" to degrees
}//else
printf ("%s", "\n");
if( thePacket->mPacketId == 12 )
{
break;
}//if( thePacket->mPacketType == 12
free( thePacket );
}//for( ; ; )
printf ("%s", "Closed file ");
printf ("%s", strFileName);
printf ("%s", "\n");
fclose(stream);
free( thePacket );
} //else - if( stream == NULL )
printf ("%s", "Close connection to Garmin Forerunner 305 \n");
CloseHandle( gHandle );
gHandle = 0;
}//else
}//void getLapData()
//-----------------------------------------------------------------------------
void getTrackData(const char* strFileName)
{
printf ("%s", "Creating Pactet_t(s) to retrieve tracks from Garmin Forerunner 305 \n");
Packet_t theDataPacket = {GARMIN_LAYERID_APPL, 0, 0, PID_COMMAND_DATA, 0 , 2, CMD_TRANSFER_TRK};
Packet_t* thePacket = 0; //packet used to retrieve the data from device
printf ("%s", "Opening USB communication to Garmin Forerunner 305 \n");
Open_GPS_Communication();
if( gHandle == 0 )
{
printf ("%s", "Garmin Forerunner 305 not found\n");
}//if( gHandle == 0 )
else
{
// Tell the device to send data.
printf ("%s", "Sending packet requesting tracks from Garmin Forerunner 305 \n");
SendPacket( theDataPacket );
printf ("%s", "Creating output file ");
printf ("%s", strFileName);
printf ("%s", "\n");
FILE* stream;
stream = freopen( strFileName, "w", stderr );
if( stream == NULL )
{
printf ("%s", "Error creating ");
printf ("%s", strFileName);
printf ("%s", "\n");
}//if( stream == NULL )
else
{
printf ("%s", "Writing information to file and screen: \n");
fprintf (stream, "%s", "Lat, Lon \n");
int intLapNumber = 0;
int intRowNumber = 0;
bool blnSkip;
bool blnOutput = false;
for( ; ; )
{
thePacket = GetPacket();
D303_Trk_Point_Type *trkpvt = NULL;
blnSkip = true;
intRowNumber++;
if (intRowNumber==1) //"header"
{
printf ("%s", "Lat, Lon, Time, alt, heart_rate \n");
printf ("%s", "\n");
}//if ( intRowNumber = 1) //"header"
else if (thePacket->mData[0] == CMD_TRANSFER_TRK)
{
//ignore
}//else if (thePacket->mData[0] == CMD_TRANSFER_LAPS)
else
{
trkpvt = (D303_Trk_Point_Type*) thePacket->mData;
if (intRowNumber > 2) //track header
{
if (trkpvt->posn.lat * 8.3819E-08 <179)
{
blnSkip = false;
intLapNumber++;
fprintf (stream, "%f", (float) trkpvt->posn.lat * 8.3819E-08); //convert "semicircles" to degrees
fprintf (stream, "%s", ", ");
fprintf (stream, "%f", (float) trkpvt->posn.lon * 8.3819E-08); //convert "semicircles" to degrees
fprintf (stream, "%s", "\n");
}//if (trkpvt->posn.lat * 8.3819E-08 <179)
}//if (intRowNumber > 2) //track header
}//else {
//output to screen
printf ("%d", intRowNumber);
printf ("%s", ", ");
if (blnSkip)
{
printf ("%s", "Skipped");
}//if (blnSkip)
else
{
printf ("%d", intLapNumber);
printf ("%s", ", ");
printf ("%f", (float) trkpvt->posn.lat * 8.3819E-08); //convert "semicircles" to degrees
printf ("%s", ", ");
printf ("%f", (float) trkpvt->posn.lon * 8.3819E-08); //convert "semicircles" to degrees
printf ("%s", ", ");
printf ("%f", (float) trkpvt->time);
printf ("%s", ", ");
printf ("%d", trkpvt->heart_rate);
}//else
printf ("%s", "\n");
if( thePacket->mPacketId == 12 )
{
break;
}//if( thePacket->mPacketType == 12
free( thePacket );
}//for( ; ; )
if (!blnOutput)
{
printf ("%s", "No coordinates - did you reset the Garmin Forerunner 305 after last run? \n");
}//if (!blnOutput)
printf ("%s", "Closed file ");
printf ("%s", strFileName);
printf ("%s", "\n");
fclose(stream);
free( thePacket );
} //else - if( stream == NULL )
printf ("%s", "Close connection to Garmin Forerunner 305 \n");
CloseHandle( gHandle );
gHandle = 0;
}//else
}//void getTrackData()
int _tmain(int argc, _TCHAR* argv[])
{
printf ("%s", "argv[0]: ");
printf ("%s", argv[0]);
printf ("%s", "\n");
if (argc == 1)
{
getLapData("lap.txt");
getTrackData("track.txt");
}//if (argc > 0)
else if (argc == 2)
{
printf ("%s", "argv[1]: ");
printf ("%s", argv[1]);
printf ("%s", "\n");
getLapData(argv[1]);
}//else if (argc == 2)
else
{
printf ("%s", "argv[1]: ");
printf ("%s", argv[1]);
printf ("%s", "\nargv[2]: ");
printf ("%s", argv[2]);
printf ("%s", "\n");
getLapData(argv[1]);
getTrackData(argv[2]);
}//else
printf ("%s", "Done\n");
return 0;
}//int _tmain(int argc, _TCHAR* argv[])
Links to other Microsoft Access Running Log screen shots:
Part one (Main Screen, Reports Screen, and Defaults): http://dhartley86.vox.com/library/post/running-log.html
Part two (Defaults Continued): http://dhartley86.vox.com/library/post/running-log---continued.html
Part three (Reports): http://dhartley86.vox.com/library/post/running-log---reports.html
Part four (Garmin GPS): http://dhartley86.vox.com/library/post/running-log---part-four-garmin-gps.html
Part five (Changes): http://dhartley86.vox.com/library/post/running-log---part-five-changes.html