Click here to Skip to main content
Licence 
First Posted 3 Jan 2003
Views 280,332
Bookmarked 168 times

Add GPS support to your desktop

By | 18 Feb 2003 | Article
Use serial ports to add GPS (Global Positioning System) support to your desktop computer by using NMEA0183 protocol
Prize winner in Competition "MFC/C++ Dec 2002"

Sample Image - GPS_support.jpg

Introduction

GPS stand for Global Positioning System and is a device for finding useful information about geographical location (in other hand, Longitude and Latitude). But these information are not limited to Longitude and Latitude. Some other information like Time, Date, Compass information, Speed and etc. can be obtained from GPS.

GPS devices use satellites (minimum of 3 and maximum of 14) to find your location on the earth. Most modern GPS devices now support a protocol called NMEA0183. This protocol used to transfer geographical location information from GPS to your desktop computer or PDA.

Connecting GPS to your PC

To transfer data from GPS to your computer, you need a serial cable that can connect to your GPS. After this, you must configure your serial port to communication go right. In this project, I configure my serial port as follow:

COM Port: COM2
Baud Rate: 4800
Data Bits: 8
Parity: No Parity
Stop Bits: 2

You must refer to your GPS manual to configure your serial port properly.

NMEA0183

As I mentioned before, NMEA0183 is a standard protocol to transfer location information from GPS to your PC. I use a free library that can be added to your project without any modification.

you can find this library in above file. Thanks Sam Blackburn for his nice library. This protocol consists of several sentences that every sentences start by $. For example the sentence

"$GPGGA,104435.12,3337.19,N,11158.43,W,1,06,4.5,,,,,,"

has these informations (in other hand, translated to):

Time: 10:44:35 AM UTC
Latitude: 33 37.19 North
Longitude: 111 58.43 West
Number of satellites: 6

Using Library

First of all, you must add nmea0183.lib to your project. For this reason, Select Project, Settings and then Link Tab. In Object/Library Modules type path of nmea0183.lib library (for example: .\NMEA0183\Debug\NMEA0183.lib).

Then press OK to return to project.

If you use a dialog in your project, Add "NMEA0183.h" to your dialog header file. In other cases add "NMEA0183.h" to main header file.
Now, Add a member variable named nmea0183 with variable type NMEA0183, like this:
NMEA0183 nmea0183;

After this, you must add header and implementation files for serial communication. I use CSerialCom from Shibu K.V. Find his article at this URL: A simple Class for Implementing Serial Communication in Win-9X/2000

Add a member variable named Serial with variable type CSerialCom, like this:
CSerialCom Serial;

Now configure your serial port by:

//Open Port: COM2
Serial.OpenPort("COM2");

//Configure COM2
Serial.ConfigurePort(4800,          //Baud Rate
                     8,             //Data Bits
                     FALSE,         //Has Parity
                     NOPARITY,      //Parity Bits
                     TWOSTOPBITS    //Stop Bits
                    );

If anything goes right, you can obtain information from GPS by Read member function, as follow: Note: any NMEA0183 sentences will finished by "\r\n" characters.
//Read data from GPS 
    
char Data[100]="\0";

BYTE DataByte='\0';
int nIndex=0;

//Obtaining information from GPS character by character
//Note: NMEA0183 sentences will finished by "\r\n" characters!
BOOL Return=Serial.ReadByte(DataByte);
while (DataByte!='\r' && DataByte!='\n' && Return==TRUE)
{
    Data[nIndex]=DataByte;
    nIndex++;
    Return=Serial.ReadByte(DataByte);
}
    
Data[nIndex++]='\r';
Data[nIndex++]='\n';
Data[nIndex++]='\0';

//Remove garbage characters if any exists!
nIndex=0;
while (Data[nIndex]!='$' && nIndex<100)
    nIndex++;

Now, it's time to work with nmea0183 member variable. NMEA0183 class has two very important member functions and one member variable:

  1. AddTail() to add strings retreived from GPS.
  2. Parse() to parse retreived strings. And
  3. PlainText a member variable that stores plain text of translated string.

