#include "app_leakage.h" #include #include "bsp_w25q.h" #include "bsp_buzzer.h" #include "bsp_relay.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_hitory_t history = { .read_history = history_read_record, .clean_history = history_clear_all, .init_history = history_init }; /*控制 声 光 继电器 报警*/ static void app_leakage_alarm_contorl(void) { if(0 != 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(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(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(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 < leakage.region_num; i++) { for(j = 0; j < leakage.region_data[i].sub_device_num; j++) { sub_device_index = leakage.region_data[i].sub_device_index[j]; /* 检查设备是否启用 */ if(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 = leakage.sub_device_data[sub_device_index].ch_data[k].state; u16 prev_state = prev_ch_state[sub_device_index][k]; u16 leak_distance = 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; } } } /*报警控制 声光报警*/ app_leakage_alarm_contorl(); } /* 获取当前时间 */ 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(); }