Garmin GPS Communication with Propeller
dman271828
Posts: 2
What is the serial communication protocol to do serial communication between a Garmin GPS (Nuvi 255W) and the Propeller? I included the C language example. What protocol follows the StartPVTPacket and StopPVTPacket which requests that the GPS send the position velocity and time data? Once I know the proper protocol I can develop the spin code to do the Propeller serial communication directly to the Garmin GPS.
// This file contains sample code to help application developers
// interface with Garmin USB units. This should not be viewed as a
// full implementation of PC to unit communication. It does not include
// error checking and other elements of a full implementation.
// Also, there are notes in the code suggesting other elements that
// might be necessary.
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <initguid.h>
#include <setupapi.h> // You may need to explicitly link with setupapi.lib
#include <winioctl.h>
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
//
HANDLE gHandle;
DWORD gUSBPacketSize;
//
#pragma pack( push, 1)
typedef struct
{
unsigned char mPacketType;
unsigned char mReserved1;
unsigned short mReserved2;
unsigned short mPacketId;
unsigned short mReserved3;
unsigned long mDataSize;
BYTE mData[2];
} Packet_t;
#pragma pack( pop)
//
void
SendPacket
(
Packet_t aPacket
)
{
DWORD theBytesToWrite = sizeof( aPacket ) - 1 + aPacket.mDataSize;
DWORD theBytesReturned = 0;
WriteFile( gHandle,
&aPacket,
theBytesToWrite,
&theBytesReturned,
NULL );
// If the packet size was an exact multiple of the USB packet
// size, we must make a final write call with no data
if( theBytesToWrite % gUSBPacketSize == 0 )
{
WriteFile( gHandle,
0,
0,
&theBytesReturned,
NULL );
}
}
//
// Gets a single packet. Since packets may come simultaneously through
// asynchrous reads and normal (ReadFile) reads, a full implementation
// may require a packet queue and multiple threads.
Packet_t*
GetPacket
(
)
{
Packet_t* thePacket = 0;
DWORD theBufferSize = 0;
BYTE* theBuffer = 0;
for( ; ; )
{
// Read async data until the driver returns less than the
// max async data size, which signifies the end of a packet
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 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;
}
else
{
return thePacket;
}
}
//
void
Initialize
(
)
{
// Make all the necessary Windows calls to get a handle
// to our USB device
DWORD theBytesReturned = 0;
PSP_INTERFACE_DEVICE_DETAIL_DATA theDevDetailData = 0;
SP_DEVINFO_DATA theDevInfoData = { sizeof( SP_DEVINFO_DATA ) };
Packet_t theStartSessionPacket = { 0, 0, 0, 5, 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;
}
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 );
// Get the USB packet size, which we need for sending packets
DeviceIoControl( gHandle,
IOCTL_USB_PACKET_SIZE,
0,
0,
&gUSBPacketSize,
sizeof( gUSBPacketSize ),
&theBytesReturned,
NULL );
// Tell the device that we are starting a session.
SendPacket( theStartSessionPacket );
// Wait until the device is ready to the start the session
for( ; ; )
{
thePacket = GetPacket();
if( thePacket->mPacketType == 0 &&
thePacket->mPacketId == 6 )
{
break;
}
free( thePacket );
}
free( thePacket );
}
//
int _tmain(int argc, _TCHAR* argv[])
{
int x;
Packet_t theProductDataPacket = { 20, 0, 0, 254, 0, 0, {0,0}};
Packet_t thePosPacket = {20, 0, 0, 10, 0, 2, {2,0}};
Packet_t StartRawPacket = {20, 0, 0, 10, 0, 4, {110,0}};
Packet_t StopRawPacket = {20, 0, 0, 10, 0, 4, {111,0}};
Packet_t StartPVTPacket = {20, 0, 0, 10, 0, 4, {49,0}};
Packet_t StopPVTPacket = {20, 0, 0, 10, 0, 4, {50,0}};
Packet_t SendEphemerisPacket = {20, 0, 0, 10, 0, 4, {93,0}};
Packet_t StopTransPacket = {20, 0, 0, 10, 0, 4, {0,0}};
Packet_t theStartSessionPacket = { 0, 0, 0, 5, 0 , 0 };
Packet_t theTurnOffPacket = { 0, 0, 0, 8, 0 , 0 };
Packet_t* thePacket = 0;
/*
theProductDataPacket.mDataSize = 4;
theProductDataPacket.mPacketId = 10;
theProductDataPacket.mPacketType = 20;
theProductDataPacket.mReserved1 = 0;
theProductDataPacket.mReserved2 = 0;
theProductDataPacket.mReserved3 = 0;
*/
Initialize();
if( gHandle == 0 )
{
printf( "%s", "No device\n" );
return 0;
}
// Tell the device to send product data
SendPacket( theStartSessionPacket );
Sleep(50);
SendPacket( theProductDataPacket );
// Get the product data packet
for( ; ; )
{
thePacket = GetPacket();
printf("ID %d\n", thePacket->mPacketId );
if( thePacket->mPacketType == 20 )// &&
// thePacket->mPacketId == 254 )
{
break;
}
// free( thePacket );
}
//free( thePacket );
// Print out the product description
printf( "%s\n", (char*) &thePacket->mData[0] );
SendPacket( theStartSessionPacket );
Sleep(50);
thePacket = GetPacket();
SendPacket(StartPVTPacket);
Sleep(3000);
thePacket = GetPacket();
/*
Sleep(50);
// Print out the product description
printf( "%s\n", (char*) &thePacket->mData[0] );
Sleep(50);
thePacket = GetPacket();
// Print out the product description
printf( "%s\n", (char*) &thePacket->mData[0] );
*/
// Print out the product description
for(x = 0; x <300 ; x++ )
{
printf( "%c", (char) thePacket->mData[x] );
if( x%60 == 0 )
printf("\n");
}
free( thePacket );
return 0;
}
// This file contains sample code to help application developers
// interface with Garmin USB units. This should not be viewed as a
// full implementation of PC to unit communication. It does not include
// error checking and other elements of a full implementation.
// Also, there are notes in the code suggesting other elements that
// might be necessary.
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <initguid.h>
#include <setupapi.h> // You may need to explicitly link with setupapi.lib
#include <winioctl.h>
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
//
HANDLE gHandle;
DWORD gUSBPacketSize;
//
#pragma pack( push, 1)
typedef struct
{
unsigned char mPacketType;
unsigned char mReserved1;
unsigned short mReserved2;
unsigned short mPacketId;
unsigned short mReserved3;
unsigned long mDataSize;
BYTE mData[2];
} Packet_t;
#pragma pack( pop)
//
void
SendPacket
(
Packet_t aPacket
)
{
DWORD theBytesToWrite = sizeof( aPacket ) - 1 + aPacket.mDataSize;
DWORD theBytesReturned = 0;
WriteFile( gHandle,
&aPacket,
theBytesToWrite,
&theBytesReturned,
NULL );
// If the packet size was an exact multiple of the USB packet
// size, we must make a final write call with no data
if( theBytesToWrite % gUSBPacketSize == 0 )
{
WriteFile( gHandle,
0,
0,
&theBytesReturned,
NULL );
}
}
//
// Gets a single packet. Since packets may come simultaneously through
// asynchrous reads and normal (ReadFile) reads, a full implementation
// may require a packet queue and multiple threads.
Packet_t*
GetPacket
(
)
{
Packet_t* thePacket = 0;
DWORD theBufferSize = 0;
BYTE* theBuffer = 0;
for( ; ; )
{
// Read async data until the driver returns less than the
// max async data size, which signifies the end of a packet
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 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;
}
else
{
return thePacket;
}
}
//
void
Initialize
(
)
{
// Make all the necessary Windows calls to get a handle
// to our USB device
DWORD theBytesReturned = 0;
PSP_INTERFACE_DEVICE_DETAIL_DATA theDevDetailData = 0;
SP_DEVINFO_DATA theDevInfoData = { sizeof( SP_DEVINFO_DATA ) };
Packet_t theStartSessionPacket = { 0, 0, 0, 5, 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;
}
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 );
// Get the USB packet size, which we need for sending packets
DeviceIoControl( gHandle,
IOCTL_USB_PACKET_SIZE,
0,
0,
&gUSBPacketSize,
sizeof( gUSBPacketSize ),
&theBytesReturned,
NULL );
// Tell the device that we are starting a session.
SendPacket( theStartSessionPacket );
// Wait until the device is ready to the start the session
for( ; ; )
{
thePacket = GetPacket();
if( thePacket->mPacketType == 0 &&
thePacket->mPacketId == 6 )
{
break;
}
free( thePacket );
}
free( thePacket );
}
//
int _tmain(int argc, _TCHAR* argv[])
{
int x;
Packet_t theProductDataPacket = { 20, 0, 0, 254, 0, 0, {0,0}};
Packet_t thePosPacket = {20, 0, 0, 10, 0, 2, {2,0}};
Packet_t StartRawPacket = {20, 0, 0, 10, 0, 4, {110,0}};
Packet_t StopRawPacket = {20, 0, 0, 10, 0, 4, {111,0}};
Packet_t StartPVTPacket = {20, 0, 0, 10, 0, 4, {49,0}};
Packet_t StopPVTPacket = {20, 0, 0, 10, 0, 4, {50,0}};
Packet_t SendEphemerisPacket = {20, 0, 0, 10, 0, 4, {93,0}};
Packet_t StopTransPacket = {20, 0, 0, 10, 0, 4, {0,0}};
Packet_t theStartSessionPacket = { 0, 0, 0, 5, 0 , 0 };
Packet_t theTurnOffPacket = { 0, 0, 0, 8, 0 , 0 };
Packet_t* thePacket = 0;
/*
theProductDataPacket.mDataSize = 4;
theProductDataPacket.mPacketId = 10;
theProductDataPacket.mPacketType = 20;
theProductDataPacket.mReserved1 = 0;
theProductDataPacket.mReserved2 = 0;
theProductDataPacket.mReserved3 = 0;
*/
Initialize();
if( gHandle == 0 )
{
printf( "%s", "No device\n" );
return 0;
}
// Tell the device to send product data
SendPacket( theStartSessionPacket );
Sleep(50);
SendPacket( theProductDataPacket );
// Get the product data packet
for( ; ; )
{
thePacket = GetPacket();
printf("ID %d\n", thePacket->mPacketId );
if( thePacket->mPacketType == 20 )// &&
// thePacket->mPacketId == 254 )
{
break;
}
// free( thePacket );
}
//free( thePacket );
// Print out the product description
printf( "%s\n", (char*) &thePacket->mData[0] );
SendPacket( theStartSessionPacket );
Sleep(50);
thePacket = GetPacket();
SendPacket(StartPVTPacket);
Sleep(3000);
thePacket = GetPacket();
/*
Sleep(50);
// Print out the product description
printf( "%s\n", (char*) &thePacket->mData[0] );
Sleep(50);
thePacket = GetPacket();
// Print out the product description
printf( "%s\n", (char*) &thePacket->mData[0] );
*/
// Print out the product description
for(x = 0; x <300 ; x++ )
{
printf( "%c", (char) thePacket->mData[x] );
if( x%60 == 0 )
printf("\n");
}
free( thePacket );
return 0;
}
Comments