#include "app_leakage.h" #include #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 }; /*区域分类,将同一区域名的设备划分到一起*/ void app_leakage_region_classify(void) { u16 i,j; u8 add_region_flag; /*数量及相关数据清零*/ p_leakage->region_num = 0; p_leakage->sub_device_num = 0; memset(p_leakage->region_data,0,sizeof(p_leakage->region_data)); /*遍历子系统*/ for(i=0;isub_device_data[i].flash_data.state) { p_leakage->sub_device_num++;/*子系统总数量++*/ /*遍历区域*/ for(j=0;jregion_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_num++; /*区域中子系统数据++*/ add_region_flag = 0;/*不添加新区域*/ break; } } /*没有找到相同名称*/ 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++; /*区域数量++*/ } } } } /*异常状态设备数量统计*/ void app_leakage_task(void) { 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(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]; /* 检查设备是否启用 */ if(p_leakage->sub_device_data[sub_device_index].flash_data.state != ENABLE) { 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)) { /* 漏液报警开始 - 记录历史报警 */ history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE, leak_distance); } if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) && !(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN)) { /* 断带报警开始 - 记录历史报警 */ history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_OPEN, 0); } if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT) && !(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT)) { /* 通讯超时报警开始 - 记录历史报警 */ 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(); }