337 lines
10 KiB
C
337 lines
10 KiB
C
#include "cm_iomux.h"
|
||
#include "cm_gpio.h"
|
||
#include "stdio.h"
|
||
#include "stdlib.h"
|
||
#include "stdarg.h"
|
||
#include "cm_os.h"
|
||
#include "cm_mem.h"
|
||
#include "cm_sys.h"
|
||
#include "cm_uart.h"
|
||
|
||
#include "app_common.h"
|
||
#include "app_uart.h"
|
||
|
||
#include "gps_config.h"
|
||
#include "local_tts.h"
|
||
|
||
#if 0
|
||
#include "app_uart.h"
|
||
#define DEBUG(fmt, args...) app_printf("[GPS]" fmt, ##args)
|
||
#else
|
||
#include "app_uart.h"
|
||
#define DEBUG(fmt, ...)
|
||
#endif
|
||
|
||
#define GPS_URAT CM_UART_DEV_1
|
||
#define GPS_RX_IOMUX UART1_RX_IOMUX
|
||
#define GPS_TX_IOMUX UART1_TX_IOMUX
|
||
|
||
#define GPS_BUF_LEN 512
|
||
|
||
static int gps_rev_len = 0;
|
||
static char gps_rev_data[GPS_BUF_LEN] = {0};
|
||
|
||
static osThreadId_t GPS_ThreadId = NULL; //串口数据接收、解析任务Handle
|
||
static void* gps_uart_sem = NULL; //串口数据接收、解析任务信号量
|
||
|
||
|
||
/**
|
||
* @brief trace 在解码时输出捕获的GPS语句
|
||
* @param str: 要输出的字符串,str_size:数据长度
|
||
* @retval 无
|
||
*/
|
||
void trace(const char *str, int str_size){
|
||
// app_printf("\r\nTrace: ");
|
||
// uart0_send_msg((uint8_t*)str, str_size, 0);
|
||
}
|
||
|
||
/**
|
||
* @brief error 在解码出错时输出提示消息
|
||
* @param str: 要输出的字符串,str_size:数据长度
|
||
* @retval 无
|
||
*/
|
||
void error(const char *str, int str_size){
|
||
// app_printf("\r\nError: ");
|
||
// uart0_send_msg((uint8_t*)str, str_size, 0);
|
||
}
|
||
|
||
/**
|
||
* @brief error 在解码出错时输出提示消息
|
||
* @param str: 要输出的字符串,str_size:数据长度
|
||
* @retval 无
|
||
*/
|
||
// void gps_info(const char *str, int str_size){
|
||
// app_printf("\r\nInfo: ");
|
||
// cm_uart_write(CM_UART_DEV_0, (void*)str, str_size, 1000);
|
||
// }
|
||
|
||
gps_data_t gps_data;
|
||
static nmeaPARSER parser;
|
||
|
||
|
||
//将度分格式转为十进制度
|
||
double dm_to_dd(double dm) {
|
||
int deg = (int)(dm / 100);
|
||
double min = dm - deg * 100;
|
||
return deg + min/60;
|
||
}
|
||
|
||
|
||
/* 串口接收处理任务,平时使用信号量挂起,当收到接收事件后,释放信号量以触发读取任务 */
|
||
static void gps_TaskHandle(void *param){
|
||
int temp_len = 0;
|
||
int it = 0;
|
||
uint8_t gps_flag = 0;
|
||
uint8_t gps_flag_last = 0;
|
||
|
||
/* 设置用于输出调试信息的函数 */
|
||
nmea_property()->trace_func = &trace;
|
||
nmea_property()->error_func = &error;
|
||
// nmea_property()->info_func = &gps_info;
|
||
|
||
gps_data.flow_num =0;
|
||
nmea_zero_INFO(&gps_data.info);
|
||
nmea_parser_init(&parser);
|
||
while(1){
|
||
if(gps_uart_sem != NULL){
|
||
osSemaphoreAcquire(gps_uart_sem, osWaitForever);//阻塞
|
||
}
|
||
temp_len = cm_uart_read(GPS_URAT, (void*)&gps_rev_data[gps_rev_len], GPS_BUF_LEN - gps_rev_len, 1000);
|
||
gps_rev_len += temp_len;
|
||
if(gps_rev_len > 370){
|
||
osMutexAcquire(gps_data.mutex, osWaitForever);
|
||
nmea_parse(&parser, gps_rev_data, gps_rev_len, &gps_data.info);
|
||
gps_data.longitude=dm_to_dd(gps_data.info.lon);
|
||
gps_data.latitude=dm_to_dd(gps_data.info.lat);
|
||
osMutexRelease(gps_data.mutex);
|
||
//nmea_info2pos(&gps_data.info, &gps_data.dpos);
|
||
gps_data.flow_num++;
|
||
DEBUG("%03d,Lat:%.09f,Lon:%.09f,Sig:%d,Fix:%d,RL=%d\n\n",
|
||
it++, gps_data.latitude, gps_data.longitude, gps_data.info.sig, gps_data.info.fix, gps_rev_len
|
||
);
|
||
|
||
if((gps_data.info.fix == 1)||(gps_data.info.sig == 0)){ // 不可用
|
||
gps_flag =0;
|
||
}else{
|
||
gps_flag =1;
|
||
}
|
||
if(gps_flag!= gps_flag_last){ // GPS状态变化
|
||
gps_flag_last = gps_flag;
|
||
if(gps_flag == 1){
|
||
// app_printf("GPS locate success!\n");
|
||
led_set_event(EVENT_GPS_LOCATE_SUCCESS);
|
||
local_tts_text_play("定位成功",0,0);
|
||
}else{
|
||
// app_printf("GPS no locate!\n");
|
||
led_set_event(EVENT_GPS_NO_LOCATE);
|
||
local_tts_text_play("定位信号弱",0,0);
|
||
}
|
||
}
|
||
|
||
memset((void*)gps_rev_data, 0, gps_rev_len);
|
||
temp_len = 0;
|
||
gps_rev_len = 0;
|
||
}
|
||
}
|
||
// nmea_parser_destroy(&parser);
|
||
}
|
||
|
||
// 串口事件回调函数
|
||
static void gps_uart_event_callback(void *param, uint32_t type){
|
||
// uart_event_msg_t msg = {0};
|
||
if (CM_UART_EVENT_TYPE_RX_ARRIVED & type){
|
||
/* 收到接收事件,触发其他线程执行读取数据 */
|
||
osSemaphoreRelease(gps_uart_sem);
|
||
}
|
||
|
||
if (CM_UART_EVENT_TYPE_RX_OVERFLOW & type){
|
||
/* 收到溢出事件,触发其他线程处理溢出事件 */
|
||
osSemaphoreRelease(gps_uart_sem);
|
||
// msg.msg_type = type;
|
||
|
||
// if (uart_event_queue != NULL){//向队列发送数据
|
||
// osMessageQueuePut(uart_event_queue, &msg, 0, 0);
|
||
// }
|
||
}
|
||
}
|
||
|
||
void gps_config_init(void){
|
||
int32_t ret = -1;
|
||
|
||
// 配置引脚复用
|
||
cm_iomux_set_pin_func(GPS_RX_IOMUX);
|
||
cm_iomux_set_pin_func(GPS_TX_IOMUX);
|
||
|
||
cm_iomux_set_pin_cmd(CM_IOMUX_PIN_28, CM_IOMUX_PINCMD3_PULL, CM_IOMUX_PINCMD3_FUNC2_PULL_HIGH);
|
||
// cm_iomux_set_pin_cmd(CM_IOMUX_PIN_29, CM_IOMUX_PINCMD3_PULL, CM_IOMUX_PINCMD3_FUNC2_PULL_HIGH);
|
||
|
||
// 事件参数
|
||
cm_uart_event_t uart_event = {
|
||
CM_UART_EVENT_TYPE_RX_ARRIVED | CM_UART_EVENT_TYPE_RX_OVERFLOW, //注册需要上报的事件类型
|
||
"uart1", //用户参数
|
||
gps_uart_event_callback //上报事件的回调函数
|
||
};
|
||
// 注册事件和回调函数
|
||
ret = cm_uart_register_event(GPS_URAT, &uart_event);
|
||
if(ret != RET_SUCCESS){
|
||
cm_log_printf(0, "uart register event err,ret=%d\n", ret);
|
||
return;
|
||
}
|
||
|
||
// 配置参数
|
||
cm_uart_cfg_t uart_cfg ={
|
||
CM_UART_BYTE_SIZE_8,
|
||
CM_UART_PARITY_NONE,
|
||
CM_UART_STOP_BIT_ONE,
|
||
CM_UART_FLOW_CTRL_NONE,
|
||
CM_UART_BAUDRATE_115200,
|
||
0 //配置为普通串口模式,若要配置为低功耗模式可改为1
|
||
};
|
||
// 开启串口
|
||
ret = cm_uart_open(GPS_URAT, &uart_cfg);
|
||
if(ret != RET_SUCCESS){
|
||
cm_log_printf(0, "uart init err,ret=%d\n", ret);
|
||
return;
|
||
}
|
||
|
||
// 串口接收处理任务
|
||
osThreadAttr_t gps_task_attr = {0};
|
||
gps_task_attr.name = "gps_uart_task";
|
||
gps_task_attr.stack_size = 4096 * 4;
|
||
gps_task_attr.priority= osPriorityNormal;
|
||
|
||
gps_data.mutex = osMutexNew(NULL); // 创建互斥锁
|
||
|
||
GPS_ThreadId= osThreadNew(gps_TaskHandle, 0, &gps_task_attr);
|
||
|
||
if(gps_uart_sem == NULL) {
|
||
gps_uart_sem = osSemaphoreNew(1, 0, NULL);
|
||
}
|
||
|
||
}
|
||
|
||
/* 关闭串口 */
|
||
void gps_config_close(void){
|
||
cm_uart_dev_e dev = GPS_URAT;
|
||
|
||
if(0 == cm_uart_close(dev)){
|
||
DEBUG("uart%d close is ok\n", dev);
|
||
}else{
|
||
DEBUG("uart%d close is error\n", dev);
|
||
}
|
||
}
|
||
|
||
|
||
// 判断闰年(仅针对于2000以后的年份)
|
||
// iYear 两位年数
|
||
// 1:为闰年 0:为平年
|
||
static uint8_t IsLeapYear(uint8_t iYear){
|
||
uint16_t Year;
|
||
Year = 2000 + iYear;
|
||
if ((Year & 3) == 0){
|
||
return ((Year % 400 == 0) || (Year % 100 != 0));
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
// 格林尼治时间换算世界各时区时间
|
||
// *DT: 表示日期时间的数组 格式 YY,MM,DD,HH,MM,SS
|
||
// GMT: 时区数
|
||
// AREA: 1(+)东区 W0(-)西区
|
||
void GMTconvert(nmeaTIME *SourceTime, nmeaTIME *ConvertTime, uint8_t GMT, uint8_t AREA){
|
||
uint32_t YY, MM, DD, hh, mm, ss; // 年月日时分秒暂存变量
|
||
|
||
if (GMT == 0)
|
||
return; // 如果处于0时区直接返回
|
||
if (GMT > 12)
|
||
return; // 时区最大为12 超过则返回
|
||
|
||
YY = SourceTime->year; // 获取年
|
||
MM = SourceTime->mon; // 获取月
|
||
DD = SourceTime->day; // 获取日
|
||
hh = SourceTime->hour; // 获取时
|
||
mm = SourceTime->min; // 获取分
|
||
ss = SourceTime->sec; // 获取秒
|
||
|
||
if(AREA){ // 东(+)时区处理
|
||
if(hh + GMT < 24){
|
||
hh += GMT; // 如果与格林尼治时间处于同一天则仅加小时即可
|
||
}else{ // 如果已经晚于格林尼治时间1天则进行日期处理
|
||
hh = hh + GMT - 24; // 先得出时间
|
||
if(MM == 1 || MM == 3 || MM == 5 || MM == 7 || MM == 8 || MM == 10){ // 大月份(12月单独处理)
|
||
if(DD < 31){
|
||
DD++;
|
||
}else{
|
||
DD = 1;
|
||
MM++;
|
||
}
|
||
}else if(MM == 4 || MM == 6 || MM == 9 || MM == 11){ // 小月份2月单独处理)
|
||
if(DD < 30){
|
||
DD++;
|
||
}else{
|
||
DD = 1;
|
||
MM++;
|
||
}
|
||
}else if (MM == 2){ // 处理2月份
|
||
if((DD == 29) || (DD == 28 && IsLeapYear(YY) == 0)){ // 本来是闰年且是2月29日 或者不是闰年且是2月28日
|
||
DD = 1;
|
||
MM++;
|
||
}else{
|
||
DD++;
|
||
}
|
||
}else if (MM == 12){ // 处理12月份
|
||
if (DD < 31){
|
||
DD++;
|
||
}else{ // 跨年最后一天
|
||
DD = 1;
|
||
MM = 1;
|
||
YY++;
|
||
}
|
||
}
|
||
}
|
||
}else{
|
||
if(hh >= GMT){
|
||
hh -= GMT; // 如果与格林尼治时间处于同一天则仅减小时即可
|
||
}else{ // 如果已经早于格林尼治时间1天则进行日期处理
|
||
hh = hh + 24 - GMT; // 先得出时间
|
||
if(MM == 2 || MM == 4 || MM == 6 || MM == 8 || MM == 9 || MM == 11){ // 上月是大月份(1月单独处理)
|
||
if(DD > 1){
|
||
DD--;
|
||
}else{
|
||
DD = 31;
|
||
MM--;
|
||
}
|
||
}else if(MM == 5 || MM == 7 || MM == 10 || MM == 12){ // 上月是小月份2月单独处理)
|
||
if(DD > 1){
|
||
DD--;
|
||
}else{
|
||
DD = 30;
|
||
MM--;
|
||
}
|
||
}else if(MM == 3){ // 处理上个月是2月份
|
||
if((DD == 1) && IsLeapYear(YY) == 0){ // 不是闰年
|
||
DD = 28;
|
||
MM--;
|
||
}else{
|
||
DD--;
|
||
}
|
||
}else if(MM == 1){ // 处理1月份
|
||
if(DD > 1){
|
||
DD--;
|
||
}else{ // 新年第一天
|
||
DD = 31;
|
||
MM = 12;
|
||
YY--;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
ConvertTime->year = YY; // 更新年
|
||
ConvertTime->mon = MM; // 更新月
|
||
ConvertTime->day = DD; // 更新日
|
||
ConvertTime->hour = hh; // 更新时
|
||
ConvertTime->min = mm; // 更新分
|
||
ConvertTime->sec = ss; // 更新秒
|
||
}
|
||
|