⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nmea0183.cpp

📁 非常好用的GPS串口通信
💻 CPP
字号:
///////////////////////////////////////////////////////////////////////////////
// Nmea0183.cpp : implementation of the CNmea0183 class
//
// Copyright (c) 2004,上海合众思壮科技有限责任公司GIS部
//
// All rights reserved
//
// 文件名称:Nmea0183.cpp
//
// 摘要    :Nmea0183协议类
//
// 作者    :Hansom
//
// 当前版本:1.1
//
// 完成日期:2004年04月12日
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Nmea0183.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

///////////////////////////////////////////////////////////////////////////////
// Construction
CNmea0183::CNmea0183()
{
	m_nWritePtr = 0;
	m_nAllSatNum = 0;
	m_nRevSatNum = 0;
	m_nRevFrmNum = 0;
	m_pchProBuf = new char[BUFFER_SIZE];
	memset(m_SatData, 0, sizeof(ST_SAT_DATA) * SAT_NUMBER);
}

///////////////////////////////////////////////////////////////////////////////
// Destruction
CNmea0183::~CNmea0183()
{
	if(m_pchProBuf != NULL)
	{
		delete [] m_pchProBuf;
		m_pchProBuf = NULL;
	}
}

///////////////////////////////////////////////////////////////////////////////
// 得到坐标转换参数
double CNmea0183::GetCoor(const double dbIn)const
{
	int nDu = (int)(dbIn / 100);
	
	return nDu + (dbIn - nDu * 100) / 60;
}

///////////////////////////////////////////////////////////////////////////////
// 从接收缓冲区的数据搜索完整一帧,并将其转换为具体的数据结构
int	CNmea0183::SearchOneFrame(char *pchRevBuf, const int nRevLen, int &nReadPtr,
							  const int nWritePtr, ST_MSG *pMsg)
{
	int	nFrmNum			= 0;
	int	ntempReadPtr	= nReadPtr;
	
	byte bdata;
	static BOOL bIsHead = FALSE;

	while(ntempReadPtr != nWritePtr)
	{
		// 接收缓冲区内容未处理完
		bdata=pchRevBuf[ntempReadPtr];
		ntempReadPtr++;
		if(ntempReadPtr >= nRevLen)
		{
			ntempReadPtr = 0;
		}

		if(bdata == '$')
		{
			// 找到起始符
			m_nWritePtr=0;
			bIsHead = TRUE;
		}
		else if(!bIsHead)
		{
			// 尚未找到起始符
			continue;
		}
		else if(bdata == 0x0d)
		{
			// 找到结束符
			m_pchProBuf[m_nWritePtr] = 0;
			bIsHead = FALSE;
			if(ProOneFrm(pMsg))
			{
				// 正确处理,返回一帧数据
				nFrmNum = 1;
				m_nWritePtr=0;
				break;
			}
			else
			{
				// 丢掉该帧,继续处理之后字节
				m_nWritePtr=0;
				continue;
			}
		}

		m_pchProBuf[m_nWritePtr] = bdata;
		m_nWritePtr++;

		if(m_nWritePtr >= BUFFER_SIZE)
		{
			// 缓冲区已满还未收全一帧,放弃当前缓冲区数据,继续处理之后字节
			m_nWritePtr=0;
			continue;
		}
	}

	nReadPtr = ntempReadPtr;

	return nFrmNum;
}