Solution

I use a thread in my dialog based project that it's duty is to communicate to GPS and show location information in a plain text. My thread function is as below:

UINT MyThread(LPVOID pParam)
{
    CSerialCom Serial;
    NMEA0183 nmea0183;
    CStringList StrList;

    if (!Serial.OpenPort("COM2"))
    {    
        AfxMessageBox("Can't Open Port!");
        return 0;
    }
    
    Serial.ConfigurePort(4800, 8, FALSE, NOPARITY, TWOSTOPBITS);
    
    //Read data from GPS
    char Data[100]="\0";
    
    BYTE DataByte='\0';
    int nIndex=0;
    
    BOOL Return=Serial.ReadByte(DataByte);
    while (DataByte!='\r' && DataByte!='\n' && Return==TRUE)
    {
        Data[nIndex]=DataByte;
        nIndex++;
        Return=Serial.ReadByte(DataByte);
    }
    
    Data[nIndex++]='\r';
    Data[nIndex++]='\n';
    Data[nIndex++]='\0';
    
    //Remove garbage characters
    nIndex=0;
    while (Data[nIndex]!='$' && nIndex<100)
        nIndex++;
    
    StrList.RemoveAll();
    StrList.AddTail(Data+nIndex);
    
    //Parse strings    
    POSITION position = StrList.GetHeadPosition();
    
    while(position!=NULL)
    {
        nmea0183 << StrList.GetNext(position);
        
        if (!nmea0183.Parse())
            AfxMessageBox("Can't parse!");
        else
        {    
            if (nmea0183.PlainText.GetLength()!= 0)
            {
                CString sMsg;
                sMsg.Format("%s",(const char *) nmea0183.PlainText);
                AfxMessageBox(sMsg);
            }
        }
    }
    Serial.ClosePort();
    
    return 0;
}

When you want to show GPS Information, use this thread as below:

AfxBeginThread(MyThread,NULL);

Linking NMEA0183 Library

We can link NMEA0183 library in two ways: Statically Linking and Dynamically Linking. For both of these situations, you must choose proper switches for compiler to compile NMEA0183 library. If you want to compile your application and link it statically with MFC, NMEA0183 should be compiled and linked statically. And if you want to compile your application and link it dynamically with MFC, you should compile NMEA0183 library dynamically.

Further Information

For further information about NMEA0183 protocol and new specifications, visit NMEA.org

Enjoy!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

A. Riazi



Iran (Islamic Republic Of) Iran (Islamic Republic Of)

Member

I was born in Shiraz, a very beautiful famous city in Iran. I started programming when I was 12 years old with GWBASIC. Since now, I worked with various programming languages from Basic, Foxpro, C/C++, Visual Basic, Pascal to MATLAB and now Visual C++.
I graduated from Iran University of Science & Technology in Communication Eng., and now work as a system programmer for a telecommunication industry.
I wrote several programs and drivers for Synthesizers, Power Amplifiers, GPIB, GPS devices, Radio cards, Data Acqusition cards and so many related devices.
I'm author of several books like Learning C (primary and advanced), Learning Visual Basic, API application for VB, Teach Yourself Object Oriented Programming (OOP) and etc.
I'm winner of January, May, August 2003 and April 2005 best article of month competetion, my articles are:

You can see list of my articles, by clicking here



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
AnswerRe: Can't Parse msg. PinmemberA. Riazi3:54 31 May '06  
GeneralRe: Can't Parse msg. PinmemberAlastair Stell11:21 18 Oct '06  
GeneralRe: Can't Parse msg. PinmemberAndrew Qu0:35 24 Oct '06  
GeneralRe: Can't Parse msg. Pinmemberrajarcr18:35 21 Jun '07  
GeneralRe: Can't Parse msg. PinmemberAndrew Qu23:19 21 Jun '07  
GeneralRe: Can't Parse msg. Pinmemberrajarcr0:50 28 Jun '07  
GeneralRe: Can't Parse msg. PinmemberAndrew Qu11:16 29 Jun '07  
Hi, Raja,
In that case, I really cannot help much. However, you may try my class that has been working for me for a couple of years now.
To use my class:
 
kgvCSerialCom gpsPort;
CString csPortName;
csPortName.Format(_T("COM%d"),port_num);
//Baud Rate: 4800
//Data Bits: 8
//Parity: None
//Stop Bits: 1
//No Flow Control
// 9600 8 odd 1
if( !gpsPort.OpenPort(csPortName) ) return 0;
if( !gpsPort.ConfigurePort(m_gpsBaudRate, m_gpsByteSize,
m_gpsfParity, m_gpsParity, m_gpsStopBits) ) return 0;
 
if( !gpsPort.SetupComm(getGpsPort(),1200,1200) ) return 0;
if( !gpsPort.PurgeComm(getGpsPort(),PURGE_RXCLEAR) ) return 0;
//
char gpsString[600];
unsigned long bytesRead;
//
for(int i=0; i<1000; i++) { // stop after 10 minute
bytesRead = 0;
BOOL bReadOk = ReadFile( kgvGpsApi::GpsApi.getGpsPort(),
gpsString, 512, &bytesRead, 0 );
if( bReadOk && bytesRead>0 ) {
gpsString[bytesRead] = '\0';
//write to a file or display somewhere
}
Sleep(500);
}
gpsPort.ClosePort();
 
Please note that, I have not tested the above code. It only serves as an example.
 

*****************************************
***** Header file ******* kgvCSerialCom.h
*****************************************
#pragma once
 
// SerialCom.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CSerialCom window
//////////////////////////////////////////////////////////////////////
// SerialCom.h: implementation of the CSerialCom class.
// Written by Shibu K.V (shibukv@erdcitvm.org)
// Copyright (c) 2002
//
// To use CSerialCom, follow these steps:
// - Copy the files SerialCom.h & SerialCom.cpp and paste it in your
// Projects Directory.
// - Take Project tab from your VC++ IDE,Take Add to Project->Files.Select files
// SerialCom.h & SerialCom.cpp and click ok
// - Add the line #include "SerialCom.h" at the top of your Dialog's Header File.
// - Create an instance of CSerialCom in your dialogs header File.Say
// CSerialCom port;

// Warning: this code hasn't been subject to a heavy testing, so
// use it on your own risk. The author accepts no liability for the
// possible damage caused by this code.
//
// Version 1.0 7 Sept 2002.
 
//////////////////////////////////////////////////////////////////////
 
class kgvCSerialCom //: public CWnd
{
// Construction
public:
kgvCSerialCom();
 
HANDLE hComm;
DCB m_dcb;
COMMTIMEOUTS m_CommTimeouts;
BOOL m_bPortReady;
BOOL bWriteRC;
BOOL bReadRC;
DWORD iBytesWritten;
DWORD iBytesRead;
DWORD dwBytesRead;
 
// Implementation
public:
BOOL ReadByte(BYTE &resp);
BOOL WriteByte(BYTE bybyte);
BOOL OpenPort(const CString &portname);
BOOL SetCommunicationTimeouts(DWORD ReadIntervalTimeout,DWORD ReadTotalTimeoutMultiplier,DWORD ReadTotalTimeoutConstant,DWORD WriteTotalTimeoutMultiplier,DWORD WriteTotalTimeoutConstant);
BOOL ConfigurePort(DWORD BaudRate,BYTE ByteSize,DWORD fParity,BYTE Parity,BYTE StopBits);
 
virtual ~kgvCSerialCom();
void ClosePort();
 
BOOL IsPortReady( ) const { return m_bPortReady && hComm!=INVALID_HANDLE_VALUE; };
 
};
*********************************
*** Source file kgvCSerialCom.cpp
*********************************
// SerialCom.cpp : implementation file
//
#include "stdafx.h"
#include "kgvSerialCom.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
 

