864 lines
22 KiB
Go
864 lines
22 KiB
Go
|
package driver
|
|||
|
|
|||
|
import (
|
|||
|
"strconv"
|
|||
|
"strings"
|
|||
|
)
|
|||
|
|
|||
|
// NMEA_TYPE 定义NMEA语句类型
|
|||
|
type NMEA_TYPE int
|
|||
|
|
|||
|
const (
|
|||
|
NMEA_UNKONW_TYPE NMEA_TYPE = iota
|
|||
|
NMEA_RMC_TYPE
|
|||
|
NMEA_GGA_TYPE
|
|||
|
NMEA_GSV_TYPE
|
|||
|
NMEA_GSA_TYPE
|
|||
|
NMEA_VTG_TYPE
|
|||
|
NMEA_GLL_TYPE
|
|||
|
NMEA_ZDA_TYPE
|
|||
|
NMEA_GRS_TYPE
|
|||
|
NMEA_GST_TYPE
|
|||
|
)
|
|||
|
|
|||
|
// NMEA 结构体定义基本的NMEA信息
|
|||
|
type NMEA struct {
|
|||
|
/*
|
|||
|
---------------------------------------
|
|||
|
GNSS星系配置 | TalkerID
|
|||
|
---------------------------------------
|
|||
|
GPS | GP
|
|||
|
---------------------------------------
|
|||
|
GLONASS | GL
|
|||
|
---------------------------------------
|
|||
|
Galileo | GA
|
|||
|
---------------------------------------
|
|||
|
BDS | GB
|
|||
|
---------------------------------------
|
|||
|
QZSS | GQ
|
|||
|
---------------------------------------
|
|||
|
组合星系 | GN
|
|||
|
---------------------------------------
|
|||
|
*/
|
|||
|
TalkerID [3]byte
|
|||
|
Type [4]byte
|
|||
|
}
|
|||
|
|
|||
|
// NMEA_RMC 结构体定义RMC语句信息
|
|||
|
type NMEA_RMC struct {
|
|||
|
Nmea NMEA
|
|||
|
/* 含义: 定位的UTC时间。
|
|||
|
格式: hhmmss.sss
|
|||
|
hh:时(00~23)
|
|||
|
mm:分(00~59)
|
|||
|
ss:秒((00~59)
|
|||
|
sss:秒的十进制小数 */
|
|||
|
UTC [11]byte
|
|||
|
|
|||
|
Status [2]byte // A有效,V导航接收警告
|
|||
|
|
|||
|
/* 含义: 纬度。
|
|||
|
格式: ddmm.mmmmmm
|
|||
|
dd:度(00~90)
|
|||
|
mm:分(00~59)
|
|||
|
mmmmmm:分的十进制小数
|
|||
|
数据无效时,为空。*/
|
|||
|
Lat [12]byte
|
|||
|
|
|||
|
N_S [2]byte // 纬度方向。N=北 S=南。数据无效时,为空
|
|||
|
|
|||
|
/* 含义: 经度。
|
|||
|
格式: dddmm.mmmmmm
|
|||
|
ddd:度(00~180)
|
|||
|
mm:分(00~59)
|
|||
|
mmmmmm:分的十进制小数
|
|||
|
数据无效时,为空。*/
|
|||
|
Lon [13]byte
|
|||
|
|
|||
|
E_W [2]byte // 经度方向。E=东 W=西。数据无效时,为空
|
|||
|
|
|||
|
SOG [11]byte // 对地速度。可变长度。最大长度待定
|
|||
|
|
|||
|
COG [7]byte // 对地真航向。可变长度,最大值:359.99。
|
|||
|
|
|||
|
/* 含义: 日期。
|
|||
|
格式: ddmmyy
|
|||
|
dd:日
|
|||
|
mm:月
|
|||
|
yy:年,真实年份需要+2000*/
|
|||
|
Date [7]byte
|
|||
|
|
|||
|
MagVar [1]byte // MagVar 磁偏角暂不支持
|
|||
|
MagVarDir [1]byte // MagVarDir 磁偏角方向暂不支持
|
|||
|
|
|||
|
ModeInd [2]byte /* 模式:A = 自主式模式,卫星系统处于非差分定位模式。
|
|||
|
D = 差分模式,卫星系统处于差分定位模式;基于地面站或SBAS的修正。
|
|||
|
N = 无定位,卫星系统没有用于位置定位,或定位无效。 */
|
|||
|
|
|||
|
NavStatus [2]byte /* 导航状态:S = 安全
|
|||
|
C = 警告
|
|||
|
U = 不安全
|
|||
|
V = 导航状态无效,设备不提供导航状态指示 */
|
|||
|
}
|
|||
|
|
|||
|
// NMEA_GGA 结构体定义GGA语句信息
|
|||
|
type NMEA_GGA struct {
|
|||
|
Nmea NMEA
|
|||
|
/* 含义: 定位的UTC时间。
|
|||
|
格式: hhmmss.sss
|
|||
|
hh:时(00~23)
|
|||
|
mm:分(00~59)
|
|||
|
ss:秒((00~59)
|
|||
|
sss:秒的十进制小数 */
|
|||
|
UTC [11]byte
|
|||
|
|
|||
|
/* 含义: 纬度。
|
|||
|
格式: ddmm.mmmmmm
|
|||
|
dd:度(00~90)
|
|||
|
mm:分(00~59)
|
|||
|
mmmmmm:分的十进制小数
|
|||
|
数据无效时,为空。*/
|
|||
|
Lat [12]byte
|
|||
|
|
|||
|
N_S [2]byte // 纬度方向。N=北 S=南。数据无效时,为空
|
|||
|
|
|||
|
/* 含义: 经度。
|
|||
|
格式: dddmm.mmmmmm
|
|||
|
ddd:度(00~180)
|
|||
|
mm:分(00~59)
|
|||
|
mmmmmm:分的十进制小数
|
|||
|
数据无效时,为空。*/
|
|||
|
Lon [13]byte
|
|||
|
|
|||
|
E_W [2]byte // 经度方向。E=东 W=西。数据无效时,为空
|
|||
|
|
|||
|
Quality [2]byte /* GPS 定位模式/状态指示:
|
|||
|
0 = 定位不可用或无效
|
|||
|
1 = GPS SPS 模式,定位有效
|
|||
|
2 = 差分 GPS,SPS 模式,或SBAS,定位有效 */
|
|||
|
|
|||
|
NumSatUsed [3]byte // 使用的卫星数
|
|||
|
HDOP [6]byte // 水平精度因子。数据无效时,此字段为 99.99。
|
|||
|
Alt [10]byte // 平均海平面以上海拔(大地水准面)。数据无效时,此字段为空。
|
|||
|
AltM [2]byte // Alt的单位。M=米。
|
|||
|
Sep [10]byte // 大地水准面差距(WGS84 基准面与平均海平面之间的差值)。数据无效时,此字段为空。
|
|||
|
SepM [2]byte // Sep的单位。M=米。
|
|||
|
DiffAge [1]byte // 差分卫星导航系统数据龄期。暂不支持。
|
|||
|
DiffStation [1]byte // 差分基准站标识号。暂不支持。
|
|||
|
}
|
|||
|
|
|||
|
// SAT_STATUS 结构体定义卫星状态信息
|
|||
|
type SAT_STATUS struct {
|
|||
|
/*
|
|||
|
----------------------------------------------------------
|
|||
|
卫星系统 | 系统标识符 | 卫星标识号 | 信号标识号/信号通道
|
|||
|
----------------------------------------------------------
|
|||
|
GPS | 1 | 1~32:GPS, 33~64:SBAS| 1=L1 C/A
|
|||
|
----------------------------------------------------------
|
|||
|
GLONASS | 2 | 65~96 | 1=L1
|
|||
|
----------------------------------------------------------
|
|||
|
Galileo | 3 | 1~36 | 7=E1
|
|||
|
----------------------------------------------------------
|
|||
|
BDS | 4 | 1~63 | 1=B1I, 3=B1C
|
|||
|
----------------------------------------------------------
|
|||
|
QZSS | 5 | 1~10 | 1=L1 C/A
|
|||
|
----------------------------------------------------------
|
|||
|
*/
|
|||
|
SatID [3]byte // 卫星标识号。
|
|||
|
SatElev [3]byte // 仰角。范围:00~90。数据无效时,此字段为空。
|
|||
|
SatAz [4]byte // 真方位角。范围:000~359。数据无效时,此字段为空。
|
|||
|
SatCN0 [3]byte // 载噪比(C/N0)。范围:00~99。未跟踪时为空。
|
|||
|
}
|
|||
|
|
|||
|
// NMEA_GSV 结构体定义GSV语句信息
|
|||
|
type NMEA_GSV struct {
|
|||
|
Nmea NMEA
|
|||
|
TotalNumSen [2]byte // 语句总数。范围:1~9。
|
|||
|
SenNum [2]byte // 语句号。范围:1~<TotalNumSen>。
|
|||
|
TotalNumSat [3]byte // 可视的卫星总数。
|
|||
|
SatStatus [4]SAT_STATUS // 卫星信息
|
|||
|
SignalID [2]byte // 信号标识符
|
|||
|
}
|
|||
|
|
|||
|
// NMEA_GSA 结构体定义GSA语句信息
|
|||
|
type NMEA_GSA struct {
|
|||
|
Nmea NMEA
|
|||
|
Mode [2]byte // A = 自动,允许2D/3D定位模式自动变换。
|
|||
|
FixMode [2]byte // 定位模式: 1=定位不可用 2=2D定位模式 3=3D定位模式
|
|||
|
SatID [12][3]byte // 解算中用到的卫星标识号。数据无效时,此字段为空。
|
|||
|
PDOP [6]byte // 位置精度因子,最大值为99.99。数据无效时,此字段为99.99。
|
|||
|
HDOP [6]byte // 水平精度因子,最大值为99.99。数据无效时,此字段为99.99。
|
|||
|
VDOP [6]byte // 垂直精度因子,最大值为99.99。数据无效时,此字段为99.99。
|
|||
|
SystemID [2]byte // GNSS系统标识符。
|
|||
|
}
|
|||
|
|
|||
|
// NMEA_VTG 结构体定义VTG语句信息
|
|||
|
type NMEA_VTG struct {
|
|||
|
Nmea NMEA
|
|||
|
COGT [7]byte // 对地航向(真北)。数据无效时,此字段为空。
|
|||
|
COGTT [2]byte // 固定字段:真。
|
|||
|
COGM [7]byte // 对地航向(磁北)。 暂不支持。
|
|||
|
COGMM [2]byte // 固定字段:磁场。
|
|||
|
SOGN [5]byte // 对地速度,以节为单位。数据无效时,此字段为空。
|
|||
|
SOGNN [2]byte // 固定字段:节。
|
|||
|
SOGK [5]byte // 对地速度,以千米每小时为单位。数据无效时,此字段为空。
|
|||
|
SOGKK [2]byte // 固定字段:千米每小时。
|
|||
|
ModeInd [2]byte /* 模式指示:
|
|||
|
A = 自主式模式,卫星系统处于非差分定位模式
|
|||
|
D = 差分模式,卫星系统处于差分定位模式;基
|
|||
|
于地面站或SBAS的修正
|
|||
|
N = 数据无效
|
|||
|
*/
|
|||
|
}
|
|||
|
|
|||
|
// NMEA_GLL 结构体定义GLL语句信息
|
|||
|
type NMEA_GLL struct {
|
|||
|
Nmea NMEA
|
|||
|
/* 含义: 纬度。
|
|||
|
格式: ddmm.mmmmmm
|
|||
|
dd:度(00~90)
|
|||
|
mm:分(00~59)
|
|||
|
mmmmmm:分的十进制小数
|
|||
|
数据无效时,为空。*/
|
|||
|
Lat [12]byte
|
|||
|
N_S [2]byte // 纬度方向。N=北 S=南。数据无效时,为空
|
|||
|
/* 含义: 经度。
|
|||
|
格式: dddmm.mmmmmm
|
|||
|
ddd:度(00~180)
|
|||
|
mm:分(00~59)
|
|||
|
mmmmmm:分的十进制小数
|
|||
|
数据无效时,为空。*/
|
|||
|
Lon [13]byte
|
|||
|
E_W [2]byte // 经度方向。E=东 W=西。数据无效时,为空
|
|||
|
/* 含义: 定位的UTC时间。
|
|||
|
格式: hhmmss.sss
|
|||
|
hh:时(00~23)
|
|||
|
mm:分(00~59)
|
|||
|
ss:秒((00~59)
|
|||
|
sss:秒的十进制小数 */
|
|||
|
UTC [11]byte
|
|||
|
Status [2]byte // A有效,V导航接收警告
|
|||
|
ModeInd [2]byte /* 模式:A = 自主式模式,卫星系统处于非差分定位模式。
|
|||
|
D = 差分模式,卫星系统处于差分定位模式;基于地面站或SBAS的修正。
|
|||
|
N = 无定位,卫星系统没有用于位置定位,或定位无效。 */
|
|||
|
}
|
|||
|
|
|||
|
// NMEA_ZDA 结构体定义ZDA语句信息
|
|||
|
type NMEA_ZDA struct {
|
|||
|
Nmea NMEA
|
|||
|
/* 含义: 定位的UTC时间。
|
|||
|
格式: hhmmss.sss
|
|||
|
hh:时(00~23)
|
|||
|
mm:分(00~59)
|
|||
|
ss:秒((00~59)
|
|||
|
sss:秒的十进制小数 */
|
|||
|
UTC [11]byte
|
|||
|
Day [3]byte // 日。范围:01~3
|
|||
|
Month [3]byte // 月。范围:01~12。
|
|||
|
Year [5]byte // 年。
|
|||
|
LocalHour [3]byte // 本时区小时。暂不支持。
|
|||
|
LocalMin [3]byte // 本时区分钟。暂不支持。
|
|||
|
}
|
|||
|
|
|||
|
// NMEA_GRS 结构体定义GRS语句信息
|
|||
|
type NMEA_GRS struct {
|
|||
|
Nmea NMEA
|
|||
|
/* 含义: 定位的UTC时间。
|
|||
|
格式: hhmmss.sss
|
|||
|
hh:时(00~23)
|
|||
|
mm:分(00~59)
|
|||
|
ss:秒((00~59)
|
|||
|
sss:秒的十进制小数 */
|
|||
|
UTC [11]byte
|
|||
|
Mode [2]byte // 使用的计算方法。0=残差用于计算匹配GGA句子中给出的位置。1=在计算GGA位置后重新计算残差。
|
|||
|
Resi [12][6]byte // 导航中使用的可视卫星的距离残差。范围:-999到999。数据无效时,此字段为空。
|
|||
|
SystemID [2]byte // GNSS系统标识符。
|
|||
|
SignalID [2]byte // 卫星标识号。
|
|||
|
}
|
|||
|
|
|||
|
// NMEA_GST 结构体定义GST语句信息
|
|||
|
type NMEA_GST struct {
|
|||
|
Nmea NMEA
|
|||
|
/* 含义: 定位的UTC时间。
|
|||
|
格式: hhmmss.sss
|
|||
|
hh:时(00~23)
|
|||
|
mm:分(00~59)
|
|||
|
ss:秒((00~59)
|
|||
|
sss:秒的十进制小数 */
|
|||
|
UTC [11]byte
|
|||
|
RMS_D [10]byte // 导航过程中输入的标准偏差范围的RMS值。数据无效时,此字段为空。
|
|||
|
MajorD [10]byte // 误差椭圆半长轴的标准偏差。数据无效时,此字段为空。
|
|||
|
MinorD [10]byte // 误差椭圆半短轴的标准偏差。数据无效时,此字段为空。
|
|||
|
Orient [10]byte // 误差椭圆半长轴方向。数据无效时,此字段为空。
|
|||
|
LatD [10]byte // 纬度误差的标准差。数据无效时,此字段为空。
|
|||
|
LonD [10]byte // 经度误差的标准偏差。数据无效时,此字段为空。
|
|||
|
AltD [10]byte // 高度误差的标准偏差。数据无效时,此字段为空。
|
|||
|
}
|
|||
|
|
|||
|
// QlCheckXOR 计算校验和
|
|||
|
func QlCheckXOR(pData []byte, length uint) byte {
|
|||
|
var checksum byte = 0
|
|||
|
for i := uint(0); i < length; i++ {
|
|||
|
checksum ^= pData[i]
|
|||
|
}
|
|||
|
return checksum
|
|||
|
}
|
|||
|
|
|||
|
// Strnstr 在haystack中查找needle,限制搜索长度为len
|
|||
|
func Strnstr(haystack string, needle string, length int) string {
|
|||
|
if len(needle) == 0 {
|
|||
|
return haystack
|
|||
|
}
|
|||
|
|
|||
|
if len(haystack) == 0 || length <= 0 {
|
|||
|
return ""
|
|||
|
}
|
|||
|
|
|||
|
if length > len(haystack) {
|
|||
|
length = len(haystack)
|
|||
|
}
|
|||
|
|
|||
|
for i := 0; i <= length-len(needle); i++ {
|
|||
|
if haystack[i:i+len(needle)] == needle {
|
|||
|
return haystack[i:]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ""
|
|||
|
}
|
|||
|
|
|||
|
// ValidateNMEAChecksum 验证NMEA语句的校验和
|
|||
|
func ValidateNMEAChecksum(sentence string, length int) bool {
|
|||
|
if length < 4 {
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
// 查找*号位置
|
|||
|
asteriskPos := strings.LastIndex(sentence, "*")
|
|||
|
if asteriskPos == -1 || asteriskPos >= length-2 {
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
// 提取校验和
|
|||
|
checksumStr := sentence[asteriskPos+1:]
|
|||
|
if len(checksumStr) < 2 {
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
expectedChecksum, err := strconv.ParseUint(checksumStr[:2], 16, 8)
|
|||
|
if err != nil {
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
// 计算实际校验和(从$后到*前的所有字符)
|
|||
|
var actualChecksum byte = 0
|
|||
|
for i := 1; i < asteriskPos; i++ {
|
|||
|
actualChecksum ^= sentence[i]
|
|||
|
}
|
|||
|
|
|||
|
return actualChecksum == byte(expectedChecksum)
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEAType 解析NMEA语句类型
|
|||
|
func ParsNMEAType(strNMEA string, length int) NMEA_TYPE {
|
|||
|
if length < 6 {
|
|||
|
return NMEA_UNKONW_TYPE
|
|||
|
}
|
|||
|
|
|||
|
// 检查是否以$开头
|
|||
|
if strNMEA[0] != '$' {
|
|||
|
return NMEA_UNKONW_TYPE
|
|||
|
}
|
|||
|
|
|||
|
// 提取语句类型(跳过$和前两个字符的TalkerID)
|
|||
|
if length >= 6 {
|
|||
|
msgType := strNMEA[3:6]
|
|||
|
switch msgType {
|
|||
|
case "GGA":
|
|||
|
return NMEA_GGA_TYPE
|
|||
|
case "RMC":
|
|||
|
return NMEA_RMC_TYPE
|
|||
|
case "GLL":
|
|||
|
return NMEA_GLL_TYPE
|
|||
|
case "GSA":
|
|||
|
return NMEA_GSA_TYPE
|
|||
|
case "GSV":
|
|||
|
return NMEA_GSV_TYPE
|
|||
|
case "VTG":
|
|||
|
return NMEA_VTG_TYPE
|
|||
|
case "GST":
|
|||
|
return NMEA_GST_TYPE
|
|||
|
case "GRS":
|
|||
|
return NMEA_GRS_TYPE
|
|||
|
case "ZDA":
|
|||
|
return NMEA_ZDA_TYPE
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NMEA_UNKONW_TYPE
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEAGST 解析GST语句
|
|||
|
func ParsNMEAGST(strGST string, length int) *NMEA_GST {
|
|||
|
// 实现解析GST语句的逻辑
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEAGRS 解析GRS语句
|
|||
|
func ParsNMEAGRS(strGRS string, length int) *NMEA_GRS {
|
|||
|
// 实现解析GRS语句的逻辑
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEAZDA 解析ZDA语句
|
|||
|
func ParsNMEAZDA(strZDA string, length int) *NMEA_ZDA {
|
|||
|
// 实现解析ZDA语句的逻辑
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEAGLL 解析GLL语句
|
|||
|
func ParsNMEAGLL(strGLL string, length int) *NMEA_GLL {
|
|||
|
if length < 10 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 验证校验和
|
|||
|
if !ValidateNMEAChecksum(strGLL, length) {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 分割字段
|
|||
|
fields := strings.Split(strGLL, ",")
|
|||
|
if len(fields) < 7 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
gll := &NMEA_GLL{}
|
|||
|
|
|||
|
// 解析TalkerID和Type
|
|||
|
if len(fields[0]) >= 6 {
|
|||
|
copy(gll.Nmea.TalkerID[:], fields[0][1:3])
|
|||
|
copy(gll.Nmea.Type[:], fields[0][3:6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析纬度
|
|||
|
if len(fields[1]) > 0 && len(fields[1]) <= 11 {
|
|||
|
copy(gll.Lat[:], fields[1])
|
|||
|
}
|
|||
|
|
|||
|
// 解析纬度方向
|
|||
|
if len(fields[2]) > 0 {
|
|||
|
copy(gll.N_S[:], fields[2])
|
|||
|
}
|
|||
|
|
|||
|
// 解析经度
|
|||
|
if len(fields[3]) > 0 && len(fields[3]) <= 12 {
|
|||
|
copy(gll.Lon[:], fields[3])
|
|||
|
}
|
|||
|
|
|||
|
// 解析经度方向
|
|||
|
if len(fields[4]) > 0 {
|
|||
|
copy(gll.E_W[:], fields[4])
|
|||
|
}
|
|||
|
|
|||
|
// 解析UTC时间
|
|||
|
if len(fields[5]) > 0 && len(fields[5]) <= 10 {
|
|||
|
copy(gll.UTC[:], fields[5])
|
|||
|
}
|
|||
|
|
|||
|
// 解析状态
|
|||
|
if len(fields[6]) > 0 {
|
|||
|
copy(gll.Status[:], fields[6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析模式指示(如果存在)
|
|||
|
if len(fields) > 7 && len(fields[7]) > 0 {
|
|||
|
copy(gll.ModeInd[:], fields[7])
|
|||
|
}
|
|||
|
|
|||
|
return gll
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEAVTG 解析VTG语句
|
|||
|
func ParsNMEAVTG(strVTG string, length int) *NMEA_VTG {
|
|||
|
if length < 10 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 验证校验和
|
|||
|
if !ValidateNMEAChecksum(strVTG, length) {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 分割字段
|
|||
|
fields := strings.Split(strVTG, ",")
|
|||
|
if len(fields) < 9 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
vtg := &NMEA_VTG{}
|
|||
|
|
|||
|
// 解析TalkerID和Type
|
|||
|
if len(fields[0]) >= 6 {
|
|||
|
copy(vtg.Nmea.TalkerID[:], fields[0][1:3])
|
|||
|
copy(vtg.Nmea.Type[:], fields[0][3:6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析对地航向(真北)
|
|||
|
if len(fields[1]) > 0 && len(fields[1]) <= 6 {
|
|||
|
copy(vtg.COGT[:], fields[1])
|
|||
|
}
|
|||
|
|
|||
|
// 解析固定字段:真
|
|||
|
if len(fields[2]) > 0 {
|
|||
|
copy(vtg.COGTT[:], fields[2])
|
|||
|
}
|
|||
|
|
|||
|
// 解析对地航向(磁北)
|
|||
|
if len(fields[3]) > 0 && len(fields[3]) <= 6 {
|
|||
|
copy(vtg.COGM[:], fields[3])
|
|||
|
}
|
|||
|
|
|||
|
// 解析固定字段:磁场
|
|||
|
if len(fields[4]) > 0 {
|
|||
|
copy(vtg.COGMM[:], fields[4])
|
|||
|
}
|
|||
|
|
|||
|
// 解析对地速度(节)
|
|||
|
if len(fields[5]) > 0 && len(fields[5]) <= 4 {
|
|||
|
copy(vtg.SOGN[:], fields[5])
|
|||
|
}
|
|||
|
|
|||
|
// 解析固定字段:节
|
|||
|
if len(fields[6]) > 0 {
|
|||
|
copy(vtg.SOGNN[:], fields[6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析对地速度(km/h)
|
|||
|
if len(fields[7]) > 0 && len(fields[7]) <= 4 {
|
|||
|
copy(vtg.SOGK[:], fields[7])
|
|||
|
}
|
|||
|
|
|||
|
// 解析固定字段:千米每小时
|
|||
|
if len(fields[8]) > 0 {
|
|||
|
copy(vtg.SOGKK[:], fields[8])
|
|||
|
}
|
|||
|
|
|||
|
// 解析模式指示(如果存在)
|
|||
|
if len(fields) > 9 && len(fields[9]) > 0 {
|
|||
|
copy(vtg.ModeInd[:], fields[9])
|
|||
|
}
|
|||
|
|
|||
|
return vtg
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEAGSA 解析GSA语句
|
|||
|
func ParsNMEAGSA(strGSA string, length int) *NMEA_GSA {
|
|||
|
if length < 10 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 验证校验和
|
|||
|
if !ValidateNMEAChecksum(strGSA, length) {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 分割字段
|
|||
|
fields := strings.Split(strGSA, ",")
|
|||
|
if len(fields) < 18 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
gsa := &NMEA_GSA{}
|
|||
|
|
|||
|
// 解析TalkerID和Type
|
|||
|
if len(fields[0]) >= 6 {
|
|||
|
copy(gsa.Nmea.TalkerID[:], fields[0][1:3])
|
|||
|
copy(gsa.Nmea.Type[:], fields[0][3:6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析模式
|
|||
|
if len(fields[1]) > 0 {
|
|||
|
copy(gsa.Mode[:], fields[1])
|
|||
|
}
|
|||
|
|
|||
|
// 解析定位模式
|
|||
|
if len(fields[2]) > 0 {
|
|||
|
copy(gsa.FixMode[:], fields[2])
|
|||
|
}
|
|||
|
|
|||
|
// 解析卫星标识号(字段3-14)
|
|||
|
for i := 0; i < 12 && i+3 < len(fields); i++ {
|
|||
|
if len(fields[i+3]) > 0 && len(fields[i+3]) <= 2 {
|
|||
|
copy(gsa.SatID[i][:], fields[i+3])
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 解析PDOP
|
|||
|
if len(fields[15]) > 0 && len(fields[15]) <= 5 {
|
|||
|
copy(gsa.PDOP[:], fields[15])
|
|||
|
}
|
|||
|
|
|||
|
// 解析HDOP
|
|||
|
if len(fields[16]) > 0 && len(fields[16]) <= 5 {
|
|||
|
copy(gsa.HDOP[:], fields[16])
|
|||
|
}
|
|||
|
|
|||
|
// 解析VDOP
|
|||
|
if len(fields[17]) > 0 && len(fields[17]) <= 5 {
|
|||
|
copy(gsa.VDOP[:], fields[17])
|
|||
|
}
|
|||
|
|
|||
|
// 解析系统标识符(如果存在)
|
|||
|
if len(fields) > 18 && len(fields[18]) > 0 {
|
|||
|
copy(gsa.SystemID[:], fields[18])
|
|||
|
}
|
|||
|
|
|||
|
return gsa
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEAGSV 解析GSV语句
|
|||
|
func ParsNMEAGSV(strGSV string, length int) *NMEA_GSV {
|
|||
|
if length < 10 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 验证校验和
|
|||
|
if !ValidateNMEAChecksum(strGSV, length) {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 分割字段
|
|||
|
fields := strings.Split(strGSV, ",")
|
|||
|
if len(fields) < 4 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
gsv := &NMEA_GSV{}
|
|||
|
|
|||
|
// 解析TalkerID和Type
|
|||
|
if len(fields[0]) >= 6 {
|
|||
|
copy(gsv.Nmea.TalkerID[:], fields[0][1:3])
|
|||
|
copy(gsv.Nmea.Type[:], fields[0][3:6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析语句总数
|
|||
|
if len(fields[1]) > 0 {
|
|||
|
copy(gsv.TotalNumSen[:], fields[1])
|
|||
|
}
|
|||
|
|
|||
|
// 解析语句号
|
|||
|
if len(fields[2]) > 0 {
|
|||
|
copy(gsv.SenNum[:], fields[2])
|
|||
|
}
|
|||
|
|
|||
|
// 解析可视卫星总数
|
|||
|
if len(fields[3]) > 0 && len(fields[3]) <= 2 {
|
|||
|
copy(gsv.TotalNumSat[:], fields[3])
|
|||
|
}
|
|||
|
|
|||
|
// 解析卫星信息(每个卫星4个字段:ID、仰角、方位角、载噪比)
|
|||
|
satIndex := 0
|
|||
|
for i := 4; i < len(fields) && satIndex < 4; {
|
|||
|
if i+3 < len(fields) {
|
|||
|
// 卫星标识号
|
|||
|
if len(fields[i]) > 0 && len(fields[i]) <= 2 {
|
|||
|
copy(gsv.SatStatus[satIndex].SatID[:], fields[i])
|
|||
|
}
|
|||
|
// 仰角
|
|||
|
if len(fields[i+1]) > 0 && len(fields[i+1]) <= 2 {
|
|||
|
copy(gsv.SatStatus[satIndex].SatElev[:], fields[i+1])
|
|||
|
}
|
|||
|
// 方位角
|
|||
|
if len(fields[i+2]) > 0 && len(fields[i+2]) <= 3 {
|
|||
|
copy(gsv.SatStatus[satIndex].SatAz[:], fields[i+2])
|
|||
|
}
|
|||
|
// 载噪比
|
|||
|
if len(fields[i+3]) > 0 && len(fields[i+3]) <= 2 {
|
|||
|
copy(gsv.SatStatus[satIndex].SatCN0[:], fields[i+3])
|
|||
|
}
|
|||
|
satIndex++
|
|||
|
i += 4
|
|||
|
} else {
|
|||
|
break
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 解析信号标识符(如果存在)
|
|||
|
lastFieldIndex := len(fields) - 1
|
|||
|
if lastFieldIndex > 4 {
|
|||
|
// 检查最后一个字段是否包含*(校验和标记)
|
|||
|
lastField := fields[lastFieldIndex]
|
|||
|
if strings.Contains(lastField, "*") {
|
|||
|
// 提取*之前的部分作为信号标识符
|
|||
|
parts := strings.Split(lastField, "*")
|
|||
|
if len(parts[0]) > 0 && len(parts[0]) <= 1 {
|
|||
|
copy(gsv.SignalID[:], parts[0])
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return gsv
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEAGGA 解析GGA语句
|
|||
|
func ParsNMEAGGA(strGGA string, length int) *NMEA_GGA {
|
|||
|
if length < 10 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 验证校验和
|
|||
|
if !ValidateNMEAChecksum(strGGA, length) {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 分割字段
|
|||
|
fields := strings.Split(strGGA, ",")
|
|||
|
if len(fields) < 15 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
gga := &NMEA_GGA{}
|
|||
|
|
|||
|
// 解析TalkerID和Type
|
|||
|
if len(fields[0]) >= 6 {
|
|||
|
copy(gga.Nmea.TalkerID[:], fields[0][1:3])
|
|||
|
copy(gga.Nmea.Type[:], fields[0][3:6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析UTC时间
|
|||
|
if len(fields[1]) > 0 && len(fields[1]) <= 10 {
|
|||
|
copy(gga.UTC[:], fields[1])
|
|||
|
}
|
|||
|
|
|||
|
// 解析纬度
|
|||
|
if len(fields[2]) > 0 && len(fields[2]) <= 11 {
|
|||
|
copy(gga.Lat[:], fields[2])
|
|||
|
}
|
|||
|
|
|||
|
// 解析纬度方向
|
|||
|
if len(fields[3]) > 0 {
|
|||
|
copy(gga.N_S[:], fields[3])
|
|||
|
}
|
|||
|
|
|||
|
// 解析经度
|
|||
|
if len(fields[4]) > 0 && len(fields[4]) <= 12 {
|
|||
|
copy(gga.Lon[:], fields[4])
|
|||
|
}
|
|||
|
|
|||
|
// 解析经度方向
|
|||
|
if len(fields[5]) > 0 {
|
|||
|
copy(gga.E_W[:], fields[5])
|
|||
|
}
|
|||
|
|
|||
|
// 解析定位质量
|
|||
|
if len(fields[6]) > 0 {
|
|||
|
copy(gga.Quality[:], fields[6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析使用的卫星数
|
|||
|
if len(fields[7]) > 0 && len(fields[7]) <= 2 {
|
|||
|
copy(gga.NumSatUsed[:], fields[7])
|
|||
|
}
|
|||
|
|
|||
|
// 解析水平精度因子
|
|||
|
if len(fields[8]) > 0 && len(fields[8]) <= 5 {
|
|||
|
copy(gga.HDOP[:], fields[8])
|
|||
|
}
|
|||
|
|
|||
|
// 解析海拔高度
|
|||
|
if len(fields[9]) > 0 && len(fields[9]) <= 9 {
|
|||
|
copy(gga.Alt[:], fields[9])
|
|||
|
}
|
|||
|
|
|||
|
// 解析海拔高度单位
|
|||
|
if len(fields[10]) > 0 {
|
|||
|
copy(gga.AltM[:], fields[10])
|
|||
|
}
|
|||
|
|
|||
|
// 解析大地水准面差距
|
|||
|
if len(fields[11]) > 0 && len(fields[11]) <= 9 {
|
|||
|
copy(gga.Sep[:], fields[11])
|
|||
|
}
|
|||
|
|
|||
|
// 解析大地水准面差距单位
|
|||
|
if len(fields[12]) > 0 {
|
|||
|
copy(gga.SepM[:], fields[12])
|
|||
|
}
|
|||
|
|
|||
|
return gga
|
|||
|
}
|
|||
|
|
|||
|
// ParsNMEARMC 解析RMC语句
|
|||
|
func ParsNMEARMC(strRMC string, length int) *NMEA_RMC {
|
|||
|
if length < 10 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 验证校验和
|
|||
|
if !ValidateNMEAChecksum(strRMC, length) {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 分割字段
|
|||
|
fields := strings.Split(strRMC, ",")
|
|||
|
if len(fields) < 12 {
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
rmc := &NMEA_RMC{}
|
|||
|
|
|||
|
// 解析TalkerID和Type
|
|||
|
if len(fields[0]) >= 6 {
|
|||
|
copy(rmc.Nmea.TalkerID[:], fields[0][1:3])
|
|||
|
copy(rmc.Nmea.Type[:], fields[0][3:6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析UTC时间
|
|||
|
if len(fields[1]) > 0 && len(fields[1]) <= 10 {
|
|||
|
copy(rmc.UTC[:], fields[1])
|
|||
|
}
|
|||
|
|
|||
|
// 解析状态
|
|||
|
if len(fields[2]) > 0 {
|
|||
|
copy(rmc.Status[:], fields[2])
|
|||
|
}
|
|||
|
|
|||
|
// 解析纬度
|
|||
|
if len(fields[3]) > 0 && len(fields[3]) <= 11 {
|
|||
|
copy(rmc.Lat[:], fields[3])
|
|||
|
}
|
|||
|
|
|||
|
// 解析纬度方向
|
|||
|
if len(fields[4]) > 0 {
|
|||
|
copy(rmc.N_S[:], fields[4])
|
|||
|
}
|
|||
|
|
|||
|
// 解析经度
|
|||
|
if len(fields[5]) > 0 && len(fields[5]) <= 12 {
|
|||
|
copy(rmc.Lon[:], fields[5])
|
|||
|
}
|
|||
|
|
|||
|
// 解析经度方向
|
|||
|
if len(fields[6]) > 0 {
|
|||
|
copy(rmc.E_W[:], fields[6])
|
|||
|
}
|
|||
|
|
|||
|
// 解析对地速度
|
|||
|
if len(fields[7]) > 0 && len(fields[7]) <= 10 {
|
|||
|
copy(rmc.SOG[:], fields[7])
|
|||
|
}
|
|||
|
|
|||
|
// 解析对地真航向
|
|||
|
if len(fields[8]) > 0 && len(fields[8]) <= 6 {
|
|||
|
copy(rmc.COG[:], fields[8])
|
|||
|
}
|
|||
|
|
|||
|
// 解析日期
|
|||
|
if len(fields[9]) > 0 && len(fields[9]) <= 6 {
|
|||
|
copy(rmc.Date[:], fields[9])
|
|||
|
}
|
|||
|
|
|||
|
return rmc
|
|||
|
}
|