///////////////////////////////////////////////////////////////////////////////
// 判断数据检验是否正确,如果正确则生成具体数据结构
BOOL CNmea0183::ProOneFrm(ST_MSG *pMsg)
{
	BOOL bRtn = FALSE;
	char *p, check[2];
	char xor_chk, val;

	// 计算校验
	p = strchr(m_pchProBuf, '*');
	if(p == NULL)
	{
		return bRtn;
	}

	p++;
	strncpy(check, p, 2);

	xor_chk = '$';
	// 计算校验
	for(int i=0; ; i++)
	{
		if(m_pchProBuf[i] == '*')
		{
			break;
		}

		xor_chk ^= m_pchProBuf[i];
	}

	if((check[0] >= '0') && (check[0] <= '9'))
	{
		val = (check[0] - '0') * 16;
	}
	else
	{
		val = (check[0] - 0x37) * 16;
	}

	if((check[1] >= '0') && (check[1] <= '9'))
	{
		val += (check[1] - '0');
	}
	else
	{
		val += (check[1] - 0x37);
	}

	if(val != xor_chk)
	{
		return bRtn;	// 校验错
	}

	char* pchMsName[] = {"GPRMC", "GPGSA", "GPGSV", "GPGGA"};
	int nMsNum = sizeof(pchMsName) / sizeof(pchMsName[0]);

	GPS_DATA_TYPE emMsType = ENUM_All_GPS;
	for(int nType = 0; nType < nMsNum; nType++)
	{
		if(memcmp(pchMsName[nType], &m_pchProBuf[1], 5) == 0)
		{
			emMsType = (GPS_DATA_TYPE)(ENUM_GPSDATA + nType);
			break;
		}
	}

	switch(emMsType)
	{
	case ENUM_GPSDATA:		// GPS主要数据
		{
			int nTmp;
			// 时间
			p = strchr(m_pchProBuf, ',');
			nTmp = atoi(++p);
			// 是否定位
			p = strchr(p, ',');
			if(*(++p) != 'A')
			{
				// GPS不定位
				m_GpsData.byFixType			= 0;
			}
			else
			{
				m_GpsData.byFixType			= 1;
			}

			m_GpsData.UtcTime.wHour			= nTmp / 10000;
			m_GpsData.UtcTime.wMinute		= nTmp / 100 % 100;
			m_GpsData.UtcTime.wSecond		= nTmp % 100;
			m_GpsData.UtcTime.wMilliseconds	= 0;

			// 纬度
			double dbCoor;
			p = strchr(p, ',');
			dbCoor				= atof(++p);
			m_GpsData.dbLat		= GetCoor(dbCoor);
			p = strchr(p, ',');
			if(*(++p) == 'S')
			{
				m_GpsData.dbLat	*= -1;
			}

			// 经度
			p = strchr(p, ',');
			dbCoor				= atof(++p);
			m_GpsData.dbLong	= GetCoor(dbCoor);
			p = strchr(p, ',');
			if(*(++p) == 'W')
			{
				m_GpsData.dbLong *= -1;
			}

			// 速度
			p = strchr(p, ',');
			m_GpsData.dbSpeed	= atof(++p);
			m_GpsData.dbSpeed = m_GpsData.dbSpeed * Knot2Meter * 1000/3600;		//节->米/秒

			//方位角
			p = strchr(p, ',');
			if(*(++p) == ',')
			{
				m_GpsData.bIsAzimuth	= FALSE;
				m_GpsData.dbAzimuth		= 0;
			}
			else
			{
				m_GpsData.bIsAzimuth	= TRUE;
				m_GpsData.dbAzimuth		= atof(p);
				// 对-180-179.9而言
				if(m_GpsData.dbAzimuth < 0)
				{
					m_GpsData.dbAzimuth = m_GpsData.dbAzimuth + 360;
				}
			}

			//日期
			p = strchr(p,',');
			nTmp = atoi(++p);
			m_GpsData.UtcTime.wDay		= nTmp/10000;
			m_GpsData.UtcTime.wMonth	= nTmp/100%100;
			m_GpsData.UtcTime.wYear		= nTmp%100 + 2000;

			pMsg->MsgHead.enumMsgType	= emMsType;
			pMsg->MsgHead.nMsgLen		= sizeof(ST_GPS_DATA);
			memcpy(pMsg->pMsg, &m_GpsData, sizeof(ST_GPS_DATA));
		}

		bRtn = TRUE;
		break;
	case ENUM_DOP:
		{
			// 定位解算精度的几何图形(DOP)
			ST_DOP_DATA DopData;
			p = strchr(m_pchProBuf, ',');
			p = strchr(++p, ',');
			p = strchr(++p, ',');

			//active sat
			int nID;
			DopData.nNum = 0;
			for(int i = 0; i<12; i++)
			{
				nID = atoi(++p);
				if(nID > 0)
				{
					DopData.nUsedID[DopData.nNum] = nID;
					DopData.nNum++;
				}

				p = strchr(p, ',');
			}

			DopData.dbPdop	= atof(++p);
			p = strchr(p, ',');
			DopData.dbHdop	= atof(++p);
			p = strchr(p, ',');
			DopData.dbVdop	= atof(++p);

			pMsg->MsgHead.enumMsgType	= emMsType;
			pMsg->MsgHead.nMsgLen		= sizeof(ST_DOP_DATA);
			memcpy(pMsg->pMsg, &DopData, sizeof(ST_DOP_DATA));
		}

		bRtn = TRUE;
		break;
	case ENUM_SAT:
		{
			int nSatFrmNum, nCurFrmNo, nSatNum;
			p = strchr(m_pchProBuf, ',');
			nSatFrmNum			= atoi(++p);
			p = strchr(p, ',');
			nCurFrmNo			= atoi(++p);
			p = strchr(p, ',');
			nSatNum				= atoi(++p);

			if(nCurFrmNo == 1)
			{
				// 第一帧卫星数据
				m_nRevSatNum	= 0;
				m_nRevFrmNum	= 0;

				if(nSatNum > 20)
				{
					return bRtn;
				}

				m_nAllSatNum	= nSatNum;
			}
			
			if(nCurFrmNo == ++m_nRevFrmNum)
			{
				// 收到的帧序号正确
				for(int i = 0; i < 4; i++)
				{
					// 解一帧数据
					p = strchr(p, ',');
					if((p == NULL) || (*(++p) == ','))
					{
						break;
					}

					m_SatData[m_nRevSatNum].nSatID		= atoi(p);
					p = strchr(p, ',');
					m_SatData[m_nRevSatNum].nElevation	= atoi(++p);
					p = strchr(p, ',');
					m_SatData[m_nRevSatNum].nAzimuth	= atoi(++p);
					p = strchr(p, ',');
					if(*(++p) == ',')
					{
						m_SatData[m_nRevSatNum].nSNR	= -1;
					}
					else
					{
						m_SatData[m_nRevSatNum].nSNR	= atoi(p);
					}

					m_nRevSatNum++;
				}

				if((nCurFrmNo >= nSatFrmNum) || (m_nRevSatNum >= m_nAllSatNum))
				{
					// 卫星已经收齐
					pMsg->MsgHead.enumMsgType	= emMsType;
					pMsg->MsgHead.nMsgLen		= sizeof(ST_SAT_DATA) * m_nRevSatNum;
					memcpy(pMsg->pMsg, m_SatData, sizeof(ST_SAT_DATA) * m_nRevSatNum);
					bRtn = TRUE;

					return bRtn;
				}				
			}
			else
			{
				m_nRevSatNum	= 0;
				m_nRevFrmNum	= 0;
				m_nAllSatNum	= 0;
			}
		}

		break;
	case ENUM_ALT:
		{
			// 高程
			p = strchr(m_pchProBuf, ',');
			for(int nID = 0 ; nID < 5 ; nID++)
			{
				p = strchr(++p, ',');
			}

			//高程
			p = strchr(++p, ',');
			p = strchr(++p, ',');
			p = strchr(++p, ',');

			m_GpsData.dbAlt = atof(++p);

		}

		break;
	default:
		break;
	}

	return bRtn;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -