#include "app_leakage.h" #include #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); static void history_init(void); static void history_save_metadata(void); static void app_leakage_init(void); /*历史报警缓冲区*/ uint8_t sector_buf[2][W25Q32_SECTOR_SIZE]; app_leakage_t leakage = { .region_num = 0, .sub_device_num = 0, .init = app_leakage_init, .task = app_leakage_task, .class_update = app_leakage_region_classify, }; 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_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(); } /*区域分类,将同一区域名的设备划分到一起*/ 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; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) { add_region_flag = 1; /*添加新区域*/ /*设备使能*/ if (ENABLE == p_leakage->sub_device_data[i].flash_data.state) { p_leakage->sub_device_num++; /*子系统总数量++*/ /********************************************区域划分******************************************************/ /*遍历区域*/ for (j = 0; j < APP_LEAKAGE_SUB_DEVICE_NUM; j++) { 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].sub_device_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); // 第一个设备索引为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++; } } } } /*控制 声 光 继电器 报警*/ static void app_leakage_alarm_contorl(void) { if (0 != p_leakage->alarm_state) { buzzer.set.on(); relay.set(BSP_RELAY_CH_ERROR_STATE, USR_ON); } else { buzzer.set.off(); relay.set(BSP_RELAY_CH_ERROR_STATE, USR_OFF); } /*漏液状态*/ if (p_leakage->alarm_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) { relay.set(BSP_RELAY_CH_LEAKAGE, USR_ON); } else { relay.set(BSP_RELAY_CH_LEAKAGE, USR_OFF); } /*断带状态*/ if (p_leakage->alarm_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) { relay.set(BSP_RELAY_CH_OPEN, USR_ON); } else { relay.set(BSP_RELAY_CH_OPEN, USR_OFF); } /*通讯超时*/ if (p_leakage->alarm_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT) { relay.set(BSP_RELAY_CH_COMMINCAION, USR_ON); } else { relay.set(BSP_RELAY_CH_COMMINCAION, USR_OFF); } } /*异常状态设备数量统计*/ 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; /* 初始化区域异常统计 */ 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; } p_leakage->alarm_state = 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; } /* 检查设备是否屏蔽 */ if (p_leakage->sub_device_data[sub_device_index].shield != UNBLOCKED) { continue; } /*历史报警存储*/ for (k = 0; k < APP_LEAKAGE_SUB_DEVICE_USE_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)) { if (k > 0 && (p_leakage->sub_device_data[sub_device_index].ch_data[0].state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT)) { /*第一个通道超时,剩余通道不存储超时报警*/ } else { /* 通讯超时报警开始 - 记录历史报警 */ 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_USE_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++; p_leakage->alarm_state |= APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT; break; } else if (current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) { p_leakage->region_data[i].open_num++; p_leakage->alarm_state |= APP_LEAKAGE_SUB_DEVICE_STATE_OPEN; } 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_LEAKAGE; } } } } /*报警控制 声光报警*/ app_leakage_alarm_contorl(); } /* 获取当前时间 */ static void get_current_time(u8 *time_buffer) { /* 年: 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读取历史报警元数据 */ 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); /* 计算该记录可能跨越的扇区范围(最多2个扇区) */ uint32_t start_sector = write_addr & ~(W25Q32_SECTOR_SIZE - 1); uint32_t end_addr = write_addr + HISTORY_ALARM_RECORD_SIZE - 1; uint32_t end_sector = end_addr & ~(W25Q32_SECTOR_SIZE - 1); uint32_t num_sectors = (end_sector - start_sector) / W25Q32_SECTOR_SIZE + 1; /* 缓冲区:最多两个扇区,每个扇区4KB */ uint32_t sectors[2] = {start_sector, (num_sectors > 1) ? end_sector : 0}; /* 1. 读取所有涉及的扇区到RAM */ for (uint32_t i = 0; i < num_sectors; i++) { w25q32.read(sectors[i], sector_buf[i], W25Q32_SECTOR_SIZE); } /* 2. 擦除这些扇区 */ for (uint32_t i = 0; i < num_sectors; i++) { w25q32_sector_erase(sectors[i]); } /* 3. 在RAM中更新新记录的内容 */ uint32_t offset_in_start = write_addr - start_sector; uint32_t first_part_len = (num_sectors == 1) ? HISTORY_ALARM_RECORD_SIZE : (W25Q32_SECTOR_SIZE - offset_in_start); memcpy(sector_buf[0] + offset_in_start, &new_alarm, first_part_len); if (num_sectors > 1) { uint32_t second_part_len = HISTORY_ALARM_RECORD_SIZE - first_part_len; memcpy(sector_buf[1], (uint8_t *)&new_alarm + first_part_len, second_part_len); } /* 4. 将修改后的缓冲区写回Flash */ for (uint32_t i = 0; i < num_sectors; i++) { w25q32.write(sectors[i], sector_buf[i], W25Q32_SECTOR_SIZE); } /* 5. 更新元数据(环形队列) */ 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++; } /* 保存元数据到Flash */ 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(); }