/*============================================================================================ Copyright(c) 2018 Quectel Wierless Solution,Co.,Ltd. All Rights Reserved. Quectel Wireless Solution Proprietary and Confidential. ============================================================================*/ #include "quec_hx_gps.h" #include "quec_rtos.h" #include "gps_debug.h" #include "gps_channel.h" #include "quec_hx_gps_update.h" #include "quec_nmea_parse.h" #include "quec_gps_rom.h" #include "gps_app.h" #include "quec_hx_apflash.h" #include "quec_cust_feature.h" #include "quec_hx_agps.h" #include "quec_gps_http.h" #define QUEC_GNSS_MSG_MAX_ITEM_NBR 50 #define QUEC_GPS_TASK_STACK_SIZE 10*1024 #define APFLASH_DATA_LEN 4*1024 #define HX_GPS_KEEPALIVE_CNT 5*1000 //5S内没有nmea语句将会重启gps模块 QUEC_GPS_DEV_T g_quec_gps_dev; QUEC_GPS_OPS g_quec_gps_ops; QUEC_NMEA_CB g_quec_nmea_cb; hx_locationg_t hx_loactiong_para;/*解析出的位置信息*/ extern int quec_gnss_type_check(void); static int gnss_rom_type; //多合一固件当前的gnss类型 hx_gnss_sys_t quec_hxgps_type = GNSS_SYS; #if 0 hx_locationg_t hx_loactiong_para_back; #endif quec_gnss_sate_num_t gnss_sate_num; #ifdef QUEC_HX_GNSS_SUPPORT #include "gps_app.h" //定义全局变量保存HTTP账号和密码,防止在头文件中被开源出去 quec_agps_cfg_t quec_hx_agps_cfg={ .profile_inx=1,\ .agps_url="http://quectel-api1.rx-networks.cn/rxn-api/locationApi/rtcm\0",\ .agpsvendorID="wLgWwv6JQt\0",\ .agpsmodelID="Quectel\0",\ .agpspassWord="aFltUERDZzZxeTY5cEp2eA==\0"\ }; #endif #define ARRAY_LENGTH(a) (sizeof a / sizeof (a[0])) extern int nmea_parse_aidinfo( quec_gnss_sate_num_t * gnss_sate_num,char *sentence); int quec_hx_gnss_sys_set(int sys_type) { #if defined (HX_GNSS_CC11_SUPPORT) if(quec_hxgps_type==BEIDOU_ONLY) { return 0; } #endif quec_gps_msg_t cmd_ptr; memset(&cmd_ptr,0,sizeof(quec_gps_msg_t)); int cfg_sys = 0; cfg_sys=sys_type; if((cfg_sys<=8)&&(cfg_sys>=0)) { char *data=malloc(4); if(NULL==data) { return -1; } memcpy(data,&cfg_sys,4); cmd_ptr.cmd_id = QUEC_GNSS_CFGSYS; cmd_ptr.data = data; quec_gnss_cmd_send(&cmd_ptr); free(data); } return 0; } /**************************************************** nmea语句 value 禁用 0 GGA 1 RMC 2 GSV 4 GSA 8 VTG 16 GLL 32 全部打开 63 *****************************************************/ int quec_hx_gnss_nmea_set(char value) { int i=0; quec_gps_msg_t cmd_ptr; memset(&cmd_ptr,0,sizeof(quec_gps_msg_t)); char *data = NULL; cmd_ptr.cmd_id = QUEC_GNSS_NMEA_TYPE; uint16 quec_gnss_nmea_type[]={0,4,3,2,5,1}; for(i=0;i<6;i++) { data=malloc(4); if(NULL==data) { return -1; } else{ memset(data,0,4); } data[0] = quec_gnss_nmea_type[i]; data[1] = (value & 0x1); value = value >>1; cmd_ptr.data = data; quec_gnss_cmd_send(&cmd_ptr); free(data); } return 0; } /******************************************************************** R3.4.0.0以下版本(国内镜像包) value: 0 H1: GPS 5 H11: GPS+BDS 7 H10: BDS R3.4.1.12 适用如下配置 北斗支持B1I value: 0 H1: GPS 1 H11: GPS+BDS 3 H1101: GPS+GLONASS+GALILEO 4 H101: GPS+ GLONASS 5 H1011: GPS+BDS+GALILEO 6 H1001: GPS+GALILEO 7 H10: BDS 和芯CC1161W支持4个星系随意组合,北斗支持B1I+B1C,QZSS和GPS绑定关系 新增2,8两个组合,后续可以根据客户需求进行扩展 0 H10001: GPS 1 H10091: GPS+BDS 2 H11191: GPS+BDS+GALILEO+GLONASS 3 H11101: GPS+GLONASS+GALILEO 4 H10101: GPS+GLONASS 5 H11091: GPS+BDS+GALILEO 6 H11001: GPS+GALILEO 7 H90: BDS 8 H10191: GPS+BDS+GLONASS *********************************************************************/ static int quec_gnss_cmd_cfgsys_process(quec_gps_msg_t *cmd_ptr) { #if defined (HX_GNSS_CC11_SUPPORT) uint16 quec_gnss_cfgsys_table_v2[]={10001,10091,11191,11101,10101,11091,11001,90,10191}; #else uint16 quec_gnss_cfgsys_table_v2[]={1,11,0,1101,101,1011,1001,10,0}; #endif int data = *(int*)(cmd_ptr->data); if((data<0)||(data>8)) { return 0; } return quec_gnss_cfgsys_table_v2[data]; } //修复CC11系列1PPS有380ms的误差,在初始化gnss时发送命令消除 void quec_gnss_cmd_1pps_config(void) { int i=0; quec_gps_msg_t cmd_ptr; memset(&cmd_ptr,0,sizeof(quec_gps_msg_t)); cmd_ptr.cmd_id = QUEC_GNSS_1PPS_CONFIG; cmd_ptr.data = NULL; quec_gnss_cmd_send(&cmd_ptr); return 0; } int quec_gps_reset(int type) { quec_gps_msg_t cmd_ptr; QUEC_GPS_DEV_T *gps_dev=quec_get_gps_dev(); if(!(gps_dev->worke_state & QUEC_NMEA_PASRE_STATE)){//必须时等到gps开始输出nmea语句时才允许发指令 return -3; } memset(&cmd_ptr,0,sizeof(quec_gps_msg_t)); if((typeQGPS_START_WARM)) { return -1; } switch(type) { case QGPS_START_COLD: cmd_ptr.cmd_id = QUEC_GNSS_COLD_RESET; cmd_ptr.data = NULL; break; case QGPS_START_WARM: cmd_ptr.cmd_id = QUEC_GNSS_WARM_RESET; cmd_ptr.data = NULL; break; case QGPS_START_HOT: cmd_ptr.cmd_id = QUEC_GNSS_HOT_RESET; cmd_ptr.data = NULL; break; default: return -2; } quec_gnss_cmd_send(&cmd_ptr); gps_dev->worke_state |= QUEC_GPS_RESET_STATE; return 0; } #if 0 void quec_gnss_aidpos_msg_send(void) { quec_gps_msg_t cmd_ptr; memset(&cmd_ptr,0,sizeof(quec_gps_msg_t)); cmd_ptr.cmd_id = QUEC_GNSS_AIDPOS_SET; cmd_ptr.data = NULL; quec_gnss_cmd_send(&cmd_ptr); } #endif void quec_gnss_aidtime_msg_send(void) { quec_gps_msg_t cmd_ptr; memset(&cmd_ptr,0,sizeof(quec_gps_msg_t)); cmd_ptr.cmd_id = QUEC_GNSS_AIDTIME_SET; cmd_ptr.data = NULL; quec_gnss_cmd_send(&cmd_ptr); } int quec_gnss_nmea_cnf(void) { QuecOSStatus err = kNoErr; quec_gps_handle *quec_param_ptr = quec_gnss_config_para_get(); if((quec_param_ptr->nmea_handle_cfg.mdflag&GNSS_SYSCONFGE_ENABLE)==0){ #if defined (HX_GNSS_CC11_SUPPORT) if(quec_hxgps_type==BEIDOU_ONLY) { quec_param_ptr->nmea_handle_cfg.gnss_sys_type = BEIDOU_SYS; } else { quec_param_ptr->nmea_handle_cfg.gnss_sys_type = GPS_BEIDOU_GALILEO_SYS; } #else quec_param_ptr->nmea_handle_cfg.gnss_sys_type = GPS_BEIDOU_GALILEO_SYS; #endif } /*设置GNSS nmea语句种类 //默认打开GGA/RMC/GSA/GSV/VTG */ if((quec_param_ptr->nmea_handle_cfg.mdflag&GNSS_NMEATYPE_ENABLE)==0){ quec_param_ptr->nmea_handle_cfg.gps_nmea_type = GGA_EN|RMC_EN|GSV_EN|GSA_EN|VTG_EN; } quec_gnss_sys_set(quec_param_ptr->nmea_handle_cfg.gnss_sys_type); quec_gnss_nmea_set(quec_param_ptr->nmea_handle_cfg.gps_nmea_type & 0x3f); return 0; } void *quec_get_gnss_sate_num(void) { return &gnss_sate_num; } int quec_gnss_nmea_ret_value_parse(char *sentence, int length) { int len = 0; int ret = 0; static int appentry = 1; QUEC_GPS_DEV_T *gps_dev=quec_get_gps_dev(); len = jmin(length,GNSS_CMD_MAX_LENGTH); if (strncmp(sentence, "$OK", 3) == 0){ GPS_LOGI("ok %d",gps_dev->worke_state); gps_dev->worke_state &= (~QUEC_GPS_RESET_STATE); GPS_LOGI("ok %d",gps_dev->worke_state); }else if(strncmp(sentence, "$FAIL", 5) == 0){ }else if(strncmp(sentence, "$AIDINFO", 8)==0){ GPS_LOGD("%s\r\n",sentence); nmea_parse_aidinfo(&gnss_sate_num,sentence); check_aidinfo_and_update_agps(); if(g_quec_gps_dev.nmea_cb->gnss_ephemeris_info_cb){ g_quec_gps_dev.nmea_cb->gnss_ephemeris_info_cb(&gnss_sate_num); } }else if(strncmp(sentence, "$CFGGEOID", 9) == 0){ ; }else if (strncmp(sentence, "$PDTINFO", 8)==0){ ; }else{/*非回复数据,走nmea解析器*/ ret = 1; } return ret ; } static struct tm *gmtime_r(const time_t *tloc, struct tm *result) { struct tm *tm; /* Bug Fix. * Return Value of gmtime() is NULL On CranePlatform. * SO local_time() is replaced here.By JoshuaWang.@0205/2021. */ tm = localtime(tloc); if(tm) return memcpy(result, tm, sizeof(struct tm)); return NULL; } int quec_gnss_aidtime_process(char *msgbuf) { int send_len =0; struct tm time; unsigned int now= GPS_GET_RTC_TIME(); gmtime_r(&now, &time); send_len = snprintf((char *)(msgbuf), sizeof("$AIDTIME"),"$AIDTIME"); send_len += snprintf((char *)(msgbuf+send_len), GNSS_CMD_MAX_LENGTH - send_len,",%d,%d,%d,%d,%d,%d,%d", time.tm_year+1900,time.tm_mon+1, time.tm_mday,time.tm_hour,time.tm_min, time.tm_sec,rand()%1000); send_len+=snprintf(msgbuf+send_len, GNSS_CMD_MAX_LENGTH - send_len, "\r\n"); GPS_LOGD("%s",msgbuf); return send_len; } #if 0 int quec_gnss_aidpos_process(char *msgbuf,hx_locationg_t *nema_data) { char rsp_str[256]= {0}; int len = 0; int send_len = 0; memset(rsp_str, 0, 256); len += (uint16)snprintf((char *)(rsp_str+len), sizeof("$AIDPOS"),"$AIDPOS"); len += (uint16)snprintf((char *)(rsp_str+len), sizeof(rsp_str)-len,",%09.6lf",nema_data->latitude); len += (uint16)snprintf((char *)(rsp_str+len), sizeof(rsp_str)-len,",%c",nema_data->latitude_cardinal); len += (uint16)snprintf((char *)(rsp_str+len), sizeof(rsp_str)-len,",%010.6lf",nema_data->longitude); len += (uint16)snprintf((char *)(rsp_str+len), sizeof(rsp_str)-len,",%c",nema_data->longitude_cardinal); len += (uint16)snprintf((char *)(rsp_str+len), sizeof(rsp_str)-len,",%.1f",nema_data->altitude); send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "%s",rsp_str); send_len+=snprintf(msgbuf+send_len, GNSS_CMD_MAX_LENGTH - send_len, "\r\n"); return send_len; } #endif uint8_t one_system_cnr_index = 0; uint8_t total_cnr_index = 0; static int quec_gnss_nmea_value_update(struct nmea_s *nmea, hx_locationg_t *gps_data) { struct nmea_gprmc_s *rmc = NULL; struct nmea_gpgsv_s *gsv = NULL; struct nmea_gpgga_s *gga = NULL; struct nmea_gpgsa_s *gsa = NULL; struct nmea_gpvtg_s *vtg = NULL; unsigned int *temp_cnr = NULL; uint8_t i = 0; if(nmea == NULL || gps_data == NULL) { GPS_LOGE("param invalid. \r\n"); return -1; } if(nmea->type == NMEA_UNKNOWN) { GPS_LOGE("gps nmea type is unknown! \r\n"); return -1; } switch(nmea->type) { case NMEA_RMC: rmc = (struct nmea_gprmc_s*)nmea->data; if(rmc) { gps_data->valid = rmc->valid; //经纬?? gps_data->longitude = (rmc->longitude.degrees)*100 + rmc->longitude.minutes; gps_data->longitude_cardinal = rmc->longitude.cardinal; gps_data->latitude = (rmc->latitude.degrees)*100 + rmc->latitude.minutes; gps_data->latitude_cardinal = rmc->latitude.cardinal; //地面航向 gps_data->heading = rmc->course; //地面速率 gps_data->gps_speed = rmc->speed; //UTC gps_data->time.tm_year = rmc->time.tm_year; gps_data->time.tm_mon = rmc->time.tm_mon; gps_data->time.tm_mday = rmc->time.tm_mday; gps_data->time.tm_hour = rmc->time.tm_hour; gps_data->time.tm_min = rmc->time.tm_min; gps_data->time.tm_sec = rmc->time.tm_sec; } if(gps_data->gsv_status == SV_UPDATING) { gps_data->cnrs_index = total_cnr_index; gps_data->gsv_status = SV_UPDATED; } break; case NMEA_GGA: gga = (struct nmea_gpgga_s*)nmea->data; if(gga) { gps_data->altitude = gga->altitude; gps_data->satellites_num = gga->satellites_tracked; } break; case NMEA_GSA: gsa = (struct nmea_gpgsa_s*)nmea->data; if(gsa != NULL) { gps_data->hdop = gsa->hdop; gps_data->pdop = gsa->pdop; gps_data->fix_mode = gsa->navmode; } break; case NMEA_VTG: vtg = (struct nmea_gpvtg_s*)nmea->data; if(vtg != NULL) { //地面航向 gps_data->cogt = vtg->cogt; //地面速率 gps_data->sog = vtg->sog; gps_data->kph = vtg->kph; } break; case NMEA_GSV: if(gps_data->gsv_status == SV_NEED_UPDATE) { memset(gps_data->cnrs, 0, sizeof(gps_data->cnrs)); one_system_cnr_index = 0; total_cnr_index = 0; gps_data->gsv_status = SV_UPDATING; } gsv = (struct nmea_gpgsv_s *)nmea->data; if (gsv != NULL) { //每次解析一条GSV,每条最多4个卫星,等到一组NMEA读取完 temp_cnr = &(gps_data->cnrs[total_cnr_index]); for (i = 0; one_system_cnr_index < gsv->total_sats && i < 4 && total_cnr_index + one_system_cnr_index < HX_GSV_MAX_SATS && gsv->sats[i].snr; i++) { temp_cnr[one_system_cnr_index] = gsv->sats[i].snr; GPS_LOGD("sat[%d]:%d total_cnr_index:%d one_system_cnr_index:%d --max%d", i, gsv->sats[i].snr, total_cnr_index, one_system_cnr_index, HX_GSV_MAX_SATS); one_system_cnr_index++; } if (one_system_cnr_index >= gsv->total_sats) { total_cnr_index += one_system_cnr_index; one_system_cnr_index = 0; } } break; default: break; } return 0; } int quec_gnss_nmea_parse(char* buf,int buf_len) { char nmea_buff[256]; char nmea_buff1[256]; unsigned int port_channel; struct nmea_s *nmea = NULL; int len = 0; int ret = 0; int i = 0; QUEC_NMEA_CB *nmea_callback = g_quec_gps_dev.nmea_cb; if(NULL == buf) return -1; len = jmin(sizeof(nmea_buff)-1, buf_len); memset(nmea_buff, 0, sizeof(nmea_buff)); memcpy(nmea_buff, buf, len); memcpy(nmea_buff1,nmea_buff,len); GPS_LOGI("%s ,%d\r\n",nmea_buff,len); if (NULL == memchr(nmea_buff, '$', len)){ return -1; } ret = quec_gnss_nmea_ret_value_parse(nmea_buff,len); if(ret == 0){ return 0; } nmea = nmea_parse(nmea_buff, len, 1); if (nmea){ ret = quec_gnss_nmea_value_update(nmea, &hx_loactiong_para); if(nmea_callback->loaction_update_cb){ nmea_callback->loaction_update_cb(&hx_loactiong_para); /*定位数据通过回调更新到上层*/ } if(nmea_callback->nmea_str_cb){ nmea_callback->nmea_str_cb(&hx_loactiong_para.time, nmea_buff1,len); /*实时nmea数据通过回调输出到上层*/ } //20230616 屏蔽和芯gnss aidpos注入功能,实际测试无效,且概率性会引起串口冲突,产生assert dump #if 0 if(hx_loactiong_para.valid){ /*非重启快速启动*/ memset(&(hx_loactiong_para_back),0,sizeof(struct quec_gnss_data_struct)); /*缓存重启前的定位数据,在重启后需要使用指令注入*/ memcpy((void*)(&(hx_loactiong_para_back)),(void*)(&hx_loactiong_para),sizeof(struct quec_gnss_data_struct)); }else { if(hx_loactiong_para_back.valid){ quec_gnss_aidpos_msg_send(); hx_loactiong_para_back.valid = 0; } } #endif if (ret){ GPS_LOGE("nmea_value_update error. \r\n"); GPS_LOGE(" %s", nmea_buff); } if (nmea->data) { free(nmea->data); nmea->data = NULL; } free(nmea); nmea = NULL; } return 0; } hx_locationg_t * hx_location_data_get(void) { return &hx_loactiong_para; } int quec_gnss_cmd_send(quec_gps_msg_t *rcv) { unsigned int send_len = 0; if(rcv == NULL) return -1; char *msgbuf=malloc(GNSS_CMD_MAX_LENGTH); if(msgbuf == NULL) ASSERT(0); memset(msgbuf,0,GNSS_CMD_MAX_LENGTH); switch(rcv->cmd_id) { case QUEC_GNSS_PDTINFO_CMD: send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$PDTINFO\r\n"); break; case QUEC_GNSS_HOT_RESET: /*热启动*/ send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$RESET,0,h00\r\n"); break; case QUEC_GNSS_WARM_RESET:/*温启动*/ send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$RESET,0,h01\r\n"); break; case QUEC_GNSS_COLD_RESET:/*冷启动*/ #if defined (HX_GNSS_CC11_SUPPORT) send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$RESET,0,hFF\r\n"); #else send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$RESET,0,h85\r\n"); #endif break; case QUEC_GNSS_AGPS_AIDINFO_REQ: send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$AIDINFO\r\n"); break; case QUEC_GNSS_CFG_GEOID_REQ: send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$CFGGEOID\r\n"); break; case QUEC_GNSS_CFG_GEOID_SET: send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$CFGGEOID,1\r\n"); break; case QUEC_GNSS_CFGSYS: if(quec_gnss_cmd_cfgsys_process(rcv)) { send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$CFGSYS,H%d",quec_gnss_cmd_cfgsys_process(rcv)); send_len+=snprintf(msgbuf+send_len, GNSS_CMD_MAX_LENGTH - 1, "\r\n"); } break; case QUEC_GNSS_NMEA_TYPE: #if defined (HX_GNSS_CC11_SUPPORT) send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$CFGMSG,0,%d,%d,1",rcv->data[0],rcv->data[1]); #else send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$CFGMSG,0,%d,%d",rcv->data[0],rcv->data[1]); #endif send_len+=snprintf(msgbuf+send_len, GNSS_CMD_MAX_LENGTH - 1, "\r\n"); break; #if defined (HX_GNSS_CC11_SUPPORT) case QUEC_GNSS_1PPS_CONFIG: send_len=snprintf(msgbuf, GNSS_CMD_MAX_LENGTH - 1, "$CFGTP,1000000,500000,1,0,800,-380"); break; #endif #if 0 case QUEC_GNSS_AIDPOS_SET: send_len = quec_gnss_aidpos_process(msgbuf,&(hx_loactiong_para_back)); break; #endif case QUEC_GNSS_AIDTIME_SET: send_len = quec_gnss_aidtime_process(msgbuf); break; default: free(msgbuf); return -2; } if(send_len) { GPS_COM_PutByte_Buffer(msgbuf,send_len); } free(msgbuf); return 0; } int quec_gps_open(void) { QUEC_GPS_DEV_T * quec_gps = &g_quec_gps_dev; int ret = QUEC_GPS_NO_ERROR; do{ if(quec_gps->power_state == QUEC_POWER_OFF){ quec_rtos_flag_release(g_quec_gps_dev.gps_event_flag_ref, QUEC_GPS_OPEN_EVENT, QUEC_FLAG_OR); ret = QUEC_GPS_NO_ERROR; break; } ret = QUEC_GPS_ALREADY_CLOSED_ERROR; GPS_LOGE("GPS_ALREADY Be CLOSED!!!\n"); }while(0); return ret; } int quec_gps_close(void) { QUEC_GPS_DEV_T * quec_gps = &g_quec_gps_dev; int ret = QUEC_GPS_NO_ERROR; do{ if(quec_gps->power_state == QUEC_POWER_ON){ quec_rtos_flag_release(g_quec_gps_dev.gps_event_flag_ref, QUEC_GPS_CLOSE_EVENT, QUEC_FLAG_OR); ret = QUEC_GPS_NO_ERROR; break; } ret = QUEC_GPS_NOT_OPEN_ERROR; GPS_LOGE("need to OPEN GPS!!!\n"); }while(0); return ret; } void quec_gps_register_nmea_str_cb(nmea_str_put cb) { g_quec_nmea_cb.nmea_str_cb = cb; } void quec_gps_register_nmea_packet_cb(gps_packet_put cb) { g_quec_nmea_cb.nmea_packets_cb = cb; } void quec_gps_register_open_success_cb(gps_open_success cb) { g_quec_nmea_cb.open_gps_success_cb = cb; } void quec_gps_register_location_para_cb(location_update cb) { g_quec_nmea_cb.loaction_update_cb = cb; } void quec_gps_register_agps_sate_cb(gnss_ephemeris_info cb) { g_quec_nmea_cb.gnss_ephemeris_info_cb = cb; } void quec_apflash_req_flag_set(void) { quec_rtos_flag_release(g_quec_gps_dev.gps_event_flag_ref,QUEC_APFLSH_REQ_EVENT,QUEC_FLAG_OR); } void quec_apflsh_req_statue_clear(void) { g_quec_gps_dev.worke_state &= ~QUEC_APFLASH_REQED; } #ifdef QUEC_HX_AGPS_TIMER void quec_agps_req_flag_set(void) { quec_rtos_flag_release(g_quec_gps_dev.gps_event_flag_ref,QUEC_AGPS_DATA_REQ_EVENT,QUEC_FLAG_OR); } #endif void quec_gps_load_fw_cb(void * para) { if(g_quec_gps_dev.power_state != QUEC_POWER_ON)/*若未开机则走下载流程*/ { quec_rtos_flag_release(g_quec_gps_dev.gps_event_flag_ref,QUEC_GPS_DOWNLOAD_FIRM,QUEC_FLAG_OR); } } /*gps 保活机制如果超过5s没检测到串口回调则会重新开关串口和gps */ void quec_keep_alive_timer(UINT32 argv) { quec_rtos_flag_release(g_quec_gps_dev.gps_event_flag_ref,QUEC_GPS_RESTART,QUEC_FLAG_OR); } void quec_gps_nmea_data_cb(void * para) { quec_gps_handle * gnss_config = quec_gnss_config_para_get(); if((1 == gnss_rom_type) ||(3 == gnss_rom_type)) { quec_gnss_apflash_struct_t * gnss_apflash = get_hx_apflash_req_status(); if(gnss_apflash->request_flag)/*如果此时发起了apflsh请求*/ { quec_rtos_flag_release(g_quec_gps_dev.gps_event_flag_ref,QUEC_GPS_APFLASH_EVENT,QUEC_FLAG_OR); } else { if(g_quec_gps_dev.worke_state & QUEC_NMEA_PASRE_STATE){ quec_rtos_flag_release(g_quec_gps_dev.gps_event_flag_ref, QUEC_GPS_NMEA_PARSE_EVENT, QUEC_FLAG_OR); } } } else { if(g_quec_gps_dev.worke_state & QUEC_NMEA_PASRE_STATE){ quec_rtos_flag_release(g_quec_gps_dev.gps_event_flag_ref, QUEC_GPS_NMEA_PARSE_EVENT, QUEC_FLAG_OR); } } //20230512 修改保活机制处理逻辑,当我们配置nmea语句不输出时,不触发保活机制,以防止gnss反复重启 if((g_quec_gps_dev.worke_state & QUEC_NMEA_PASRE_STATE) && (gnss_config->nmea_handle_cfg.gps_nmea_type != 0)){ quec_rtos_timer_start(g_quec_gps_dev.gps_keep_alive_timer, HX_GPS_KEEPALIVE_CNT, 0, quec_keep_alive_timer, 0); } else { quec_rtos_timer_stop(g_quec_gps_dev.gps_keep_alive_timer); } } int quec_gps_start_parse(void) { QUEC_GPS_DEV_T * quec_gps = &g_quec_gps_dev; QUEC_GPS_OPS * quec_ops = (QUEC_GPS_OPS *)g_quec_gps_dev.ops; int ret = QUEC_GPS_ERROR; if(!(quec_gps->worke_state & QUEC_NMEA_PASRE_STATE )){ GPS_COM_register_cb(quec_gps_nmea_data_cb); quec_rtos_timer_start(g_quec_gps_dev.gps_keep_alive_timer, HX_GPS_KEEPALIVE_CNT, 0, quec_keep_alive_timer, 0); quec_gps->worke_state |= QUEC_NMEA_PASRE_STATE; ret = QUEC_GPS_NO_ERROR; GPS_LOGI("start nmea parse %d",quec_gps->worke_state); } return ret ; } int quec_gps_stop_nmea_parse(void) { QUEC_GPS_DEV_T * quec_gps = &g_quec_gps_dev; int ret = QUEC_GPS_ERROR; if(quec_gps->worke_state & QUEC_NMEA_PASRE_STATE){ GPS_COM_register_cb(NULL); quec_rtos_timer_stop(g_quec_gps_dev.gps_keep_alive_timer); ret = QUEC_GPS_NO_ERROR; quec_gps->worke_state &= ~QUEC_NMEA_PASRE_STATE; } return ret ; } int gps_open(void) { int ret = QUEC_GPS_NO_ERROR; int i ; g_quec_gps_dev.power_state = QUEC_POWER_OFF; GPS_COM_register_cb(quec_gps_load_fw_cb); for(i=0;i<=3;i++){ ret = hx_gnss_open(); if(ret == HX_L26_INIT_NO_ERROR){ break; } else{ GPS_LOGE("GPS UPDATE FAILED: %d",ret); hx_gnss_close(); ret = QUEC_GPS_NOT_OPEN_ERROR; } } GPS_COM_register_cb(NULL); g_quec_gps_dev.power_state = QUEC_POWER_ON; return ret; } int gps_close(void) { int ret = QUEC_GPS_NO_ERROR; ret = hx_gnss_close(); g_quec_gps_dev.power_state = QUEC_POWER_OFF; return ret; } extern QUEC_GPS_USER_CALLBACK quec_asr_gps_user_callback_init; static void quec_gps_process_thread(void* argv) { unsigned int gps_flags = 0; char nmea_r[256] = {0}; char pos = 0; char aidtimeflag=0; char agnss_delay=0; QUEC_GPS_DEV_T * quec_gps = &g_quec_gps_dev; QUEC_GPS_OPS * quec_ops = (QUEC_GPS_OPS *)g_quec_gps_dev.ops; unsigned int buffer_len = 0; char * rx_buf = NULL; int ret = 0; unsigned int cnt =0; int i; char overflow_flag = 0; while(1){ quec_rtos_flag_wait(g_quec_gps_dev.gps_event_flag_ref, QUEC_GPS_EVENT_MASK, QUEC_FLAG_OR_CLEAR, &gps_flags,QUEC_WAIT_FOREVER); if(gps_flags & QUEC_GPS_OPEN_EVENT){ /*gnss打开事件*/ /*step 1:gps 上电*/ ret = gps_open(); if(ret == QUEC_GPS_NO_ERROR){ /*step 2:开启agps定时器*/ quec_hx_agps_init(); /*step 3:初始化gps配置*/ quec_gnss_nmea_cnf(); #if defined (HX_GNSS_CC11_SUPPORT) //CC11系列1PPS有380ms的误差,需要使用原厂指令进行修正 quec_gnss_cmd_1pps_config(); #endif /*step 4:初始化gps配置*/ if((1 == gnss_rom_type) ||(3 == gnss_rom_type)) { /*step 4:初始化gps配置*/ quec_apflash_timer_init(); } ret = quec_gps_start_parse(); if(quec_asr_gps_user_callback_init!=NULL) quec_asr_gps_user_callback_init(QUEC_GPS_INITIAL_SUCCESS,NULL,0); } else { if(quec_asr_gps_user_callback_init!=NULL) quec_asr_gps_user_callback_init(QUEC_GPS_INITIAL_FAILED,NULL,0); } if(ret == QUEC_GPS_NO_ERROR){ if(quec_gps->nmea_cb->open_gps_success_cb) quec_gps->nmea_cb->open_gps_success_cb(); } } else if (gps_flags & QUEC_GPS_CLOSE_EVENT){/*gnss关闭事件*/ /*step 1:关闭nmea解析器*/ quec_gps_stop_nmea_parse(); /*step 2:gps下电*/ gps_close(); /*step 3:关串口,关闭串口操作要在stop_nmea_parse后面,否则可能关机时间和串口接收中断装上导致异常*/ GPS_COM_Deinit(); /*step 4:关闭agps定时器*/ quec_hx_agps_deinit(); if((1 == gnss_rom_type) ||(3 == gnss_rom_type)) { quec_apflash_timer_deinit(); } memset(&hx_loactiong_para,0,sizeof(hx_locationg_t)); quec_gps->worke_state = QUEC_GPS_INIT_STATE; agnss_delay=0; aidtimeflag=0; if(quec_asr_gps_user_callback_init!=NULL) quec_asr_gps_user_callback_init(QUEC_GPS_DEINIT_SUCCESS,NULL,0); } else if (gps_flags & QUEC_GPS_NMEA_PARSE_EVENT){/*nmea数据解析*/ if(g_quec_gps_dev.power_state == QUEC_POWER_ON){ GPS_LOGI("nmea data cnt %d\n",cnt++); buffer_len=GPS_COM_GetByteStatus(); rx_buf = malloc(buffer_len); memset(rx_buf,0,buffer_len); GPS_COM_GetByte_Buffer((char*)rx_buf,buffer_len); if(g_quec_gps_dev.nmea_cb->nmea_packets_cb){ g_quec_gps_dev.nmea_cb->nmea_packets_cb(rx_buf,buffer_len); } for(i=0;i= (int) sizeof(nmea_r)-1 ) { /*如果检测到超出缓冲区大小直接开始下一次*/ overflow_flag = 1; pos = 0; continue; } nmea_r[pos] = (char)rx_buf[i]; pos += 1; if(rx_buf[i] == '\n'){ ret = quec_gnss_nmea_parse(nmea_r,pos); pos = 0; } } if((1 == gnss_rom_type) ||(3 == gnss_rom_type)) { /*检查本地apflash数据是否需要更新*/ if(hx_loactiong_para.valid && ((g_quec_gps_dev.worke_state & QUEC_APFLASH_REQED)==0)){ if(quec_apflsh_data_need_update()){ quec_apflash_req_flag_set();/*第一次定位成功立即获取apflash数据*/ } else { quec_gps->worke_state |= QUEC_APFLASH_REQED; } } } if(ret != QUEC_GPS_NO_ERROR) GPS_LOGE("nmea data parse faile\n"); free(rx_buf); if(GPS_GET_RTC_STATUS()==1 && !aidtimeflag){ quec_gnss_aidtime_msg_send(); aidtimeflag++; } /*开机到现在未同步过agps,可能是由于pdp尚未激活导致,这里查询到如果有pdp激活则会尝试请求一次*/ if(!quec_get_agps_status() && agnss_delay>=3){ //pony add 第一次开机等输出5s的nmea再注入agnss,过早注入可能导致agnss失效 /*如果有pdp激活,尝试同步一次agps*/ if(GPS_GET_NETIF_STATUS() && GPS_GET_RTC_STATUS()){ quec_agps_file_set_to_gps(); } } if(agnss_delay<6) agnss_delay++; if(quec_get_agps_status()&&aidtimeflag){ if(GPS_NW_DEACT) { /*删除网络监控线程节省资源*/ GPS_NW_DEACT(); } } } } #ifdef QUEC_HX_AGPS_TIMER else if(gps_flags & QUEC_AGPS_DATA_REQ_EVENT) { quec_set_agps_status(0); } #endif else if(gps_flags & QUEC_APFLSH_REQ_EVENT) { if(g_quec_gps_dev.power_state == QUEC_POWER_ON){ quec_gnss_apflash_data_request(); quec_gps->worke_state |= QUEC_APFLASH_REQED; GPS_LOGI("GPS REQ APFLSH "); } } else if(gps_flags & QUEC_GPS_APFLASH_EVENT) { if(g_quec_gps_dev.power_state == QUEC_POWER_ON){ GPS_LOGI("GPS RECV APFLSH"); ret = quec_gnss_apflash_recv(); /*接收gps数据*/ if(!ret){ GPS_LOGI("GPS RECV APFLSH not over"); } } } else if(gps_flags & QUEC_GPS_RESTART) { /*step 0:关闭串口*/ GPS_COM_Deinit(); /*step 1:关闭nmea解析器*/ quec_gps_stop_nmea_parse(); /*step 2:gps下电*/ gps_close(); /*step 3:关闭agps定时器*/ quec_hx_agps_deinit(); if((1 == gnss_rom_type) ||(3 == gnss_rom_type)) { /*step 3:关闭apflash定时器*/ quec_apflash_timer_deinit(); } /*step 4:*/ memset(&hx_loactiong_para,0,sizeof(hx_locationg_t)); /*step 5:*/ g_quec_gps_dev.worke_state = QUEC_GPS_INIT_STATE; /*step 1:gps 上电*/ gps_open(); /*step 2:开启agps定时器*/ quec_hx_agps_init(); /*step 3:初始化gps配置*/ quec_gnss_nmea_cnf(); #if defined (HX_GNSS_CC11_SUPPORT) //CC11系列1PPS有380ms的误差,需要使用原厂指令进行修正 quec_gnss_cmd_1pps_config(); #endif if((1 == gnss_rom_type) ||(3 == gnss_rom_type)) { /*step 4:初始化gps配置*/ quec_apflash_timer_init(); } quec_rtos_task_sleep_ms(10); /*step 5:注入agps数据*/ quec_agps_file_set_to_gps(); /*step 6:检查导入的星历是否有效*/ quec_agps_check_vaild(); /*step 7:开启nmea解析器*/ quec_gps_start_parse(); if(quec_asr_gps_user_callback_init!=NULL) quec_asr_gps_user_callback_init(QUEC_GPS_INITIAL_SUCCESS,NULL,0); } else { GPS_LOGE("unknow gps event !!!\n"); } } } int quec_gps_status_get(void) { QUEC_GPS_DEV_T * quec_gps = &g_quec_gps_dev; return quec_gps->power_state; } void quec_gps_dev_init(void) { g_quec_gps_ops.q_gps_open = quec_gps_open; g_quec_gps_ops.q_gps_close = quec_gps_close; g_quec_gps_ops.q_gps_reset = quec_gps_reset; g_quec_gps_ops.q_reg_nmea_str_cb = quec_gps_register_nmea_str_cb; g_quec_gps_ops.q_reg_location_update_cb = quec_gps_register_location_para_cb; g_quec_gps_ops.q_reg_open_gps_success_cb = quec_gps_register_open_success_cb; g_quec_gps_ops.q_reg_agps_sate_num_cb = quec_gps_register_agps_sate_cb; g_quec_gps_ops.q_reg_nmea_packet_cb = quec_gps_register_nmea_packet_cb; g_quec_gps_dev.gps_manufacturer = HX_GPS_MODULE; g_quec_gps_dev.power_state = QUEC_POWER_OFF; g_quec_gps_dev.worke_state = QUEC_GPS_INIT_STATE; g_quec_gps_dev.gps_event_flag_ref = NULL; g_quec_gps_dev.gps_task_ref = NULL; g_quec_gps_dev.gps_keep_alive_timer = NULL; g_quec_gps_dev.ops = &g_quec_gps_ops; g_quec_gps_dev.nmea_cb = &g_quec_nmea_cb; } QUEC_GPS_DEV_T *quec_get_gps_dev(void) { return &g_quec_gps_dev; } static void sys_32k_init(void) { if(1) { #if defined (HX_GNSS_CC11_SUPPORT) && !defined (__QUECTEL_PROJECT_EG915NLA_GK__) unsigned int temp = (*(volatile unsigned long *)(0xD401E32C)); temp = temp & ~0x07; temp |= 0x01; // function 2, select 32K clock mode (*(volatile unsigned long *)(0xD401E32C)) = temp; #else volatile unsigned int temp = 0; unsigned int addr = 0xD401E000 + 50*4; // address of GPIO 122 temp = (*(volatile unsigned long *)(0xD4050038)); GPS_LOGI("SCCR register %08x\r\n", temp); temp = (*(volatile unsigned long *)(addr)); temp = temp & ~0x07; temp |= 0x02; // function 2, select 32K clock mode (*(volatile unsigned long *)(addr)) = temp; #endif } else { GPS_LOGI("Pls Check DCS Mode!!"); } } void quec_gps_init(void) { /*STEP 2: gps主线程初始化*/ //20230807 兼容和芯gnss rom1 rom2处理,rom2需要输出32k gnss_rom_type = quec_gnss_type_check(); int gnss_vbckp_select = quec_hx_bckp_get(); if((2==gnss_rom_type)&&(0 == gnss_vbckp_select)){ gnss_rom_type = 3;//20231011 add type 3:ROM2不接备电 } if(2 == gnss_rom_type) { sys_32k_init(); } quec_gps_dev_init(); quec_gnss_firm_init(); quec_rtos_flag_create(&g_quec_gps_dev.gps_event_flag_ref); quec_rtos_task_create(&g_quec_gps_dev.gps_task_ref , QUEC_GPS_TASK_STACK_SIZE , 90, "qgps_task", quec_gps_process_thread, NULL, NULL); quec_rtos_timer_create(&g_quec_gps_dev.gps_keep_alive_timer);/*gnss保活定时器*/ } #ifdef HX_GNSS_CC11_SUPPORT int read_gnss_id() { int ret = -1; char ack_id[256]={0}; char cnt = 10; int len = 0; memset(ack_id,0,256); while(cnt--) { if(select_read(200)) { len = deal_read(ack_id+len,256-len); //RTI_LOG("quec----,%s,%s",__func__,ack_id); if(strstr((char *)ack_id, "CC1177W")) { ret=BEIDOU_ONLY; break; } if(strstr((char *)ack_id, "CC1161W")) { ret=GNSS_SYS; break; } len+=len; if(len>=256) break; } else break; }//读取超过256字节,退出循环判定硬件ID,防止没有读取到ID信息,一直接收导致数组越界或者硬件ID信息被截断,判定失败 return ret; } int quec_hxgnss_open_getid() { int i=0,reset_sucess=-1; sys_32k_init(); quec_rtos_flag_create(&g_quec_gps_dev.gps_event_flag_ref); g_quec_gps_dev.power_state = QUEC_POWER_OFF; gps_channel_init(); GPS_COM_register_cb(quec_gps_load_fw_cb); GPS_COM_Init(); GPS_COM_SetBaudRate(115200); for(i=0;i<3;i++) { quec_gnss_power_on_off(0); gps_delay_ms(50); quec_gnss_power_on_off(1); //读取GNSSID,-1:读取失败 0:CC1161W,1:CC1177W reset_sucess =read_gnss_id(); if(reset_sucess!=-1) break; GPS_COM_PurgeFIFO(); } quec_gnss_power_on_off(0); GPS_COM_register_cb(NULL); quec_rtos_flag_delete(g_quec_gps_dev.gps_event_flag_ref); g_quec_gps_dev.gps_event_flag_ref = NULL; g_quec_gps_dev.power_state = QUEC_POWER_ON; GPS_COM_Deinit(); return reset_sucess; } #endif