www.pudn.com > GPSViewer.rar > GPSViewerDlg.cpp


/* GPSViewerDlg.cpp 
 * ---------------- 
 * This file is the heart of the GPSViewer Application and demonstrates how to 
 * use the Centrality GPS NMEA interface located on COM7.  Careful study of this 
 * code will allow the user to understand the methods needed to fully utilize 
 * the COM7 GPS port.  This code is intended to be used as a fully functional 
 * sample for complete integration with the Centrality GPS platform and this  
 * purpose only.  Debug statements have been commented out but left embedded in 
 * the code for development purposes. 
 * 
 * Here are the key steps that you should take note of as you walk through 
 * this code: 
 * 
 * 1. Using Createfile to open the COM7 port 
 * 2. Setting up the COM7 port 
 * 3. Creating a thread to wait on COM7 and read its contents 
 * 4. Parsing NMEA commands that come out of the COM7 port 
 * 5. Safely closing the port 
 * 
 * Author: Howard Shen, Centrality Communications MTS 
 * Date: 8/29/03 
*/ 
 
#include "stdafx.h" 
#include "GPSViewer.h" 
#include "GPSViewerDlg.h" 
#include "GPSExport.h" 
#include "windows.h" 
#include "math.h" 
#include "stdlib.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
/* Global Defines */ 
/* -------------- */ 
#define g_UpdateInterval 1000  // This is the update interval for the screen (in milliseconds) 
 
 
/* Global variables */ 
/* ---------------- */ 
CString time, lat, latdir, lon, londir, numused, alt; 
UINT g_allinit; 
char buff[1000];		// Read buffer 
UINT m_nTimer;			// Timer for refreshing the screen 
HANDLE comm_hand;		// Global handle to the COM7 port 
HANDLE nmeathread_hand; // Global handle to the NMEA reading thread 
 
 
/* Function Prototypes */ 
/* ------------------- */ 
DWORD WINAPI ReadNMEAThread(LPVOID lpParameter); 
// This is the function which contorls the NMEA reading thread 
 
 
/* START of Microsoft Machine Generated Message Handler Code - DO NOT MODIFY */ 
///////////////////////////////////////////////////////////////////////////// 
// CGPSViewerDlg dialog 
 
CGPSViewerDlg::CGPSViewerDlg(CWnd* pParent /*=NULL*/) 
	: CDialog(CGPSViewerDlg::IDD, pParent) 
{ 
	//{{AFX_DATA_INIT(CGPSViewerDlg) 
	m_staticlong = _T(""); 
	//}}AFX_DATA_INIT 
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
} 
 
void CGPSViewerDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CGPSViewerDlg) 
	DDX_Text(pDX, IDC_STATIC_LONG, m_staticlong); 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CGPSViewerDlg, CDialog) 
	//{{AFX_MSG_MAP(CGPSViewerDlg) 
	ON_WM_CANCELMODE() 
	ON_WM_TIMER() 
	ON_WM_PAINT() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_CLOSE() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// End of Microsoft machine generated code 
 
 
/* Function: OnInitDialog() 
 * ------------------------ 
 * This fucntion gets called at startup and initalizes the whole program. 
 * Initializing the COM port takes place here.  Key steps (1), (2) ,and (3) 
 * take place in this function. 
 */ 
BOOL CGPSViewerDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog(); 
	DCB commDCB; 
	COMMTIMEOUTS timeouts; 
	DWORD dwError; 
	ULONG bytesWritten; 
 
	// Set the icon for this dialog.  The framework does this automatically 
	//  when the application's main window is not a dialog 
	SetIcon(m_hIcon, TRUE);			// Set big icon 
	SetIcon(m_hIcon, FALSE);		// Set small icon 
	 
	CenterWindow(GetDesktopWindow());	// center to the hpc screen 
 
	// Key Step #1 - Using CreateFile to open COM7 
	// ------------------------------------------- 
	comm_hand = CreateFile(L"COM7:", GENERIC_READ | GENERIC_WRITE, 0, NULL, 
								OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL); 
	if(comm_hand == NULL) 
	{ 
		MessageBox (TEXT("Unable to open COM7."), TEXT("Error"), MB_OK); 
		dwError = GetLastError (); 
		DEBUGMSG(1, (L"Opening COM7 failed: %d!\r\n", (int)GetLastError())); 
		return TRUE; 
	} 
 
	commDCB.DCBlength = sizeof (DCB);      
 
	// Key Step #2 - Setting the COM7 port settings 
	// -------------------------------------------- 
	// Get the default port setting information. 
	if(!GetCommState (comm_hand, &commDCB)) 
	{ 
		CloseHandle(comm_hand); 
		DEBUGMSG(1, (L"Failed in getting COM7 DCB settings: %d!\r\n", (int)GetLastError())); 
		return FALSE; 
	} 
 
	commDCB.DCBlength = sizeof(DCB);  
	commDCB.BaudRate = 38400;             // Current baud 
	commDCB.ByteSize = 8;                 // Number of bits/bytes, 4-8 
	commDCB.Parity = NOPARITY;            // 0-4=no,odd,even,mark,space  
	commDCB.StopBits = ONESTOPBIT;        // 0,1,2 = 1, 1.5, 2 
   
	// Setting COM7 to Centrality speicifcations 
	if (!SetCommState(comm_hand, &commDCB)) 
	{ 
		CloseHandle(comm_hand); 
		MessageBox (TEXT("Unable to configure COM7 DCB settings"), TEXT("Error"), MB_OK); 
		DEBUGMSG(1, (L"Error in trying to set COM7 DCB settings: %d!\r\n", (int)GetLastError())); 
		dwError = GetLastError (); 
		return FALSE; 
	} 
  
	// Get the default timeout settings for port 
	if(!GetCommTimeouts(comm_hand, &timeouts)) 
	{ 
		CloseHandle(comm_hand); 
		DEBUGMSG(1, (L"Failed in getting COM7 timeout settings: %d!\r\n", (int)GetLastError())); 
		return FALSE; 
	} 
	DEBUGMSG(1, (L"DCB set successfully.\r\n")); 
 
	// Change the timeouts structure settings to Centrality settings 
	timeouts.ReadIntervalTimeout = 0;   
	timeouts.ReadTotalTimeoutMultiplier = 0;   
	timeouts.ReadTotalTimeoutConstant = 0;     
 
	// Set the time-out parameters for all read and write operations on the port.  
	if (!SetCommTimeouts(comm_hand, &timeouts)) 
	{ 
		CloseHandle(comm_hand); 
		MessageBox (TEXT("Unable to configure COM7 timeout settings"), TEXT("Error"), MB_OK); 
		DEBUGMSG(1, (L"Error in trying to set COM7 timeout settings: %d!\r\n", (int)GetLastError())); 
		dwError = GetLastError (); 
		return FALSE; 
	} 
	DEBUGMSG(1, (L"Comm timeouts set successfully.\r\n")); 
 
	// Key Step #3 - Creating a thread to wait on COM7 and read its contents 
	// ---------------------------------------------------------------------- 
	// * See definition of ReadNMEAThread() for details on thread operations 
	nmeathread_hand = CreateThread(NULL, 0, ReadNMEAThread, NULL, 0, NULL); 
	if(!nmeathread_hand) 
	{ 
		DEBUGMSG(1, (L"Could not create NMEA read thread.\r\n")); 
		return 0; 
	} 
	m_nTimer = SetTimer(1, g_UpdateInterval, 0); 
	g_allinit = 1; 
 
	// Writing something to the COM7 port to start GPS processing (Added March 2004) 
	// ----------------------------------------------------------------------------- 
	if(!WriteFile(comm_hand, (L"StartGPS!\r\n"), 20, &bytesWritten, NULL)) 
	{ 
		DEBUGMSG(1, (L"Could not write message to COM7 to start GPS.\r\n")); 
	} 
	DEBUGMSG(1, (L"GPS started! Bytes written: %d.\r\n", bytesWritten)); 
	 
	return TRUE; 
} 
 
 
/* Function: OnCancelMode() 
 * ------------------------ 
 * This fucntion gets called to deinitialize the GPSViewer.  Notice that you   
 * should wait for the NMEA reading thread to exit cleanly before continuing. 
 * Key step (5) is covered by this function. 
 */ 
void CGPSViewerDlg::OnCancelMode()  
{ 
	CDialog::OnCancelMode(); 
	 
	if(g_allinit == 1) { 
		DEBUGMSG(1, (L"Cancel application.  Shutting down.\r\n"));	 
 
		SetCommMask(comm_hand, 0); 
 
		// Wait for NMEA reading thread to cleanly exit (max 5 sec) 
		WaitForSingleObject(nmeathread_hand, 5000); 
 
		KillTimer(m_nTimer); 
 
		// This call officially closes the COM7 and shuts down GPS. 
		CloseHandle(comm_hand); 
 
		g_allinit = 0; 
	} else { 
		DEBUGMSG(1, (L"Trying to cancel, but nothing was started.  Exiting.\r\n")); 
	} 
} 
 
 
/* Function: OnNotify() 
 * ------------------------ 
 * This fucntion is not vital to the opertaions of GPS but needs to exist 
 * for Microsoft EVC programs.  There is no need to modify/study this function. 
 */ 
BOOL CGPSViewerDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)  
{ 
	// TODO: Add your specialized code here and/or call the base class 
	 
	return CDialog::OnNotify(wParam, lParam, pResult); 
} 
 
 
/* Function: OnNotify() 
 * -------------------- 
 * This fucntion's only purpose is to force the application to redraw the 
 * output at the interval specified by g_UpdateInterval.  It's not that  
 * important. 
 */ 
void CGPSViewerDlg::OnTimer(UINT nIDEvent)  
{ 
	//MessageBeep(0xFFFFFFFF);  // Beep 
	DEBUGMSG(1, (L"Timer Signled.")); 
	Invalidate(); 
	UpdateWindow(); 
	CDialog::OnTimer(nIDEvent); 
} 
 
 
/* Function: ReadNMEAThread() 
 * -------------------------- 
 * This is the function responsible for reading the GPS NMEA port (COM7)  
 * and parsing the output - key step (4).  Basically, this function sets 
 * up to read the COM port whenever an event is passed down by the GPS  
 * NMEA driver.  This event is the simple EV_RXCHAR.  You must first set up 
 * the function to wait on this even (4a) and then read from the port when 
 * the event is signified (4b).  After reading information out of the port, 
 * you must then parse it to extract the needed location/satellite  
 * information (4c).  You will notice that all the information needed 
 * by GPSViewer is contained in the $GPGGA NMEA message.  You are obviously 
 * free to do use whatever information you need that is supported by the  
 * NMEA standard.  If you need other mesages to be supported by Centrality 
 * Communications, please contact your local representative. 
 */ 
