From: SnickerSun Date: Sun, 22 Dec 2024 14:00:32 +0000 (+0800) Subject: 添加nmea0183协议解析 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=5deee5f0e026d2910c4b1c7b5d42f43312a342ea;p=mirrors%2FFD230.git 添加nmea0183协议解析 --- diff --git a/code/sdk/zhihui/services/gnss/CMakeLists.txt b/code/sdk/zhihui/services/gnss/CMakeLists.txt index 35b4049a3..85161725c 100644 --- a/code/sdk/zhihui/services/gnss/CMakeLists.txt +++ b/code/sdk/zhihui/services/gnss/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES # ${CMAKE_CURRENT_SOURCE_DIR}/gnss_config_array.c ${CMAKE_CURRENT_SOURCE_DIR}/src/uart_gnss.c ${CMAKE_CURRENT_SOURCE_DIR}/src/gnss_ctl.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/NMEA0183.c ${TIOT_SRC_LIST} ) set(PUBLIC_HEADER @@ -23,7 +24,7 @@ set(PUBLIC_DEFINES CONFIG_GNSS_WAKEUP_TYPE_UART=1 CONFIG_GNSS_TCXO_FREQ_26M=1 CONFIG_GNSS_UART_BAUDRATE=115200 - CONFIG_GNSS_UART_WITH_FLOWCTRL + # CONFIG_GNSS_UART_WITH_FLOWCTRL CONFIG_FILE_BY_ARRAY=1 CONFIG_FIRMWARE_CFG_HANDLE_PRIV=1 CONFIG_FIRMWARE_FILE_READ_BUF_LEN=1029 diff --git a/code/sdk/zhihui/services/gnss/inc/NMEA0183.h b/code/sdk/zhihui/services/gnss/inc/NMEA0183.h new file mode 100644 index 000000000..17febca97 --- /dev/null +++ b/code/sdk/zhihui/services/gnss/inc/NMEA0183.h @@ -0,0 +1,234 @@ +/* +* GPS NMEA0183协议简要解析框架 +* +* 支持解析 RMC、GGA、VTG、HDT等消息字段信息,由于解析框架比较明了, +* 移植源码者可自行考虑添加新的解析代码。 +* 解析方式采用逐个字段解析的方式,能很大程度上节省消耗内存空间。 +* 重新编写数据转换函数,不依赖外部库,移植时一般只需包含NMEA0183.h +* 文件即可。 +* +* 代码示例: +* + char nmea[] = \ + "$GNRMC,102219.00,A,2239.11578,N,11406.59325,E,0.009,,291018,,,D*62\r\n"\ + "$GNVTG,,T,,M,0.009,N,0.017,K,D*37\r\n"\ + "$GNGGA,102220.00,2239.11583,N,11406.59338,E,2,09,1.30,112.7,M,-2.3,M,,0000*52\r\n"; + +$GPGGA,,,,,,0,,,,,,,,*66 + +$GPGLL,,,,,,V,N*64 + +$GPGSA,A,1,,,,,,,,,,,,,,,*1E + +$GPRMC,,V,,,,,,,,,E,N,V*6C + +$GPVTG,,T,,M,,N,,K,N*2C + +$GPZDA,,,,,00,00*48 + +$PNTH000,13,,-87,0,,,,,1,1*22 + +$PNTH001,0.000000,0.00,0.00,300000.00,1,0,0*1D + +$PNTH002,,T,0.000000,0,200,0.000000,3,0.000000*4B + + + gps_nmea gps_nmea_temp; /// 定义解析时用到的暂存状态数据,只供解析时使用 + gps_data gps_data1; /// GPS解析得到的最终数据,用户可使用 + unsigned int index = 0; + + for(index=0; index='0'&&(x)<='9')||(x)=='-'||(x)=='.' ) +#define CHAR_TO_DIGITAL(x) ((x)-'0') +#define DIGITAL_TO_CHAR(x) ( (x)+'0' ) + +/**************** 枚举量定义 ***************/ + typedef enum _sentence_types + { /* 每个枚举量表示该字段的起始位置,有些特殊字段需要10个字段域 */ + GPS_SENTENCE_RMC = 32, /* RMC字段 推荐的最少专用导航数据。*/ + GPS_SENTENCE_GGA = (32*2), /* GGA字段 接收机定位数据。*/ + GPS_SENTENCE_GSV = (32*3), /* GSV字段 可见卫星数据。*/ + GPS_SENTENCE_GSA = (32*4), /* GSA字段 有效卫星与精度因子数据。*/ + GPS_SENTENCE_GLL = (32*5), /* GLL字段 接收机地理位置数据。*/ + GPS_SENTENCE_VTG = (32*6), /* VTG字段 对地速度与航向数据。*/ + // GPS_SENTENCE_HDT = (32*7), /* HDT字段 */ + GPS_SENTENCE_ZDA = (32*7), /* ZDA字段 时间与日期数据。*/ + GPS_SENTENCE_TH000 = (32*8), /* 接收机前端增益信息。*/ + GPS_SENTENCE_TH001 = (32*9), /* 接收机定位质量信息。*/ + GPS_SENTENCE_TH002 = (32*10), /* 接收机功耗模式信息。*/ + GPS_SENTENCE_OTHER = 0 /* 默认没有字段 */ + }sentence_types; + +/**************** 结构体定义 ***************/ + /* GPS定位状态枚举量 */ + typedef enum _gps_status + { + NO_GPS = 0, /* 无GPS */ + NO_FIX, /* 接收到GPS信息,但没有定位 */ + GPS_OK_FIX_2D, /* 2D定位 */ + GPS_OK_FIX_3D, /* 3D定位 */ + GPS_OK_FIX_3D_DGPS, /* 优于3D定位 */ + GPS_OK_FIX_3D_RTK_FLOAT, /* RTK浮点解状态 */ + GPS_OK_FIX_3D_RTK_FIXED, /* RTK固定解状态 */ + }gps_status; + + +/** + * +BDS, // GB +GPS, // GP +Galileo,// GA +GLONASS,// GL +QZSS,// GQ + +signal systemID signalID +GPS L1C/A 1 1 +GLONASS L1OF 2 1 +Galileo E1C 3 7 +BDS B1i 4 1 +QZSS L1C/A 5 1 + +卫星编号 + +GNSS "NMEA svid range" "GNSS PRN range" "PRN to svid" +GPS L1C/A 1~32 1~32 PRN+0 +GLONASS L1OF 65~88 1~24 PRN+64 +Galileo E1C 1~36 1~36 PRN+0 +BDS B1i 1~50 1~50 PRN+0 +QZSS L1C/A 1~4 193~196 PRN-192 + +*/ + typedef enum _location_system + { + GNSS, //GN + GPS_L1C_A=1, //GP + GLONASS_L1OF, //GL + Galileo_E1C, //GA + BDS_Bli, //GB + QZSS_L1C_A, //GQ + MAX_LOCATION_SYSTEM + } location_system_t; + + typedef struct _start + { + unsigned char starID; + unsigned char snr; + }start_stat_t; + + /* GPS点位置 */ + typedef struct _location + { + int alt:24; /* 海拔高度 meters * 100 单位为厘米 */ + float lat; /* 纬度 * 暂时不乘以10**7,原始保存*/ + float lng; /* 精度 * 暂时不乘以10**7,原始保存*/ + }Location; + + /* 数据解析状态结构体定义 */ + typedef struct _gps_nmea + { + /* 数据解析状态 */ + unsigned char parity; /* 校验计算和 */ + unsigned char is_checksum_term; /* 当前字段域为校验字 */ + char term[15]; /* 当前字段域缓冲区,','为字段域分割符 */ + unsigned char location_system; /* 字段类别,location_system_t gps_type, 北斗,GPS,GNSS,GLONASS 等*/ + unsigned char term_number; /* 当前字段域序号 */ + unsigned char term_offset; /* 字段域数据偏移量 */ + unsigned char gps_data_good; /* GPS数据有效状态 */ + unsigned int sentence_type; /* 字段类别,见枚举 sentence_types*/ + /* 数据解析结果 */ + unsigned int new_time; /* UTC时间 */ + unsigned int new_date; /* UTC日期 */ + float new_latitude; /* 纬度 */ + float new_longitude; /* 经度 */ + int new_altitude; /* 海拔高度 cm*/ + float new_speed; /* 地速 km/h */ + float new_course; /* RMC、VTG字段磁偏角信息*/ + float new_gps_yaw; /* HDT航向信息 */ + unsigned short new_hdop; /* 水平精度 *100 */ + unsigned char new_satellite_count; /* 当前使用卫星的颗数 */ + unsigned char new_quality_indicator; /* 定位状态 */ + unsigned int last_RMC_ms; /* 最后更新字段时间 */ + unsigned int last_GGA_ms; + unsigned int last_VTG_ms; + unsigned int last_HDT_ms; + unsigned int last_GSV_ms; + unsigned int last_GSA_ms; + unsigned int last_GLL_ms; + unsigned int last_ZDA_ms; + start_stat_t starts[20]; + unsigned int gsvpagecount; + unsigned int gsvpage; + unsigned int startnum; + }gps_nmea; + + /* 时间结构体 */ + typedef struct _time + { + unsigned char year; + unsigned short int month : 4; + unsigned short int : 4; + unsigned short int day : 5; + unsigned short int week : 3; + }DateTime; + + /* GPS数据区域,供上层应用调用 */ + typedef struct _gps_data { + unsigned char instance; /* GPS实例个数 */ + gps_status status; /* GPS定位状态 */ + Location location; /* GPS定位到的当前位置 */ + DateTime date_time; + start_stat_t starts[20]; + unsigned int startnum; + float ground_speed; /* 地速 m/s */ + float ground_course; /* 地速航向 度 顺时针 0-360 */ + float gps_yaw; /* GPHDT字段航向信息 一般用于双天线测向 */ + unsigned short hdop; /* 水平精度 cm */ + unsigned short vdop; /* 垂直精度 cm */ + unsigned char num_sats; /* 可见卫星颗数 */ + unsigned char have_gps_yaw; /* GPHDT航向字段有效 */ + unsigned int last_gps_time_ms; /* 最后获取GPS信息时的时间 ms */ + }gps_data; + + /* NMEA0183结构体对象 */ + typedef struct _nmea0183 + { + gps_nmea gpsParse; + gps_data gpsData; + unsigned char (*nmea_decode)(struct _nmea0183* pnmea, char c); + }NMEA0183; + +/**************** 函数定义 ***************/ + +unsigned char nmea_decode(NMEA0183* pnmea, char c); +char* get_gps_status_str(gps_status status); +char* get_gps_sentence_type_str(sentence_types sentencetype); +void dump_location_data(gps_data *locationdata); + +#endif + + diff --git a/code/sdk/zhihui/services/gnss/sample/gnss_sample/gnss_sample.c b/code/sdk/zhihui/services/gnss/sample/gnss_sample/gnss_sample.c index 18e1d8a71..b2ee187b5 100644 --- a/code/sdk/zhihui/services/gnss/sample/gnss_sample/gnss_sample.c +++ b/code/sdk/zhihui/services/gnss/sample/gnss_sample/gnss_sample.c @@ -109,7 +109,7 @@ static int32_t QryVersion(tiot_handle handle) static const GnssSamplesCfgTable g_gnssSamplesCfg[] = { {COLDSTART_FIXMODEGPS_NMEAALL_SAMPLE, CfgColdStartFixModeGpsNmeaAll}, - {AUTOSTART_FIXMODEALL_NMEADEF_SAMPLE, CfgAutoStartFixModeAllNmeaDefault} + // {AUTOSTART_FIXMODEALL_NMEADEF_SAMPLE, CfgAutoStartFixModeAllNmeaDefault} }; static int32_t StartGnss(tiot_handle handle) @@ -139,6 +139,27 @@ static int32_t StopGnss(tiot_handle handle) return 1; } +#include "NMEA0183.h" +NMEA0183 g_nmeadata={0}; +gps_data g_global_gpsData={0}; +static int decode_nmea(char c) +{ + int ret=0; + if(nmea_decode(&g_nmeadata,c) ) ///调用解析函数 + { + // dump_nmea_str(&(g_nmeadata.gpsParse)); + if (g_nmeadata.gpsParse.sentence_type == GPS_SENTENCE_TH002) + { + //一组数据最后一条 + memcpy_s(&g_global_gpsData,sizeof(gps_data),&(g_nmeadata.gpsData),sizeof(gps_data)); + ret = 1; + memset(&g_nmeadata,0,sizeof(g_nmeadata)); + } + } + + return ret; +} + static void ListenGnssData(tiot_handle handle) { int32_t i = 0; @@ -150,8 +171,16 @@ static void ListenGnssData(tiot_handle handle) uint16_t *type = (uint16_t *)g_gnssServiceBuff; if (type[0] == MSG_TYPE_ASCII) { g_gnssServiceBuff[ret] = '\0'; - printf("%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]); - fprintf(g_gnssLogFp, "%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]); + char* pbuf=(char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]; + printf("%s\n", pbuf); + fprintf(g_gnssLogFp, "%s\n", pbuf); + for (int index=0;index < ret ;index++) + { + if (decode_nmea(pbuf[index])) + { + dump_location_data(&g_global_gpsData); + } + } } i++; } diff --git a/code/sdk/zhihui/services/gnss/src/NMEA0183.c b/code/sdk/zhihui/services/gnss/src/NMEA0183.c index 959db4482..b772c41fc 100644 --- a/code/sdk/zhihui/services/gnss/src/NMEA0183.c +++ b/code/sdk/zhihui/services/gnss/src/NMEA0183.c @@ -1,6 +1,6 @@ #include "NMEA0183.h" - +#include static short int from_hex(char a); static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata); static int sring_to_int(const char* pstr, unsigned char* b); @@ -12,7 +12,7 @@ static double string_to_float(const char* pstr, unsigned char* b); static int sring_to_int(const char* pstr, unsigned char* b); static int make_date_time(gps_data* pdata, unsigned int date, unsigned int time); -/* GPSÊý¾Ý½âÎö */ +/* GPS数据解析 */ unsigned char nmea_decode(NMEA0183* nmea, char c) { unsigned char valid_sentence = 0; @@ -21,7 +21,7 @@ unsigned char nmea_decode(NMEA0183* nmea, char c) switch (c) { - case ',': /* ×Ö¶ÎÓò·Ö¸î·ûºÅ */ + case ',': /* 字段域分割符号 */ nmea->gpsParse.parity ^= c; /* no break */ case '\r': @@ -34,10 +34,10 @@ unsigned char nmea_decode(NMEA0183* nmea, char c) } ++nmea->gpsParse.term_number; nmea->gpsParse.term_offset = 0; - nmea->gpsParse.is_checksum_term = (c == '*'); /* ºóÃæÁ½¸ö×Ö½ÚΪУÑé×Ö¶Î */ + nmea->gpsParse.is_checksum_term = (c == '*'); /* 后面两个字节为校验字段 */ return valid_sentence; - case '$': /* ×Ö¶ÎÐÅÏ¢¿ªÊ¼ */ + case '$': /* 字段信息开始 */ nmea->gpsParse.term_number = nmea->gpsParse.term_offset = 0; nmea->gpsParse.parity = 0; nmea->gpsParse.sentence_type = GPS_SENTENCE_OTHER; @@ -46,7 +46,7 @@ unsigned char nmea_decode(NMEA0183* nmea, char c) return valid_sentence; } - /* ±£´æ×Ö¶ÎÓòÊý¾Ý */ + /* 保存字段域数据 */ if (nmea->gpsParse.term_offset < sizeof(nmea->gpsParse.term) - 1) nmea->gpsParse.term[nmea->gpsParse.term_offset++] = c; if (!nmea->gpsParse.is_checksum_term) @@ -55,7 +55,7 @@ unsigned char nmea_decode(NMEA0183* nmea, char c) return valid_sentence; } -/* µ¥¸öÊ®Áù½øÖÆ×Ö·ûת»»ÎªÊ®½øÖÆ */ +/* 单个十六进制字符转换为十进制 */ static short int from_hex(char a) { if (a >= 'A' && a <= 'F') @@ -66,7 +66,7 @@ static short int from_hex(char a) return a - '0'; } -/* ´¦Àíµ¥¸ö×Ö¶ÎÓòÊý¾Ý */ +/* 处理单个字段域数据 */ static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata) { if((void*)0==pnmea || (void*)0==pdata) return 0; @@ -75,7 +75,7 @@ static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata) { unsigned char checksum = 16 * from_hex(pnmea->term[0]) + from_hex(pnmea->term[1]); - /* ¼ìÑéÐÅÏ¢¶ÎÊÇ·ñÍêÕûÎÞ´í£¬Èç¹ûУÑéͨ¹ý£¬Ôò½«½âÎöµÃµ½µÄÊý¾Ý±£´æ£¬²¢Ìṩ¸øÓû§µ÷ÓÃ*/ + /* 检验信息段是否完整无错,如果校验通过,则将解析得到的数据保存,并提供给用户调用*/ if (checksum == pnmea->parity) { if (pnmea->gps_data_good) @@ -138,11 +138,38 @@ static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata) // VTG has no fix indicator, can't change fix status break; - case GPS_SENTENCE_HDT: - pnmea->last_HDT_ms = now; -// pdata->gps_yaw = wrap_360(pnmea->new_gps_yaw*0.01f); - pdata->have_gps_yaw = 1; - break; +// case GPS_SENTENCE_HDT: +// pnmea->last_HDT_ms = now; +// // pdata->gps_yaw = wrap_360(pnmea->new_gps_yaw*0.01f); +// pdata->have_gps_yaw = 1; +// break; + case GPS_SENTENCE_GSA: + pnmea->last_GSA_ms = now; + //time = _new_time; + //date = _new_date; + // pdata->location.lat = pnmea->new_latitude; + // pdata->location.lng = pnmea->new_longitude; + // pdata->ground_speed = pnmea->new_speed; + // pdata->ground_course = pnmea->new_course; + // make_date_time(pdata, pnmea->new_date, pnmea->new_time); + // pdata->last_gps_time_ms = now; + break; + case GPS_SENTENCE_GSV: + pnmea->last_GSV_ms = now; + for (int j=0;j<20;j++) + { + pdata->starts[j].snr=pnmea->starts[j].snr; + pdata->starts[j].starID=pnmea->starts[j].starID; + } + pdata->startnum = pnmea->startnum; + printf("gsv startnum copy to pdata %d\r\n",pdata->startnum ); + break; + case GPS_SENTENCE_GLL: + pnmea->last_GLL_ms = now; + break; + case GPS_SENTENCE_ZDA: + pnmea->last_ZDA_ms = now; + break; } } else { switch (pnmea->sentence_type) { @@ -173,15 +200,52 @@ static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata) pnmea->sentence_type = GPS_SENTENCE_OTHER; return 0; } + switch(pnmea->term[1]) + { + case 'B': + pnmea->location_system = BDS_Bli; + break; + case 'L': + pnmea->location_system = GLONASS_L1OF; + break; + case 'P': + pnmea->location_system = GPS_L1C_A; + break; + case 'Q': + pnmea->location_system = QZSS_L1C_A; + break; + case 'A': + pnmea->location_system = Galileo_E1C; + break; + case 'N': + pnmea->location_system = GNSS; + break; + default: + pnmea->location_system = MAX_LOCATION_SYSTEM; + break; + } + + const char *term_type = &pnmea->term[2]; if (strcmp(term_type, "RMC") == 0) { pnmea->sentence_type = GPS_SENTENCE_RMC; } else if (strcmp(term_type, "GGA") == 0) {; pnmea->sentence_type = GPS_SENTENCE_GGA; - }else if (strcmp(term_type, "HDT") == 0) { - pnmea->sentence_type = GPS_SENTENCE_HDT; - // HDT doesn't have a data qualifier - pnmea->gps_data_good = 1; + } else if (strcmp(term_type, "GSV") == 0) {; + pnmea->sentence_type = GPS_SENTENCE_GSV; + } else if (strcmp(term_type, "GSA") == 0) {; + pnmea->sentence_type = GPS_SENTENCE_GSA; + } else if (strcmp(term_type, "GLL") == 0) {; + pnmea->sentence_type = GPS_SENTENCE_GLL; + } else if (strcmp(term_type, "ZDA") == 0) {; + pnmea->sentence_type = GPS_SENTENCE_ZDA; + } else if (strcmp(term_type, "TH000") == 0) {; + pnmea->sentence_type = GPS_SENTENCE_TH000; + } else if (strcmp(term_type, "TH001") == 0) {; + pnmea->sentence_type = GPS_SENTENCE_TH001; + } else if (strcmp(term_type, "TH002") == 0) {; + pnmea->sentence_type = GPS_SENTENCE_TH002; + }else if (strcmp(term_type, "VTG") == 0) { pnmea->sentence_type = GPS_SENTENCE_VTG; // VTG may not contain a data qualifier, presume the solution is good @@ -192,7 +256,9 @@ static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata) } return 0; } - + + + unsigned char startindex; // 32 = RMC, 64 = GGA, 96 = VTG if (pnmea->sentence_type != GPS_SENTENCE_OTHER && pnmea->term[0]) { switch (pnmea->sentence_type + pnmea->term_number) { @@ -214,7 +280,67 @@ static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata) case GPS_SENTENCE_GGA + 8: // HDOP (GGA) pnmea->new_hdop = (unsigned short)(string_to_float((const char*)pnmea->term, (void*)0)*100); break; - + case GPS_SENTENCE_GSV + 1: // GSV numMsg 2 GSV 语句总数。 + pnmea->gsvpagecount = (unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv pagecount %d\r\n",pnmea->gsvpagecount ); + pnmea->gps_data_good=1; + break; + case GPS_SENTENCE_GSV + 2: // GSV msgNo GSV 语句编号。 + pnmea->gsvpage = (unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv gsvpage %d\r\n",pnmea->gsvpage ); + break; + case GPS_SENTENCE_GSV + 3: // GSV numSV 可见卫星总数。 + pnmea->startnum = (unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv startnum %d\r\n",pnmea->startnum ); + break; + case GPS_SENTENCE_GSV + 4: // GSV svid 卫星编号 + startindex=4*(pnmea->gsvpage-1); + if (startindex>=pnmea->startnum) break; + pnmea->starts[startindex].starID=(unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv startindex %d startid %d\r\n",startindex ,pnmea->starts[startindex].starID); + break; + case GPS_SENTENCE_GSV + 7: // GSV cn0 载噪比:0~99,无效时为空 + startindex=4*(pnmea->gsvpage-1); + if (startindex>=pnmea->startnum) break; + pnmea->starts[startindex].snr=(unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv startindex %d snr %d\r\n",startindex ,pnmea->starts[startindex].snr); + break; + case GPS_SENTENCE_GSV + 8: // GSV svid 卫星编号 N*4 + startindex=4*(pnmea->gsvpage-1)+1; + if (startindex>=pnmea->startnum) break; + pnmea->starts[startindex].starID=(unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv startindex %d startid %d\r\n",startindex ,pnmea->starts[startindex].starID); + break; + case GPS_SENTENCE_GSV + 11: // GSV cn0 载噪比:0~99,无效时为空 + startindex=4*(pnmea->gsvpage-1)+1; + if (startindex>=pnmea->startnum) break; + pnmea->starts[startindex].snr=(unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv startindex %d snr %d\r\n",startindex ,pnmea->starts[startindex].snr); + break; + case GPS_SENTENCE_GSV + 12: // GSV svid 卫星编号 + startindex=4*(pnmea->gsvpage-1)+2; + if (startindex>=pnmea->startnum) break; + pnmea->starts[startindex].starID=(unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv startindex %d startid %d\r\n",startindex ,pnmea->starts[startindex].starID); + break; + case GPS_SENTENCE_GSV + 15: // GSV cn0 载噪比:0~99,无效时为空 + startindex=4*(pnmea->gsvpage-1)+2; + if (startindex>=pnmea->startnum) break; + pnmea->starts[startindex].snr=(unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv startindex %d snr %d\r\n",startindex ,pnmea->starts[startindex].snr); + break; + case GPS_SENTENCE_GSV + 16: // GSV svid 卫星编号 + startindex=4*(pnmea->gsvpage-1)+3; + if (startindex>=pnmea->startnum) break; + pnmea->starts[startindex].starID=(unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv startindex %d startid %d\r\n",startindex ,pnmea->starts[startindex].starID); + break; + case GPS_SENTENCE_GSV + 19: // GSV cn0 载噪比:0~99,无效时为空 + startindex=4*(pnmea->gsvpage-1)+3; + if (startindex>=pnmea->startnum) break; + pnmea->starts[startindex].snr=(unsigned char)sring_to_int((const char*)pnmea->term, (void*)0); + printf("gsv startindex %d snr %d\r\n",startindex ,pnmea->starts[startindex].snr); + break; // time and date // case GPS_SENTENCE_RMC + 1: // Time (RMC) @@ -262,9 +388,9 @@ static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata) pnmea->new_speed = string_to_float((const char*)pnmea->term, (void*)0); //km/h break; - case GPS_SENTENCE_HDT + 1: // Course (HDT) - pnmea->new_gps_yaw = string_to_float((const char*)pnmea->term, (void*)0); - break; + // case GPS_SENTENCE_HDT + 1: // Course (HDT) + // pnmea->new_gps_yaw = string_to_float((const char*)pnmea->term, (void*)0); + // break; case GPS_SENTENCE_RMC + 8: // Course (GPRMC) case GPS_SENTENCE_VTG + 1: // Course (VTG) pnmea->new_course = string_to_float((const char*)pnmea->term, (void*)0); @@ -275,7 +401,7 @@ static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata) return 0; } -/* ¶à´Î·½ */ +/* 多次方 */ static int int_pow(int value, unsigned int count) { int v = 1; @@ -294,7 +420,7 @@ static double double_pow(double value, unsigned int count) return v; } -/* ¼ì²é×Ö·û´®ÊÇ·ñΪÊý×Ö×Ö·û´®£¬ÊÇ·µ»Ø1£¬·ñÔò·µ»Ø0 */ +/* 检查字符串是否为数字字符串,是返回1,否则返回0 */ static unsigned char string_check_digital(const char* pc) { const char* p; @@ -309,13 +435,13 @@ static unsigned char string_check_digital(const char* pc) return 1; } -/* Êý×Ö×Ö·û´®´¦Àíº¯Êý,ʶ±ð·ûºÅ²¢ÇÒ²»¼ì²éÒç³ö -* Èç¹ûÊÇСÊý£¬ÔòÖ»·µ»ØÕûÊý²¿·Ö,Èç¹ûת»»³ö´í£¬·µ»Ø0 -* ´«Èë²ÎÊý£º ԭʼ×Ö·û´®£¬ ת»»³É¹¦±êÖ¾ 0-´íÎó 1-ÕýÈ· +/* 数字字符串处理函数,识别符号并且不检查溢出 +* 如果是小数,则只返回整数部分,如果转换出错,返回0 +* 传入参数: 原始字符串, 转换成功标志 0-错误 1-正确 */ static int sring_to_int(const char* pstr, unsigned char* b) { - char nega = 1; /* ¸ºÊýΪ1£¬ ÕýÊýΪ1 */ + char nega = 1; /* 负数为1, 正数为1 */ const char* psrc = (void*)0; int value = 0; @@ -332,7 +458,7 @@ static int sring_to_int(const char* pstr, unsigned char* b) } psrc = pstr; - if('-'==*psrc) /* ·ûºÅλ */ + if('-'==*psrc) /* 符号位 */ { nega = -1; ++psrc; @@ -350,14 +476,14 @@ static int sring_to_int(const char* pstr, unsigned char* b) return value; } -/* ×Ö·û´®×ª»»³ÉСÊý */ +/* 字符串转换成小数 */ static double string_to_float(const char* pstr, unsigned char* b) { - char nega = 1; /* ¸ºÊýΪ1£¬ ÕýÊýΪ1 */ + char nega = 1; /* 负数为1, 正数为1 */ const char* psrc = (void*)0; double value = 0.0; - double lvalue = 0.0; /* СÊýµãºóÃæÊý×Ö */ - unsigned char dotflag = 0; /* СÊýµã±ê¼Ç 1Ϊ֮ǰ³öÏÖ¹ýСÊýµã */ + double lvalue = 0.0; /* 小数点后面数字 */ + unsigned char dotflag = 0; /* 小数点标记 1为之前出现过小数点 */ unsigned char j = 0; if( (void*)0==pstr ) @@ -373,7 +499,7 @@ static double string_to_float(const char* pstr, unsigned char* b) return 0; } - if('-'==*psrc) /* ·ûºÅλ */ + if('-'==*psrc) /* 符号位 */ { nega = -1; ++psrc; @@ -406,9 +532,9 @@ static double string_to_float(const char* pstr, unsigned char* b) return value; } -/* ¸¡µãÊýת»»Îª×Ö·û´®£¬°üÀ¨ÕûÊýת»»Îª×Ö·û´® -* intgrÖ¸¶¨ÕûÊýλ¸öÊý£¬decÖ¸¶¨Ð¡Êýλ¸öÊý -* ×Ô¶¯È¥³ýÇ°ÃæµÄ0£¬Ð¡ÊýµãºóÃæµÄ0²»»áÉáÈ¥ +/* 浮点数转换为字符串,包括整数转换为字符串 +* intgr指定整数位个数,dec指定小数位个数 +* 自动去除前面的0,小数点后面的0不会舍去 */ static unsigned char float_to_string(double value, char* pdest, unsigned int intgr, unsigned int dec) { @@ -456,7 +582,7 @@ static unsigned char float_to_string(double value, char* pdest, unsigned int int if( !zeroflag ) *pstr++ = '0'; - /* Èç¹ûСÊýλÊýΪ0£¬Ôò·µ»ØÕûÊý²¿·Ö */ + /* 如果小数位数为0,则返回整数部分 */ if(0==dec) { *pstr = '\0'; @@ -479,13 +605,13 @@ static unsigned char float_to_string(double value, char* pdest, unsigned int int } -/* ÕûÊýת»»³É×Ö·û´®£¬ÄÚ²¿Æäʵµ÷ÓÃÁË float_to_string */ +/* 整数转换成字符串,内部其实调用了 float_to_string */ static unsigned char int_to_string(int value, char* pdest, unsigned int intgr) { return float_to_string((double)value, pdest, intgr,0); } -/* ʱ¼ä´¦Àí ´«Èë²ÎÊýΪÈÕÔÂÄêºÍºÁÃë*/ +/* 时间处理 传入参数为日月年和毫秒*/ static int make_date_time(gps_data* pdata, unsigned int date, unsigned int time) { @@ -531,4 +657,155 @@ static int make_date_time(gps_data* pdata, unsigned int date, unsigned int time) return 1; } +char* get_gps_status_str(gps_status status) +{ + char* ret="NO_GPS"; + switch(status) + { + case NO_GPS: + ret = "无卫星"; + break; + case NO_FIX: + ret = "接收到GPS信息,但没有定位"; + break; + case GPS_OK_FIX_2D: + ret = "2D定位"; + break; + case GPS_OK_FIX_3D: + ret = "3D定位"; + break; + case GPS_OK_FIX_3D_DGPS: + ret = "优于3D定位"; + break; + case GPS_OK_FIX_3D_RTK_FLOAT: + ret = "RTK浮点解状态"; + break; + case GPS_OK_FIX_3D_RTK_FIXED: + ret = "RTK固定解状态"; + break; + + default: + ret = "未知卫星状态"; + } + return ret; +} + +char* get_gps_sentence_type_str(sentence_types sentencetype) +{ + switch(sentencetype) + { + case GPS_SENTENCE_RMC: + return "RMC字段 推荐的最少专用导航数据。"; + case GPS_SENTENCE_GGA: + return "GGA字段 接收机定位数据。"; + case GPS_SENTENCE_GSV: + return "GSV字段 可见卫星数据。"; + case GPS_SENTENCE_GSA: + return "GSA字段 有效卫星与精度因子数据。"; + case GPS_SENTENCE_GLL: + return "GLL字段 接收机地理位置数据。"; + case GPS_SENTENCE_VTG: + return "VTG字段 对地速度与航向数据。"; + // case GPS_SENTENCE_HDT: + // return "HDT字段"; + case GPS_SENTENCE_ZDA: + return "ZDA字段 时间与日期数据"; + case GPS_SENTENCE_TH000: + return "接收机前端增益信息。"; + case GPS_SENTENCE_TH001: + return "接收机定位质量信息。"; + case GPS_SENTENCE_TH002: + return "接收机功耗模式信息。"; + case GPS_SENTENCE_OTHER: + return "其他字段"; + default: + return "unknown_type"; + } +} +char* get_gps_location_system_str(location_system_t lsystem) +{ +switch(lsystem) + { + case GNSS: + return "全球导航卫星系统"; + case GPS_L1C_A: + return "全球定位系统"; + case GLONASS_L1OF: + return "全球导航卫星系统(俄)"; + case Galileo_E1C: + return "伽利略卫星定位系统"; + case BDS_Bli: + return "北斗卫星导航系统"; + case QZSS_L1C_A: + return "准天顶卫星系统"; + default: + return "未知定位系统或自定义系统指令"; + } +} + +void dump_nmea_str(gps_nmea *nmeadata) +{ + + printf("\r\n"); + printf("%s\r\n",get_gps_location_system_str(nmeadata->location_system)); + printf("%s\r\n",get_gps_sentence_type_str(nmeadata->sentence_type)); + printf("\r\n"); +} +void dump_location_data(gps_data*locationdata) +{ + + printf("\r\n"); + printf("20%02d-%02d-%02d,\r\n定位状态(%s)\r\n", + locationdata->date_time.year, + locationdata->date_time.month, + locationdata->date_time.day, + get_gps_status_str(locationdata->status) + ); + printf("可见卫星颗数(%d),\r\n坐标(%f,%f,%d),\r\nhdop(%d),vdop(%d)\r\n", + locationdata->num_sats, + locationdata->location.lat, + locationdata->location.lng, + locationdata->location.alt, + locationdata->hdop, + locationdata->vdop + ); + if (locationdata->startnum>0) + { + printf("卫星数[%d]",locationdata->startnum); + for(int i=0;i<20;i++) + { + if (i< locationdata->startnum) + { + printf(",(%d,%d)", + locationdata->starts[i].starID, + locationdata->starts[i].snr); + + } + } + printf("\r\n"); + }else{ + printf("无卫星数据\r\n"); + } + printf("\r\n"); +} + + + +// NMEA0183 g_nmeadata={0}; + +// int decode_nmea(char c) +// { +// if(nmea_decode(&g_nmeadata,c) ) ///调用解析函数 +// { +// dump_nmea_str(&(g_nmeadata.gpsParse)); +// if (g_nmeadata.gpsParse.sentence_type == GPS_SENTENCE_TH002) +// { +// //一组数据最后一条 +// dump_location_data(&(g_nmeadata.gpsData)); +// memset(&g_nmeadata,0,sizeof(g_nmeadata)); +// } +// } + +// return 0; +// } diff --git a/code/sdk/zhihui/services/gnss/src/NMEA0183.h b/code/sdk/zhihui/services/gnss/src/NMEA0183.h deleted file mode 100644 index 9a48388b2..000000000 --- a/code/sdk/zhihui/services/gnss/src/NMEA0183.h +++ /dev/null @@ -1,154 +0,0 @@ -/* -* GPS NMEA0183ЭÒé¼òÒª½âÎö¿ò¼Ü -* -* Ö§³Ö½âÎö RMC¡¢GGA¡¢VTG¡¢HDTµÈÏûÏ¢×Ö¶ÎÐÅÏ¢£¬ÓÉÓÚ½âÎö¿ò¼Ü±È½ÏÃ÷ÁË£¬ -* ÒÆÖ²Ô´ÂëÕß¿É×ÔÐп¼ÂÇÌí¼ÓеĽâÎö´úÂë¡£ -* ½âÎö·½Ê½²ÉÓÃÖð¸ö×ֶνâÎöµÄ·½Ê½£¬Äܴܺó³Ì¶ÈÉϽÚÊ¡ÏûºÄÄÚ´æ¿Õ¼ä¡£ -* ÖØÐ±àдÊý¾Ýת»»º¯Êý£¬²»ÒÀÀµÍⲿ¿â£¬ÒÆÖ²Ê±Ò»°ãÖ»Ðè°üº¬NMEA0183.h -* Îļþ¼´¿É¡£ -* -* ´úÂëʾÀý£º -* - char nmea[] = \ - "$GNRMC,102219.00,A,2239.11578,N,11406.59325,E,0.009,,291018,,,D*62\r\n"\ - "$GNVTG,,T,,M,0.009,N,0.017,K,D*37\r\n"\ - "$GNGGA,102220.00,2239.11583,N,11406.59338,E,2,09,1.30,112.7,M,-2.3,M,,0000*52\r\n"; - - gps_nmea gps_nmea_temp; /// ¶¨Òå½âÎöʱÓõ½µÄÔÝ´æ×´Ì¬Êý¾Ý,Ö»¹©½âÎöʱʹÓà - gps_data gps_data1; /// GPS½âÎöµÃµ½µÄ×îÖÕÊý¾Ý£¬Óû§¿ÉʹÓà - unsigned int index = 0; - - for(index=0; index='0'&&(x)<='9')||(x)=='-'||(x)=='.' ) -#define CHAR_TO_DIGITAL(x) ((x)-'0') -#define DIGITAL_TO_CHAR(x) ( (x)+'0' ) - -/**************** ö¾ÙÁ¿¶¨Òå ***************/ - /* ½âÎö×Ö¶Îö¾ÙÁ¿ */ - typedef enum _sentence_types - { /* ÿ¸öö¾ÙÁ¿±íʾ¸Ã×Ö¶ÎµÄÆðʼλÖã¬ÓÐÐ©ÌØÊâ×Ö¶ÎÐèÒª10¸ö×Ö¶ÎÓò */ - GPS_SENTENCE_RMC = 32, /* RMC×Ö¶Î */ - GPS_SENTENCE_GGA = 64, /* GGA×Ö¶Î */ - GPS_SENTENCE_VTG = 96, /* VTG×Ö¶Î */ - GPS_SENTENCE_HDT = 128, /* HDT×Ö¶Î */ - GPS_SENTENCE_OTHER = 0 /* ĬÈÏûÓÐ×Ö¶Î */ - }sentence_types; - -/**************** ½á¹¹Ì嶨Òå ***************/ - /* GPS¶¨Î»×´Ì¬Ã¶¾ÙÁ¿ */ - typedef enum _gps_status - { - NO_GPS = 0, /* ÎÞGPS */ - NO_FIX, /* ½ÓÊÕµ½GPSÐÅÏ¢£¬µ«Ã»Óж¨Î» */ - GPS_OK_FIX_2D, /* 2D¶¨Î» */ - GPS_OK_FIX_3D, /* 3D¶¨Î» */ - GPS_OK_FIX_3D_DGPS, /* ÓÅÓÚ3D¶¨Î» */ - GPS_OK_FIX_3D_RTK_FLOAT, /* RTK¸¡µã½â״̬ */ - GPS_OK_FIX_3D_RTK_FIXED, /* RTK¹Ì¶¨½â״̬ */ - }gps_status; - - /* GPSµãλÖà */ - typedef struct _location - { - int alt:24; /* º£°Î¸ß¶È meters * 100 µ¥Î»ÎªÀåÃ× */ - float lat; /* γ¶È * ÔÝʱ²»³ËÒÔ10**7£¬Ô­Ê¼±£´æ*/ - float lng; /* ¾«¶È * ÔÝʱ²»³ËÒÔ10**7£¬Ô­Ê¼±£´æ*/ - }Location; - - /* Êý¾Ý½âÎö״̬½á¹¹Ì嶨Òå */ - typedef struct _gps_nmea - { - /* Êý¾Ý½âÎö״̬ */ - unsigned char parity; /* УÑ鼯ËãºÍ */ - unsigned char is_checksum_term; /* µ±Ç°×Ö¶ÎÓòΪУÑé×Ö */ - char term[15]; /* µ±Ç°×Ö¶ÎÓò»º³åÇø£¬','Ϊ×Ö¶ÎÓò·Ö¸î·û */ - unsigned char sentence_type; /* ×Ö¶ÎÀà±ð£¬¼ûö¾Ù sentence_types*/ - unsigned char term_number; /* µ±Ç°×Ö¶ÎÓòÐòºÅ */ - unsigned char term_offset; /* ×Ö¶ÎÓòÊý¾ÝÆ«ÒÆÁ¿ */ - unsigned char gps_data_good; /* GPSÊý¾ÝÓÐЧ״̬ */ - - /* Êý¾Ý½âÎö½á¹û */ - unsigned int new_time; /* UTCʱ¼ä */ - unsigned int new_date; /* UTCÈÕÆÚ */ - float new_latitude; /* γ¶È */ - float new_longitude; /* ¾­¶È */ - int new_altitude; /* º£°Î¸ß¶È cm*/ - float new_speed; /* µØËÙ km/h */ - float new_course; /* RMC¡¢VTG×Ö¶Î´ÅÆ«½ÇÐÅÏ¢*/ - float new_gps_yaw; /* HDTº½ÏòÐÅÏ¢ */ - unsigned short new_hdop; /* ˮƽ¾«¶È *100 */ - unsigned char new_satellite_count; /* µ±Ç°Ê¹ÓÃÎÀÐǵĿÅÊý */ - unsigned char new_quality_indicator; /* ¶¨Î»×´Ì¬ */ - - unsigned int last_RMC_ms; /* ×îºó¸üÐÂ×Ö¶Îʱ¼ä */ - unsigned int last_GGA_ms; - unsigned int last_VTG_ms; - unsigned int last_HDT_ms; - }gps_nmea; - - /* ʱ¼ä½á¹¹Ìå */ - typedef struct _time - { - unsigned char year; - unsigned short int month : 4; - unsigned short int : 4; - unsigned short int day : 5; - unsigned short int week : 3; - }DateTime; - - /* GPSÊý¾ÝÇøÓò£¬¹©ÉϲãÓ¦Óõ÷Óà */ - typedef struct _gps_data { - unsigned char instance; /* GPSʵÀý¸öÊý */ - gps_status status; /* GPS¶¨Î»×´Ì¬ */ - Location location; /* GPS¶¨Î»µ½µÄµ±Ç°Î»Öà */ - DateTime date_time; - float ground_speed; /* µØËÙ m/s */ - float ground_course; /* µØËÙº½Ïò ¶È ˳ʱÕë 0-360 */ - float gps_yaw; /* GPHDT×ֶκ½ÏòÐÅÏ¢ Ò»°ãÓÃÓÚË«ÌìÏß²âÏò */ - unsigned short hdop; /* ˮƽ¾«¶È cm */ - unsigned short vdop; /* ´¹Ö±¾«¶È cm */ - unsigned char num_sats; /* ¿É¼ûÎÀÐÇ¿ÅÊý */ - unsigned char have_gps_yaw; /* GPHDTº½Ïò×Ö¶ÎÓÐЧ */ - unsigned int last_gps_time_ms; /* ×îºó»ñÈ¡GPSÐÅϢʱµÄʱ¼ä ms */ - }gps_data; - - /* NMEA0183½á¹¹Ìå¶ÔÏó */ - typedef struct _nmea0183 - { - gps_nmea gpsParse; - gps_data gpsData; - unsigned char (*nmea_decode)(struct _nmea0183* pnmea, char c); - }NMEA0183; - -/**************** º¯Êý¶¨Òå ***************/ - -unsigned char nmea_decode(NMEA0183* pnmea, char c); - -#endif - - diff --git a/code/sdk/zhihui/services/gnss/src/decodenmea.c b/code/sdk/zhihui/services/gnss/src/decodenmea.c new file mode 100644 index 000000000..dbbaec492 --- /dev/null +++ b/code/sdk/zhihui/services/gnss/src/decodenmea.c @@ -0,0 +1,95 @@ +/** + * + * +$GPGGA,,,,,,0,,,,,,,,*66 + +$GPGLL,,,,,,V,N*64 + +$GPGSA,A,1,,,,,,,,,,,,,,,*1E + +$GPRMC,,V,,,,,,,,,E,N,V*6C + +$GPVTG,,T,,M,,N,,K,N*2C + +$GPZDA,,,,,00,00*48 + +$PNTH000,13,,-87,0,,,,,1,1*22 + +$PNTH001,0.000000,0.00,0.00,300000.00,1,0,0*1D + +$PNTH002,,T,0.000000,0,200,0.000000,3,0.000000*4B +*/ + + +#include "NMEA0183.h" +#include +#include + +char* nmealines[]={ + "$GPGGA,,,,,,0,,,,,,,,*66\r\n", + "$GPGLL,,,,,,V,N*64\r\n", + "$GPGSA,A,1,,,,,,,,,,,,,,,*1E\r\n", + "$GPRMC,,V,,,,,,,,,E,N,V*6C\r\n", + "$GPVTG,,T,,M,,N,,K,N*2C\r\n", + "$GPZDA,,,,,00,00*48\r\n", + "$PNTH000,13,,-87,0,,,,,1,1*22\r\n", + "$PNTH001,0.000000,0.00,0.00,300000.00,1,0,0*1D\r\n", + "$PNTH002,,T,0.000000,0,200,0.000000,3,0.000000*4B\r\n" +}; +char nmealines1[]={ + "$GBGSV,3,1,11,07,75,129,27,08,68,213,28,10,88,303,26,11,58,322,26,1*7D\r\n"\ + "$GBGSV,3,2,11,13,51,216,31,25,43,237,33,34,62,011,26,38,81,201,30,1*75\r\n"\ + "$GBGSV,3,3,11,40,64,107,30,42,17,157,29,43,38,289,27,1*47\r\n"\ + "$GNGSA,A,3,7,8,10,11,13,25,34,38,40,42,43,,1.5,0.8,1.2,4*39\r\n"\ + "$GNRMC,102219.00,A,2239.11578,N,11406.59325,E,0.009,,291018,,,D*62\r\n"\ + "$GNVTG,,T,,M,0.009,N,0.017,K,D*37\r\n"\ + "$GNGLL,3412.433366,N,10852.420048,E,094345.00,A,A*7F\r\n"\ + "$GNZDA,094343.00,24,03,2022,00,00*76\r\n"\ + "$GNGGA,094343.00,3412.431698,N,10852.419449,E,1,22,0.8,378.8,M,,M,,0000*67\r\n"\ + "$PNTH000,13,,-87,0,,,,,1,1*22\r\n"\ + "$PNTH001,0.000000,0.00,0.00,300000.00,1,0,0*1D\r\n"\ + "$PNTH002,,T,0.000000,0,200,0.000000,3,0.000000*4B\r\n" +}; + + +NMEA0183 g_nmeadata={0}; + +int decode_nmea(char c) +{ + if(nmea_decode(&g_nmeadata,c) ) ///调用解析函数 + { + dump_nmea_str(&(g_nmeadata.gpsParse)); + if (g_nmeadata.gpsParse.sentence_type == GPS_SENTENCE_TH002) + { + //一组数据最后一条 + dump_location_data(&(g_nmeadata.gpsData)); + memset(&g_nmeadata,0,sizeof(g_nmeadata)); + } + } + + + return 0; +} + +int main1(int argc, char** argv) +{ + + char tmpc=0; + FILE *fp = NULL; + fp = fopen("nmealist.txt", "r"); + while (fread(&tmpc, 1,1, (FILE*)fp)) + decode_nmea(tmpc); + fclose(fp); + +} + +int main(int argc, char** argv) +{ + + for(int i=0; i