📄 wgps.cpp
字号:
/*++
Copyright (c) Wangsoft Corporation. All rights reserved.
File: wgps.cpp
Abstract:
Contents:
GPS related functions
--*/
#include "stdafx.h"
#include "wgps.h"
//#include <aygshell.h>
//#include <sipapi.h>
// Global Variables:
HANDLE g_hGPSPort = INVALID_HANDLE_VALUE;
HANDLE g_hGPSNewLocationData;
HANDLE g_hGPSDeviceStateChange;
GPS_POSITION g_gps_position;
GPS_DEVICE g_gps_device;
// Forward declarations of functions included in this code module:
DWORD WINAPI GPSReadThreadFunc(LPVOID lpParam);
void ParseRMC(LPTSTR szSentence);
LPTSTR GetNextToken(LPTSTR lpSentence, LPTSTR lpToken);
//
// FUNCTION: GPSOpenDevice()
//
// PURPOSE: Creates a connection to the GPS Intermediate Driver.
//
// COMMENTS:
//
// Parameters:
// hNewLocationData
// Handle to a Windows CE event created using CreateEvent, or NULL.
// The GPS Intermediate Driver signals the passed event whenever it has new GPS location information.
// hDeviceStateChange
// Handle to a Windows CE event created using CreateEvent, or NULL.
// The GPS Intermediate Driver signals the passed event whenever the state of the device changes.
// szDeviceName
// Reserved. Must be NULL.
// dwFlags
// Reserved. Must be 0.
//
// Return Values:
// If successful, returns a handle to the GPS Intermediate Driver.
// If unsuccessful, returns NULL.
//
HANDLE GPSOpenDevice(HANDLE hNewLocationData, HANDLE hDeviceStateChange, const WCHAR *szDeviceName, DWORD dwFlags)
{
DWORD dwError;
COMMTIMEOUTS ct;
DCB dcb;
if(NULL != hNewLocationData)
{
g_hGPSNewLocationData = hNewLocationData;
}
if(NULL != hDeviceStateChange)
{
g_hGPSDeviceStateChange = hDeviceStateChange;
}
g_hGPSPort = CreateFile (szDeviceName,
GENERIC_READ | GENERIC_WRITE,
0, // COM port cannot be shared
NULL, // Always NULL for Windows CE
OPEN_EXISTING,
0, // Non-overlapped operation only
NULL); // Always NULL for Windows CE
if(INVALID_HANDLE_VALUE == g_hGPSPort)
{
dwError = GetLastError();
return NULL;
}
// Set the timeouts to specify the behavior of reads and writes.
GetCommTimeouts(g_hGPSPort, &ct);
ct.ReadIntervalTimeout = MAXDWORD;
ct.ReadTotalTimeoutMultiplier = 0;
ct.ReadTotalTimeoutConstant = 0;
ct.WriteTotalTimeoutMultiplier = 10;
ct.WriteTotalTimeoutConstant = 1000;
if(FALSE == SetCommTimeouts(g_hGPSPort, &ct))
{
GPSCloseDevice(g_hGPSPort); // Close comm port
dwError = GetLastError();
return NULL;
}
// Get the current communications parameters, and configure baud rate
dcb.DCBlength = sizeof(DCB);
GetCommState(g_hGPSPort, &dcb);
dcb.BaudRate = CBR_4800; // Set baud rate to 4,800
dcb.fOutxCtsFlow = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fOutxDsrFlow = FALSE;
dcb.fOutX = TRUE; // XON/XOFF control
dcb.fInX = TRUE;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
if(FALSE == SetCommState(g_hGPSPort, &dcb))
{
GPSCloseDevice(g_hGPSPort); // Close comm port
dwError = GetLastError();
return NULL;
}
// Now need to create the thread that will be reading the comms port
HANDLE hGPSReadThread = CreateThread(NULL, 0, GPSReadThreadFunc, NULL, 0, NULL);
if(NULL != hGPSReadThread)
{
CloseHandle(hGPSReadThread);
}
else
{
GPSCloseDevice(g_hGPSPort); // Close comm port
dwError = GetLastError();
return NULL;
}
return g_hGPSPort;
}
//
// FUNCTION: GPSGetPosition()
//
// PURPOSE: Retrieves location information, including latitude and longitude.
//
// COMMENTS:
//
// Parameters:
// hGPSDevice
// Handle returned by a call to GPSOpenDevice.
// This parameter can also be NULL. If NULL, the GPS Intermediate Driver does not turn on the GPS hardware,
// but does return data if the data has already been received (through some other use of the GPS
// Intermediate Driver), and the data satisfies the criteria set by the dwMaximumAge parameter.
// Passing NULL enables applications that can use location information, but do not require it,
// to retrieve existing data without requiring that the GPS hardware consume power.
// pGPSPosition
// Pointer to a GPS_POSITION structure. On return, this structure is filled with location data
// obtained by the GPS Intermediate Driver. The dwValidFields member of the GPS_POSITION instance
// specifies which fields of the instance are valid.
// dwMaximumAge
// Maximum age, in milliseconds, of location information. The GPS Intermediate Driver only returns
// information that has been received within the time specified by this parameter.
// Any information that is older than this age is not returned. The elements of the GPS_POSITION
// instance that are valid for the given dwMaximumAge value are specified in the dwValidFields
// element of the instance.
// dwFlags
// Reserved. Must be 0.
//
// Return Values:
// If successful, returns ERROR_SUCCESS.
// If unsuccessful, returns an error code.
//
DWORD GPSGetPosition(HANDLE hGPSDevice, GPS_POSITION *pGPSPosition, DWORD dwMaximumAge, DWORD dwFlags)
{
pGPSPosition->dwVersion = g_gps_position.dwVersion;
pGPSPosition->dwValidFields = g_gps_position.dwValidFields;
pGPSPosition->dwFlags = g_gps_position.dwFlags;
pGPSPosition->stUTCTime = g_gps_position.stUTCTime;
pGPSPosition->dblLatitude = g_gps_position.dblLatitude;
pGPSPosition->dblLongitude = g_gps_position.dblLongitude;
pGPSPosition->flSpeed = g_gps_position.flSpeed;
pGPSPosition->flHeading = g_gps_position.flHeading;
pGPSPosition->dblMagneticVariation = g_gps_position.dblMagneticVariation;
return ERROR_SUCCESS;
}
//
// FUNCTION: GPSGetDeviceState()
//
// PURPOSE: Retrieves information about the current state of the GPS hardware.
//
// COMMENTS:
//
// Parameters:
// pGPSDevice
// Pointer to a GPS_DEVICE structure. On return, this structure is filled with
// device data for the GPS hardware managed by the GPS Intermediate Driver.
// Return Values:
// If successful, returns ERROR_SUCCESS.
// If unsuccessful, returns an error code.
//
DWORD GPSGetDeviceState(GPS_DEVICE *pGPSDevice)
{
pGPSDevice->dwVersion = g_gps_device.dwVersion;
pGPSDevice->dwDeviceState = g_gps_device.dwDeviceState;
pGPSDevice->ftLastDataReceived = g_gps_device.ftLastDataReceived;
return ERROR_SUCCESS;
}
//
// FUNCTION: GPSCloseDevice()
//
// PURPOSE: Closes the connection to the GPS Intermediate Driver.
//
// COMMENTS:
//
// Parameters:
// hGPSDevice
// Handle returned by a call to GPSOpenDevice.
//
// Return Values:
// If successful, returns ERROR_SUCCESS.
// If unsuccessful, returns an error code.
//
DWORD GPSCloseDevice(HANDLE hGPSDevice)
{
if(INVALID_HANDLE_VALUE != hGPSDevice)
{
CloseHandle(hGPSDevice);
g_hGPSPort = INVALID_HANDLE_VALUE;
}
else
{
if(INVALID_HANDLE_VALUE != g_hGPSPort)
{
CloseHandle(g_hGPSPort);
g_hGPSPort = INVALID_HANDLE_VALUE;
}
}
return ERROR_SUCCESS;
}
// Thread function reads NMEA output from GPS device.
DWORD WINAPI GPSReadThreadFunc(LPVOID lpParam)
{
DWORD dwBytesRead, dwEvtMask;
char szSentence[1000], c;
TCHAR szwcsSentence[1000];
int nc = 0;
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
// Specify a set of events to be monitored for the port.
SetCommMask(g_hGPSPort, EV_RXCHAR | EV_ERR);
// Init g_gps_position.
g_gps_position.dwVersion = GPS_VERSION_1;
g_gps_position.dwFlags = GPS_DATA_FLAGS_HARDWARE_ON;
g_gps_position.dwValidFields = 0;
// Init g_gps_device.
g_gps_device.dwVersion = GPS_VERSION_1;
g_gps_device.dwDeviceState = GPS_DEVICE_STATE_ON;
// Send GPSDeviceStateChange ON event.
if(NULL != g_hGPSDeviceStateChange)
{
SetEvent(g_hGPSDeviceStateChange);
}
while(INVALID_HANDLE_VALUE != g_hGPSPort)
{
// Waiting for EV_RXCHAR and EV_ERR event.
WaitCommEvent(g_hGPSPort, &dwEvtMask, 0);
// Again specify a set of events to be monitored for the port.
SetCommMask(g_hGPSPort, EV_RXCHAR | EV_ERR);
if(dwEvtMask == EV_ERR)
{
// Deal with communications error
return GetLastError();
}
do
{
// If dwEvtMask == EV_RXCHAR
if(!ReadFile(g_hGPSPort, &c, 1, &dwBytesRead, NULL))
{
return GetLastError();
}
if(dwBytesRead == 1)
{
if(c != '\n') // LF marks end of sentence
{
szSentence[nc++] = c;
}
else
{
// Remove trailing CR
szSentence[nc-1] = '\0';
nc = 0;
if(strlen(szSentence) <= 6)
{
break;
}
else if(szSentence[0] != '$')
{
break;
}
else
{
// Read a sentence. Convert to Unicode
mbstowcs(szwcsSentence, szSentence, 1000);
// Find sentence ID
if(wcsncmp(&szwcsSentence[3], _T("RMC"), 3) == 0)
{
// Parse RMC data into g_gps_position and g_gps_device.
ParseRMC(szwcsSentence);
// Send GPSNewLocationData event.
if((NULL != g_hGPSNewLocationData) && (0 != g_gps_position.dwValidFields))
{
SetEvent(g_hGPSNewLocationData);
}
}
}
}
}
}
while (dwBytesRead == 1);
}
// Mark the state flag from ON to OFF.
g_gps_position.dwFlags = GPS_DATA_FLAGS_HARDWARE_OFF;
g_gps_position.dwValidFields = 0;
g_gps_device.dwDeviceState = GPS_DEVICE_STATE_OFF;
// Send GPSDeviceStateChange OFF event.
if(NULL != g_hGPSDeviceStateChange)
{
SetEvent(g_hGPSDeviceStateChange);
}
return ERROR_SUCCESS;
}
// Parses a RMC sentence which has the format:
// $GPRMC,195531,A,5326.986,N,00610.147,W,000.0,360.0,170500,007.2,W*7F
void ParseRMC(LPTSTR szSentence)
{
TCHAR szToken[20];
DWORD dwCheckSum = 0;
DWORD dwSentenceCheckSum;
LPTSTR lpEnd;
GPS_POSITION gps_position;
// Calculate the checksum. Exclude $ and work up to *
for(UINT i = 1; i < wcslen(szSentence) && szSentence[i] != '*'; i++)
{
dwCheckSum ^= szSentence[i];
}
// lpNextTok points at ID $GPRMS, ignore this
szSentence = GetNextToken(szSentence, szToken);
// Time of Fix, convert to Unicode (UTC hhmmss)
szSentence = GetNextToken(szSentence, szToken);
gps_position.stUTCTime.wSecond = (WORD)wcstoul(szToken+4, &lpEnd, 10);
szToken[4] = '\0';
gps_position.stUTCTime.wMinute = (WORD)wcstoul(szToken+2, &lpEnd, 10);
szToken[2] = '\0';
gps_position.stUTCTime.wHour = (WORD)wcstoul(szToken, &lpEnd, 10);
// Navigation receiver (GPS) warning
szSentence = GetNextToken(szSentence, szToken);
if(szToken[0] != 'A')
{
// Suspect signal
g_gps_position.dwValidFields = 0;
return;
}
// If Receiving OK
// Latitude (ddmm.ss)
szSentence = GetNextToken(szSentence, szToken);
gps_position.dblLatitude = wcstod(szToken, NULL);
// Latitude N or S
szSentence = GetNextToken(szSentence, szToken);
if (szToken[0] == 'S')
{
gps_position.dblLatitude = 0 - gps_position.dblLatitude;
}
// Longitude (dddmm.ss)
szSentence = GetNextToken(szSentence, szToken);
gps_position.dblLongitude = wcstod(szToken, NULL);
// Longitude E or W
szSentence = GetNextToken(szSentence, szToken);
if (szToken[0] == 'W')
{
gps_position.dblLongitude = 0 - gps_position.dblLongitude;
}
// Speed (Knots)
szSentence = GetNextToken(szSentence, szToken);
gps_position.flSpeed = (float)wcstod(szToken, NULL);
// Course made good (Deg)
szSentence = GetNextToken(szSentence, szToken);
gps_position.flHeading = (float)wcstod(szToken, NULL);
// Date (ddmmyyyy)
szSentence = GetNextToken(szSentence, szToken);
gps_position.stUTCTime.wYear = (WORD)wcstoul(szToken+4, &lpEnd, 10);
szToken[4] = '\0';
gps_position.stUTCTime.wMonth = (WORD)wcstoul(szToken+2, &lpEnd, 10);
szToken[2] = '\0';
gps_position.stUTCTime.wDay = (WORD)wcstoul(szToken, &lpEnd, 10);
// Magnetic Variation (Deg)
szSentence = GetNextToken(szSentence, szToken);
gps_position.dblMagneticVariation = wcstod(szToken, NULL);
// Magnetic Variation E or W
szSentence = GetNextToken(szSentence, szToken);
if (szToken[0] == 'W')
{
gps_position.dblMagneticVariation = 0 - gps_position.dblMagneticVariation;
}
// Do the check sum
szSentence = GetNextToken(szSentence, szToken);
dwSentenceCheckSum = wcstoul(szToken, &lpEnd, 16);
if(dwCheckSum == dwSentenceCheckSum)
{
// Checksum OK
// Set g_gps_position Data.
g_gps_position.dwValidFields = GPS_VALID_MAGNETIC_VARIATION;
g_gps_position.stUTCTime = gps_position.stUTCTime;
g_gps_position.dblLatitude = gps_position.dblLatitude;
g_gps_position.dblLongitude = gps_position.dblLongitude;
g_gps_position.flSpeed = gps_position.flSpeed;
g_gps_position.flHeading = gps_position.flHeading;
g_gps_position.dblMagneticVariation = gps_position.dblMagneticVariation;
// Set g_gps_device Data.
SystemTimeToFileTime(&g_gps_position.stUTCTime, &g_gps_device.ftLastDataReceived);
}
else
{
// Checksum ERROR
g_gps_position.dwValidFields = 0;
}
}
// Returns the next token from the sentence.
LPTSTR GetNextToken(LPTSTR lpSentence, LPTSTR lpToken)
{
lpToken[0] = '\0';
if(lpSentence == NULL) // empty sentence
{
return NULL;
}
if(lpSentence[0] == '\0') // end of sentence
{
return NULL;
}
if(lpSentence[0] == ',') // empty token
{
return lpSentence + 1;
}
while(*lpSentence != ',' && *lpSentence != '\0' && *lpSentence != '*')
{
*lpToken = *lpSentence;
lpToken++;
lpSentence++;
}
// Skip over comma that terminated the token.
lpSentence++;
*lpToken = '\0';
return lpSentence;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -