嵌入式故障码管理系统设计实现

文章目录

  • 前言
  • 一、故障码管理系统概述
  • 二、核心数据结构设计
    • 2.1 故障严重等级定义
    • 2.2 模块 ID 定义
    • 2.3 故障代码结构
    • 2.4 故障记录结构
  • 三、故障管理核心功能实现
    • 3.1 初始化功能
    • 3.2 故障记录功能
    • 3.3 记录查询与清除功能
    • 3.4 系统自检功能
  • 四、故障存储实现
    • 4.1 Flash 存储实现
    • 4.2 RAM 存储实现
  • 五、测试案例
  • 六、源码
    • 6.1 fault_manager.c
    • 6.2 fault_manager.h
    • 6.3 fault_storage.h
    • 6.4 fault_storage_flash.c
    • 6.5 fault_storage_ram.c
    • 6.6 example_usage


前言

在嵌入式系统开发中,故障管理是保障系统稳定运行的关键一环。当系统出现异常时,及时准确地记录和处理故障信息,不仅有助于快速定位问题,还能为系统的优化和维护提供重要依据。本文将基于一套实际的嵌入式故障码管理系统代码,详细介绍其设计思路与实现方法。

一、故障码管理系统概述

该故障码管理系统旨在为嵌入式设备提供全面的故障记录、存储与处理能力。它能够记录系统运行过程中出现的各种故障,包括不同模块产生的不同类型故障,并根据故障的严重程度进行分类处理。同时,系统还支持故障记录的存储、查询、清除以及自检等功能,确保故障信息的完整性和准确性。

故障码管理系统主要分为两大模块:

  • FaultManager(故障管理器)
    负责对外提供初始化、记录故障、查询故障、清除故障、系统自检等功能接口,并维护内部状态(如是否已初始化、已记录故障数量等)。

  • FaultStorage(故障存储)
    提供对故障记录的持久化后端支持,可根据需求选择 Flash 存储或 RAM 环境下的环形/数组存储实现。包含初始化、添加记录、获取记录、删除记录和清空记录等操作。

两者通过明确定义的接口契约解耦,FaultManager 不关心底层存储细节,只要调用 FaultStorage_* 系列接口即可。

设计特点:

  • 多级分类:支持Info/Warning/Error/Critical四级故障

  • 模块化设计:各功能模块独立,便于扩展

  • 双存储引擎:RAM缓存+Flash持久化

  • 低资源占用:适合资源受限的MCU环境

二、核心数据结构设计

2.1 故障严重等级定义

typedef enum {FAULT_SEVERITY_INFO = 0,     // 信息类故障FAULT_SEVERITY_WARNING,      // 警告类故障FAULT_SEVERITY_ERROR,        // 错误类故障FAULT_SEVERITY_CRITICAL      // 严重故障
} FaultSeverity_t;

通过枚举类型定义了故障的四种严重等级。信息类故障用于提示系统的一般运行信息,如软件版本更新提示;警告类故障表示系统出现潜在问题,如磁盘空间即将不足;错误类故障会导致部分功能失效,如网络连接中断;严重故障则可能危及系统安全,如电源电压骤降,为后续分级处理故障提供了清晰标准。

2.2 模块 ID 定义

typedef enum {FAULT_MODULE_SYSTEM = 0,     // 系统模块FAULT_MODULE_POWER,          // 电源模块FAULT_MODULE_COMM,           // 通信模块FAULT_MODULE_SENSOR,         // 传感器模块FAULT_MODULE_ACTUATOR,       // 执行器模块FAULT_MODULE_CUSTOM          // 自定义模块
} FaultModule_t;

该枚举类型明确标识了嵌入式系统中常见的故障模块。不同模块对应不同的硬件或软件功能单元,例如电源模块负责供电,通信模块处理数据传输,传感器模块采集环境数据等,使得故障定位更具针对性。

2.3 故障代码结构

