#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; // 更新秒 }