From 1df713942de8eaca839c5744c929410b759ef6a8 Mon Sep 17 00:00:00 2001 From: kkkjtr Date: Fri, 22 Aug 2025 14:14:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=89=B4=E6=9D=83=E7=A0=81?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E4=BF=9D=E5=AD=98=E6=9C=BA=E5=88=B6=EF=BC=8C?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- custom/attr_broadcast/inc/attr_broadcast.h | 16 ++ custom/attr_broadcast/src/attr_broadcast.c | 136 ++++++++++++++- custom/jt808/src/jt808_msg_parse.c | 5 +- custom/jt808/src/jt808_pkg_transmit.c | 4 +- custom/jt808/src/jt808_set_TermParam.c | 2 +- custom/tcp_client/src/tcp_client.c | 192 ++++++++++++++++++++- 6 files changed, 347 insertions(+), 8 deletions(-) diff --git a/custom/attr_broadcast/inc/attr_broadcast.h b/custom/attr_broadcast/inc/attr_broadcast.h index d54d711..65e1c48 100644 --- a/custom/attr_broadcast/inc/attr_broadcast.h +++ b/custom/attr_broadcast/inc/attr_broadcast.h @@ -11,6 +11,12 @@ #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 // 删除鉴权码 + + // 景点信息 typedef struct { double longitude; // 经度 @@ -34,6 +40,16 @@ extern const char *park_desc[]; // 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,景区播报专用 void safe_tts_play(const char* segments[], int count); diff --git a/custom/attr_broadcast/src/attr_broadcast.c b/custom/attr_broadcast/src/attr_broadcast.c index 04b9b4a..feb079b 100644 --- a/custom/attr_broadcast/src/attr_broadcast.c +++ b/custom/attr_broadcast/src/attr_broadcast.c @@ -37,6 +37,7 @@ #define MAX_TTS_SEGMENT_LEN 70 // TTS每段最大长度(字符) #define ATTRACTIONS_FILE "attr.txt" // 区域ID列表文件 #define DATA_VERSION_FILE "version.txt" // 本地数据版本文件 +#define AUTH_CODE_FILE "auth_code.txt" // 鉴权码文件 static nmeaPARSER parser; @@ -91,6 +92,7 @@ const char *park_desc[] = { static osMutexId_t attractions_mutex = NULL; static AttractionNode* attractions_head = NULL; static osMutexId_t version_mutex = NULL; +static osMutexId_t auth_mutex = NULL; static BroadcastState broadcast_state = {0}; static int tts_speed = 5; static int tts_volume = 10; @@ -174,6 +176,118 @@ int attr_broadcast_manage_version(uint8_t op, uint8_t type, uint32_t* version) { 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 result = {0}; @@ -876,14 +990,18 @@ void attr_broadcast_init(void) { if (attractions_mutex == NULL) { attractions_mutex = osMutexNew(NULL); } - if (version_mutex == NULL) { + if (version_mutex == NULL) { version_mutex = osMutexNew(NULL); } + if (auth_mutex == NULL) { + auth_mutex = osMutexNew(NULL); + } + // 景点文件是否存在 if(1 == cm_fs_exist(ATTRACTIONS_FILE)) { - DEBUG("file exist\n"); + DEBUG("attraction file exist\n"); } else { @@ -908,6 +1026,20 @@ void attr_broadcast_init(void) { 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)); diff --git a/custom/jt808/src/jt808_msg_parse.c b/custom/jt808/src/jt808_msg_parse.c index a1ee383..aff9ffa 100644 --- a/custom/jt808/src/jt808_msg_parse.c +++ b/custom/jt808/src/jt808_msg_parse.c @@ -61,8 +61,11 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){ JT808_DEBUG("[%s,%s] malloc failed\r\n", __FUNCTION__,__LINE__); 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); 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; } @@ -484,7 +487,7 @@ static int jt808_BodyParse(void *Prsmsg_body, PrsResult_t *Result){ if (packet_count == 0) { // 无数据需要更新 - update_manager_no_update(); + update_manager_complete(); JT808_DEBUG("No data to update\n"); Result->Rsp_result = Msg_ok; } else { diff --git a/custom/jt808/src/jt808_pkg_transmit.c b/custom/jt808/src/jt808_pkg_transmit.c index b91946e..28d28a3 100644 --- a/custom/jt808/src/jt808_pkg_transmit.c +++ b/custom/jt808/src/jt808_pkg_transmit.c @@ -47,7 +47,7 @@ int jt808_pkg_send(MessageID_t Msg_ID, uint32_t timeout){ // JT808_DEBUG("send pkg_msg:%04x\n", Msg_ID); if(osOK == osMessageQueuePut(jt808_send_msg_queue, &send_pkg_msg, 0, 0)){ //将数据送入发送队列 return 0; - + } else { @@ -61,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 || PrsResult.msg_head.msg_id == ID_data_update_reply) + 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; diff --git a/custom/jt808/src/jt808_set_TermParam.c b/custom/jt808/src/jt808_set_TermParam.c index f09be90..32350cb 100644 --- a/custom/jt808/src/jt808_set_TermParam.c +++ b/custom/jt808/src/jt808_set_TermParam.c @@ -931,7 +931,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参数本身没有初始化 char str_hw_ver[] = "1.0.0"; // 硬件版本 - char str_fw_ver[] = "1.2.0"; // 固件版本 原本为1.0.0 + char str_fw_ver[] = "1.2.1"; // 固件版本 原本为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.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)); // 硬件版本 diff --git a/custom/tcp_client/src/tcp_client.c b/custom/tcp_client/src/tcp_client.c index 6da0af5..ecc62ae 100644 --- a/custom/tcp_client/src/tcp_client.c +++ b/custom/tcp_client/src/tcp_client.c @@ -3,6 +3,7 @@ #include "cm_modem.h" #include "cm_pm.h" + #include "jt808_msg_pkg.h" #include "jt808_msg_parse.h" #include "jt808_pkg_transmit.h" @@ -10,8 +11,10 @@ #include "tcp_client.h" #include "app_common.h" #include "local_tts.h" +#include "attr_broadcast.h" -#define TCP_CLIENT_ENABLE 0 + +#define TCP_CLIENT_ENABLE 1 #if TCP_CLIENT_ENABLE #include "app_uart.h" @@ -27,6 +30,45 @@ osSemaphoreId_t netconn_disconnect_sem = NULL; // 断开连接信号量 #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接收线程 static void tcp_recv_task(void){ int ret = 0; @@ -55,6 +97,13 @@ static void tcp_recv_task(void){ DEBUG("tcp_read recv too long:%d\n", ret); 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); 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:服务端口 int tcp_client_connect(const char *host, int port) { int ret = 0; @@ -143,7 +328,7 @@ void tcp_client_close(void){ // 网络管理线程 -static void net_manage_task(void *arg){ +/*static void net_manage_task(void *arg){ // osThreadState_t state; DEBUG("net_manage_task!\r\n"); @@ -200,6 +385,7 @@ TCP_DISABLE: if(0 == ret){ // 0:成功;1:车辆已被注册;2:数据库中无该车辆;3:终端已被注册;4:数据库中无该终端 DEBUG("send ID_Term_Reg success!\n"); for(uint8_t i = 0; i < 5; i++){ + osDelay(1000/5); ret =jt808_pkg_send(ID_Term_Auth,5000/5);//终端鉴权 超时:10S if(0 == ret){ DEBUG("send ID_Term_Auth success!\n"); @@ -241,6 +427,8 @@ TCP_DISABLE: } } +*/ + void tcp_client_init(void){ osThreadAttr_t net_manage_task_attr={ .name = "net_manage_task",