/////////////////////////////////////////////////////////////////////////////
// SerialCom.cpp: implementation of the CSerialCom class.
 
// Written by Shibu K.V (shibukv@erdcitvm.org)
// Copyright (c) 2002
//
// To use CSerialCom, follow these steps:
// - Copy the files SerialCom.h & SerialCom.cpp and paste it in your
// Projects Directory.
// - Take Project tab from your VC++ IDE,Take Add to Project->Files.Select files
// SerialCom.h & SerialCom.cpp and click ok
// - Add the line #include "SerialCom.h" at the top of your Dialog's Header File.
// - Create an instance of CSerialCom in your dialogs header File.Say
// CSerialCom port;

// Warning: this code hasn't been subject to a heavy testing, so
// use it on your own risk. The author accepts no liability for the
// possible damage caused by this code.
//
// Version 1.0 7 Sept 2002.
 
//////////////////////////////////////////////////////////////////////
 
// CSerialCom
 
kgvCSerialCom::kgvCSerialCom()
{
hComm=INVALID_HANDLE_VALUE;
}
 
kgvCSerialCom::~kgvCSerialCom()
{
if( hComm!=INVALID_HANDLE_VALUE ) CloseHandle(hComm);
}
 

//BEGIN_MESSAGE_MAP(kgvCSerialCom, CWnd)
//{{AFX_MSG_MAP(kgvCSerialCom)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
//END_MESSAGE_MAP()
 

/////////////////////////////////////////////////////////////////////////////
// kgvCSerialCom message handlers
// Example : OpenPort(L"COM2");
//
BOOL kgvCSerialCom::OpenPort( const CString &portname)
{
CString csPTN =_T("\\\\.\\"); //_T("//./");
#if WINVER > 0x0410
csPTN += portname;
#else
csPTN =portname;
#endif
 
hComm = CreateFile( csPTN,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
0,
0);
 
//
// hGpsPort = CreateFile(csPort, GENERIC_READ | GENERIC_WRITE,
// 1,NULL, OPEN_EXISTING,0,NULL);

return hComm!=INVALID_HANDLE_VALUE;
 
}
 

BOOL kgvCSerialCom::ConfigurePort(DWORD BaudRate, BYTE ByteSize,
DWORD fParity, BYTE Parity, BYTE StopBits)
{
if( hComm==INVALID_HANDLE_VALUE ) return FALSE;
 
if((m_bPortReady = GetCommState(hComm, &m_dcb))==0){
#ifdef _DEBUG
AfxMessageBox(L"GetCommState Error",MB_OK+MB_ICONERROR,-1);
#endif
CloseHandle(hComm);
hComm = INVALID_HANDLE_VALUE;
return false;
}
m_dcb.BaudRate = BaudRate;
m_dcb.ByteSize = ByteSize;
m_dcb.Parity =Parity ;
m_dcb.StopBits =StopBits;
m_dcb.fParity=fParity;
/*
m_dcb.fBinary=TRUE;
m_dcb.fDsrSensitivity=false;
m_dcb.fOutX=false;
m_dcb.fInX=false;
m_dcb.fNull=false;
m_dcb.fAbortOnError=TRUE;
m_dcb.fOutxCtsFlow=FALSE;
m_dcb.fOutxDsrFlow=false;
m_dcb.fDtrControl=DTR_CONTROL_DISABLE;
m_dcb.fDsrSensitivity=false;
m_dcb.fRtsControl=RTS_CONTROL_DISABLE;
m_dcb.fOutxCtsFlow=false;
m_dcb.fOutxCtsFlow=false;
*/
m_bPortReady = SetCommState(hComm, &m_dcb);
 
if(m_bPortReady ==0){
CloseHandle(hComm);
hComm = INVALID_HANDLE_VALUE;
return false;
}
 
return true;
}
 
