景点及电子围栏请求逻辑更新测试完成,双工通信测试完成,OTA待测试
This commit is contained in:
parent
9e65e4a905
commit
06945aa58d
|
|
@ -14,7 +14,7 @@
|
|||
#include "gps_config.h"
|
||||
#include "local_tts.h"
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
#include "app_uart.h"
|
||||
#define DEBUG(fmt, args...) app_printf("[GPS]" fmt, ##args)
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -3,7 +3,13 @@
|
|||
#include "cm_os.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
|
||||
|
||||
// 景点信息
|
||||
typedef struct {
|
||||
|
|
@ -22,6 +28,12 @@ typedef struct {
|
|||
|
||||
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);
|
||||
|
||||
|
||||
//多文字tts,景区播报专用
|
||||
void safe_tts_play(const char* segments[], int count);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
#include "attr_broadcast.h"
|
||||
#include "gps_config.h"
|
||||
#include "local_tts.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
#include "app_uart.h"
|
||||
|
|
@ -33,7 +36,7 @@
|
|||
#define TTS_PRIORITY 5 // TTS播报优先级
|
||||
#define MAX_TTS_SEGMENT_LEN 70 // TTS每段最大长度(字符)
|
||||
#define ATTRACTIONS_FILE "attr.txt" // 区域ID列表文件
|
||||
|
||||
#define DATA_VERSION_FILE "version.txt" // 本地数据版本文件
|
||||
|
||||
static nmeaPARSER parser;
|
||||
|
||||
|
|
@ -69,9 +72,6 @@ typedef struct {
|
|||
} BroadcastState;
|
||||
|
||||
|
||||
typedef int BOOL;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
const char *park_desc[] = {
|
||||
"尊敬的游客欢迎来到顾村公园游玩",
|
||||
|
|
@ -90,12 +90,89 @@ const char *park_desc[] = {
|
|||
|
||||
static osMutexId_t attractions_mutex = NULL;
|
||||
static AttractionNode* attractions_head = NULL;
|
||||
static osMutexId_t version_mutex = NULL;
|
||||
static BroadcastState broadcast_state = {0};
|
||||
static int tts_speed = 5;
|
||||
static int tts_volume = 10;
|
||||
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;
|
||||
}
|
||||
|
||||
// 智能分段函数
|
||||
SegmentedText smart_segment_text(const char* text, int max_segment_len) {
|
||||
|
|
@ -590,7 +667,7 @@ int attr_broadcast_load_attractions(void) {
|
|||
}
|
||||
/******************** 关键修改:ID去重检查 ********************/
|
||||
// 检查链表中是否已存在相同ID的景点
|
||||
BOOL is_duplicate = false;
|
||||
bool is_duplicate = false;
|
||||
AttractionNode* current_node = attractions_head;
|
||||
while (current_node) {
|
||||
if (current_node->region_id == new_node->region_id) {
|
||||
|
|
@ -734,7 +811,7 @@ static void play_attraction_info(AttractionNode* attraction, double distance) {
|
|||
|
||||
static void attr_broadcast_task(void* arg) {
|
||||
(void)arg; // 避免未使用参数警告
|
||||
BOOL should_play; //是否播放最后判断量
|
||||
bool should_play; //是否播放最后判断量
|
||||
|
||||
DEBUG("task begin\r\n");
|
||||
|
||||
|
|
@ -799,7 +876,9 @@ void attr_broadcast_init(void) {
|
|||
if (attractions_mutex == NULL) {
|
||||
attractions_mutex = osMutexNew(NULL);
|
||||
}
|
||||
|
||||
if (version_mutex == NULL) {
|
||||
version_mutex = osMutexNew(NULL);
|
||||
}
|
||||
|
||||
if(1 == cm_fs_exist(ATTRACTIONS_FILE))
|
||||
{
|
||||
|
|
@ -822,6 +901,14 @@ void attr_broadcast_init(void) {
|
|||
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);
|
||||
}
|
||||
|
||||
// 初始化状态
|
||||
memset(&broadcast_state, 0, sizeof(broadcast_state));
|
||||
broadcast_state.distance_threshold = 20.0; // 默认阈值50米
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ void my_appimg_enter(char *param){
|
|||
}
|
||||
local_tts_init();
|
||||
local_tts_mute(0);// 取消静音
|
||||
local_tts_volume(100); // 设置音量为55
|
||||
local_tts_volume(40); // 设置音量为55
|
||||
// local_tts_set(7, 7, CM_LOCAL_TTS_DIGIT_AUTO);
|
||||
local_tts_text_play("已开机",0,0);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ typedef enum {
|
|||
ID_Delete_Polygon_area = 0x8605, // 删除多边形区域
|
||||
ID_Data_Down = 0x8900, // 数据透传下行
|
||||
ID_Data_Up = 0x0900, // 数据透传上行
|
||||
//ID_Req_Fence_update =
|
||||
ID_Req_data_update = 0x0B03, //请求电子围栏/景点更新
|
||||
ID_data_update_reply = 0x8B03, //电子围栏/景点数量下发
|
||||
ID_data_update_complete = 0x8B02, //电子围栏/景点更新完成
|
||||
}MessageID_t;
|
||||
|
||||
#pragma pack(1)
|
||||
|
|
|
|||
|
|
@ -104,6 +104,37 @@ typedef struct {// 终端参数项
|
|||
|
||||
#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;
|
||||
|
||||
// 声明全局变量(在.c文件中定义)
|
||||
extern UpdateStatus_t update_status;
|
||||
extern osMutexId_t update_mutex;
|
||||
|
||||
extern Term_Param_item_t jt808_term_param_item;
|
||||
|
||||
extern osThreadFunc_t Autoreport_param_ThreadId;
|
||||
|
|
@ -112,7 +143,6 @@ extern uint8_t Rsp_locked_condition; // 锁车状态, BYTE
|
|||
|
||||
extern osMutexId_t Polygon_fence_mutex; // 多边形围栏互斥锁
|
||||
|
||||
|
||||
// 控制车辆状态
|
||||
void jt808_Set_CarStatus(uint8_t status);
|
||||
|
||||
|
|
@ -142,7 +172,56 @@ void jt808_Autoreport_param_stop(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);
|
||||
|
||||
#endif // JT808_SET_TERM_PARAM_H_
|
||||
|
|
@ -5,11 +5,16 @@
|
|||
#include "attr_broadcast.h"
|
||||
#include "cm_fota.h"
|
||||
#include "cm_fs.h"
|
||||
#include <stdbool.h>
|
||||
//#include <stdbool.h>
|
||||
|
||||
|
||||
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);
|
||||
|
|
@ -37,6 +42,7 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
|||
Result->Rsp_flow_num = Swap16(resp_body.msg_flow_num); // 应答流水号
|
||||
Result->Rsp_msg_id = Swap16(resp_body.msg_id_ack); // 应答ID
|
||||
Result->Rsp_result = resp_body.result; // 结果
|
||||
break;
|
||||
}
|
||||
case ID_FillPktReq:{// 补传分包请求
|
||||
|
||||
|
|
@ -168,31 +174,29 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
|||
|
||||
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
|
||||
{
|
||||
|
||||
}
|
||||
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时不建议执行升级,关键文件系统操作可能会失败 */
|
||||
//文件系统剩余空间为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;
|
||||
}
|
||||
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)
|
||||
|
|
@ -267,10 +271,13 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
|||
break;
|
||||
}
|
||||
case ID_Set_Circle_Area:{// 设置圆形区域(0x8600)
|
||||
// 检查是否在更新流程中
|
||||
bool in_update = update_manager_is_active() && update_status.state == UPDATE_RECEIVING_DATA;
|
||||
|
||||
|
||||
int ret = 0;
|
||||
uint8_t *p = (uint8_t *)Prsmsg_body;
|
||||
|
||||
|
||||
// 解析固定字段
|
||||
uint32_t Area_ID = Swap32(*(uint32_t *)p);
|
||||
uint16_t Area_att = Swap16(*(uint16_t *)(p + 4));
|
||||
|
|
@ -311,6 +318,17 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
|||
// 释放名称内存
|
||||
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_flow_num = Result->msg_head.msg_flow_num;
|
||||
|
|
@ -350,6 +368,10 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
|||
break;
|
||||
}
|
||||
case ID_Set_Polygon_area:{// 设置多边形区域
|
||||
// 检查是否在更新流程中
|
||||
bool in_update = update_manager_is_active() && update_status.state == UPDATE_RECEIVING_DATA;
|
||||
|
||||
|
||||
int ret = 0;
|
||||
uint32_t Area_ID; // 区域ID
|
||||
uint16_t Area_att; // 区域属性
|
||||
|
|
@ -364,6 +386,16 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
|||
(AreaPoint_t *)(((uint8_t *)Prsmsg_body) + 23)); // 区域点坐标
|
||||
if(ret == 0){
|
||||
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{
|
||||
Result->Rsp_result = Msg_err;
|
||||
}
|
||||
|
|
@ -423,6 +455,111 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){
|
|||
// JT808_DEBUG("ID_Data_Down\r\n");
|
||||
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_no_update();
|
||||
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:{
|
||||
return -2; // 没有对应的消息体解析函数
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#include "jt808_msg_pkg.h"
|
||||
#include "jt808_msg_parse.h"
|
||||
#include "attr_broadcast.h"
|
||||
|
||||
|
||||
|
||||
// 协议消息体打包(会自动为p_msg_body分配合适长度的内存,注意释放)
|
||||
static int jt808_BodyPackage(JT808_2013_MsgFrame_t *p_MsgFrame, MessageID_t Msg_ID){
|
||||
|
|
@ -193,6 +196,49 @@ static int jt808_BodyPackage(JT808_2013_MsgFrame_t *p_MsgFrame, MessageID_t Msg_
|
|||
// JT808_DEBUG("ID_Data_Up\r\n");
|
||||
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:{
|
||||
return -2;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -39,8 +39,6 @@ static void jt808_timeout_monitor_task(void *arg) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 触发消息发送修改版
|
||||
int jt808_pkg_send(MessageID_t Msg_ID, uint32_t timeout){
|
||||
pkg_msg_t send_pkg_msg={0};
|
||||
|
|
@ -63,7 +61,7 @@ void jt808_pkg_handle(uint8_t *receive_buf, uint16_t receive_len) {
|
|||
// 1. 解析协议数据
|
||||
if (0 == jt808_msg_parse(receive_buf, receive_len, &PrsResult)) {
|
||||
// 2. 提取接收到的消息ID和流水号 这地方根据消息id分两种情况 一种是平台应答 另一种是平台指令 平台应答需要判断结构体里的id和流水号
|
||||
if (PrsResult.msg_head.msg_id == ID_Plat_GenResp ||PrsResult.msg_head.msg_id == ID_Term_RegResp)
|
||||
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)
|
||||
{
|
||||
uint16_t recv_msg_id = PrsResult.Rsp_msg_id;
|
||||
uint16_t recv_flow_num = PrsResult.Rsp_flow_num;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
#include "cm_fs.h"
|
||||
#include "cm_sim.h"
|
||||
#include "cm_pm.h"
|
||||
|
||||
#include "cm_fota.h"
|
||||
#include "attr_broadcast.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "local_tts.h"
|
||||
#include "control_out.h"
|
||||
|
|
@ -19,33 +21,153 @@
|
|||
#define LOCAL_FENCE_COUNT (sizeof(local_fences) / sizeof(LocalFenceConfig_t))
|
||||
#define __DMB() __asm__ volatile("dmb sy" ::: "memory") // GCC
|
||||
|
||||
|
||||
|
||||
Term_Param_item_t jt808_term_param_item; // 终端参数项
|
||||
osMutexId_t term_param_mutex = NULL; // 终端参数项互斥锁
|
||||
osMutexId_t Polygon_fence_mutex = NULL; // 多边形围栏互斥锁
|
||||
osMutexId_t update_mutex = NULL; //更新数据状态互斥锁
|
||||
|
||||
// 安全获取RadarEN值
|
||||
uint8_t jt808_get_radar_en(void) {
|
||||
// 内存屏障确保读取最新值
|
||||
__DMB();
|
||||
uint8_t value = jt808_term_param_item.set_term_param.RadarEN;
|
||||
__DMB();
|
||||
return value;
|
||||
// 定义全局变量
|
||||
UpdateStatus_t update_status = {
|
||||
.state = UPDATE_IDLE,
|
||||
.type = UPDATE_TYPE_NONE,
|
||||
.start_time = 0,
|
||||
.retry_count = 0,
|
||||
.expected_packets = 0,
|
||||
.received_packets = 0
|
||||
};
|
||||
|
||||
|
||||
static void __cm_fota_cb(cm_fota_error_e error)
|
||||
{
|
||||
JT808_DEBUG("[FOTA] error code is %d\r\n", error);
|
||||
}
|
||||
|
||||
// 安全设置RadarEN值
|
||||
void jt808_set_radar_en(uint8_t value) {
|
||||
// 验证值范围
|
||||
if (value > 2) {
|
||||
JT808_DEBUG("Invalid RadarEN value: %d", value);
|
||||
return;
|
||||
|
||||
// 重置更新状态
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 内存屏障
|
||||
__DMB();
|
||||
jt808_term_param_item.set_term_param.RadarEN = value;
|
||||
__DMB();
|
||||
// 标记更新完成
|
||||
void update_manager_complete(void) {
|
||||
osMutexAcquire(update_mutex, osWaitForever);
|
||||
update_status.state = UPDATE_COMPLETED;
|
||||
osMutexRelease(update_mutex);
|
||||
|
||||
JT808_DEBUG("Set RadarEN to %d", value);
|
||||
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);
|
||||
}
|
||||
|
||||
// 控制车辆状态
|
||||
|
|
@ -630,6 +752,16 @@ void Autoreport_param_Task(void *arg){
|
|||
#endif
|
||||
|
||||
while(1){
|
||||
|
||||
|
||||
// 检查超时
|
||||
update_manager_check_timeout();
|
||||
|
||||
|
||||
|
||||
if (!update_manager_is_active())
|
||||
{
|
||||
// 正常的自动上报逻辑
|
||||
osMutexAcquire(gps_data.mutex, osWaitForever);
|
||||
memcpy(&gps_data_msg, &gps_data, sizeof(gps_data_t));
|
||||
osMutexRelease(gps_data.mutex);
|
||||
|
|
@ -668,6 +800,88 @@ 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");
|
||||
}
|
||||
}
|
||||
/*
|
||||
if(count_Sec == 80)
|
||||
{
|
||||
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("https://youyuanmao.oss-cn-shanghai.aliyuncs.com/system_patch.bin"); //仅作为示例,url不可使用
|
||||
|
||||
cm_fs_system_info_t fs_info = {0, 0};
|
||||
cm_fs_getinfo(&fs_info);
|
||||
|
||||
//文件系统剩余空间为0时不建议执行升级,关键文件系统操作可能会失败
|
||||
if (0 == fs_info.free_size)
|
||||
{
|
||||
JT808_DEBUG("insufficient space left in the file system");
|
||||
return;
|
||||
}
|
||||
|
||||
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]", info.fixed_info.url);
|
||||
}
|
||||
else if (CM_FOTA_TYPE_FTP == info.fixed_info.fota_mode)
|
||||
{
|
||||
JT808_DEBUG("FTP server [%s] [%s] [%s]", info.fixed_info.url, info.fixed_info.username, info.fixed_info.passwd);
|
||||
}
|
||||
else
|
||||
{
|
||||
JT808_DEBUG("HTTP server error");
|
||||
return;
|
||||
}
|
||||
|
||||
osDelay(200);
|
||||
|
||||
cm_fota_exec_upgrade();
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
count_Sec++;
|
||||
osDelay(1000/5); // 1S
|
||||
}
|
||||
|
|
@ -701,6 +915,7 @@ void jt808_set_term_param_init(void){
|
|||
|
||||
term_param_mutex = osMutexNew(NULL); // 创建互斥锁
|
||||
Polygon_fence_mutex = osMutexNew(NULL); // 创建互斥锁
|
||||
update_mutex = osMutexNew(NULL); // 创建互斥锁
|
||||
|
||||
memset(&jt808_term_param_item,0,sizeof(Term_Param_item_t));
|
||||
// 加载围栏区域信息
|
||||
|
|
@ -742,7 +957,7 @@ void jt808_set_term_param_init(void){
|
|||
}else{
|
||||
jt808_term_param_item.set_term_param.HeartBeatInterval = 30; // 心跳包间隔(秒)
|
||||
#if 1
|
||||
char ServerAddr[] ="106.15.224.140"; // 三一服务器地址
|
||||
char ServerAddr[] ="106.15.224.140"; // 三一服务器地址 47.99.118.34
|
||||
uint32_t ServerPort = 5000; // 服务器端口
|
||||
#else
|
||||
char ServerAddr[] ="106.14.30.23"; // 生产服务器地址
|
||||
|
|
|
|||
Loading…
Reference in New Issue