#include "ec20gnss.h" #include #include "syslib.h" /******************************************************************************** * @file ec20gnss.c * @author 晏诚科技 Mr.Wang * @version V1.0.0 * @date 9-Jan-2021 * @brief Quectel模块EC20公 GNSS全球定位系统相关驱动 ****************************************************************************** * @attention * EC20模块支持多定位系统,本驱动默认使用GPS卫星进行定位 *******************************************************************************/ /***************************************** *ec20 GNSS 驱动内部使用常变量 ****************************************/ #define GNSS_CMDPACK_LEN 128 //EC20 GNSS相关命令字符串的最大长度 NMEARMC_s sRMCData ; //NMEARMC_s结构体全局 用于存放NMEA语句中RMC语句的数据 /******************************************************** ec20模块 GNSS 相关AT指令处理 *********************************************************/ enum eGnssCmdNum { OPENNMEA =0, SELFOPENGNSS = 1, OPENGNSS =2, QUERYRMC =3 , CLOSEGNSS =4 } ; //枚举ec20模块GNSS相关指令 volatile EC20_CMD_DATA_s sGnssCmd[11]= { // cmdNum cmdStr, timeout(100ms), trueStr, trueOffset falseStr revResult rtyNum {OPENNMEA, "AT+QGPSCFG=\"nmeasrc\",1\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 }, //启用通过 AT+QGPSGNMEA 获取 NMEA 语句 {SELFOPENGNSS, "AT+QGPSCFG=\"autogps\",1\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 }, //开启GNSS自启动功能 {OPENGNSS, "AT+QGPS=1\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 }, //打开GNSS {QUERYRMC, "AT+QGPSGNMEA=\"RMC\"\r\n", 3, "+QGPSGNMEA: $GPRMC" , -1, "ERROR", TIMEOUT, 2 }, //获取 NMEA 语句中的RMC {CLOSEGNSS, "AT+QGPSEND\r\n", 3, "OK" , -1, "ERROR", TIMEOUT, 2 } //关闭GNSS } ; //EC20模块NET相关指令的EC20_CMD_DATA_s结构体类型参数 /************************************************************************************************** * 名 称: static inline const char *GnssCmdNumToString(enum eGnssCmdNum result) * 功能说明: 输出枚举成员名的字符串指针。 * 入口参数: eGnssCmdNum类型的枚举 * 出口参数: 为枚举的成员名字符串指针 **************************************************************************************************/ static inline const char *GnssCmdNumToString(enum eGnssCmdNum result) { switch (result) { ENUM_CHIP_TYPE_CASE(OPENNMEA) ENUM_CHIP_TYPE_CASE(SELFOPENGNSS) ENUM_CHIP_TYPE_CASE(OPENGNSS) ENUM_CHIP_TYPE_CASE(QUERYRMC) ENUM_CHIP_TYPE_CASE(CLOSEGNSS) } ErrorLogPrintf("EC20 无效eGnssCmdNum!") ; return "无此命令"; } /************************************************************************************************** * 名 称: RunResult EC20_SendGnssCmd( uint8_t cmdNum, char *format,... ) * 功能说明: MCU串口向EC20发送GNSS相关命令 * 入口参数: * @param1 cmdNum EC20_CMD_DATA_s中cmdNum成员命令编号 * @param2 char *format,... 可变参变量 * 出口参数: * @param1 status RunResult枚举类型变量,返回函数运行结果 **************************************************************************************************/ RunResult EC20_SendGnssCmd( uint8_t cmdNum, char *format,... ) { uint8_t revTimes = 0 ; RunResult status = TIMEOUT ; uint8_t retryTimes = sGnssCmd[cmdNum].rtyNum ; char *cmdPack = NULL ; format = sGnssCmd[cmdNum].cmdStr ; cmdPack = portMalloc(GNSS_CMDPACK_LEN*sizeof(uint8_t)) ; va_list ap; va_start (ap, format); int outLen = vsnprintf(cmdPack, GNSS_CMDPACK_LEN, (const char*)format, ap); //vsprintf (temp, cmd, ap); //到此为止,所有的参数情况已经汇总到temp了 if((outLen<=0)||( outLen > GNSS_CMDPACK_LEN)) //vsprintf (temp, cmd, ap); //到此为止,所有的参数情况已经汇总到temp了 { ErrorLogPrintf("%s,%d:cmdPack spillover!",__FILE__, __LINE__) ; //增加NET_CMDPACK_LEN数值 status = RUNERR ; goto netCmdOut ; } while(retryTimes--) { Ec20AtBufReset() ; revTimes = 0 ; //UARTx_Printf(EC20_UART, (uint8_t *)"%s", (uint8_t *)cmdPack); UARTx_SendData(EC20_UART, cmdPack, outLen) ; //DMA发送 while( revTimes++ < sGnssCmd[cmdNum].timeout ) { Wait_For_Nms(100); sGnssCmd[cmdNum].trueOffset = kmp(ec20AtBuf, sGnssCmd[cmdNum].trueStr) ; if( sGnssCmd[cmdNum].trueOffset >= 0) { status = RUNOK ; goto netCmdOut ; } else if( kmp(ec20AtBuf, sGnssCmd[cmdNum].falseStr) >= 0) { status = RUNERR ; goto netCmdOut ; } } Wait_For_Nms( 1000 ) ; } netCmdOut:portFree(cmdPack) ; va_end (ap); DebugLogPrintf("%s %s", GnssCmdNumToString((enum eGnssCmdNum)cmdNum), RunResultToString(status) ) ; return (status) ; } /************************************************************************************************** * 名 称: RunResult EC20GnssConfig(void) * 功能说明: EC20 GNSS功能配置 主要启用通过 AT+QGPSGNMEA 获取 NMEA 语句 * 出口参数: * @param1 runResult RunResult枚举类型变量,返回函数运行结果 **************************************************************************************************/ RunResult EC20GnssConfig(void) { RunResult runResult = EC20_SendGnssCmd(OPENNMEA, NULL ) ; return (runResult) ; } /************************************************************************************************** * 名 称: RunResult EC20SelfOpenGnss(void) * 功能说明: EC20 开机自启动GNSS引擎 * 出口参数: * @param1 runResult RunResult枚举类型变量,返回函数运行结果 **************************************************************************************************/ RunResult EC20SelfOpenGnss(void) { RunResult runResult = EC20_SendGnssCmd(SELFOPENGNSS, NULL ) ; return (runResult) ; } /************************************************************************************************** * 名 称: RunResult EC20OpenGnss(void) * 功能说明: EC20 开启EC20 GNSS引擎 * 出口参数: * @param1 runResult RunResult枚举类型变量,返回函数运行结果 **************************************************************************************************/ RunResult EC20OpenGnss(void) { RunResult runResult = EC20_SendGnssCmd(OPENGNSS, NULL ) ; return (runResult) ; } /************************************************************************************************** * 名 称: RunResult EC20CloseGnss(void) * 功能说明: EC20 关闭EC20 GNSS引擎 * 出口参数: * @param1 runResult RunResult枚举类型变量,返回函数运行结果 **************************************************************************************************/ RunResult EC20CloseGnss(void) { RunResult runResult = EC20_SendGnssCmd(CLOSEGNSS, NULL ) ; return (runResult) ; } /************************************************************************************************** * 名 称: RunResult EC20GnssQueryRMC(void) * 功能说明: 获取 NMEA 语句中的RMC * 出口参数: * @param1 runResult RunResult枚举类型变量,返回函数运行结果 **************************************************************************************************/ RunResult EC20GnssQueryRMC(NMEARMC_s *psNmeaRMC ) { RunResult runResult = EC20_SendGnssCmd(QUERYRMC, NULL ) ; memset(psNmeaRMC, 0, sizeof(NMEARMC_s)) ; //先清空NMEARMC_s类型变量 if( runResult == RUNOK ) { strtok(&ec20AtBuf[sGnssCmd[QUERYRMC].trueOffset], ",") ; strncpy(psNmeaRMC->utcTime, strtok(NULL, ","), sizeof(psNmeaRMC->utcTime) ) ; //填充UTC时间 strncpy((char*)&psNmeaRMC->eGnssStatus, strtok(NULL, ","), 1 ) ; //填充GNSS定位状态 if( psNmeaRMC->eGnssStatus == ALREADY ) //已经定位成功 { strncpy(psNmeaRMC->latitude, strtok(NULL, ","), sizeof(psNmeaRMC->latitude) ) ; //填充GNSS定位纬度值 strncpy((char*)&psNmeaRMC->eLatitudeDirect, strtok(NULL, ","), 1 ) ; //填充GNSS定位纬度方向 strncpy(psNmeaRMC->longitude, strtok(NULL, ","), sizeof(psNmeaRMC->longitude) ) ; //填充GNSS定位经度值 strncpy((char*)&psNmeaRMC->eLongitudeDirect, strtok(NULL, ","), 1 ) ; //填充GNSS定位经度方向 strncpy(psNmeaRMC->speed, strtok(NULL, ","), sizeof(psNmeaRMC->speed) ) ; //填充GNSS定位物体速度 单位:节 strncpy(psNmeaRMC->angDirect, strtok(NULL, ","), sizeof(psNmeaRMC->angDirect) ) ; //填充GNSS定位角方向 strncpy(psNmeaRMC->utcDate, strtok(NULL, ","), sizeof(psNmeaRMC->utcDate) ) ; //填充GNSS定位UTC日期 } else //还在定位中,表示GPS信号弱 { runResult = TIMEOUT ; } } return (runResult) ; } /************************************************************************************************** * 名 称: void RMCUtcToBJT(Calendar_u *puSetRTC, NMEARMC_s *psRMCData ) * 功能说明: 将GNSS返回的RMC语句中的日期和时间转化为 Calendar_u共用体数据格式 * 出口参数: * @param1 puSetRTC Calendar_u共用体指针 * @param2 psRMCData NMEARMC_s结构体指针 **************************************************************************************************/ void RMCUtcToBJT(Calendar_u *puSetRTC, NMEARMC_s *psRMCData ) { strncpy((char*)&puSetRTC->sCalendar.w_year[0], "20", 2 ) ; strncpy((char*)&puSetRTC->sCalendar.w_year[2], &psRMCData->utcDate[4], 2 ) ; //填充年 strncpy((char*)puSetRTC->sCalendar.w_month , &psRMCData->utcDate[2], 2 ) ; //填充月 strncpy((char*)puSetRTC->sCalendar.w_date , &psRMCData->utcDate[0], 2 ) ; //填充日 strncpy((char*)&puSetRTC->sCalendar.hour , &psRMCData->utcTime[0], 2 ) ; //填充时 int hour = atoi((const char*)puSetRTC->sCalendar.hour) +8 ; puSetRTC->sCalendar.hour[0] = hour/10 + 0x30 ; puSetRTC->sCalendar.hour[1] = hour%10 + 0x30 ; strncpy((char*)&puSetRTC->sCalendar.min , &psRMCData->utcTime[2], 2 ) ; //填充分 strncpy((char*)&puSetRTC->sCalendar.sec , &psRMCData->utcTime[4], 2 ) ; //填充秒 puSetRTC->sCalendar.colon1 = puSetRTC->sCalendar.colon2 = '.' ; puSetRTC->sCalendar.dash1 = puSetRTC->sCalendar.dash2 = '-' ; puSetRTC->sCalendar.spacing = ' ' ; }