update modbus
This commit is contained in:
@@ -8,7 +8,10 @@
|
||||
#include "bsp_Led.h"
|
||||
#include "bsp_74HC4067.h"
|
||||
#include "bsp_Flash.h"
|
||||
#include "bsp_W5500.h"
|
||||
#include "bsp_w25q.h"
|
||||
#include "bsp_DS1302.h"
|
||||
#include "app_leakage.h"
|
||||
|
||||
#include "proto_modbus_master_tdlas.h"
|
||||
#include "proto_modbus_slave_ex.h"
|
||||
@@ -60,7 +63,10 @@ void app_init(void)
|
||||
UartCH_Config.init();
|
||||
|
||||
app_timer.init(APP_TIMER_TASK_NUM,app_timer_task); /*分时复用,时间片轮询*/
|
||||
W5500.Init();
|
||||
tjc_hmi.init();
|
||||
DS1302.Init();
|
||||
tdlas.init();
|
||||
led.init();
|
||||
|
||||
//Wdg.Init();
|
||||
@@ -77,6 +83,7 @@ void app_task(void)
|
||||
{
|
||||
app_timer.task();
|
||||
task_idle();
|
||||
W5500.Task();
|
||||
}
|
||||
/*空闲执行的函数*/
|
||||
void task_idle(void)
|
||||
@@ -108,12 +115,14 @@ void task_200ms(void)
|
||||
void task_500ms(void)
|
||||
{
|
||||
led.task();
|
||||
tdlas.tx_task();
|
||||
}
|
||||
|
||||
|
||||
void task_1s(void)
|
||||
{
|
||||
|
||||
p_leakage->task();
|
||||
DS1302.Task();
|
||||
}
|
||||
|
||||
void task_2s(void)
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
#include "app_leakage.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "bsp_w25q.h"
|
||||
|
||||
|
||||
static void history_clear_all(void);
|
||||
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record);
|
||||
static void history_init(void);
|
||||
static void history_save_metadata(void);
|
||||
|
||||
app_leakage_t leakage =
|
||||
{
|
||||
|
||||
.region_num = 0,
|
||||
.sub_device_num = 0,
|
||||
.init = NULL,
|
||||
.task = app_leakage_task
|
||||
};
|
||||
app_leakage_t *p_leakage = &leakage;
|
||||
|
||||
app_hitory_t history =
|
||||
{
|
||||
.read_history = history_read_record,
|
||||
.clean_history = history_clear_all,
|
||||
.init_history = history_init
|
||||
};
|
||||
|
||||
/*区域分类,将同一区域名的设备划分到一起*/
|
||||
static void app_leakage_region_classify(void)
|
||||
void app_leakage_region_classify(void)
|
||||
{
|
||||
u16 i,j;
|
||||
u8 add_region_flag;
|
||||
@@ -36,7 +50,7 @@ static void app_leakage_region_classify(void)
|
||||
{
|
||||
/*添加子设备*/
|
||||
p_leakage->region_data[j].sub_device_index[p_leakage->region_data[j].leakage_num] = i;/*绑定子设备索引*/
|
||||
p_leakage->region_data[j].leakage_num++; /*区域中子系统数据++*/
|
||||
p_leakage->region_data[j].sub_device_num++; /*区域中子系统数据++*/
|
||||
add_region_flag = 0;/*不添加新区域*/
|
||||
break;
|
||||
}
|
||||
@@ -48,7 +62,7 @@ static void app_leakage_region_classify(void)
|
||||
/*复制名称*/
|
||||
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].leakage_num++; /*区域中子系统数据++*/
|
||||
p_leakage->region_data[p_leakage->region_num].sub_device_num++; /*区域中子系统数据++*/
|
||||
p_leakage->region_num++; /*区域数量++*/
|
||||
}
|
||||
}
|
||||
@@ -58,43 +72,285 @@ static void app_leakage_region_classify(void)
|
||||
/*异常状态设备数量统计*/
|
||||
void app_leakage_task(void)
|
||||
{
|
||||
u16 i,j,k,sub_device_index;
|
||||
/*计算异常设备数量*/
|
||||
/*遍历区域*/
|
||||
for(i=0;i<p_leakage->region_num;i++)
|
||||
static u16 prev_ch_state[APP_LEAKAGE_SUB_DEVICE_NUM][APP_LEAKAGE_SUB_DEVICE_CH_NUM] = {0};
|
||||
u16 i, j, k, sub_device_index;
|
||||
static u8 initialized = 0;
|
||||
|
||||
/* 初始化历史模块 */
|
||||
if(!initialized)
|
||||
{
|
||||
history.init_history();
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
/* 初始化区域异常统计 */
|
||||
for(i = 0; i < p_leakage->region_num; i++)
|
||||
{
|
||||
/*清除设备*/
|
||||
p_leakage->region_data[i].leakage_num = 0;
|
||||
p_leakage->region_data[i].open_num = 0;
|
||||
p_leakage->region_data[i].time_out_num = 0;
|
||||
/*遍历区域里面的设备*/
|
||||
for(j=0;j<p_leakage->region_data[i].leakage_num;j++)
|
||||
}
|
||||
|
||||
/* 检测状态变化并统计异常数量 */
|
||||
for(i = 0; i < p_leakage->region_num; i++)
|
||||
{
|
||||
for(j = 0; j < p_leakage->region_data[i].sub_device_num; j++)
|
||||
{
|
||||
/*记录索引*/
|
||||
sub_device_index = p_leakage->region_data[i].sub_device_index[j];
|
||||
|
||||
/*遍历通道*/
|
||||
for(k=0;k<APP_LEAKAGE_SUB_DEVICE_CH_NUM;k++)
|
||||
/* 检查设备是否启用 */
|
||||
if(p_leakage->sub_device_data[sub_device_index].flash_data.state != ENABLE)
|
||||
{
|
||||
/*通讯超时*/
|
||||
if(p_leakage->sub_device_data[sub_device_index].ch_data[k].state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT)
|
||||
continue;
|
||||
}
|
||||
|
||||
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
|
||||
{
|
||||
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
|
||||
u16 prev_state = prev_ch_state[sub_device_index][k];
|
||||
u16 leak_distance = p_leakage->sub_device_data[sub_device_index].ch_data[k].distance;
|
||||
|
||||
/* 检测状态变化并记录历史报警 */
|
||||
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) &&
|
||||
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE))
|
||||
{
|
||||
p_leakage->region_data[i].time_out_num++;
|
||||
break;
|
||||
/* 漏液报警开始 - 记录历史报警 */
|
||||
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE, leak_distance);
|
||||
}
|
||||
/*断带*/
|
||||
else if(p_leakage->sub_device_data[sub_device_index].ch_data[k].state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN)
|
||||
|
||||
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) &&
|
||||
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN))
|
||||
{
|
||||
p_leakage->region_data[i].open_num++;
|
||||
break;
|
||||
/* 断带报警开始 - 记录历史报警 */
|
||||
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_OPEN, 0);
|
||||
}
|
||||
/*漏液*/
|
||||
else if(p_leakage->sub_device_data[sub_device_index].ch_data[k].state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE)
|
||||
|
||||
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT) &&
|
||||
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT))
|
||||
{
|
||||
p_leakage->region_data[i].leakage_num++;
|
||||
break;
|
||||
}
|
||||
/* 通讯超时报警开始 - 记录历史报警 */
|
||||
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT, 0);
|
||||
}
|
||||
|
||||
/* 更新历史状态 */
|
||||
prev_ch_state[sub_device_index][k] = current_state;
|
||||
}
|
||||
|
||||
/* 统计区域异常设备数量 - 按设备统计 */
|
||||
|
||||
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
|
||||
{
|
||||
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
|
||||
|
||||
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT)
|
||||
{
|
||||
p_leakage->region_data[i].time_out_num++;
|
||||
continue; /* 通讯超时,设备已离线,不再检查其他异常 */
|
||||
}
|
||||
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN)
|
||||
{
|
||||
|
||||
p_leakage->region_data[i].open_num++;
|
||||
}
|
||||
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE)
|
||||
{
|
||||
p_leakage->region_data[i].leakage_num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 获取当前时间 */
|
||||
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; /* 分 */
|
||||
}
|
||||
|
||||
/* 从Flash读取历史报警元数据 */
|
||||
static void history_read_metadata(void)
|
||||
{
|
||||
app_leakage_history_metadata_t temp_metadata;
|
||||
|
||||
w25q32.read(W25Q32_HISTORY_ALARM_METADATA_ADDR,
|
||||
(uint8_t*)&temp_metadata,
|
||||
sizeof(app_leakage_history_metadata_t));
|
||||
|
||||
|
||||
if(temp_metadata.total_records <= temp_metadata.max_records &&
|
||||
temp_metadata.write_index < temp_metadata.max_records)
|
||||
{
|
||||
/* 数据有效,复制到全局变量 */
|
||||
memcpy(&leakage.history_metadata, &temp_metadata, sizeof(app_leakage_history_metadata_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 数据无效,初始化 */
|
||||
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
|
||||
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
|
||||
|
||||
/* 保存到Flash */
|
||||
history_save_metadata();
|
||||
}
|
||||
}
|
||||
|
||||
/* 保存历史报警元数据到Flash */
|
||||
static void history_save_metadata(void)
|
||||
{
|
||||
/* 擦除元数据扇区 */
|
||||
w25q32_sector_erase(W25Q32_HISTORY_ALARM_METADATA_ADDR);
|
||||
|
||||
/* 写入元数据 */
|
||||
w25q32.write(W25Q32_HISTORY_ALARM_METADATA_ADDR,
|
||||
(uint8_t*)&leakage.history_metadata,
|
||||
sizeof(app_leakage_history_metadata_t));
|
||||
}
|
||||
|
||||
/* 计算记录在Flash中的地址 */
|
||||
static uint32_t history_calc_record_addr(u32 record_index)
|
||||
{
|
||||
return W25Q32_HISTORY_ALARM_DATA_ADDR +
|
||||
(record_index * HISTORY_ALARM_RECORD_SIZE);
|
||||
}
|
||||
|
||||
/* 获取记录所在的扇区地址 */
|
||||
static uint32_t history_calc_sector_addr(u32 record_index)
|
||||
{
|
||||
uint32_t record_addr = history_calc_record_addr(record_index);
|
||||
return record_addr & ~(W25Q32_SECTOR_SIZE - 1); /* 4K对齐 */
|
||||
}
|
||||
|
||||
/* 添加历史报警记录 */
|
||||
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance)
|
||||
{
|
||||
app_leakage_history_alarm_t new_alarm;
|
||||
uint32_t write_addr;
|
||||
|
||||
/* 填充报警记录 */
|
||||
memset(&new_alarm, 0, sizeof(app_leakage_history_alarm_t));
|
||||
|
||||
/* 区域名 */
|
||||
if(region_idx < leakage.region_num)
|
||||
{
|
||||
memcpy(new_alarm.region_name, leakage.region_data[region_idx].name,
|
||||
APP_LEAKAGE_STRING_NANE_LEN);
|
||||
}
|
||||
|
||||
/* 设备ID和名称 */
|
||||
if(device_idx < APP_LEAKAGE_SUB_DEVICE_NUM)
|
||||
{
|
||||
new_alarm.device_id = leakage.sub_device_data[device_idx].flash_data.modbus_id;
|
||||
memcpy(new_alarm.device_name, leakage.sub_device_data[device_idx].flash_data.device_name,
|
||||
APP_LEAKAGE_STRING_NANE_LEN);
|
||||
}
|
||||
|
||||
/* 报警类型、通道和漏液距离 */
|
||||
new_alarm.alarm_type = alarm_type;
|
||||
new_alarm.channel = channel;
|
||||
new_alarm.leak_distance = leak_distance;
|
||||
|
||||
/* 开始时间 */
|
||||
get_current_time(new_alarm.start_time);
|
||||
|
||||
/* 计算写入地址 */
|
||||
write_addr = history_calc_record_addr(leakage.history_metadata.write_index);
|
||||
|
||||
/* 检查是否需要擦除新扇区 */
|
||||
uint32_t current_sector = history_calc_sector_addr(leakage.history_metadata.write_index);
|
||||
uint32_t prev_sector = history_calc_sector_addr(
|
||||
(leakage.history_metadata.write_index == 0) ?
|
||||
leakage.history_metadata.max_records - 1 :
|
||||
leakage.history_metadata.write_index - 1);
|
||||
|
||||
/* 如果切换到新扇区,需要擦除 */
|
||||
if(current_sector != prev_sector)
|
||||
{
|
||||
w25q32_sector_erase(current_sector);
|
||||
}
|
||||
|
||||
/* 写入记录 */
|
||||
w25q32.write(write_addr, (uint8_t*)&new_alarm, HISTORY_ALARM_RECORD_SIZE);
|
||||
|
||||
/* 更新元数据 */
|
||||
leakage.history_metadata.write_index++;
|
||||
if(leakage.history_metadata.write_index >= leakage.history_metadata.max_records)
|
||||
{
|
||||
leakage.history_metadata.write_index = 0;
|
||||
}
|
||||
|
||||
if(leakage.history_metadata.total_records < leakage.history_metadata.max_records)
|
||||
{
|
||||
leakage.history_metadata.total_records++;
|
||||
}
|
||||
|
||||
/* 保存元数据 */
|
||||
history_save_metadata();
|
||||
}
|
||||
|
||||
/* 读取历史报警记录 */
|
||||
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record)
|
||||
{
|
||||
if(record_index >= leakage.history_metadata.total_records)
|
||||
{
|
||||
return 0; /* 记录索引无效 */
|
||||
}
|
||||
|
||||
/* 计算实际存储索引(考虑循环队列) */
|
||||
uint32_t actual_index;
|
||||
if(leakage.history_metadata.total_records == leakage.history_metadata.max_records)
|
||||
{
|
||||
/* 缓冲区已满,计算相对索引 */
|
||||
actual_index = (leakage.history_metadata.write_index + record_index) %
|
||||
leakage.history_metadata.max_records;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 缓冲区未满,直接读取 */
|
||||
actual_index = record_index;
|
||||
}
|
||||
|
||||
uint32_t read_addr = history_calc_record_addr(actual_index);
|
||||
w25q32.read(read_addr, (uint8_t*)record, HISTORY_ALARM_RECORD_SIZE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 清空所有历史报警记录 */
|
||||
static void history_clear_all(void)
|
||||
{
|
||||
/* 重置元数据 */
|
||||
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
|
||||
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
|
||||
|
||||
/* 保存元数据 */
|
||||
history_save_metadata();
|
||||
|
||||
/* 擦除所有数据扇区(可选) */
|
||||
for(uint32_t i = 0; i < HISTORY_ALARM_SECTORS_NEEDED; i++)
|
||||
{
|
||||
uint32_t sector_addr = W25Q32_HISTORY_ALARM_DATA_ADDR + i * W25Q32_SECTOR_SIZE;
|
||||
w25q32_sector_erase(sector_addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 初始化历史报警模块 */
|
||||
static void history_init(void)
|
||||
{
|
||||
/* 读取元数据 */
|
||||
history_read_metadata();
|
||||
}
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
#define APP_LEAKAGE_SUB_DEVICE_NUM (32)
|
||||
#define APP_LEAKAGE_SUB_DEVICE_CH_NUM (4)
|
||||
|
||||
void app_leakage_task(void);
|
||||
void app_leakage_region_classify(void);
|
||||
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance);
|
||||
|
||||
|
||||
/*子设备存储的参数*/
|
||||
typedef struct
|
||||
{
|
||||
@@ -33,6 +38,8 @@ typedef struct
|
||||
u16 state; /*状态*/
|
||||
u16 distance; /*漏液距离*/
|
||||
}ch_data[APP_LEAKAGE_SUB_DEVICE_CH_NUM]; /*通道数据*/
|
||||
u8 heartbeat; /*心跳包,0-59循环*/
|
||||
u8 test_mode; /*测试模式,0=正常,1-4=测试对应通道*/
|
||||
}app_leakage_sub_device_class_t;
|
||||
|
||||
|
||||
@@ -47,6 +54,27 @@ typedef struct
|
||||
u8 sub_device_index[APP_LEAKAGE_SUB_DEVICE_NUM]; /*设备的索引*/
|
||||
}app_leakage_region_data_class_t;
|
||||
|
||||
/* 历史报警记录结构 */
|
||||
typedef struct
|
||||
{
|
||||
u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 区域名 */
|
||||
u8 device_id; /* 设备ID */
|
||||
u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 设备名称 */
|
||||
u16 alarm_type; /* 报警类型 */
|
||||
u8 start_time[6]; /* 开始时间: 年(2字节)月日时分 */
|
||||
u16 leak_distance; /* 漏液距离 (0表示非漏液报警) */
|
||||
u8 channel; /* 通道号 (0-3) */
|
||||
} app_leakage_history_alarm_t;
|
||||
|
||||
/* 历史报警管理结构 */
|
||||
typedef struct
|
||||
{
|
||||
u32 total_records; /* 总记录数 */
|
||||
u32 write_index; /* 写指针 */
|
||||
u32 read_index; /* 读指针 */
|
||||
u32 max_records; /* 最大记录数 */
|
||||
} app_leakage_history_metadata_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 region_num;
|
||||
@@ -54,9 +82,20 @@ typedef struct
|
||||
app_leakage_region_data_class_t region_data[APP_LEAKAGE_SUB_DEVICE_NUM];
|
||||
app_leakage_sub_device_class_t sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM];
|
||||
|
||||
app_leakage_history_metadata_t history_metadata;
|
||||
|
||||
void (*init)(void); /*初始化*/
|
||||
void (*task)(void); /*执行任务*/
|
||||
}app_leakage_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 (*read_history)(u32, app_leakage_history_alarm_t *);
|
||||
void (*clean_history)(void);
|
||||
void (*init_history)(void);
|
||||
}app_hitory_t;
|
||||
|
||||
extern app_leakage_t leakage;
|
||||
#endif
|
||||
extern app_leakage_t *p_leakage;
|
||||
extern app_hitory_t history;
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user