Compare commits
10 Commits
524226f4a4
...
7599a821d1
| Author | SHA1 | Date |
|---|---|---|
|
|
7599a821d1 | |
|
|
a71b3e73cc | |
|
|
799d48d0ed | |
|
|
f440f80db4 | |
|
|
1df713942d | |
|
|
f0da87e943 | |
|
|
06945aa58d | |
|
|
9e65e4a905 | |
|
|
7709d118d2 | |
|
|
f551d38609 |
|
|
@ -106,8 +106,9 @@ static void gps_TaskHandle(void *param){
|
||||||
osMutexRelease(gps_data.mutex);
|
osMutexRelease(gps_data.mutex);
|
||||||
//nmea_info2pos(&gps_data.info, &gps_data.dpos);
|
//nmea_info2pos(&gps_data.info, &gps_data.dpos);
|
||||||
gps_data.flow_num++;
|
gps_data.flow_num++;
|
||||||
DEBUG("%03d,Lat:%.09f,Lon:%.09f,Sig:%d,Fix:%d,RL=%d\n\n",
|
DEBUG("%03d,Lat:%.09f,Lon:%.09f,Sig:%d,Fix:%d,elv:%.09f,PDOP:%.09f,HDOP:%.09f,VDOP:%.09f,inview:%d,inuse:%d,speed:%.09f,direction:%.09f,Sat1Sig:%d,Sat2Sig:%d,Sat3Sig:%d,Sat4Sig:%d,Sat5Sig:%d,RL=%d\n\n",
|
||||||
it++, gps_data.latitude, gps_data.longitude, gps_data.info.sig, gps_data.info.fix, gps_rev_len
|
it++, gps_data.latitude, gps_data.longitude, gps_data.info.sig, gps_data.info.fix, gps_data.info.elv, gps_data.info.PDOP, gps_data.info.HDOP, gps_data.info.VDOP, gps_data.info.satinfo.inview, gps_data.info.satinfo.inuse, gps_data.info.speed, gps_data.info.direction,
|
||||||
|
gps_data.info.satinfo.sat[0].sig, gps_data.info.satinfo.sat[1].sig, gps_data.info.satinfo.sat[2].sig, gps_data.info.satinfo.sat[3].sig, gps_data.info.satinfo.sat[4].sig, gps_rev_len
|
||||||
);
|
);
|
||||||
|
|
||||||
if((gps_data.info.fix == 1)||(gps_data.info.sig == 0)){ // 不可用
|
if((gps_data.info.fix == 1)||(gps_data.info.sig == 0)){ // 不可用
|
||||||
|
|
@ -185,7 +186,7 @@ void gps_config_init(void){
|
||||||
CM_UART_STOP_BIT_ONE,
|
CM_UART_STOP_BIT_ONE,
|
||||||
CM_UART_FLOW_CTRL_NONE,
|
CM_UART_FLOW_CTRL_NONE,
|
||||||
CM_UART_BAUDRATE_115200,
|
CM_UART_BAUDRATE_115200,
|
||||||
0 //配置为普通串口模式,若要配置为低功耗模式可改为1
|
0 //配置为普通串口模式,若要配置为低功耗模式可改为1 确誉达默认为115200 百年星38400 大夏龙雀 9600
|
||||||
};
|
};
|
||||||
// 开启串口
|
// 开启串口
|
||||||
ret = cm_uart_open(GPS_URAT, &uart_cfg);
|
ret = cm_uart_open(GPS_URAT, &uart_cfg);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,18 @@
|
||||||
#include "cm_os.h"
|
#include "cm_os.h"
|
||||||
#include "nmea/nmea.h"
|
#include "nmea/nmea.h"
|
||||||
|
|
||||||
|
// 版本类型定义
|
||||||
|
#define VERSION_TYPE_ATTRACTION 0
|
||||||
|
#define VERSION_TYPE_FENCE 1
|
||||||
|
|
||||||
|
// 操作类型定义
|
||||||
|
#define VERSION_OP_GET 0
|
||||||
|
#define VERSION_OP_SET 1
|
||||||
|
|
||||||
|
// 鉴权码管理操作类型定义
|
||||||
|
#define AUTH_OP_GET 0 // 获取鉴权码
|
||||||
|
#define AUTH_OP_SET 1 // 设置鉴权码
|
||||||
|
#define AUTH_OP_DEL 2 // 删除鉴权码
|
||||||
|
|
||||||
|
|
||||||
// 景点信息
|
// 景点信息
|
||||||
|
|
@ -22,6 +34,22 @@ typedef struct {
|
||||||
|
|
||||||
extern const char *park_desc[];
|
extern const char *park_desc[];
|
||||||
|
|
||||||
|
// 统一的版本号管理接口
|
||||||
|
// op: 操作类型 (VERSION_OP_GET 或 VERSION_OP_SET) 0:获取版本号 1:写入版本号
|
||||||
|
// type: 版本类型 (VERSION_TYPE_ATTRACTION 或 VERSION_TYPE_FENCE) 0:景区版本号 1:电子围栏版本号
|
||||||
|
// version: 用于设置或返回版本号的指针
|
||||||
|
int attr_broadcast_manage_version(uint8_t op, uint8_t type, uint32_t* version);
|
||||||
|
|
||||||
|
// 统一的鉴权码管理接口
|
||||||
|
// op: 操作类型 (AUTH_OP_GET, AUTH_OP_SET 或 AUTH_OP_DEL)
|
||||||
|
// auth_code: 用于设置或返回鉴权码的指针
|
||||||
|
// 对于 AUTH_OP_GET: 输出参数,需要预先分配足够的内存
|
||||||
|
// 对于 AUTH_OP_SET: 输入参数,指向要设置的鉴权码字符串
|
||||||
|
// 对于 AUTH_OP_DEL: 忽略此参数
|
||||||
|
// max_len: 对于 AUTH_OP_GET: 表示 auth_code 缓冲区的最大长度
|
||||||
|
// 对于其他操作: 忽略此参数
|
||||||
|
// 返回值: 0表示成功,负数表示失败
|
||||||
|
int auth_code_manage(uint8_t op, char* auth_code, uint16_t max_len);
|
||||||
|
|
||||||
//多文字tts,景区播报专用
|
//多文字tts,景区播报专用
|
||||||
void safe_tts_play(const char* segments[], int count);
|
void safe_tts_play(const char* segments[], int count);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@
|
||||||
#include "attr_broadcast.h"
|
#include "attr_broadcast.h"
|
||||||
#include "gps_config.h"
|
#include "gps_config.h"
|
||||||
#include "local_tts.h"
|
#include "local_tts.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#include "app_uart.h"
|
#include "app_uart.h"
|
||||||
|
|
@ -33,7 +36,8 @@
|
||||||
#define TTS_PRIORITY 5 // TTS播报优先级
|
#define TTS_PRIORITY 5 // TTS播报优先级
|
||||||
#define MAX_TTS_SEGMENT_LEN 70 // TTS每段最大长度(字符)
|
#define MAX_TTS_SEGMENT_LEN 70 // TTS每段最大长度(字符)
|
||||||
#define ATTRACTIONS_FILE "attr.txt" // 区域ID列表文件
|
#define ATTRACTIONS_FILE "attr.txt" // 区域ID列表文件
|
||||||
|
#define DATA_VERSION_FILE "version.txt" // 本地数据版本文件
|
||||||
|
#define AUTH_CODE_FILE "auth_code.txt" // 鉴权码文件
|
||||||
|
|
||||||
static nmeaPARSER parser;
|
static nmeaPARSER parser;
|
||||||
|
|
||||||
|
|
@ -69,9 +73,6 @@ typedef struct {
|
||||||
} BroadcastState;
|
} BroadcastState;
|
||||||
|
|
||||||
|
|
||||||
typedef int BOOL;
|
|
||||||
#define true 1
|
|
||||||
#define false 0
|
|
||||||
|
|
||||||
const char *park_desc[] = {
|
const char *park_desc[] = {
|
||||||
"尊敬的游客欢迎来到顾村公园游玩",
|
"尊敬的游客欢迎来到顾村公园游玩",
|
||||||
|
|
@ -90,12 +91,202 @@ const char *park_desc[] = {
|
||||||
|
|
||||||
static osMutexId_t attractions_mutex = NULL;
|
static osMutexId_t attractions_mutex = NULL;
|
||||||
static AttractionNode* attractions_head = NULL;
|
static AttractionNode* attractions_head = NULL;
|
||||||
|
static osMutexId_t version_mutex = NULL;
|
||||||
|
static osMutexId_t auth_mutex = NULL;
|
||||||
static BroadcastState broadcast_state = {0};
|
static BroadcastState broadcast_state = {0};
|
||||||
static int tts_speed = 5;
|
static int tts_speed = 5;
|
||||||
static int tts_volume = 10;
|
static int tts_volume = 10;
|
||||||
static osThreadId_t Attr_Broadcast_ThreadId = NULL; //串口数据接收、解析任务Handle
|
static osThreadId_t Attr_Broadcast_ThreadId = NULL; //串口数据接收、解析任务Handle
|
||||||
|
|
||||||
|
|
||||||
|
// 统一的版本号管理接口
|
||||||
|
// op: 操作类型 (VERSION_OP_GET 或 VERSION_OP_SET)
|
||||||
|
// type: 版本类型 (VERSION_TYPE_ATTRACTION 或 VERSION_TYPE_FENCE)
|
||||||
|
// version: 用于设置或返回版本号的指针
|
||||||
|
int attr_broadcast_manage_version(uint8_t op, uint8_t type, uint32_t* version) {
|
||||||
|
if (version_mutex == NULL || version == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
osMutexAcquire(version_mutex, osWaitForever);
|
||||||
|
|
||||||
|
// 读取当前版本文件内容
|
||||||
|
uint32_t attr_version = 0, fence_version = 0;
|
||||||
|
|
||||||
|
// 检查文件是否存在
|
||||||
|
if (cm_fs_exist(DATA_VERSION_FILE)) {
|
||||||
|
int32_t fd = cm_fs_open(DATA_VERSION_FILE, CM_FS_RB);
|
||||||
|
if (fd >= 0) {
|
||||||
|
uint8_t buf[8];
|
||||||
|
if (cm_fs_read(fd, buf, sizeof(buf)) == sizeof(buf)) {
|
||||||
|
attr_version = *(uint32_t*)&buf[0];
|
||||||
|
fence_version = *(uint32_t*)&buf[4];
|
||||||
|
}
|
||||||
|
cm_fs_close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
// 根据操作类型处理
|
||||||
|
switch (op) {
|
||||||
|
case VERSION_OP_GET: // 获取版本号
|
||||||
|
if (type == VERSION_TYPE_ATTRACTION) {
|
||||||
|
*version = attr_version;
|
||||||
|
} else if (type == VERSION_TYPE_FENCE) {
|
||||||
|
*version = fence_version;
|
||||||
|
} else {
|
||||||
|
result = -2; // 无效的类型
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VERSION_OP_SET: // 设置版本号
|
||||||
|
if (type == VERSION_TYPE_ATTRACTION) {
|
||||||
|
attr_version = *version;
|
||||||
|
} else if (type == VERSION_TYPE_FENCE) {
|
||||||
|
fence_version = *version;
|
||||||
|
} else {
|
||||||
|
result = -2; // 无效的类型
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入更新后的版本号
|
||||||
|
if (result == 0) {
|
||||||
|
uint8_t buf[8];
|
||||||
|
memcpy(&buf[0], &attr_version, sizeof(attr_version));
|
||||||
|
memcpy(&buf[4], &fence_version, sizeof(fence_version));
|
||||||
|
|
||||||
|
int32_t fd = cm_fs_open(DATA_VERSION_FILE, CM_FS_WB);
|
||||||
|
if (fd < 0) {
|
||||||
|
result = -3; // 文件打开失败
|
||||||
|
} else {
|
||||||
|
if (cm_fs_write(fd, buf, sizeof(buf)) != sizeof(buf)) {
|
||||||
|
result = -4; // 写入失败
|
||||||
|
}
|
||||||
|
cm_fs_close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = -5; // 无效的操作
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osMutexRelease(version_mutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一的鉴权码管理接口
|
||||||
|
// op: 操作类型 (AUTH_OP_GET, AUTH_OP_SET 或 AUTH_OP_DEL)
|
||||||
|
// auth_code: 用于设置或返回鉴权码的指针
|
||||||
|
// 对于 AUTH_OP_GET: 输出参数,需要预先分配足够的内存
|
||||||
|
// 对于 AUTH_OP_SET: 输入参数,指向要设置的鉴权码字符串
|
||||||
|
// 对于 AUTH_OP_DEL: 忽略此参数
|
||||||
|
// max_len: 对于 AUTH_OP_GET: 表示 auth_code 缓冲区的最大长度
|
||||||
|
// 对于其他操作: 忽略此参数
|
||||||
|
// 返回值: 0表示成功,负数表示失败
|
||||||
|
int auth_code_manage(uint8_t op, char* auth_code, uint16_t max_len) {
|
||||||
|
|
||||||
|
// 初始化互斥锁
|
||||||
|
if (auth_mutex == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
osMutexAcquire(auth_mutex, osWaitForever);
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case AUTH_OP_GET: // 获取鉴权码
|
||||||
|
if (auth_code == NULL || max_len == 0) {
|
||||||
|
result = -2; // 无效的参数
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查文件是否存在
|
||||||
|
if (!cm_fs_exist(AUTH_CODE_FILE)) {
|
||||||
|
result = -3; // 文件不存在
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件大小
|
||||||
|
int32_t file_size = cm_fs_filesize(AUTH_CODE_FILE);
|
||||||
|
if (file_size <= 0) {
|
||||||
|
result = -4; // 文件为空
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保不超过提供的缓冲区大小
|
||||||
|
if (file_size >= max_len) {
|
||||||
|
result = -5; // 缓冲区太小
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取文件内容
|
||||||
|
int32_t fd = cm_fs_open(AUTH_CODE_FILE, CM_FS_RB);
|
||||||
|
if (fd < 0) {
|
||||||
|
result = -6; // 文件打开失败
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cm_fs_read(fd, auth_code, file_size) != file_size) {
|
||||||
|
cm_fs_close(fd);
|
||||||
|
result = -7; // 读取失败
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cm_fs_close(fd);
|
||||||
|
auth_code[file_size] = '\0'; // 添加字符串终止符
|
||||||
|
|
||||||
|
DEBUG("Auth code loaded from file: %s\n", auth_code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUTH_OP_SET: // 设置鉴权码
|
||||||
|
if (auth_code == NULL || strlen(auth_code) == 0) {
|
||||||
|
result = -2; // 无效的参数
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入鉴权码到文件
|
||||||
|
fd = cm_fs_open(AUTH_CODE_FILE, CM_FS_WB);
|
||||||
|
if (fd < 0) {
|
||||||
|
result = -8; // 文件打开失败
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t auth_len = strlen(auth_code);
|
||||||
|
if (cm_fs_write(fd, auth_code, auth_len) != auth_len) {
|
||||||
|
cm_fs_close(fd);
|
||||||
|
result = -9; // 写入失败
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cm_fs_close(fd);
|
||||||
|
DEBUG("Auth code saved to file: %s\n", auth_code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUTH_OP_DEL: // 删除鉴权码
|
||||||
|
if (cm_fs_exist(AUTH_CODE_FILE)) {
|
||||||
|
if (cm_fs_delete(AUTH_CODE_FILE) < 0) {
|
||||||
|
result = -10; // 删除失败
|
||||||
|
} else {
|
||||||
|
DEBUG("Auth code file deleted\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG("Auth code file does not exist, nothing to delete\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = -11; // 无效的操作
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osMutexRelease(auth_mutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 智能分段函数
|
// 智能分段函数
|
||||||
SegmentedText smart_segment_text(const char* text, int max_segment_len) {
|
SegmentedText smart_segment_text(const char* text, int max_segment_len) {
|
||||||
|
|
@ -590,7 +781,7 @@ int attr_broadcast_load_attractions(void) {
|
||||||
}
|
}
|
||||||
/******************** 关键修改:ID去重检查 ********************/
|
/******************** 关键修改:ID去重检查 ********************/
|
||||||
// 检查链表中是否已存在相同ID的景点
|
// 检查链表中是否已存在相同ID的景点
|
||||||
BOOL is_duplicate = false;
|
bool is_duplicate = false;
|
||||||
AttractionNode* current_node = attractions_head;
|
AttractionNode* current_node = attractions_head;
|
||||||
while (current_node) {
|
while (current_node) {
|
||||||
if (current_node->region_id == new_node->region_id) {
|
if (current_node->region_id == new_node->region_id) {
|
||||||
|
|
@ -734,7 +925,7 @@ static void play_attraction_info(AttractionNode* attraction, double distance) {
|
||||||
|
|
||||||
static void attr_broadcast_task(void* arg) {
|
static void attr_broadcast_task(void* arg) {
|
||||||
(void)arg; // 避免未使用参数警告
|
(void)arg; // 避免未使用参数警告
|
||||||
BOOL should_play; //是否播放最后判断量
|
bool should_play; //是否播放最后判断量
|
||||||
|
|
||||||
DEBUG("task begin\r\n");
|
DEBUG("task begin\r\n");
|
||||||
|
|
||||||
|
|
@ -799,12 +990,18 @@ void attr_broadcast_init(void) {
|
||||||
if (attractions_mutex == NULL) {
|
if (attractions_mutex == NULL) {
|
||||||
attractions_mutex = osMutexNew(NULL);
|
attractions_mutex = osMutexNew(NULL);
|
||||||
}
|
}
|
||||||
|
if (version_mutex == NULL) {
|
||||||
|
version_mutex = osMutexNew(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth_mutex == NULL) {
|
||||||
|
auth_mutex = osMutexNew(NULL);
|
||||||
|
}
|
||||||
|
// 景点文件是否存在
|
||||||
if(1 == cm_fs_exist(ATTRACTIONS_FILE))
|
if(1 == cm_fs_exist(ATTRACTIONS_FILE))
|
||||||
{
|
{
|
||||||
|
|
||||||
DEBUG("file exist\n");
|
DEBUG("attraction file exist\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -822,6 +1019,28 @@ void attr_broadcast_init(void) {
|
||||||
DEBUG("No saved attractions\n");
|
DEBUG("No saved attractions\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果版本文件不存在则创建
|
||||||
|
if (!cm_fs_exist(DATA_VERSION_FILE)) {
|
||||||
|
uint32_t init_version = 0;
|
||||||
|
// 初始化两个版本号为0
|
||||||
|
attr_broadcast_manage_version(VERSION_OP_SET, VERSION_TYPE_ATTRACTION, &init_version);
|
||||||
|
attr_broadcast_manage_version(VERSION_OP_SET, VERSION_TYPE_FENCE, &init_version);
|
||||||
|
}
|
||||||
|
//鉴权码本地文件是否存在
|
||||||
|
if(1 == cm_fs_exist(AUTH_CODE_FILE))
|
||||||
|
{
|
||||||
|
|
||||||
|
DEBUG("attraction file exist\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int32_t fd = cm_fs_open(AUTH_CODE_FILE, CM_FS_WB);
|
||||||
|
if (fd >= 0) {
|
||||||
|
|
||||||
|
DEBUG("Created empty auth code file\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化状态
|
// 初始化状态
|
||||||
memset(&broadcast_state, 0, sizeof(broadcast_state));
|
memset(&broadcast_state, 0, sizeof(broadcast_state));
|
||||||
broadcast_state.distance_threshold = 20.0; // 默认阈值50米
|
broadcast_state.distance_threshold = 20.0; // 默认阈值50米
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
#ifndef __JT808_PKG_PARSE__
|
#ifndef __JT808_PKG_PARSE__
|
||||||
#define __JT808_PKG_PARSE__
|
#define __JT808_PKG_PARSE__
|
||||||
#include "jt808_protocol.h"
|
#include "jt808_protocol.h"
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,24 @@ typedef struct{
|
||||||
#define PKG_SEND(__buf, __len) 0
|
#define PKG_SEND(__buf, __len) 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MAX_PENDING_REQUESTS 5 // 最大并发等待请求数
|
||||||
|
|
||||||
extern PrsResult_t PrsResult;
|
extern PrsResult_t PrsResult;
|
||||||
|
|
||||||
|
// 等待请求结构体
|
||||||
|
typedef struct {
|
||||||
|
uint16_t msg_id; // 发送的消息ID
|
||||||
|
uint16_t flow_num; // 消息流水号
|
||||||
|
uint32_t timeout; // 等待超时时间(毫秒)
|
||||||
|
uint32_t start_tick; // 开始等待的时间戳
|
||||||
|
uint8_t is_waiting; // 是否在等待中(1=是,0=否)
|
||||||
|
uint8_t response_received; // 是否已收到应答(1=是,0=否)
|
||||||
|
} PendingRequest_t;
|
||||||
|
|
||||||
|
|
||||||
|
// 全局变量
|
||||||
|
static PendingRequest_t pending_requests[MAX_PENDING_REQUESTS]; // 等待请求数组
|
||||||
|
|
||||||
// 触发消息发送
|
// 触发消息发送
|
||||||
int jt808_pkg_send(MessageID_t Msg_ID, uint32_t timeout);
|
int jt808_pkg_send(MessageID_t Msg_ID, uint32_t timeout);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,9 @@ typedef enum {
|
||||||
ID_Delete_Polygon_area = 0x8605, // 删除多边形区域
|
ID_Delete_Polygon_area = 0x8605, // 删除多边形区域
|
||||||
ID_Data_Down = 0x8900, // 数据透传下行
|
ID_Data_Down = 0x8900, // 数据透传下行
|
||||||
ID_Data_Up = 0x0900, // 数据透传上行
|
ID_Data_Up = 0x0900, // 数据透传上行
|
||||||
|
ID_Req_data_update = 0x0B03, //请求电子围栏/景点更新
|
||||||
|
ID_data_update_reply = 0x8B03, //电子围栏/景点数量下发
|
||||||
|
ID_data_update_complete = 0x8B02, //电子围栏/景点更新完成
|
||||||
}MessageID_t;
|
}MessageID_t;
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
@ -169,12 +172,10 @@ typedef struct {
|
||||||
|
|
||||||
// 下发终端升级包体(0x8108)
|
// 下发终端升级包体(0x8108)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t upgrade_type; // 升级类型
|
uint8_t upgrade_type; // 升级类型(1字节)
|
||||||
uint8_t manufacturer_id[5];// 制造商ID, 固定5个字节
|
uint16_t file_crc; // 文件CRC(2字节)
|
||||||
uint8_t ver_len;// 版本号长度
|
uint8_t path_len; // 文件路径长度(1字节)
|
||||||
uint8_t *str_ver;// 版本号
|
char *file_path; // 文件路径字符串
|
||||||
uint32_t upgrade_pkg_len;// 升级包长度 单位为 BYTE
|
|
||||||
uint8_t *str_upgrade_pkg;// 升级包
|
|
||||||
}Term_Upgrade_t;
|
}Term_Upgrade_t;
|
||||||
|
|
||||||
// 终端升级结果通知体(0x0108)
|
// 终端升级结果通知体(0x0108)
|
||||||
|
|
@ -250,8 +251,8 @@ typedef union{
|
||||||
uint32_t IO_TX_brake :1; // 1:正常 0:刹车
|
uint32_t IO_TX_brake :1; // 1:正常 0:刹车
|
||||||
uint32_t A_brake :1; // 1:自动刹车,0:手动刹车
|
uint32_t A_brake :1; // 1:自动刹车,0:手动刹车
|
||||||
uint32_t A_Speed_Cut :1; // 1:自动减速,0:手动减速
|
uint32_t A_Speed_Cut :1; // 1:自动减速,0:手动减速
|
||||||
uint32_t P_Radar_EN :1; // 1:雷达使能,0:雷达禁止
|
uint32_t P_Radar_EN :2; // 1:雷达使能,0:雷达禁止
|
||||||
uint32_t retain2 : 3;// 保留10位
|
uint32_t retain2 : 2;// 保留10位
|
||||||
};
|
};
|
||||||
uint32_t val32;
|
uint32_t val32;
|
||||||
}LocStatus_t;
|
}LocStatus_t;
|
||||||
|
|
|
||||||
|
|
@ -53,13 +53,13 @@ typedef struct{
|
||||||
uint8_t CarPlateColor;//车牌颜色,按照 JT/T415-2006 的 5.4.12
|
uint8_t CarPlateColor;//车牌颜色,按照 JT/T415-2006 的 5.4.12
|
||||||
|
|
||||||
uint8_t RadarEN; // 雷达使能位, 0 代表关闭, 1 代表开启
|
uint8_t RadarEN; // 雷达使能位, 0 代表关闭, 1 代表开启
|
||||||
uint8_t ManagerACC; // 管理员模式油门0~100%
|
uint32_t ManagerACC; // 管理员模式油门0~100%
|
||||||
uint8_t TouristACC; // 游客模式油门0~100%
|
uint32_t TouristACC; // 游客模式油门0~100%
|
||||||
uint8_t SpeedCutACC; // 自动减速油门0~100%
|
uint32_t SpeedCutACC; // 自动减速油门0~100%
|
||||||
uint16_t BrakeLimit; //前进刹车距离
|
uint32_t BrakeLimit; //前进刹车距离
|
||||||
uint16_t SpeedCutLimit; // 前进自动减速刹车距离
|
uint32_t SpeedCutLimit; // 前进自动减速刹车距离
|
||||||
uint16_t BrakeLimit_B; // 后退刹车距离
|
uint32_t BrakeLimit_B; // 后退刹车距离
|
||||||
uint16_t SpeedCutLimit_B; // 后退自动减速刹车距离
|
uint32_t SpeedCutLimit_B; // 后退自动减速刹车距离
|
||||||
uint8_t Ban_Fence_Polygon_Delay_OFF; // 禁止围栏延时关闭时间, 单位秒
|
uint8_t Ban_Fence_Polygon_Delay_OFF; // 禁止围栏延时关闭时间, 单位秒
|
||||||
}set_TermParam_t;
|
}set_TermParam_t;
|
||||||
|
|
||||||
|
|
@ -104,6 +104,45 @@ typedef struct {// 终端参数项
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
|
// 更新状态枚举
|
||||||
|
typedef enum {
|
||||||
|
UPDATE_IDLE, // 空闲状态,无更新进行
|
||||||
|
UPDATE_REQUEST_SENT, // 更新请求已发送,等待响应
|
||||||
|
UPDATE_RECEIVING_DATA, // 正在接收数据
|
||||||
|
UPDATE_COMPLETE, // 最后一包数据接收完成
|
||||||
|
UPDATE_COMPLETED, // 更新完成
|
||||||
|
UPDATE_FAILED // 更新失败
|
||||||
|
} UpdateState_t;
|
||||||
|
|
||||||
|
// 更新类型
|
||||||
|
typedef enum {
|
||||||
|
UPDATE_TYPE_NONE = 0, // 无更新类型
|
||||||
|
UPDATE_TYPE_FENCE = 1, // 电子围栏更新
|
||||||
|
UPDATE_TYPE_ATTR = 2 // 景点更新
|
||||||
|
} UpdateType_t;
|
||||||
|
|
||||||
|
// 全局状态结构体
|
||||||
|
typedef struct {
|
||||||
|
UpdateState_t state; // 当前更新状态
|
||||||
|
UpdateType_t type; // 当前更新类型
|
||||||
|
uint32_t start_time; // 更新开始时间(系统滴答计数)
|
||||||
|
uint8_t retry_count; // 重试次数
|
||||||
|
uint16_t expected_packets;// 预期数据包数量
|
||||||
|
uint16_t received_packets;// 已接收数据包数量
|
||||||
|
} UpdateStatus_t;
|
||||||
|
|
||||||
|
// 终端参数转化描述结构体
|
||||||
|
typedef struct {
|
||||||
|
uint32_t param_id; // 参数ID
|
||||||
|
size_t offset; // 在set_TermParam_t中的偏移量
|
||||||
|
uint8_t param_size; // 参数大小
|
||||||
|
_Bool need_swap; // 是否需要字节序转换
|
||||||
|
} ParamDescriptor;
|
||||||
|
|
||||||
|
// 声明全局变量(在.c文件中定义)
|
||||||
|
extern UpdateStatus_t update_status;
|
||||||
|
extern osMutexId_t update_mutex;
|
||||||
|
|
||||||
extern Term_Param_item_t jt808_term_param_item;
|
extern Term_Param_item_t jt808_term_param_item;
|
||||||
|
|
||||||
extern osThreadFunc_t Autoreport_param_ThreadId;
|
extern osThreadFunc_t Autoreport_param_ThreadId;
|
||||||
|
|
@ -112,7 +151,6 @@ extern uint8_t Rsp_locked_condition; // 锁车状态, BYTE
|
||||||
|
|
||||||
extern osMutexId_t Polygon_fence_mutex; // 多边形围栏互斥锁
|
extern osMutexId_t Polygon_fence_mutex; // 多边形围栏互斥锁
|
||||||
|
|
||||||
|
|
||||||
// 控制车辆状态
|
// 控制车辆状态
|
||||||
void jt808_Set_CarStatus(uint8_t status);
|
void jt808_Set_CarStatus(uint8_t status);
|
||||||
|
|
||||||
|
|
@ -142,7 +180,69 @@ void jt808_Autoreport_param_stop(void);
|
||||||
// 初始化终端参数
|
// 初始化终端参数
|
||||||
void jt808_set_term_param_init(void);
|
void jt808_set_term_param_init(void);
|
||||||
|
|
||||||
|
// 函数声明
|
||||||
|
/**
|
||||||
|
* @brief 重置更新状态到初始值
|
||||||
|
*/
|
||||||
|
void update_manager_reset(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 启动更新流程
|
||||||
|
* @param type 更新类型 (UPDATE_TYPE_FIRMWARE/UPDATE_TYPE_CONFIG)
|
||||||
|
*/
|
||||||
|
void update_manager_start(UpdateType_t type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 标记数据接收开始
|
||||||
|
* @param packet_count 预期接收的总数据包数量
|
||||||
|
*/
|
||||||
|
void update_manager_begin_receiving(uint16_t packet_count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 标记单个数据包接收完成
|
||||||
|
* @note 当接收包数达到预期值时自动标记为完成状态
|
||||||
|
*/
|
||||||
|
void update_manager_packet_received(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 强制标记更新完成
|
||||||
|
*/
|
||||||
|
void update_manager_complete(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 标记更新失败
|
||||||
|
*/
|
||||||
|
void update_manager_fail(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查更新是否正在进行
|
||||||
|
* @return true 表示更新活跃中,false 表示空闲/完成/失败
|
||||||
|
*/
|
||||||
|
_Bool update_manager_is_active(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查更新状态是否为"最后一包数据接收完成"
|
||||||
|
* @return true 表示更新处于"最后一包数据接收完成"状态,false 表示其他状态
|
||||||
|
*/
|
||||||
|
_Bool update_manager_is_complete(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 标记无需更新
|
||||||
|
*/
|
||||||
|
void update_manager_no_update(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将 set_TermParam_t 参数转换为 TermParamlist_t 链表
|
||||||
|
* @param set_param 源参数结构体指针
|
||||||
|
* @return 成功返回参数链表头指针,失败返回NULL
|
||||||
|
*/
|
||||||
|
TermParamlist_t* convert_set_term_param_to_list(const set_TermParam_t* set_param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 释放参数链表内存
|
||||||
|
* @param head 链表头指针
|
||||||
|
*/
|
||||||
|
void free_param_list(TermParamlist_t* head);
|
||||||
|
|
||||||
|
|
||||||
#endif // JT808_SET_TERM_PARAM_H_
|
#endif // JT808_SET_TERM_PARAM_H_
|
||||||
|
|
@ -3,19 +3,45 @@
|
||||||
#include "local_tts.h"
|
#include "local_tts.h"
|
||||||
#include "jt808_electronic_fence.h"
|
#include "jt808_electronic_fence.h"
|
||||||
#include "attr_broadcast.h"
|
#include "attr_broadcast.h"
|
||||||
|
#include "cm_fota.h"
|
||||||
|
#include "cm_fs.h"
|
||||||
|
//#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
PrsResult_t PrsResult;
|
PrsResult_t PrsResult;
|
||||||
|
|
||||||
|
typedef int bool;
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
|
||||||
|
|
||||||
|
static void __cm_fota_cb(cm_fota_error_e error)
|
||||||
|
{
|
||||||
|
JT808_DEBUG("[FOTA] error code is %d\r\n", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查URL是否以http://或https://开头
|
||||||
|
static bool is_valid_url(const char *url) {
|
||||||
|
if(!url) return false;
|
||||||
|
|
||||||
|
// 检查基本协议
|
||||||
|
if(strncmp(url, "http://", 7) == 0) return true;
|
||||||
|
if(strncmp(url, "https://", 8) == 0) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 消息体解析
|
// 消息体解析
|
||||||
static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
switch (Result->msg_head.msg_id){
|
switch (Result->msg_head.msg_id){
|
||||||
case ID_Plat_GenResp:{// 平台通用应答
|
case ID_Plat_GenResp:{// 平台通用应答
|
||||||
memcpy(&(Result->Rsp_flow_num), Prsmsg_body, sizeof(Plat_GenResp_t));
|
Plat_GenResp_t resp_body;
|
||||||
|
//从消息体复制数据
|
||||||
|
memcpy(&resp_body, Prsmsg_body, sizeof(Plat_GenResp_t));
|
||||||
// 转小端
|
// 转小端
|
||||||
Result->Rsp_flow_num = Swap16(Result->msg_head.msg_flow_num);
|
Result->Rsp_flow_num = Swap16(resp_body.msg_flow_num); // 应答流水号
|
||||||
Result->Rsp_msg_id = Swap16(Result->msg_head.msg_id);
|
Result->Rsp_msg_id = Swap16(resp_body.msg_id_ack); // 应答ID
|
||||||
// Result->Rsp_result = Result->Rsp_result;
|
Result->Rsp_result = resp_body.result; // 结果
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ID_FillPktReq:{// 补传分包请求
|
case ID_FillPktReq:{// 补传分包请求
|
||||||
|
|
@ -35,8 +61,11 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
JT808_DEBUG("[%s,%s] malloc failed\r\n", __FUNCTION__,__LINE__);
|
JT808_DEBUG("[%s,%s] malloc failed\r\n", __FUNCTION__,__LINE__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
JT808_DEBUG("auth code =%s\r\n", Result->term_param_item->big_auth_info.str_auth_code);
|
||||||
memset(Result->term_param_item->big_auth_info.str_auth_code, 0, Result->msg_head.msgbody_attr.msgbodylen - 3 +1);
|
memset(Result->term_param_item->big_auth_info.str_auth_code, 0, Result->msg_head.msgbody_attr.msgbodylen - 3 +1);
|
||||||
memcpy(Result->term_param_item->big_auth_info.str_auth_code, Prsmsg_body + 3 , Result->msg_head.msgbody_attr.msgbodylen - 3);
|
memcpy(Result->term_param_item->big_auth_info.str_auth_code, Prsmsg_body + 3 , Result->msg_head.msgbody_attr.msgbodylen - 3);
|
||||||
|
// 使用统一接口保存鉴权码到文件
|
||||||
|
auth_code_manage(AUTH_OP_SET, Result->term_param_item->big_auth_info.str_auth_code, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -58,6 +87,10 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
}
|
}
|
||||||
case ID_GetTermParams:{// 查询终端参数
|
case ID_GetTermParams:{// 查询终端参数
|
||||||
|
|
||||||
|
|
||||||
|
Result->Rsp_flow_num = Result->msg_head.msg_flow_num;
|
||||||
|
Result->Rsp_msg_id = Result->msg_head.msg_id;
|
||||||
|
jt808_pkg_send(ID_GetTermParamsResp, 0);// 发送终端通用应答
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ID_GetSpecificTermParams:{// 查询指定终端参数
|
case ID_GetSpecificTermParams:{// 查询指定终端参数
|
||||||
|
|
@ -75,6 +108,121 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
}
|
}
|
||||||
case ID_Term_Upgrade:{// 下发终端升级包
|
case ID_Term_Upgrade:{// 下发终端升级包
|
||||||
|
|
||||||
|
// 确保消息体至少有4字节(升级类型1+CRC2+路径长度1)
|
||||||
|
if (Result->msg_head.msgbody_attr.msgbodylen < 4) {
|
||||||
|
JT808_DEBUG("Upgrade msg too short: %d bytes\n",
|
||||||
|
Result->msg_head.msgbody_attr.msgbodylen);
|
||||||
|
Result->Rsp_result = Msg_invalid;
|
||||||
|
} else {
|
||||||
|
uint8_t *p_body = (uint8_t *)Prsmsg_body;
|
||||||
|
|
||||||
|
// 解析固定字段
|
||||||
|
uint8_t upgrade_type = p_body[0]; // 升级类型(1字节)
|
||||||
|
uint16_t file_crc = (p_body[1] << 8) | p_body[2]; // 文件CRC(2字节)
|
||||||
|
uint8_t path_len = p_body[3]; // 路径长度(1字节)
|
||||||
|
|
||||||
|
// 移动到路径开始位置
|
||||||
|
p_body += 4;
|
||||||
|
|
||||||
|
// 验证路径长度是否匹配
|
||||||
|
if ((path_len + 4) != Result->msg_head.msgbody_attr.msgbodylen) {
|
||||||
|
JT808_DEBUG("Path len mismatch: expected %d, actual %d\n",
|
||||||
|
path_len, Result->msg_head.msgbody_attr.msgbodylen - 4);
|
||||||
|
Result->Rsp_result = Msg_invalid;
|
||||||
|
} else {
|
||||||
|
// 释放旧路径内存(如果有)
|
||||||
|
if (Result->term_param_item->big_upgrade_info.file_path != NULL) {
|
||||||
|
jt808_free(Result->term_param_item->big_upgrade_info.file_path);
|
||||||
|
Result->term_param_item->big_upgrade_info.file_path = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分配新路径内存
|
||||||
|
Result->term_param_item->big_upgrade_info.file_path = (char *)jt808_malloc(path_len + 1);
|
||||||
|
|
||||||
|
if (Result->term_param_item->big_upgrade_info.file_path == NULL) {
|
||||||
|
JT808_DEBUG("File path malloc failed (%d bytes)\n", path_len + 1);
|
||||||
|
Result->Rsp_result = Msg_err;
|
||||||
|
} else {
|
||||||
|
// 复制并添加终止符
|
||||||
|
memcpy(Result->term_param_item->big_upgrade_info.file_path, p_body, path_len);
|
||||||
|
Result->term_param_item->big_upgrade_info.file_path[path_len] = '\0';
|
||||||
|
|
||||||
|
// 更新升级信息
|
||||||
|
Result->term_param_item->big_upgrade_info.upgrade_type = upgrade_type;
|
||||||
|
Result->term_param_item->big_upgrade_info.file_crc = file_crc;
|
||||||
|
Result->term_param_item->big_upgrade_info.path_len = path_len;
|
||||||
|
|
||||||
|
JT808_DEBUG("Received upgrade cmd: type=%u, crc=0x%04X, path=%s\n",
|
||||||
|
upgrade_type, file_crc, Result->term_param_item->big_upgrade_info.file_path);
|
||||||
|
|
||||||
|
|
||||||
|
Result->Rsp_result = Msg_ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置应答并发送通用应答
|
||||||
|
Result->Rsp_flow_num = Result->msg_head.msg_flow_num;
|
||||||
|
Result->Rsp_msg_id = Result->msg_head.msg_id;
|
||||||
|
jt808_pkg_send(ID_Term_GenResp, 0);
|
||||||
|
|
||||||
|
// 启动升级处理流程(同步执行)
|
||||||
|
// start_upgrade_process(&Result->big_upgrade_info);
|
||||||
|
local_tts_text_play("软件升级流程开始,请勿断电",0,0);
|
||||||
|
local_tts_text_play("升级完成后会自动重启",0,0);
|
||||||
|
const char *url = Result->term_param_item->big_upgrade_info.file_path;
|
||||||
|
if(!is_valid_url(url)) {
|
||||||
|
JT808_DEBUG("Invalid URL: %s\n", url);
|
||||||
|
jt808_free(Result->term_param_item->big_upgrade_info.file_path);
|
||||||
|
Result->term_param_item->big_upgrade_info.file_path = NULL;
|
||||||
|
break; // 不继续升级
|
||||||
|
}
|
||||||
|
int ret = 0;
|
||||||
|
cm_fota_set_ota_plan(CM_FOTA_ASR_PLAN_MINI_INTEGRATE);
|
||||||
|
cm_fota_res_callback_register((cm_fota_result_callback)__cm_fota_cb);
|
||||||
|
|
||||||
|
ret = cm_fota_set_url(Result->term_param_item->big_upgrade_info.file_path); //设置url路径
|
||||||
|
if(0 != ret)
|
||||||
|
{
|
||||||
|
JT808_DEBUG("url error\r\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JT808_DEBUG("url right\r\n");
|
||||||
|
cm_fs_system_info_t fs_info = {0, 0};
|
||||||
|
cm_fs_getinfo(&fs_info);
|
||||||
|
|
||||||
|
JT808_DEBUG("free size =%u",fs_info.free_size);
|
||||||
|
|
||||||
|
//文件系统剩余空间为0时不建议执行升级,关键文件系统操作可能会失败
|
||||||
|
if (0 == fs_info.free_size)
|
||||||
|
{
|
||||||
|
JT808_DEBUG("insufficient space left in the file system\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#define MIN_FOTA_SPACE (4 * 1024) // 512KB
|
||||||
|
if(fs_info.free_size < MIN_FOTA_SPACE)
|
||||||
|
{
|
||||||
|
JT808_DEBUG("Insufficient space: %u < %u\n", fs_info.free_size, MIN_FOTA_SPACE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cm_fota_info_t info = {0};
|
||||||
|
cm_fota_read_config(&info);
|
||||||
|
if (CM_FOTA_TYPE_HTTP_HTTPS == info.fixed_info.fota_mode)
|
||||||
|
{
|
||||||
|
JT808_DEBUG("HTTP server [%s]\r\n", info.fixed_info.url);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JT808_DEBUG("HTTP server error\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osDelay(2000/5);
|
||||||
|
cm_fota_exec_upgrade();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ID_GetLocInfo:{// 位置信息查询
|
case ID_GetLocInfo:{// 位置信息查询
|
||||||
|
|
@ -102,13 +250,13 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
local_tts_set(speed, volume, mode);
|
local_tts_set(speed, volume, mode);
|
||||||
}else{
|
}else{
|
||||||
JT808_DEBUG("error speed or volume or mode\r\n");
|
JT808_DEBUG("error speed or volume or mode\r\n");
|
||||||
local_tts_volume(50); // 设置音量大小
|
local_tts_volume(100); // 设置音量大小
|
||||||
local_tts_set(6, 7, CM_LOCAL_TTS_DIGIT_AUTO);
|
local_tts_set(6, 7, CM_LOCAL_TTS_DIGIT_AUTO);
|
||||||
Result->Rsp_result = Msg_invalid;//消息有误
|
Result->Rsp_result = Msg_invalid;//消息有误
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
JT808_DEBUG("error speed or volume or mode\r\n");
|
JT808_DEBUG("error speed or volume or mode\r\n");
|
||||||
local_tts_volume(80); // 设置音量大小
|
local_tts_volume(100); // 设置音量大小
|
||||||
local_tts_set(7, 15, CM_LOCAL_TTS_DIGIT_AUTO);
|
local_tts_set(7, 15, CM_LOCAL_TTS_DIGIT_AUTO);
|
||||||
Result->Rsp_result = Msg_invalid;//消息有误
|
Result->Rsp_result = Msg_invalid;//消息有误
|
||||||
}
|
}
|
||||||
|
|
@ -132,10 +280,13 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ID_Set_Circle_Area:{// 设置圆形区域(0x8600)
|
case ID_Set_Circle_Area:{// 设置圆形区域(0x8600)
|
||||||
|
// 检查是否在更新流程中
|
||||||
|
bool in_update = update_manager_is_active() && update_status.state == UPDATE_RECEIVING_DATA;
|
||||||
|
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint8_t *p = (uint8_t *)Prsmsg_body;
|
uint8_t *p = (uint8_t *)Prsmsg_body;
|
||||||
|
|
||||||
|
|
||||||
// 解析固定字段
|
// 解析固定字段
|
||||||
uint32_t Area_ID = Swap32(*(uint32_t *)p);
|
uint32_t Area_ID = Swap32(*(uint32_t *)p);
|
||||||
uint16_t Area_att = Swap16(*(uint16_t *)(p + 4));
|
uint16_t Area_att = Swap16(*(uint16_t *)(p + 4));
|
||||||
|
|
@ -176,6 +327,17 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
// 释放名称内存
|
// 释放名称内存
|
||||||
if (scenic_name) jt808_free(scenic_name);
|
if (scenic_name) jt808_free(scenic_name);
|
||||||
|
|
||||||
|
// 如果在更新流程中,标记数据包接收
|
||||||
|
if (in_update) {
|
||||||
|
update_manager_packet_received();
|
||||||
|
JT808_DEBUG("Received attr packet %d/%d\n", update_status.received_packets, update_status.expected_packets);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JT808_DEBUG("Direct attr packet received, please check \r\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 设置响应结果
|
// 设置响应结果
|
||||||
Result->Rsp_result = (ret == 0) ? Msg_ok : Msg_err;
|
Result->Rsp_result = (ret == 0) ? Msg_ok : Msg_err;
|
||||||
Result->Rsp_flow_num = Result->msg_head.msg_flow_num;
|
Result->Rsp_flow_num = Result->msg_head.msg_flow_num;
|
||||||
|
|
@ -215,6 +377,10 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ID_Set_Polygon_area:{// 设置多边形区域
|
case ID_Set_Polygon_area:{// 设置多边形区域
|
||||||
|
// 检查是否在更新流程中
|
||||||
|
bool in_update = update_manager_is_active() && update_status.state == UPDATE_RECEIVING_DATA;
|
||||||
|
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint32_t Area_ID; // 区域ID
|
uint32_t Area_ID; // 区域ID
|
||||||
uint16_t Area_att; // 区域属性
|
uint16_t Area_att; // 区域属性
|
||||||
|
|
@ -229,6 +395,16 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
(AreaPoint_t *)(((uint8_t *)Prsmsg_body) + 23)); // 区域点坐标
|
(AreaPoint_t *)(((uint8_t *)Prsmsg_body) + 23)); // 区域点坐标
|
||||||
if(ret == 0){
|
if(ret == 0){
|
||||||
Result->Rsp_result = Msg_ok;
|
Result->Rsp_result = Msg_ok;
|
||||||
|
// 如果在更新流程中,标记数据包接收
|
||||||
|
if (in_update) {
|
||||||
|
update_manager_packet_received();
|
||||||
|
JT808_DEBUG("Received fence packet %d/%d\n", update_status.received_packets, update_status.expected_packets);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JT808_DEBUG("Direct fence packet received, please check\r\n");
|
||||||
|
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
Result->Rsp_result = Msg_err;
|
Result->Rsp_result = Msg_err;
|
||||||
}
|
}
|
||||||
|
|
@ -288,6 +464,111 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
||||||
// JT808_DEBUG("ID_Data_Down\r\n");
|
// JT808_DEBUG("ID_Data_Down\r\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ID_data_update_reply:{// 电子围栏/景点数量下发
|
||||||
|
if (update_manager_is_active()) {
|
||||||
|
// 检查消息体长度至少为5字节 (2+1+2)
|
||||||
|
if (Result->msg_head.msgbody_attr.msgbodylen < 5) {
|
||||||
|
JT808_DEBUG("Invalid update reply length: %d\n", Result->msg_head.msgbody_attr.msgbodylen);
|
||||||
|
Result->Rsp_result = Msg_invalid;
|
||||||
|
update_manager_fail();
|
||||||
|
} else {
|
||||||
|
uint8_t *p_body = (uint8_t *)Prsmsg_body;
|
||||||
|
|
||||||
|
// 手动组合应答流水号(2字节大端)
|
||||||
|
uint16_t reply_flow_num = (p_body[0] << 8) | p_body[1];
|
||||||
|
Result->Rsp_flow_num = reply_flow_num;
|
||||||
|
|
||||||
|
|
||||||
|
// 解析类型 (1字节)
|
||||||
|
uint8_t update_type = p_body[2];
|
||||||
|
|
||||||
|
// 手动组合围栏/景点数量(2字节大端)
|
||||||
|
uint16_t packet_count = (p_body[3] << 8) | p_body[4];
|
||||||
|
|
||||||
|
JT808_DEBUG("Update reply: type=%d, count=%d\n", update_type, packet_count);
|
||||||
|
|
||||||
|
// 验证类型是否匹配当前更新
|
||||||
|
if ((update_type == 1 && update_status.type == UPDATE_TYPE_FENCE) ||
|
||||||
|
(update_type == 2 && update_status.type == UPDATE_TYPE_ATTR)) {
|
||||||
|
|
||||||
|
if (packet_count == 0) {
|
||||||
|
// 无数据需要更新
|
||||||
|
update_manager_complete();
|
||||||
|
JT808_DEBUG("No data to update\n");
|
||||||
|
Result->Rsp_result = Msg_ok;
|
||||||
|
} else {
|
||||||
|
// 开始接收数据
|
||||||
|
update_manager_begin_receiving(packet_count);
|
||||||
|
JT808_DEBUG("Expecting %d data packets\n", packet_count);
|
||||||
|
Result->Rsp_result = Msg_ok;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 类型不匹配
|
||||||
|
JT808_DEBUG("Type mismatch: msg_type=%d, current_type=%d\n",update_type, update_status.type);
|
||||||
|
Result->Rsp_result = Msg_invalid;
|
||||||
|
update_manager_fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Result->Rsp_result = Msg_err; // 更新管理器未激活
|
||||||
|
JT808_DEBUG("Received update reply without active update\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置应答
|
||||||
|
Result->Rsp_msg_id = Result->msg_head.msg_id;
|
||||||
|
jt808_pkg_send(ID_Term_GenResp, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ID_data_update_complete:{// 电子围栏/景点更新完成
|
||||||
|
if (update_manager_is_complete()) {
|
||||||
|
// 检查消息体长度至少为5字节 (1字节类型+4字节版本号)
|
||||||
|
if (Result->msg_head.msgbody_attr.msgbodylen < 5) {
|
||||||
|
JT808_DEBUG("Invalid update complete length: %d\n", Result->msg_head.msgbody_attr.msgbodylen);
|
||||||
|
Result->Rsp_result = Msg_invalid;
|
||||||
|
update_manager_fail();
|
||||||
|
} else {
|
||||||
|
uint8_t *p_body = (uint8_t *)Prsmsg_body;
|
||||||
|
|
||||||
|
// 解析类型 (1字节)
|
||||||
|
uint8_t update_type = p_body[0];
|
||||||
|
|
||||||
|
// 解析版本号 (4字节大端) - 使用Swap32转换
|
||||||
|
uint32_t new_version = Swap32(*(uint32_t*)(p_body+1));
|
||||||
|
|
||||||
|
JT808_DEBUG("Update complete: type=%d, version=%u\n", update_type, new_version);
|
||||||
|
|
||||||
|
// 验证类型是否匹配当前更新
|
||||||
|
if ((update_type == 1 && update_status.type == UPDATE_TYPE_FENCE) ||
|
||||||
|
(update_type == 2 && update_status.type == UPDATE_TYPE_ATTR)) {
|
||||||
|
|
||||||
|
// 更新本地版本号
|
||||||
|
attr_broadcast_manage_version(
|
||||||
|
VERSION_OP_SET,
|
||||||
|
(update_type == 1) ? VERSION_TYPE_FENCE : VERSION_TYPE_ATTRACTION,
|
||||||
|
&new_version
|
||||||
|
);
|
||||||
|
|
||||||
|
update_manager_complete();
|
||||||
|
Result->Rsp_result = Msg_ok;
|
||||||
|
} else {
|
||||||
|
JT808_DEBUG("Type mismatch: msg_type=%d, current_type=%d\n",
|
||||||
|
update_type, update_status.type);
|
||||||
|
Result->Rsp_result = Msg_invalid;
|
||||||
|
update_manager_fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Result->Rsp_result = Msg_err; // 更新管理器未激活
|
||||||
|
JT808_DEBUG("Received update complete without active update\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置应答
|
||||||
|
Result->Rsp_flow_num = Result->msg_head.msg_flow_num;
|
||||||
|
Result->Rsp_msg_id = Result->msg_head.msg_id;
|
||||||
|
jt808_pkg_send(ID_Term_GenResp, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
default:{
|
default:{
|
||||||
return -2; // 没有对应的消息体解析函数
|
return -2; // 没有对应的消息体解析函数
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
#include "jt808_msg_pkg.h"
|
#include "jt808_msg_pkg.h"
|
||||||
#include "jt808_msg_parse.h"
|
#include "jt808_msg_parse.h"
|
||||||
|
#include "attr_broadcast.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 协议消息体打包(会自动为p_msg_body分配合适长度的内存,注意释放)
|
// 协议消息体打包(会自动为p_msg_body分配合适长度的内存,注意释放)
|
||||||
static int jt808_BodyPackage(JT808_2013_MsgFrame_t *p_MsgFrame, MessageID_t Msg_ID){
|
static int jt808_BodyPackage(JT808_2013_MsgFrame_t *p_MsgFrame, MessageID_t Msg_ID){
|
||||||
|
|
@ -75,13 +78,67 @@ static int jt808_BodyPackage(JT808_2013_MsgFrame_t *p_MsgFrame, MessageID_t Msg_
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ID_GetTermParamsResp:{ // 查询终端参数应答
|
case ID_GetTermParamsResp:{ // 查询终端参数应答
|
||||||
// p_MsgFrame->msg_head.msgbody_attr.msgbodylen = sizeof(GetTermParamsResp_t);// 消息体长度
|
// 将 set_term_param 转换为链表形式
|
||||||
// GetTermParamsResp_t *get_term_params_resp = (GetTermParamsResp_t *)jt808_realloc(p_MsgFrame->p_msg_body, sizeof(GetTermParamsResp_t));
|
TermParamlist_t* param_list = convert_set_term_param_to_list(&jt808_term_param_item.set_term_param);
|
||||||
// if(get_term_params_resp == NULL){
|
if (param_list == NULL) {
|
||||||
// JT808_DEBUG("[%s,%s] malloc failed \r\n", __FUNCTION__,__LINE__);
|
JT808_DEBUG("[%s,%s] convert_set_term_param_to_list failed \r\n", __FUNCTION__,__LINE__);
|
||||||
// return -1;
|
return -1;
|
||||||
// }
|
}
|
||||||
// p_MsgFrame->p_msg_body = (void *)get_term_params_resp;
|
|
||||||
|
// 计算参数总数和消息体长度
|
||||||
|
uint8_t param_total_num = 0;
|
||||||
|
uint16_t msgbody_len = 3; // msg_flow_num(2) + param_Total_num(1)
|
||||||
|
TermParamlist_t* current = param_list;
|
||||||
|
|
||||||
|
while (current != NULL) {
|
||||||
|
param_total_num++;
|
||||||
|
// 每个参数项:参数ID(4) + 参数长度(1) + 参数值(变长)
|
||||||
|
msgbody_len += 4 + 1 + current->param_len;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分配消息体缓冲区
|
||||||
|
uint8_t* msg_body_buf = (uint8_t*)jt808_malloc(msgbody_len);
|
||||||
|
if(msg_body_buf == NULL){
|
||||||
|
JT808_DEBUG("[%s,%s] malloc failed for msg_body_buf \r\n", __FUNCTION__,__LINE__);
|
||||||
|
free_param_list(param_list);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化消息体
|
||||||
|
uint16_t offset = 0;
|
||||||
|
|
||||||
|
// 1. 消息流水号 (2字节)
|
||||||
|
uint16_t flow_num_be = Swap16(PrsResult.Rsp_flow_num);
|
||||||
|
memcpy(msg_body_buf + offset, &flow_num_be, 2);
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
// 2. 参数总数 (1字节)
|
||||||
|
msg_body_buf[offset++] = param_total_num;
|
||||||
|
|
||||||
|
// 3. 参数项列表
|
||||||
|
current = param_list;
|
||||||
|
while (current != NULL) {
|
||||||
|
// 参数ID (4字节,大端)
|
||||||
|
memcpy(msg_body_buf + offset, ¤t->param_id, 4);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
// 参数长度 (1字节)
|
||||||
|
msg_body_buf[offset++] = current->param_len;
|
||||||
|
|
||||||
|
// 参数值 (变长)
|
||||||
|
memcpy(msg_body_buf + offset, current->param_value, current->param_len);
|
||||||
|
offset += current->param_len;
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放参数链表
|
||||||
|
free_param_list(param_list);
|
||||||
|
|
||||||
|
// 设置消息体长度
|
||||||
|
p_MsgFrame->msg_head.msgbody_attr.msgbodylen = msgbody_len;
|
||||||
|
p_MsgFrame->p_msg_body =msg_body_buf;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ID_GetTermAttrResp:{ // 查询终端属性应答
|
case ID_GetTermAttrResp:{ // 查询终端属性应答
|
||||||
|
|
@ -193,6 +250,49 @@ static int jt808_BodyPackage(JT808_2013_MsgFrame_t *p_MsgFrame, MessageID_t Msg_
|
||||||
// JT808_DEBUG("ID_Data_Up\r\n");
|
// JT808_DEBUG("ID_Data_Up\r\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ID_Req_data_update:{// //请求电子围栏/景点更新
|
||||||
|
// 获取当前更新类型
|
||||||
|
UpdateType_t current_type;
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
current_type = update_status.type;
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t cur_ver = 0;
|
||||||
|
uint8_t update_type = (current_type == UPDATE_TYPE_FENCE) ? 1 : 2;
|
||||||
|
|
||||||
|
// 获取对应类型的版本号
|
||||||
|
uint8_t res = attr_broadcast_manage_version(VERSION_OP_GET, (current_type == UPDATE_TYPE_FENCE) ? VERSION_TYPE_FENCE : VERSION_TYPE_ATTRACTION, &cur_ver);
|
||||||
|
|
||||||
|
if (res != 0) {
|
||||||
|
JT808_DEBUG("Failed to get version for update request\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 根据协议构造消息体 (类型1字节 + 版本4字节)
|
||||||
|
uint8_t *update_req_buf = (uint8_t *)jt808_malloc(5);
|
||||||
|
if (update_req_buf == NULL) {
|
||||||
|
JT808_DEBUG("Malloc failed for update request\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 填充消息体
|
||||||
|
update_req_buf[0] = update_type; // 更新类型 (1或2)
|
||||||
|
|
||||||
|
// 填充对应类型的版本号 (大端格式)
|
||||||
|
uint32_t version_to_send = cur_ver;
|
||||||
|
version_to_send = Swap32(version_to_send); // 转换为大端字节序
|
||||||
|
memcpy(update_req_buf + 1, &version_to_send, sizeof(uint32_t));
|
||||||
|
|
||||||
|
// 设置消息体长度
|
||||||
|
p_MsgFrame->msg_head.msgbody_attr.msgbodylen = 5;
|
||||||
|
p_MsgFrame->p_msg_body = (void *)update_req_buf;
|
||||||
|
|
||||||
|
JT808_DEBUG("Sending update request: type=%d, version=%u\n", update_type, cur_ver);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:{
|
default:{
|
||||||
return -2;
|
return -2;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,106 +1,196 @@
|
||||||
#include "jt808_pkg_transmit.h"
|
#include "jt808_pkg_transmit.h"
|
||||||
|
|
||||||
static osThreadId_t jt808_pkg_send_ThreadId;
|
static osThreadId_t jt808_pkg_send_ThreadId;
|
||||||
|
static osThreadId_t jt808_timeout_monitor_ThreadId;
|
||||||
static osMessageQueueId_t jt808_send_msg_queue = NULL;
|
static osMessageQueueId_t jt808_send_msg_queue = NULL;
|
||||||
static osSemaphoreId_t jt808_send_ack_sem = NULL; // 发送成功应答信号量
|
static osMutexId_t pending_mutex = NULL;
|
||||||
static osSemaphoreId_t jt808_parse_ok_sem = NULL; // 解析完成信号量
|
|
||||||
|
|
||||||
// 触发消息发送
|
// 超时监控任务 - 后台处理超时
|
||||||
|
static void jt808_timeout_monitor_task(void *arg) {
|
||||||
|
while (1) {
|
||||||
|
osDelay(50); // 每50ms检查一次
|
||||||
|
|
||||||
|
uint32_t current_tick = osKernelGetTickCount();
|
||||||
|
osMutexAcquire(pending_mutex, osWaitForever);
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_PENDING_REQUESTS; i++) {
|
||||||
|
if (pending_requests[i].is_waiting) {
|
||||||
|
PendingRequest_t *req = &pending_requests[i];
|
||||||
|
uint32_t elapsed = current_tick - req->start_tick;
|
||||||
|
|
||||||
|
if (req->response_received) {
|
||||||
|
JT808_DEBUG("Response OK: ID=0x%04X, Flow=%d\n",
|
||||||
|
req->msg_id, req->flow_num);
|
||||||
|
req->is_waiting = 0; // 标记槽位为空闲
|
||||||
|
}
|
||||||
|
else if (elapsed > req->timeout) {
|
||||||
|
JT808_DEBUG("Response Timeout: ID=0x%04X, Flow=%d\n",
|
||||||
|
req->msg_id, req->flow_num);
|
||||||
|
req->is_waiting = 0; // 标记槽位为空闲
|
||||||
|
|
||||||
|
// 这里可以添加超时处理逻辑,如重发
|
||||||
|
// 如果需要重发,调用 jt808_pkg_send(req->msg_id, req->timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
osMutexRelease(pending_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 触发消息发送修改版
|
||||||
int jt808_pkg_send(MessageID_t Msg_ID, uint32_t timeout){
|
int jt808_pkg_send(MessageID_t Msg_ID, uint32_t timeout){
|
||||||
pkg_msg_t send_pkg_msg={0};
|
pkg_msg_t send_pkg_msg={0};
|
||||||
send_pkg_msg.msg_id = Msg_ID;
|
send_pkg_msg.msg_id = Msg_ID;
|
||||||
send_pkg_msg.timeout = timeout;
|
send_pkg_msg.timeout = timeout;
|
||||||
// JT808_DEBUG("send pkg_msg:%04x\n", Msg_ID);
|
// JT808_DEBUG("send pkg_msg:%04x\n", Msg_ID);
|
||||||
if(osOK == osMessageQueuePut(jt808_send_msg_queue, &send_pkg_msg, 0, 0)){ //
|
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;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
// 接收处理 (放入TCP接收回调中)
|
}
|
||||||
void jt808_pkg_handle(uint8_t *receive_buf, uint16_t receive_len){
|
else
|
||||||
if(0 ==jt808_msg_parse(receive_buf, receive_len, &PrsResult)){ // 解析协议数据
|
{
|
||||||
osSemaphoreRelease(jt808_parse_ok_sem); // 释放解析完成信号量
|
return -1;
|
||||||
// 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){
|
// 接收处理 (放入TCP接收回调中)修改版
|
||||||
if(osOK == osMessageQueueGet(jt808_send_msg_queue, &send_pkg_msg, NULL, osWaitForever)){
|
void jt808_pkg_handle(uint8_t *receive_buf, uint16_t receive_len) {
|
||||||
if(0 == jt808_msg_pkg(send_pkg_msg.msg_id ,&MsgESC)){ // 生成协议数据成功
|
// 1. 解析协议数据
|
||||||
// 发送数据
|
if (0 == jt808_msg_parse(receive_buf, receive_len, &PrsResult)) {
|
||||||
if(NULL == MsgESC.buf){ // 协议数据为空(发生错误)
|
// 2. 提取接收到的消息ID和流水号 这地方根据消息id分两种情况 一种是平台应答 另一种是平台指令 平台应答需要判断结构体里的id和流水号
|
||||||
JT808_DEBUG("MsgESC.buf is NULL:len=%d\n",MsgESC.len);
|
if (PrsResult.msg_head.msg_id == ID_Plat_GenResp /*|| PrsResult.msg_head.msg_id == ID_Term_RegResp */|| PrsResult.msg_head.msg_id == ID_data_update_reply)
|
||||||
continue;
|
{
|
||||||
|
uint16_t recv_msg_id = PrsResult.Rsp_msg_id;
|
||||||
|
uint16_t recv_flow_num = PrsResult.Rsp_flow_num;
|
||||||
|
|
||||||
|
JT808_DEBUG("Recv Msg: ID=0x%04X, Flow=%d\n", recv_msg_id, recv_flow_num);
|
||||||
|
|
||||||
|
// 3. 在等待队列中查找匹配项
|
||||||
|
int matched = -1; // 匹配的请求索引
|
||||||
|
osMutexAcquire(pending_mutex, osWaitForever); // 获取互斥锁
|
||||||
|
|
||||||
|
// 遍历所有等待中的请求
|
||||||
|
for (int i = 0; i < MAX_PENDING_REQUESTS; i++) {
|
||||||
|
if ((1 == pending_requests[i].is_waiting)&&
|
||||||
|
recv_msg_id == pending_requests[i].msg_id && recv_flow_num == pending_requests[i].flow_num) // 消息ID匹配且流水号匹配
|
||||||
|
{
|
||||||
|
pending_requests[i].response_received = 1;
|
||||||
|
JT808_DEBUG("Matched response for Flow=%d\n", recv_flow_num);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// JT808_DEBUG("tcp send %d bytes\n", MsgESC.len);
|
}
|
||||||
if(0 == PKG_SEND(MsgESC.buf, MsgESC.len)){ // 发送成功处理
|
osMutexRelease(pending_mutex); // 释放互斥锁
|
||||||
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");
|
// 5. 如果不是等待中的应答,检查是否是命令消息
|
||||||
|
else //if ()
|
||||||
|
{
|
||||||
|
JT808_DEBUG("Recv Command: ID=0x%04X\n", PrsResult.msg_head.msg_id);
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
JT808_DEBUG("jt808_parse_ok_sem is NULL\n");
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//发送任务修改版
|
||||||
|
static void jt808_pkg_send_task(void *arg) {
|
||||||
|
pkg_msg_t send_pkg_msg = {0};
|
||||||
|
JT808MsgESC_t MsgESC = {0};
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// 1. 从发送队列获取消息
|
||||||
|
if (osOK == osMessageQueueGet(jt808_send_msg_queue, &send_pkg_msg, NULL, osWaitForever)) {
|
||||||
|
// 2. 生成协议数据
|
||||||
|
if (0 == jt808_msg_pkg(send_pkg_msg.msg_id, &MsgESC)) {
|
||||||
|
// 3. 发送数据
|
||||||
|
if (MsgESC.buf && (0 == PKG_SEND(MsgESC.buf, MsgESC.len))) {
|
||||||
|
PendingRequest_t *req = NULL;
|
||||||
|
|
||||||
|
// 4. 如果需要等待应答(timeout>0)
|
||||||
|
if (send_pkg_msg.timeout > 0) {
|
||||||
|
osMutexAcquire(pending_mutex, osWaitForever); // 获取互斥锁
|
||||||
|
|
||||||
|
// 5. 查找空闲槽位
|
||||||
|
int slot = -1;
|
||||||
|
for (int i = 0; i < MAX_PENDING_REQUESTS; i++) {
|
||||||
|
if (!pending_requests[i].is_waiting) {
|
||||||
|
slot = i;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 6. 创建等待请求
|
||||||
|
if (slot >= 0) {
|
||||||
|
req = &pending_requests[slot];
|
||||||
|
req->msg_id = send_pkg_msg.msg_id;
|
||||||
|
req->flow_num = PrsResult.term_param_item->msg_flow_num;
|
||||||
|
req->timeout = send_pkg_msg.timeout;
|
||||||
|
req->start_tick = osKernelGetTickCount();
|
||||||
|
req->is_waiting = 1;
|
||||||
|
req->response_received = 0;
|
||||||
|
|
||||||
|
JT808_DEBUG("Waiting: ID=0x%04X, Flow=%d, MsgID=0x%04X\n",
|
||||||
|
req->msg_id, req->flow_num, req->msg_id);
|
||||||
}
|
}
|
||||||
if(MsgESC.buf!= NULL){ // 释放发送缓存
|
osMutexRelease(pending_mutex); // 释放互斥锁
|
||||||
// JT808_DEBUG("jt808_free MsgESC.buf\n");
|
}
|
||||||
|
|
||||||
|
// 7. 递增全局流水号(无论是否等待应答)
|
||||||
|
if (PrsResult.term_param_item != NULL) {
|
||||||
|
PrsResult.term_param_item->msg_flow_num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. 释放发送缓存
|
||||||
jt808_free(MsgESC.buf);
|
jt808_free(MsgESC.buf);
|
||||||
MsgESC.buf = NULL;
|
MsgESC.buf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//jt808_free(MsgESC.buf);
|
||||||
|
//MsgESC.buf = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// jt808协议初始化
|
// jt808协议初始化
|
||||||
int jt808_init(void){
|
int jt808_init(void){
|
||||||
if(jt808_send_msg_queue == NULL){
|
if(jt808_send_msg_queue == NULL){
|
||||||
jt808_send_msg_queue = osMessageQueueNew(3, sizeof(pkg_msg_t), NULL);
|
jt808_send_msg_queue = osMessageQueueNew(5, sizeof(pkg_msg_t), NULL);
|
||||||
}
|
}
|
||||||
if(jt808_send_ack_sem == NULL){
|
|
||||||
jt808_send_ack_sem = osSemaphoreNew(1, 0, NULL);
|
// 创建互斥锁
|
||||||
|
if(pending_mutex == NULL) {
|
||||||
|
pending_mutex = osMutexNew(NULL);
|
||||||
}
|
}
|
||||||
if(jt808_parse_ok_sem == NULL){
|
|
||||||
jt808_parse_ok_sem = osSemaphoreNew(1, 0, NULL);
|
// 初始化等待请求数组
|
||||||
|
for (int i = 0; i < MAX_PENDING_REQUESTS; i++) {
|
||||||
|
pending_requests[i].is_waiting = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建发送任务
|
||||||
osThreadAttr_t jt808_pkg_send_task_attr = {
|
osThreadAttr_t jt808_pkg_send_task_attr = {
|
||||||
.name = "jt808_pkg_send_task",
|
.name = "jt808_pkg_send_task",
|
||||||
.stack_size = 4096*4,
|
.stack_size = 4096*4,
|
||||||
.priority = osPriorityNormal,
|
.priority = osPriorityNormal,
|
||||||
};
|
};
|
||||||
|
// 创建超时监控任务
|
||||||
|
osThreadAttr_t monitor_task_attr = {
|
||||||
|
.name = "jt808_monitor_task",
|
||||||
|
.stack_size = 2048,
|
||||||
|
.priority = osPriorityBelowNormal,
|
||||||
|
};
|
||||||
|
|
||||||
jt808_pkg_send_ThreadId = osThreadNew((osThreadFunc_t)jt808_pkg_send_task, 0, &jt808_pkg_send_task_attr);
|
jt808_pkg_send_ThreadId = osThreadNew((osThreadFunc_t)jt808_pkg_send_task, 0, &jt808_pkg_send_task_attr);
|
||||||
|
jt808_timeout_monitor_ThreadId = osThreadNew((osThreadFunc_t)jt808_timeout_monitor_task, 0, &monitor_task_attr);
|
||||||
// osDelay(200); // 等待线程启动
|
// osDelay(200); // 等待线程启动
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@
|
||||||
#include "cm_fs.h"
|
#include "cm_fs.h"
|
||||||
#include "cm_sim.h"
|
#include "cm_sim.h"
|
||||||
#include "cm_pm.h"
|
#include "cm_pm.h"
|
||||||
|
#include "cm_fota.h"
|
||||||
|
#include "attr_broadcast.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "local_tts.h"
|
#include "local_tts.h"
|
||||||
#include "control_out.h"
|
#include "control_out.h"
|
||||||
|
|
@ -19,33 +21,245 @@
|
||||||
#define LOCAL_FENCE_COUNT (sizeof(local_fences) / sizeof(LocalFenceConfig_t))
|
#define LOCAL_FENCE_COUNT (sizeof(local_fences) / sizeof(LocalFenceConfig_t))
|
||||||
#define __DMB() __asm__ volatile("dmb sy" ::: "memory") // GCC
|
#define __DMB() __asm__ volatile("dmb sy" ::: "memory") // GCC
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Term_Param_item_t jt808_term_param_item; // 终端参数项
|
Term_Param_item_t jt808_term_param_item; // 终端参数项
|
||||||
osMutexId_t term_param_mutex = NULL; // 终端参数项互斥锁
|
osMutexId_t term_param_mutex = NULL; // 终端参数项互斥锁
|
||||||
osMutexId_t Polygon_fence_mutex = NULL; // 多边形围栏互斥锁
|
osMutexId_t Polygon_fence_mutex = NULL; // 多边形围栏互斥锁
|
||||||
|
osMutexId_t update_mutex = NULL; //更新数据状态互斥锁
|
||||||
|
|
||||||
// 安全获取RadarEN值
|
// 定义全局变量
|
||||||
uint8_t jt808_get_radar_en(void) {
|
UpdateStatus_t update_status = {
|
||||||
// 内存屏障确保读取最新值
|
.state = UPDATE_IDLE,
|
||||||
__DMB();
|
.type = UPDATE_TYPE_NONE,
|
||||||
uint8_t value = jt808_term_param_item.set_term_param.RadarEN;
|
.start_time = 0,
|
||||||
__DMB();
|
.retry_count = 0,
|
||||||
return value;
|
.expected_packets = 0,
|
||||||
|
.received_packets = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 参数描述数组
|
||||||
|
static const ParamDescriptor param_descriptors[] = {
|
||||||
|
{ID_HeartBeatInterval, offsetof(set_TermParam_t, HeartBeatInterval), sizeof(uint32_t), 0},
|
||||||
|
{ID_RadarEN, offsetof(set_TermParam_t, RadarEN), sizeof(uint8_t), 0},
|
||||||
|
{ID_ManagerACC, offsetof(set_TermParam_t, ManagerACC), sizeof(uint32_t), 0},
|
||||||
|
{ID_TouristACC, offsetof(set_TermParam_t, TouristACC), sizeof(uint32_t), 0},
|
||||||
|
{ID_SpeedCutACC, offsetof(set_TermParam_t, SpeedCutACC), sizeof(uint32_t), 0},
|
||||||
|
{ID_BrakeLimit, offsetof(set_TermParam_t, BrakeLimit), sizeof(uint32_t), 1},
|
||||||
|
{ID_SpeedCutLimit, offsetof(set_TermParam_t, SpeedCutLimit), sizeof(uint32_t), 1},
|
||||||
|
{ID_BrakeLimit_B, offsetof(set_TermParam_t, BrakeLimit_B), sizeof(uint32_t), 1},
|
||||||
|
{ID_SpeedCutLimit_B, offsetof(set_TermParam_t, SpeedCutLimit_B), sizeof(uint32_t), 1},
|
||||||
|
{ID_Ban_Fence_Polygon_Delay_OFF, offsetof(set_TermParam_t, Ban_Fence_Polygon_Delay_OFF), sizeof(uint8_t), 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 释放参数链表
|
||||||
|
void free_param_list(TermParamlist_t* head) {
|
||||||
|
TermParamlist_t* current = head;
|
||||||
|
while (current != NULL) {
|
||||||
|
TermParamlist_t* next = current->next;
|
||||||
|
if (current->param_value != NULL) {
|
||||||
|
jt808_free(current->param_value);
|
||||||
|
}
|
||||||
|
jt808_free(current);
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 安全设置RadarEN值
|
// 添加参数到链表
|
||||||
void jt808_set_radar_en(uint8_t value) {
|
static TermParamlist_t* add_param_to_list(TermParamlist_t* tail,
|
||||||
// 验证值范围
|
uint32_t param_id,
|
||||||
if (value > 2) {
|
const void* param_value,
|
||||||
JT808_DEBUG("Invalid RadarEN value: %d", value);
|
uint8_t param_len) {
|
||||||
return;
|
TermParamlist_t* new_node = (TermParamlist_t*)jt808_malloc(sizeof(TermParamlist_t));
|
||||||
|
if (new_node == NULL) return NULL;
|
||||||
|
|
||||||
|
new_node->param_id = Swap32(param_id); // 参数ID转换为大端
|
||||||
|
new_node->param_len = param_len;
|
||||||
|
new_node->param_value = jt808_malloc(param_len);
|
||||||
|
|
||||||
|
if (new_node->param_value == NULL) {
|
||||||
|
jt808_free(new_node);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 内存屏障
|
memcpy(new_node->param_value, param_value, param_len);
|
||||||
__DMB();
|
new_node->next = NULL;
|
||||||
jt808_term_param_item.set_term_param.RadarEN = value;
|
|
||||||
__DMB();
|
|
||||||
|
|
||||||
JT808_DEBUG("Set RadarEN to %d", value);
|
if (tail != NULL) {
|
||||||
|
tail->next = new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 简化的参数转换函数
|
||||||
|
TermParamlist_t* convert_set_term_param_to_list(const set_TermParam_t* set_param) {
|
||||||
|
TermParamlist_t* head = NULL;
|
||||||
|
TermParamlist_t* tail = NULL;
|
||||||
|
|
||||||
|
// 获取参数描述符数量
|
||||||
|
size_t num_params = sizeof(param_descriptors) / sizeof(param_descriptors[0]);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_params; i++) {
|
||||||
|
const ParamDescriptor* desc = ¶m_descriptors[i];
|
||||||
|
const void* param_ptr = (const uint8_t*)set_param + desc->offset;
|
||||||
|
|
||||||
|
// 处理需要字节序转换的参数
|
||||||
|
if (desc->need_swap) {
|
||||||
|
if (desc->param_size == sizeof(uint16_t)) {
|
||||||
|
uint16_t value = *(const uint16_t*)param_ptr;
|
||||||
|
uint16_t be_value = Swap32(value);
|
||||||
|
param_ptr = &be_value;
|
||||||
|
}
|
||||||
|
// 可以添加其他大小的参数处理
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加参数到链表
|
||||||
|
TermParamlist_t* new_tail = add_param_to_list(tail, desc->param_id, param_ptr, desc->param_size);
|
||||||
|
if (new_tail == NULL) {
|
||||||
|
free_param_list(head);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (head == NULL) {
|
||||||
|
head = new_tail;
|
||||||
|
}
|
||||||
|
tail = new_tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __cm_fota_cb(cm_fota_error_e error)
|
||||||
|
{
|
||||||
|
JT808_DEBUG("[FOTA] error code is %d\r\n", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 重置更新状态
|
||||||
|
void update_manager_reset(void) {
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
update_status.state = UPDATE_IDLE;
|
||||||
|
update_status.type = UPDATE_TYPE_NONE;
|
||||||
|
update_status.start_time = 0;
|
||||||
|
update_status.retry_count = 0;
|
||||||
|
update_status.expected_packets = 0;
|
||||||
|
update_status.received_packets = 0;
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始更新流程
|
||||||
|
void update_manager_start(UpdateType_t type) {
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
update_status.state = UPDATE_REQUEST_SENT;
|
||||||
|
update_status.type = type;
|
||||||
|
update_status.start_time = osKernelGetTickCount();
|
||||||
|
update_status.retry_count = 0;
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
local_tts_text_play("更新流程开始",0,0);
|
||||||
|
JT808_DEBUG("Update started: type=%d\n", type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记数据接收开始
|
||||||
|
void update_manager_begin_receiving(uint16_t packet_count) {
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
update_status.state = UPDATE_RECEIVING_DATA;
|
||||||
|
update_status.expected_packets = packet_count;
|
||||||
|
update_status.received_packets = 0;
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
local_tts_text_play("开始接收数据",0,0);
|
||||||
|
JT808_DEBUG("Receiving %d data packets\n", packet_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记数据包接收
|
||||||
|
void update_manager_packet_received(void) {
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
if (update_status.state == UPDATE_RECEIVING_DATA) {
|
||||||
|
update_status.received_packets++;
|
||||||
|
|
||||||
|
// 检查是否所有数据包都已接收
|
||||||
|
if (update_status.received_packets >= update_status.expected_packets) {
|
||||||
|
update_status.state = UPDATE_COMPLETE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记更新完成
|
||||||
|
void update_manager_complete(void) {
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
update_status.state = UPDATE_COMPLETED;
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
local_tts_text_play("接收数据完成",0,0);
|
||||||
|
JT808_DEBUG("Update completed: type=%d\n", update_status.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记无需更新
|
||||||
|
void update_manager_no_update(void) {
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
update_status.state = UPDATE_COMPLETE;
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
|
||||||
|
JT808_DEBUG("Update completed: type=%d\n", update_status.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记更新失败
|
||||||
|
void update_manager_fail(void) {
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
update_status.state = UPDATE_FAILED;
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
|
||||||
|
JT808_DEBUG("Update failed: type=%d\n", update_status.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查更新是否正在进行
|
||||||
|
bool update_manager_is_active(void) {
|
||||||
|
bool is_active = false;
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
is_active = (update_status.state != UPDATE_IDLE &&
|
||||||
|
update_status.state != UPDATE_COMPLETED &&
|
||||||
|
update_status.state != UPDATE_FAILED);
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
return is_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在 jt808_set_TermParam.c 文件中添加函数实现
|
||||||
|
bool update_manager_is_complete(void) {
|
||||||
|
bool is_complete = false;
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
is_complete = (update_status.state == UPDATE_COMPLETE);
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
|
return is_complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 超时检查(在自动上报任务中调用)
|
||||||
|
void update_manager_check_timeout(void) {
|
||||||
|
osMutexAcquire(update_mutex, osWaitForever);
|
||||||
|
|
||||||
|
if (update_status.state == UPDATE_REQUEST_SENT ||
|
||||||
|
update_status.state == UPDATE_RECEIVING_DATA) {
|
||||||
|
|
||||||
|
uint32_t current_time = osKernelGetTickCount();
|
||||||
|
uint32_t elapsed = current_time - update_status.start_time;
|
||||||
|
|
||||||
|
// 30秒超时
|
||||||
|
if (elapsed > 30000) {
|
||||||
|
if (update_status.retry_count < 3) {
|
||||||
|
JT808_DEBUG("Update timeout, retrying (%d/3)\n", update_status.retry_count + 1);
|
||||||
|
update_status.retry_count++;
|
||||||
|
update_status.start_time = current_time;
|
||||||
|
|
||||||
|
// 这里可以触发重发机制
|
||||||
|
// resend_update_request(update_status.type);
|
||||||
|
} else {
|
||||||
|
JT808_DEBUG("Update failed after 3 retries\n");
|
||||||
|
update_status.state = UPDATE_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
osMutexRelease(update_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 控制车辆状态
|
// 控制车辆状态
|
||||||
|
|
@ -280,30 +494,7 @@ int jt808_setTermParam(set_TermParamID_t param_id, void *param, uint8_t param_le
|
||||||
}
|
}
|
||||||
case ID_RadarEN:{// TODO: 雷达使能位
|
case ID_RadarEN:{// TODO: 雷达使能位
|
||||||
// JT808_DEBUG("RadarEN=%d", radar_en);
|
// JT808_DEBUG("RadarEN=%d", radar_en);
|
||||||
|
|
||||||
jt808_term_param_item.set_term_param.RadarEN = param_val32 & 0xFF;
|
jt808_term_param_item.set_term_param.RadarEN = param_val32 & 0xFF;
|
||||||
|
|
||||||
if(2 == jt808_term_param_item.set_term_param.RadarEN)
|
|
||||||
{
|
|
||||||
|
|
||||||
JT808_DEBUG("radar ok\r\n");
|
|
||||||
sys_sta.P_Radar_EN=2;
|
|
||||||
}
|
|
||||||
else if(1 == jt808_term_param_item.set_term_param.RadarEN)
|
|
||||||
{
|
|
||||||
|
|
||||||
sys_sta.P_Radar_EN=1;
|
|
||||||
}
|
|
||||||
else if(0 == jt808_term_param_item.set_term_param.RadarEN)
|
|
||||||
{
|
|
||||||
|
|
||||||
JT808_DEBUG("radar ok\r\n");
|
|
||||||
sys_sta.P_Radar_EN=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:{
|
default:{
|
||||||
|
|
@ -418,7 +609,8 @@ uint16_t scenic_Fence_Polygon_count = 0;
|
||||||
uint16_t ban_Fence_Polygon_count = 0;
|
uint16_t ban_Fence_Polygon_count = 0;
|
||||||
uint16_t ban_unlock_count = 0;
|
uint16_t ban_unlock_count = 0;
|
||||||
uint16_t delay_off_count = 0; // 延时关闭计数
|
uint16_t delay_off_count = 0; // 延时关闭计数
|
||||||
uint8_t ban_unlock_flag = 0; //0:围栏非空 1:空围栏
|
uint8_t ban_unlock_flag = 0; //禁区开锁标志
|
||||||
|
uint8_t first_warning_flag = 0; //第一次进入禁区标志
|
||||||
|
|
||||||
|
|
||||||
uint8_t Rsp_locked_condition = 0; // 锁车状态, BYTE
|
uint8_t Rsp_locked_condition = 0; // 锁车状态, BYTE
|
||||||
|
|
@ -488,8 +680,12 @@ void jt808_LocReport_param_update(void){
|
||||||
// lng = 121369446;
|
// lng = 121369446;
|
||||||
flag=jt808_is_fence_empty();
|
flag=jt808_is_fence_empty();
|
||||||
|
|
||||||
|
if(0 == flag)
|
||||||
|
{
|
||||||
JT808_DEBUG("list not null\r\n");
|
JT808_DEBUG("list not null\r\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Rsp_Bigscenic_Fence_Polygon_area_ID = Swap32(jt808_Polygon_fence_check(0x0001, lat, lng));
|
Rsp_Bigscenic_Fence_Polygon_area_ID = Swap32(jt808_Polygon_fence_check(0x0001, lat, lng));
|
||||||
Rsp_Bigban_Fence_Polygon_area_ID = Swap32(jt808_Polygon_fence_check(0x0002, lat, lng));
|
Rsp_Bigban_Fence_Polygon_area_ID = Swap32(jt808_Polygon_fence_check(0x0002, lat, lng));
|
||||||
|
|
||||||
|
|
@ -534,10 +730,22 @@ void jt808_LocReport_param_update(void){
|
||||||
jt808_pkg_send(ID_LocReport,10000/5); // 发送位置信息上报包
|
jt808_pkg_send(ID_LocReport,10000/5); // 发送位置信息上报包
|
||||||
}
|
}
|
||||||
ban_Fence_Polygon_count++;
|
ban_Fence_Polygon_count++;
|
||||||
if((ban_Fence_Polygon_count >= 2) && (0 == flag)){ // 2S
|
if((ban_Fence_Polygon_count >= 3) && (0 == flag)){ // 2S
|
||||||
ban_Fence_Polygon_count = 0;
|
ban_Fence_Polygon_count = 0;
|
||||||
|
// if(first_warning_flag == 0)
|
||||||
|
// {
|
||||||
|
// first_warning_flag = 1; //第一次进入禁区
|
||||||
|
// local_tts_text_play("您已进入禁区,请尽快离开!",0,0);
|
||||||
|
// jt808_pkg_send(ID_LocReport,10000/5); // 发送位置信息上报包
|
||||||
|
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
local_tts_text_play("您已进入禁区,请尽快离开!",0,0);
|
local_tts_text_play("您已进入禁区,请尽快离开!",0,0);
|
||||||
jt808_pkg_send(ID_LocReport,10000/5); // 发送位置信息上报包
|
jt808_pkg_send(ID_LocReport,10000/5); // 发送位置信息上报包
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -547,6 +755,8 @@ void jt808_LocReport_param_update(void){
|
||||||
ban_Fence_Polygon_count = 0;
|
ban_Fence_Polygon_count = 0;
|
||||||
ban_unlock_count = 0;
|
ban_unlock_count = 0;
|
||||||
ban_unlock_flag = 0;
|
ban_unlock_flag = 0;
|
||||||
|
first_warning_flag = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
scenic_Fence_Polygon_count = 0;
|
scenic_Fence_Polygon_count = 0;
|
||||||
|
|
@ -556,7 +766,6 @@ void jt808_LocReport_param_update(void){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JT808_DEBUG("list null\r\n");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
osMutexRelease(term_param_mutex);
|
osMutexRelease(term_param_mutex);
|
||||||
|
|
@ -615,6 +824,16 @@ void Autoreport_param_Task(void *arg){
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while(1){
|
while(1){
|
||||||
|
|
||||||
|
|
||||||
|
// 检查超时
|
||||||
|
update_manager_check_timeout();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!update_manager_is_active())
|
||||||
|
{
|
||||||
|
// 正常的自动上报逻辑
|
||||||
osMutexAcquire(gps_data.mutex, osWaitForever);
|
osMutexAcquire(gps_data.mutex, osWaitForever);
|
||||||
memcpy(&gps_data_msg, &gps_data, sizeof(gps_data_t));
|
memcpy(&gps_data_msg, &gps_data, sizeof(gps_data_t));
|
||||||
osMutexRelease(gps_data.mutex);
|
osMutexRelease(gps_data.mutex);
|
||||||
|
|
@ -653,6 +872,46 @@ void Autoreport_param_Task(void *arg){
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 在15秒时发送电子围栏更新请求
|
||||||
|
if (count_Sec == 15) {
|
||||||
|
if (!update_manager_is_active()) {
|
||||||
|
uint32_t fence_ver = 0;
|
||||||
|
int res = attr_broadcast_manage_version(VERSION_OP_GET, VERSION_TYPE_FENCE, &fence_ver);
|
||||||
|
|
||||||
|
if (res == 0) {
|
||||||
|
update_manager_start(UPDATE_TYPE_FENCE);
|
||||||
|
jt808_pkg_send(ID_Req_data_update, 200); // 发送围栏更新请求
|
||||||
|
JT808_DEBUG("Sending fence update request, version=%u\n", fence_ver);
|
||||||
|
} else {
|
||||||
|
JT808_DEBUG("Failed to get fence version: %d\n", res);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JT808_DEBUG("Skipping fence request: update already active\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在45秒时发送景点更新请求
|
||||||
|
if (count_Sec == 45) {
|
||||||
|
if (!update_manager_is_active()) {
|
||||||
|
uint32_t attr_ver = 0;
|
||||||
|
int res = attr_broadcast_manage_version(VERSION_OP_GET, VERSION_TYPE_ATTRACTION, &attr_ver);
|
||||||
|
|
||||||
|
if (res == 0) {
|
||||||
|
update_manager_start(UPDATE_TYPE_ATTR);
|
||||||
|
jt808_pkg_send(ID_Req_data_update, 200); // 发送景点更新请求
|
||||||
|
JT808_DEBUG("Sending attraction update request, version=%u\n", attr_ver);
|
||||||
|
} else {
|
||||||
|
JT808_DEBUG("Failed to get attraction version: %d\n", res);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JT808_DEBUG("Skipping attraction request: update already active\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
count_Sec++;
|
count_Sec++;
|
||||||
osDelay(1000/5); // 1S
|
osDelay(1000/5); // 1S
|
||||||
}
|
}
|
||||||
|
|
@ -686,6 +945,7 @@ void jt808_set_term_param_init(void){
|
||||||
|
|
||||||
term_param_mutex = osMutexNew(NULL); // 创建互斥锁
|
term_param_mutex = osMutexNew(NULL); // 创建互斥锁
|
||||||
Polygon_fence_mutex = osMutexNew(NULL); // 创建互斥锁
|
Polygon_fence_mutex = osMutexNew(NULL); // 创建互斥锁
|
||||||
|
update_mutex = osMutexNew(NULL); // 创建互斥锁
|
||||||
|
|
||||||
memset(&jt808_term_param_item,0,sizeof(Term_Param_item_t));
|
memset(&jt808_term_param_item,0,sizeof(Term_Param_item_t));
|
||||||
// 加载围栏区域信息
|
// 加载围栏区域信息
|
||||||
|
|
@ -701,7 +961,7 @@ void jt808_set_term_param_init(void){
|
||||||
// memcpy(jt808_term_param_item.big_term_attr_resp.term_ICCID+4, jt808_term_param_item.phone_BCDnum, 6); // 终端手机号码 但是你照这个来云端收到的iccid全是,因为BCDnum参数本身没有初始化
|
// memcpy(jt808_term_param_item.big_term_attr_resp.term_ICCID+4, jt808_term_param_item.phone_BCDnum, 6); // 终端手机号码 但是你照这个来云端收到的iccid全是,因为BCDnum参数本身没有初始化
|
||||||
|
|
||||||
char str_hw_ver[] = "1.0.0"; // 硬件版本
|
char str_hw_ver[] = "1.0.0"; // 硬件版本
|
||||||
char str_fw_ver[] = "1.1.6"; // 固件版本 原本为1.0.0
|
char str_fw_ver[] = "1.2.3"; // 固件版本 原本为1.0.0
|
||||||
jt808_term_param_item.big_term_attr_resp.hw_ver_len = strlen(str_hw_ver); // 硬件版本长度
|
jt808_term_param_item.big_term_attr_resp.hw_ver_len = strlen(str_hw_ver); // 硬件版本长度
|
||||||
jt808_term_param_item.big_term_attr_resp.fw_ver_len = strlen(str_fw_ver); // 固件版本长度
|
jt808_term_param_item.big_term_attr_resp.fw_ver_len = strlen(str_fw_ver); // 固件版本长度
|
||||||
memcpy(jt808_term_param_item.big_term_attr_resp.str_hw_ver, str_hw_ver, strlen(str_hw_ver)); // 硬件版本
|
memcpy(jt808_term_param_item.big_term_attr_resp.str_hw_ver, str_hw_ver, strlen(str_hw_ver)); // 硬件版本
|
||||||
|
|
@ -727,7 +987,7 @@ void jt808_set_term_param_init(void){
|
||||||
}else{
|
}else{
|
||||||
jt808_term_param_item.set_term_param.HeartBeatInterval = 30; // 心跳包间隔(秒)
|
jt808_term_param_item.set_term_param.HeartBeatInterval = 30; // 心跳包间隔(秒)
|
||||||
#if 1
|
#if 1
|
||||||
char ServerAddr[] ="106.15.224.140"; // 三一服务器地址
|
char ServerAddr[] ="106.15.224.140"; // 三一服务器地址 106.15.224.140 测试服务器地址 47.99.118.34
|
||||||
uint32_t ServerPort = 5000; // 服务器端口
|
uint32_t ServerPort = 5000; // 服务器端口
|
||||||
#else
|
#else
|
||||||
char ServerAddr[] ="106.14.30.23"; // 生产服务器地址
|
char ServerAddr[] ="106.14.30.23"; // 生产服务器地址
|
||||||
|
|
@ -752,7 +1012,7 @@ void jt808_set_term_param_init(void){
|
||||||
jt808_term_param_item.set_term_param.SpeedCutLimit =2000; // 前进自动减速刹车距离
|
jt808_term_param_item.set_term_param.SpeedCutLimit =2000; // 前进自动减速刹车距离
|
||||||
jt808_term_param_item.set_term_param.BrakeLimit_B =1000; // 后退刹车距离
|
jt808_term_param_item.set_term_param.BrakeLimit_B =1000; // 后退刹车距离
|
||||||
jt808_term_param_item.set_term_param.SpeedCutLimit_B =1600; // 后退自动减速刹车距离
|
jt808_term_param_item.set_term_param.SpeedCutLimit_B =1600; // 后退自动减速刹车距离
|
||||||
jt808_term_param_item.set_term_param.Ban_Fence_Polygon_Delay_OFF =5; // 禁止围栏延时锁车时间
|
jt808_term_param_item.set_term_param.Ban_Fence_Polygon_Delay_OFF =15; // 禁止围栏延时锁车时间
|
||||||
jt808_save_TermParam(); // 保存终端参数
|
jt808_save_TermParam(); // 保存终端参数
|
||||||
}
|
}
|
||||||
}while(0);
|
}while(0);
|
||||||
|
|
@ -778,7 +1038,7 @@ void jt808_set_term_param_init(void){
|
||||||
if((operator_val ==0)||(operator_val ==2)||(operator_val ==4)||(operator_val ==7)){ // 中国移动
|
if((operator_val ==0)||(operator_val ==2)||(operator_val ==4)||(operator_val ==7)){ // 中国移动
|
||||||
start_val -= 12;
|
start_val -= 12;
|
||||||
}else if((operator_val ==1)||(operator_val ==6)||(operator_val ==9)){ // 中国联通
|
}else if((operator_val ==1)||(operator_val ==6)||(operator_val ==9)){ // 中国联通
|
||||||
start_val -= 12;
|
start_val -= 13;
|
||||||
}else if((operator_val ==3)||(operator_val ==11)){ // 电信
|
}else if((operator_val ==3)||(operator_val ==11)){ // 电信
|
||||||
start_val -= 13;
|
start_val -= 13;
|
||||||
}
|
}
|
||||||
|
|
@ -864,14 +1124,14 @@ void jt808_set_term_param_free(void){
|
||||||
jt808_free(jt808_term_param_item.big_ctrl_info.str_cmd_params);
|
jt808_free(jt808_term_param_item.big_ctrl_info.str_cmd_params);
|
||||||
jt808_term_param_item.big_ctrl_info.str_cmd_params = NULL;
|
jt808_term_param_item.big_ctrl_info.str_cmd_params = NULL;
|
||||||
}
|
}
|
||||||
if(jt808_term_param_item.big_upgrade_info.str_upgrade_pkg != NULL){ // 释放残留升级包内存
|
if(jt808_term_param_item.big_upgrade_info.file_path != NULL){ // 释放升级包路径名称
|
||||||
jt808_free(jt808_term_param_item.big_upgrade_info.str_upgrade_pkg);
|
jt808_free(jt808_term_param_item.big_upgrade_info.file_path);
|
||||||
jt808_term_param_item.big_upgrade_info.str_upgrade_pkg = NULL;
|
jt808_term_param_item.big_upgrade_info.file_path = 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;
|
|
||||||
}
|
}
|
||||||
|
// 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; // 附加信息
|
||||||
Loc_addi_info_t *p_addi_info_next; // 附加信息下一个节点
|
Loc_addi_info_t *p_addi_info_next; // 附加信息下一个节点
|
||||||
p_addi_info = jt808_term_param_item.big_loc_report.addi_info;
|
p_addi_info = jt808_term_param_item.big_loc_report.addi_info;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
#define _RADAR_H
|
#define _RADAR_H
|
||||||
#include "cm_os.h"
|
#include "cm_os.h"
|
||||||
|
|
||||||
#define RADAR_BUFF_MAX 9
|
//#define RADAR_STA jt808_term_param_item.set_term_param.RadarEN // 雷达使能位, 0 代表关闭, 1 代表开启
|
||||||
|
|
||||||
|
|
||||||
typedef struct radar_daraframe{
|
typedef struct radar_daraframe{
|
||||||
volatile uint16_t Front_data;
|
volatile uint16_t Front_data;
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,7 @@
|
||||||
static osThreadId_t os_RADAR_ThreadId;
|
static osThreadId_t os_RADAR_ThreadId;
|
||||||
radar_data_t radar_data;
|
radar_data_t radar_data;
|
||||||
osMutexId_t radar_mutex; // 互斥锁
|
osMutexId_t radar_mutex; // 互斥锁
|
||||||
|
uint8_t old_state = 0;
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Name: CRC-16/MODBUS
|
* Name: CRC-16/MODBUS
|
||||||
* Poly: 0x8005 ( x16+x15+x2+1 )
|
* Poly: 0x8005 ( x16+x15+x2+1 )
|
||||||
|
|
@ -133,7 +132,28 @@ static void RADAR_TaskHandle(void *param){
|
||||||
uint32_t time_count =0;
|
uint32_t time_count =0;
|
||||||
while(1){
|
while(1){
|
||||||
|
|
||||||
// sys_sta.P_Radar_EN=jt808_term_param_item.set_term_param.RadarEN;
|
if(old_state != jt808_term_param_item.set_term_param.RadarEN)
|
||||||
|
{
|
||||||
|
sys_sta.P_Radar_EN = jt808_term_param_item.set_term_param.RadarEN;
|
||||||
|
old_state = jt808_term_param_item.set_term_param.RadarEN;
|
||||||
|
|
||||||
|
if (0==sys_sta.P_Radar_EN)
|
||||||
|
{
|
||||||
|
local_tts_text_play("雷达关闭",0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1==sys_sta.P_Radar_EN)
|
||||||
|
{
|
||||||
|
local_tts_text_play("雷达开启",0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (2==sys_sta.P_Radar_EN)
|
||||||
|
{
|
||||||
|
local_tts_text_play("雷达临时关闭",0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
DEBUG("radar task init\r\n");
|
||||||
|
|
||||||
if(0==sys_sta.P_Radar_EN)
|
if(0==sys_sta.P_Radar_EN)
|
||||||
{
|
{
|
||||||
|
|
@ -167,7 +187,7 @@ static void RADAR_TaskHandle(void *param){
|
||||||
// DEBUG("SendCMD:ID=%#02x", (0 == sys_sta.IO_RX_back)?RADAR_ID_Back:RADAR_ID_Front);
|
// DEBUG("SendCMD:ID=%#02x", (0 == sys_sta.IO_RX_back)?RADAR_ID_Back:RADAR_ID_Front);
|
||||||
radar_Sendcmd((0 == sys_sta.IO_RX_back)?RADAR_ID_Back:RADAR_ID_Front, RADAR_MODE_Real);
|
radar_Sendcmd((0 == sys_sta.IO_RX_back)?RADAR_ID_Back:RADAR_ID_Front, RADAR_MODE_Real);
|
||||||
|
|
||||||
DEBUG("radar 1\r\n"); // 任务结束
|
// DEBUG("radar 1\r\n"); // 任务结束
|
||||||
}else{
|
}else{
|
||||||
sys_sta.A_Speed_Cut =0; // 清空自动减速状态
|
sys_sta.A_Speed_Cut =0; // 清空自动减速状态
|
||||||
sys_sta.A_brake =0; // 清空自动刹车状态
|
sys_sta.A_brake =0; // 清空自动刹车状态
|
||||||
|
|
@ -175,9 +195,6 @@ static void RADAR_TaskHandle(void *param){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (2==sys_sta.P_Radar_EN)
|
else if (2==sys_sta.P_Radar_EN)
|
||||||
|
|
@ -189,7 +206,7 @@ static void RADAR_TaskHandle(void *param){
|
||||||
|
|
||||||
if(time_count>=400)
|
if(time_count>=400)
|
||||||
{
|
{
|
||||||
sys_sta.P_Radar_EN=1;
|
sys_sta.P_Radar_EN = 1;
|
||||||
time_count=0;
|
time_count=0;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -200,7 +217,6 @@ static void RADAR_TaskHandle(void *param){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
osMutexRelease(radar_mutex);
|
osMutexRelease(radar_mutex);
|
||||||
osDelay(140/5); // 140ms
|
osDelay(140/5); // 140ms
|
||||||
}
|
}
|
||||||
|
|
@ -214,7 +230,7 @@ void radar_init(void){
|
||||||
osThreadAttr_t radar_task_attr = {
|
osThreadAttr_t radar_task_attr = {
|
||||||
.name = "uart_tx_task",
|
.name = "uart_tx_task",
|
||||||
.stack_size = 4096*4,
|
.stack_size = 4096*4,
|
||||||
.priority= osPriorityNormal
|
.priority= osPriorityBelowNormal
|
||||||
};
|
};
|
||||||
os_RADAR_ThreadId= osThreadNew(RADAR_TaskHandle, 0, &radar_task_attr);
|
os_RADAR_ThreadId= osThreadNew(RADAR_TaskHandle, 0, &radar_task_attr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "cm_modem.h"
|
#include "cm_modem.h"
|
||||||
#include "cm_pm.h"
|
#include "cm_pm.h"
|
||||||
|
|
||||||
|
|
||||||
#include "jt808_msg_pkg.h"
|
#include "jt808_msg_pkg.h"
|
||||||
#include "jt808_msg_parse.h"
|
#include "jt808_msg_parse.h"
|
||||||
#include "jt808_pkg_transmit.h"
|
#include "jt808_pkg_transmit.h"
|
||||||
|
|
@ -10,6 +11,8 @@
|
||||||
#include "tcp_client.h"
|
#include "tcp_client.h"
|
||||||
#include "app_common.h"
|
#include "app_common.h"
|
||||||
#include "local_tts.h"
|
#include "local_tts.h"
|
||||||
|
#include "attr_broadcast.h"
|
||||||
|
|
||||||
|
|
||||||
#define TCP_CLIENT_ENABLE 0
|
#define TCP_CLIENT_ENABLE 0
|
||||||
|
|
||||||
|
|
@ -27,6 +30,45 @@ osSemaphoreId_t netconn_disconnect_sem = NULL; // 断开连接信号量
|
||||||
|
|
||||||
#define RECV_MAX_LEN (1024) // 接收最大长度
|
#define RECV_MAX_LEN (1024) // 接收最大长度
|
||||||
|
|
||||||
|
// 修改后的检查鉴权码文件函数
|
||||||
|
static int check_auth_code_file(void)
|
||||||
|
{
|
||||||
|
char auth_code[64] = {0}; // 假设鉴权码最大长度为63字符
|
||||||
|
|
||||||
|
int ret = auth_code_manage(AUTH_OP_GET, auth_code, sizeof(auth_code));
|
||||||
|
if (ret != 0) {
|
||||||
|
DEBUG("No valid auth code file found: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查鉴权码是否有效(至少有一定长度)
|
||||||
|
size_t auth_len = strlen(auth_code);
|
||||||
|
if (auth_len < 4) { // 假设有效鉴权码至少4字符
|
||||||
|
DEBUG("Auth code is too short to be valid\n");
|
||||||
|
auth_code_manage(AUTH_OP_DEL, NULL, 0); // 删除无效文件
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将鉴权码设置到全局参数中
|
||||||
|
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(strlen(auth_code) + 1);
|
||||||
|
if (!PrsResult.term_param_item->big_auth_info.str_auth_code) {
|
||||||
|
DEBUG("Memory allocation failed for auth code\n");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用与解析代码相同的方式:先memset清零,再memcpy复制数据
|
||||||
|
memset(PrsResult.term_param_item->big_auth_info.str_auth_code, 0, auth_len + 1);
|
||||||
|
memcpy(PrsResult.term_param_item->big_auth_info.str_auth_code, auth_code, auth_len);
|
||||||
|
|
||||||
|
DEBUG("Auth code loaded from file: %s\n", auth_code);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// TCP接收线程
|
// TCP接收线程
|
||||||
static void tcp_recv_task(void){
|
static void tcp_recv_task(void){
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
@ -55,6 +97,13 @@ static void tcp_recv_task(void){
|
||||||
DEBUG("tcp_read recv too long:%d\n", ret);
|
DEBUG("tcp_read recv too long:%d\n", ret);
|
||||||
ret = RECV_MAX_LEN;
|
ret = RECV_MAX_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG("Raw TCP recv:%d\n", ret);
|
||||||
|
for(int i = 0; i < ret; i++){
|
||||||
|
DEBUG("%02X ", buf[i]);
|
||||||
|
}
|
||||||
|
DEBUG("\n");
|
||||||
|
|
||||||
// 处理接收到的数据
|
// 处理接收到的数据
|
||||||
jt808_pkg_handle(buf, ret);
|
jt808_pkg_handle(buf, ret);
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
@ -75,6 +124,142 @@ static void tcp_recv_task(void){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void net_manage_task(void *arg) {
|
||||||
|
DEBUG("net_manage_task!\r\n");
|
||||||
|
int ret = 0;
|
||||||
|
cm_cereg_state_t cereg_state = {0};
|
||||||
|
uint8_t error_time_out = 0;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
// 等待插入SIM卡并建立网络连接
|
||||||
|
while(1) {
|
||||||
|
osDelay(1000/5);
|
||||||
|
error_time_out++;
|
||||||
|
if(error_time_out > 15) { // 超时退出
|
||||||
|
DEBUG("network connect timeout!\n");
|
||||||
|
local_tts_text_play("网络异常,5秒后重启!",0,0);
|
||||||
|
osDelay(5000/5);
|
||||||
|
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");
|
||||||
|
local_tts_text_play("网络正常!",0,0);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
DEBUG("waiting for network...\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG("cereg_get_state fail!\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TCP_CONNECT:
|
||||||
|
error_time_out = 0;
|
||||||
|
// 连接服务器
|
||||||
|
do {
|
||||||
|
osDelay(1000/5);
|
||||||
|
error_time_out++;
|
||||||
|
if(error_time_out > 15) { // 超时退出
|
||||||
|
DEBUG("network connect timeout!\n");
|
||||||
|
local_tts_text_play("服务器连接失败,重连中...",0,0);
|
||||||
|
}
|
||||||
|
} while(0 != tcp_client_connect((char *)(PrsResult.term_param_item->set_term_param.MainServerAddr),
|
||||||
|
PrsResult.term_param_item->set_term_param.ServerPort));
|
||||||
|
|
||||||
|
DEBUG("tcp_client_connect success!\r\n");
|
||||||
|
|
||||||
|
// 先检查是否有有效的鉴权码文件
|
||||||
|
int auth_file_valid = check_auth_code_file();
|
||||||
|
|
||||||
|
if(auth_file_valid == 0) {
|
||||||
|
// 有有效的鉴权码,直接进行鉴权
|
||||||
|
DEBUG("Using saved auth code, skipping registration\n");
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < 5; i++) {
|
||||||
|
osDelay(200/5);
|
||||||
|
ret = jt808_pkg_send(ID_Term_Auth, 5000/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) || (i == 4)) { // 5次尝试都失败
|
||||||
|
// 鉴权失败,可能是鉴权码已过期,删除文件并重新注册
|
||||||
|
auth_code_manage(AUTH_OP_DEL, NULL, 0);
|
||||||
|
goto REGISTRATION_PROCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
REGISTRATION_PROCESS:
|
||||||
|
// 没有有效的鉴权码,执行正常注册流程
|
||||||
|
for(uint8_t i = 0; i < 3; i++) { // 发送3次注册
|
||||||
|
ret = jt808_pkg_send(ID_Term_Reg, 5000/5); // 注册终端 超时:8S
|
||||||
|
if(0 == ret) { // 0:成功;1:车辆已被注册;2:数据库中无该车辆;3:终端已被注册;4:数据库中无该终端
|
||||||
|
DEBUG("send ID_Term_Reg success!\n");
|
||||||
|
|
||||||
|
// 等待注册应答并处理(包括保存鉴权码到文件)
|
||||||
|
osDelay(2000/5);
|
||||||
|
|
||||||
|
// 然后进行鉴权
|
||||||
|
for(uint8_t j = 0; j < 5; j++) {
|
||||||
|
osDelay(1000/5);
|
||||||
|
ret = jt808_pkg_send(ID_Term_Auth, 5000/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) || (j == 4)) {
|
||||||
|
goto TCP_DISCONNECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
local_tts_text_play("设备未绑定,注册异常", 0, 0);
|
||||||
|
osDelay(10000/5);
|
||||||
|
DEBUG("send ID_Term_Reg fail:%d!\n", ret);
|
||||||
|
if(ret == -1) { // 发送失败
|
||||||
|
goto TCP_DISCONNECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i == 2 && ret != 0) { // 3次尝试都失败
|
||||||
|
goto TCP_DISCONNECT; // 跳转重连
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jt808_pkg_send(ID_GetTermAttrResp, 0); // 发送终端属性查询应答包
|
||||||
|
jt808_Autoreport_param_start(); // 开启自动上报参数设置
|
||||||
|
led_set_event(EVENT_NETWORK_READY); // 网络连接成功
|
||||||
|
DEBUG("NetwarK connected!\r\n");
|
||||||
|
local_tts_text_play("服务器已连接",0,0);
|
||||||
|
|
||||||
|
osSemaphoreAcquire(netconn_disconnect_sem, osWaitForever); // 等待断开连接信号
|
||||||
|
|
||||||
|
TCP_DISCONNECT:
|
||||||
|
jt808_Autoreport_param_stop(); // 停止自动上报参数设置
|
||||||
|
led_set_event(EVENT_NETWORK_DISCONNECT); // 网络断开连接
|
||||||
|
DEBUG("NetwarK disconnected!\r\n");
|
||||||
|
local_tts_text_play("服务器已断开",0,0);
|
||||||
|
|
||||||
|
// 关闭TCP连接
|
||||||
|
tcp_client_close();
|
||||||
|
|
||||||
|
// 跳转回TCP连接部分,重新尝试连接
|
||||||
|
goto TCP_CONNECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TCP连接 // host:服务地址,port:服务端口
|
// TCP连接 // host:服务地址,port:服务端口
|
||||||
int tcp_client_connect(const char *host, int port) {
|
int tcp_client_connect(const char *host, int port) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
@ -142,102 +327,6 @@ void tcp_client_close(void){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 网络管理线程
|
|
||||||
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){
|
|
||||||
while(1){ // 等待插入SIM卡并建立网络连接
|
|
||||||
osDelay(1000/5);
|
|
||||||
error_time_out++;
|
|
||||||
if(error_time_out > 15){ // 超时退出
|
|
||||||
DEBUG("network connect timeout!\n");
|
|
||||||
local_tts_text_play("网络异常,5秒后重启!",0,0);
|
|
||||||
osDelay(5000/5);
|
|
||||||
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");
|
|
||||||
local_tts_text_play("网络正常!",0,0);
|
|
||||||
break;
|
|
||||||
}else{
|
|
||||||
DEBUG("waiting for network...\n");
|
|
||||||
// local_tts_text_play("等待网络连接!",0,0);
|
|
||||||
}
|
|
||||||
}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");
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
TCP_DISABLE:
|
|
||||||
error_time_out = 0;
|
|
||||||
do{// 连接服务器
|
|
||||||
osDelay(1000/5);
|
|
||||||
error_time_out++;
|
|
||||||
if(error_time_out > 15){ // 超时退出
|
|
||||||
DEBUG("network connect timeout!\n");
|
|
||||||
local_tts_text_play("服务器连接失败,重连中...",0,0);
|
|
||||||
}
|
|
||||||
}while(0 != tcp_client_connect((char *)(PrsResult.term_param_item->set_term_param.MainServerAddr) , PrsResult.term_param_item->set_term_param.ServerPort)); // 连接到TCP服务器
|
|
||||||
DEBUG("tcp_client_connect success!\r\n");
|
|
||||||
for(uint8_t i = 0; i < 3; i++){ // 发送3次注册、鉴权、参数设置、上报参数
|
|
||||||
ret =jt808_pkg_send(ID_Term_Reg,5000/5);//注册终端 超时:8S
|
|
||||||
if(0 == ret){ // 0:成功;1:车辆已被注册;2:数据库中无该车辆;3:终端已被注册;4:数据库中无该终端
|
|
||||||
DEBUG("send ID_Term_Reg success!\n");
|
|
||||||
for(uint8_t i = 0; i < 5; i++){
|
|
||||||
ret =jt808_pkg_send(ID_Term_Auth,5000/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)||(i == 3)){
|
|
||||||
goto TCP_DISABLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}else{
|
|
||||||
local_tts_text_play("设备未绑定,注册异常",0,0);
|
|
||||||
osDelay(10000/5);
|
|
||||||
DEBUG("send ID_Term_Reg fail:%d!\n",ret);
|
|
||||||
if(ret == -1){ // 发送失败
|
|
||||||
goto TCP_DISABLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jt808_pkg_send(ID_GetTermAttrResp, 0); // 发送终端属性查询应答包
|
|
||||||
jt808_Autoreport_param_start();//开启自动上报参数设置
|
|
||||||
led_set_event(EVENT_NETWORK_READY); // 网络连接成功
|
|
||||||
DEBUG("NetwarK connected!\r\n");
|
|
||||||
// local_tts_set(5, 15, CM_LOCAL_TTS_DIGIT_AUTO);
|
|
||||||
local_tts_text_play("服务器已连接",0,0);
|
|
||||||
// local_tts_text_play("欢迎使用莱昂特智能终端设备...。",0,0); // 0:表示自动计算字符串长度,10000表示最大等待时间
|
|
||||||
osSemaphoreAcquire(netconn_disconnect_sem, osWaitForever); // 等待断开连接信号
|
|
||||||
jt808_Autoreport_param_stop();//停止自动上报参数设置
|
|
||||||
led_set_event(EVENT_NETWORK_DISCONNECT); // 网络断开连接
|
|
||||||
DEBUG("NetwarK disconnected!\r\n");
|
|
||||||
// local_tts_set(5, 15, CM_LOCAL_TTS_DIGIT_AUTO);
|
|
||||||
local_tts_text_play("服务器已断开",0,0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tcp_client_init(void){
|
void tcp_client_init(void){
|
||||||
osThreadAttr_t net_manage_task_attr={
|
osThreadAttr_t net_manage_task_attr={
|
||||||
.name = "net_manage_task",
|
.name = "net_manage_task",
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,10 +0,0 @@
|
||||||
ML307A-DSLN/ML307A-GCLN/ML307A-GSLN/ML305A-DS等型号均可在1.4.2版本至1.4.3版本上进行(跨SDK版本)最小系统FOTA升级,升级方法参见《固件升级开发指导手册》
|
|
||||||
|
|
||||||
|
|
||||||
受限于模组flash剩余空间较少,ML307A-GCLN无法通过常规的最小系统FOTA的方式从SDK 1.4.2版本升级至SDK1.4.3版本,需在调整升级包切片大小的基础上进行升级,方式如下
|
|
||||||
基础升级包基础制作方式参见《固件升级开发指导手册》
|
|
||||||
制作升级包时,除使用基础支持方式外,需要使用-s命令将升级包切片大小设置为0x20000,即添加命令-s 20000,示例如下:
|
|
||||||
adiff.exe system_old.img system_new.img system_patch.bin -a1 user_app user_app.bin -m -s 20000
|
|
||||||
|
|
||||||
|
|
||||||
受限于模组flash剩余空间不足,ML307A-DCLN/ML305A-DC无法通过最小系统FOTA的方式从SDK 1.4.2版本升级至SDK1.4.3版本
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,24 +0,0 @@
|
||||||
[Image_List]
|
|
||||||
Number_of_Images = 4
|
|
||||||
1_Image_Enable = 1
|
|
||||||
1_Image_Image_ID = 0x30
|
|
||||||
1_Image_Path = system.img
|
|
||||||
1_Image_Flash_Entry_Address = 0x00024000
|
|
||||||
1_Image_ID_Name = 1
|
|
||||||
2_Image_Enable = 1
|
|
||||||
2_Image_Image_ID = 0x31
|
|
||||||
2_Image_Path = app.bin
|
|
||||||
2_Image_Flash_Entry_Address = 0x006DD000
|
|
||||||
2_Image_ID_Name = 2
|
|
||||||
3_Image_Enable = 1
|
|
||||||
3_Image_Image_ID = 0x32
|
|
||||||
3_Image_Path = cusapp.bin
|
|
||||||
3_Image_Flash_Entry_Address = 0x008DD000
|
|
||||||
3_Image_ID_Name = 3
|
|
||||||
4_Image_Enable = 1
|
|
||||||
4_Image_Image_ID = 0x33
|
|
||||||
4_Image_Path = logoapp.bin
|
|
||||||
4_Image_Flash_Entry_Address = 0x009DD000
|
|
||||||
4_Image_ID_Name = 4
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
@echo off
|
|
||||||
|
|
||||||
del /s /q /f fbf_dfota.bin
|
|
||||||
del /s /q /f a\patchfolder\*
|
|
||||||
FBFMake_CF_V1.5.exe -o fbf_dfota.bin -f system.img -r 147456 -d 0x10000 -a a -b b
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
@echo off
|
|
||||||
|
|
||||||
del /s /q /f fbf_dfota.bin
|
|
||||||
del /s /q /f a\patchfolder\*
|
|
||||||
FBFMake_CF_V1.6-150.exe -f config -d 0x10000 -a a -b b -o fbf_dfota.bin -q
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
@echo off
|
|
||||||
|
|
||||||
del /s /q /f fbf_dfota.bin
|
|
||||||
del /s /q /f a\patchfolder\*
|
|
||||||
FBFMake_CF_V1.6-150.exe -o fbf.bin -f config -a a -b a
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue