EdgexAgent/device-gps-go/run/driver/nmea.go
2025-07-10 20:30:06 +08:00

864 lines
22 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
hh00~23
mm00~59
ss(00~59
sss秒的十进制小数 */
UTC [11]byte
Status [2]byte // A有效V导航接收警告
/* 含义: 纬度。
格式: ddmm.mmmmmm
dd00~90
mm00~59
mmmmmm分的十进制小数
数据无效时,为空。*/
Lat [12]byte
N_S [2]byte // 纬度方向。N=北 S=南。数据无效时,为空
/* 含义: 经度。
格式: dddmm.mmmmmm
ddd00~180
mm00~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
hh00~23
mm00~59
ss(00~59
sss秒的十进制小数 */
UTC [11]byte
/* 含义: 纬度。
格式: ddmm.mmmmmm
dd00~90
mm00~59
mmmmmm分的十进制小数
数据无效时,为空。*/
Lat [12]byte
N_S [2]byte // 纬度方向。N=北 S=南。数据无效时,为空
/* 含义: 经度。
格式: dddmm.mmmmmm
ddd00~180
mm00~59
mmmmmm分的十进制小数
数据无效时,为空。*/
Lon [13]byte
E_W [2]byte // 经度方向。E=东 W=西。数据无效时,为空
Quality [2]byte /* GPS 定位模式/状态指示:
0 = 定位不可用或无效
1 = GPS SPS 模式,定位有效
2 = 差分 GPSSPS 模式或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
dd00~90
mm00~59
mmmmmm分的十进制小数
数据无效时,为空。*/
Lat [12]byte
N_S [2]byte // 纬度方向。N=北 S=南。数据无效时,为空
/* 含义: 经度。
格式: dddmm.mmmmmm
ddd00~180
mm00~59
mmmmmm分的十进制小数
数据无效时,为空。*/
Lon [13]byte
E_W [2]byte // 经度方向。E=东 W=西。数据无效时,为空
/* 含义: 定位的UTC时间。
格式: hhmmss.sss
hh00~23
mm00~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
hh00~23
mm00~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
hh00~23
mm00~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
hh00~23
mm00~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
}