diff --git a/custom/GPS/inc/gps_config.h b/custom/GPS/inc/gps_config.h index 401337c..3fa8563 100644 --- a/custom/GPS/inc/gps_config.h +++ b/custom/GPS/inc/gps_config.h @@ -3,9 +3,19 @@ #include "cm_os.h" #include "nmea/nmea.h" +typedef struct{ + uint16_t flow_num; // 流水号 + nmeaINFO info; // GPS信息 + nmeaPOS dpos; // 经纬度 +} gps_data_t; + +extern gps_data_t gps_data; + void gps_config_init(void); /* 关闭串口 */ void gps_config_close(void); +void GMTconvert(nmeaTIME *SourceTime, nmeaTIME *ConvertTime, uint8_t GMT, uint8_t AREA); + #endif /* GPS_CONFIG_H */ \ No newline at end of file diff --git a/custom/GPS/src/gps_config.c b/custom/GPS/src/gps_config.c index 9bff314..7ec3e18 100644 --- a/custom/GPS/src/gps_config.c +++ b/custom/GPS/src/gps_config.c @@ -26,54 +26,79 @@ static osThreadId_t GPS_ThreadId = NULL; //串口数据接收、解析任务Hand 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: "); + // cm_uart_write(CM_UART_DEV_0, (void*)str, str_size, 1000); +} + +/** + * @brief error 在解码出错时输出提示消息 + * @param str: 要输出的字符串,str_size:数据长度 + * @retval 无 + */ +void error(const char *str, int str_size){ + // app_printf("\r\nError: "); + // cm_uart_write(CM_UART_DEV_0, (void*)str, str_size, 1000); +} + +/** + * @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; + /* 串口接收处理任务,平时使用信号量挂起,当收到接收事件后,释放信号量以触发读取任务 */ static void gps_TaskHandle(void *param){ int temp_len = 0; int it = 0; - // nmeaPOS dpos; - nmeaINFO info; - nmeaPARSER parser; - nmea_zero_INFO(&info); + /* 设置用于输出调试信息的函数 */ + 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, 1000); - if(temp_len > 0){ - - nmea_parse(&parser, gps_rev_data, temp_len, &info); - // nmea_info2pos(&info, &dpos); - - // app_printf( - // "%03d, Lat: %f, Lon: %f, Sig: %d, Fix: %d, RL= %d\n", - // it++, dpos.lat, dpos.lon, info.sig, info.fix, temp_len - // ); + gps_rev_len += temp_len; + if(gps_rev_len > 480){ + nmea_parse(&parser, gps_rev_data, gps_rev_len, &gps_data.info); + nmea_info2pos(&gps_data.info, &gps_data.dpos); + gps_data.flow_num++; app_printf( - "%03d, Lat: %f, Lon: %f, Sig: %d, Fix: %d, RL= %d\n", - it++, info.lat, info.lon, info.sig, info.fix, temp_len + "\nGPS:%03d,Lat:%.02f,Lon:%.02f,Sig:%d,Fix:%d,RL=%d\n", + it++, gps_data.info.lat, gps_data.info.lon, gps_data.info.sig, gps_data.info.fix, gps_rev_len ); - // cm_uart_write(CM_UART_DEV_0, gps_rev_data, temp_len, 1000); - memset((void*)gps_rev_data, 0, temp_len); + + if((gps_data.info.fix == 1)||(gps_data.info.sig == 0)){ // 不可用 + // app_printf("GPS no locate!\n"); + led_set_event(EVENT_GPS_NO_LOCATE); + }else{ + // app_printf("GPS locate success!\n"); + led_set_event(EVENT_GPS_LOCATE_SUCCESS); + } + + memset((void*)gps_rev_data, 0, gps_rev_len); temp_len = 0; gps_rev_len = 0; } - // temp_len = cm_uart_read(GPS_URAT, (void*)&gps_rev_data[gps_rev_len], GPS_BUF_LEN - gps_rev_len, 1000); - // if(gps_rev_len < GPS_BUF_LEN){ - // gps_rev_len += temp_len; - // }else{ - // gps_rev_len = 0; - // } - // app_printf("uart rev data len = %d\n", gps_rev_len); - - // if (gps_uart_sem != NULL && (strstr(gps_rev_data, "\r\n"))){ - // //处理收到数据事件 - // cm_uart_write(GPS_URAT, gps_rev_data, gps_rev_len, 1000); - - // memset((void*)gps_rev_data, 0, sizeof(gps_rev_data)); - // gps_rev_len = 0; - // } } // nmea_parser_destroy(&parser); } @@ -138,10 +163,10 @@ void gps_config_init(void){ // 串口接收处理任务 osThreadAttr_t gps_task_attr = {0}; gps_task_attr.name = "gps_uart_task"; - gps_task_attr.stack_size = 2048; + gps_task_attr.stack_size = 4096 * 4; gps_task_attr.priority= osPriorityNormal; - GPS_ThreadId= osThreadNew(gps_TaskHandle, 0, &gps_task_attr); + GPS_ThreadId= osThreadNew(gps_TaskHandle, 0, &gps_task_attr); if(gps_uart_sem == NULL) { gps_uart_sem = osSemaphoreNew(1, 0, NULL); @@ -161,3 +186,115 @@ void gps_config_close(void){ } +// 判断闰年(仅针对于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; // 更新秒 +} + diff --git a/custom/adc_dac/adc_dac.mk b/custom/adc_dac/adc_dac.mk new file mode 100644 index 0000000..789c4de --- /dev/null +++ b/custom/adc_dac/adc_dac.mk @@ -0,0 +1,6 @@ + +CUSTOM_MAIN_DIR := custom/adc_dac + +OC_FILES += $(CUSTOM_MAIN_DIR)/src/adc_dac.c + +INC += -I'$(CUSTOM_MAIN_DIR)/inc' \ No newline at end of file diff --git a/custom/adc_dac/inc/adc_dac.h b/custom/adc_dac/inc/adc_dac.h new file mode 100644 index 0000000..3c751b8 --- /dev/null +++ b/custom/adc_dac/inc/adc_dac.h @@ -0,0 +1,8 @@ +#ifndef __ADC_DAC_H__ +#define __ADC_DAC_H__ +#include "cm_os.h" + + +void adc_dac_init(void); + +#endif //__ADC_DAC_H__ \ No newline at end of file diff --git a/custom/adc_dac/src/adc_dac.c b/custom/adc_dac/src/adc_dac.c new file mode 100644 index 0000000..20a2532 --- /dev/null +++ b/custom/adc_dac/src/adc_dac.c @@ -0,0 +1,81 @@ +#include "adc_dac.h" +#include +#include "cm_adc.h" +#include "cm_gpio.h" +#include "cm_iomux.h" +#include "cm_pwm.h" + +#define ADC_DAC_DEBUG_ENABLE 1 + +#if ADC_DAC_DEBUG_ENABLE +#include "app_uart.h" +#define DEBUG(fmt, args...) app_printf("[ADC]" fmt, ##args) +#else +#define DEBUG(fmt, arg...) +#endif + +#define PWM0_IOMUX CM_IOMUX_PIN_74, CM_IOMUX_FUNC_FUNCTION1 +#define PWM1_IOMUX CM_IOMUX_PIN_75, CM_IOMUX_FUNC_FUNCTION1 +#define PWM2_IOMUX CM_IOMUX_PIN_21, CM_IOMUX_FUNC_FUNCTION2 +#define PWM3_IOMUX 0, 0 + +osThreadId_t adc_dac_TaskHandle = NULL; + +typedef enum { + ADC_power = 0, + ADC_acc = 1, +}adc_chx_t; + +int32_t get_voltage(adc_chx_t chx){ + int32_t voltage = 0; + if(chx == ADC_acc){ + cm_gpio_set_level(CM_GPIO_NUM_20, 1); + }else if(chx == ADC_power){ + cm_gpio_set_level(CM_GPIO_NUM_20, 0); + }else{ + return 0; + } + osDelay(1);//5ms + if(0 != cm_adc_read(CM_ADC_0,&voltage)){ + DEBUG("ADC read fail\r\n"); + voltage = 0; + } + // cm_gpio_set_level(CM_GPIO_NUM_20, 1); //恢复默认状态 + return voltage; +} + +void adc_dac_task(void *argument){ + while(1){ + DEBUG("ADC_acc:%d\r\n",get_voltage(ADC_acc)); + DEBUG("ADC_power:%d\r\n\n",get_voltage(ADC_power)); + osDelay(500/5); + } +} + +void adc_dac_init(void){ + cm_gpio_cfg_t cfg = {0}; + cfg.direction = CM_GPIO_DIRECTION_OUTPUT; + cfg.pull = CM_GPIO_PULL_UP; + cm_iomux_set_pin_func(CM_IOMUX_PIN_86, CM_IOMUX_FUNC_FUNCTION2);//初始化之前一定要先设置引脚复用 + cm_gpio_init(CM_GPIO_NUM_20, &cfg); + cm_gpio_set_level(CM_GPIO_NUM_20, 1); + + // pwm init + cm_iomux_set_pin_func(PWM0_IOMUX); + if(0 != cm_pwm_set_clk(CM_PWM_DEV_0, CM_PWM_CLK_12800K)){//时钟源选择需要放在open之前 + DEBUG("pwm0 set clk fail\r\n"); + return; + } + + if(0 != cm_pwm_open_ns(CM_PWM_DEV_0, 100000,30000)){ //设置频率为10KHz,占空比为30% + DEBUG("pwm0 open error\n"); + } + + osThreadAttr_t adc_dac_task_attr = {0}; + adc_dac_task_attr.name = "adc_dac_task"; + adc_dac_task_attr.stack_size = 1024; + adc_dac_task_attr.priority = osPriorityNormal; + + adc_dac_TaskHandle = osThreadNew((osThreadFunc_t)adc_dac_task,0,&adc_dac_task_attr); +} + diff --git a/custom/custom.mk b/custom/custom.mk index ecf35ce..be8b3bf 100644 --- a/custom/custom.mk +++ b/custom/custom.mk @@ -7,4 +7,7 @@ include $(CUSTOM_DIR)/custom_main/custom_main.mk include $(CUSTOM_DIR)/nmealib/nmealib.mk include $(CUSTOM_DIR)/GPS/gps.mk include $(CUSTOM_DIR)/jt808/jt808.mk +include $(CUSTOM_DIR)/tcp_client/tcp_client.mk +include $(CUSTOM_DIR)/adc_dac/adc_dac.mk +include $(CUSTOM_DIR)/local_tts/local_tts.mk endif \ No newline at end of file diff --git a/custom/custom_main/inc/app_common.h b/custom/custom_main/inc/app_common.h index e35354e..f89b09a 100644 --- a/custom/custom_main/inc/app_common.h +++ b/custom/custom_main/inc/app_common.h @@ -43,8 +43,24 @@ typedef enum{ RET_SUCCESS = 0 }CM_RET_E; +typedef enum{ + EVENT_NETWORK_READY = 0x00000001, + EVENT_NETWORK_DISCONNECT = 0x00000002, + EVENT_GPS_LOCATE_SUCCESS = 0x00000004, + EVENT_GPS_NO_LOCATE = 0x00000008, + EVENT_ERROR = 0x80000000, +}led_event_t; +typedef union{ + struct{ + uint8_t network_ready : 1; + uint8_t gps_ready : 1; + uint8_t reserved : 6; + }; + uint32_t val8; +}led_status_t; +void led_set_event(led_event_t event); #endif /* __APP_COMMON_H__ */ diff --git a/custom/custom_main/src/custom_main.c b/custom/custom_main/src/custom_main.c index c39df77..efa6444 100644 --- a/custom/custom_main/src/custom_main.c +++ b/custom/custom_main/src/custom_main.c @@ -12,100 +12,292 @@ #include "cm_rtc.h" #include "cm_gpio.h" #include "cm_iomux.h" -// #include "cm_demo_i2c.h" -// #include "cm_demo_adc.h" -// #include "cm_demo_spi.h" -// #include "cm_demo_lcd.h" -// #include "cm_demo_gpio.h" -// #include "cm_demo_keypad.h" -// #include "cm_demo_pwm.h" -// #include "cm_demo_pm.h" -// #include "cm_demo_http.h" -// #include "cm_demo_mqtt.h" -// #include "cm_demo_ntp.h" -// #include "cm_demo_fota.h" -// #include "cm_demo_audio.h" -// #include "cm_demo_virt_at.h" -// #include "cm_demo_lbs.h" -// #include "cm_demo_tts.h" -// #include "cm_modem.h" -// #include "cm_demo_cJSON.h" -// #include "cm_demo_sd.h" -// #include "cm_demo_gnss.h" -// #include "cm_demo_aliyun.h" -// #include "cm_demo_wifiscan.h" -// #include "cm_demo_camera.h" -// #include "cm_demo_ftp.h" -// #include "cm_demo_lwip.h" -// #include "cm_demo_ssl.h" +#include "cm_modem.h" #include "app_uart.h" #include "gps_config.h" -#include "client_manager.h" -#include "jt808_packager.h" +#include "app_common.h" + +#include "jt808_msg_pkg.h" +#include "jt808_msg_parse.h" +#include "jt808_pkg_transmit.h" +#include "tcp_client.h" + +#include "local_tts.h" + +#define SECOND_OF_DAY (24*60*60) + +typedef struct cm_tm { + int tm_sec; /* 秒 – 取值区间为[0,59] */ + int tm_min; /* 分 - 取值区间为[0,59] */ + int tm_hour; /* 时 - 取值区间为[0,23] */ + int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */ + int tm_mon; /* 月份 */ + int tm_year; /* 年份 */ +}cm_tm_t; + +// static const char * weekday[] = {"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"}; +// static const char DayOfMon[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; + osThreadId_t OC_APP_TaskHandle; + +// void oc_ring_cb(unsigned char *param) +// { +// if(0 == strncmp((char *)param, "\r\nRING",6))//来电提示 +// { +// app_printf("oc_ring_cb:%s\n",param); +// } +// else if (0 == strncmp((char *)param, "\r\n+CLCC:",8)) //来电信息 +// { +// app_printf("oc_ring_cb:%s\n",param); +// } +// else if(0 == strncmp((char *)param, "\r\nNO CARRIER",12))//对方挂断 +// { +// app_printf("oc_ring_cb:%s\n",param); +// } +// if (0 == strncmp((char *)param, "\r\n+CMTI:",8))//短信信息 +// { +// app_printf("message:%s\n",param); +// } + +// } + + +// static void cm_sec_to_date(long lSec, cm_tm_t *tTime) +// { +// unsigned short i,j,iDay; +// unsigned long lDay; + +// lDay = lSec / SECOND_OF_DAY; +// lSec = lSec % SECOND_OF_DAY; + +// i = 1970; +// while(lDay > 365) +// { +// if(((i%4==0)&&(i%100!=0)) || (i%400==0)) +// { +// lDay -= 366; +// } +// else +// { +// lDay -= 365; +// } +// i++; +// } +// if((lDay == 365) && !(((i%4==0)&&(i%100!=0)) || (i%400==0))) +// { +// lDay -= 365; +// i++; +// } +// tTime->tm_year = i; +// for(j=0;j<12;j++) +// { +// if((j==1) && (((i%4==0)&&(i%100!=0)) || (i%400==0))) +// { +// iDay = 29; +// } +// else +// { +// iDay = DayOfMon[j]; +// } +// if(lDay >= iDay) lDay -= iDay; +// else break; +// } +// tTime->tm_mon = j+1; +// tTime->tm_mday = lDay+1; +// tTime->tm_hour = ((lSec / 3600))%24;//这里注意,世界时间已经加上北京时间差8, +// tTime->tm_min = (lSec % 3600) / 60; +// tTime->tm_sec = (lSec % 3600) % 60; +// } + +// static uint8_t cm_time_to_weekday(cm_tm_t *t) +// { +// uint32_t u32WeekDay = 0; +// uint32_t u32Year = t->tm_year; +// uint8_t u8Month = t->tm_mon; +// uint8_t u8Day = t->tm_mday; +// if(u8Month < 3U) +// { +// /*D = { [(23 x month) / 9] + day + 4 + year + [(year - 1) / 4] - [(year - 1) / 100] + [(year - 1) / 400] } mod 7*/ +// u32WeekDay = (((23U * u8Month) / 9U) + u8Day + 4U + u32Year + ((u32Year - 1U) / 4U) - ((u32Year - 1U) / 100U) + ((u32Year - 1U) / 400U)) % 7U; +// } +// else +// { +// /*D = { [(23 x month) / 9] + day + 4 + year + [year / 4] - [year / 100] + [year / 400] - 2 } mod 7*/ +// u32WeekDay = (((23U * u8Month) / 9U) + u8Day + 4U + u32Year + (u32Year / 4U) - (u32Year / 100U) + (u32Year / 400U) - 2U ) % 7U; +// } + +// if (0U == u32WeekDay) +// { +// u32WeekDay = 7U; +// } + +// return (uint8_t)u32WeekDay; +// } + + +void print_network_info(void){ + cm_cereg_state_t cereg_state = {0}; + + if(0 == cm_modem_get_cpin()){ + app_printf("sim card ready!\r\n\n"); + }else{ + app_printf("sim card not ready!\r\n\n"); + } + if(0 ==cm_modem_get_cereg_state(&cereg_state)){ // 获取PS网络注册状态 + app_printf("cereg_state:%d\n",cereg_state.state); // 注册状态 + }else{ + app_printf("cereg_get_state fail!\n\n"); + } + if(cm_modem_get_pdp_state(1) == 1){ //网络就绪 + app_printf("network ready\n"); + }else{ + app_printf("waiting for network...\n"); + } +} + + +led_status_t led_status = {0}; +osEventFlagsId_t LED_EventFlags = NULL; + void my_appimg_enter(char *param){ - int isRegistered=0; - int isAuthenticated=0; - unsigned int v_alarm_value = 0; - unsigned int v_status_value = 0; + LED_EventFlags =osEventFlagsNew(NULL); + if(NULL == LED_EventFlags){ + app_printf("LED_EventFlags create fail\n"); + // return; + } cm_gpio_cfg_t cfg = {0}; - cfg.direction = CM_GPIO_DIRECTION_OUTPUT; cfg.pull = CM_GPIO_PULL_UP; - cm_iomux_set_pin_func(CM_IOMUX_PIN_16, CM_IOMUX_FUNC_FUNCTION1);//初始化之前一定要先设置引脚复用 - - cm_gpio_init(0, &cfg); - cm_gpio_set_level(0, 1); + cm_gpio_init(CM_GPIO_NUM_0, &cfg); + cm_gpio_set_level(CM_GPIO_NUM_0, 0); + + // cm_iomux_set_pin_func(CM_IOMUX_PIN_77, CM_IOMUX_FUNC_FUNCTION2);//初始化之前一定要先设置引脚复用 + // cm_gpio_init(CM_GPIO_NUM_13, &cfg); + // cm_gpio_set_level(CM_GPIO_NUM_13, 0); app_uart_init(); - gps_config_init(); app_printf("Hello, world!\r\n"); - initSystemParameters(0); - //设置手机号(唯一识别id) - setUUID(); - //终端注册 - if(isRegistered == 0){ - jt808TerminalRegister(&isRegistered); - if(isRegistered==0){ - // system_reboot(); - // continue; - } + // adc_dac_init(); + local_tts_init(); + + local_tts_mute(0);// 取消静音 + local_tts_volume(10); // 设置音量为5 + local_tts_set(8, 15, CM_LOCAL_TTS_DIGIT_AUTO); + + while(1){ + + cm_gpio_set_level(CM_GPIO_NUM_0, 1); + local_tts_text_play("欢迎使用莱昂特智能终端设备...。",0 ,osWaitForever); // 0:表示自动计算字符串长度,10000表示最大等待时间 + // osDelay(3000/5); + cm_gpio_set_level(CM_GPIO_NUM_0, 0); + // osDelay(3000/5); + local_tts_text_play("欢迎使用游园猫,您的专属智能向导。",0 ,osWaitForever); // 0:表示自动计算字符串长度,10000表示最大等待时间 } - //终端鉴权 - if(isAuthenticated == 0){ - jt808TerminalAuthentication(&isAuthenticated); - if(isAuthenticated==0){ - // system_reboot(); - // continue; - } - } - - //设置位置上报警报位、状态位 - initLocationInfo(v_alarm_value, v_status_value); - setStatusBit(); +//-------------------------------------------- +{ + // cm_tm_t t; + // int i; + int ret; + char buf[CM_VER_LEN] = {0}; + int pdp_time_out=0; + cm_fs_system_info_t info = {0, 0}; + cm_heap_stats_t stats = {0}; + app_printf("\n\n\n\n\n"); + app_printf("CM OpenCPU Starts\n"); + cm_sys_get_cm_ver(buf, CM_VER_LEN); + app_printf("SDK VERSION:%s\n", buf); + cm_fs_getinfo(&info); + cm_mem_get_heap_stats(&stats); + app_printf("fs total:%d,remain:%d\n", info.total_size, info.free_size); + app_printf("heap total:%d,remain:%d\n",stats.total_size,stats.free); + + // app_printf("waiting for network...\n"); + // while(1){ + // if(pdp_time_out>10){ + // app_printf("network timeout\n"); + // break; + // } + // if(cm_modem_get_pdp_state(1) == 1){ + // app_printf("network ready\n"); + // break; + // } + // osDelay(200); + // pdp_time_out++; + // } + +} +// ----------------------------------------------------- + jt808_set_term_param_init(); + jt808_init(); + tcp_client_init(); + gps_config_init(); + + uint32_t led_event = 0; while(1){ - osDelay(200/5);//300ms - cm_gpio_set_level(0, 1); - osDelay(200/5);//300ms - cm_gpio_set_level(0, 0); - // app_printf("Hello, world!\r\n"); + led_event = osEventFlagsWait(LED_EventFlags, 0x0000000f, osFlagsWaitAny, 0); //0等待 + if (led_event & 0x80000000) { // 错误处理 + // app_printf("led task error\n"); + }else if(led_event & EVENT_NETWORK_READY){ // 网络就绪 + app_printf("led network ready\n"); + led_status.network_ready = 1; + }else if(led_event & EVENT_NETWORK_DISCONNECT){ // 网络断开 + app_printf("led network disconnect\n"); + led_status.network_ready = 0; + }else if(led_event & EVENT_GPS_LOCATE_SUCCESS){ // GPS定位成功 + app_printf("led GPS locate success\n"); + led_status.gps_ready = 1; + }else if(led_event & EVENT_GPS_NO_LOCATE){ // GPS无定位 + app_printf("led GPS no locate\n"); + led_status.gps_ready = 0; + } + + if(led_status.network_ready && led_status.gps_ready){ // 网络就绪,GPS定位成功 + cm_gpio_set_level(CM_GPIO_NUM_0, 1); // 常亮 + osDelay(1000/5);//300ms + }else if(led_status.network_ready && (0 ==led_status.gps_ready)){ // 网络就绪,GPS无定位 + cm_gpio_set_level(CM_GPIO_NUM_0, 1); + osDelay(500/5);//300ms + cm_gpio_set_level(CM_GPIO_NUM_0, 0); + osDelay(500/5);//300ms + }else if((0 ==led_status.network_ready) && led_status.gps_ready){ // 网络断开,GPS定位成功 + for(int i=0;i<5;i++){ // 快闪500ms,灭500ms + cm_gpio_set_level(CM_GPIO_NUM_0, 1); + osDelay(100/5);//300ms + cm_gpio_set_level(CM_GPIO_NUM_0, 0); + osDelay(100/5);//300ms + } + cm_gpio_set_level(CM_GPIO_NUM_0, 0); + osDelay(500/5);//300ms + }else{ // 网络断开,GPS无定位 + cm_gpio_set_level(CM_GPIO_NUM_0, 1); // 快闪 + osDelay(100/5);//300ms + cm_gpio_set_level(CM_GPIO_NUM_0, 0); + osDelay(100/5);//300ms + } } } +void led_set_event(led_event_t event){ + if(NULL == LED_EventFlags){ + app_printf("LED_EventFlags is NULL\n"); + return; + } + osEventFlagsSet(LED_EventFlags, event); +} + int cm_opencpu_entry(char * param) { osThreadAttr_t app_task_attr = {0}; app_task_attr.name = "main_task"; - app_task_attr.stack_size = 4096 * 2; + app_task_attr.stack_size = 4096 * 4; app_task_attr.priority = osPriorityNormal; OC_APP_TaskHandle = osThreadNew((osThreadFunc_t)my_appimg_enter,0,&app_task_attr); - return 0; return 0; } diff --git a/custom/jt808/inc/jt808_config.h b/custom/jt808/inc/jt808_config.h new file mode 100644 index 0000000..70e6a95 --- /dev/null +++ b/custom/jt808/inc/jt808_config.h @@ -0,0 +1,24 @@ +#ifndef _JT808_CONFIG_H_ +#define _JT808_CONFIG_H_ +#include +#include +#include +#include +#include "jt808_util.h" + +#define JT808_DEBUG_ENABLE 1 + +#if JT808_DEBUG_ENABLE +#include "app_uart.h" +#define JT808_DEBUG(fmt, args...) app_printf("[JT808]" fmt, ##args) +#else +#define JT808_DEBUG(fmt, arg...) +#endif + + +#include "cm_mem.h" +#define jt808_malloc(size) cm_malloc(size) +#define jt808_realloc(ptr, size) cm_realloc(ptr, size) +#define jt808_free(ptr) cm_free(ptr) + +#endif \ No newline at end of file diff --git a/custom/jt808/inc/jt808_debug.h b/custom/jt808/inc/jt808_debug.h deleted file mode 100644 index 561d454..0000000 --- a/custom/jt808/inc/jt808_debug.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _JT808_DEBUG_H_ -#define _JT808_DEBUG_H_ - -#define JT808_DEBUG_ENABLE 1 - -#if JT808_DEBUG_ENABLE -#include "app_uart.h" -#define JT808_DEBUG(fmt, args...) app_printf("[JT808]" fmt, ##args) -#else -#define JT808_DEBUG(fmt, arg...) -#endif - -#endif \ No newline at end of file diff --git a/custom/jt808/inc/jt808_msg_parse.h b/custom/jt808/inc/jt808_msg_parse.h new file mode 100644 index 0000000..80b31f2 --- /dev/null +++ b/custom/jt808/inc/jt808_msg_parse.h @@ -0,0 +1,25 @@ + + +#ifndef __JT808_PKG_PARSE__ +#define __JT808_PKG_PARSE__ +#include "jt808_protocol.h" +#include "jt808_set_TermParam.h" +#include "jt808_config.h" + +#pragma pack(1) +// 解析结果以及终端参数项 +typedef struct{ + uint16_t Rsp_flow_num; //应答流水号 + uint16_t Rsp_msg_id; // 应答消息ID + uint8_t Rsp_result; // 应答结果 + MsgHead_t msg_head; // 解析的消息头 + Term_Param_item_t *term_param_item; // 终端参数项 +}PrsResult_t; +#pragma pack() + +// ------------------------------- 全局变量声明 ---------- +extern PrsResult_t PrsResult; // 解析结果以及终端参数项 + +int jt808_msg_parse(const uint8_t *BufferReceive, uint16_t length, PrsResult_t *PrsResult); + +#endif // __JT808_PKG_PARSE__ diff --git a/custom/jt808/inc/jt808_msg_pkg.h b/custom/jt808/inc/jt808_msg_pkg.h new file mode 100644 index 0000000..5089fdc --- /dev/null +++ b/custom/jt808/inc/jt808_msg_pkg.h @@ -0,0 +1,14 @@ +#ifndef __JT808_PKG_PKG__ +#define __JT808_PKG_PKG__ +#include "jt808_protocol.h" +#include "jt808_config.h" + +typedef struct { + uint8_t *buf; // 打包后的消息帧 + uint16_t len; // 打包后的消息帧长度 +} JT808MsgESC_t; + +// 消息帧打包 (会自动为msgEscape->buf分配合适长度的内存,注意释放) +int jt808_msg_pkg(MessageID_t Msg_ID, JT808MsgESC_t *msgEscape); + +#endif // __JT808_PKG_PKG__ diff --git a/custom/jt808/inc/jt808_pkg_transmit.h b/custom/jt808/inc/jt808_pkg_transmit.h new file mode 100644 index 0000000..0cae177 --- /dev/null +++ b/custom/jt808/inc/jt808_pkg_transmit.h @@ -0,0 +1,33 @@ +#ifndef _JT808_PKG_TRANSMIT_H_ +#define _JT808_PKG_TRANSMIT_H_ +#include "jt808_msg_pkg.h" +#include "jt808_msg_parse.h" +#include "jt808_config.h" +#include "tcp_client.h" + +// #pragma pack(1) +typedef struct{ + uint16_t msg_id; + uint32_t timeout; //超时时间,单位ms +}pkg_msg_t; +// #pragma pack() + +// 原型 :int tcp_client_send(const char *buf, int len); +#ifdef __TCP_CLIENT_H__ +#define PKG_SEND(__buf, __len) tcp_client_send(__buf, __len) +#else +#define PKG_SEND(__buf, __len) 0 +#endif + +extern PrsResult_t PrsResult; + +// 触发消息发送 +int jt808_pkg_send(MessageID_t Msg_ID, uint32_t timeout); + +// 接收处理 (放入TCP接收回调中) +void jt808_pkg_handle(uint8_t *receive_buf, uint16_t receive_len); + +// jt808协议初始化 +int jt808_init(void); + +#endif // _JT808_PKG_TRANSMIT_H_ \ No newline at end of file diff --git a/custom/jt808/inc/jt808_protocol.h b/custom/jt808/inc/jt808_protocol.h new file mode 100644 index 0000000..a576d80 --- /dev/null +++ b/custom/jt808/inc/jt808_protocol.h @@ -0,0 +1,331 @@ +#ifndef __JT808_PROTOCOL__ +#define __JT808_PROTOCOL__ +#include "jt808_config.h" + +// 已支持的消息ID +typedef enum { + ID_Term_GenResp = 0x0001, // 终端通用应答 + ID_Plat_GenResp = 0x8001, // 平台通用应答 + ID_Term_HB = 0x0002, // 终端心跳 + ID_FillPktReq = 0x8003, // 补传分包请求 + ID_Term_Reg = 0x0100, // 终端注册 + ID_Term_RegResp = 0x8100, // 终端注册应答 + ID_Term_Logout = 0x0003, // 终端注销 + ID_Term_Auth = 0x0102, // 终端鉴权 + ID_SetTermParams = 0x8103, // 设置终端参数 + ID_GetTermParams = 0x8104, // 查询终端参数 + ID_GetTermParamsResp = 0x0104, // 查询终端参数应答 + ID_Term_Ctrl = 0x8105, // 终端控制 + ID_GetSpecificTermParams = 0x8106,// 查询指定终端参数 + ID_GetTermAttr = 0x8107, // 查询终端属性 + ID_GetTermAttrResp = 0x0107, // 查询终端属性应答 + ID_Term_Upgrade = 0x8108, // 下发终端升级包 + ID_Term_UpgradeResult = 0x0108, // 终端升级结果通知 + ID_LocReport = 0x0200, // 位置信息汇报 + ID_GetLocInfo = 0x8201, // 位置信息查询 + ID_GetLocInfoResp = 0x0201, // 位置信息查询应答 + ID_LocTrackingCtrl = 0x8202, // 临时位置跟踪控制 + ID_TxtMsgdelivery = 0x8300, // 文本信息下发 + ID_Car_Ctrl = 0x8500, // 车辆控制 + ID_Car_CtrlResp = 0x0500, // 车辆控制应答 +} MessageID_t; + +#pragma pack(1) +// ----------------------------- 协议消息体结构体定义 ---------- +// 终端通用应答体(0x0001) +typedef struct { + uint16_t msg_flow_num; // 对应的平台消息的流水号 + uint16_t msg_id_ack; // 对应的平台消息的 ID + uint8_t result; // 结果 0:成功/确认;1:失败;2:消息有误;3:不支持 +}Term_GenResp_t; + +// 平台通用应答体(0x8001) +typedef struct { + uint16_t msg_flow_num; // 对应的终端消息的流水号 + uint16_t msg_id_ack; // 对应的终端消息的 ID + uint8_t result; // 结果 0:成功/确认;1:失败;2:消息有误;3:不支持 +}Plat_GenResp_t; + +// 终端心跳体(0x0002空包) + +// 补传分包请求体(0x8003) +typedef struct { + uint16_t msg_flow_num; // 对应要求补传的原始消息第一包的消息流水号 + uint8_t Total_num; // 重传包总数 + uint16_t *pkt_seq; // 重传包序号顺序排列,如“包 ID1 包 ID2包 IDn”。 +}FillPktReq_t; + +typedef enum { + none_plate = 0, // 无牌照 + blue_plate = 1, // 蓝牌 + yellow_plate = 2, // 黄牌 + black_plate = 3, // 黑牌 + white_plate = 4, // 白牌 + green_plate = 5, // 绿牌 + other_plate = 6, // 其他牌照 +}plate_type_t; +// 终端注册体(0x0100) +typedef struct { + uint16_t province_id;// 省域ID + uint16_t city_id;// 市县域ID + uint8_t manufacturer_id[5];// 制造商ID, 固定5个字节 + uint8_t term_model[20];// 终端型号, 固定20个字节, 位数不足后补0x00 + uint8_t term_id[7];// 终端ID, 固定7个字节, 位数不足后补0x00 + uint8_t car_plate_color;// 车牌颜色, 0表示未上牌 + uint8_t car_plate_num[10];// 车辆标识, 仅在上牌时使用 +}Term_RegInfo_t; + +// 终端注册应答体(0x8100) +typedef struct { + uint16_t msg_flow_num; // 对应的终端注册消息的流水号 + uint8_t result; // 0:成功;1:车辆已被注册;2:数据库中无该车辆;3:终端已被注册;4:数据库中无该终端 + // uint8_t *str_auth_code; //只有在成功后才有该字段 +}Term_RegResp_t; + +// 终端注销体(0x0003空包) + +// 终端鉴权体(0x0102) +typedef struct { + void *str_auth_code; //只有在成功后才有该字段 +}Term_Auth_t; + +// 终端参数项数据结构体 +typedef struct TermParamlist_t{ + uint32_t param_id; // 参数ID + uint8_t param_len; // 参数长度 + void *param_value; // 参数值 + struct TermParamlist_t *next; // 下一个参数项 +}TermParamlist_t; +// 设置终端参数体(0x8103) +typedef struct { + uint8_t param_Total_num; // 参数总数 + TermParamlist_t *param_list; // 参数项列表 +}SetTermParams_t; + +// 查询终端参数体(0x8104空包) + +// 查询指定终端参数体(0x8106) +typedef struct { + uint8_t param_Total_num; // 参数总数 + uint32_t *param_id_list; // 参数ID列表 +}GetSpecificTermParams_t; + +// 查询终端参数应答体(0x0104) +typedef struct { + uint16_t msg_flow_num; // 对应的终端参数查询消息的流水号 + uint8_t param_Total_num; // 参数总数 + TermParamlist_t *param_list; // 参数项列表 +}GetTermParamsResp_t; + +// 终端控制命令字 +typedef union { + struct{ + uint8_t _0 : 1; // + uint8_t _1 : 1; // 无线升级 + uint8_t _2 : 1; // 控制终端连接指定服务器 + uint8_t _3 : 1; // 终端关机 + uint8_t _4 : 1; // 终端复位 + uint8_t _5 : 1; // 终端恢复出厂设置 + uint8_t _6 : 1; // 关闭数据通信 + uint8_t _7 : 1; // 关闭所有无线通信 + }; + uint8_t val8; +}Term_Ctrl_Cmd_t; +// 终端控制体(0x8105) +typedef struct { + Term_Ctrl_Cmd_t com_word; //命令字 + uint8_t *str_cmd_params; //命令参数每个 STRING 字段先按 GBK 编码处理后再组成消息 +}Term_Ctrl_t; + +// 查询终端属性体(0x8107空包) + +// 查询终端属性应答体(0x0107) +typedef struct { + uint16_t term_type; // 终端类型 + uint8_t manufacturer_id[5];// 制造商ID, 固定5个字节 + uint8_t term_model[20];// 终端型号, 固定20个字节, 位数不足后补0x00 + uint8_t term_id[7];// 终端ID, 固定7个字节, 位数不足后补0x00 + uint8_t term_ICCID[10];// ICCID, + uint8_t hw_ver_len;// 终端硬件版本号长度 + uint8_t *str_hw_ver;// 终端硬件版本号 + uint8_t fw_ver_len;// 终端固件版本号长度 + uint8_t *str_fw_ver;// 终端固件版本号 + uint8_t GnssModule_attr;// GNSS模块属性 + uint8_t CommModule_attr;// 通讯模块属性 +}GetTermAttrResp_t; + +// 下发终端升级包体(0x8108) +typedef struct { + uint8_t upgrade_type; // 升级类型 + uint8_t manufacturer_id[5];// 制造商ID, 固定5个字节 + uint8_t ver_len;// 版本号长度 + uint8_t *str_ver;// 版本号 + uint32_t upgrade_pkg_len;// 升级包长度 单位为 BYTE + uint8_t *str_upgrade_pkg;// 升级包 +}Term_Upgrade_t; + +// 终端升级结果通知体(0x0108) +typedef struct { + uint8_t upgrade_type; // 升级类型 0:终端,12:道路运输证 IC 卡读卡器,52:北斗卫星定位模块 + uint8_t upgrade_result; // 结果 0:成功,1:失败,2:取消 +}Term_UpgradeResult_t; + +// 报警标志位 +typedef union{ + struct{ + uint32_t sos : 1;// bit_0 紧急报警,触动报警开关后触/收到应答后清零 + uint32_t overspeed : 1;// bit_1 超速报警 + uint32_t fatigue : 1;// bit_2 疲劳驾驶 + uint32_t early_warning : 1;// bit_3 危险预警 + uint32_t gnss_fault : 1;// bit_4 GNSS模块发生故障 + uint32_t gnss_antenna_cut : 1; // bit_5 GNSS天线未接或被剪断 + uint32_t gnss_antenna_shortcircuit : 1;// bit_6 GNSS天线短路 + uint32_t power_low : 1;// bit_7 终端主电源欠压 + uint32_t power_cut : 1;// bit_8 终端主电源掉电 + uint32_t lcd_fault : 1;// bit_9 终端LCD或显示器故障 + uint32_t tts_fault : 1;// bit_10 TTS模块故障 + uint32_t camera_fault : 1;// bit_11 摄像头故障 + uint32_t transport_license_IC_card_fault : 1;// bit_12 道路运输证 IC 卡模块故障 + uint32_t overspeed_notice : 1; // bit_1 超速预警 + uint32_t fatigue_notice : 1;// bit_2 疲劳驾驶预警 + uint32_t retain1 : 3;// 保留3位 + uint32_t day_drive_overtime : 1;// bit_18 当天累计驾驶超时 + uint32_t stop_driving_overtime : 1;// bit_19 超时停车 + uint32_t in_out_area : 1;// bit_20 进出区域.收到应答后清零 + uint32_t in_out_road : 1; // bit_21 进出路线.收到应答后清零 + uint32_t road_drive_time : 1;// bit_22 路段行驶时间不足/过长.收到应答后清零 + uint32_t road_deviate : 1;// bit_23 路线偏离报警 + uint32_t vss_fault : 1;// bit_24 车辆VSS故障 + uint32_t oil_fault : 1;// bit_25 车辆油量异常 + uint32_t car_alarm : 1;// bit_26 车辆被盗(通过车辆防盗器) + uint32_t car_acc_alarm : 1;// bit_27 车辆非法点火.收到应答后清零 + uint32_t car_move : 1;// bit_28 车辆非法位移.收到应答后清零 + uint32_t collision : 1;// 碰撞报警 + uint32_t rollover : 1;// 侧翻报警 + uint32_t Illegal_opendoor : 1;// 非法开门报警(终端未设置区域时,不判断非法开门)/收到应答后清零 + }; + uint32_t val32; +}LocAlarm_t; +// 状态位 +typedef union{ + struct{ + uint32_t acc : 1;// ACC开关, 0:ACC关; 1:ACC开 + uint32_t positioning : 1;// 定位标志, 0:未定位; 1:定位 + uint32_t sn_latitude : 1;// 纬度半球, 0:北纬: 1:南纬 + uint32_t ew_longitude : 1;// 经度半球, 0:东经; 1:西经 + uint32_t operation : 1; // 0:运营状态; 1:停运状态 + uint32_t gps_encrypt : 1;// 0:经纬度未经保密插件加密; 1:经纬度已经保密插件加密 + uint32_t retain1 : 2;// 保留2位 + uint32_t trip_status : 2;// 00: 空车; 01: 半载; 10: 保留; 11: 满载 + uint32_t oil_cut : 1;// 0:车辆油路正常; 1:车辆油路断开 + uint32_t circuit_cut : 1;// 0:车辆电路正常; 1:车辆电路断开 + uint32_t door_lock : 1;// 0:车门解锁; 1: 车门加锁 + uint32_t door1_status : 1;// 0:门1 关; 1: 门1 开; (前门) + uint32_t door2_status : 1;// 0:门2 关; 1: 门2 开; (中门) + uint32_t door3_status : 1;// 0:门 3 关; 1: 门 3 开; (后门) + + uint32_t door4_status : 1;// 0:门 4 关; 1: 门 4 开; (驾驶席门) + uint32_t door5_status : 1;// 0:门 5 关; 1: 门 5 开; (自定义) + uint32_t gps_en : 1;// 0: 未使用 GPS 卫星进行定位; 1: 使用 GPS 卫星进行定位 + uint32_t beidou_en : 1;// 0: 未使用北斗卫星进行定位; 1: 使用北斗卫星进行定位 + uint32_t glonass_en : 1;// 0: 未使用 GLONASS 卫星进行定位; 1: 使用 GLONASS 卫星进行定位 + uint32_t galileo_en : 1;// 0: 未使用 Galileo 卫星进行定位; 1: 使用 Galileo 卫星进行定位 + uint32_t retain2 : 10;// 保留10位 + }; + uint32_t val32; +}LocStatus_t; +// 位置信息汇报消息体 +typedef struct{ + LocAlarm_t alarm_flag; // 报警标志 + LocStatus_t status; // 状态 + uint32_t latitude; // 纬度 + uint32_t longitude; // 经度 + uint16_t altitude; // 高度 + uint16_t speed; // 速度 + uint16_t direction; // 方向 + uint8_t BCDtime[6]; // 时间YY-MM-DD-hh-mm-ss(GMT+8 时间,本标准中之后涉及的时间均采用此时区) +}Loc_basic_info_t; +typedef enum{ + MileageID = 0x01,// 里程, 1/10km, 对应车上里程表读数, DWORD + OilMassID = 0x02,// 油量, 1/10L, 对应车上油量表读数, WORD + TachographSpeedID = 0x03,// 行驶记录功能获取的速度, 1/10km/h, WORD + AlarmCountID = 0x04,// 需要人工确认报警事件的 ID, 从 1 开始计数, WORD + OverSpeedAlarmID = 0x11,// 超速报警附加信息, BYTE or BYTE+DWORD + AccessAreaAlarmID = 0x12,// 进出区域/路线报警附加信息, BYTE+DWORD+BYTE + DrivingTimeAlarmID = 0x13,// 路段行驶时间不足/过长报警附加信息, DWORD+WORD+BYTE + VehicleSignalStatusID = 0x25,// 扩展车辆信号状态位, DWORD + IoStatusID = 0x2A,// IO 状态位, WORD + AnalogQuantityID = 0x2B,// 模拟量, DWORD + NetworkQuantityID = 0x30,// 无线通信网络信号强度, BYTE + GnssSatellitesID = 0x31,// GNSS 定位卫星数, BYTE + CustomInformationLengthID = 0xE0,// 后续自定义信息长度, BYTE +}addi_infoID_t; +// 位置附加信息 +typedef struct Loc_addi_info_t{ + uint8_t msg_id; // 附加消息ID + uint8_t msg_len; // 附加消息长度 + void *msg; // 附加消息内容 + struct Loc_addi_info_t *next; // 下一个附加信息 +}Loc_addi_info_t; +// 位置信息汇报体(0x0200) +typedef struct{ + Loc_basic_info_t basic_info; // 基本信息 + Loc_addi_info_t *addi_info; // 附加信息 +}LocReport_t; + +// 位置信息查询体(0x8201空包) + +// 位置信息查询应答体(0x0201) +typedef struct { + uint16_t msg_flow_num; // 对应的位置信息查询消息的流水号 + LocReport_t *loc_info; // 位置信息 +}GetLocInfoResp_t; + +// 临时位置跟踪控制体(0x8202) +typedef struct { + uint16_t time_intv; // 时间间隔 + uint32_t eff_time; // 追踪有效时间,单位为秒(s) +}LocTrackingCtrl_t; + +// ------------------------------ 协议帧结构体定义 ---------- +// 转义相关标识 +typedef enum { + PSIGN = 0x7E, // 标识位 + PESC = 0x7D, // 转义标识 + PESC_SIGN = 0x02, // 0x7E<-->0x7D后紧跟一个0x02 + PESC_ESCAPE = 0x01, // 0x7D<-->0x7D后紧跟一个0x01 +} ProtocolEscapeFlag; + +// 消息体属性 +typedef union { + struct { + uint16_t msgbodylen : 10;// 消息体长度, 占用10bit + uint16_t encrypt : 3;// 数据加密方式, 当此三位都为0, 表示消息体不加密, 当第10位为1, 表示消息体经过RSA算法加密 + uint16_t packet : 1;// 分包标记 + uint16_t retain : 2;// 保留2位 + }; + uint16_t val16; +}MsgBodyAttr_t; + +// 消息头 +typedef struct { + uint16_t msg_id;// 消息ID + MsgBodyAttr_t msgbody_attr;// 消息体属性 + uint8_t phone_BCDnum[6];// 终端手机号 + uint16_t msg_flow_num;// 消息流水号 + uint16_t total_packet;// 总包数, 分包情况下使用 + uint16_t packet_seq;// 当前包序号, 分包情况下使用 +}MsgHead_t; + +// 消息结构体 +typedef struct { + uint8_t Head_SIGN; // 头标识位 + MsgHead_t msg_head; // 消息头 + void *p_msg_body; // 消息体 + uint8_t BCC_Check; // BCC校验码 + uint8_t Tail_SIGN; // 尾标识位 +}JT808_2013_MsgFrame_t; + +#pragma pack() + +#endif // __JT808_PROTOCOL__ diff --git a/custom/jt808/inc/jt808_set_TermParam.h b/custom/jt808/inc/jt808_set_TermParam.h new file mode 100644 index 0000000..d156402 --- /dev/null +++ b/custom/jt808/inc/jt808_set_TermParam.h @@ -0,0 +1,70 @@ +#ifndef JT808_SET_TERM_PARAM_H_ +#define JT808_SET_TERM_PARAM_H_ +#include "jt808_protocol.h" +#include "jt808_config.h" + +#pragma pack(1) +// 终端参数设置项参数ID +typedef enum { + HeartBeatInterval = 0x0001,// DWORD, 终端心跳发送间隔(s) + MainServerAddr = 0x0013,//STRING, 主服务器地址,IP 或域名 + ServerPort = 0x0018,//DWORD, 服务器 TCP 端口 + DefaultTimeReportInterval = 0x0029,// DWORD, 缺省时间汇报间隔 + InflexionAngle = 0x0030,// DWORD, 拐点补传角度, < 180° + MaxSpeed = 0x0055,// DWORD, 最高速度, km/h. + ProvinceID = 0x0081,// WORD, 车辆所在的省域 ID + CityID = 0x0082,// WORD, 车辆所在的市域 ID + CarPlateNum = 0x0083,//STRING, 公安交通管理部门颁发的机动车号牌 + CarPlateColor = 0x0084,//车牌颜色,按照 JT/T415-2006 的 5.4.12 +}set_TermParamID_t; +typedef struct{ + uint32_t HeartBeatInterval;// DWORD, 终端心跳发送间隔(s) + uint8_t MainServerAddr[50];//STRING, 主服务器地址,IP 或域名 + uint32_t ServerPort;//DWORD, 服务器 TCP 端口 + uint32_t DefaultTimeReportInterval;// DWORD, 缺省时间汇报间隔 + uint32_t InflexionAngle;// DWORD, 拐点补传角度, < 180° + uint32_t MaxSpeed;// DWORD, 最高速度, km/h + uint16_t ProvinceID;// WORD, 车辆所在的省域 ID + uint16_t CityID;// WORD, 车辆所在的市域 ID + uint8_t CarPlateNum[10];//STRING, 公安交通管理部门颁发的机动车号牌 + uint8_t CarPlateColor;//车牌颜色,按照 JT/T415-2006 的 5.4.12 +}set_TermParam_t; + +// big_标记的参数需以大端方式存储,需手动转换为大端 +typedef struct {// 终端参数项 + uint8_t phone_BCDnum[6];// 终端手机号 + uint16_t msg_flow_num;// 累加的消息流水号 + Term_RegInfo_t big_reg_info; // 注册信息 + Term_Auth_t big_auth_info; // 终端鉴权信息 + set_TermParam_t set_term_param; // 设置终端参数 + GetSpecificTermParams_t big_specific_params; // 解析出的待查询指定终端参数列表 + Term_Ctrl_t big_ctrl_info; // 解析出的终端控制信息 + Term_Upgrade_t big_upgrade_info; // 解析出的升级信息 + LocReport_t big_loc_report; // 位置信息汇报 + LocTrackingCtrl_t big_loc_tracking_ctrl; // 临时位置跟踪控制 +}Term_Param_item_t; +#pragma pack() + +extern Term_Param_item_t jt808_term_param_item; + +extern osThreadFunc_t Autoreport_param_ThreadId; + +// 控制车辆状态 +void jt808_Set_CarStatus(uint8_t status); + +// 获取车辆状态 +uint8_t jt808_Get_CarStatus(void); + +// 设置终端参数 +int jt808_setTermParam(set_TermParamID_t param_id, void *param, uint8_t param_len); + +// 启动自动上报参数 +void jt808_Autoreport_param_start(void); + +// 停止自动上报参数 +void jt808_Autoreport_param_stop(void); + +// 初始化终端参数 +void jt808_set_term_param_init(void); + +#endif // JT808_SET_TERM_PARAM_H_ \ No newline at end of file diff --git a/custom/jt808/inc/jt808_util.h b/custom/jt808/inc/jt808_util.h new file mode 100644 index 0000000..6c6c12d --- /dev/null +++ b/custom/jt808/inc/jt808_util.h @@ -0,0 +1,37 @@ + +#ifndef JT808_UTIL_H_ +#define JT808_UTIL_H_ + +#include +#include +#include +#include +#include +// #include + +// 双字节大小端交换 +uint16_t Swap16(uint16_t val16); +// 四字节大小端交换 +uint32_t Swap32(uint32_t val32); +// 异或校验 +uint8_t BCC_Check(const uint8_t *src, uint32_t len); + + +// 十进制转BCD码 +uint8_t DecToBcd(uint8_t Dec); + +// BCD码转十进制 +uint8_t BcdToDec(uint8_t Bcd); + +// 原始字符串转BCD码 //奇数位时,首位BCD码前面补0 +uint8_t *rawStrToBcd(uint8_t *bcd, const uint8_t *str, uint16_t str_len); + +// BCD转字符串,自动去掉bcd码前导零 +// bcdlen 为bcd码字节数 +uint8_t *BcdToStr(uint8_t *str, const uint8_t *bcd, int bcd_len); + +// 原始BCD数据转字符串 +// strlen 为原始BCD数据字节数 +uint8_t *rawBcdToStr(uint8_t *str, const uint8_t *bcd, int bcd_len); + +#endif // JT808_UTIL_H_ diff --git a/custom/jt808/inc/protocol_parameter.h b/custom/jt808/inc/protocol_parameter.h index e9c0e45..8373435 100644 --- a/custom/jt808/inc/protocol_parameter.h +++ b/custom/jt808/inc/protocol_parameter.h @@ -263,7 +263,7 @@ struct ProtocolParameter struct LocationTrackingControl location_tracking_control; // 升级信息. - struct UpgradeInfo upgrade_info; + struct UpgradeInfo big_upgrade_info; // 补传分包信息. struct FillPacket fill_packet; @@ -298,7 +298,7 @@ struct ProtocolParameter struct LocationTrackingControl location_tracking_control; // 解析出的升级信息. - struct UpgradeInfo upgrade_info; + struct UpgradeInfo big_upgrade_info; // 解析出的补传分包信息. struct FillPacket fill_packet; diff --git a/custom/jt808/jt808.mk b/custom/jt808/jt808.mk index 81b7c7d..248309b 100644 --- a/custom/jt808/jt808.mk +++ b/custom/jt808/jt808.mk @@ -1,14 +1,19 @@ CUSTOM_MAIN_DIR := custom/jt808 -OC_FILES += $(CUSTOM_MAIN_DIR)/src/bcd.c -OC_FILES += $(CUSTOM_MAIN_DIR)/src/client_manager.c -OC_FILES += $(CUSTOM_MAIN_DIR)/src/gbk_utf8.c -OC_FILES += $(CUSTOM_MAIN_DIR)/src/jt808_packager.c -OC_FILES += $(CUSTOM_MAIN_DIR)/src/jt808_parser.c -OC_FILES += $(CUSTOM_MAIN_DIR)/src/location_report.c -OC_FILES += $(CUSTOM_MAIN_DIR)/src/set_terminal_parameter.c -OC_FILES += $(CUSTOM_MAIN_DIR)/src/terminal_register.c -OC_FILES += $(CUSTOM_MAIN_DIR)/src/util.c +# OC_FILES += $(CUSTOM_MAIN_DIR)/src/bcd.c +# OC_FILES += $(CUSTOM_MAIN_DIR)/src/client_manager.c +# OC_FILES += $(CUSTOM_MAIN_DIR)/src/gbk_utf8.c +# OC_FILES += $(CUSTOM_MAIN_DIR)/src/jt808_packager.c +# OC_FILES += $(CUSTOM_MAIN_DIR)/src/jt808_parser.c +# OC_FILES += $(CUSTOM_MAIN_DIR)/src/location_report.c +# OC_FILES += $(CUSTOM_MAIN_DIR)/src/set_terminal_parameter.c +# OC_FILES += $(CUSTOM_MAIN_DIR)/src/terminal_register.c +# OC_FILES += $(CUSTOM_MAIN_DIR)/src/util.c +OC_FILES += $(CUSTOM_MAIN_DIR)/src/jt808_util.c +OC_FILES += $(CUSTOM_MAIN_DIR)/src/jt808_msg_pkg.c +OC_FILES += $(CUSTOM_MAIN_DIR)/src/jt808_msg_parse.c +OC_FILES += $(CUSTOM_MAIN_DIR)/src/jt808_pkg_transmit.c +OC_FILES += $(CUSTOM_MAIN_DIR)/src/jt808_set_TermParam.c INC += -I'$(CUSTOM_MAIN_DIR)/inc' \ No newline at end of file diff --git a/custom/jt808/src/bcd.c b/custom/jt808/src/bcd.c index 50d85b3..6e16e96 100644 --- a/custom/jt808/src/bcd.c +++ b/custom/jt808/src/bcd.c @@ -1,5 +1,5 @@ #include "bcd.h" -#include "jt808_debug.h" +#include "jt808_config.h" unsigned char HexToBcd(unsigned char src) { diff --git a/custom/jt808/src/client_manager.c b/custom/jt808/src/client_manager.c index 0bf6654..5abe8c0 100644 --- a/custom/jt808/src/client_manager.c +++ b/custom/jt808/src/client_manager.c @@ -6,7 +6,7 @@ #include "bcd.h" #include "jt808_packager.h" #include "jt808_parser.h" -#include "jt808_debug.h" +#include "jt808_config.h" uint8_t Non_transliterated_receive[1024]; struct ProtocolParameter parameter_; diff --git a/custom/jt808/src/gbk_utf8.c b/custom/jt808/src/gbk_utf8.c index 321e8dc..aec0c68 100644 --- a/custom/jt808/src/gbk_utf8.c +++ b/custom/jt808/src/gbk_utf8.c @@ -1,5 +1,5 @@ #include "gbk_utf8.h" -#include "jt808_debug.h" +#include "jt808_config.h" /* namespace libjt808 diff --git a/custom/jt808/src/jt808_msg_parse.c b/custom/jt808/src/jt808_msg_parse.c new file mode 100644 index 0000000..ac3757a --- /dev/null +++ b/custom/jt808/src/jt808_msg_parse.c @@ -0,0 +1,183 @@ +#include "jt808_msg_parse.h" +#include "jt808_pkg_transmit.h" + +PrsResult_t PrsResult; + +// 消息体解析 +static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *PrsResult){ + switch (PrsResult->msg_head.msg_id){ + case ID_Plat_GenResp:{// 平台通用应答 + memcpy(&(PrsResult->Rsp_flow_num), Prsmsg_body, sizeof(Plat_GenResp_t)); + // 转小端 + PrsResult->Rsp_flow_num = Swap16(PrsResult->Rsp_flow_num); + PrsResult->Rsp_msg_id = Swap16(PrsResult->Rsp_msg_id); + // PrsResult->Rsp_result = PrsResult->Rsp_result; + break; + } + case ID_FillPktReq:{// 补传分包请求 + + break; + } + case ID_Term_RegResp:{// 终端注册应答 + PrsResult->Rsp_flow_num = (uint16_t)(((uint8_t *)Prsmsg_body)[0] << 8) | (((uint8_t *)Prsmsg_body)[1]); + PrsResult->Rsp_result = ((uint8_t *)Prsmsg_body)[2]; + if(PrsResult->Rsp_result == 0){ // 成功时,读取鉴权码 + if(PrsResult->term_param_item->big_auth_info.str_auth_code != NULL){ + jt808_free(PrsResult->term_param_item->big_auth_info.str_auth_code); + PrsResult->term_param_item->big_auth_info.str_auth_code = NULL; + } + PrsResult->term_param_item->big_auth_info.str_auth_code = (char *)jt808_malloc(PrsResult->msg_head.msgbody_attr.msgbodylen - 3 +1); // 加1是为了加上结束符 + if(PrsResult->term_param_item->big_auth_info.str_auth_code == NULL){ + JT808_DEBUG("[%s,%s] malloc failed\r\n", __FUNCTION__,__LINE__); + return -1; + } + memset(PrsResult->term_param_item->big_auth_info.str_auth_code, 0, PrsResult->msg_head.msgbody_attr.msgbodylen - 3 +1); + memcpy(PrsResult->term_param_item->big_auth_info.str_auth_code, Prsmsg_body + 3 , PrsResult->msg_head.msgbody_attr.msgbodylen - 3); + } + break; + } + case ID_SetTermParams:{// 设置终端参数 + PrsResult->term_param_item->big_specific_params.param_Total_num = ((uint8_t *)Prsmsg_body)[0]; // 总参数个数 + uint16_t param_lenoffset = 1; + for(int i = 0; i < PrsResult->term_param_item->big_specific_params.param_Total_num; i++){ + // 设置终端参数 + jt808_setTermParam(Swap32(*(uint32_t *)(Prsmsg_body + param_lenoffset)), // 参数ID + (void *)(Prsmsg_body + param_lenoffset + 5), // 参数值 + *((uint8_t*)(Prsmsg_body + param_lenoffset + 4))); // 参数长度 + param_lenoffset += 5 + (*((uint8_t*)(Prsmsg_body + param_lenoffset + 4))); // 参数ID(4) + 参数长度(1) + 参数值(n) + } + + jt808_pkg_send(ID_Term_GenResp, 0);// 发送终端通用应答 + break; + } + case ID_GetTermParams:{// 查询终端参数 + + break; + } + case ID_GetSpecificTermParams:{// 查询指定终端参数 + + break; + } + case ID_Term_Ctrl:{// 终端控制 + + break; + } + case ID_GetTermAttr:{// 查询终端属性 + + break; + } + case ID_Term_Upgrade:{// 下发终端升级包 + + break; + } + case ID_GetLocInfo:{// 位置信息查询 + + break; + } + case ID_LocTrackingCtrl:{// 临时位置跟踪控制 + + break; + } + case ID_Car_Ctrl:{// 车辆控制 + + jt808_pkg_send(ID_Car_CtrlResp, 0);// 发送车辆控制应答,设置本消息无发送应答 + break; + } + default:{ + return -2; // 没有对应的消息体解析函数 + break; + } + } + return 0; +} + +// jt808协议包处理 +int jt808_msg_parse(const uint8_t *BufferReceive, uint16_t length, PrsResult_t *PrsResult){ + uint8_t *raw_Buffer = (uint8_t *)jt808_malloc(length * sizeof(uint8_t)); + if(raw_Buffer == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + return -1; + } + memcpy(raw_Buffer, BufferReceive, length); + + // // 打印原始数据 + // app_printf("raw_Buffer: %d\r\n", length); + // for(int i = 0; i < length; i++){ + // app_printf("%02x ", raw_Buffer[i]); + // } + // app_printf("\r\n"); + + // 计算需要逆转义字符的个数 + uint16_t para_length = 0; + for(int i = 1; i < (length - 2); i++){ + if(((raw_Buffer[i] == PESC)&&(raw_Buffer[i+1] == PESC_SIGN)) || // 7d 02 转义7e + ((raw_Buffer[i] == PESC)&&(raw_Buffer[i+1] == PESC_ESCAPE))){ // 7d 01 转义7d + para_length++; + } + } + para_length =length - para_length; + uint8_t *para_Buffer = (uint8_t *)jt808_malloc(para_length * sizeof(uint8_t)); + if(para_Buffer == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + jt808_free(raw_Buffer); + return -1; + } + para_Buffer[0] = PSIGN; + para_Buffer[para_length - 1] = PSIGN; + + // 逆转义 + uint16_t offset_num = 0; + for(int i = 1; i < (para_length - 1); i++){ + if(((raw_Buffer[i + offset_num] == PESC)&&(raw_Buffer[i + offset_num + 1] == PESC_SIGN))){ // 7d 02 转义7e + para_Buffer[i] = PSIGN; + offset_num++; + }else if(((raw_Buffer[i + offset_num] == PESC)&&(raw_Buffer[i + offset_num + 1] == PESC_ESCAPE))){ // 7d 01 转义7d + para_Buffer[i] = PESC; + offset_num++; + }else{ + para_Buffer[i] =raw_Buffer[i + offset_num]; + } + } + // 释放内存 + jt808_free(raw_Buffer); + + if(offset_num != length - para_length){ // 转义后长度有误 + JT808_DEBUG("error offset_num != length - para_length\r\n"); + jt808_free(para_Buffer); + return -1; + } + + // // 打印逆转义后数据 + // app_printf("para_Buffer: %d\r\n", para_length); + // for(int i = 0; i < para_length; i++){ + // app_printf("%02x ", para_Buffer[i]); + // } + // app_printf("\r\n"); + + // 异或校验 + if(para_Buffer[para_length - 2] != BCC_Check(para_Buffer + 1, para_length - 2 - 1)){ + JT808_DEBUG("BCC_CheckSum ERROR: %x %x\r\n",para_Buffer[para_length - 2] ,BCC_Check(para_Buffer + 1, para_length - 2 - 1)); + jt808_free(para_Buffer); + return -1; + } + + // 解析消息头 + memcpy(&PrsResult->msg_head, para_Buffer + 1, sizeof(MsgHead_t) - ((para_Buffer[3] & 0x02)==0? 4 : 0)); + PrsResult->msg_head.msg_id = Swap16(PrsResult->msg_head.msg_id);// 消息ID + PrsResult->msg_head.msgbody_attr.val16 = Swap16(PrsResult->msg_head.msgbody_attr.val16);// 消息体属性 + PrsResult->msg_head.msg_flow_num = Swap16(PrsResult->msg_head.msg_flow_num);// 消息流水号 + PrsResult->msg_head.total_packet = Swap16(PrsResult->msg_head.total_packet);// 总包数, 分包情况下使用 + PrsResult->msg_head.packet_seq = Swap16(PrsResult->msg_head.packet_seq);// 当前包序号, 分包情况下使用 + + // 消息体解析 + if(0 != jt808_BodyParse((void *)(para_Buffer + 1 + sizeof(MsgHead_t) - ((para_Buffer[3] & 0x02)==0? 4 : 0)) ,PrsResult)){ + JT808_DEBUG("error jt808_BodyParse\r\n"); + // 释放内存 + jt808_free(para_Buffer); + return -1; + } + + // 释放内存 + jt808_free(para_Buffer); + return 0; +} diff --git a/custom/jt808/src/jt808_msg_pkg.c b/custom/jt808/src/jt808_msg_pkg.c new file mode 100644 index 0000000..9c0b65c --- /dev/null +++ b/custom/jt808/src/jt808_msg_pkg.c @@ -0,0 +1,253 @@ +#include "jt808_msg_pkg.h" +#include "jt808_msg_parse.h" + +// 协议消息体打包(会自动为p_msg_body分配合适长度的内存,注意释放) +static int jt808_BodyPackage(JT808_2013_MsgFrame_t *p_MsgFrame, MessageID_t Msg_ID){ + if(PrsResult.term_param_item == NULL){ + JT808_DEBUG("[%s,%s] term_param_item is NULL \r\n", __FUNCTION__,__LINE__); + return -1; + } + p_MsgFrame->msg_head.msgbody_attr.encrypt = 0;// 数据加密方式 + p_MsgFrame->msg_head.msgbody_attr.packet = 0;// 分包标记 + p_MsgFrame->msg_head.msgbody_attr.retain = 0;// 保留2位 + + p_MsgFrame->msg_head.total_packet = 0;// 总包数, 分包情况下使用 + p_MsgFrame->msg_head.packet_seq = 0;// 当前包序号, 分包情况下使用 + // 填充消息体 + switch(Msg_ID){ + case ID_Term_GenResp:{ // 终端通用应答 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = sizeof(Term_GenResp_t);// 消息体长度 + + // 定义大端结构体 + Term_GenResp_t *big_term_reg_resp = (Term_GenResp_t *)jt808_malloc(sizeof(Term_GenResp_t)); + if(big_term_reg_resp == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + return -1; + } + memset(big_term_reg_resp, 0, sizeof(Term_GenResp_t)); + // 大小端转换 + big_term_reg_resp->msg_flow_num = Swap16(PrsResult.Rsp_flow_num); // 返回消息应答结果 + big_term_reg_resp->msg_id_ack = Swap16(PrsResult.Rsp_msg_id); + big_term_reg_resp->result = PrsResult.Rsp_result; + p_MsgFrame->p_msg_body = (void *)big_term_reg_resp; + break; + } + case ID_Term_HB:{ // 终端心跳 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = 0;// 消息体长度 + break; + } + case ID_Term_Reg:{ // 终端注册 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = sizeof(Term_RegInfo_t);// 消息体长度 + + // 定义大端结构体 + Term_RegInfo_t *big_term_reg = (Term_RegInfo_t *)jt808_malloc(sizeof(Term_RegInfo_t)); + if(big_term_reg == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + return -1; + } + // memset(big_term_reg, 0, sizeof(Term_RegInfo_t)); + memcpy(big_term_reg, &PrsResult.term_param_item->big_reg_info, sizeof(Term_RegInfo_t)); // 复制注册信息内容 + p_MsgFrame->p_msg_body = (void *)big_term_reg; + break; + } + case ID_Term_Logout:{ // 终端注销 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = 0;// 消息体长度 + break; + } + case ID_Term_Auth:{ // 终端鉴权 + // JT808_DEBUG("ID_Term_Auth\r\n"); + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = strlen(PrsResult.term_param_item->big_auth_info.str_auth_code);// 消息体长度 + if((NULL == PrsResult.term_param_item->big_auth_info.str_auth_code) || (1 >= p_MsgFrame->msg_head.msgbody_attr.msgbodylen)){ + JT808_DEBUG("[%s,%s] auth_code len is 0 \r\n", __FUNCTION__,__LINE__); + return -1; + } + void *str_auth_code = jt808_malloc(p_MsgFrame->msg_head.msgbody_attr.msgbodylen); + if(str_auth_code == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + return -1; + } + // memset(str_auth_code, 0, p_MsgFrame->msg_head.msgbody_attr.msgbodylen); + JT808_DEBUG("auth_code:%d,%s\r\n",strlen(PrsResult.term_param_item->big_auth_info.str_auth_code), + PrsResult.term_param_item->big_auth_info.str_auth_code); + memcpy(str_auth_code, PrsResult.term_param_item->big_auth_info.str_auth_code, p_MsgFrame->msg_head.msgbody_attr.msgbodylen); + p_MsgFrame->p_msg_body = (void *)str_auth_code; + break; + } + case ID_GetTermParamsResp:{ // 查询终端参数应答 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = sizeof(GetTermParamsResp_t);// 消息体长度 + GetTermParamsResp_t *get_term_params_resp = (GetTermParamsResp_t *)jt808_realloc(p_MsgFrame->p_msg_body, sizeof(GetTermParamsResp_t)); + if(get_term_params_resp == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + return -1; + } + p_MsgFrame->p_msg_body = (void *)get_term_params_resp; + break; + } + case ID_GetTermAttrResp:{ // 查询终端属性应答 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = sizeof(GetTermAttrResp_t);// 消息体长度 + GetTermAttrResp_t *get_term_attr_resp = (GetTermAttrResp_t *)jt808_realloc(p_MsgFrame->p_msg_body, sizeof(GetTermAttrResp_t)); + if(get_term_attr_resp == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + return -1; + } + p_MsgFrame->p_msg_body = (void *)get_term_attr_resp; + break; + } + case ID_Term_UpgradeResult:{ // 终端升级结果通知 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = sizeof(Term_UpgradeResult_t);// 消息体长度 + Term_UpgradeResult_t *term_upgrade_result = (Term_UpgradeResult_t *)jt808_realloc(p_MsgFrame->p_msg_body, sizeof(Term_UpgradeResult_t)); + if(term_upgrade_result == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + return -1; + } + p_MsgFrame->p_msg_body = (void *)term_upgrade_result; + break; + } + case ID_LocReport:{ // 位置信息汇报 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = sizeof(Loc_basic_info_t);// 消息体长度 + Loc_addi_info_t *p_loc_addi_info = PrsResult.term_param_item->big_loc_report.addi_info; + while(p_loc_addi_info != NULL){ // 计算附加信息长度 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen += p_loc_addi_info->msg_len + 2; + p_loc_addi_info = p_loc_addi_info->next; + } + uint8_t *loc_report_buf = (uint8_t *)jt808_malloc(p_MsgFrame->msg_head.msgbody_attr.msgbodylen); + if(loc_report_buf == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + return -1; + } + memcpy(loc_report_buf, &PrsResult.term_param_item->big_loc_report, sizeof(Loc_basic_info_t)); // 复制基本信息内容 + p_loc_addi_info = PrsResult.term_param_item->big_loc_report.addi_info; + uint16_t loc_report_offset = sizeof(Loc_basic_info_t); + uint8_t loc_len = 0; + while(p_loc_addi_info != NULL){ // 填充附加信息内容 + loc_len= p_loc_addi_info->msg_len + 2; + memcpy(loc_report_buf + loc_report_offset, &p_loc_addi_info->msg_id, 2); + memcpy(loc_report_buf + loc_report_offset + 2, p_loc_addi_info->msg, p_loc_addi_info->msg_len); + loc_report_offset += loc_len; + p_loc_addi_info = p_loc_addi_info->next; + } + p_MsgFrame->p_msg_body = (void *)loc_report_buf; + break; + } + case ID_GetLocInfoResp:{ // 查询位置信息应答 + p_MsgFrame->msg_head.msgbody_attr.msgbodylen = sizeof(GetLocInfoResp_t);// 消息体长度 + GetLocInfoResp_t *get_loc_info_resp = (GetLocInfoResp_t *)jt808_realloc(p_MsgFrame->p_msg_body, sizeof(GetLocInfoResp_t)); + if(get_loc_info_resp == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + return -1; + } + p_MsgFrame->p_msg_body = (void *)get_loc_info_resp; + break; + } + default: + return -2; + break; + } + + return 0; +} + +// 消息帧打包 (会自动为msgEscape->buf分配合适长度的内存,注意释放) +int jt808_msg_pkg(MessageID_t Msg_ID, JT808MsgESC_t *msgEscape){ + JT808_2013_MsgFrame_t big_MsgFrame;// 定义大端消息帧 + + JT808_DEBUG("BodyPackage ID:0x%04X\r\n", Msg_ID); + big_MsgFrame.p_msg_body = NULL; + if(0 != jt808_BodyPackage(&big_MsgFrame, Msg_ID)){// 填充消息体 (注意释放p_msg_body内存) + JT808_DEBUG("jt808_BodyPackage failed\r\n"); + return -1; + } + // 计算消息帧总长度 + uint16_t msg_total_len = 1 + sizeof(MsgHead_t) - (1 ==big_MsgFrame.msg_head.msgbody_attr.packet ? 0 : 4); + uint16_t msgbody_len =big_MsgFrame.msg_head.msgbody_attr.msgbodylen; + msg_total_len += msgbody_len + 2; + JT808_DEBUG("total_len:%d,len:%d\r\n", msg_total_len, msgbody_len); + + big_MsgFrame.Head_SIGN = PSIGN; + big_MsgFrame.Tail_SIGN = PSIGN; + + // 大端转换 + big_MsgFrame.msg_head.msg_id = Swap16(Msg_ID);// 消息ID + big_MsgFrame.msg_head.msgbody_attr.val16 = Swap16(big_MsgFrame.msg_head.msgbody_attr.val16); + memcpy(big_MsgFrame.msg_head.phone_BCDnum, PrsResult.term_param_item->phone_BCDnum, 6); + big_MsgFrame.msg_head.msg_flow_num = Swap16(PrsResult.term_param_item->msg_flow_num);// 消息流水号 + big_MsgFrame.msg_head.total_packet = Swap16(big_MsgFrame.msg_head.total_packet);// 总包数, 分包情况下使用 + big_MsgFrame.msg_head.packet_seq = Swap16(big_MsgFrame.msg_head.total_packet);// 当前包序号, 分包情况下使用 + + uint8_t *msg_buf = (uint8_t *)jt808_malloc(msg_total_len); + if(msg_buf == NULL){ + JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__); + if(big_MsgFrame.p_msg_body != NULL){ // 释放消息体内存(必要操作) + jt808_free(big_MsgFrame.p_msg_body); + big_MsgFrame.p_msg_body = NULL; + } + return -1; + } + // 填充头标识和消息头 + memcpy(msg_buf, &big_MsgFrame.Head_SIGN, msg_total_len - msgbody_len - 2); + // 填充消息体 + if(0 < msgbody_len && big_MsgFrame.p_msg_body != NULL){ + memcpy(msg_buf + (msg_total_len - msgbody_len - 2), big_MsgFrame.p_msg_body, msgbody_len); + } + // 计算BCC校验码 + big_MsgFrame.BCC_Check = BCC_Check(msg_buf + 1, msg_total_len - 2 - 1); + memcpy(msg_buf + msg_total_len - 2, &big_MsgFrame.BCC_Check, 2); + + //// DEBUG + // app_printf("JT808_2013_MsgFrame_t:\r\n"); + // for (size_t i = 0; i < msg_total_len - msgbody_len - 2; i++){ + // app_printf("%02X ", *((uint8_t *)(&big_MsgFrame) + i)); + // } + // app_printf("\r\n"); + // for (size_t i = 0; i < msgbody_len; i++){ + // app_printf("%02X ", *((uint8_t *)big_MsgFrame.p_msg_body + i)); + // } + // app_printf("\r\n"); + // for (size_t i = 0; i < 2; i++){ + // app_printf("%02X ", *((uint8_t *)(&big_MsgFrame.BCC_Check) + i)); + // } + // app_printf("\r\n"); + + if(big_MsgFrame.p_msg_body != NULL){ // 释放消息体内存(必要操作) + jt808_free(big_MsgFrame.p_msg_body); + big_MsgFrame.p_msg_body = NULL; + } + + // 7E 转义处理 + uint16_t escape_len = 0; + for(uint16_t i = 1; i < msg_total_len - 1; i++){ + if(msg_buf[i] == PSIGN || msg_buf[i] == PESC){ + escape_len++; + } + } + msgEscape->buf = (uint8_t *)jt808_malloc(msg_total_len + escape_len); + uint16_t offset_num = 0; + msgEscape->buf[0] = PSIGN; + msgEscape->buf[msg_total_len + escape_len - 1] = PSIGN; + + for(uint16_t i = 1; i < msg_total_len - 1; i++){ + if(msg_buf[i] == PSIGN){ + msgEscape->buf[i + offset_num++] = PESC; + msgEscape->buf[i + offset_num] = PESC_SIGN; + }else if(msg_buf[i] == PESC){ + msgEscape->buf[i + offset_num++] = PESC; + msgEscape->buf[i + offset_num] = PESC_ESCAPE; + }else { + msgEscape->buf[i + offset_num] = msg_buf[i]; + } + } + jt808_free(msg_buf); + + // 返回消息帧总长度 + msgEscape->len = msg_total_len + escape_len; + + app_printf("msgEscape->buf:%d\r\n", msg_total_len + escape_len); + for(uint16_t i = 0; i < msg_total_len + escape_len; i++){ + app_printf("%02X ", *(msgEscape->buf + i)); + } + + app_printf("\r\n"); + // jt808_free(msgEscape->buf); + + return 0; +} diff --git a/custom/jt808/src/jt808_packager.c b/custom/jt808/src/jt808_packager.c index 328d980..9b111b9 100644 --- a/custom/jt808/src/jt808_packager.c +++ b/custom/jt808/src/jt808_packager.c @@ -2,7 +2,7 @@ #include "util.h" #include "terminal_parameter.h" #include "client_manager.h" -#include "jt808_debug.h" +#include "jt808_config.h" // 所有终端数据打包命令. unsigned short kTerminalPackagerCMD[PACKAGER_NUM] = { @@ -391,7 +391,12 @@ int jt808MsgEscape() BufferSend[RealBufferSendSize - 1] = 0x00; outBufferSize = RealBufferSendSize * 2; - outBuffer = (unsigned char *)malloc(outBufferSize); + outBuffer = (unsigned char *)jt808_malloc(outBufferSize); + if(outBuffer == NULL) + { + JT808_DEBUG("[%s] malloc failed \r\n", __FUNCTION__); + return -1; + } if (Escape_C(BufferSend, RealBufferSendSize, outBuffer, &outBufferSize) < 0) { @@ -407,7 +412,7 @@ int jt808MsgEscape() if (outBuffer != NULL) { - free(outBuffer); + jt808_free(outBuffer); outBuffer = NULL; } #ifdef __JT808_DEBUG @@ -507,8 +512,7 @@ int jt808FramePackage(struct ProtocolParameter *para) JT808_DEBUG("[Write buffersend end PROTOCOL_SIGN] OK !\r\n"); #endif // 6、处理转义. - if (jt808MsgEscape() < 0) - { + if (jt808MsgEscape() < 0){ JT808_DEBUG("[jt808MsgEscape] FAILED"); return -1; } diff --git a/custom/jt808/src/jt808_parser.c b/custom/jt808/src/jt808_parser.c index 719c5f6..f48549c 100644 --- a/custom/jt808/src/jt808_parser.c +++ b/custom/jt808/src/jt808_parser.c @@ -3,7 +3,7 @@ #include "client_manager.h" #include "util.h" #include "bcd.h" -#include "jt808_debug.h" +#include "jt808_config.h" // 所有终端解析命令. unsigned short kTerminalParserCMD[PARSER_NUM] = { @@ -172,7 +172,7 @@ int handle_kTerminalRegisterResponse(struct ProtocolParameter *para) if (para->parse.respone_result == kRegisterSuccess) { len_code = para->parse.msg_head.msgbody_attr.bit.msglen - 3; - para->parse.authentication_code = (unsigned char *)malloc((len_code + 1) * sizeof(unsigned char)); + para->parse.authentication_code = (unsigned char *)jt808_malloc((len_code + 1) * sizeof(unsigned char)); memcpy(para->parse.authentication_code, &(BufferReceive[pos + 3]), len_code); JT808_DEBUG("[%s] authentication_code = %s\r\n", __FUNCTION__, para->parse.authentication_code); @@ -281,9 +281,9 @@ int handle_kTerminalUpgrade(struct ProtocolParameter *para) pos = MSGBODY_PACKET_POS; } - para->upgrade_info.upgrade_type = BufferReceive[pos++]; + para->big_upgrade_info.upgrade_type = BufferReceive[pos++]; - memset(para->upgrade_info.manufacturer_id, 0, sizeof(para->upgrade_info.manufacturer_id)); + memset(para->big_upgrade_info.manufacturer_id, 0, sizeof(para->big_upgrade_info.manufacturer_id)); for (i = 0; i < 5; i++) { } @@ -398,7 +398,15 @@ int jt808FrameParse(const unsigned char *in, unsigned int in_len, struct Protoco memcpy(BufferReceive, in, in_len); RealBufferReceiveSize = in_len; outBufferSize = RealBufferReceiveSize; - outBuffer = (unsigned char *)malloc(outBufferSize * sizeof(unsigned char)); + if(outBufferSize < 1){ + JT808_DEBUG("outBufferSize < 1\r\n"); + return -1; + } + outBuffer = (unsigned char *)jt808_malloc(outBufferSize * sizeof(unsigned char)); + if(outBuffer == NULL){ + JT808_DEBUG("[%s] malloc failed \r\n", __FUNCTION__); + return -1; + } memset(outBuffer, 0, outBufferSize); #ifdef __JT808_DEBUG @@ -445,7 +453,7 @@ int jt808FrameParse(const unsigned char *in, unsigned int in_len, struct Protoco // 释放缓存 if (outBuffer != NULL) { - free(outBuffer); + jt808_free(outBuffer); outBuffer = NULL; } diff --git a/custom/jt808/src/jt808_pkg_transmit.c b/custom/jt808/src/jt808_pkg_transmit.c new file mode 100644 index 0000000..d002cd0 --- /dev/null +++ b/custom/jt808/src/jt808_pkg_transmit.c @@ -0,0 +1,106 @@ +#include "jt808_pkg_transmit.h" + +static osThreadId_t jt808_pkg_send_ThreadId; +static osMessageQueueId_t jt808_send_msg_queue = NULL; +static osSemaphoreId_t jt808_send_ack_sem = NULL; // 发送成功应答信号量 +static osSemaphoreId_t jt808_parse_ok_sem = NULL; // 解析完成信号量 + +// 触发消息发送 +int jt808_pkg_send(MessageID_t Msg_ID, uint32_t timeout){ + pkg_msg_t send_pkg_msg={0}; + send_pkg_msg.msg_id = Msg_ID; + send_pkg_msg.timeout = timeout; + JT808_DEBUG("send pkg_msg:%04x\n", Msg_ID); + if(osOK == osMessageQueuePut(jt808_send_msg_queue, &send_pkg_msg, 0, 0)){ // + if(0 < timeout){ // 阻塞等待发送回应 + + osStatus_t ret =osSemaphoreAcquire(jt808_send_ack_sem, timeout); + if(ret == osOK){ + return PrsResult.Rsp_result; // 发送成功应答 + JT808_DEBUG("send ack success\n"); + }else if(ret == osErrorTimeout){ + JT808_DEBUG("send ack timeout\n"); + return -1;// 发送失败 + } + } + }else{ + JT808_DEBUG("osMessageQueuePut fail\n"); + return -1;// 发送失败 + } + return 0; +} + +// 接收处理 (放入TCP接收回调中) +void jt808_pkg_handle(uint8_t *receive_buf, uint16_t receive_len){ + if(0 ==jt808_msg_parse(receive_buf, receive_len, &PrsResult)){ // 解析协议数据 + osSemaphoreRelease(jt808_parse_ok_sem); // 释放解析完成信号量 + JT808_DEBUG("jt808_msg_parse success\n"); + } +} + +// 发送任务 +static void jt808_pkg_send_task(void *arg){ + pkg_msg_t send_pkg_msg={0}; + JT808MsgESC_t MsgESC={ + .buf = NULL, + .len = 0, + }; + + while(1){ + if(osOK == osMessageQueueGet(jt808_send_msg_queue, &send_pkg_msg, NULL, osWaitForever)){ + if(0 == jt808_msg_pkg(send_pkg_msg.msg_id ,&MsgESC)){ // 生成协议数据成功 + // 发送数据 + if(NULL == MsgESC.buf){ // 协议数据为空(发生错误) + JT808_DEBUG("MsgESC.buf is NULL:len=%d\n",MsgESC.len); + continue; + } + JT808_DEBUG("tcp send %d bytes\n", MsgESC.len); + if(0 == PKG_SEND(MsgESC.buf, MsgESC.len)){ // 发送成功处理 + if(NULL != jt808_parse_ok_sem){ + osStatus_t ret =osSemaphoreAcquire(jt808_parse_ok_sem, send_pkg_msg.timeout);// 等待接收数据并解析完成 + if(ret == osOK || 0 == send_pkg_msg.timeout){ + osSemaphoreRelease(jt808_send_ack_sem); // 释放发送成功应答信号量 + JT808_DEBUG("parse success\n"); + if(PrsResult.term_param_item!= NULL){ // 协议参数项不为空 + PrsResult.term_param_item->msg_flow_num++; // 协议流水号+1 + }else{ + JT808_DEBUG("PrsResult.term_param_item is NULL\n"); + } + + }else if(ret == osErrorTimeout){ + JT808_DEBUG("parse timeout\n"); + } + }else{ + JT808_DEBUG("jt808_parse_ok_sem is NULL\n"); + } + } + } + if(MsgESC.buf!= NULL){ // 释放发送缓存 + JT808_DEBUG("jt808_free MsgESC.buf\n"); + jt808_free(MsgESC.buf); + MsgESC.buf = NULL; + } + } + } +} + +// jt808协议初始化 +int jt808_init(void){ + if(jt808_send_msg_queue == NULL){ + jt808_send_msg_queue = osMessageQueueNew(1, sizeof(pkg_msg_t), NULL); + } + if(jt808_send_ack_sem == NULL){ + jt808_send_ack_sem = osSemaphoreNew(1, 0, NULL); + } + if(jt808_parse_ok_sem == NULL){ + jt808_parse_ok_sem = osSemaphoreNew(1, 0, NULL); + } + osThreadAttr_t jt808_pkg_send_task_attr = { + .name = "jt808_pkg_send_task", + .stack_size = 1024, + .priority = osPriorityNormal, + }; + jt808_pkg_send_ThreadId = osThreadNew((osThreadFunc_t)jt808_pkg_send_task, 0, &jt808_pkg_send_task_attr); + osDelay(200); // 等待线程启动 + return 0; +} diff --git a/custom/jt808/src/jt808_set_TermParam.c b/custom/jt808/src/jt808_set_TermParam.c new file mode 100644 index 0000000..cec9b77 --- /dev/null +++ b/custom/jt808/src/jt808_set_TermParam.c @@ -0,0 +1,294 @@ +#include "jt808_set_TermParam.h" +#include "gps_config.h" +#include "jt808_msg_pkg.h" +#include "jt808_msg_parse.h" +#include "jt808_pkg_transmit.h" +#include "cm_sys.h" +#include "cm_sim.h" + +Term_Param_item_t jt808_term_param_item; // 终端参数项 + +// 控制车辆状态 +void jt808_Set_CarStatus(uint8_t status){ + // (void)status; + // TODO: 车辆控制状态 +} + +// 获取车辆状态 +uint8_t jt808_Get_CarStatus(void){ + // TODO: 车辆控制状态 + return 0; +} + + +// 设置终端参数 +int jt808_setTermParam(set_TermParamID_t param_id, void *param, uint8_t param_len){ + switch(param_id){ + case HeartBeatInterval:{ + jt808_term_param_item.set_term_param.HeartBeatInterval =Swap32(*(uint32_t*)param); + break; + } + case MainServerAddr:{ + memcpy(jt808_term_param_item.set_term_param.MainServerAddr,param,50= 8; i--) { + if(cm_iccid[i] >= '0' && cm_iccid[i] <= '9') { + get_iccid_ok++; + }else{ + break; + } + } + JT808_DEBUG("get_iccid_ok:%d\n",get_iccid_ok); + if(get_iccid_ok == 12){ // IC CID 获取成功 + JT808_DEBUG("iccid:%d,:%s\n",strlen(cm_iccid), cm_iccid); + rawStrToBcd(jt808_term_param_item.phone_BCDnum, cm_iccid+8, 12); // 终端手机号码 + break; + }else{ + error_count++; + JT808_DEBUG("get iccid failed count:%d\n",error_count); + } + osDelay(1000 / 5); // 根据需求设置延时 + } + + jt808_term_param_item.msg_flow_num =0; + JT808_DEBUG("phone_BCDnum:"); + for(int i=0;i<6;i++){ + app_printf("%02X ",jt808_term_param_item.phone_BCDnum[i]); + } + app_printf("\n"); + }while(0); + do{// 注册信息初始化 + char read_buf[35] = {0}; + + jt808_term_param_item.big_reg_info.province_id = Swap16(0); // 省域ID + jt808_term_param_item.big_reg_info.city_id = Swap16(0); // 市域ID + memcpy(jt808_term_param_item.big_reg_info.manufacturer_id, "LAT01", 5); // 制造商ID + + while(0 != cm_sys_get_sn(read_buf)){ + JT808_DEBUG("get sn failed\n"); + osDelay(1000/5); + } + JT808_DEBUG("SN:%s\n", read_buf); + memcpy(jt808_term_param_item.big_reg_info.term_model, read_buf, 20); // 终端型号 + + while(0 != cm_sys_get_imei(read_buf)){ + JT808_DEBUG("get imei failed\n"); + osDelay(1000/5); + } + JT808_DEBUG("IMEI:%s\n", read_buf); + memcpy(jt808_term_param_item.big_reg_info.term_id, read_buf, 7); // 终端ID + + jt808_term_param_item.big_reg_info.car_plate_color = blue_plate; // 车牌颜色 + + char CarPlateNum[] ="京A12345"; // 车牌号码 + memcpy(jt808_term_param_item.big_reg_info.car_plate_num, CarPlateNum, strlen(CarPlateNum)); // 车牌号码 + }while(0); + do{// 授权信息初始化 + + char str_auth[]="auth code error..."; // 授权码 + jt808_term_param_item.big_auth_info.str_auth_code = jt808_malloc(strlen(str_auth)+1); // 授权码 + if(jt808_term_param_item.big_auth_info.str_auth_code == NULL){ + JT808_DEBUG("malloc auth_code failed\r\n"); + } + memcpy(jt808_term_param_item.big_auth_info.str_auth_code, str_auth, strlen(str_auth)+1); // 授权码 + JT808_DEBUG("auth_code:%d,%s\r\n",strlen(jt808_term_param_item.big_auth_info.str_auth_code), jt808_term_param_item.big_auth_info.str_auth_code); + // jt808_free(jt808_term_param_item.big_auth_info.str_auth_code); + // jt808_term_param_item.big_auth_info.str_auth_code = NULL; + }while(0); + do{// 终端参数初始化 + jt808_term_param_item.set_term_param.HeartBeatInterval = 5; // 心跳包间隔(秒) + char ServerAddr[] ="47.99.118.34"; // 车牌号码 + uint32_t ServerPort = 5000; // 服务器端口 + // char ServerAddr[] ="36.137.226.30"; // 车牌号码 + // uint32_t ServerPort = 36204; // 服务器端口 + // memset(jt808_term_param_item.set_term_param.MainServerAddr, 0, 50); + memcpy(jt808_term_param_item.set_term_param.MainServerAddr, ServerAddr, strlen(ServerAddr)+1); // 主服务器地址 + jt808_term_param_item.set_term_param.ServerPort = ServerPort; // 服务器端口 + jt808_term_param_item.set_term_param.DefaultTimeReportInterval = 60; // 默认时间上报间隔(秒) + jt808_term_param_item.set_term_param.InflexionAngle = 0; // 俯仰角(度) + jt808_term_param_item.set_term_param.MaxSpeed = 0; // 最大速度(km/h) + jt808_term_param_item.set_term_param.ProvinceID = 0; // 省域ID + jt808_term_param_item.set_term_param.CityID = 0; // 市域ID + jt808_term_param_item.set_term_param.CarPlateNum[0] = 0; // 车牌号码 + jt808_term_param_item.set_term_param.CarPlateColor = 0; // 车牌颜色 + }while(0); + do{// 位置信息上报初始化 + memset(&jt808_term_param_item.big_loc_report.basic_info,0,sizeof(Loc_basic_info_t)); + jt808_term_param_item.big_loc_report.basic_info.status.val32 = 0; // 状态信息 + jt808_term_param_item.big_loc_report.basic_info.alarm_flag.val32 = 0; // 报警标志 + }while(0); + PrsResult.term_param_item =&jt808_term_param_item;// 全局变量指针指向终端参数项 + + // JT808_DEBUG("auth_code:%s\r\n",PrsResult.term_param_item->big_auth_info.str_auth_code); +} + +// 释放终端参数 +void jt808_set_term_param_free(void){ + if(jt808_term_param_item.big_auth_info.str_auth_code != NULL){ // 释放授权码 + jt808_free(jt808_term_param_item.big_auth_info.str_auth_code); + jt808_term_param_item.big_auth_info.str_auth_code = NULL; + } + if(jt808_term_param_item.big_specific_params.param_id_list != NULL){ // 释放特定参数列表 + jt808_free(jt808_term_param_item.big_specific_params.param_id_list); + jt808_term_param_item.big_specific_params.param_id_list = NULL; + } + if(jt808_term_param_item.big_ctrl_info.str_cmd_params != NULL){ // 释放控制命令参数 + jt808_free(jt808_term_param_item.big_ctrl_info.str_cmd_params); + jt808_term_param_item.big_ctrl_info.str_cmd_params = NULL; + } + if(jt808_term_param_item.big_upgrade_info.str_upgrade_pkg != NULL){ // 释放残留升级包内存 + jt808_free(jt808_term_param_item.big_upgrade_info.str_upgrade_pkg); + jt808_term_param_item.big_upgrade_info.str_upgrade_pkg = NULL; + } + if(jt808_term_param_item.big_upgrade_info.str_ver != NULL){ // 释放升级版本号 + jt808_free(jt808_term_param_item.big_upgrade_info.str_ver); + jt808_term_param_item.big_upgrade_info.str_ver = NULL; + } + Loc_addi_info_t *p_addi_info; // 附加信息 + Loc_addi_info_t *p_addi_info_next; // 附加信息下一个节点 + p_addi_info = jt808_term_param_item.big_loc_report.addi_info; + p_addi_info_next = p_addi_info->next; + while(p_addi_info != NULL){ // 释放附加信息列表 + jt808_free(p_addi_info); + p_addi_info = p_addi_info_next; + if(p_addi_info != NULL){ + p_addi_info_next = p_addi_info->next; + } + } + PrsResult.term_param_item = NULL; +} diff --git a/custom/jt808/src/jt808_util.c b/custom/jt808/src/jt808_util.c new file mode 100644 index 0000000..6a26864 --- /dev/null +++ b/custom/jt808/src/jt808_util.c @@ -0,0 +1,93 @@ +#include "jt808_util.h" +#include "jt808_config.h" + +// 双字节大小端转换 +uint16_t Swap16(uint16_t val16){ + return (((val16 & 0x00FF) << 8) | + ((val16 & 0xFF00) >> 8)); +} + +// 四字节大小端转换 +uint32_t Swap32(uint32_t val32){ + return (((val32 & 0x000000FF) << 24) | + ((val32 & 0x0000FF00) << 8) | + ((val32 & 0x00FF0000) >> 8) | + ((val32 & 0xFF000000) >> 24)); +} + +// 异或校验 +uint8_t BCC_Check(const uint8_t *src, uint32_t len) +{ + uint8_t bcc_check = 0; + for(uint32_t i = 0; i < len; ++i){ + bcc_check ^= src[i]; + } + return bcc_check; +} + +// 十进制转BCD码 +uint8_t DecToBcd(uint8_t Dec){ + uint8_t temp; + temp = ((Dec / 10) << 4) + (Dec % 10); + return temp; +} + +// BCD码转十进制 +uint8_t BcdToDec(uint8_t Bcd){ + uint8_t temp; + temp = (Bcd >> 4) * 10 + (Bcd & 0x0f); + return temp; +} + +// 原始字符串转BCD码 //奇数位时,首位BCD码前面补0 +uint8_t *rawStrToBcd(uint8_t *bcd, const uint8_t *str, uint16_t str_len){ + uint8_t *ptr = bcd; + uint8_t temp; + if (str_len % 2 != 0){ + *ptr++ = DecToBcd(*str++ - '0'); + } + while (*str){ + temp = *str++ - '0'; + temp *= 10; + temp += *str++ - '0'; + *ptr++ = DecToBcd(temp); + } + return bcd; +} + +// BCD转字符串,自动去掉bcd码前导零 +// bcdlen 为bcd码字节数 +uint8_t *BcdToStr(uint8_t *str, const uint8_t *bcd, int bcd_len){ + uint8_t *ptr = str; + uint8_t temp; + int cnt = bcd_len; + while (cnt--){ + temp = BcdToDec(*bcd); + *ptr++ = temp / 10 + '0'; + if(str[0] == '0'){ + ptr = str; + } + *ptr++ = temp % 10 + '0'; + if(str[0] == '0'){ + ptr = str; + } + ++bcd; + } + return str; +} + +// 原始BCD数据转字符串 +// strlen 为原始BCD数据字节数 +uint8_t *rawBcdToStr(uint8_t *str, const uint8_t *bcd, int bcd_len){ + uint8_t *ptr = str; + uint8_t temp; + int cnt = bcd_len; + while (cnt--) + { + temp = BcdToDec(*bcd); + *ptr++ = temp / 10 + '0'; + *ptr++ = temp % 10 + '0'; + ++bcd; + } + return str; +} diff --git a/custom/jt808/src/location_report.c b/custom/jt808/src/location_report.c deleted file mode 100644 index b91e624..0000000 --- a/custom/jt808/src/location_report.c +++ /dev/null @@ -1,74 +0,0 @@ -#include "location_report.h" -#include -#include "util.h" -#include "jt808_debug.h" - -// double const v_latitude = 23.123456; -// double const v_longitude = 123.123456; -// float const v_altitude=10; -// float const v_speed=10; -// float const v_bearing=100; -// unsigned char *v_timestamp = "211221213045"; - -// void initGPSInfo(struct ProtocolParameter *para, unsigned int v_alarm_value, -// unsigned int v_status_value, double const v_latitude, -// double const v_longitude, float const v_altitude, -// float const v_speed, float const v_bearing, -// unsigned char *v_timestamp) -// { -// JT808_DEBUG("\n\r[initGPSInfo] OK !\n"); -// //报警标志 -// para->location_info.alarm.value = v_alarm_value; -// JT808_DEBUG("para->alarm.value = %d\n", para->location_info.alarm.value); -// //状态 -// para->location_info.status.value = v_status_value; -// JT808_DEBUG("para->status.value = %d\n", para->location_info.status.value); - -// // if (speed >= 10) //默认车速大于等于10公里时为正常行驶状态 -// // { -// // isCarMoving.store(true); -// // } -// // else -// // { -// // isCarMoving.store(false); -// // } -// para->location_info.latitude = v_latitude * 1e6; -// JT808_DEBUG("para->latitude = %d\n", para->location_info.latitude); - -// para->location_info.longitude = v_longitude * 1e6; -// JT808_DEBUG("para->longitude = %d\n", para->location_info.longitude); - -// para->location_info.altitude = v_altitude; -// JT808_DEBUG("para->altitude = %d\n", para->location_info.altitude); - -// para->location_info.speed = v_speed * 10; -// JT808_DEBUG("para->speed = %d\n", para->location_info.speed); - -// para->location_info.bearing = v_bearing; -// JT808_DEBUG("para->bearing = %d\n", para->location_info.bearing); - -// para->location_info.time = v_timestamp; -// JT808_DEBUG("para->time = %s\n", para->location_info.time); -// } - -// void UpdateLocation(double const latitude, double const longitude, -// float const altitude, float const speed, -// float const bearing, unsigned char *timestamp) -// { -// // if (speed >= 10) //默认车速大于等于10公里时为正常行驶状态 -// // { -// // isCarMoving.store(true); -// // } -// // else -// // { -// // isCarMoving.store(false); -// // } -// para->location_info.latitude = static_cast(latitude * 1e6); -// para->location_info.longitude = static_cast(longitude * 1e6); -// para->location_info.altitude = static_cast(altitude); -// para->location_info.speed = static_cast(speed * 10); -// para->location_info.bearing = static_cast(bearing); -// para->location_info.time.assign(timestamp.begin(), timestamp.end()); - -// // spdlog::info("[{}] [{}] 更新上报位置信息 ", libjt808::getCurrentFileName(__FILE__), __LINE__); -// } diff --git a/custom/jt808/src/set_terminal_parameter.c b/custom/jt808/src/set_terminal_parameter.c index aa628b6..7a82208 100644 --- a/custom/jt808/src/set_terminal_parameter.c +++ b/custom/jt808/src/set_terminal_parameter.c @@ -1,7 +1,7 @@ #include "set_terminal_parameter.h" #include "terminal_parameter.h" #include "client_manager.h" -#include "jt808_debug.h" +#include "jt808_config.h" unsigned short kParameterSettingCMD[PARA_SETTING_LIMIT] = { kTerminalHeartBeatInterval, // DWORD, 终端心跳发送间隔(s). @@ -93,7 +93,7 @@ void handle_HeartBeatInterval(unsigned char *buf, unsigned char buf_len, struct if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * buf_len); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * buf_len); memcpy(p, buf, buf_len); memcpy(u32converter.u8array, p, buf_len); @@ -103,7 +103,7 @@ void handle_HeartBeatInterval(unsigned char *buf, unsigned char buf_len, struct JT808_DEBUG("handle_HeartBeatInterval ==== %d \r\n", para->parse.terminal_parameters.HeartBeatInterval); // FLASH_WriteByte(FLASH_ADDR , (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); - free(p); + jt808_free(p); return; } @@ -114,7 +114,7 @@ void handle_MainServerAddress(unsigned char *buf, unsigned char buf_len, struct if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * (buf_len + 1)); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * (buf_len + 1)); memcpy(p, buf, buf_len); // 字符串注意GBK转码 @@ -122,7 +122,7 @@ void handle_MainServerAddress(unsigned char *buf, unsigned char buf_len, struct memcpy(para->parse.terminal_parameters.MainServerAddress, p, buf_len); // FLASH_WriteByte(FLASH_ADDR , (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); JT808_DEBUG("handle_MainServerAddress ==== %s \r\n", para->parse.terminal_parameters.MainServerAddress); - free(p); + jt808_free(p); return; } @@ -136,7 +136,7 @@ void handle_ServerPort(unsigned char *buf, unsigned char buf_len, struct Protoco if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * buf_len); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * buf_len); memcpy(p, buf, buf_len); memcpy(u32converter.u8array, p, buf_len); @@ -145,7 +145,7 @@ void handle_ServerPort(unsigned char *buf, unsigned char buf_len, struct Protoco para->parse.terminal_parameters.ServerPort = serverPort; // FLASH_WriteByte(FLASH_ADDR , (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); JT808_DEBUG("handle_ServerPort ==== %d \r\n", para->parse.terminal_parameters.ServerPort); - free(p); + jt808_free(p); return; } @@ -158,7 +158,7 @@ void handle_DefaultTimeReportTimeInterval(unsigned char *buf, unsigned char buf_ if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * buf_len); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * buf_len); memcpy(p, buf, buf_len); memcpy(u32converter.u8array, p, buf_len); @@ -174,7 +174,7 @@ void handle_DefaultTimeReportTimeInterval(unsigned char *buf, unsigned char buf_ para->parse.terminal_parameters.DefaultTimeReportTimeInterval = DefaultTimeReportTimeInterval; // FLASH_WriteByte(FLASH_ADDR , (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); JT808_DEBUG("handle_DefaultTimeReportTimeInterval ==== %d \r\n", para->parse.terminal_parameters.DefaultTimeReportTimeInterval); - free(p); + jt808_free(p); return; } @@ -187,7 +187,7 @@ void handle_CornerPointRetransmissionAngle(unsigned char *buf, unsigned char buf if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * buf_len); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * buf_len); memcpy(p, buf, buf_len); memcpy(u32converter.u8array, p, buf_len); @@ -196,7 +196,7 @@ void handle_CornerPointRetransmissionAngle(unsigned char *buf, unsigned char buf para->parse.terminal_parameters.CornerPointRetransmissionAngle = CornerPointRetransmissionAngle; // FLASH_WriteByte(FLASH_ADDR , (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); JT808_DEBUG("handle_DefaultTimeReportTimeInterval ==== %d \r\n", para->parse.terminal_parameters.DefaultTimeReportTimeInterval); - free(p); + jt808_free(p); return; } @@ -209,7 +209,7 @@ void handle_MaxSpeed(unsigned char *buf, unsigned char buf_len, struct ProtocolP if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * buf_len); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * buf_len); memcpy(p, buf, buf_len); memcpy(u32converter.u8array, p, buf_len); @@ -218,7 +218,7 @@ void handle_MaxSpeed(unsigned char *buf, unsigned char buf_len, struct ProtocolP para->parse.terminal_parameters.MaxSpeed = MaxSpeed; // FLASH_WriteByte(FLASH_ADDR, (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); JT808_DEBUG("handle_MaxSpeed ==== %d \r\n", para->parse.terminal_parameters.MaxSpeed); - free(p); + jt808_free(p); return; } @@ -231,7 +231,7 @@ void handle_ProvinceID(unsigned char *buf, unsigned char buf_len, struct Protoco if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * buf_len); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * buf_len); memcpy(p, buf, buf_len); memcpy(u16converter.u8array, p, buf_len); @@ -240,7 +240,7 @@ void handle_ProvinceID(unsigned char *buf, unsigned char buf_len, struct Protoco para->parse.terminal_parameters.ProvinceID = ProvinceID; // FLASH_WriteByte(FLASH_ADDR , (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); JT808_DEBUG("handle_ProvinceID ==== %d \r\n", para->parse.terminal_parameters.ProvinceID); - free(p); + jt808_free(p); return; } @@ -253,7 +253,7 @@ void handle_CityID(unsigned char *buf, unsigned char buf_len, struct ProtocolPar if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * buf_len); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * buf_len); memcpy(p, buf, buf_len); memcpy(u16converter.u8array, p, buf_len); @@ -262,7 +262,7 @@ void handle_CityID(unsigned char *buf, unsigned char buf_len, struct ProtocolPar para->parse.terminal_parameters.CityID = CityID; // FLASH_WriteByte(FLASH_ADDR, (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); JT808_DEBUG("handle_CityID ==== %d \r\n", para->parse.terminal_parameters.CityID); - free(p); + jt808_free(p); return; } @@ -274,14 +274,14 @@ void handle_CarPlateNum(unsigned char *buf, unsigned char buf_len, struct Protoc if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * buf_len + 1); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * buf_len + 1); memcpy(p, buf, buf_len); memset(para->parse.terminal_parameters.CarPlateNum, 0, sizeof(para->parse.terminal_parameters.CarPlateNum)); memcpy(para->parse.terminal_parameters.CarPlateNum, p, buf_len); // FLASH_WriteByte(FLASH_ADDR , (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); JT808_DEBUG("handle_CarPlateNum ==== %s \r\n", para->parse.terminal_parameters.CarPlateNum); - free(p); + jt808_free(p); return; } @@ -292,13 +292,13 @@ void handle_CarPlateColor(unsigned char *buf, unsigned char buf_len, struct Prot // unsigned char write_buf[FLASH_BUFFER_SIZE] = {0}; if ((buf == NULL) || (buf_len == 0)) return; - p = (unsigned char *)malloc(sizeof(unsigned char) * buf_len + 1); + p = (unsigned char *)jt808_malloc(sizeof(unsigned char) * buf_len + 1); memcpy(p, buf, buf_len); para->parse.terminal_parameters.CarPlateColor = *p; // FLASH_WriteByte(FLASH_ADDR , (uint8_t *) ¶->parse.terminal_parameters , sizeof(para->parse.terminal_parameters)); JT808_DEBUG("handle_CarPlateColor ==== 0x%02x \r\n", para->parse.terminal_parameters.CarPlateColor); - free(p); + jt808_free(p); return; } diff --git a/custom/jt808/src/terminal_register.c b/custom/jt808/src/terminal_register.c index 0f2be82..3571e9e 100644 --- a/custom/jt808/src/terminal_register.c +++ b/custom/jt808/src/terminal_register.c @@ -1,6 +1,6 @@ #include "terminal_register.h" #include "string.h" -#include "jt808_debug.h" +#include "jt808_config.h" struct RegisterInfo registerInfo_; diff --git a/custom/jt808/src/util.c b/custom/jt808/src/util.c index 303e8af..d0b65e8 100644 --- a/custom/jt808/src/util.c +++ b/custom/jt808/src/util.c @@ -1,7 +1,7 @@ #include "util.h" #include "protocol_parameter.h" #include "client_manager.h" -#include "jt808_debug.h" +#include "jt808_config.h" union U16ToU8Array u16converter; union U32ToU8Array u32converter; diff --git a/custom/local_tts/inc/local_tts.h b/custom/local_tts/inc/local_tts.h new file mode 100644 index 0000000..f5c2edf --- /dev/null +++ b/custom/local_tts/inc/local_tts.h @@ -0,0 +1,27 @@ +#ifndef __LOCAL_TTS_H__ +#define __LOCAL_TTS_H__ +#include +#include +#include +#include +#include "cm_local_tts.h" + + + +void local_tts_init(void); + +// 静音 mute: 0-关闭 1-打开 +void local_tts_mute(uint8_t mute); + +// 音量设置 volume: 0-100 +uint8_t local_tts_volume(uint8_t volume); + +// speed: 语速,取值范围0-15,默认为5 +// volume: 音量,取值范围0-15,默认为5 +// mode: 0-自动模式 1-数字模式,2-数值模式 +void local_tts_set(int32_t speed, int32_t volume, cm_local_tts_digit_e mode); + +// 本地TTS播放 +int8_t local_tts_text_play(char *text, uint8_t len, uint32_t timeout); + +#endif // __LOCAL_TTS_H__ \ No newline at end of file diff --git a/custom/local_tts/local_tts.mk b/custom/local_tts/local_tts.mk new file mode 100644 index 0000000..4cce087 --- /dev/null +++ b/custom/local_tts/local_tts.mk @@ -0,0 +1,6 @@ + +CUSTOM_MAIN_DIR := custom/local_tts + +OC_FILES += $(CUSTOM_MAIN_DIR)/src/local_tts.c + +INC += -I'$(CUSTOM_MAIN_DIR)/inc' \ No newline at end of file diff --git a/custom/local_tts/src/local_tts.c b/custom/local_tts/src/local_tts.c new file mode 100644 index 0000000..1a08d7c --- /dev/null +++ b/custom/local_tts/src/local_tts.c @@ -0,0 +1,173 @@ +#include "stdio.h" +#include "stdlib.h" +#include "cm_fs.h" +#include "cm_mem.h" +#include "cm_sys.h" +#include "cm_gpio.h" +#include "cm_iomux.h" +#include "cm_modem.h" + +#include "cm_audio_player.h" +#include "cm_audio_recorder.h" +#include "cm_local_tts.h" + +#include "local_tts.h" + +#if 1 +#include "app_uart.h" +#define DEBUG(fmt, args...) app_printf("[tts]" fmt, ##args) +#else +#define DEBUG(fmt, arg...) +#endif +static osMessageQueueId_t local_tts_play_queue = NULL; +static osSemaphoreId_t local_tts_play_ok_sem = NULL; + +/* 离线TTS回调函数 */ +static void __local_tts_callback(cm_local_tts_event_e event, void *param) +{ + switch(event){ + case CM_LOCAL_TTS_EVENT_SYNTH_DATA:{ + // cm_local_tts_synth_data_t *data = (cm_local_tts_synth_data_t *)param; + // DEBUG("[%s] SYNTH_DATA [%d] \n", data->user, data->len); //打印log操作较费时 + break; + } + case CM_LOCAL_TTS_EVENT_SYNTH_FAIL: + case CM_LOCAL_TTS_EVENT_SYNTH_INTERRUPT: + case CM_LOCAL_TTS_EVENT_SYNTH_FINISH: + break; + case CM_LOCAL_TTS_EVENT_PLAY_FAIL: + DEBUG("[%s] PLAY_FAIL\n", (char *)param); + break; + case CM_LOCAL_TTS_EVENT_PLAY_INTERRUPT: + DEBUG("[[%s] PLAY_INTERRUPT\n", (char *)param); + break; + case CM_LOCAL_TTS_EVENT_PLAY_FINISH: + DEBUG("[%s] PLAY_FINISH\n", (char *)param); + osSemaphoreRelease(local_tts_play_ok_sem); // 释放发送成功应答信号量 + break; + default: + break; + } +} + +// 静音 mute: 0-关闭 1-打开 +void local_tts_mute(uint8_t mute){ + cm_gpio_set_level(CM_GPIO_NUM_13, mute? 1 : 0); +} + +// 音量设置 volume: 0-100 +uint8_t local_tts_volume(uint8_t volume){ + uint8_t ret; + if(volume > 100){ + volume = 100; + } + cm_audio_play_set_cfg(CM_AUDIO_PLAY_CFG_VOLUME, &volume); //音量设置 0-100 + cm_audio_play_get_cfg(CM_AUDIO_PLAY_CFG_VOLUME, &ret); + DEBUG("[AUDIO] volume:%d\n", ret); + return ret; +} + +// speed: 语速,取值范围0-15,默认为5 +// volume: 音量,取值范围0-15,默认为5 +// mode: 0-自动模式 1-数字模式,2-数值模式 +void local_tts_set(int32_t speed, int32_t volume, cm_local_tts_digit_e mode){ + cm_local_tts_deinit(); + + cm_local_tts_cfg_t tts_cfg = {0}; + tts_cfg.speed = speed; + tts_cfg.volume = volume; + tts_cfg.encode = CM_LOCAL_TTS_ENCODE_TYPE_UTF8; // 离线TTS仅支持UTF8格式 + tts_cfg.digit = mode; + + if(0 == cm_local_tts_init(&tts_cfg)){ + DEBUG("tts set:speed %d,volume %d,encode %d,digit %d\n" , tts_cfg.speed, tts_cfg.volume, tts_cfg.encode, tts_cfg.digit); + }else{ + DEBUG("tts set error\n"); + } + osDelay(100/5); // 等待初始化完成 +} + + +typedef struct{ + char *text; + uint8_t len; +}tts_play_queue_t; + +// 发送本地TTS播放内容 //timeout=osWaitForever时表示等待播放完成 +int8_t local_tts_text_play(char *text, uint8_t len, uint32_t timeout){ + tts_play_queue_t tts_play_queue = {0}; + + local_tts_mute(0); // 取消静音 + + if(0 == len || len > strlen(text)){ + len = strlen(text); + DEBUG("tts play text len > len:%d \n", len); + } + tts_play_queue.text = cm_malloc(len + 1); + if(tts_play_queue.text == NULL){ + DEBUG("tts play malloc error\n"); + return -1; + } + memcpy(tts_play_queue.text, text, len); + tts_play_queue.text[len] = '\0'; + tts_play_queue.len = len; + if(osOK != osMessageQueuePut(local_tts_play_queue, &tts_play_queue, 0, 0)){ + DEBUG("tts play queue put error\n"); + cm_free(tts_play_queue.text); + return -1; + } + // 等待播放完成 + osSemaphoreAcquire(local_tts_play_ok_sem, timeout); + DEBUG("tts play queue put success\n"); + return 0; +} + +// 异步播放,播放完成后播放下一条 //TODO: 待优化(暂时方案,打断播放) +static osThreadFunc_t local_tts_play_task(void *arg){ + tts_play_queue_t tts_play_queue; + + while(1){ + if(osOK == osMessageQueueGet(local_tts_play_queue, &tts_play_queue, NULL, osWaitForever)){ // + DEBUG("tts play stop\n"); + cm_local_tts_play_stop(); // 停止播放 + osDelay(200/5); // 等待播放停止 + if(tts_play_queue.text == NULL){ + DEBUG("tts play text is null\n"); + continue; + } + DEBUG("tts play start\n"); + cm_local_tts_play(tts_play_queue.text, tts_play_queue.len, __local_tts_callback,"Chinese"); + cm_free(tts_play_queue.text); + tts_play_queue.text = NULL; + } + } + return 0; +} + +// 初始化 +void local_tts_init(void){ + cm_gpio_cfg_t cfg = {0}; + cfg.direction = CM_GPIO_DIRECTION_OUTPUT; + cfg.pull = CM_GPIO_PULL_UP; + + cm_iomux_set_pin_func(CM_IOMUX_PIN_77, CM_IOMUX_FUNC_FUNCTION2);//初始化之前一定要先设置引脚复用 + cm_gpio_init(CM_GPIO_NUM_13, &cfg); + + local_tts_mute(1); // 关闭静音 + local_tts_volume(100); // 设置音量为50 + + local_tts_set(7, 5, CM_LOCAL_TTS_DIGIT_AUTO); // 设置TTS转换参数 + + if(local_tts_play_queue == NULL){ + local_tts_play_queue = osMessageQueueNew(10, sizeof(tts_play_queue_t), NULL); + } + if(local_tts_play_ok_sem == NULL){ + local_tts_play_ok_sem = osSemaphoreNew(1, 0, NULL); + } + osThreadAttr_t local_tts_play_thread_attr = { + .name = "local_tts_play_thread", + .stack_size = 4096 * 4, + .priority = osPriorityNormal + }; + osThreadNew((osThreadFunc_t)local_tts_play_task, NULL, &local_tts_play_thread_attr); +} diff --git a/custom/nmealib/inc/nmea/config.h b/custom/nmealib/inc/nmea/config.h index 6e86a15..f3bf4b4 100644 --- a/custom/nmealib/inc/nmea/config.h +++ b/custom/nmealib/inc/nmea/config.h @@ -49,8 +49,8 @@ #endif #include "cm_mem.h" -#define name_malloc(size) cm_malloc(size) -#define name_free(ptr) cm_free(ptr) +#define name_malloc(size) malloc(size) +#define name_free(ptr) free(ptr) #endif /* __NMEA_CONFIG_H__ */ diff --git a/custom/tcp_client/inc/tcp_client.h b/custom/tcp_client/inc/tcp_client.h new file mode 100644 index 0000000..0fd46af --- /dev/null +++ b/custom/tcp_client/inc/tcp_client.h @@ -0,0 +1,25 @@ +#ifndef __TCP_CLIENT_H__ +#define __TCP_CLIENT_H__ +#include +#include +#include +#include "string.h" +#include "cm_os.h" + +#define TCP_HOST "36.137.226.30" //TCP地址 例"192.168.0.1" +#define TCP_PORT 38840 //TCP端口 + +// 连接TCP服务器 +int tcp_client_connect(const char *host, int port); + +// 发送数据到TCP服务器 +int tcp_client_send(const uint8_t *buf, uint16_t len); + +// 关闭TCP连接 +void tcp_client_close(void); + +// 初始化TCP客户端 +void tcp_client_init(void); + + +#endif /* __TCP_CLIENT_H__ */ \ No newline at end of file diff --git a/custom/tcp_client/src/tcp_client.c b/custom/tcp_client/src/tcp_client.c new file mode 100644 index 0000000..980416f --- /dev/null +++ b/custom/tcp_client/src/tcp_client.c @@ -0,0 +1,227 @@ +#include "lwip/lwip/netdb.h" +#include "lwip/lwip/sockets.h" +#include "cm_modem.h" +#include "cm_pm.h" + +#include "jt808_msg_pkg.h" +#include "jt808_msg_parse.h" +#include "jt808_pkg_transmit.h" +#include "jt808_set_TermParam.h" +#include "tcp_client.h" +#include "app_common.h" + + +#define TCP_CLIENT_ENABLE 1 + +#if TCP_CLIENT_ENABLE +#include "app_uart.h" +#define DEBUG(fmt, args...) app_printf("[TCP]" fmt, ##args) +#else +#define DEBUG(fmt, arg...) +#endif + +static int tcp_client_sock = -1; +static osThreadId_t tcp_recv_ThreadId = NULL; +static osThreadId_t net_manage_ThreadId = NULL; +osSemaphoreId_t netconn_disconnect_sem = NULL; // 断开连接信号量 + +// TCP接收线程 +static void tcp_recv_task(void){ + int ret = 0; + fd_set sets; + struct timeval timeout; + uint8_t buf[128] = {0}; + + while(1){ + FD_ZERO(&sets); + FD_SET(tcp_client_sock, &sets); + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + ret = select(tcp_client_sock + 1, &sets, NULL, NULL, &timeout);//监听套接字 + if(ret > 0){ // 发生状态变化,可以进行读取、写入或者有异常事件 + // DEBUG("tcp_read select ret %d\n", ret); + if(FD_ISSET(tcp_client_sock, &sets)){ // 套接字可读 + ret = recv(tcp_client_sock, buf, sizeof(buf), 0); + if(ret > 0){ + DEBUG("tcp_read recv:%d\n", ret); + for(int i = 0; i < ret; i++){ + app_printf("%02x ", buf[i]); + } + app_printf("\n\n"); + + // 处理接收到的数据 + jt808_pkg_handle(buf, ret); + memset(buf, 0, sizeof(buf)); + }else if(ret <= 0){// 连接已断开或发生错误,客户端需要执行close操作 + DEBUG("tcp_read closed %d\n", errno); + close(tcp_client_sock); + } + } + }else if(ret == 0){// select 等待超时 + // TODO + DEBUG("tcp_read_test select timeout %d\n", errno); + }else{// 走到这时当前socket已关闭,此时select将一直报错,故而挂起线程,等待重新连接后再次恢复线程 + DEBUG("tcp_recv_task Suspend %d\n", errno); + close(tcp_client_sock); + osSemaphoreRelease(netconn_disconnect_sem); // 发送断开连接信号 + osThreadSuspend(tcp_recv_ThreadId); + } + } +} + +// TCP连接 // host:服务地址,port:服务端口 +int tcp_client_connect(const char *host, int port) { + int ret = 0; + + tcp_client_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (tcp_client_sock == -1){ + DEBUG("tcp socket create error\n"); + return -1; + } + + DEBUG("tcp connect:%s, %d\n", host, port); + + struct sockaddr_in server_addr; + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_len = sizeof(server_addr); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); //端口 + server_addr.sin_addr.s_addr = inet_addr(host); //服务地址 + + ret = connect(tcp_client_sock, (const struct sockaddr *)&server_addr, sizeof(server_addr)); + if (ret == -1){ + DEBUG("tcp connect error\n"); + close(tcp_client_sock); + return -1; + }else if (ret == 0){ + /* 建立新的线程供select异步读取*/ + DEBUG("tcp connect ok\n"); + if (tcp_recv_ThreadId == NULL){ + osThreadAttr_t tcp_recv_task_attr = {0}; + tcp_recv_task_attr.name = "tcp_recv_task"; + tcp_recv_task_attr.stack_size = 1024; + tcp_recv_task_attr.priority = osPriorityNormal; + + tcp_recv_ThreadId = osThreadNew((osThreadFunc_t)tcp_recv_task, 0, &tcp_recv_task_attr); + }else{ + DEBUG("tcp_recv_task Resume %d\n", errno); + osThreadResume(tcp_recv_ThreadId); //恢复线程 + } + } + return 0; +} + +// TCP发送数据 +int tcp_client_send(const uint8_t *buf, uint16_t len){ // 不可加打印 + int ret = 0; + ret = send(tcp_client_sock, (char *)buf, len, 0); + if(ret < 0){ + DEBUG("tcp send error\n"); + // close(tcp_client_sock); + return -1; + } + // DEBUG("tcp send %d bytes\n", ret); + return 0; +} + +void tcp_client_close(void){ + if(tcp_client_sock != -1){ + close(tcp_client_sock); + tcp_client_sock = -1; + } + if(tcp_recv_ThreadId != NULL){ + osThreadSuspend(tcp_recv_ThreadId); //挂起线程 + // tcp_recv_ThreadId = NULL; + } +} + + +// 网络管理线程 +static void net_manage_task(void *arg){ + // osThreadState_t state; + + DEBUG("net_manage_task!\r\n"); + int ret = 0; + cm_cereg_state_t cereg_state = {0}; + uint8_t error_time_out = 0; + while(1){ +TCP_DISABLE: + do{// 连接服务器 + while(1){ // 等待插入SIM卡并建立网络连接 + osDelay(1000/5); + error_time_out++; + if(error_time_out > 15){ // 超时退出 + DEBUG("network connect timeout!\n"); + cm_pm_reboot(); + } + if(0 == cm_modem_get_cpin()){ // 插入SIM卡 + DEBUG("sim card ready!\r\n"); + }else{ + DEBUG("waiting for sim card...\r\n"); + } + if(0 ==cm_modem_get_cereg_state(&cereg_state)){ // 获取PS网络注册状态 + DEBUG("cereg_state:%d\n",cereg_state.state); // 注册状态 + if(cereg_state.state == 1){ // 已注册 + DEBUG("network ready\n"); + break; + }else{ + DEBUG("waiting for network...\n"); + } + }else{ + DEBUG("cereg_get_state fail!\n\n"); + } + // if(cm_modem_get_pdp_state(1) == 1){ // 网络就绪 + // app_printf("network ready\n"); + // }else{ + // app_printf("waiting for network...\n"); + // } + } + }while(0 != tcp_client_connect(PrsResult.term_param_item->set_term_param.MainServerAddr , PrsResult.term_param_item->set_term_param.ServerPort)); // 连接到TCP服务器 + DEBUG("tcp_client_connect success!\r\n"); + // jt808_pkg_send(ID_Term_GenResp,5000/5); + for(uint8_t i = 0; i < 3; i++){ // 发送3次注册、鉴权、参数设置、上报参数 + ret =jt808_pkg_send(ID_Term_Reg,8000/5);//注册终端 超时:8S + if(0 == ret){ + DEBUG("send ID_Term_Reg success!\n"); + for(uint8_t i = 0; i < 3; i++){ + ret =jt808_pkg_send(ID_Term_Auth,10000/5);//终端鉴权 超时:10S + if(0 == ret){ + DEBUG("send ID_Term_Auth success!\n"); + break; + }else{ + DEBUG("send ID_Term_Auth fail:%d!\n",ret); + if(ret == -1){ + goto TCP_DISABLE; + } + } + } + break; + }else{ + DEBUG("send ID_Term_Reg fail:%d!\n",ret); + if(ret == -1){ + goto TCP_DISABLE; + } + } + } + + jt808_Autoreport_param_start();//开启自动上报参数设置 + led_set_event(EVENT_NETWORK_READY); // 网络连接成功 + osSemaphoreAcquire(netconn_disconnect_sem, osWaitForever); // 等待断开连接信号 + jt808_Autoreport_param_stop();//停止自动上报参数设置 + led_set_event(EVENT_NETWORK_DISCONNECT); // 网络断开连接 + } +} + +void tcp_client_init(void){ + osThreadAttr_t net_manage_task_attr={ + .name = "net_manage_task", + .stack_size = 1024, + .priority = osPriorityNormal, + }; + DEBUG("tcp_client_init!\r\n"); + if(netconn_disconnect_sem == NULL){ + netconn_disconnect_sem = osSemaphoreNew(1, 0, NULL); + } + net_manage_ThreadId = osThreadNew((osThreadFunc_t)net_manage_task, 0, &net_manage_task_attr); +} \ No newline at end of file diff --git a/custom/tcp_client/tcp_client.mk b/custom/tcp_client/tcp_client.mk new file mode 100644 index 0000000..cc1f7a9 --- /dev/null +++ b/custom/tcp_client/tcp_client.mk @@ -0,0 +1,6 @@ + +CUSTOM_MAIN_DIR := custom/tcp_client + +OC_FILES += $(CUSTOM_MAIN_DIR)/src/tcp_client.c + +INC += -I'$(CUSTOM_MAIN_DIR)/inc' \ No newline at end of file diff --git a/src/cm_lib/cm_tts_play/cm_tts_play.c b/src/cm_lib/cm_tts_play/cm_tts_play.c index 8d167d1..4eca545 100644 --- a/src/cm_lib/cm_tts_play/cm_tts_play.c +++ b/src/cm_lib/cm_tts_play/cm_tts_play.c @@ -6,8 +6,16 @@ #include "cm_audio_player.h" #include "cm_audio_common.h" +#define DEBUG_ENABLE 0 -#define CM_TTS_FRAME_BUFFER_SIZE (320 * 50 * 10) //支持存放10秒数据,可修改 +#if DEBUG_ENABLE +#include "app_uart.h" +#define DEBUG(fmt, args...) app_printf("[tts]" fmt, ##args) +#else +#define DEBUG(fmt, arg...) +#endif + +#define CM_TTS_FRAME_BUFFER_SIZE (320 * 50 * 60) //支持存放10秒数据,可修改 typedef struct { osThreadId_t TaskHandle; /* TTS播放管理句柄 */ @@ -39,7 +47,7 @@ static void __cm_tts_play_callback(cm_local_tts_event_e event, void *param) { cm_tts_play_cfg.user_cb(event, param); } - //cm_log_printf(0, "[TTS] [%s] CM_LOCAL_TTS_EVENT_SYNTH_DATA [%d] \n", synth_data->user, synth_data->len); + DEBUG("[TTS] [%s] CM_LOCAL_TTS_EVENT_SYNTH_DATA [%d] \n", synth_data->user, synth_data->len); break; } case CM_LOCAL_TTS_EVENT_SYNTH_FAIL: @@ -68,7 +76,7 @@ static void __cm_tts_play_task(void *param) /* 转码速度大于播放速度,故无需考虑播放速度大于转码速度情况的延迟等待问题 */ while (index < cm_tts_play_cfg.TtsPcmBufLen && CM_LOCAL_TTS_STATE_WORKING == cm_tts_play_cfg.state) { - //cm_log_printf(0, "%s() __%d__ Length is %d, index is %d", __func__, __LINE__, cm_tts_play_cfg.TtsPcmBufLen, index); + DEBUG("%s() __%d__ Length is %d, index is %d", __func__, __LINE__, cm_tts_play_cfg.TtsPcmBufLen, index); /* 每200ms传10帧PCM数据 */ if (index + 3200 <= cm_tts_play_cfg.TtsPcmBufLen) @@ -121,7 +129,7 @@ static void __cm_tts_play_task(void *param) //cm_heap_stats_t stats = {0}; //cm_mem_get_heap_stats(&stats); - //cm_log_printf(0, "heap total:%d,remain:%d\n",stats.total_size,stats.free); + //DEBUG(0, "heap total:%d,remain:%d\n",stats.total_size,stats.free); } } @@ -147,7 +155,7 @@ int32_t cm_local_tts_play(const char *text, int32_t len, cm_local_tts_callback c //需要判断当前是否处于播放过程中,处于播放过程中报错 if (CM_LOCAL_TTS_STATE_WORKING == cm_tts_play_cfg.state) { - cm_log_printf(0, "%s() __%d__ TTS busy", __func__, __LINE__); + DEBUG("%s() __%d__ TTS busy", __func__, __LINE__); return -1; } @@ -157,7 +165,7 @@ int32_t cm_local_tts_play(const char *text, int32_t len, cm_local_tts_callback c if (NULL == cm_tts_play_cfg.TtsPcmBuf) { - cm_log_printf(0, "%s() __%d__ cm_malloc() error", __func__, __LINE__); + DEBUG("%s() __%d__ cm_malloc() error", __func__, __LINE__); return -1; } } @@ -165,10 +173,14 @@ int32_t cm_local_tts_play(const char *text, int32_t len, cm_local_tts_callback c cm_audio_sample_param_t frame = {.sample_format = CM_AUDIO_SAMPLE_FORMAT_16BIT, .rate = CM_AUDIO_SAMPLE_RATE_8000HZ, .num_channels = CM_AUDIO_SOUND_MONO}; int32_t ret = cm_audio_player_stream_open(CM_AUDIO_PLAY_FORMAT_PCM, &frame); //从pipe中播放音频(开启) - if (-1 == ret) - { - cm_log_printf(0, "%s() __%d__ cm_audio_player_stream_open() error, ret is %d", __func__, __LINE__, ret); - return -1; + if (-1 == ret){ + DEBUG("%s() __%d__ cm_audio_player_stream_open0() error, ret is %d", __func__, __LINE__, ret); + cm_audio_player_stream_close(); + ret = cm_audio_player_stream_open(CM_AUDIO_PLAY_FORMAT_PCM, &frame); //从pipe中播放音频(开启) + if (-1 == ret){ + DEBUG("%s() __%d__ cm_audio_player_stream_open1() error, ret is %d", __func__, __LINE__, ret); + return -1; + } } if (NULL == cm_tts_play_cfg.SemHandle) @@ -177,7 +189,7 @@ int32_t cm_local_tts_play(const char *text, int32_t len, cm_local_tts_callback c if (NULL == cm_tts_play_cfg.SemHandle) { - cm_log_printf(0, "%s() __%d__ osSemaphoreNew() error", __func__, __LINE__); + DEBUG("%s() __%d__ osSemaphoreNew() error", __func__, __LINE__); cm_audio_player_stream_close(); return -1; } @@ -195,7 +207,7 @@ int32_t cm_local_tts_play(const char *text, int32_t len, cm_local_tts_callback c if (NULL == cm_tts_play_cfg.TaskHandle) { - cm_log_printf(0, "%s() __%d__ osThreadNew() error", __func__, __LINE__); + DEBUG("%s() __%d__ osThreadNew() error", __func__, __LINE__); cm_audio_player_stream_close(); return -1; } @@ -225,11 +237,9 @@ int32_t cm_local_tts_play(const char *text, int32_t len, cm_local_tts_callback c * * @details 仅8M版本(ML307A-DSLN ML307A-GSLN ML305A-DS等)支持离线TTS功能 */ -int32_t cm_local_tts_play_stop(void) -{ - if (CM_LOCAL_TTS_STATE_IDLE == cm_tts_play_cfg.state) - { - cm_log_printf(0, "%s() __%d__ no TTS task", __func__, __LINE__); +int32_t cm_local_tts_play_stop(void){ + if (CM_LOCAL_TTS_STATE_IDLE == cm_tts_play_cfg.state){ + DEBUG("%s() __%d__ no TTS task", __func__, __LINE__); return -1; }