BOOL kgvCSerialCom::SetCommunicationTimeouts(DWORD ReadIntervalTimeout,
DWORD ReadTotalTimeoutMultiplier,
DWORD ReadTotalTimeoutConstant,
DWORD WriteTotalTimeoutMultiplier,
DWORD WriteTotalTimeoutConstant)
{
if( hComm==INVALID_HANDLE_VALUE ) return FALSE;
 
if((m_bPortReady = GetCommTimeouts (hComm, &m_CommTimeouts))==0) return false;
 
m_CommTimeouts.ReadIntervalTimeout =ReadIntervalTimeout;
m_CommTimeouts.ReadTotalTimeoutConstant =ReadTotalTimeoutConstant;
m_CommTimeouts.ReadTotalTimeoutMultiplier =ReadTotalTimeoutMultiplier;
m_CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant;
m_CommTimeouts.WriteTotalTimeoutMultiplier =WriteTotalTimeoutMultiplier;
 
m_bPortReady = SetCommTimeouts (hComm, &m_CommTimeouts);
if(m_bPortReady ==0){
CloseHandle(hComm);
hComm = INVALID_HANDLE_VALUE;
return false;
}
 
return true;
}
 
BOOL kgvCSerialCom::WriteByte(BYTE bybyte)
{
iBytesWritten=0;
if( hComm==INVALID_HANDLE_VALUE ) return FALSE;
 
if(WriteFile(hComm,&bybyte,1,&iBytesWritten,NULL)==0) return false;
else return true;
}
 
BOOL kgvCSerialCom::ReadByte(BYTE &resp)
{
BYTE rx;
resp=0;
 
DWORD dwBytesTransferred=0;
if( hComm==INVALID_HANDLE_VALUE ) return FALSE;
 
if (ReadFile (hComm, &rx, 1, &dwBytesTransferred, 0)){
if (dwBytesTransferred == 1){
resp=rx;
return true;
}
}

return false;
}
 

void kgvCSerialCom::ClosePort()
{
if( hComm==INVALID_HANDLE_VALUE ) CloseHandle(hComm);
 
hComm = INVALID_HANDLE_VALUE;
 
return;
}
 

GeneralMy inaccurate data or conversions PinmemberJohnnyBoyWonder9:11 19 Sep '05  
GeneralRe: My inaccurate data or conversions PinmemberJohnnyBoyWonder5:05 20 Sep '05  
GeneralRe: My inaccurate data or conversions PinmemberJohnnyBoyWonder2:02 21 Sep '05  
Generalnice city Pinmemberbiberkopf23:04 6 Sep '05  
GeneralRe: nice city PinmemberA. Riazi23:47 6 Sep '05  
GeneralRe: nice city Pinmemberbiberkopf21:17 7 Sep '05  
GeneralRe: nice city PinmemberA. Riazi22:14 7 Sep '05  
GeneralConverting positions to x-y coordinates PinsussAnonymous8:37 19 May '05  
GeneralRe: Converting positions to x-y coordinates PinsussMuhammad Arsalan Khan1:38 9 Jul '05  
GeneralCan't Open Port Pinsussilmo Jung19:17 20 Mar '05  
GeneralRe: Can't Open Port PinmemberA. Riazi19:32 20 Mar '05  
GeneralRe: Can't Open Port Pinmember_DIFF_23:07 20 Mar '05  
GeneralRe: Can't Open Port Pinsussilmo Jung19:45 20 Mar '05  
Generalxyz co-ordinates PinsussAnonymous8:24 27 Jan '05  
GeneralRe: &#52852;&#46300;&#49324; &#51204;&#54868; &#48155;&#44592;/&#48730; &#50504;&#44058;&#44256; &#50724;&#47000; &#48260;&#54000;&#44592; &#50836;&#47161; PinmemberA. Riazi17:33 17 Apr '04  
GeneralGPS -Requirements Pinmemberjohnmcaffe19:51 16 Apr '04  
GeneralRe: GPS -Requirements PinmemberA. Riazi21:01 16 Apr '04  
GeneralRe: GPS -Requirements PinmemberAlex Evans12:47 6 May '04  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120529.1 | Last Updated 19 Feb 2003
Article Copyright 2003 by A. Riazi
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid