From 7373c0ad950e23692999db9d38994a1c8a763df4 Mon Sep 17 00:00:00 2001 From: chenzongxiong Date: Fri, 6 Mar 2026 13:48:42 +0800 Subject: [PATCH] =?UTF-8?q?update:=20=E8=AE=BE=E5=A4=87=E5=B1=8F=E8=94=BD?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20=E9=80=82=E9=85=8D=E6=96=B0=E7=89=88?= =?UTF-8?q?=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RTE/_leakage_system/RTE_Components.h | 6 + leakage_system/MDK-ARM/leakage_system.uvprojx | 18 +- leakage_system/usr/app/app.c | 4 +- leakage_system/usr/app/app_com.c | 85 +- leakage_system/usr/app/app_com.h | 3 +- leakage_system/usr/app/app_leakage.c | 52 +- leakage_system/usr/app/app_leakage.h | 7 +- leakage_system/usr/bsp/bsp_buzzer.c | 33 +- leakage_system/usr/bsp/bsp_uart.c | 4 +- leakage_system/usr/bsp/bsp_uart.h | 2 +- leakage_system/usr/bsp/bsp_w25q.h | 6 + leakage_system/usr/gui/gui_tjc_hmi.c | 955 ++++++++++++------ .../protocol/proto_modbus_master_leakage.c | 5 +- .../usr/protocol/proto_modbus_tcp_slave_ex.c | 11 +- 14 files changed, 854 insertions(+), 337 deletions(-) diff --git a/leakage_system/MDK-ARM/RTE/_leakage_system/RTE_Components.h b/leakage_system/MDK-ARM/RTE/_leakage_system/RTE_Components.h index 0246594..153dac0 100644 --- a/leakage_system/MDK-ARM/RTE/_leakage_system/RTE_Components.h +++ b/leakage_system/MDK-ARM/RTE/_leakage_system/RTE_Components.h @@ -11,5 +11,11 @@ #define RTE_COMPONENTS_H +/* + * Define the Device Header File: + */ +#define CMSIS_device_header "stm32f4xx.h" + + #endif /* RTE_COMPONENTS_H */ diff --git a/leakage_system/MDK-ARM/leakage_system.uvprojx b/leakage_system/MDK-ARM/leakage_system.uvprojx index 78663ef..1c6f363 100644 --- a/leakage_system/MDK-ARM/leakage_system.uvprojx +++ b/leakage_system/MDK-ARM/leakage_system.uvprojx @@ -10,14 +10,14 @@ leakage_system 0x4 ARM-ADS - 5060960::V5.06 update 7 (build 960)::.\ARMCC + 5060750::V5.06 update 6 (build 750)::ARMCC 0 STM32F407VGTx STMicroelectronics - Keil.STM32F4xx_DFP.3.0.0 - https://www.keil.com/pack/ + Keil.STM32F4xx_DFP.2.15.0 + http://www.keil.com/pack/ IRAM(0x20000000,0x00020000) IRAM2(0x10000000,0x00010000) IROM(0x08000000,0x00100000) CPUTYPE("Cortex-M4") FPU2 CLOCK(12000000) ELITTLE @@ -185,7 +185,6 @@ 0 2 0 - 0 1 0 8 @@ -352,7 +351,7 @@ 0 0 0 - 4 + 0 @@ -787,13 +786,4 @@ - - - - leakage_system - 1 - - - - diff --git a/leakage_system/usr/app/app.c b/leakage_system/usr/app/app.c index 49c34e6..4fddc85 100644 --- a/leakage_system/usr/app/app.c +++ b/leakage_system/usr/app/app.c @@ -60,6 +60,8 @@ void app_init(void) /*flash*/ w25q32.init(); +// HAL_Delay(5000); + /*串口初始化*/ com_uart1.init(&com_uart1); com_uart2.init(&com_uart2); @@ -148,7 +150,7 @@ void task_500ms(void) modbus_leakage[APP_COM1].tx_task(&modbus_leakage[APP_COM1]); modbus_leakage[APP_COM2].tx_task(&modbus_leakage[APP_COM2]); modbus_leakage[APP_COM3].tx_task(&modbus_leakage[APP_COM3]); -// modbus_leakage[APP_COM4].tx_task(&modbus_leakage[APP_COM4]); + modbus_leakage[APP_COM4].tx_task(&modbus_leakage[APP_COM4]); } diff --git a/leakage_system/usr/app/app_com.c b/leakage_system/usr/app/app_com.c index 842b3a1..36bf6c8 100644 --- a/leakage_system/usr/app/app_com.c +++ b/leakage_system/usr/app/app_com.c @@ -1,5 +1,7 @@ #include "app_com.h" #include "app_leakage.h" +#include "bsp_w25q.h" +#include #include "proto_modbus_master_leakage.h" /*com口对应的串口*/ @@ -11,32 +13,91 @@ bsp_uart_t *com_to_uart[APP_COM_NUM] = &com_uart6, }; -static void app_com_uart_class_rate_set(app_com_class_t * p_com,u16 baud_rate); +static void app_com_class_baud_rate_set(app_com_class_t *p_com, u32 baud_enum); static void app_com_class_update(void ); static void app_com_init(void); +static void app_com_save_baudrate_to_flash(void); +static void app_com_load_baudrate_from_flash(void); app_com_t app_com= { .init = app_com_init, .class_update = app_com_class_update, + .save_flah = app_com_save_baudrate_to_flash, }; + static void app_com_init(void) { u8 i; for(i=0;icom_uart->set.baud_rate(p_com->com_uart,baud_rate); + u32 baud_value; + switch (baud_enum) { + case 0: baud_value = 4800; break; + case 1: baud_value = 9600; break; + case 2: baud_value = 19200; break; + case 3: baud_value = 57600; break; + case 4: baud_value = 115200; break; + default: baud_value = 115200; break; + } + if (p_com->com_uart && p_com->com_uart->set.baud_rate) { + p_com->com_uart->set.baud_rate(p_com->com_uart, baud_value); + } +} + +/* 从Flash加载波特率到内存并应用 */ +static void app_com_load_baudrate_from_flash(void) +{ + u8 baud_vals[APP_COM_NUM]; + w25q32.read(W25Q32_COM_BAUDRATE_ADDR, baud_vals, APP_COM_NUM); + + for (u8 i = 0; i < APP_COM_NUM; i++) { + if (baud_vals[i] == 0xFF) { // 未初始化,设为默认115200 + app_com.com[i].flash_data.baudrate = 4; + } else { + app_com.com[i].flash_data.baudrate = baud_vals[i]; + } + // 应用波特率到串口硬件 + app_com_class_baud_rate_set(&app_com.com[i], app_com.com[i].flash_data.baudrate); + } +} + +/* 将当前波特率保存到Flash */ +static void app_com_save_baudrate_to_flash(void) +{ + u8 current_vals[APP_COM_NUM]; + u8 flash_vals[APP_COM_NUM]; + + /*当前内存中的波特率枚举值*/ + for (u8 i = 0; i < APP_COM_NUM; i++) { + current_vals[i] = app_com.com[i].flash_data.baudrate; + } + + /*从 Flash 读取已存储的值*/ + w25q32.read(W25Q32_COM_BAUDRATE_ADDR, flash_vals, APP_COM_NUM); + + // 比较是否完全相同 + if (memcmp(current_vals, flash_vals, APP_COM_NUM) == 0) { + // 没有变化,无需写入 + return; + } + + // 擦除包含该地址的扇区(4K对齐) + uint32_t erase_addr = W25Q32_COM_BAUDRATE_ADDR & ~(W25Q32_SECTOR_SIZE - 1); + w25q32_sector_erase(erase_addr); + w25q32.write(W25Q32_COM_BAUDRATE_ADDR, current_vals, APP_COM_NUM); } @@ -61,10 +122,18 @@ static void app_com_class_update(void ) /********************************************COM口划分******************************************************/ com_index = leakage.sub_device_data[i].flash_data.com; id = leakage.sub_device_data[i].flash_data.modbus_id; + + proto_sensor_class_t *p_sensor = &modbus_leakage[com_index].sensor[modbus_leakage[com_index].sensor_num]; + + /* ★ 清空整个传感器结构体 */ + memset(p_sensor, 0, sizeof(proto_sensor_class_t)); + /*绑定modbus id*/ - modbus_leakage[com_index].sensor[modbus_leakage[com_index].sensor_num].comm.id = id; + p_sensor->comm.id = id; /*绑定子设备索引索引*/ - modbus_leakage[com_index].sensor[modbus_leakage[com_index].sensor_num].comm.leakage_data_index = i; + p_sensor->comm.leakage_data_index = i; + /* ★ 设置初始状态为默认(发送请求) */ + p_sensor->comm.state = PROTO_LEAKAGE_COMM_STATE_DEFAULT; /*comm口设备总数++*/ modbus_leakage[com_index].sensor_num++; } diff --git a/leakage_system/usr/app/app_com.h b/leakage_system/usr/app/app_com.h index a9453f0..042a0fe 100644 --- a/leakage_system/usr/app/app_com.h +++ b/leakage_system/usr/app/app_com.h @@ -26,7 +26,7 @@ struct app_com_class_t bsp_uart_t *com_uart; /*绑定的实际物理串口*/ struct { - void (*baud_rate)(app_com_class_t *,u16); /*设置波特率*/ + void (*baud_rate)(app_com_class_t *,u32); /*设置波特率*/ }set; //void (*init)(app_com_class_t *); /*初始化*/ }; @@ -36,6 +36,7 @@ typedef struct app_com_class_t com[APP_COM_NUM]; void (*init)(void); /*初始化*/ void (*class_update)(void ); /*com区域分类*/ + void (*save_flah)(void); }app_com_t; extern app_com_t app_com; diff --git a/leakage_system/usr/app/app_leakage.c b/leakage_system/usr/app/app_leakage.c index b7affb8..71e914d 100644 --- a/leakage_system/usr/app/app_leakage.c +++ b/leakage_system/usr/app/app_leakage.c @@ -4,6 +4,7 @@ #include "bsp_w25q.h" #include "bsp_buzzer.h" #include "bsp_relay.h" +#include "bsp_DS1302.h" static void history_clear_all(void); static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record); @@ -32,6 +33,11 @@ app_hitory_t history = static void app_leakage_init(void) { +// for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) +// { +// memset(leakage.sub_device_data[i].ch_data, 0, +// sizeof(leakage.sub_device_data[i].ch_data)); +// } app_leakage_region_classify(); } @@ -61,7 +67,7 @@ void app_leakage_region_classify(void) if(0 == memcmp(p_leakage->region_data[j].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN))/*名称相同*/ { /*添加子设备*/ - p_leakage->region_data[j].sub_device_index[p_leakage->region_data[j].leakage_num] = i;/*绑定子设备索引*/ + p_leakage->region_data[j].sub_device_index[p_leakage->region_data[j].sub_device_num] = i;/*绑定子设备索引*/ p_leakage->region_data[j].sub_device_num++; /*区域中子系统数据++*/ add_region_flag = 0;/*不添加新区域*/ break; @@ -72,10 +78,13 @@ void app_leakage_region_classify(void) if(add_region_flag)/*添加新区域*/ { /*复制名称*/ - memcpy(p_leakage->region_data[p_leakage->region_num].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN); - p_leakage->region_data[p_leakage->region_num].sub_device_index[p_leakage->region_data[p_leakage->region_num].leakage_num] = i;/*绑定子设备索引*/ - p_leakage->region_data[p_leakage->region_num].sub_device_num++; /*区域中子系统数据++*/ - p_leakage->region_num++; /*区域数量++*/ + memcpy(p_leakage->region_data[p_leakage->region_num].name, + p_leakage->sub_device_data[i].flash_data.region_name, + APP_LEAKAGE_STRING_NANE_LEN); + // 第一个设备索引为0 + p_leakage->region_data[p_leakage->region_num].sub_device_index[0] = i; + p_leakage->region_data[p_leakage->region_num].sub_device_num = 1; + p_leakage->region_num++; } } } @@ -153,6 +162,12 @@ void app_leakage_task(void) continue; } + /* 检查设备是否屏蔽 */ + if(p_leakage->sub_device_data[sub_device_index].flash_data.shield != UNBLOCKED) + { + continue; + } + /*历史报警存储*/ for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++) { @@ -195,6 +210,7 @@ void app_leakage_task(void) { p_leakage->region_data[i].time_out_num++; p_leakage->alarm_state |= APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT; + break; } else if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) { @@ -204,7 +220,7 @@ void app_leakage_task(void) else if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) { p_leakage->region_data[i].leakage_num++; - p_leakage->alarm_state |= APP_LEAKAGE_SUB_DEVICE_STATE_OPEN; + p_leakage->alarm_state |= APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE; } } @@ -217,21 +233,15 @@ void app_leakage_task(void) /* 获取当前时间 */ static void get_current_time(u8 *time_buffer) { -// RTC_TimeTypeDef sTime; -// RTC_DateTypeDef sDate; -// -// /* 获取RTC时间 */ -// HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); -// HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN); -// -// /* 年: 2字节 (例如: 2024 -> 0x07 0xE8) */ -// uint16_t year = 2000 + sDate.Year; /* RTC年份通常从2000开始 */ -// time_buffer[0] = (year >> 8) & 0xFF; /* 高字节 */ -// time_buffer[1] = year & 0xFF; /* 低字节 */ -// time_buffer[2] = sDate.Month; /* 月 */ -// time_buffer[3] = sDate.Date; /* 日 */ -// time_buffer[4] = sTime.Hours; /* 时 */ -// time_buffer[5] = sTime.Minutes; /* 分 */ + /* 年: 2字节 (例如: 2024 -> 0x07 0xE8) */ + uint16_t year = 2000 + DS1302.Time.Year; /* RTC年份通常从2000开始 */ + time_buffer[0] = (year >> 8) & 0xFF; /* 高字节 */ + time_buffer[1] = year & 0xFF; /* 低字节 */ + time_buffer[2] = DS1302.Time.Month; /* 月 */ + time_buffer[3] = DS1302.Time.Day; /* 日 */ + time_buffer[4] = DS1302.Time.Hour; /* 时 */ + time_buffer[5] = DS1302.Time.Minute; /* 分 */ + time_buffer[6] = DS1302.Time.Second; /* 秒 */ } /* 从Flash读取历史报警元数据 */ diff --git a/leakage_system/usr/app/app_leakage.h b/leakage_system/usr/app/app_leakage.h index 8739a9a..1fc04fa 100644 --- a/leakage_system/usr/app/app_leakage.h +++ b/leakage_system/usr/app/app_leakage.h @@ -6,6 +6,9 @@ #define ENABLE (1) #define DISABLE (0) +#define BLOCKED (1) /*屏蔽*/ +#define UNBLOCKED (0) + #define APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE (0x0001) /*漏液状态*/ #define APP_LEAKAGE_SUB_DEVICE_STATE_OPEN (0x0002) /*断带状态*/ #define APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT (0x8000) /*通讯超时*/ @@ -24,6 +27,8 @@ typedef struct { u8 state; /*状态 使能 非使能*/ u8 com; /*端口*/ + u8 baudrate; /*波特率*/ + u8 shield; /*设备屏蔽状态*/ u8 modbus_id; /*modbus id*/ u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /*设备名*/ u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /*区域名*/ @@ -61,7 +66,7 @@ typedef struct u8 device_id; /* 设备ID */ u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 设备名称 */ u16 alarm_type; /* 报警类型 */ - u8 start_time[6]; /* 开始时间: 年(2字节)月日时分 */ + u8 start_time[7]; /* 开始时间: 年(2字节)月日时分 */ u16 leak_distance; /* 漏液距离 (0表示非漏液报警) */ u8 channel; /* 通道号 (0-3) */ } app_leakage_history_alarm_t; diff --git a/leakage_system/usr/bsp/bsp_buzzer.c b/leakage_system/usr/bsp/bsp_buzzer.c index 778cfec..97aaac1 100644 --- a/leakage_system/usr/bsp/bsp_buzzer.c +++ b/leakage_system/usr/bsp/bsp_buzzer.c @@ -1,4 +1,5 @@ #include "bsp_buzzer.h" +#include "bsp_w25q.h" /*开关控制电平,使用同一的电平控制方式*/ #define BUZZER_GPIO_ON GPIO_PIN_SET @@ -14,6 +15,7 @@ static void bsp_buzzer_on(void); static void bsp_buzzer_off(void); static void bsp_buzzer_enable(void); static void bsp_buzzer_disable(void); +static void bsp_buzzer_flash_data_load(void); bsp_buzzer_t buzzer = { @@ -35,11 +37,40 @@ static void bsp_buzzer_init(void) { BUZZER_OFF; p_buzzer->p_flash_data = &flash_data; + bsp_buzzer_flash_data_load(); } static void bsp_buzzer_flash_data_save(void) { - + // 擦除整个扇区(地址是扇区起始) + w25q32_sector_erase(W25Q32_BUZZER_STATE_ADDR); + w25q32.write(W25Q32_BUZZER_STATE_ADDR, (uint8_t*)&flash_data, sizeof(bsp_buzzer_flash_data_t)); +} + +static void bsp_buzzer_flash_data_load(void) +{ + w25q32.read(W25Q32_BUZZER_STATE_ADDR, (uint8_t*)&flash_data, sizeof(bsp_buzzer_flash_data_t)); + + // 检查是否全为0xFF(首次使用) + uint8_t *p = (uint8_t*)&flash_data; + u8 all_ff = 1; + for (u8 i = 0; i < sizeof(bsp_buzzer_flash_data_t); i++) { + if (p[i] != 0xFF) { + all_ff = 0; + break; + } + } + + if (all_ff) { + // 首次使用,默认关闭蜂鸣器 + flash_data.sw = USR_DISABLE; + bsp_buzzer_flash_data_save(); + } + + // 根据加载的状态设置蜂鸣器使能 + if (flash_data.sw == USR_ENABLE) { + p_buzzer->p_flash_data->sw = flash_data.sw; + } } static void bsp_buzzer_task(void) diff --git a/leakage_system/usr/bsp/bsp_uart.c b/leakage_system/usr/bsp/bsp_uart.c index 61ac7f4..527c078 100644 --- a/leakage_system/usr/bsp/bsp_uart.c +++ b/leakage_system/usr/bsp/bsp_uart.c @@ -57,7 +57,7 @@ static void bsp_uart_rx_task(bsp_uart_t *p_uart); static void bsp_uart_rx_time_start(bsp_uart_t *p_uart); static void bsp_uart_tx_dma_tc_int(bsp_uart_t *p_uart); static void bsp_uart_dma_send(bsp_uart_t *p_uart, u8 *p_data, u16 len); -static void bsp_uart_baud_rate_set(bsp_uart_t *p_uart,u16 baud_rate); +static void bsp_uart_baud_rate_set(bsp_uart_t *p_uart,u32 baud_rate); /* 外部HAL句柄声明 */ extern UART_HandleTypeDef huart1; @@ -269,7 +269,7 @@ static void bsp_uart_init(bsp_uart_t *p_uart) HAL_UARTEx_ReceiveToIdle_DMA(p_uart->uart, p_uart->rx_addr, p_uart->rx_dma_len); } -static void bsp_uart_baud_rate_set(bsp_uart_t *p_uart,u16 baud_rate) +static void bsp_uart_baud_rate_set(bsp_uart_t *p_uart,u32 baud_rate) { p_uart->uart->Init.BaudRate = baud_rate; HAL_UART_Init(p_uart->uart); diff --git a/leakage_system/usr/bsp/bsp_uart.h b/leakage_system/usr/bsp/bsp_uart.h index 1027655..a17e082 100644 --- a/leakage_system/usr/bsp/bsp_uart.h +++ b/leakage_system/usr/bsp/bsp_uart.h @@ -61,7 +61,7 @@ struct bsp_uart_t struct { - void (*baud_rate)(bsp_uart_t *,u16); + void (*baud_rate)(bsp_uart_t *,u32); }set; void (*init)(bsp_uart_t *); /* 初始化函数指针 */ diff --git a/leakage_system/usr/bsp/bsp_w25q.h b/leakage_system/usr/bsp/bsp_w25q.h index 5f29c8f..d227b83 100644 --- a/leakage_system/usr/bsp/bsp_w25q.h +++ b/leakage_system/usr/bsp/bsp_w25q.h @@ -49,6 +49,12 @@ void w25q32_sector_erase(uint32_t sector_addr); #define MAX_HISTORY_ALARM_RECORDS (1000) /* 最大历史报警记录数 */ #define HISTORY_ALARM_SECTORS_NEEDED ((MAX_HISTORY_ALARM_RECORDS * HISTORY_ALARM_RECORD_SIZE + W25Q32_SECTOR_SIZE - 1) / W25Q32_SECTOR_SIZE) +/* COM口波特率存储地址 - 使用独立扇区(扇区13) */ +#define W25Q32_COM_BAUDRATE_ADDR 0x00D000 /*存储4个COM口波特率枚举值(4字节)*/ + +/* 蜂鸣器状态存储地址 - 使用独立扇区(扇区14) */ +#define W25Q32_BUZZER_STATE_ADDR 0x00E000 /*存储蜂鸣器状态(1字节)*/ + /* w25q32 对象结构体 */ typedef struct { void (*init)(void); diff --git a/leakage_system/usr/gui/gui_tjc_hmi.c b/leakage_system/usr/gui/gui_tjc_hmi.c index 6622205..ce66976 100644 --- a/leakage_system/usr/gui/gui_tjc_hmi.c +++ b/leakage_system/usr/gui/gui_tjc_hmi.c @@ -66,15 +66,13 @@ static char *hmi_proto_string_com[] = /*字符名称 波特率*/ static char *hmi_proto_string_baudrate[] = { + "2400", "4800", "9600", - "19200", - "57600", "115200", }; - static bsp_uart_t * p_rx_uart = NULL; gui_tjc_hmi_t tjc_hmi = @@ -127,6 +125,8 @@ static void gui_tjc_hmi_read_password_from_w25q(void) /*将密码保存到W25Q32*/ static void gui_tjc_hmi_save_password_to_w25q(void) { + uint32_t erase_addr = W25Q32_PASSWORD_ADDR & ~(W25Q32_SECTOR_SIZE - 1); + w25q32_sector_erase(erase_addr); /*将4字节密码写入W25Q32*/ w25q32.write(W25Q32_PASSWORD_ADDR, p_tjc_hmi->password, 4); } @@ -158,6 +158,23 @@ static void gui_tjc_hmi_save_device_info_to_w25q(void) DEVICE_INFO_STORAGE_SIZE); } +/*解析网络函数*/ +static void parse_ip_string(u8 *str, u8 len, u8 *ip) +{ + u8 i = 0, part = 0, val = 0; + while (i < len) { + if (str[i] == '.') { + ip[part++] = val; + val = 0; + } else if (str[i] >= '0' && str[i] <= '9') { + val = val * 10 + (str[i] - '0'); + } + i++; + } + ip[part] = val; // 最后一个部分 +} + + /*设置对应的控件 x:第几行 y:第几个 @@ -225,12 +242,42 @@ static void gui_tjc_hmi_main_send(u8 cmd,u8 opa,u8 *p_data) DS1302.Time.Second); len += gui_tjc_hmi_tx_text_display(0,0,(char *)&hmi_tx_buffer[len],"%s",time); + /*IP地址*/ + len += gui_tjc_hmi_tx_text_display(0,1,(char *)&hmi_tx_buffer[len], + "%d.%d.%d.%d", + W5500.IP_Addr[0], + W5500.IP_Addr[1], + W5500.IP_Addr[2], + W5500.IP_Addr[3]); + + /*蜂鸣器状态*/ + u8 buzzer_state = (buzzer.p_flash_data->sw == USR_ENABLE) ? 11 : 13; + /*构造 "sw0.val=x" 指令(x 为 0 或 1)*/ + len += sprintf((char*)&hmi_tx_buffer[len], "p4.pic=%d", buzzer_state); + for (u8 i = 0; i < 3; i++) + { + hmi_tx_buffer[len + i] = 0xFF; + } + len += 3; + if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) { case 0x01:/*读取区域信息*/ { + if (leakage.region_num == 0) + { + for (j = 0; j < MAIN_PAGE_SUB_DEVICE_NUM; j++) + { + for (y = 0; y < 5; y++) + { + len += gui_tjc_hmi_tx_text_display(j+1, y+1, (char *)&hmi_tx_buffer[len], ""); + } + } + break; + } + if(p_tjc_hmi->page.main_index == page_num - 1 && remain_region_num >0)/*显示剩余区域*/ { for(j=0;jsub_device_num / DETAIL_MAIN_NUM; - remain_device_num = region_data->sub_device_num % DETAIL_MAIN_NUM; - if (remain_device_num > 0) - { - page_num++; - } +// /* 计算详情页面数量:每页显示4个设备 */ +// page_num = region_data->sub_device_num / DETAIL_MAIN_NUM; +// remain_device_num = region_data->sub_device_num % DETAIL_MAIN_NUM; +// if (remain_device_num > 0) +// { +// page_num++; +// } if (HMI_PROTO_CMD_GET == cmd) /* 获取数据 */ { @@ -610,61 +721,39 @@ static void gui_tjc_hmi_detail_main_send(u8 cmd, u8 opa, u8 *p_data) { case 0x01: /* 获取设备详情信息 */ { - /* 从指令中获取区域索引 (p_data[0] = 相对区域索引,从1开始,对应当前主界面的1-4) */ u8 relative_region_idx = p_data[0]; - if (relative_region_idx < 1 || relative_region_idx > 4) - { - /* 相对区域索引无效,默认显示第一个 */ -// relative_region_idx = 1; return; - } - - /* 计算全局区域索引: 全局索引 = 主界面页码 * 4 + 相对索引 - 1 */ + + /* 计算全局区域索引 */ region_idx = p_tjc_hmi->page.main_index * 4 + (relative_region_idx - 1); - - /* 检查区域索引是否有效 */ if (region_idx >= leakage.region_num) - { - /* 区域索引越界,尝试显示第一个区域 */ -// region_idx = 0; return; - } - - /* 判断是否切换了区域 */ + + /* 切换区域时重置详情页码 */ if (region_idx != p_tjc_hmi->page.deliniter_main_index) - { - p_tjc_hmi->page.detail_main_index = 0; - } - - /* 保存当前区域索引和主界面页码,翻页时使用 */ + p_tjc_hmi->page.detail_main_index = 0; + p_tjc_hmi->page.deliniter_main_index = region_idx; - - /* 获取区域数据 */ region_data = &leakage.region_data[region_idx]; - - /* 获取当前详情页面的设备数据 */ + + /* 计算页面参数 */ + page_num = region_data->sub_device_num / DETAIL_MAIN_NUM; + remain_device_num = region_data->sub_device_num % DETAIL_MAIN_NUM; + if (remain_device_num > 0) page_num++; + if (page_num == 0) page_num = 1; + u8 start_index = p_tjc_hmi->page.detail_main_index * DETAIL_MAIN_NUM; - - if (p_tjc_hmi->page.detail_main_index == page_num - 1 && remain_device_num > 0) - { - display_count = remain_device_num; - } - else - { - display_count = DETAIL_MAIN_NUM; - } + display_count = (p_tjc_hmi->page.detail_main_index == page_num - 1 && remain_device_num > 0) + ? remain_device_num : DETAIL_MAIN_NUM; for (i = 0; i < display_count; i++) { index = start_index + i; - if (index >= region_data->sub_device_num) break; - - /* 获取设备的全局索引 */ sub_device_index = region_data->sub_device_index[index]; - x = i; /* 0-3表示当前详情页面的4个设备位置 */ + x = i; /* 设备ID: t(x+1)_1 */ y = 0; @@ -692,19 +781,28 @@ static void gui_tjc_hmi_detail_main_send(u8 cmd, u8 opa, u8 *p_data) break; } } - if (comm_state) + if(leakage.sub_device_data[sub_device_index].flash_data.shield == UNBLOCKED) { - len += gui_tjc_hmi_tx_text_display(x+1, y+1, - (char *)&hmi_tx_buffer[len], - "超时"); - } - else + if (comm_state) + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, + (char *)&hmi_tx_buffer[len], + "超时"); + } + else + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, + (char *)&hmi_tx_buffer[len], + "正常"); + } + }else { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "正常"); } + /* 通道1-4状态 */ for (ch = 0; ch < APP_LEAKAGE_SUB_DEVICE_CH_NUM; ch++) { @@ -713,68 +811,120 @@ static void gui_tjc_hmi_detail_main_send(u8 cmd, u8 opa, u8 *p_data) /* 漏液状态 */ y = 3 + (ch * 3); - if (ch_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) + if(leakage.sub_device_data[sub_device_index].flash_data.shield == UNBLOCKED) { - len += gui_tjc_hmi_tx_text_display(x+1, y+1, - (char *)&hmi_tx_buffer[len], - "漏液"); - } - else + if (ch_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, + (char *)&hmi_tx_buffer[len], + "漏液"); + } + else + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, + (char *)&hmi_tx_buffer[len], + "正常"); + } + }else { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "正常"); } + /* 断带状态 */ y = 4 + (ch * 3); - if (ch_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) + if(leakage.sub_device_data[sub_device_index].flash_data.shield == UNBLOCKED) { - len += gui_tjc_hmi_tx_text_display(x+1, y+1, - (char *)&hmi_tx_buffer[len], - "断带"); - } - else + if (ch_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, + (char *)&hmi_tx_buffer[len], + "断带"); + } + else + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, + (char *)&hmi_tx_buffer[len], + "正常"); + } + }else { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "正常"); } + /* 漏液位置 */ y = 5 + (ch * 3); - if (ch_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) + if(leakage.sub_device_data[sub_device_index].flash_data.shield == UNBLOCKED) + { + if (ch_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, + (char *)&hmi_tx_buffer[len], + "%d", + ch_distance); + } + else + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, + (char *)&hmi_tx_buffer[len], + "0"); + } + }else { len += gui_tjc_hmi_tx_text_display(x+1, y+1, - (char *)&hmi_tx_buffer[len], - "%d", - ch_distance); - } - else - { - len += gui_tjc_hmi_tx_text_display(x+1, y+1, - (char *)&hmi_tx_buffer[len], - "0"); + (char *)&hmi_tx_buffer[len], + "0"); } + } + /* 屏蔽状态显示: t(x+1)_16 */ + y = 15; // 第16列对应y=15 + if (leakage.sub_device_data[sub_device_index].flash_data.shield == BLOCKED) + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "禁用中"); + } + else + { + len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "启用中"); + } + } + + /*清空未使用的*/ + for (; i < DETAIL_MAIN_NUM; i++) + { + x = i; + len += gui_tjc_hmi_tx_text_display(x+1, 1, (char *)&hmi_tx_buffer[len], ""); + len += gui_tjc_hmi_tx_text_display(x+1, 2, (char *)&hmi_tx_buffer[len], ""); + len += gui_tjc_hmi_tx_text_display(x+1, 3, (char *)&hmi_tx_buffer[len], ""); + for (ch = 0; ch < APP_LEAKAGE_SUB_DEVICE_CH_NUM; ch++) + { + len += gui_tjc_hmi_tx_text_display(x+1, 4 + (ch*3), (char *)&hmi_tx_buffer[len], ""); + len += gui_tjc_hmi_tx_text_display(x+1, 5 + (ch*3), (char *)&hmi_tx_buffer[len], ""); + len += gui_tjc_hmi_tx_text_display(x+1, 6 + (ch*3), (char *)&hmi_tx_buffer[len], ""); + } + len += gui_tjc_hmi_tx_text_display(x+1, 16, (char *)&hmi_tx_buffer[len], ""); } } break; case 0x03: /* 翻页 */ { - /* 使用之前保存的全局区域索引 */ - region_idx = p_tjc_hmi->page.deliniter_main_index; - - /* 检查区域索引是否有效 */ - if (region_idx >= leakage.region_num) - { - return; /* 区域索引越界 */ - } - - /* 获取区域数据 */ + region_idx = p_tjc_hmi->page.deliniter_main_index; + if (region_idx >= leakage.region_num) return; + region_data = &leakage.region_data[region_idx]; + /*重新计算页数*/ + page_num = region_data->sub_device_num / DETAIL_MAIN_NUM; + remain_device_num = region_data->sub_device_num % DETAIL_MAIN_NUM; + if (remain_device_num > 0) page_num++; + if (page_num == 0) page_num = 1; + if(0x01 == p_data[0]) /* 下一页 */ { if(page_num - 1 <= p_tjc_hmi->page.detail_main_index) @@ -814,7 +964,63 @@ static void gui_tjc_hmi_detail_main_send(u8 cmd, u8 opa, u8 *p_data) { case 0x01: /* */ { - + u8 len_id = 0; + u8 device_id = 0; + + /* 解析设备ID:从p_data[0]开始,直到遇到分隔符 */ + while (p_data[len_id] != HMI_PROTO_ASCII_RX_DELINITER) { + if (p_data[len_id] < '0' || p_data[len_id] > '9') { + return; /* 非法字符 */ + } + len_id++; + if (len_id > 3) { /* ID最多3位数字(0-255) */ + return; + } + } + if (len_id == 0) { + return; /* ID不能为空 */ + } + + /* 将ASCII数字串转换为数值 */ + char id_str[4] = {0}; /* 最多3位数字加'\0' */ + memcpy(id_str, p_data, len_id); + id_str[len_id] = '\0'; + int temp_id = atoi(id_str); + if (temp_id < 0 || temp_id > 255) { + return; /* ID超出范围 */ + } + device_id = (u8)temp_id; + + /* 检查操作码及其后的分隔符 */ + u8 op_index = len_id + 1; /* 操作码位置 */ + u8 delim_index = len_id + 2; /* 操作码后的分隔符位置 */ + if (p_data[delim_index] != HMI_PROTO_ASCII_RX_DELINITER) { + return; + } + u8 operation = p_data[op_index]; /* 操作码直接作为数值 */ + + /* 遍历所有使能的设备,查找匹配的modbus_id */ + u8 found = 0; + for (u8 i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) { + if (leakage.sub_device_data[i].flash_data.state == ENABLE && + leakage.sub_device_data[i].flash_data.modbus_id == device_id) { + if (operation == 0x01) { + leakage.sub_device_data[i].flash_data.shield = BLOCKED; /* 屏蔽 */ + } else if (operation == 0x02) { + leakage.sub_device_data[i].flash_data.shield = UNBLOCKED; /* 恢复 */ + } else { + return; + } + found = 1; + break; + } + } + if (found) + { + /*将修改后的设备信息保存到 Flash*/ + gui_tjc_hmi_save_device_info_to_w25q(); + } + return; } break; @@ -828,53 +1034,56 @@ static void gui_tjc_hmi_login_send(u8 cmd,u8 opa,u8 *p_data) { u16 len = 0,i; - if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ + if(HMI_PROTO_CMD_GET == cmd) /* 获取数据 */ { switch(opa) { - case 0x01:/*读取flash中存储的密码*/ + case 0x01: /* 读取flash中存储的密码 */ { - memset(hmi_tx_buffer,0,sizeof(hmi_tx_buffer)); - len = gui_tjc_hmi_tx_text_display(1,1,(char *)hmi_tx_buffer,"%02X%02X%02X%02X", - p_tjc_hmi->password[0], - p_tjc_hmi->password[1], - p_tjc_hmi->password[2], - p_tjc_hmi->password[3]); - - gui_tjc_hmi_data_send(hmi_tx_buffer,len); - - }break; - case 0x02:/*无*/ - { - - }break; - default:return; + gui_tjc_hmi_read_password_from_w25q(); + memset(hmi_tx_buffer, 0, sizeof(hmi_tx_buffer)); + /* 将密码数值以连续数字形式发送到控件 t22_1 */ + len = gui_tjc_hmi_tx_text_display(22, 1, (char *)hmi_tx_buffer, + "%d%d%d%d", + p_tjc_hmi->password[0], + p_tjc_hmi->password[1], + p_tjc_hmi->password[2], + p_tjc_hmi->password[3]); + gui_tjc_hmi_data_send(hmi_tx_buffer, len); + return; /* 直接返回,避免外层重复发送 */ + } break; + case 0x02: /* 无操作 */ + default: + return; } - len = strlen((char *)hmi_tx_buffer); - gui_tjc_hmi_data_send(hmi_tx_buffer,len); } - else if(HMI_PROTO_CMD_SET == cmd)/*设置*/ + else if(HMI_PROTO_CMD_SET == cmd) /* 设置数据 */ { switch(opa) { - case 0x01:/*将密码存入flash中*/ + case 0x01: /* 将密码存入flash */ { - for(i=0; i<4; i++) + /* 将ASCII码转换为数值('0'~'9') */ + for(i = 0; i < 4; i++) { - p_tjc_hmi->password[i] = p_data[i]; + if(p_data[i] >= '0' && p_data[i] <= '9') + { + p_tjc_hmi->password[i] = p_data[i] - '0'; + } + else + { + p_tjc_hmi->password[i] = 0; /* 非法字符时清零 */ + } } - - /*保存到W25Q32*/ + /* 保存到W25Q32 */ gui_tjc_hmi_save_password_to_w25q(); - }break; - case 0x02:/*无*/ - { - - }break; - default:return; + /* 设置命令无需响应,直接返回 */ + return; + } break; + case 0x02: /* 无操作 */ + default: + return; } - len = strlen((char *)hmi_tx_buffer); - gui_tjc_hmi_data_send(hmi_tx_buffer,len); } } @@ -955,11 +1164,11 @@ static void gui_tjc_hmi_history_alarm_send(u8 cmd,u8 opa,u8 *p_data) "%d", history_record.device_id); - /* 设备名称: t(i+1)_3 */ - len += gui_tjc_hmi_tx_text_display(i+1, 3, - (char *)&hmi_tx_buffer[len], - "%s", - history_record.device_name); + /*通道信息:t(i+1)_3*/ + len += gui_tjc_hmi_tx_text_display(i+1,3, + (char *)&hmi_tx_buffer[len], + "%d", + history_record.channel); /* 报警类型: t(i+1)_4 */ alarm_type_str[0] = '\0'; @@ -975,18 +1184,11 @@ static void gui_tjc_hmi_history_alarm_send(u8 cmd,u8 opa,u8 *p_data) "%s", alarm_type_str); - /* 开始时间: t(i+1)_5 */ - uint16_t year = (history_record.start_time[0] << 8) | history_record.start_time[1]; - sprintf(time_str, "%04d-%02d-%02d %02d:%02d", - year, - history_record.start_time[2], - history_record.start_time[3], - history_record.start_time[4], - history_record.start_time[5]); + /* 设备名称: t(i+1)_5 */ len += gui_tjc_hmi_tx_text_display(i+1, 5, (char *)&hmi_tx_buffer[len], "%s", - time_str); + history_record.device_name); /* 漏液距离: t(i+1)_6 (如果是漏液报警才显示) */ if(history_record.alarm_type == APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) @@ -1002,6 +1204,20 @@ static void gui_tjc_hmi_history_alarm_send(u8 cmd,u8 opa,u8 *p_data) (char *)&hmi_tx_buffer[len], "0"); } + + /* 开始时间: t(i+1)_7 */ + uint16_t year = (history_record.start_time[0] << 8) | history_record.start_time[1]; + sprintf(time_str, "%04d-%02d-%02d %02d:%02d:%02d", + year, + history_record.start_time[2], + history_record.start_time[3], + history_record.start_time[4], + history_record.start_time[5], + history_record.start_time[6]); + len += gui_tjc_hmi_tx_text_display(i+1, 7, + (char *)&hmi_tx_buffer[len], + "%s", + time_str); } else { @@ -1069,6 +1285,24 @@ static void gui_tjc_hmi_history_alarm_send(u8 cmd,u8 opa,u8 *p_data) case 0x01:/*清空*/ { history.clean_history(); + p_tjc_hmi->page.history_alarm_index = 0; // 重置页码 + + memset(hmi_tx_buffer, 0, sizeof(hmi_tx_buffer)); + len = 0; + +// // 清空所有15行的7列数据 +// for(i = 0; i < HISTORY_ALARM_PER_PAGE; i++) +// { +// len += gui_tjc_hmi_tx_text_display(i+1, 1, (char *)&hmi_tx_buffer[len], ""); // 区域名 +// len += gui_tjc_hmi_tx_text_display(i+1, 2, (char *)&hmi_tx_buffer[len], ""); // 设备ID +// len += gui_tjc_hmi_tx_text_display(i+1, 3, (char *)&hmi_tx_buffer[len], ""); // 通道 +// len += gui_tjc_hmi_tx_text_display(i+1, 4, (char *)&hmi_tx_buffer[len], ""); // 报警类型 +// len += gui_tjc_hmi_tx_text_display(i+1, 5, (char *)&hmi_tx_buffer[len], ""); // 设备名称 +// len += gui_tjc_hmi_tx_text_display(i+1, 6, (char *)&hmi_tx_buffer[len], ""); // 漏液距离 +// len += gui_tjc_hmi_tx_text_display(i+1, 7, (char *)&hmi_tx_buffer[len], ""); // 时间 +// } + + gui_tjc_hmi_data_send(hmi_tx_buffer, len); }break; case 0x02:/*无*/ { @@ -1116,13 +1350,13 @@ static void gui_tjc_hmi_tcp_config_send(u8 cmd,u8 opa,u8 *p_data) W5500.Gateway_IP[1], W5500.Gateway_IP[2], W5500.Gateway_IP[3]); - len += gui_tjc_hmi_tx_text_display(1,4,(char *)&hmi_tx_buffer[len],"%s","114.114.114.114"); + len += gui_tjc_hmi_tx_text_display(1,4,(char *)&hmi_tx_buffer[len],"%s","5000"); }else if(p_data[0] == 0x00) { len += gui_tjc_hmi_tx_text_display(1,1,(char *)&hmi_tx_buffer[len],"%s","192.168.100.100"); len += gui_tjc_hmi_tx_text_display(1,2,(char *)&hmi_tx_buffer[len],"%s","255.255.255.0"); len += gui_tjc_hmi_tx_text_display(1,3,(char *)&hmi_tx_buffer[len],"%s","192.168.50.1"); - len += gui_tjc_hmi_tx_text_display(1,4,(char *)&hmi_tx_buffer[len],"%s","114.114.114.114"); + len += gui_tjc_hmi_tx_text_display(1,4,(char *)&hmi_tx_buffer[len],"%s","5000"); } }break; case 0x02:/*无*/ @@ -1141,56 +1375,63 @@ static void gui_tjc_hmi_tcp_config_send(u8 cmd,u8 opa,u8 *p_data) case 0x01:/*添加网络配置,并将网络配置信息存入flash*/ { u8 field_count = 0; - u8 *current_pos = p_data; - - /*解析IP地址*/ - for(i=0; i<16; i++) - { - if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) - { - memcpy(W5500.IP_Addr, current_pos, i); - current_pos += (i + 1); - field_count++; - break; + u8 *current_pos = p_data; + u8 ip_str[16], mask_str[16], gw_str[16], dns_str[16]; + u8 ip_len, mask_len, gw_len, dns_len; + + /* 解析IP地址 */ + for (i = 0; i < 16; i++) { + if (current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { + ip_len = i; + memcpy(ip_str, current_pos, ip_len); + ip_str[ip_len] = '\0'; + current_pos += (i + 1); + field_count++; + break; + } } - } - - /*解析子网掩码*/ - for(i=0; i<16; i++) - { - if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) - { - memcpy(W5500.Sub_Mask, current_pos, i); - current_pos += (i + 1); - field_count++; - break; + + /* 解析子网掩码 */ + for (i = 0; i < 16; i++) { + if (current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { + mask_len = i; + memcpy(mask_str, current_pos, mask_len); + mask_str[mask_len] = '\0'; + current_pos += (i + 1); + field_count++; + break; + } } - } - - /*解析网关*/ - for(i=0; i<16; i++) - { - if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) - { - memcpy(W5500.Gateway_IP, current_pos, i); - current_pos += (i + 1); - field_count++; - break; + + /* 解析网关 */ + for (i = 0; i < 16; i++) { + if (current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { + gw_len = i; + memcpy(gw_str, current_pos, gw_len); + gw_str[gw_len] = '\0'; + current_pos += (i + 1); + field_count++; + break; + } } - } - - /*解析DNS服务器*/ - for(i=0; i<16; i++) - { - if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) - { -// memcpy(p_tjc_hmi->network_config.dns, current_pos, i); -// p_tjc_hmi->network_config.dns[i] = '\0'; - field_count++; - break; + + /* 解析DNS服务器 */ + for (i = 0; i < 16; i++) { + if (current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { + dns_len = i; + memcpy(dns_str, current_pos, dns_len); + dns_str[dns_len] = '\0'; + current_pos += (i + 1); + field_count++; + break; + } + } + + if (field_count == 4) { + parse_ip_string(ip_str, ip_len, W5500.IP_Addr); + parse_ip_string(mask_str, mask_len, W5500.Sub_Mask); + parse_ip_string(gw_str, gw_len, W5500.Gateway_IP); } - } - }break; case 0x02:/*无*/ @@ -1217,22 +1458,6 @@ static void gui_tjc_hmi_device_config_send(u8 cmd,u8 opa,u8 *p_data) memset(hmi_tx_buffer,0,sizeof(hmi_tx_buffer)); - - - /*计算总页数*/ - page_num = enabled_device_count / DEVICES_PER_PAGE; - remain_region_num = enabled_device_count % DEVICES_PER_PAGE; - if(remain_region_num > 0) - { - page_num++; - } - - /*确保页码在有效范围内*/ - if(p_tjc_hmi->page.device_config_index >= page_num) - { - p_tjc_hmi->page.device_config_index = 0; - } - if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) @@ -1253,9 +1478,32 @@ static void gui_tjc_hmi_device_config_send(u8 cmd,u8 opa,u8 *p_data) enabled_device_count++; } } - + + /*计算总页数*/ + page_num = enabled_device_count / DEVICES_PER_PAGE; + remain_region_num = enabled_device_count % DEVICES_PER_PAGE; + if(remain_region_num > 0) + { + page_num++; + } + + /*确保页码在有效范围内*/ + if(p_tjc_hmi->page.device_config_index >= page_num) + { + p_tjc_hmi->page.device_config_index = 0; + } + if(enabled_device_count == 0) { + for(i = 0; i < DEVICES_PER_PAGE; i++) + { + len += gui_tjc_hmi_tx_text_display(i+1, 1, (char *)&hmi_tx_buffer[len], ""); + len += gui_tjc_hmi_tx_text_display(i+1, 2, (char *)&hmi_tx_buffer[len], ""); + len += gui_tjc_hmi_tx_text_display(i+1, 3, (char *)&hmi_tx_buffer[len], ""); + len += gui_tjc_hmi_tx_text_display(i+1, 4, (char *)&hmi_tx_buffer[len], ""); + } + len = strlen((char *)hmi_tx_buffer); + gui_tjc_hmi_data_send(hmi_tx_buffer, len); return; } @@ -1353,8 +1601,53 @@ static void gui_tjc_hmi_device_config_send(u8 cmd,u8 opa,u8 *p_data) }break; + case 0x02: /*读取四个COM口的波特率*/ + { + u8 baud_vals[4]; + for (i = 0; i < 4; i++) { + baud_vals[i] = app_com.com[i].flash_data.baudrate; + } + + len = 0; + len += sprintf((char*)&hmi_tx_buffer[len], "cb0.val=%d", baud_vals[0]); + for (i = 0; i < 3; i++) hmi_tx_buffer[len + i] = 0xFF; + len += 3; + + len += sprintf((char*)&hmi_tx_buffer[len], "cb1.val=%d", baud_vals[1]); + for (i = 0; i < 3; i++) hmi_tx_buffer[len + i] = 0xFF; + len += 3; + + len += sprintf((char*)&hmi_tx_buffer[len], "cb2.val=%d", baud_vals[2]); + for (i = 0; i < 3; i++) hmi_tx_buffer[len + i] = 0xFF; + len += 3; + + len += sprintf((char*)&hmi_tx_buffer[len], "cb3.val=%d", baud_vals[3]); + for (i = 0; i < 3; i++) hmi_tx_buffer[len + i] = 0xFF; + len += 3; + + gui_tjc_hmi_data_send(hmi_tx_buffer, len); + return; + } break; + case 0x03:/*翻页功能,每页显示8个设备*/ { + enabled_device_count = 0; + for (i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) + { + if (leakage.sub_device_data[i].flash_data.state == ENABLE) + { + enabled_device_count++; + } + } + + page_num = enabled_device_count / DEVICES_PER_PAGE; + remain_region_num = enabled_device_count % DEVICES_PER_PAGE; + if (remain_region_num > 0) + { + page_num++; + } + if (page_num == 0) page_num = 1; + if(0x01 == p_data[0]) /*下一页*/ { if(page_num - 1 <= p_tjc_hmi->page.device_config_index) @@ -1452,6 +1745,45 @@ static void gui_tjc_hmi_device_config_send(u8 cmd,u8 opa,u8 *p_data) } } +// /*解析波特率*/ +// for(i = 0; i < 10; i++) // 波特率最大为115200 +// { +// if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) +// { +// if(i == 0) +// { +// /*波特率不能为空*/ +// return; +// } + +// char baud_str[10] = {0}; +// memcpy(baud_str, current_pos, i); +// baud_str[i] = '\0'; + +// /*将字符串波特率转换为数值*/ +// if(strcmp(baud_str, "2400") == 0) +// { +// new_device.baudrate = 0; +// } +// else if(strcmp(baud_str, "4800") == 0) +// { +// new_device.baudrate = 1; +// } +// else if(strcmp(baud_str, "9600") == 0) +// { +// new_device.baudrate = 2; +// } +// else if(strcmp(baud_str, "115200") == 0) +// { +// new_device.baudrate = 3; +// } + +// current_pos += (i + 1); +// field_count++; +// break; +// } +// } + /*解析区域名*/ for(i = 0; i < APP_LEAKAGE_STRING_NANE_LEN; i++) { @@ -1508,6 +1840,8 @@ static void gui_tjc_hmi_device_config_send(u8 cmd,u8 opa,u8 *p_data) if (leakage.sub_device_data[x].flash_data.modbus_id == new_device.modbus_id) { new_device.state = ENABLE; + new_device.baudrate = app_com.com[new_device.com].flash_data.baudrate; + new_device.shield = UNBLOCKED; leakage.sub_device_data[x].flash_data = new_device; gui_tjc_hmi_save_device_info_to_w25q(); gui_tjc_hmi_class_update(); @@ -1522,15 +1856,31 @@ static void gui_tjc_hmi_device_config_send(u8 cmd,u8 opa,u8 *p_data) /*设置默认状态为启用*/ new_device.state = ENABLE; + /*波特率设置*/ + new_device.baudrate = app_com.com[new_device.com].flash_data.baudrate; + + new_device.shield = UNBLOCKED; + /*添加到app_leakage的设备列表中*/ leakage.sub_device_data[empty_slot_index].flash_data = new_device; + /*清空通道数据*/ + memset(leakage.sub_device_data[empty_slot_index].ch_data, 0, + sizeof(leakage.sub_device_data[empty_slot_index].ch_data)); + /*保存到W25Q32*/ gui_tjc_hmi_save_device_info_to_w25q(); /*重新分类区域*/ gui_tjc_hmi_class_update(); +// if (new_device.com < APP_COM_NUM && new_device.baudrate < 4) { +// app_com.com[new_device.com].set.baud_rate( +// &app_com.com[new_device.com], +// new_device.baudrate +// ); +// } + } else { @@ -1568,64 +1918,94 @@ static void gui_tjc_hmi_device_config_send(u8 cmd,u8 opa,u8 *p_data) return; } - /*遍历8个选中框字节,删除被选中的设备*/ - u8 deleted_count = 0; /*记录删除的设备数量*/ - u8 shift_offset = 0; /*偏移量,用于处理删除后设备索引的变化*/ - - for(i = 0; i < 8; i++) + /*遍历8个选中框字节,删除被选中的设备(从后往前删除)*/ + u8 deleted_count = 0; + for(i = page_device_count; i > 0; i--) { - /*只处理当前页实际存在的设备*/ - if(i >= page_device_count) + u8 idx = i - 1; + if(p_data[idx] == 0x01) { - break; - } - - /*检查设备是否被选中删除*/ - if(p_data[i] == 0x01) - { - /*计算实际要删除的设备在app_leakage中的索引*/ - u8 actual_index = page_device_indices[i] - shift_offset; - - /*直接删除设备:将后面的设备向前移动*/ + u8 actual_index = page_device_indices[idx]; // 直接使用原始索引 + /*将后面的设备向前移动*/ for(j = actual_index; j < APP_LEAKAGE_SUB_DEVICE_NUM - 1; j++) { leakage.sub_device_data[j].flash_data = leakage.sub_device_data[j + 1].flash_data; } - /*最后一个设备清空*/ - memset(&leakage.sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM - 1].flash_data, 0, + memset(&leakage.sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM - 1].flash_data, 0, sizeof(app_leakage_sub_device_flash_data_t)); leakage.sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM - 1].flash_data.state = DISABLE; - /*删除设备后,后面的设备索引会变化,更新偏移量*/ - shift_offset++; - deleted_count++; + /*清空通道数据*/ + memset(leakage.sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM - 1].ch_data, 0, + sizeof(leakage.sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM - 1].ch_data)); - /*重新计算当前页的设备索引,设备前移*/ - for(u8 k = i + 1; k < page_device_count; k++) - { - page_device_indices[k]--; - } + deleted_count++; } } - + if(deleted_count > 0) { /*保存到W25Q32*/ gui_tjc_hmi_save_device_info_to_w25q(); - /*重新分类区域*/ gui_tjc_hmi_class_update(); - - /*发送确认响应*/ + /*可选:发送确认响应*/ } else { /*没有选中任何设备*/ - return; + return; } - }break; - default:return; + }break; + + case 0x03: /*设置波特率,波特率1对应COM1的*/ + { + u8 *ptr = p_data; + u8 baud_vals[APP_COM_NUM]; + char temp_buf[10]; /*临时存储ASCII字符串*/ + + for (i = 0; i < APP_COM_NUM; i++) { + u8 temp_len = 0; + // 提取直到下一个0xAA分隔符 + while (*ptr != HMI_PROTO_ASCII_RX_DELINITER && temp_len < sizeof(temp_buf) - 1) { + temp_buf[temp_len++] = *ptr++; + } + if (*ptr != HMI_PROTO_ASCII_RX_DELINITER) { + return; + } + temp_buf[temp_len] = '\0'; + ptr++; // 跳过分隔符 + + // 将ASCII字符串转换为整数波特率 + u32 baud_int = atoi(temp_buf); + + // 映射到枚举值 + u8 enum_val; + if (baud_int == 4800) enum_val = 0; + else if (baud_int == 9600) enum_val = 1; + else if (baud_int == 19200) enum_val = 2; + else if (baud_int == 57600) enum_val = 3; + else if (baud_int == 115200) enum_val = 4; + else enum_val = 4; + + baud_vals[i] = enum_val; + } + + /*设置每个COM的波特率*/ + for (i = 0; i < APP_COM_NUM; i++) { + if (app_com.com[i].flash_data.baudrate != baud_vals[i]) { + app_com.com[i].flash_data.baudrate = baud_vals[i]; + if (app_com.com[i].set.baud_rate) { + app_com.com[i].set.baud_rate(&app_com.com[i], baud_vals[i]); + } + } + } + app_com.save_flah(); + return; + } break; + + default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); @@ -1645,41 +2025,48 @@ static void gui_tjc_hmi_time_set_send(u8 cmd,u8 opa,u8 *p_data) { case 0x01: /* 设置时间 */ { - /* 检查数据长度 */ - if(p_data[4] != 0xAA || /* 年后的分隔符 */ - p_data[7] != 0xAA || /* 月后的分隔符 */ - p_data[10] != 0xAA || /* 日后的分隔符 */ - p_data[13] != 0xAA) /* 时后的分隔符 */ + int idx = 0; /*数据索引*/ + int field = 0; /*当前字段编号(0:年,1:月,2:日,3:时,4:分)*/ + char temp_buf[5]; + int value; + + while (field < 5) + { + int len = 0; + /*收集当前字段的ASCII字符直到遇到分隔符0xAA*/ + while (p_data[idx] != 0xAA) + { + if (len >= 4) + { + return; + } + temp_buf[len++] = p_data[idx++]; + } + + if (len == 0) { return; } - - /* 解析年份 (4个字节ASCII码) */ - memcpy(temp_buf, &p_data[0], 4); - temp_buf[4] = '\0'; /* 添加结束符 */ - new_time.Year = atoi(temp_buf)%2000; - - /* 解析月份 (2个字节ASCII码) */ - memcpy(temp_buf, &p_data[5], 2); - temp_buf[2] = '\0'; /* 添加结束符 */ - new_time.Month = atoi(temp_buf); - - /* 解析日期 (2个字节ASCII码) */ - memcpy(temp_buf, &p_data[8], 2); - temp_buf[2] = '\0'; /* 添加结束符 */ - new_time.Day = atoi(temp_buf); - - /* 解析小时 (2个字节ASCII码) */ - memcpy(temp_buf, &p_data[11], 2); - temp_buf[2] = '\0'; /* 添加结束符 */ - new_time.Hour = atoi(temp_buf); - - /* 解析分钟 (2个字节ASCII码) */ - memcpy(temp_buf, &p_data[14], 2); - temp_buf[2] = '\0'; /* 添加结束符 */ - new_time.Minute = atoi(temp_buf); - - DS1302.Set(&new_time); + + temp_buf[len] = '\0'; + value = atoi(temp_buf); + + /* 根据字段序号赋值*/ + switch (field) + { + case 0: new_time.Year = value % 2000; break; // 年份取后两位 + case 1: new_time.Month = value; break; + case 2: new_time.Day = value; break; + case 3: new_time.Hour = value; break; + case 4: new_time.Minute = value; break; + } + + /*跳过当前分隔符0xAA,准备下一个字段*/ + idx++; + field++; + } + + DS1302.Set(&new_time); } break; diff --git a/leakage_system/usr/protocol/proto_modbus_master_leakage.c b/leakage_system/usr/protocol/proto_modbus_master_leakage.c index a515d40..bd0c5fa 100644 --- a/leakage_system/usr/protocol/proto_modbus_master_leakage.c +++ b/leakage_system/usr/protocol/proto_modbus_master_leakage.c @@ -68,7 +68,7 @@ static void proto_leakage_init(proto_leakage_t *p_leakage) } else if(p_leakage == &modbus_leakage[APP_COM4]) { - com_to_uart[APP_COM3]->rx_data_analysis = proto_leakage_rx_task; + com_to_uart[APP_COM4]->rx_data_analysis = proto_leakage_rx_task; } /*绑定modbus_id和对应的索引在app_com中完成*/ } @@ -251,7 +251,8 @@ static void proto_leakage_rx_task(u8 *p_data,u16 len,void *other_data) { /*计算当前设备索引*/ u8 sensor_index = p_sensor->comm.leakage_data_index; - u16 ch_addr_offset[4] = {0,4,8,11}; /*漏液待数据地址偏移*/ +// u16 ch_addr_offset[4] = {0,4,8,11}; /*漏液待数据地址偏移*/ + u16 ch_addr_offset[4] = {0,8,16,22}; /*漏液待数据地址偏移*/ u16 temp; if(sensor_index >= APP_LEAKAGE_SUB_DEVICE_NUM) diff --git a/leakage_system/usr/protocol/proto_modbus_tcp_slave_ex.c b/leakage_system/usr/protocol/proto_modbus_tcp_slave_ex.c index a52e715..73356a5 100644 --- a/leakage_system/usr/protocol/proto_modbus_tcp_slave_ex.c +++ b/leakage_system/usr/protocol/proto_modbus_tcp_slave_ex.c @@ -265,7 +265,16 @@ static u16 proto_modbus_data_read(u16 addr) { case 0:/*端口&ID*/ { - data = (leakage.sub_device_data[sensor_index].flash_data.com + 1)<< 8 | leakage.sub_device_data[sensor_index].flash_data.modbus_id; +// data = (leakage.sub_device_data[sensor_index].flash_data.com + 1)<< 8 | leakage.sub_device_data[sensor_index].flash_data.modbus_id; + u16 value = (leakage.sub_device_data[sensor_index].flash_data.com + 1) << 8; + value |= leakage.sub_device_data[sensor_index].flash_data.modbus_id; + if (leakage.sub_device_data[sensor_index].flash_data.shield == BLOCKED) { + value |= 0x8000; /*最高位表示屏蔽*/ + } + if (leakage.sub_device_data[sensor_index].flash_data.state == ENABLE) { + value |= 0x4000; /*次高位表示使能*/ + } + data = value; }break; case 1 ... 5:/*区域名*/ {