DWORD WINAPI ReadNMEAThread(LPVOID lpParameter) 
{ 
	int start, endline, onestart, oneend, length, linelen, degdig; 
	ULONG bytesRead; 
	DWORD EventMask = EV_RXCHAR; 
 
	// Setting the CommMask to listen for this event (4a) 
	SetCommMask(comm_hand, EV_RXCHAR); 
	 
	// Wait on the event 
	while(WaitCommEvent(comm_hand, &EventMask, NULL)) 
	{ 
		// Clear the buffer before you start reading 
		memset(buff, 0, 1000); 
 
		// Read from COM7 (4b) 
		while(ReadFile(comm_hand, buff, 1000, &bytesRead, NULL)) 
		{ 
			if(bytesRead == 0) 
				break; 
 
			CString dacstr(buff); 
			DEBUGMSG(1, (L"bytesRead = %d", bytesRead)); 
			DEBUGMSG(1, (L"CString = %s", dacstr)); 
 
			start = 0; 
			endline = 0; 
 
			// Parse/Process the output (4c) 
			while(1) 
			{ 
				start = dacstr.Find(L"$G", start); 
				if(start < 0) 
					break; 
				endline = dacstr.Find(L"\r\n", start); 
				if(endline < 0) 
					break; 
 
				linelen = endline - start; 
				//DEBUGMSG(1, (L"start = %d endline = %d length = %d", start, endline, linelen));	 
 
				// Extract one line 
				CString oneline; 
				oneline = dacstr.Mid(start, linelen); 
				DEBUGMSG(1, (L"Oneline = %s", oneline)); 
 
				// Process one line 
				onestart = 0; 
				oneend = 0; 
				if(oneline.Left(6) == L"$GPGGA") 
				{ 
					onestart += oneline.Find(L",", onestart); 
					oneend = oneline.Find(L",", onestart+1); 
					length = oneend - onestart - 1; 
					time = oneline.Mid(onestart + 1, length); 
					time = time.Left(2) + L":" + time.Mid(2,2) + L":" + time.Right(5); 
					//DEBUGMSG(1, (L"onestart = %d oneend = %d length = %d", onestart, oneend, length)); 
 
					onestart = oneend+1; 
					oneend = oneline.Find(L",", onestart+1); 
					length = oneend - onestart; 
					lat = oneline.Mid(onestart, length); 
					degdig = lat.GetLength() - 2; 
					lat = lat.Left(2) + L"° " + lat.Right(degdig); 
					//DEBUGMSG(1, (L"onestart = %d oneend = %d length = %d", onestart, oneend, length)); 
				 
					onestart = oneend+1; 
					oneend = oneline.Find(L",", onestart+1); 
					length = oneend - onestart; 
					latdir = oneline.Mid(onestart, length);	 
 
					onestart = oneend+1; 
					oneend = oneline.Find(L",", onestart+1); 
					length = oneend - onestart; 
					lon = oneline.Mid(onestart, length); 
					degdig = lon.GetLength() - 3; 
					lon = lon.Left(3) + "° " + lon.Right(degdig); 
 
					onestart = oneend+1; 
					oneend = oneline.Find(L",", onestart+1); 
					length = oneend - onestart; 
					londir = oneline.Mid(onestart, length); 
 
					onestart = oneend+1; 
					oneend = oneline.Find(L",", onestart+1); 
					length = oneend - onestart; 
					// skip GPS quality indicator 
			 
					onestart = oneend+1; 
					oneend = oneline.Find(L",", onestart+1); 
					length = oneend - onestart; 
					numused = oneline.Mid(onestart, length);	 
 
					onestart = oneend+1; 
					oneend = oneline.Find(L",", onestart+1); 
					length = oneend - onestart; 
					// skip horizontal dilution of position 
 
					onestart = oneend+1; 
					oneend = oneline.Find(L",", onestart+1); 
					length = oneend - onestart; 
					alt = oneline.Mid(onestart, length); 
 
					//DEBUGMSG(1, (L"time = %s lat = %s latdir = %s", time, lat, latdir)); 
					//DEBUGMSG(1, (L"lon = %s londir = %s numused = %s alt = %s", lon, londir, numused, alt)); 
 
				} // end of processing for one line 
				 
				start = endline + 2; 
 
			} // end of buffer processing 
		} // end of ReadFile 
	} // end of WaitCommEvent 
 
	return 0; 
}// end of ReadNMEAThread 
 
 
/* Function: OnPaint() 
 * ------------------- 
 * This fucntion just updates the strings needed to be drawn for output. 
 * It is not very exciting. 
 */ 
void CGPSViewerDlg::OnPaint()  
{ 
	CPaintDC dc(this); // device context for painting 
	 
	// TODO: Add your message handler code here 
 
	CString tempstr; 
 
	tempstr.Format(L"LON : %s %s", lon, londir); 
	GetDlgItem(IDC_STATIC_LONG)->SetWindowText(tempstr); 
 
	tempstr.Format(L"LAT : %s %s", lat, latdir); 
	GetDlgItem(IDC_STATIC_LAT)->SetWindowText(tempstr); 
 
	tempstr.Format(L"TIME: %s", time); 
	GetDlgItem(IDC_STATIC_TIME)->SetWindowText(tempstr); 
 
	tempstr.Format(L"SATs: %s", numused); 
	GetDlgItem(IDC_STATIC_SAT)->SetWindowText(tempstr); 
 
	tempstr.Format(L"ALT : %s M", alt); 
	GetDlgItem(IDC_STATIC_ALT)->SetWindowText(tempstr); 
 
	// Do not call CDialog::OnPaint() for painting messages 
} 
 
 
/* Function: OnNotify() 
 * -------------------- 
 * This function closes the application when you bit the "X" button on the 
 * console.  OnClose will call the OnCancel function, so hitting "X" and 
 * hitting "OK" has the same effect. 
 */ 
void CGPSViewerDlg::OnClose()  
{ 
	DEBUGMSG(1, (L"Closing application.  Shutting down.\r\n")); 
 
	CDialog::OnClose(); 
}