typedef union {uint32_t code;struct {uint16_t module_id : 8;   // 模块IDuint16_t error_id : 8;    // 错误IDuint16_t severity : 4;   // 严重等级uint16_t reserved : 12;   // 保留位} fields;
} FaultCode_t;

采用联合体与结构体结合的设计,code 作为一个 32 位整数可整体存储和传输故障码,fields 结构体则将其拆分为具体信息。8 位的模块 ID 能区分多达 256 种不同模块,8 位的错误 ID 可定义 256 种具体错误类型,4 位的严重等级对应前述四种故障级别,12 位保留位为未来功能扩展预留空间。

2.4 故障记录结构

typedef struct {FaultCode_t fault_code;      // 故障代码uint32_t timestamp;         // 时间戳(ms)uint8_t context[4];         // 上下文数据
} FaultRecord_t;

FaultRecord_t 结构体完整描述一次故障。fault_code 包含故障的类型和严重程度信息;timestamp 基于系统时钟获取故障发生的精确时刻,单位为毫秒,便于分析故障发生的时序;context 数组存储与故障相关的额外数据,如传感器的异常读数、通信数据包片段等,为故障分析提供更丰富的细节。

三、故障管理核心功能实现

3.1 初始化功能

bool FaultManager_Init(void)
{if (fm_state.initialized) {return true;}// 初始化存储子系统if (!FaultStorage_Init()) {return false;}// 获取记录数量fm_state.record_count = FaultStorage_GetRecordCount();fm_state.initialized = true;return true;
}

FaultManager_Init 函数首先检查系统是否已经初始化,如果已初始化则直接返回 true。接着调用 FaultStorage_Init 函数初始化故障存储子系统,若初始化失败则返回 false。成功初始化存储子系统后,获取已有的故障记录数量,并将系统初始化状态标志 fm_state.initialized 设置为 true,最后返回 true 表示初始化成功。

3.2 故障记录功能

void FaultManager_LogFault(FaultCode_t code, const uint8_t* context)
{if (!fm_state.initialized) {return;}FaultRecord_t record;record.fault_code = code;record.timestamp = HAL_GetTick(); // 假设使用HAL库if (context != NULL) {memcpy(record.context, context, sizeof(record.context));} else {memset(record.context, 0, sizeof(record.context));}// 存储记录if (FaultStorage_AddRecord(&record)) {fm_state.record_count++;}// 根据故障等级处理switch (code.fields.severity) {case FAULT_SEVERITY_CRITICAL:// 严重故障可能需要系统复位break;case FAULT_SEVERITY_ERROR:// 错误处理逻辑break;default:break;}
}

FaultManager_LogFault 函数用于记录故障信息。首先检查系统是否已经初始化,若未初始化则直接返回。然后创建一个 FaultRecord_t 类型的变量 record,将传入的故障代码 code 和当前时间戳(通过 HAL_GetTick 函数获取)赋值给 record。如果存在上下文数据,则将其复制到 record.context 中;否则将 record.context 清零。接着调用 FaultStorage_AddRecord 函数将故障记录存储到存储系统中,如果存储成功则更新故障记录数量。最后根据故障的严重程度,在 switch 语句中执行相应的处理逻辑,对于严重故障可能需要考虑系统复位等操作,对于其他故障可进行相应的错误处理。

3.3 记录查询与清除功能

uint16_t FaultManager_GetRecordCount(void)
{return fm_state.record_count;
}bool FaultManager_GetRecord(uint16_t index, FaultRecord_t* record)
{if (!fm_state.initialized || record == NULL) {return false;}if (index >= fm_state.record_count) {return false;}return FaultStorage_GetRecord(index, record);
}void FaultManager_ClearAllRecords(void)
{if (!fm_state.initialized) {return;}FaultStorage_ClearAll();fm_state.record_count = 0;
}

FaultManager_GetRecordCount 函数直接返回当前已记录的故障数量。FaultManager_GetRecord 函数用于获取指定索引的故障记录,首先检查系统是否初始化以及传入的记录指针是否有效,然后判断索引是否越界,若都满足条件则调用 FaultStorage_GetRecord 函数从存储系统中获取记录。FaultManager_ClearAllRecords 函数用于清除所有故障记录,同样先检查系统初始化状态,然后调用 FaultStorage_ClearAll 函数清除存储系统中的所有记录,并将记录数量清零。

3.4 系统自检功能

bool FaultManager_SelfTest(void)
{if (!fm_state.initialized) {return false;}// 测试存储系统FaultRecord_t test_record = {.fault_code = {.fields = {.module_id = FAULT_MODULE_SYSTEM,.error_id = 0xFF,.severity = FAULT_SEVERITY_INFO}},.timestamp = HAL_GetTick(),.context = {0xAA, 0x55, 0xAA, 0x55}};uint16_t old_count = fm_state.record_count;// 添加测试记录FaultManager_LogFault(test_record.fault_code, test_record.context);// 验证记录FaultRecord_t read_record;if (!FaultManager_GetRecord(old_count, &read_record)) {return false;}// 比较记录内容if (memcmp(&test_record, &read_record, sizeof(FaultRecord_t)) != 0) {return false;}// 恢复原始状态FaultStorage_DeleteRecord(old_count);fm_state.record_count = old_count;return true;
}

FaultManager_SelfTest 函数用于对故障管理系统进行自检。先检查系统是否初始化,若未初始化则返回 false。创建一个测试用的 FaultRecord_t 类型变量 test_record,设置好故障代码、时间戳和上下文数据。记录下当前的故障记录数量 old_count,然后调用 FaultManager_LogFault 函数添加测试记录。接着尝试获取刚刚添加的测试记录,如果获取失败则返回 false。将获取到的记录与测试记录进行内容比较,如果不一致也返回 false。最后删除测试记录,恢复原始的记录数量,并返回 true 表示自检通过。

四、故障存储实现

4.1 Flash 存储实现

bool FaultStorage_Init(void)
{// 检查Flash是否为空uint32_t addr = FLASH_BASE_ADDR;storage_state.record_count = 0;while (addr < FLASH_BASE_ADDR + (MAX_RECORDS * RECORD_SIZE)) {uint32_t value = *(__IO uint32_t*)addr;if (value == 0xFFFFFFFF) {break;}storage_state.record_count++;addr += RECORD_SIZE;}storage_state.next_write_addr = FLASH_BASE_ADDR + (storage_state.record_count * RECORD_SIZE);return true;
}

FaultStorage_Init 函数用于初始化 Flash 存储。通过遍历 Flash 存储区域,检查每个记录存储单元的值,如果值为 0xFFFFFFFF(表示未使用)则停止遍历,同时记录已有的记录数量 record_count,并计算出下一个可写入地址 next_write_addr。

bool FaultStorage_AddRecord(const FaultRecord_t* record)
{if (record == NULL || storage_state.record_count >= MAX_RECORDS) {return false;}// 如果需要擦除扇区if (storage_state.next_write_addr >= FLASH_BASE_ADDR + (MAX_RECORDS * RECORD_SIZE)) {FLASH_EraseInitTypeDef erase = {.TypeErase = FLASH_TYPEERASE_SECTORS,.Sector = FLASH_SECTOR,.NbSectors = 1,.VoltageRange = FLASH_VOLTAGE_RANGE_3};uint32_t sector_error;HAL_FLASH_Unlock();if (HAL_FLASHEx_Erase(&erase, &sector_error) != HAL_OK) {HAL_FLASH_Lock();return false;}storage_state.next_write_addr = FLASH_BASE_ADDR;storage_state.record_count = 0;}// 写入FlashHAL_FLASH_Unlock();uint32_t src = (uint32_t)record;uint32_t dst = storage_state.next_write_addr;uint32_t remaining = RECORD_SIZE;while (remaining > 0) {if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, dst, *(uint32_t*)src) != HAL_OK) {HAL_FLASH_Lock();return false;}dst += 4;src += 4;remaining -= 4;}HAL_FLASH_Lock();storage_state.record_count++;storage_state.next_write_addr += RECORD_SIZE;return true;
}

FaultStorage_AddRecord 函数用于向 Flash 存储中添加故障记录。首先检查传入的记录指针是否有效以及存储记录数量是否达到上限,若不满足条件则返回 false。然后判断是否需要擦除扇区(当达到存储区域末尾时),如果需要则进行扇区擦除操作,擦除成功后更新存储状态。接着进行数据写入操作,将故障记录按字写入 Flash,写入过程中若出现错误则立即锁定 Flash 并返回 false。成功写入后更新记录数量和下一个写入地址,并返回 true。

4.2 RAM 存储实现

bool FaultStorage_Init(void)
{memset(&ram_storage, 0, sizeof(ram_storage));return true;
}

FaultStorage_Init 函数对于 RAM 存储的初始化非常简单,直接使用 memset 函数将存储状态结构体 ram_storage 清零即可。

bool FaultStorage_AddRecord(const FaultRecord_t* record)
{if (record == NULL || ram_storage.record_count >= MAX_RAM_RECORDS) {return false;}memcpy(&ram_storage.records[ram_storage.next_index], record, sizeof(FaultRecord_t));ram_storage.next_index = (ram_storage.next_index + 1) % MAX_RAM_RECORDS;if (ram_storage.record_count < MAX_RAM_RECORDS) {ram_storage.record_count++;}return true;
}

FaultStorage_AddRecord 函数向 RAM 存储中添加故障记录。同样先检查记录指针有效性和存储数量上限,然后将记录复制到 ram_storage.records 数组的当前写入位置,更新写入索引 next_index,并根据记录数量是否达到上限决定是否增加记录数量,最后返回 true 表示添加成功。

五、测试案例

#include "fault_manager.h"void example_usage(void)
{// 初始化故障管理系统FaultManager_Init();// 记录一个电源模块的警告故障FaultCode_t power_warning = {.fields = {.module_id = FAULT_MODULE_POWER,.error_id = 0x01,  // 假设0x01表示电压低.severity = FAULT_SEVERITY_WARNING}};uint8_t context[] = {0x0C, 0x22, 0x00, 0x00}; // 12.34VFaultManager_LogFault(power_warning, context);// 记录一个通信模块的错误故障FaultCode_t comm_error = {.fields = {.module_id = FAULT_MODULE_COMM,.error_id = 0x02,  // 假设0x02表示超时.severity = FAULT_SEVERITY_ERROR}};FaultManager_LogFault(comm_error, NULL);// 查询并打印所有故障记录uint16_t count = FaultManager_GetRecordCount();for (uint16_t i = 0; i < count; i++) {FaultRecord_t record;if (FaultManager_GetRecord(i, &record)) {printf("[%lu] Module:%d, Error:%d, Sev:%d\n",record.timestamp,record.fault_code.fields.module_id,record.fault_code.fields.error_id,record.fault_code.fields.severity);}}
}

在 example_usage 测试函数中,首先调用 FaultManager_Init 函数初始化故障管理系统。接着模拟两个故障场景:记录一个电源模块的警告故障,设置故障代码表示电源模块电压低,同时提供包含电压数据的上下文信息;记录一个通信模块的错误故障,设置故障代码表示通信超时,未提供上下文数据。最后通过 FaultManager_GetRecordCount 和 FaultManager_GetRecord 函数查询并打印所有故障记录,直观展示故障记录功能的有效性,验证系统能够准确记录和查询故障信息,确保故障管理系统在实际应用中的可靠性。

谢谢你的翻阅,希望可以对你有所帮助!

六、源码

6.1 fault_manager.c

#include "fault_manager.h"
#include "fault_storage.h"
#include <string.h>// 内部状态
static struct {bool initialized;uint16_t record_count;
} fm_state;// 初始化故障管理系统
bool FaultManager_Init(void)
{if (fm_state.initialized) {return true;}// 初始化存储子系统if (!FaultStorage_Init()) {return false;}// 获取记录数量fm_state.record_count = FaultStorage_GetRecordCount();fm_state.initialized = true;return true;
}// 记录故障
void FaultManager_LogFault(FaultCode_t code, const uint8_t* context)
{if (!fm_state.initialized) {return;}FaultRecord_t record;record.fault_code = code;record.timestamp = HAL_GetTick(); // 假设使用HAL库if (context != NULL) {memcpy(record.context, context, sizeof(record.context));} else {memset(record.context, 0, sizeof(record.context));}// 存储记录if (FaultStorage_AddRecord(&record)) {fm_state.record_count++;}// 根据故障等级处理switch (code.fields.severity) {case FAULT_SEVERITY_CRITICAL:// 严重故障可能需要系统复位break;case FAULT_SEVERITY_ERROR:// 错误处理逻辑break;default:break;}
}// 获取故障记录数量
uint16_t FaultManager_GetRecordCount(void)
{return fm_state.record_count;
}// 获取指定索引的故障记录
bool FaultManager_GetRecord(uint16_t index, FaultRecord_t* record)
{if (!fm_state.initialized || record == NULL) {return false;}if (index >= fm_state.record_count) {return false;}return FaultStorage_GetRecord(index, record);
}// 清除所有故障记录
void FaultManager_ClearAllRecords(void)
{if (!fm_state.initialized) {return;}FaultStorage_ClearAll();fm_state.record_count = 0;
}// 系统自检
bool FaultManager_SelfTest(void)
{if (!fm_state.initialized) {return false;}// 测试存储系统FaultRecord_t test_record = {.fault_code = {.fields = {.module_id = FAULT_MODULE_SYSTEM,.error_id = 0xFF,.severity = FAULT_SEVERITY_INFO}},.timestamp = HAL_GetTick(),.context = {0xAA, 0x55, 0xAA, 0x55}};uint16_t old_count = fm_state.record_count;// 添加测试记录FaultManager_LogFault(test_record.fault_code, test_record.context);// 验证记录FaultRecord_t read_record;if (!FaultManager_GetRecord(old_count, &read_record)) {return false;}// 比较记录内容if (memcmp(&test_record, &read_record, sizeof(FaultRecord_t)) != 0) {return false;}// 恢复原始状态FaultStorage_DeleteRecord(old_count);fm_state.record_count = old_count;return true;
}

6.2 fault_manager.h

#ifndef FAULT_MANAGER_H
#define FAULT_MANAGER_H#include <stdint.h>
#include <stdbool.h>#ifdef __cplusplus
extern "C" {
#endif// 故障严重等级定义
typedef enum {FAULT_SEVERITY_INFO = 0,     // 信息类故障FAULT_SEVERITY_WARNING,      // 警告类故障FAULT_SEVERITY_ERROR,        // 错误类故障FAULT_SEVERITY_CRITICAL      // 严重故障
} FaultSeverity_t;// 模块ID定义
typedef enum {FAULT_MODULE_SYSTEM = 0,     // 系统模块FAULT_MODULE_POWER,          // 电源模块FAULT_MODULE_COMM,           // 通信模块FAULT_MODULE_SENSOR,         // 传感器模块FAULT_MODULE_ACTUATOR,       // 执行器模块FAULT_MODULE_CUSTOM          // 自定义模块
} FaultModule_t;// 故障代码结构
typedef union {uint32_t code;struct {uint16_t module_id : 8;   // 模块IDuint16_t error_id : 8;    // 错误IDuint16_t severity : 4;   // 严重等级uint16_t reserved : 12;   // 保留位} fields;
} FaultCode_t;// 故障记录结构
typedef struct {FaultCode_t fault_code;      // 故障代码uint32_t timestamp;         // 时间戳(ms)uint8_t context[4];         // 上下文数据
} FaultRecord_t;// 初始化故障管理系统
bool FaultManager_Init(void);// 记录故障
void FaultManager_LogFault(FaultCode_t code, const uint8_t* context);// 获取故障记录数量
uint16_t FaultManager_GetRecordCount(void);// 获取指定索引的故障记录
bool FaultManager_GetRecord(uint16_t index, FaultRecord_t* record);// 清除所有故障记录
void FaultManager_ClearAllRecords(void);// 系统自检
bool FaultManager_SelfTest(void);#ifdef __cplusplus
}
#endif#endif // FAULT_MANAGER_H

6.3 fault_storage.h

#ifndef FAULT_STORAGE_H
#define FAULT_STORAGE_H#include "fault_manager.h"#ifdef __cplusplus
extern "C" {
#endif// 初始化存储系统
bool FaultStorage_Init(void);// 添加故障记录
bool FaultStorage_AddRecord(const FaultRecord_t* record);// 获取故障记录数量
uint16_t FaultStorage_GetRecordCount(void);// 获取指定索引的故障记录
bool FaultStorage_GetRecord(uint16_t index, FaultRecord_t* record);// 删除指定索引的故障记录
bool FaultStorage_DeleteRecord(uint16_t index);// 清除所有故障记录
void FaultStorage_ClearAll(void);#ifdef __cplusplus
}
#endif#endif // FAULT_STORAGE_H

6.4 fault_storage_flash.c

#include "fault_storage.h"
#include "stm32f4xx_hal.h" // 根据实际MCU修改
#include <string.h>// Flash存储配置
#define FLASH_SECTOR            FLASH_SECTOR_6
#define FLASH_BASE_ADDR         0x08040000  // 假设使用Sector 6
#define MAX_RECORDS             100         // 最大记录数
#define RECORD_SIZE            sizeof(FaultRecord_t)// 存储状态
static struct {uint16_t record_count;uint32_t next_write_addr;
} storage_state;// 初始化Flash存储
bool FaultStorage_Init(void)
{// 检查Flash是否为空uint32_t addr = FLASH_BASE_ADDR;storage_state.record_count = 0;while (addr < FLASH_BASE_ADDR + (MAX_RECORDS * RECORD_SIZE)) {uint32_t value = *(__IO uint32_t*)addr;if (value == 0xFFFFFFFF) {break;}storage_state.record_count++;addr += RECORD_SIZE;}storage_state.next_write_addr = FLASH_BASE_ADDR + (storage_state.record_count * RECORD_SIZE);return true;
}// 添加记录到Flash
bool FaultStorage_AddRecord(const FaultRecord_t* record)
{if (record == NULL || storage_state.record_count >= MAX_RECORDS) {return false;}// 如果需要擦除扇区if (storage_state.next_write_addr >= FLASH_BASE_ADDR + (MAX_RECORDS * RECORD_SIZE)) {FLASH_EraseInitTypeDef erase = {.TypeErase = FLASH_TYPEERASE_SECTORS,.Sector = FLASH_SECTOR,.NbSectors = 1,.VoltageRange = FLASH_VOLTAGE_RANGE_3};uint32_t sector_error;HAL_FLASH_Unlock();if (HAL_FLASHEx_Erase(&erase, &sector_error) != HAL_OK) {HAL_FLASH_Lock();return false;}storage_state.next_write_addr = FLASH_BASE_ADDR;storage_state.record_count = 0;}// 写入FlashHAL_FLASH_Unlock();uint32_t src = (uint32_t)record;uint32_t dst = storage_state.next_write_addr;uint32_t remaining = RECORD_SIZE;while (remaining > 0) {if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, dst, *(uint32_t*)src) != HAL_OK) {HAL_FLASH_Lock();return false;}dst += 4;src += 4;remaining -= 4;}HAL_FLASH_Lock();storage_state.record_count++;storage_state.next_write_addr += RECORD_SIZE;return true;
}// 获取记录数量
uint16_t FaultStorage_GetRecordCount(void)
{return storage_state.record_count;
}// 从Flash获取记录
bool FaultStorage_GetRecord(uint16_t index, FaultRecord_t* record)
{if (index >= storage_state.record_count || record == NULL) {return false;}uint32_t addr = FLASH_BASE_ADDR + (index * RECORD_SIZE);memcpy(record, (void*)addr, RECORD_SIZE);return true;
}// 删除记录(Flash中不支持单独删除,只能全部擦除)
bool FaultStorage_DeleteRecord(uint16_t index)
{// Flash实现中不支持单独删除return false;
}// 清除所有记录
void FaultStorage_ClearAll(void)
{FLASH_EraseInitTypeDef erase = {.TypeErase = FLASH_TYPEERASE_SECTORS,.Sector = FLASH_SECTOR,.NbSectors = 1,.VoltageRange = FLASH_VOLTAGE_RANGE_3};uint32_t sector_error;HAL_FLASH_Unlock();HAL_FLASHEx_Erase(&erase, &sector_error);HAL_FLASH_Lock();storage_state.record_count = 0;storage_state.next_write_addr = FLASH_BASE_ADDR;
}

6.5 fault_storage_ram.c

#include "fault_storage.h"
#include <string.h>// RAM存储配置
#define MAX_RAM_RECORDS     50  // RAM中最大记录数// 存储状态
static struct {FaultRecord_t records[MAX_RAM_RECORDS];uint16_t record_count;uint16_t next_index;
} ram_storage;// 初始化RAM存储
bool FaultStorage_Init(void)
{memset(&ram_storage, 0, sizeof(ram_storage));return true;
}// 添加记录到RAM
bool FaultStorage_AddRecord(const FaultRecord_t* record)
{if (record == NULL || ram_storage.record_count >= MAX_RAM_RECORDS) {return false;}memcpy(&ram_storage.records[ram_storage.next_index], record, sizeof(FaultRecord_t));ram_storage.next_index = (ram_storage.next_index + 1) % MAX_RAM_RECORDS;if (ram_storage.record_count < MAX_RAM_RECORDS) {ram_storage.record_count++;}return true;
}// 获取记录数量
uint16_t FaultStorage_GetRecordCount(void)
{return ram_storage.record_count;
}// 从RAM获取记录
bool FaultStorage_GetRecord(uint16_t index, FaultRecord_t* record)
{if (index >= ram_storage.record_count || record == NULL) {return false;}uint16_t actual_index;if (ram_storage.record_count < MAX_RAM_RECORDS) {actual_index = index;} else {actual_index = (ram_storage.next_index + index) % MAX_RAM_RECORDS;}memcpy(record, &ram_storage.records[actual_index], sizeof(FaultRecord_t));return true;
}// 删除RAM中的记录
bool FaultStorage_DeleteRecord(uint16_t index)
{if (index >= ram_storage.record_count) {return false;}if (ram_storage.record_count < MAX_RAM_RECORDS) {// 简单数组,移动后面的元素for (uint16_t i = index; i < ram_storage.record_count - 1; i++) {memcpy(&ram_storage.records[i], &ram_storage.records[i + 1], sizeof(FaultRecord_t));}} else {// 环形缓冲区,实现更复杂// 这里简化处理,不支持删除return false;}ram_storage.record_count--;return true;
}// 清除所有RAM记录
void FaultStorage_ClearAll(void)
{ram_storage.record_count = 0;ram_storage.next_index = 0;
}

6.6 example_usage

#include "fault_manager.h"void example_usage(void)
{// 初始化故障管理系统FaultManager_Init();// 记录一个电源模块的警告故障FaultCode_t power_warning = {.fields = {.module_id = FAULT_MODULE_POWER,.error_id = 0x01,  // 假设0x01表示电压低.severity = FAULT_SEVERITY_WARNING}};uint8_t context[] = {0x0C, 0x22, 0x00, 0x00}; // 12.34VFaultManager_LogFault(power_warning, context);// 记录一个通信模块的错误故障FaultCode_t comm_error = {.fields = {.module_id = FAULT_MODULE_COMM,.error_id = 0x02,  // 假设0x02表示超时.severity = FAULT_SEVERITY_ERROR}};FaultManager_LogFault(comm_error, NULL);// 查询并打印所有故障记录uint16_t count = FaultManager_GetRecordCount();for (uint16_t i = 0; i < count; i++) {FaultRecord_t record;if (FaultManager_GetRecord(i, &record)) {printf("[%lu] Module:%d, Error:%d, Sev:%d\n",record.timestamp,record.fault_code.fields.module_id,record.fault_code.fields.error_id,record.fault_code.fields.severity);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/905774.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动态规划-63.不同路径II-力扣(LeetCode)

一、题目解析 与62.不同路径不同的一点是现在网格中有了障碍物&#xff0c;其他的并没有什么不同 二、算法解析 1.状态表示 dp[i][j]表示&#xff1a;到[i,j]位置时&#xff0c;不同的路径数 2.状态转移方程 由于多了障碍物&#xff0c;所以我们要判断是否遇到障碍物 3.初…

使用CherryStudio +SiliconFlow 部署独立的deepseek+知识库

deepseek知识库&#xff0c;独立的deepseek 首先我们先了解 CherryStudio&#xff1f;SiliconFlow&#xff1f; CherryStudio是一个支持多平台的AI客户端&#xff0c;我们致力于让更多人能够享受到AI带来的便利。 简单来说&#xff0c;它是一个能让普通人轻松用上AI 的「万能工…

Openshift节点Disk pressure

OpenShift 监控以下指标&#xff0c;并定义以下垃圾回收的驱逐阈值。请参阅产品文档以更改任何驱逐值。 nodefs.available 从 cadvisor 来看&#xff0c;该node.stats.fs.available指标表示节点文件系统&#xff08;所在位置&#xff09;上有多少可用&#xff08;剩余&#xf…

MySQL的 JOIN 优化终极指南

目录 前言序章&#xff1a;为何要有JOIN&#xff1f;——“一个好汉三个帮”的数据库哲学 &#x1f91d;第一章&#xff1a;JOIN的“七十二变”——常见JOIN类型速览 &#x1f3ad;第二章&#xff1a;MySQL的“红娘秘籍”——JOIN执行原理大揭秘 &#x1f575;️‍♀️&#x1…

TLS 1.3黑魔法:从协议破解到极致性能调优

一、TLS协议逆向工程实验 1.1 密码学套件破解剧场 实验准备&#xff1a; 靶机&#xff1a;启用TLS 1.2的Nginx服务器 工具集&#xff1a;Wireshark OpenSSL s_client 定制Python脚本 实战攻击复现&#xff1a; # 强制使用弱加密套件连接 openssl s_client -connect exa…

国标GB/T 12536-90滑行试验全解析:纯电动轻卡行驶阻力模型参数精准标定

摘要 本文以国标GB/T 12536-90为核心框架&#xff0c;深度解析纯电动轻卡滑行试验的完整流程与数据建模方法&#xff0c;提供&#xff1a; 法规级试验规范&#xff1a;从环境要求到数据采集全流程详解行驶阻力模型精准标定&#xff1a;最小二乘法求解 ( FAv^2BvC ) 的MATLAB实…

【GaussDB迁移攻略】DRS支持CDC,解决大规模数据迁移挑战

目录 1 背景介绍 2 CDC的实现原理 3 DRS的CDC实现方式 4 DRS的CDC使用介绍 5 总结 1 背景介绍 随着国内各大行业数字化转型的加速&#xff0c;客户的数据同步需求越来越复杂。特别是当需要将一个源数据库的数据同时迁移到不同的目标库场景时&#xff0c;华为云通常会创建…

PSA Certified

Arm 推出的 PSA Certified 已成为安全芯片设计领域的黄金标准。通过对安全启动、加密服务以及更新协议等方面制定全面的要求&#xff0c;PSA Certified为芯片制造商提供了清晰的路线图&#xff0c;使其能将安全机制深植于定制芯片解决方案的基础架构中。作为对PSA Certified的补…

游戏引擎学习第286天:开始解耦实体行为

回顾并为今天的内容定下基调 我们目前正在进入实体系统的一个新阶段&#xff0c;之前我们已经让实体的移动系统变得更加灵活&#xff0c;现在我们想把这个思路继续延伸到实体系统的更深层次。今天的重点&#xff0c;是重新审视我们处理实体类型&#xff08;entity type&#x…

遥感图像非法采矿矿区识别分割数据集labelme格式1818张3类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;1818 标注数量(json文件个数)&#xff1a;1818 标注类别数&#xff1a;3 标注类别名称:["river","illegal-mining"…

python爬虫实战训练

前言&#xff1a;哇&#xff0c;今天终于能访问豆瓣了&#xff0c;前几天爬太多次了&#xff0c;网页都不让我访问了&#xff08;要登录&#xff09;。 先来个小练习试试手吧&#xff01; 爬取豆瓣第一页&#xff08;多页同上篇文章&#xff09;所有电影的排名、电影名称、星…

Go语言实现生产者-消费者问题的多种方法

Go语言实现生产者-消费者问题的多种方法 生产者-消费者问题是并发编程中的经典问题&#xff0c;涉及多个生产者生成数据&#xff0c;多个消费者消费数据&#xff0c;二者通过缓冲区&#xff08;队列&#xff09;进行协调&#xff0c;保证数据的正确传递和同步。本文将从简单到…

【Opencv】canny边缘检测提取中心坐标

采用opencv 对图像中的小球通过canny边缘检测的方式进行提取坐标 本文介绍了如何使用OpenCV对图像中的小球进行Canny边缘检测&#xff0c;并通过Zernike矩进行亚像素边缘检测&#xff0c;最终拟合椭圆以获取小球的精确坐标。首先&#xff0c;图像被转换为灰度图并进行高斯平滑…

蓝桥杯12届国B 123

题目描述 小蓝发现了一个有趣的数列&#xff0c;这个数列的前几项如下&#xff1a; 1,1,2,1,2,3,1,2,3,4,⋯ 小蓝发现&#xff0c;这个数列前 1 项是整数 1&#xff0c;接下来 2 项是整数 1 至 2&#xff0c;接下来 3 项是整数 1 至 3&#xff0c;接下来 4 项是整数 1 至 4&…

鸿蒙OSUniApp 制作动态加载的瀑布流布局#三方框架 #Uniapp

使用 UniApp 制作动态加载的瀑布流布局 前言 最近在开发一个小程序项目时&#xff0c;遇到了需要实现瀑布流布局的需求。众所周知&#xff0c;瀑布流布局在展示不规则尺寸内容&#xff08;如图片、商品卡片等&#xff09;时非常美观和实用。但在实际开发过程中&#xff0c;我…

ThinkStation图形工作站进入BIOS方法

首先视频线需要接在独立显卡上&#xff0c;重新开机&#xff0c;持续按F1&#xff0c;或者显示器出来lenovo的logo的时候按F1&#xff0c;这样就进到bios里了。联*想*坑&#xff0c;戴尔贵。靠。

【源码级开发】Qwen3接入MCP,企业级智能体开发实战!

Qwen3接入MCP智能体开发实战&#xff08;上&#xff09; 一、MCP技术与Qwen3原生MCP能力介绍 1.智能体开发核心技术—MCP 1.1 Function calling技术回顾 如何快速开发一款智能体应用&#xff0c;最关键的技术难点就在于如何让大模型高效稳定的接入一些外部工具。而在MCP技术…

Linux下载与安装

一、YUM 1.1 什么是YUM 在CentOS系统中&#xff0c;软件管理方式通常有三种方式&#xff1a;rpm安装、yum安装以及编译&#xff08;源码&#xff09;安装。 编译安装&#xff0c;从过程上来讲比较麻烦&#xff0c;包需要用户自行下载&#xff0c;下载的是源码包&#xff0c;需…

PostgreSQL中的全页写

一、概述 在PGSQL数据库中&#xff0c;默认的页面大小为8KB&#xff0c;但是磁盘buffer的大小为4KB&#xff0c;扇区大小为512B。这就导致在操作系统的角度看数据库的写操作&#xff0c;其实并不是一种原子操作。如果操作系统发生了系统级别的故障&#xff0c;此时正好操作系统…

WEB安全--Java安全--shiro550反序列化漏洞

一、前言 什么是shiro&#xff1f; shiro是一个Apache的Java安全框架 它的作用是什么&#xff1f; Apache Shiro 是一个强大且灵活的 Java 安全框架&#xff0c;用于处理身份验证、授权、密码管理以及会话管理等功能 二、shiro550反序列化原理 1、用户首次登录并勾选记住密码…