65.9K
CodeProject 正在变化。 阅读更多。
Home

GPS 虚拟驱动程序

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.67/5 (3投票s)

2007年6月12日

GPL3

4分钟阅读

viewsIcon

78960

downloadIcon

2046

虚拟串行 (COM) 驱动程序,可将 NMEA 0183 v2.3 的 GPS 输入转换为 v2.0,以便被旧式 GPS 应用程序使用。

引言

本文介绍如何使用虚拟串行 (COM) 端口读取和转换 GPS 数据流,使其格式从一种转换为另一种,从而使旧式 GPS 应用程序能够与新型 GPS 接收器配合使用。

背景

我有一台 HPC CASSIO Cassiopeia A-10,运行 Windows CE 2.00,我专门将其用于 GPS 导航。我使用 TeleType 应用程序 (WinCE 2.00) 和 Delorme Tripmate GPS。最近,我将我的 GPS 升级到 Pharos GPS-500 SiRF III,但 TeleType 应用程序无法与之配合使用。原来,该应用程序使用的是比 GPS-500 更旧版本的 NMEA 协议。该应用程序使用 NMEA 0183 v2.0,而 GPS-500 使用 NMEA 0183 v2.3。

该应用程序实际上只使用了 NMEA 协议中的两个句子 - GGA 和 RMC。

GGA — 全球定位系统固定数据

$GPGGA,161229.487,3723.2475,N,12158.3416,W,1,07,1.0,9.0,M,,,,0000*18
名称 示例 单位 描述
消息 ID $GPGGA GGA 协议头
UTC 时间 161229.487 hhmmss.sss
纬度 3723.2475 ddmm.mmmm
N/S 指示符 N N=北或 S=南
经度 12158.3416 dddmm.mmmm
E/W 指示符 W E=东或 W=西
位置固定指示符 1 参见表 1-4
使用的卫星数 7 范围 0 至 12
HDOP 1 水平精度稀释度
MSL 高度 9
单位 M
大地水准面分离度
单位 M
差分校正年龄。 second 未使用 DGPS 时字段为空。
差分参考站 ID 0000
校验和 *18
<CR> <LF> 消息结束符

请注意,NMEA v2.0 和 v2.3 之间的 GGA 没有区别。

RMC — 推荐的最小特定 GNSS 数据

$GPRMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598,,A*10
名称 示例 单位 描述
消息 ID $GPRMC RMC 协议头
UTC 时间 161229.487 hhmmss.sss
状态 A A=数据有效或 V=数据无效
纬度 3723.2475 ddmm.mmmm
N/S 指示符 N N=北或 S=南
经度 12158.3416 dddmm.mmmm
E/W 指示符 W E=东或 W=西
对地速度 0.13
对地航向 309.62 True
日期 120598 ddmmyy
磁差 E=东或 W=西
模式 A A=自主,D=DGPS,E= DR (v2.0 中缺失)
校验和 *10
<CR> <LF> 消息结束符

最后一个字段“Mode”在 NMEA v2.0 中不存在。为了使我的应用程序正常工作,它需要将 RMC 从 v2.3 (GPS-500) 翻译为 v2.0 (应用程序)。在翻译过程中,需要移除 RMC 数据中的最后一个字段,使其看起来像这样:

$GPRMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598,*20

Using the Code

要构建虚拟串行 (COM) 端口,我使用了本文中提供的优秀示例。(非常感谢作者。)

虚拟端口充当实际端口和应用程序之间的连接。在读取 GPS 数据并将其传递给应用程序的过程中,虚拟端口将 GPS 数据格式从 NMEA 2.3 翻译为 NMEA 2.0,用于 RMC 语句。

以下代码显示了虚拟端口的“read”函数:

DWORD COM_Read( DWORD hOpenContext, LPVOID pBuffer, DWORD Count )
{
    if (hOpenContext != OPEN_CONTEXT)
        return 0;

    // read from the actual port 
    DWORD dwBytes = 0;
    ReadFile(hComm, pBuffer, Count, &dwBytes, NULL);

    // convert the data before it's returned
    Convert( pBuffer, dwBytes );

    return dwBytes;
}

Convert”函数负责查找和转换 RMC 语句。

char * atoh = "0123456789ABCDEF";

//             "   0    1    2    3    4    5    6    7    8    9 : ; 
// < = > ? @    A    B    C    D    E    F"
BYTE htoa1[] = {0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,
		0,0,0,0,0,0,0,0xA0,0xB0,0xC0,0xD0,0xE0,0xF0};
BYTE htoa2[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
		0,0,0,0,0,0,0,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};

void Convert( LPVOID pBuffer, DWORD Count )
{
    char* pCh = (char*)pBuffer;
    char ch, crc1, crc2; DWORD nCRC; BYTE state = 10;
    for (DWORD i=0;i<Count; i++)
    {
        ch = pCh[i];

        if (ch == '$') 
            state = 11; 
        else
        {
            switch ( state )
            {
            case 11: state = ch == 'G'? 12:10; break;
            case 12: state = ch == 'P'? 13:10; break;
            case 13: state = ch == 'R'? 14:10; break;
            case 14: state = ch == 'M'? 15:10; break;
            case 15: state = ch == 'C'? 16:10; break;
            case 16: state = ch == ','? 20:10; break;

            case 20:     if (ch == 'A') state = 21; break;
            case 21: state = ch == '*'? 22:20; break;
            case 22: 
                    crc1 = ch; state = 23; break;
            case 23: 
                { 
                    crc2 = ch; 

                    // get the crc
                    nCRC = htoa1[crc1 - '0'] + htoa2[crc2 - '0'];

                    // remove the chars we are deleting
                    nCRC -= 'A';
                    nCRC -= ',';

                    // ... ,,A*72\n
                    //          ^ current pos
                    //      ^ write over pos

                    pCh[i-4]='*';
                    pCh[i-3]=atoh[(nCRC & 0xF0) >> 4];
                    pCh[i-2]=atoh[ nCRC & 0x0F ];
                    pCh[i-1]=13;
                    pCh[i-0]=10;

                    state = 10;
                }
                break;
            }
        }
    }
}

该函数遍历输入缓冲区 pBuffer 并查找任何 RMC 语句。对于每个 RMC,它会检查末尾的 string A*”并将其移除。它还会计算并更新末尾的 CRC 校验和。

要安装虚拟端口驱动程序,我们需要将驱动程序 DLL 文件复制到设备上的 \windows 文件夹,并在注册表中添加以下条目:

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial6]
"ManagePort"=dword:00000002
"DeviceType"=dword:00000001
"Index"=dword:00000006
"DevConfig"=hex: 10,00,00,00,05,00,00,00,10,01,00,00,00,4b,
		00,00,00,00,08,00,00,00,00,00,00
"Tsp"="Unimodem.dll"
"Order"=dword:00000006
"Prefix"="COM"
"FriendlyName"="GPS Virtual Driver"
"Dll"="GpsVirtualDriver.dll"

"ManagePort" 是 GPS 设备连接到的端口号。在本例中,GPS 通过 PCMCIA 卡连接,并显示为设备上的 COM2。
"Index" 是虚拟串行端口 COM 号。在本例中,它是 COM6。

要将应用程序部署到设备,我们需要构建一个 cab 文件。这是一个简单的 INF 文件,用于构建 cab 文件:

; sample.inf
;
;==================================================

[Version]
Signature    = "$Windows NT$"
Provider    = "Gps"
CESignature    = "$Windows CE$"

;
; Supports only WinCE 2.00
;
[CEDevice]
VersionMin=2.00
VersionMax=2.00

[CEStrings]
AppName = "Virtual Driver"
InstallDir = %CE2%

[Strings]
reg_path = Drivers\Builtin\Serial6

;==================================================

[DefaultInstall]
CopyFiles    = Dllfiles
Addreg        = Regkeys

;==================================================

[SourceDisksNames]
1 =, "Common Files",, .

[SourceDisksFiles]
GpsVirtualDriver.dll    = 1

;==================================================
; Ouput directories for files & shortcuts

[DestinationDirs]
Dllfiles = 0, %CE2%

[Dllfiles]
GpsVirtualDriver.dll

[Regkeys]
HKLM,%reg_path%,Dll,0x00000000,GpsVirtualDriver.dll
HKLM,%reg_path%,Prefix,0x00000000,COM
HKLM,%reg_path%,FriendlyName,0x00000000,GPS Virtual Driver
HKLM,%reg_path%,Index,0x00010001,6
HKLM,%reg_path%,Order,0x00010001,2
HKLM,%reg_path%,ManagePort,0x00010001,2
HKLM,%reg_path%,DeviceType,0x00010001,1
HKLM,%reg_path%,Tsp,0x00000000,Unimodem.dll
HKLM,%reg_path%,DevConfig,0x00000001,10,00,00,00,05,00,00,00,10,
	01,00,00,00,4b,00,00,00,00,08,00,00,00,00,00,00

安装 cab 文件后,需要进行软重置才能使驱动程序开始工作。

关注点

完成这个小型项目充满了乐趣,我学会了如何为 Windows CE 2.00 构建简单的设备驱动程序。现在,我的 Cassiopeia 运行着 TeleType GPS 应用程序和新的 GPS-500 接收器。GPS-500 非常紧凑,安装在我的 PCMCIA 扩展插槽中,从那里获取电力,无需电池和/或笨重的电缆。它还使我能够继续使用我旧而可靠的 Cassiopeia A-10 进行 GPS 导航。

参考文献

历史

  • 2007 年 6 月 12 日 - 首次发布
© . All rights reserved.