805 lines
26 KiB
C
805 lines
26 KiB
C
#include "service_gps.h"
|
||
#include "ble_api.h"
|
||
#include "fs_user_common.h"
|
||
#include "gnss/gnss_datatypes.h"
|
||
#include "gnss/pgnss_encode.h"
|
||
#include "minmea.h"
|
||
#include "pm_definition.h"
|
||
#include "rtc_api.h"
|
||
#include "securec.h"
|
||
#include "sys_config.h"
|
||
#include "sys_typedef.h"
|
||
#include "task_service_timer.h"
|
||
#include "time.h"
|
||
#include "tiot_service_interface.h"
|
||
#include <cmsis_os2.h>
|
||
#include <dirent.h>
|
||
#include <stdio.h>
|
||
|
||
#define LOG_LEVEL_UNKNOWN 0 /*!< Log level unknown. */
|
||
#define LOG_LEVEL_ERR 1 /*!< Log level error. */
|
||
#define LOG_LEVEL_WARNING 2 /*!< Log level warning. */
|
||
#define LOG_LEVEL_INFO 3 /*!< Log level info. */
|
||
#define LOG_LEVEL_DEBUG 4 /*!< Log level debug. */
|
||
|
||
#define LOG_LEVEL LOG_LEVEL_DEBUG
|
||
|
||
#define PRINT_LOG(level, func, s, ...) \
|
||
do { \
|
||
if (LOG_LEVEL >= level) { \
|
||
func(s, ##__VA_ARGS__); \
|
||
} \
|
||
} while (0)
|
||
|
||
#define static_print_info(s, ...) PRINT_LOG(LOG_LEVEL_INFO, sys_gps_log_i, s, ##__VA_ARGS__)
|
||
#define static_print_debug(s, ...) PRINT_LOG(LOG_LEVEL_DEBUG, sys_gps_log_d, s, ##__VA_ARGS__)
|
||
#define static_print_warn(s, ...) PRINT_LOG(LOG_LEVEL_WARNING, sys_gps_log_w, s, ##__VA_ARGS__)
|
||
#define static_print_error(s, ...) PRINT_LOG(LOG_LEVEL_ERR, sys_gps_log_e, s, ##__VA_ARGS__)
|
||
|
||
#define GPS_PATH TJD_FS_DIR_GPS "/"
|
||
|
||
#define PGNSS_FIXMODEALL_NMEADEF_SAMPLE 0
|
||
#define PGNSS_LESS_FILES_FIXMODEALL_NMEADEF_SAMPLE 1
|
||
|
||
|
||
#ifndef ARRAY_SIZE
|
||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||
#endif
|
||
#define MSG_TYPE_BINRY 0
|
||
#define MSG_TYPE_ASCII 1
|
||
#define LISTEN_DATA_MAX_LINES 1000
|
||
|
||
#pragma region PGNSS_ENCODE
|
||
|
||
#define GNSS_ENCODE_BUFF_MAX_LEN 9300
|
||
#define FILE_PATH_LEN 1024
|
||
#define GLO_EPH_VALID_TIME 900
|
||
#define OTHER_EPH_VALID_TIME 7200
|
||
#define NON_GLO_GNSS_TYPES 4
|
||
#define GLO_EPH_NUM_ONE_FILE 8
|
||
#define OTHER_ASSIST_TYPES 7
|
||
#define INJECT_SLEEP_MS_TIME 100
|
||
#define PGNSS_FILE_MAX_SIZE 1024000
|
||
|
||
// 监听消息
|
||
static uint8_t g_ackBuff[REPORT_MAX_BYTES] = {0};
|
||
|
||
/* 计算命令内容校准和 */
|
||
static uint16_t CalcChecksum(uint8_t *buff, uint16_t len)
|
||
{
|
||
uint16_t checksum = 0;
|
||
uint16_t i = 0;
|
||
while (i++ < len) {
|
||
checksum += *buff;
|
||
buff++;
|
||
}
|
||
return checksum;
|
||
}
|
||
|
||
static uint16_t FillGnssMessageData(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen)
|
||
{
|
||
errno_t ret = memcpy_s(outBuff, outLen, inBuff, inLen);
|
||
if (ret != EOK) {
|
||
static_print_error("memcpy XgnssData failed! Errno is %d", ret);
|
||
return 0;
|
||
}
|
||
|
||
return inLen;
|
||
}
|
||
|
||
static int32_t EncodeGnssMsg(uint8_t *inBuff, uint32_t inLen, uint8_t *outBuff, uint32_t outLen)
|
||
{
|
||
uint16_t len = FillGnssMessageData(inBuff, inLen, outBuff, outLen);
|
||
if (len > 0) {
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static void ListenAck(tiot_handle handle)
|
||
{
|
||
int32_t i = 0;
|
||
for (;;) {
|
||
// 监听
|
||
int32_t ret = tiot_service_read(handle, g_ackBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR);
|
||
if (ret > 0) {
|
||
uint16_t *type = (uint16_t *)g_ackBuff;
|
||
// 二进制消息类型
|
||
if (type[0] == 0) {
|
||
g_ackBuff[ret] = '\0';
|
||
}
|
||
i++;
|
||
}
|
||
if (i >= 1) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
static int32_t EncodeAndInjectCmd(tiot_handle handle, GnssCmdType cmdType, uint8_t *inBuff, uint32_t inLen)
|
||
{
|
||
// 获取GNSS业务消息头
|
||
int32_t len = 0;
|
||
uint8_t *buff = (uint8_t *)malloc(GNSS_ENCODE_BUFF_MAX_LEN);
|
||
if (buff == NULL) {
|
||
static_print_error("malloc failed in EncodeAndInjectCmd");
|
||
return 0;
|
||
}
|
||
memset_s(buff, GNSS_ENCODE_BUFF_MAX_LEN, 0, GNSS_ENCODE_BUFF_MAX_LEN);
|
||
|
||
GnssMsg *gnssHdr = (GnssMsg *)buff;
|
||
len += sizeof(GnssMsg);
|
||
|
||
gnssHdr->sequence = 0;
|
||
|
||
int32_t retLen = EncodeGnssMsg(inBuff, inLen, buff + len, (GNSS_ENCODE_BUFF_MAX_LEN - len));
|
||
if (retLen != 1) {
|
||
static_print_error("Encode Cmd failed: %d", cmdType);
|
||
free(buff);
|
||
return retLen;
|
||
}
|
||
gnssHdr->cmd = cmdType;
|
||
gnssHdr->dataLength = inLen;
|
||
gnssHdr->checkSum = CalcChecksum(gnssHdr->data, gnssHdr->dataLength);
|
||
int32_t ret = tiot_service_write(handle, buff, (sizeof(GnssMsg) + gnssHdr->dataLength));
|
||
if (ret < 0) {
|
||
static_print_error("Inject Cmd failed: %d", cmdType);
|
||
free(buff);
|
||
return 0;
|
||
}
|
||
ListenAck(handle);
|
||
static_print_debug("Inject Cmd SUCCESS: %x", cmdType);
|
||
free(buff);
|
||
return 1;
|
||
}
|
||
|
||
int32_t FormatFileName(char *fileName, char *dName)
|
||
{
|
||
int32_t ret = snprintf_s(fileName, FILE_PATH_LEN, (FILE_PATH_LEN - 1), "%s%s", GPS_PATH "", dName);
|
||
if (ret <= 0) {
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
// 以下为使用PGNSS解析数据合并输出接口生成的星历文件进行注入的代码
|
||
int32_t GetNonGloEphFileName(int32_t ts, char *fileName)
|
||
{
|
||
const char prefix[] = "NonGlo";
|
||
DIR *dir = opendir(GPS_PATH "");
|
||
if (dir == NULL) {
|
||
static_print_debug("Failed to open /user/tjd_gps directory.");
|
||
return 0;
|
||
}
|
||
int32_t time, ret;
|
||
int32_t minDist = OTHER_EPH_VALID_TIME;
|
||
int32_t closestTime = 0;
|
||
struct dirent *entry;
|
||
for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) {
|
||
// 检查文件名
|
||
if (strstr(entry->d_name, ".eph") != NULL) {
|
||
char *p = strrchr(entry->d_name, '_');
|
||
if (p != NULL) {
|
||
char *q = strstr(entry->d_name, prefix);
|
||
if (q != NULL) {
|
||
time = atoi(p + 1);
|
||
// 查找星历文件时间戳与当前时间相差2小时以内且距离最近的
|
||
if (abs(time - ts) < minDist) {
|
||
minDist = abs(time - ts);
|
||
closestTime = time;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (closestTime != 0) {
|
||
ret =
|
||
snprintf_s(fileName, FILE_PATH_LEN, (FILE_PATH_LEN - 1), "%s%d%s", GPS_PATH "NonGlo_", closestTime, ".eph");
|
||
closedir(dir);
|
||
return ((ret <= 0) ? 0 : 1);
|
||
}
|
||
closedir(dir);
|
||
return 0;
|
||
}
|
||
|
||
int32_t GetGloEphFileName(int32_t ts, char *fileName)
|
||
{
|
||
const char prefix[] = "GLO";
|
||
DIR *dir = opendir(GPS_PATH "");
|
||
if (dir == NULL) {
|
||
static_print_debug("Failed to open /user/tjd_gps directory.");
|
||
return 0;
|
||
}
|
||
int32_t ephTime, ret;
|
||
struct dirent *entry;
|
||
for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) {
|
||
// 检查文件名
|
||
if (strstr(entry->d_name, ".eph") != NULL) {
|
||
char *p = strrchr(entry->d_name, '_');
|
||
if (p != NULL) {
|
||
char *q = strstr(entry->d_name, prefix);
|
||
if (q != NULL) {
|
||
ephTime = atoi(p + 1);
|
||
// 当前时间大于GLO星历文件时间戳,则需要选取相差2小时以内的星历
|
||
// 当前时间小于GLO星历文件时间戳,则需要选取相差小于15分钟的星历
|
||
if (((ts - ephTime) >= 0 && abs(ephTime - ts) < OTHER_EPH_VALID_TIME) ||
|
||
((ts - ephTime) <= 0 && abs(ephTime - ts) < GLO_EPH_VALID_TIME)) {
|
||
ret = FormatFileName(fileName, entry->d_name);
|
||
closedir(dir);
|
||
return ret;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
closedir(dir);
|
||
return 0;
|
||
}
|
||
|
||
void PgnssSendNonGloEph(tiot_handle handle, const char *fileName)
|
||
{
|
||
FILE *fp = fopen(fileName, "rb");
|
||
if (fp == NULL) {
|
||
static_print_error("open file failed: %s", fileName);
|
||
return;
|
||
}
|
||
fseek(fp, 0, SEEK_END);
|
||
int32_t len = ftell(fp);
|
||
fseek(fp, 0, SEEK_SET);
|
||
if (len < 0 || len > PGNSS_FILE_MAX_SIZE) {
|
||
fclose(fp);
|
||
static_print_error("get file len failed: %s", fileName);
|
||
return;
|
||
}
|
||
uint8_t *buff = (uint8_t *)malloc(len);
|
||
if (buff == NULL) {
|
||
fclose(fp);
|
||
static_print_error("malloc file len failed: %s", fileName);
|
||
return;
|
||
}
|
||
int32_t dataSize = fread(buff, len, 1, fp);
|
||
if (dataSize < 0) {
|
||
fclose(fp);
|
||
static_print_error("read file failed: %s", fileName);
|
||
free(buff);
|
||
return;
|
||
}
|
||
fclose(fp);
|
||
int32_t fileLen = 0;
|
||
for (int32_t i = 0; i < NON_GLO_GNSS_TYPES && fileLen <= len; i++) {
|
||
EphHeadInfo *ephHdr = (EphHeadInfo *)(buff + fileLen);
|
||
EncodeAndInjectCmd(handle, ephHdr->cmd, (buff + fileLen + sizeof(EphHeadInfo)), ephHdr->len);
|
||
fileLen += (ephHdr->len + sizeof(EphHeadInfo));
|
||
osal_msleep(INJECT_SLEEP_MS_TIME);
|
||
}
|
||
free(buff);
|
||
}
|
||
|
||
void PgnssSendGloEph(tiot_handle handle, const char *fileName, int32_t ts)
|
||
{
|
||
FILE *fp = fopen(fileName, "rb");
|
||
if (fp == NULL) {
|
||
static_print_error("open file failed: %s", fileName);
|
||
return;
|
||
}
|
||
fseek(fp, 0, SEEK_END);
|
||
int32_t len = ftell(fp);
|
||
fseek(fp, 0, SEEK_SET);
|
||
if (len < 0 || len > PGNSS_FILE_MAX_SIZE) {
|
||
fclose(fp);
|
||
static_print_error("get file len failed: %s", fileName);
|
||
return;
|
||
}
|
||
uint8_t *buff = (uint8_t *)malloc(len);
|
||
if (buff == NULL) {
|
||
fclose(fp);
|
||
static_print_error("malloc file len failed: %s", fileName);
|
||
return;
|
||
}
|
||
int32_t dataSize = fread(buff, len, 1, fp);
|
||
if (dataSize < 0) {
|
||
fclose(fp);
|
||
static_print_error("read file failed: %s", fileName);
|
||
free(buff);
|
||
return;
|
||
}
|
||
fclose(fp);
|
||
int32_t fileLen = 0;
|
||
for (int32_t i = 0; i < GLO_EPH_NUM_ONE_FILE && fileLen <= len; i++) {
|
||
EphHeadInfo *ephHdr = (EphHeadInfo *)(buff + fileLen);
|
||
if (abs((int32_t)ephHdr->time - ts) < GLO_EPH_VALID_TIME) {
|
||
EncodeAndInjectCmd(handle, ephHdr->cmd, (buff + fileLen + sizeof(EphHeadInfo)), ephHdr->len);
|
||
osal_msleep(INJECT_SLEEP_MS_TIME);
|
||
break;
|
||
}
|
||
fileLen += (ephHdr->len + sizeof(EphHeadInfo));
|
||
}
|
||
free(buff);
|
||
}
|
||
|
||
void PgnssInjectAllEphLessFiles(tiot_handle handle, uint32_t ts)
|
||
{
|
||
char fileName[FILE_PATH_LEN] = {0};
|
||
if (GetNonGloEphFileName(ts, fileName) == 0) {
|
||
static_print_error("GetNonGloEphFileName failed");
|
||
return;
|
||
}
|
||
PgnssSendNonGloEph(handle, fileName);
|
||
if (GetGloEphFileName(ts, fileName) == 0) {
|
||
static_print_error("GetGloEphFileName failed");
|
||
return;
|
||
}
|
||
PgnssSendGloEph(handle, fileName, ts);
|
||
}
|
||
|
||
void PgnssSendOtherAssistInfo(tiot_handle handle, const char *fileName)
|
||
{
|
||
FILE *fp = fopen(fileName, "rb");
|
||
if (fp == NULL) {
|
||
static_print_error("open file failed: %s", fileName);
|
||
return;
|
||
}
|
||
fseek(fp, 0, SEEK_END);
|
||
int32_t len = ftell(fp);
|
||
fseek(fp, 0, SEEK_SET);
|
||
if (len < 0 || len > PGNSS_FILE_MAX_SIZE) {
|
||
fclose(fp);
|
||
static_print_error("get file len failed: %s", fileName);
|
||
return;
|
||
}
|
||
uint8_t *buff = (uint8_t *)malloc(len);
|
||
if (buff == NULL) {
|
||
fclose(fp);
|
||
static_print_error("malloc file len failed: %s", fileName);
|
||
return;
|
||
}
|
||
int32_t dataSize = fread(buff, len, 1, fp);
|
||
if (dataSize < 0) {
|
||
fclose(fp);
|
||
static_print_error("read file failed: %s", fileName);
|
||
free(buff);
|
||
return;
|
||
}
|
||
fclose(fp);
|
||
int32_t fileLen = 0;
|
||
for (int32_t i = 0; i < OTHER_ASSIST_TYPES && fileLen <= len; i++) {
|
||
OtherAssistHeadInfo *otherHdr = (OtherAssistHeadInfo *)(buff + fileLen);
|
||
EncodeAndInjectCmd(handle, otherHdr->cmd, (buff + fileLen + sizeof(OtherAssistHeadInfo)), otherHdr->len);
|
||
fileLen += (otherHdr->len + sizeof(OtherAssistHeadInfo));
|
||
osal_msleep(INJECT_SLEEP_MS_TIME);
|
||
}
|
||
free(buff);
|
||
}
|
||
#pragma endregion
|
||
|
||
#pragma region GNSS_CALLBACK
|
||
|
||
static gnss_service_cb_t g_gnssServiceCb;
|
||
static gnss_data_t g_rmcData;
|
||
static struct minmea_sentence_gga g_gga;
|
||
|
||
static void gnss_service_status_changed_callback(bool open)
|
||
{
|
||
if (g_gnssServiceCb.service_changed_cb != NULL) {
|
||
g_gnssServiceCb.service_changed_cb(open);
|
||
}
|
||
}
|
||
|
||
static void rmc_changed_callback(const struct minmea_sentence_rmc *frame)
|
||
{
|
||
if (g_gnssServiceCb.rmc_status_cb != NULL) {
|
||
gnss_rmc_data_t rmc_data = {
|
||
.latitude = minmea_tocoord(&frame->latitude),
|
||
.longitude = minmea_tocoord(&frame->longitude),
|
||
.speed = minmea_tofloat(&frame->speed),
|
||
.course = minmea_tofloat(&frame->course),
|
||
.valid = frame->valid,
|
||
};
|
||
g_gnssServiceCb.rmc_status_cb(&rmc_data);
|
||
}
|
||
}
|
||
|
||
static void gsv_changed_callback(const struct minmea_sentence_gsv *frame)
|
||
{
|
||
if (g_gnssServiceCb.gsv_status_cb != NULL) {
|
||
g_gnssServiceCb.gsv_status_cb(frame);
|
||
}
|
||
}
|
||
|
||
static void zda_changed_callback(const struct minmea_sentence_zda *frame)
|
||
{
|
||
char time[48] = {0};
|
||
snprintf_s(time, sizeof(time), sizeof(time) - 1, "%d:%d:%d %02d.%02d.%d UTC%+03d:%02d", frame->time.hours,
|
||
frame->time.minutes, frame->time.seconds, frame->date.day, frame->date.month, frame->date.year,
|
||
frame->hour_offset, frame->minute_offset);
|
||
if (g_gnssServiceCb.zda_status_cb != NULL) {
|
||
g_gnssServiceCb.zda_status_cb(time);
|
||
}
|
||
}
|
||
|
||
static void gga_changed_callback(const struct minmea_sentence_gga *frame)
|
||
{
|
||
if (g_gnssServiceCb.gga_status_cb != NULL) {
|
||
g_gnssServiceCb.gga_status_cb(frame);
|
||
}
|
||
}
|
||
|
||
static void vtg_changed_callback(const struct minmea_sentence_vtg *frame)
|
||
{
|
||
if (g_gnssServiceCb.vtg_status_cb != NULL) {
|
||
gnss_vtg_data_t vtg_data = {
|
||
.true_track_degrees = minmea_tofloat(&frame->true_track_degrees),
|
||
.magnetic_track_degrees = minmea_tofloat(&frame->magnetic_track_degrees),
|
||
.speed_knots = minmea_tofloat(&frame->speed_knots),
|
||
.speed_kph = minmea_tofloat(&frame->speed_kph),
|
||
};
|
||
g_gnssServiceCb.vtg_status_cb(&vtg_data);
|
||
}
|
||
}
|
||
|
||
void register_gnss_changed_cb(gnss_service_cb_t *gnss_service_func)
|
||
{
|
||
memcpy_s(&g_gnssServiceCb, sizeof(gnss_service_cb_t), gnss_service_func, sizeof(gnss_service_cb_t));
|
||
}
|
||
|
||
void unregister_gnss_changed_cb(void)
|
||
{
|
||
memset_s(&g_gnssServiceCb, sizeof(gnss_service_cb_t), 0, sizeof(gnss_service_cb_t));
|
||
}
|
||
|
||
#pragma endregion
|
||
|
||
void PgnssInjectOtherAssistLessFiles(tiot_handle handle)
|
||
{
|
||
PgnssSendOtherAssistInfo(handle, GPS_PATH "AssistInfo.dat");
|
||
}
|
||
|
||
static FILE *g_gnssLogFp = NULL;
|
||
static uint8_t *g_gnssServiceBuff = NULL;
|
||
static tiot_handle g_handle;
|
||
|
||
typedef int32_t (*GnssCfgFunc)(tiot_handle handle);
|
||
|
||
typedef struct
|
||
{
|
||
uint16_t sampleId;
|
||
GnssCfgFunc cfgHandle;
|
||
} GnssSamplesCfgTable;
|
||
|
||
static int32_t QryVersion(tiot_handle handle)
|
||
{
|
||
const uint8_t qryVersion[] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
|
||
// 查询版本号
|
||
int32_t ret = tiot_service_write(handle, qryVersion, sizeof(qryVersion));
|
||
if (ret < 0) {
|
||
static_print_error("QryVersion error: %d", ret);
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
// 注入PGNSS,使用默认配置启动
|
||
int32_t InjectPgnssLessFilesCfgAutoStartFixModeAndNmeaDefault(tiot_handle handle)
|
||
{
|
||
const uint8_t cfgFixModeAllCmd[] = {0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00,
|
||
0x00, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00};
|
||
const uint8_t cfgLogLevelInfo[] = {0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x10, 0x01, 0x00, 0x03};
|
||
const uint8_t cfgNmeaCmd[] = {0x03, 0x00, 0x04, 0x01, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x02, 0x00, 0xff, 0x00};
|
||
|
||
// 配置log级别:info级别。
|
||
int32_t ret = tiot_service_write(handle, cfgLogLevelInfo, sizeof(cfgLogLevelInfo));
|
||
if (ret < 0) {
|
||
static_print_error("cfgLogLevelInfo error: %d", ret);
|
||
return 0;
|
||
}
|
||
|
||
// 配置使能的GNSS星座:QZSS/GAL/BDS/GLO/GPS。
|
||
ret = tiot_service_write(handle, cfgFixModeAllCmd, sizeof(cfgFixModeAllCmd));
|
||
if (ret < 0) {
|
||
static_print_error("error: cfgFixModeAllCmd error: %d", ret);
|
||
return 0;
|
||
}
|
||
|
||
// 配置上报NMEA类型:PNT/ZDA/VTG/RMC/GSV/GSA/GLL/GGA。
|
||
ret = tiot_service_write(handle, cfgNmeaCmd, sizeof(cfgNmeaCmd));
|
||
if (ret < 0) {
|
||
static_print_error("error: cfgNmeaCmd error: %d", ret);
|
||
return 0;
|
||
}
|
||
|
||
// 注入UTC时间, 注入Pgnss辅助数据前必须先注入参考时间
|
||
struct rtc_time time;
|
||
tjd_driver_rtc_get_ops()->get_rtc_utc_time(&time);
|
||
// 需要用当前的UTC时间替换
|
||
GnssUtcTime utcTime = {time.tm_year, time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, 0, 1};
|
||
uint32_t ts = 0;
|
||
ret = PgnssInjectUtcTime(handle, &utcTime, &ts);
|
||
if (ret == 0) {
|
||
static_print_error("PgnssInjectUtcTime failed!");
|
||
return 0;
|
||
}
|
||
static_print_debug("PgnssInjectUtcTime success! ts = %u", ts);
|
||
|
||
// PGNSS注入
|
||
// 注意,默认PGNSS星历文件存放在/user/tjd_gps/目录中,如修改目录,请全局搜索替换
|
||
PgnssInjectLessFiles(handle, ts);
|
||
|
||
return 1;
|
||
}
|
||
|
||
static int32_t StartGnss(tiot_handle handle)
|
||
{
|
||
const uint8_t startCmd[] = {0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||
// 启动GNSS
|
||
int32_t ret = tiot_service_write(handle, startCmd, sizeof(startCmd));
|
||
if (ret < 0) {
|
||
static_print_error("start gnss error: %d", ret);
|
||
return 0;
|
||
}
|
||
static_print_debug("start gnss");
|
||
return 1;
|
||
}
|
||
|
||
static int32_t StopGnss(tiot_handle handle)
|
||
{
|
||
const uint8_t stopCmd[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||
// 停止GNSS
|
||
int32_t ret = tiot_service_write(handle, stopCmd, sizeof(stopCmd));
|
||
if (ret < 0) {
|
||
static_print_error("stop gnss error: %d", ret);
|
||
return 0;
|
||
}
|
||
static_print_debug("stop gnss");
|
||
return 1;
|
||
}
|
||
|
||
static void gnss_data_process(char *line, uint32_t len)
|
||
{
|
||
switch (minmea_sentence_id(line, false)) {
|
||
case MINMEA_SENTENCE_RMC: {
|
||
struct minmea_sentence_rmc frame;
|
||
if (minmea_parse_rmc(&frame, line)) {
|
||
g_rmcData.latitude = minmea_tocoord(&frame.latitude);
|
||
g_rmcData.longitude = minmea_tocoord(&frame.longitude);
|
||
g_rmcData.valid = frame.valid;
|
||
rmc_changed_callback(&frame);
|
||
}
|
||
}
|
||
case MINMEA_SENTENCE_GGA: {
|
||
struct minmea_sentence_gga frame;
|
||
if (minmea_parse_gga(&frame, line)) {
|
||
memcpy_s(&g_gga, sizeof(struct minmea_sentence_gga), &frame, sizeof(struct minmea_sentence_gga));
|
||
g_rmcData.num_sats = frame.satellites_tracked;
|
||
gga_changed_callback(&frame);
|
||
static_print_debug("$xxGGA: fix quality: %d, satellites_tracked: %d", frame.fix_quality,
|
||
frame.satellites_tracked);
|
||
}
|
||
} break;
|
||
case MINMEA_SENTENCE_GSV: {
|
||
struct minmea_sentence_gsv frame;
|
||
if (minmea_parse_gsv(&frame, line)) {
|
||
// frame.gnss_type;
|
||
gsv_changed_callback(&frame);
|
||
static_print_debug("$xxGSV: message %d of %d", frame.msg_nr, frame.total_msgs);
|
||
static_print_debug("$xxGSV: satellites in view: %d", frame.total_sats);
|
||
for (int i = 0; i < 4; i++) {
|
||
static_print_debug("$xxGSV: sat nr %d, elevation: %d, azimuth: %d, snr: %d dbm", frame.sats[i].nr,
|
||
frame.sats[i].elevation, frame.sats[i].azimuth, frame.sats[i].snr);
|
||
}
|
||
}
|
||
} break;
|
||
case MINMEA_SENTENCE_VTG: {
|
||
struct minmea_sentence_vtg frame;
|
||
if (minmea_parse_vtg(&frame, line)) {
|
||
vtg_changed_callback(&frame);
|
||
static_print_debug("$xxVTG: true track degrees = %f", minmea_tofloat(&frame.true_track_degrees));
|
||
static_print_debug(" magnetic track degrees = %f", minmea_tofloat(&frame.magnetic_track_degrees));
|
||
static_print_debug(" speed knots = %f", minmea_tofloat(&frame.speed_knots));
|
||
static_print_debug(" speed kph = %f", minmea_tofloat(&frame.speed_kph));
|
||
}
|
||
} break;
|
||
case MINMEA_SENTENCE_ZDA: {
|
||
struct minmea_sentence_zda frame;
|
||
if (minmea_parse_zda(&frame, line)) {
|
||
zda_changed_callback(&frame);
|
||
static_print_debug("$xxZDA: %d:%d:%d %02d.%02d.%d UTC%+03d:%02d", frame.time.hours, frame.time.minutes,
|
||
frame.time.seconds, frame.date.day, frame.date.month, frame.date.year, frame.hour_offset,
|
||
frame.minute_offset);
|
||
}
|
||
} break;
|
||
default: {
|
||
} break;
|
||
};
|
||
}
|
||
|
||
static bool g_gps_service_is_open = false;
|
||
void gps_service_task(void *argument)
|
||
{
|
||
g_handle = tiot_service_open("gn71", NULL);
|
||
if (g_handle == 0) {
|
||
static_print_debug("open tiot service fail");
|
||
return;
|
||
}
|
||
|
||
/* 注入离线星历,采用合并的方式注入 */
|
||
InjectPgnssLessFilesCfgAutoStartFixModeAndNmeaDefault(g_handle);
|
||
|
||
QryVersion(g_handle);
|
||
|
||
if (StartGnss(g_handle) == 0) {
|
||
static_print_debug("start gnss fail");
|
||
return;
|
||
}
|
||
|
||
gnss_service_status_changed_callback(true);
|
||
|
||
g_gps_service_is_open = true;
|
||
|
||
if (g_gnssServiceBuff == NULL) {
|
||
g_gnssServiceBuff = (uint8_t *)malloc(REPORT_MAX_BYTES);
|
||
if (g_gnssServiceBuff == NULL) {
|
||
static_print_error("malloc failed in gps_service_task");
|
||
return;
|
||
}
|
||
}
|
||
|
||
for (;;) {
|
||
// 监听
|
||
int32_t ret = tiot_service_read(g_handle, g_gnssServiceBuff, REPORT_MAX_BYTES, LISTEN_TIME_THR);
|
||
if (ret > 0) {
|
||
uint16_t *type = (uint16_t *)g_gnssServiceBuff;
|
||
if (type[0] == MSG_TYPE_ASCII) {
|
||
g_gnssServiceBuff[ret] = '\0';
|
||
gnss_data_process((char *)&g_gnssServiceBuff[MSG_CONTENT_IDX], ret - MSG_CONTENT_IDX);
|
||
static_print_debug("%s", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]);
|
||
fprintf(g_gnssLogFp, "%s\n", (char *)&g_gnssServiceBuff[MSG_CONTENT_IDX]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static osThreadId_t g_gps_task_id = NULL;
|
||
static void tjd_service_charger_start_send(void)
|
||
{
|
||
if (g_gps_task_id != NULL) {
|
||
static_print_debug("gps service task is already running");
|
||
return;
|
||
}
|
||
|
||
osThreadAttr_t task_attr = {"tjd_gps_task", 0, NULL, 0, NULL, 0x1200, 17, 0, 0};
|
||
task_attr.stack_mem = memalign(16, task_attr.stack_size); // add
|
||
g_gps_task_id = osThreadNew(gps_service_task, NULL, &task_attr);
|
||
if (g_gps_task_id == NULL) {
|
||
static_print_error("create gps service task failed");
|
||
return;
|
||
}
|
||
// queue_default_info_t msg_data = {tjd_service_charger_handle, NULL, 100, NULL};
|
||
// osal_msg_queue_write_copy(tjd_task_service_timer_get_queue_id(), (void *)&msg_data, sizeof(queue_default_info_t),
|
||
// 0);
|
||
}
|
||
|
||
static void tjd_service_charger_end_send(void)
|
||
{
|
||
if (g_gps_task_id != NULL) {
|
||
osThreadTerminate(g_gps_task_id);
|
||
g_gps_task_id = NULL;
|
||
}
|
||
// queue_default_info_t msg_data = {tjd_service_charger_handle, NULL, 0, NULL};
|
||
// osal_msg_queue_write_copy(tjd_task_service_timer_get_queue_id(), (void *)&msg_data, sizeof(queue_default_info_t),
|
||
// 0);
|
||
}
|
||
|
||
bool tjd_service_gps_ephemer_is_valid(void)
|
||
{
|
||
uint64_t ts = 0;
|
||
tjd_driver_rtc_get_ops()->get_timestamp(&ts);
|
||
char fileName[FILE_PATH_LEN] = {0};
|
||
static_print_debug("ts = %llu", ts);
|
||
if (GetNonGloEphFileName(ts, fileName) == 0) {
|
||
static_print_error("GetNonGloEphFileName failed");
|
||
return false;
|
||
}
|
||
if (GetGloEphFileName(ts, fileName) == 0) {
|
||
static_print_error("GetGloEphFileName failed");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
uint32_t tjd_service_gps_open(void)
|
||
{
|
||
if (g_gps_service_is_open) {
|
||
static_print_debug("gnss samples is already open");
|
||
return 0;
|
||
}
|
||
uapi_pm_add_sleep_veto(PM_ID_SYS);
|
||
static_print_debug("enter gnss samples");
|
||
|
||
g_gnssLogFp = fopen("/user/gnss.log", "w");
|
||
if (g_gnssLogFp == NULL) {
|
||
static_print_error("open log file error");
|
||
return 1;
|
||
}
|
||
|
||
tjd_service_charger_start_send();
|
||
static_print_info("open tiot service success");
|
||
return 0;
|
||
}
|
||
|
||
void tjd_service_gps_close(void)
|
||
{
|
||
if (!g_gps_service_is_open) {
|
||
static_print_debug("gnss samples is already close");
|
||
return;
|
||
}
|
||
tjd_service_charger_end_send();
|
||
StopGnss(g_handle);
|
||
tiot_service_close(g_handle);
|
||
fclose(g_gnssLogFp);
|
||
g_gnssLogFp = NULL;
|
||
uapi_pm_remove_sleep_veto(PM_ID_SYS);
|
||
static_print_info("finish gnss samples");
|
||
gnss_service_status_changed_callback(false);
|
||
|
||
if (g_gnssServiceBuff) {
|
||
free(g_gnssServiceBuff);
|
||
g_gnssServiceBuff = NULL;
|
||
}
|
||
g_gps_service_is_open = false;
|
||
}
|
||
|
||
static struct timespec last_time = {0};
|
||
void tjd_service_gps_sync_ephemeris_event(void)
|
||
{
|
||
if (!tjd_service_gps_ephemer_is_valid()) {
|
||
static_print_debug("gps ephemer is not valid");
|
||
tjd_ble_request_gps();
|
||
return;
|
||
}
|
||
struct timespec time = {0};
|
||
clock_gettime(CLOCK_MONOTONIC, &time);
|
||
if (last_time.tv_sec != 0 && (time.tv_sec - last_time.tv_sec) < 60 * 60 * 2) {
|
||
static_print_debug("tjd_service_gps_sync_ephemeris_event too fast");
|
||
return;
|
||
}
|
||
static_print_debug("tjd_service_gps_sync_ephemeris_event");
|
||
last_time = time;
|
||
tjd_ble_request_gps();
|
||
}
|
||
|
||
#define GPS_SYNC_EPH_TIME (8 * 60 * 60 * 1000)
|
||
#define GPS_SYNC_EPH_ERR_TIME (10 * 60 * 1000)
|
||
static signed int tjd_service_gps_sync_handle(void *param)
|
||
{
|
||
static_print_debug("tjd_service_gps_sync_handle");
|
||
if (tjd_get_ble_is_connect()) {
|
||
tjd_service_gps_sync_ephemeris_event();
|
||
} else {
|
||
return GPS_SYNC_EPH_ERR_TIME;
|
||
}
|
||
return GPS_SYNC_EPH_TIME;
|
||
}
|
||
|
||
void tjd_service_gps_sync_open()
|
||
{
|
||
queue_default_info_t msg_data = {tjd_service_gps_sync_handle, NULL, GPS_SYNC_EPH_TIME, NULL};
|
||
osal_msg_queue_write_copy(tjd_task_service_timer_get_queue_id(), (void *)&msg_data, sizeof(msg_data), 0);
|
||
}
|
||
|
||
void tjd_service_gps_get_data(gnss_data_t *rmc_data)
|
||
{
|
||
if (rmc_data == NULL) {
|
||
return;
|
||
}
|
||
memcpy_s(rmc_data, sizeof(gnss_data_t), &g_rmcData, sizeof(gnss_data_t));
|
||
}
|
||
|
||
void tjd_service_gps_get_gga_data(struct minmea_sentence_gga *gga_data)
|
||
{
|
||
if (gga_data == NULL) {
|
||
return;
|
||
}
|
||
memcpy_s(gga_data, sizeof(struct minmea_sentence_gga), &g_gga, sizeof(struct minmea_sentence_gga));
|
||
}
|