/** * @file diagnosis.c * @author xxx * @date 2023-09-05 09:18:35 * @brief 定位器诊断模块 * @copyright Copyright (c) 2023 by xxx, All Rights Reserved. */ #include "diagnosis.h" #include "board.h" #include "test_bsp.h" #include "fal_execution.h" #include "convert.h" // 诊断函数集合 void (*diagnosis_fun[DIAGNOSIS_MENU_MAX])(void); // 诊断结果统计 diag_result_t diag_result __attribute__((section("NOINIT"), zero_init)); // 诊断结果 // 模块是否初始化完成 static BOOL init_flag = FALSE; /** * @brief 比较诊断报警时间是否超时 * * 比较传入的消息和超时时间,如果超时则返回TRUE,否则返回FALSE。 * * @param msg 指向diag_msg_t结构的指针,包含了需要比较开始时间和超时时间的消息 * @param sec_timeout 超时时间,单位为秒 * * @return 如果超时返回TRUE,否则返回FALSE */ static BOOL diagnosis_alarm_time_comparison(diag_msg_t *msg, uint16_t sec_timeout) { uint32_t cur_time = 0, dif_time = 0; // 产生偏差,记录开始时间 if (msg->process.start_tag == FALSE) { msg->process.start_tag = TRUE; msg->process.start_time = sys_millis(); } else { // 产生偏差超时,设置故障 cur_time = sys_millis(); dif_time = (cur_time - msg->process.start_time) / 1000; if (dif_time >= sec_timeout) { msg->process.start_tag = FALSE; msg->process.start_time = 0; return TRUE; } } return FALSE; } /** * @brief 清除诊断报警时间 * * 该函数用于清除诊断消息中的报警时间信息。 * * @param msg 诊断消息指针,指向包含诊断信息的消息结构体 */ static void diagnosis_alarm_time_clear(diag_msg_t *msg) { msg->process.start_tag = FALSE; msg->process.start_time = 0; } /** * @brief 索引诊断项目 * @param {uint8_t} id 诊断项目ID * @return {diag_msg_t *} 诊断项目句柄 * @note */ static diag_msg_t *diagnosis_menu_index(uint8_t id) { DBG_ASSERT(id < DIAGNOSIS_MENU_MAX __DBG_LINE); uint8_t i = 0; // 如果diag_msg中的数据是根据枚举排序的,下面的代码速度会更快 if (get_diagnosis_result()->diag_msg[id].diag_id == id) { return (diag_msg_t *)&get_diagnosis_result()->diag_msg[id]; } for (i = 0; i < DIAGNOSIS_MENU_MAX; i++) { if (get_diagnosis_result()->diag_msg[i].diag_id == id) { return (diag_msg_t *)&get_diagnosis_result()->diag_msg[i]; } } return NULL; } static void diagnosis_dev_realtime(void) { diagnosis_set_status(DIAGNOSIS_DEV_REALTIME, OK); // 不激活 } /** * @brief 诊断动作次数 * * 该函数用于对设备的使用周期进行检测,如果设备的动作次数超过了设定的限制,并且超过限制的时间超过了设定的报警时间,则诊断为失败。 * * @return 无 */ static void diagnosis_act_sum(void) { uint8_t id = DIAGNOSIS_ACT_SUM; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_save.cycle_count > udevice.cycle_count_limit) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 行程累计诊断 * * 该函数用于诊断行驶里程和是否超出设定的阈值,并设置相应的诊断状态。 * * 如果设备的行驶里程累加器高警告未启用(udevice.more_status_mask_6x.bits.u3.travel_accumulator_high_alert != ENABLE), * 则不激活诊断,并返回。 * * 如果实时数据中的行驶里程累加值(rt_save.travel_accum)大于等于设定的行驶里程警告阈值(udevice.travel_accum_alert_pt), * 则判断当前时间与上一次报警时间之间的间隔是否超过了设定的诊断报警时间阈值(DIAGNOSIS_ALARM_TIME_SEC), * 如果超过,则设置诊断状态为FAIL,否则不操作。 * * 如果行驶里程累加值小于设定的行驶里程警告阈值,则清除上一次报警时间,并设置诊断状态为OK。 */ static void diagnosis_travel_sum(void) { uint8_t id = DIAGNOSIS_TRAVEL_SUM; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_save.travel_accum >= udevice.travel_accum_alert_pt) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断内存使用情况 * * 此函数用于检测并诊断内存的使用情况。 * * 函数首先通过调用 diagnosis_menu_index 函数获取内存使用诊断的索引号,并检查返回值是否为 NULL。 * 然后,调用 my_mem_perused 函数计算 SRAMIN 的内存使用率,并将其存储在局部变量 mem 中。 * 如果内存使用率超过预设的最大值 MEM_UGAGE_MAX,则进一步检查是否已经超过了设定的报警时间。 * 如果超过了报警时间,则将诊断状态设置为失败(FAIL)。 * 否则,将报警时间清零,并将诊断状态设置为正常(OK)。 * * @return 无返回值 */ static void diagnosis_mem_usage(void) { uint8_t id = DIAGNOSIS_MEM_USAGE; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); uint8_t mem = 0; // 内存使用率 // 内存占比检测 mem = my_mem_perused(SRAMIN); if (mem >= MEM_UGAGE_MAX) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断CPU使用率 * * 该函数用于诊断系统的CPU使用率是否过高。 * * @param void 无参数 * * @return void 无返回值 */ static void diagnosis_cpu_usage(void) { uint8_t id = DIAGNOSIS_CPU_USAGE; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.cpu_percent >= CPU_UGAGE_MAX) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } static void indicate_diag_data_available(void) { diagnosis_set_status(INDICATE_DIAG_DATA_AVAILABLE, OK); // 不激活 } static void indicate_nvm_protect_mode(void) { diagnosis_set_status(INDICATE_NVM_PROTECT_MODE, OK); // 不激活 } static void indicate_offline(void) { diagnosis_set_status(INDICATE_OFFLINE, OK); // 不激活 } static void indicate_alert_record_full(void) { uint8_t id = INDICATE_ALERT_RECORD_FULL; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (get_diagnosis_result()->record[DIAGNOSIS_CLASS_FAIL] == (DEFALT_CLASS_FAIL_MAX_NUM - DEFALT_CLASS_FAIL_MIN_NUM) && get_diagnosis_result()->record[DIAGNOSIS_CLASS_SPEC] == (DEFALT_CLASS_SPEC_MAX_NUM - DEFALT_CLASS_SPEC_MIN_NUM) && get_diagnosis_result()->record[DIAGNOSIS_CLASS_MAINT] == (DEFALT_CLASS_MAINT_MAX_NUM - DEFALT_CLASS_MAINT_MIN_NUM) && get_diagnosis_result()->record[DIAGNOSIS_CLASS_CHECK] == (DEFALT_CLASS_CHECK_MAX_NUM - DEFALT_CLASS_CHECK_MIN_NUM)) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } static void indicate_alert_record_not_empty(void) { uint8_t id = INDICATE_ALERT_RECORD_NOT_EMPTY; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (get_diagnosis_result()->record[DIAGNOSIS_CLASS_FAIL] != 0 || get_diagnosis_result()->record[DIAGNOSIS_CLASS_SPEC] != 0 || get_diagnosis_result()->record[DIAGNOSIS_CLASS_MAINT] != 0 || get_diagnosis_result()->record[DIAGNOSIS_CLASS_CHECK] != 0) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 指示校准状态 * * 根据当前系统的校准状态,设置相应的诊断信息。 * * @return 无返回值 */ static void indicate_calibration(void) { uint8_t id = INDICATE_CALIBRATION; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.flag.bits.tuning_enter == TRUE) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } static void indicate_test_progress(void) { diagnosis_set_status(INDICATE_TEST_PROGRESS, OK); // 不激活 } static void indicate_press_active(void) { diagnosis_set_status(INDICATE_PRESS_ACTIVE, OK); // 不激活 } static void indicate_auto_calibration(void) { uint8_t id = INDICATE_AUTO_CALIBRATION; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } static void diagnosis_limit_cutoff_hi(void) { uint8_t id = DIAGNOSIS_LIMIT_CUTOFF_HI; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } if (rt_data.target_travel > udevice.cutoff_limit_hi) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } static void diagnosis_limit_cutoff_lo(void) { uint8_t id = DIAGNOSIS_LIMIT_CUTOFF_LO; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } if (rt_data.target_travel < udevice.cutoff_limit_lo) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } static void diagnosis_ui_saturated_high(void) { diagnosis_set_status(DIAGNOSIS_UI_SATURATED_HIGH, OK); // 不激活 } static void diagnosis_ui_saturated_low(void) { diagnosis_set_status(DIAGNOSIS_UI_SATURATED_LOW, OK); // 不激活 } static void diagnosis_press_error(void) { diagnosis_set_status(DIAGNOSIS_PRESS_ERROR, OK); // 不激活 } /** * @brief 诊断输出压力限制 * * 该函数用于诊断输出压力是否超过限制。 * * 如果设备输出压力限制功能未启用,则直接返回不激活状态。 * 如果启用,并且实际压力超过限制值,且诊断报警时间超过设定阈值,则设置诊断状态为失败。 * 否则,清除诊断报警时间,并设置诊断状态为正常。 */ static void diagnosis_output_press_limit(void) { uint8_t id = DIAGNOSIS_OUTPUT_PRESS_LIMIT; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.pressure_a_kpa > udevice.press_a_limit) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断行程误差 * * 该函数用于诊断设备的行程误差。首先检查是否启用了行程偏差报警,如果没有启用,则不激活诊断结果。 * 如果启用了行程偏差报警,则比较目标行程与实际行程的差值是否超过设定的误差阈值。 * 如果差值超过阈值,并且诊断时间达到预设的报警时间,则将诊断结果设置为失败。 * 否则,清除诊断时间,并将诊断结果设置为正常。 */ static void diagnosis_travel_error(void) { uint8_t id = DIAGNOSIS_TRAVEL_ERROR; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } if (ABS(rt_data.target_travel - rt_data.actual_travel) > udevice.travel_dev_alert_pt) // udevice.travel_error_time = 10 S { if (diagnosis_alarm_time_comparison(msg, udevice.travel_error_time) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } static void diagnosis_travel_lo_lo(void) { uint8_t id = DIAGNOSIS_TRAVEL_LO_LO; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } if (rt_data.actual_travel < udevice.travel_lolo_alert_pt) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { if (get_diagnosis_fault_result(id) == FAIL) { if (rt_data.actual_travel > (udevice.travel_lolo_alert_pt + udevice.travel_alert_dead)) { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } } static void diagnosis_travel_hi_hi(void) { uint8_t id = DIAGNOSIS_TRAVEL_HI_HI; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } if (rt_data.actual_travel > udevice.travel_hihi_alert_pt) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { if (get_diagnosis_fault_result(id) == FAIL) { if (rt_data.actual_travel < (udevice.travel_hihi_alert_pt - udevice.travel_alert_dead)) { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } } /** * @brief 诊断低行程故障 * * 该函数用于诊断设备低行程故障。 * * 函数首先获取诊断菜单中的低行程故障项,并验证该项不为空。 * 然后检查设备是否启用了低行程警报。如果没有启用,则设置低行程故障状态为正常,并返回。 * 如果启用了低行程警报,函数将检查当前实际行程是否低于设定的低行程警报点。 * 如果实际行程低于设定的低行程警报点,并且距离上次报警时间超过了设定时间,则设置低行程故障状态为失败。 * 否则,清除低行程故障报警时间,并设置低行程故障状态为正常。 */ static void diagnosis_travel_lo(void) { uint8_t id = DIAGNOSIS_TRAVEL_LO; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } if (rt_data.actual_travel < udevice.travel_lo_alert_pt) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { if (get_diagnosis_fault_result(id) == FAIL) { if (rt_data.actual_travel > (udevice.travel_lo_alert_pt + udevice.travel_alert_dead)) { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } } /** * @brief 诊断行程过高故障 * * 此函数用于诊断设备行程是否过高,并设置相应的诊断状态。 * * 如果设备状态掩码中的行程过高警告未启用,则诊断状态设置为正常(OK)。 * 如果实时行程数据大于设定的行程过高警告点,并且距离上次诊断时间超过设定的时间间隔, * 则将诊断状态设置为失败(FAIL),否则将诊断时间清零并设置诊断状态为正常(OK)。 * * @return 无返回值 */ static void diagnosis_travel_hi(void) { uint8_t id = DIAGNOSIS_TRAVEL_HI; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } if (rt_data.actual_travel > udevice.travel_hi_alert_pt) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { if (get_diagnosis_fault_result(id) == FAIL) { if (rt_data.actual_travel < (udevice.travel_hi_alert_pt - udevice.travel_alert_dead)) { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } } /** * @brief 诊断弹性下限 * * 此函数用于检查实时数据的弹性值是否低于设备的弹性下限。 * 如果实时数据的弹性值低于设备的弹性下限,并且自上次报警以来已经过去了足够的时间(由DIAGNOSIS_ALARM_TIME_SEC定义), * 则将诊断状态设置为FAIL,并触发相应的报警。 * 如果实时数据的弹性值不低于设备的弹性下限,则清除报警时间,并将诊断状态设置为OK。 * */ static void diagnosis_elasticity_lower(void) { uint8_t id = DIAGNOSIS_ELASTICITY_LOWER; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.elasticity < udevice.elasticity_lower) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 检测上弹性极限 * * 检测当前弹性值是否超过了设备规定的上弹性极限值。如果超过并且报警时间满足条件,则将该诊断项标记为失败;否则,清除报警时间,并标记为正常。 * * @note 本函数为静态函数,仅在内部使用。 */ static void diagnosis_elasticity_upper(void) { uint8_t id = DIAGNOSIS_ELASTICITY_UPPER; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.elasticity > udevice.elasticity_upper) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 检测摩擦力是否低于下限 * * 该函数用于检测当前摩擦力是否低于设定的下限值。如果低于下限值,并且当前报警时间超过预设时间, * 则将诊断结果设置为失败,否则将报警时间清零并将诊断结果设置为正常。 * */ static void diagnosis_friction_lower(void) { uint8_t id = DIAGNOSIS_FRICTION_LOWER; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.friction < udevice.friction_lower) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断上摩擦故障 * * 该函数用于诊断设备的上摩擦是否超出设定范围。 * * @note 无 */ static void diagnosis_friction_upper(void) { uint8_t id = DIAGNOSIS_FRICTION_UPPER; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.friction > udevice.friction_upper) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断气源压力低 * * 该函数用于诊断气源压力是否低于设定的报警阈值,如果低于报警阈值并且处于报警状态,则更新诊断状态为失败; * 如果压力高于报警阈值或者未处于报警状态,则更新诊断状态为正常。 * */ static void diagnosis_supply_lower(void) { uint8_t id = DIAGNOSIS_SUPPLY_LOWER; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.pressure_s_kpa < udevice.low_supply_alert_pt) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 检查供气压力是否过高 * * 该函数用于检查设备的供气压力是否超过了设定的上限值。如果超过了设定的上限值,并且之前未激活报警,则激活报警; * 如果供气压力低于上限值,则清除报警,并将状态设置为正常。 */ static void diagnosis_supply_upper(void) { uint8_t id = DIAGNOSIS_SUPPLY_UPPER; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.pressure_s_kpa > udevice.high_supply_alert_pt) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断温度过低的函数 * * 此函数用于诊断温度是否低于设备允许的最小温度。 * 如果温度低于最小温度且满足报警时间间隔,则将该诊断项的状态设置为失败。 * 否则,清除该诊断项的报警时间,并将状态设置为成功。 * * @return 无返回值 */ static void diagnosis_temperature_lower(void) { uint8_t id = DIAGNOSIS_TEMPERATURE_LOWER; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.temperature < temperature_c2unit(udevice.min_temp, udevice.temp_unit)) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断温度是否超过上限 * * 此函数用于诊断温度是否超过了设备的最高温度限制。 * * 如果当前温度超过设备的最高温度限制,并且诊断警报时间达到预设时间,则将该诊断项的状态设置为失败。 * 否则,清除诊断警报时间,并将该诊断项的状态设置为正常。 * */ static void diagnosis_temperature_upper(void) { uint8_t id = DIAGNOSIS_TEMPERATURE_UPPER; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.temperature > temperature_c2unit(udevice.max_temp, udevice.temp_unit)) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断输出电路故障 * * 该函数用于诊断输出电路是否存在故障。 * * 函数首先获取诊断菜单中输出电路错误的索引,并检查该错误是否被激活。 * 如果输出电路错误未激活,则直接返回。 * * 接着,函数检查IP输出值不为0,但回采电流为0或者回采IP输出大于最大输出的情况。 * 如果出现这种情况,并且该错误的报警时间超过了预设的时间阈值,则将输出电路错误的状态设置为失败。 * 如果不满足上述条件,或者满足条件但报警时间未超过阈值,则将输出电路错误的状态设置为正常,并清除报警时间。 */ static void diagnosis_output_circuit(void) { uint8_t id = DIAGNOSIS_OUTPUT_CIRCUIT_ERROR; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } // IP输出值不为0,回采电流为0或者回采IP输出大于最大输出 if ((ip2current() == 0.0f && rt_data.ip_output != 0) || ip2current() > IP_CURRENT_MAX) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断驱动信号 * * 该函数用于对驱动信号进行诊断,判断其是否在正常范围内,并根据判断结果更新诊断信息。 * * @note 如果驱动信号警报未启用,则不激活诊断。 * */ static void diagnosis_drive_signal(void) { uint8_t id = DIAGNOSIS_DRIVE_SIGNAL; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } if (rt_data.ip_output > udevice.output_max || rt_data.ip_output < udevice.output_min) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } static void diagnosis_flash_integrity(void) { diagnosis_set_status(DIAGNOSIS_FLASH_INTEGRITY, OK); // 不激活 } /** * @brief 诊断温度传感器是否正常工作 * * 该函数用于诊断温度传感器是否正常工作。首先检查温度传感器是否故障, * 如果未故障则继续检查实时温度是否在最小温度和最大温度范围内。 * 如果温度超出范围,并且距离上次报警时间超过一定时间,则判定温度传感器故障。 * * @note 该函数没有返回值。 */ static void diagnosis_temperature_sensor(void) { uint8_t id = DIAGNOSIS_TEMPERATURE_SENSOR; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.temperature < temperature_c2unit(udevice.min_temp, udevice.temp_unit) || rt_data.temperature > temperature_c2unit(udevice.max_temp, udevice.temp_unit)) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断压力传感器 * * 该函数用于诊断压力传感器是否正常工作。 * * 如果压力传感器未启用(通过udevice.more_status_mask_6x.bits.u1.pressure_sensor_failure标志判断), * 则不激活诊断状态,直接返回。 * * 如果压力传感器A、B和S均正常工作(通过get_diagnosis_fault_result函数判断), * 则清除报警时间并设置诊断状态为正常(OK)。 * * 否则,如果自上次诊断以来已达到报警时间阈值(通过diagnosis_alarm_time_comparison函数判断), * 则设置诊断状态为失败(FAIL)。 */ static void diagnosis_press_sensor(void) { uint8_t id = DIAGNOSIS_PRESS_SENSOR; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (get_diagnosis_fault_result(DIAGNOSIS_PRESS_SENSOR_S) == OK && get_diagnosis_fault_result(DIAGNOSIS_PRESS_SENSOR_A) == OK && get_diagnosis_fault_result(DIAGNOSIS_PRESS_SENSOR_B) == OK) { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } else { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } } static void diagnosis_press_sensor_b(void) { uint8_t id = DIAGNOSIS_PRESS_SENSOR_B; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); // if (rt_data.pressure_b_kpa > udevice.pos100_press_b_vol || rt_data.pressure_b_kpa < udevice.pos0_press_b_vol) // { // if (diagnosis_alarm_time_comparison(msg, udevice.press_dev_alert_time) == TRUE) // { // diagnosis_set_status(id, FAIL); // } // } // else // { // diagnosis_alarm_time_clear(msg); // diagnosis_set_status(id, OK); // } } static void diagnosis_press_sensor_a(void) { uint8_t id = DIAGNOSIS_PRESS_SENSOR_A; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); // if (rt_data.pressure_a_kpa > udevice.pos100_press_a_vol || rt_data.pressure_a_kpa < udevice.pos0_press_a_vol) // { // if (diagnosis_alarm_time_comparison(msg, udevice.press_dev_alert_time) == TRUE) // { // diagnosis_set_status(id, FAIL); // } // } // else // { // diagnosis_alarm_time_clear(msg); // diagnosis_set_status(id, OK); // } } /** * @brief 诊断压力传感器S * * 该函数用于诊断压力传感器S的状态,并根据压力值设置诊断状态。 * * @return 无返回值 */ static void diagnosis_press_sensor_s(void) { uint8_t id = DIAGNOSIS_PRESS_SENSOR_S; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (rt_data.pressure_s_kpa > udevice.high_supply_alert_pt || rt_data.pressure_s_kpa < udevice.low_supply_alert_pt) { if (diagnosis_alarm_time_comparison(msg, udevice.press_dev_alert_time) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } static void diagnosis_micro_loop(void) { diagnosis_set_status(DIAGNOSIS_MICRO_LOOP, OK); // 不激活 } /** * @brief 诊断磁条传感器 * * 该函数用于诊断磁条传感器是否正常工作。 * * 如果磁条传感器没有故障,则将其状态设置为正常(OK),否则根据诊断逻辑将其状态设置为故障(FAIL)。 * * 传感器诊断判定依据: * 1. 磁条位置最大最小反馈值大于定义的阈值; * 2. 当前磁条位置反馈值超过整定过程中得到的磁条反馈值范围; * 3. 磁条安装位置不在中心点附近。 */ static void diagnosis_magnet(void) { uint8_t id = DIAGNOSIS_MAGNET; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } /*传感器诊断判定依据 * 1.磁条位置最大最小反馈值大于定义的阈值; * 2.当前磁条位置反馈值超过整定过程中得到的磁条反馈值范围; * 3.磁条安装位置不在中心点附近。 */ if (mode_params.control.ad_0 < POSITION_FEEDBACK_MIN || mode_params.control.ad_100 > POSITION_FEEDBACK_MAX || rt_data.crossover_out_u < mode_params.control.ad_0 || rt_data.crossover_out_u > mode_params.control.ad_100 || ABS((mode_params.control.ad_0 + mode_params.control.ad_100) / 2 - POSITION_FEEDBACK_CENTER) > POSITION_FEEDBACK_CENTER_OFFSER) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断RTC时间 * * 从RTC获取当前时间,并判断时间是否合法。 * 如果时间合法,则清除诊断报警时间,并将诊断状态设置为OK; * 如果时间不合法,且当前时间与诊断报警时间相差在设定的阈值内,则将诊断状态设置为FAIL。 * 如果实时时间一直不改变,将诊断状态设置为FAIL。 * */ static void diagnosis_rtc(void) { date_time_t time; uint8_t id = DIAGNOSIS_RTC; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (get_timestamp(&time) == FALSE) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } return; } // 判断数据是否合法 if ((time.date.year > 99) || (time.date.month > 12) || (time.date.day > 31) || (time.date.hour > 23) || (time.date.minute > 59) || (time.date.second > 59)) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { if (time.date.minute == rt_save.real_time.date.minute && time.date.second == rt_save.real_time.date.second) // 如果时间相同 { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断非关键NVM故障 * * 该函数用于诊断非关键NVM(如EEPROM)是否存在故障。 * * @note 如果 udevice.more_status_mask_6x.bits.u3.non_critical_nvm_alert 为DISABLE,则不会激活此诊断。 * @return 无返回值 */ static void diagnosis_non_critical_nvm(void) { state_e m95_2; uint8_t id = DIAGNOSIS_NON_CRITICAL_NVM; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); m95_2 = get_diagnosis_fault_result(DIAGNOSIS_EEPROM_M95_2); if (m95_2 == OK) { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } else { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } } /** * @brief 诊断关键NVM(非易失性存储器)的状态 * * 该函数用于诊断系统中的关键NVM组件,包括EEPROM M95_1、EEPROM FM24和EEPROM LC02。 * 如果检测到任何一个NVM组件故障,将根据报警时间设置相应的诊断状态。 * * @note 如果 udevice.more_status_mask_6x.bits.u1.critical_nvm_failure 为DISABLE,则不会激活此诊断。 */ static void diagnosis_critical_nvm(void) { state_e m95_1, fm24, lc02; uint8_t id = DIAGNOSIS_CRITICAL_NVM; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); m95_1 = get_diagnosis_fault_result(DIAGNOSIS_EEPROM_M95_1); fm24 = get_diagnosis_fault_result(DIAGNOSIS_EEPROM_FM24); lc02 = get_diagnosis_fault_result(DIAGNOSIS_EEPROM_LC02); if (m95_1 == OK && fm24 == OK && lc02 == OK) { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } else { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } } static void diagnosis_eeprom_lc02(void) { } /** * @brief 诊断FM24 EEPROM * * 该函数用于诊断FM24 EEPROM的工作状态。 * * 首先,获取FM24 EEPROM的诊断ID,并查找对应的诊断消息。 * 然后,检查FM24 EEPROM的执行状态。 * 如果FM24 EEPROM未执行,并且距离上次警报时间超过设定的阈值,则将该诊断项标记为失败。 * 如果FM24 EEPROM已执行,则清除该诊断项的警报时间,并将该诊断项标记为成功。 * * @return 无返回值 */ static void diagnosis_eeprom_fm24(void) { uint8_t id = DIAGNOSIS_EEPROM_FM24; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (fal_execution_status_get(FAL_EXECUTION_EEPROM_FM24) == FALSE) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 对EEPROM M95-2进行诊断 * * 该函数用于对EEPROM M95-2进行诊断。首先,通过调用diagnosis_menu_index函数获取EEPROM M95-2的诊断信息, * 然后检查EEPROM M95-2的执行状态。如果EEPROM M95-2的执行状态为FALSE,并且EEPROM M95-2的报警时间超过了预设的时间阈值, * 则将EEPROM M95-2的诊断状态设置为FAIL;否则,清除EEPROM M95-2的报警时间,并将诊断状态设置为OK。 * */ static void diagnosis_eeprom_m95_2(void) { uint8_t id = DIAGNOSIS_EEPROM_M95_2; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (fal_execution_status_get(FAL_EXECUTION_EEPROM_M95_2) == FALSE) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断EEPROM M95_1模块 * * 该函数用于诊断EEPROM M95_1模块的状态。首先,通过diagnosis_menu_index函数获取EEPROM M95_1的诊断信息。 * 如果EEPROM M95_1的执行状态为FALSE(即未执行或执行失败),则进一步检查该模块的报警时间是否超过预设阈值。 * 如果超过,则将该模块的诊断状态设置为FAIL;否则,清除报警时间,并将诊断状态设置为OK。 * * @param 无 * * @return 无 */ static void diagnosis_eeprom_m95_1(void) { uint8_t id = DIAGNOSIS_EEPROM_M95_1; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (fal_execution_status_get(FAL_EXECUTION_EEPROM_M95_1) == FALSE) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断IP驱动 * * 该函数用于诊断IP驱动是否正常工作。通过比较理论电压和实际电压的差值,判断是否超出允许的误差范围。 * * @return 无 */ static void diagnosis_ip_driver(void) { uint8_t id = DIAGNOSIS_IP_DRIVER; float32 target_cur; // 理论电流ma float32 target_vol; // 理论电压v uint16_t actual_adc; // 实际ip输出 float32 actual_vol; // 实际电压v diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (udevice.auto_cal_status != CAL_SUCCESS) { diagnosis_set_status(id, FAIL); return; } // 计算理论电流ma target_cur = ip_dac2current(rt_data.ip_output); // 计算理论电压v target_vol = target_cur * 10 * 101 / 1000; // 读取实际ip输出 actual_adc = adc_result_average(ADCS_1, ADC_VIP_CHANNEL); // 计算实际电压v actual_vol = (float32)actual_adc / 4096 * VREF_VALUE / 1000; // 判断实际电压与理论电压的差值是否小于允许的误差范围 if (fabs(target_vol - actual_vol) > IP_VOL_OFFSET) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 输入电流诊断 * * 该函数用于诊断输入电流是否在正常范围内。 * * 首先,获取诊断输入的ID和实时电流数据。然后,通过调用 diagnosis_menu_index 函数获取对应的诊断消息对象。 * 接着,检查实时电流是否在设备的输入范围内 * 如果电流不在范围内,将诊断状态设置为失败,并检查是否满足误报警时间条件,若满足,则保持失败状态。 * 如果电流在范围内,则清除误报警时间,并将诊断状态设置为正常。 * * @note 该函数没有返回值。 */ static void diagnosis_input(void) { uint8_t id = DIAGNOSIS_INPUT; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); // 输入电流诊断 if (rt_data.loop_current < udevice.input_range_lo - LOOP_CURRENT_OFFSET || rt_data.loop_current > udevice.input_range_hi + LOOP_CURRENT_OFFSET) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /** * @brief 诊断基准电压 * * 此函数用于诊断设备的基准电压是否正常。 * * 通过读取ADC采集的基准电压值,与预设的基准电压值进行比较, * 若差异超过设定的阈值,并且持续时间超过预设的故障超时时间, * 则将该故障记录为失败状态,否则记录为正常状态。 */ static void diagnosis_vref(void) { uint8_t id = DIAGNOSIS_VREF; diag_msg_t *msg = diagnosis_menu_index(id); DBG_ASSERT(msg != NULL __DBG_LINE); if (ABS(rt_data.cpu_volt - CPU_VREF) > CPU_VREF_OFFSET) { if (diagnosis_alarm_time_comparison(msg, DIAGNOSIS_ALARM_TIME_SEC) == TRUE) { diagnosis_set_status(id, FAIL); } } else { diagnosis_alarm_time_clear(msg); diagnosis_set_status(id, OK); } } /*******************************************************************************************************************/ /** * @brief 诊断数据恢复出厂设置 * @return {*} * @note */ void diagnosis_param_restart(void) { osel_memset((uint8_t *)&diag_result, 0x00, sizeof(diag_result_t)); get_diagnosis_result()->priority = DIAGNOSIS_CLASS_OK; uint8_t i = 0; for (i = 0; i < ARRAY_LEN(get_diagnosis_result()->diag_msg); i++) { get_diagnosis_result()->diag_msg[i].diag_class = DIAGNOSIS_CLASS_NONE; // 默认不分类的不用显示 } // 诊断项目初始化 diag_msg_t *p = get_diagnosis_result()->diag_msg; // DIAGNOSIS_CLASS_FAIL for (i = DEFALT_CLASS_FAIL_MIN_NUM; i < DEFALT_CLASS_FAIL_MAX_NUM; i++) { p->diag_id = (diag_item_e)i; p->diag_class = DIAGNOSIS_CLASS_FAIL; p++; } // DIAGNOSIS_CLASS_SPEC for (i = DEFALT_CLASS_SPEC_MIN_NUM; i < DEFALT_CLASS_SPEC_MAX_NUM; i++) { p->diag_id = (diag_item_e)i; p->diag_class = DIAGNOSIS_CLASS_SPEC; p++; } // DIAGNOSIS_CLASS_MAINT for (i = DEFALT_CLASS_MAINT_MIN_NUM; i < DEFALT_CLASS_MAINT_MAX_NUM; i++) { p->diag_id = (diag_item_e)i; p->diag_class = DIAGNOSIS_CLASS_MAINT; p++; } // DIAGNOSIS_CLASS_CHECK for (i = DEFALT_CLASS_CHECK_MIN_NUM; i < DEFALT_CLASS_CHECK_MAX_NUM; i++) { p->diag_id = (diag_item_e)i; p->diag_class = DIAGNOSIS_CLASS_CHECK; p++; } // 诊断禁用 osel_memset((uint8_t *)udevice.more_status_mask_6x.data, 0, ARRAY_LEN(udevice.more_status_mask_6x.data)); get_diagnosis_result()->crc = crc32_compute((uint8_t *)get_diagnosis_result(), sizeof(diag_result_t) - sizeof(uint32_t)); } /** * @brief 设置诊断项目状态 * @param {diag_fail_e} id 诊断项目ID * @param {uint8_t} state 状态 * @return {*} * @note */ void diagnosis_set_status(uint8_t id, state_e state) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); uint8_t time_len = ARRAY_LEN(rt_save.real_time.data); diag_msg_t *msg = NULL; msg = diagnosis_menu_index(id); uint8_t last_state = msg->diag_state; if (msg == NULL) { return; } // 状态没有改变,检测是否使能,如果没有使能不需要更新诊断结果 if (msg->diag_state == state && state == get_diagnosis_fault_result_of_enable_state(id)) { return; } msg->diag_state = state; // 状态发生改变,需要更新诊断结果 if (state == OK) { // 更新清除时间 osel_memcpy((uint8_t *)msg->last_clear_time.data, (uint8_t *)rt_save.real_time.data, time_len); // 更新故障数量 get_diagnosis_result()->record[msg->diag_class]--; } else { if (get_diagnosis_fault_result_of_enable_state(id) == OK) { msg->diag_state = OK; if (last_state == FAIL) { // 更新清除时间 osel_memcpy((uint8_t *)msg->last_clear_time.data, (uint8_t *)rt_save.real_time.data, time_len); // 更新故障数量 get_diagnosis_result()->record[msg->diag_class]--; } } else { // 更新产生时间 osel_memcpy((uint8_t *)msg->last_mark_time.data, (uint8_t *)rt_save.real_time.data, time_len); // 更新清除时间 osel_memset((uint8_t *)msg->last_clear_time.data, 0x00, time_len); // 更新故障数量 get_diagnosis_result()->record[msg->diag_class]++; // msg->diag_state = FAIL; } } } /** * @brief 设置诊断项目等级 * @param {uint8_t} id 诊断项目ID * @param {uint8_t} class 等级 * @return {*} * @note */ void diagnosis_set_class(uint8_t id, diag_class_e class) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); diag_msg_t *msg = NULL; msg = diagnosis_menu_index(id); if (msg == NULL) { return; } // 等级没有改变,不需要更新诊断结果 if (msg->diag_class == class) { return; } else { msg->diag_class = class; } } /** * @brief 诊断结果最高等级检查 * @return {*} * @note */ static void diagnosis_priority_check(void) { uint8_t i = 0; for (i = 0; i < DIAG_CLASS_NUM; i++) { if (get_diagnosis_result()->record[i] != 0) { get_diagnosis_result()->priority = (diag_class_e)i; return; } } // 没有故障,设置最高等级为OK get_diagnosis_result()->priority = DIAGNOSIS_CLASS_OK; } /** * @brief 诊断处理方式检查 * @return {*} * @note */ static void diagnosis_process_mode_check(void) { if (get_diagnosis_result()->priority == DIAGNOSIS_CLASS_OK) { get_diagnosis_result()->cmd = ALARM_HANDLING_CONTINUE; } else { get_diagnosis_result()->cmd = (alarm_handle_mode_e)udevice.alarm_handle_mode; } } /** * @brief 诊断结果led指示 * @param {diag_class_e} sta * @return {*} * @note */ void diagnosis_fault_indicate(diag_class_e sta) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); static diag_class_e current = DIAGNOSIS_CLASS_OK; // xsh:记录当前状态,如果传入的状态和当前状态一样,关闭所有的LED if (current != sta) { current = sta; leds_off_all(); } // GPS2000 只有绿色和红色 if (udevice.dev_model == POSITIONER_MODEL_GPS2000) { switch (sta) { case DIAGNOSIS_CLASS_FAIL: ///< 设备故障 case DIAGNOSIS_CLASS_SPEC: ///< 超出规格 case DIAGNOSIS_CLASS_CHECK: ///< 功能检查 case DIAGNOSIS_CLASS_MAINT: ///< 要求维护 leds_toggle(LEDS_RED); break; case DIAGNOSIS_CLASS_OK: ///< 诊断正常 leds_toggle(LEDS_GREEN); break; } } else { switch (sta) { case DIAGNOSIS_CLASS_FAIL: ///< 设备故障 leds_toggle(LEDS_RED); break; case DIAGNOSIS_CLASS_SPEC: ///< 超出规格 leds_toggle(LEDS_YELLOW); break; case DIAGNOSIS_CLASS_CHECK: ///< 功能检查 leds_toggle(LEDS_ORANGE); break; case DIAGNOSIS_CLASS_MAINT: ///< 要求维护 leds_toggle(LEDS_BLUE); break; case DIAGNOSIS_CLASS_OK: ///< 诊断正常 leds_toggle(LEDS_GREEN); break; } } // 下面2行代码让面板LED强制绿色 // leds_off_all(); // leds_on(LEDS_GREEN); } /** * @brief 诊断结果处理 * @return {*} * @note */ void diagnosis_fault_deal(void) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); // 故障优先级检查 diagnosis_priority_check(); // 故障处理方式检查 diagnosis_process_mode_check(); // 故障处理 // 1.故障指示(转移到TIM16中断处理) // 2.阀门控制 switch (get_diagnosis_result()->cmd) { case ALARM_HANDLING_CONTINUE: break; case ALARM_HANDLING_KEEP: break; case ALARM_HANDLING_SHUTDOWN: break; default: break; } } /** * @brief 获取诊断项目数量 * @param {diag_class_e} cls 类型 * @return {uint8_t} 数量 * @note */ uint8_t get_diagnosis_items_num(diag_class_e cls) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); uint8_t count = ARRAY_LEN(get_diagnosis_result()->diag_msg); uint8_t num = 0; diag_msg_t *p = get_diagnosis_result()->diag_msg; for (uint8_t i = 0; i < count; i++) { if (p->diag_class == cls) { num++; } p++; } return num; } /** * @brief 获取故障数量 * @param {diag_class_e} cls 故障类型 * @return {uint8_t} 故障数量 * @note */ uint8_t get_diagnosis_fault_num(diag_class_e cls) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); return get_diagnosis_result()->record[cls]; } /** * @brief 获取故障优先级 * @return {*} * @note */ diag_class_e get_diagnosis_fault_priority(void) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); return (diag_class_e)get_diagnosis_result()->priority; } /** * @brief 获取诊断结果 * @param {uint8_t} code 故障代码 * @return {state_e} * @note */ state_e get_diagnosis_fault_result(uint8_t id) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); diag_msg_t *msg = NULL; msg = diagnosis_menu_index(id); if (msg == NULL) { return FAIL; } else { return (state_e)msg->diag_state; } } state_e get_diagnosis_fault_result_of_enable_state(uint8_t id) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); state_e state = OK; switch (id) { case DIAGNOSIS_MAGNET: state = (udevice.more_status_mask_6x.bits.u1.travel_sensor_failure == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_PRESS_SENSOR: state = (udevice.more_status_mask_6x.bits.u1.pressure_sensor_failure == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_TEMPERATURE_SENSOR: state = (udevice.more_status_mask_6x.bits.u1.temperature_sensor_failure == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_CRITICAL_NVM: state = (udevice.more_status_mask_6x.bits.u1.critical_nvm_failure == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_IP_DRIVER: state = (udevice.more_status_mask_6x.bits.u1.drive_current_failure == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_VREF: state = (udevice.more_status_mask_6x.bits.u1.reference_voltage_failure == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_MICRO_LOOP: state = (udevice.more_status_mask_6x.bits.u1.mlfb_sensor_alarm == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_FLASH_INTEGRITY: state = (udevice.more_status_mask_6x.bits.u1.flash_integrity_failure == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case INDICATE_AUTO_CALIBRATION: state = (udevice.more_status_mask_6x.bits.u2.auto_cal_in_progress_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case INDICATE_NVM_PROTECT_MODE: state = (udevice.more_status_mask_6x.bits.u2.nvm_protective_mode == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case INDICATE_PRESS_ACTIVE: state = (udevice.more_status_mask_6x.bits.u2.pressure_fallback_active_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case INDICATE_TEST_PROGRESS: state = (udevice.more_status_mask_6x.bits.u2.diagnostics_in_progress_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case INDICATE_CALIBRATION: state = (udevice.more_status_mask_6x.bits.u2.calibration_in_progress_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case INDICATE_ALERT_RECORD_NOT_EMPTY: state = (udevice.more_status_mask_6x.bits.u2.alert_record_not_empty_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case INDICATE_ALERT_RECORD_FULL: state = (udevice.more_status_mask_6x.bits.u3.alert_record_full_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_ACT_SUM: state = (udevice.more_status_mask_6x.bits.u3.cycle_counter_high_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_DEV_REALTIME: state = (udevice.more_status_mask_6x.bits.u3.instrument_time_is_approximate_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_NON_CRITICAL_NVM: state = (udevice.more_status_mask_6x.bits.u3.non_critical_nvm_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case INDICATE_OFFLINE: state = (udevice.more_status_mask_6x.bits.u3.offline_failed_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_TRAVEL_SUM: state = (udevice.more_status_mask_6x.bits.u3.travel_accumulator_high_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case INDICATE_DIAG_DATA_AVAILABLE: state = (udevice.more_status_mask_6x.bits.u4.diagnostic_data_available_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_PRESS_ERROR: state = (udevice.more_status_mask_6x.bits.u4.end_point_pressure_deviation_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_UI_SATURATED_HIGH: state = (udevice.more_status_mask_6x.bits.u4.integrator_saturated_high_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_UI_SATURATED_LOW: state = (udevice.more_status_mask_6x.bits.u4.integrator_saturated_low_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_SUPPLY_UPPER: state = (udevice.more_status_mask_6x.bits.u4.supply_pressure_high_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_SUPPLY_LOWER: state = (udevice.more_status_mask_6x.bits.u4.supply_pressure_low_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_DRIVE_SIGNAL: state = (udevice.more_status_mask_6x.bits.u5.drive_signal_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_TRAVEL_HI: state = (udevice.more_status_mask_6x.bits.u5.travel_alert_hi == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_TRAVEL_HI_HI: state = (udevice.more_status_mask_6x.bits.u5.travel_alert_hi_hi == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_TRAVEL_LO: state = (udevice.more_status_mask_6x.bits.u5.travel_alert_lo == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_TRAVEL_LO_LO: state = (udevice.more_status_mask_6x.bits.u5.travel_alert_lo_lo == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_TRAVEL_ERROR: state = (udevice.more_status_mask_6x.bits.u5.travel_deviation_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_LIMIT_CUTOFF_HI: state = (udevice.more_status_mask_6x.bits.u5.travel_limit_cutoff_hi_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_LIMIT_CUTOFF_LO: state = (udevice.more_status_mask_6x.bits.u5.travel_limit_cutoff_lo_alert == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_OUTPUT_CIRCUIT_ERROR: state = (udevice.more_status_mask_6x.bits.u6.output_circuit_error == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; case DIAGNOSIS_OUTPUT_PRESS_LIMIT: state = (udevice.more_status_mask_6x.bits.u6.output_pressure_limiting == ENABLE) ? get_diagnosis_fault_result(id) : OK; break; default: state = get_diagnosis_fault_result(id); break; } return state; } /** * @brief 开机自检 * @return {*} * @note */ void power_on_diagnosis(void) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); if (noinit_data.flag.bits.reset_or_power_on == TRUE) { if (mode_get()->interface_req.mode_adjust_result() == TUNED_ONGOING) { udevice.auto_cal_status = POWER_LOST; } rt_data.flag.bits.calib_param_storage = storage_check_all(calib_param_storage, (uint8_t *)&calib_param); rt_data.flag.bits.specification_table_data_storage = storage_check_all(specification_table_data_storage, (uint8_t *)&spec_table_data); rt_data.flag.bits.mode_params_storage = storage_check_all(mode_params_storage, (uint8_t *)&mode_params); rt_data.flag.bits.hart_attribute_storage = storage_check_all(hart_attribute_storage, (uint8_t *)&hart_device_attribute.flash_variable); rt_data.flag.bits.hart_variable_storage = storage_check_all(hart_variable_storage, (uint8_t *)&hart_device_attribute.device_variable); rt_data.flag.bits.hart_constant_storage = storage_check_all(hart_constant_storage, (uint8_t *)&hart_device_attribute.device_constant); rt_data.flag.bits.hart_standard_variable_storage = storage_check_all(hart_standard_variable_storage, (uint8_t *)&hart_device_attribute.device_standard_variable); } else { rt_data.flag.bits.calib_param_storage = TRUE; rt_data.flag.bits.specification_table_data_storage = TRUE; rt_data.flag.bits.mode_params_storage = TRUE; rt_data.flag.bits.hart_attribute_storage = TRUE; rt_data.flag.bits.hart_variable_storage = TRUE; rt_data.flag.bits.hart_constant_storage = TRUE; rt_data.flag.bits.hart_standard_variable_storage = TRUE; } hart_device_status_set_operational_state(DEVICE_OPERATIONAL_STATE_6); if (hart_device_attribute.flash_variable.loop_current_mode == 0) // ZKBW { hart_device_status_set_operational_state(DEVICE_OPERATIONAL_STATE_4); } else { hart_device_status_clr_operational_state(DEVICE_OPERATIONAL_STATE_4); } } /** * @brief 过程诊断 * @return {*} * @note */ void diagnosis_inspection(void) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); uint8_t i = 0; for (i = 0; i < DIAGNOSIS_MENU_MAX; i++) { diagnosis_fun[i](); } get_diagnosis_result()->crc = crc32_compute((uint8_t *)get_diagnosis_result(), sizeof(diag_result_t) - sizeof(uint32_t)); } diag_result_t *get_diagnosis_result(void) { DBG_ASSERT(init_flag == TRUE __DBG_LINE); return &diag_result; } /** * @brief 诊断模块初始化 * @return {*} * @note 在params_init()之后调用 */ void diagnosis_init(void) { // 诊断函数映射 diagnosis_fun[DIAGNOSIS_VREF] = diagnosis_vref; // 基准电压诊断 diagnosis_fun[DIAGNOSIS_INPUT] = diagnosis_input; // 输入电流诊断 diagnosis_fun[DIAGNOSIS_IP_DRIVER] = diagnosis_ip_driver; // 驱动电流诊断 diagnosis_fun[DIAGNOSIS_EEPROM_M95_1] = diagnosis_eeprom_m95_1; // EEPROM M95-1诊断 diagnosis_fun[DIAGNOSIS_EEPROM_M95_2] = diagnosis_eeprom_m95_2; // EEPROM M95-2诊断 diagnosis_fun[DIAGNOSIS_EEPROM_FM24] = diagnosis_eeprom_fm24; // EEPROM FM24诊断 diagnosis_fun[DIAGNOSIS_EEPROM_LC02] = diagnosis_eeprom_lc02; // EEPROM LC02诊断 diagnosis_fun[DIAGNOSIS_CRITICAL_NVM] = diagnosis_critical_nvm; // 主要存储器诊断 diagnosis_fun[DIAGNOSIS_NON_CRITICAL_NVM] = diagnosis_non_critical_nvm; // 次要存储器诊断 diagnosis_fun[DIAGNOSIS_RTC] = diagnosis_rtc; // RTC诊断 diagnosis_fun[DIAGNOSIS_MAGNET] = diagnosis_magnet; // 磁条诊断 diagnosis_fun[DIAGNOSIS_MICRO_LOOP] = diagnosis_micro_loop; // 小回路诊断 diagnosis_fun[DIAGNOSIS_PRESS_SENSOR_S] = diagnosis_press_sensor_s; // 压力传感器S诊断 diagnosis_fun[DIAGNOSIS_PRESS_SENSOR_A] = diagnosis_press_sensor_a; // 压力传感器A诊断 diagnosis_fun[DIAGNOSIS_PRESS_SENSOR_B] = diagnosis_press_sensor_b; // 压力传感器B诊断 diagnosis_fun[DIAGNOSIS_PRESS_SENSOR] = diagnosis_press_sensor; // 压力传感器诊断 diagnosis_fun[DIAGNOSIS_TEMPERATURE_SENSOR] = diagnosis_temperature_sensor; // 温度传感器诊断 diagnosis_fun[DIAGNOSIS_FLASH_INTEGRITY] = diagnosis_flash_integrity; // Flash完整性诊断 diagnosis_fun[DIAGNOSIS_DRIVE_SIGNAL] = diagnosis_drive_signal; // 驱动信号诊断 diagnosis_fun[DIAGNOSIS_OUTPUT_CIRCUIT_ERROR] = diagnosis_output_circuit; // 输出电路诊断 diagnosis_fun[DIAGNOSIS_TEMPERATURE_UPPER] = diagnosis_temperature_upper; // 温度上限诊断 diagnosis_fun[DIAGNOSIS_TEMPERATURE_LOWER] = diagnosis_temperature_lower; // 温度下限诊断 diagnosis_fun[DIAGNOSIS_SUPPLY_UPPER] = diagnosis_supply_upper; // 供气压上限诊断 diagnosis_fun[DIAGNOSIS_SUPPLY_LOWER] = diagnosis_supply_lower; // 供气压下限诊断 diagnosis_fun[DIAGNOSIS_FRICTION_UPPER] = diagnosis_friction_upper; // 摩擦力上限诊断 diagnosis_fun[DIAGNOSIS_FRICTION_LOWER] = diagnosis_friction_lower; // 摩擦力下限诊断 diagnosis_fun[DIAGNOSIS_ELASTICITY_UPPER] = diagnosis_elasticity_upper; // 弹性上限诊断 diagnosis_fun[DIAGNOSIS_ELASTICITY_LOWER] = diagnosis_elasticity_lower; // 弹性下限诊断 diagnosis_fun[DIAGNOSIS_TRAVEL_HI] = diagnosis_travel_hi; // 行程上限诊断 diagnosis_fun[DIAGNOSIS_TRAVEL_LO] = diagnosis_travel_lo; // 行程下限诊断 diagnosis_fun[DIAGNOSIS_TRAVEL_HI_HI] = diagnosis_travel_hi_hi; // 行程上限过高诊断 diagnosis_fun[DIAGNOSIS_TRAVEL_LO_LO] = diagnosis_travel_lo_lo; // 行程下限过低诊断 diagnosis_fun[DIAGNOSIS_TRAVEL_ERROR] = diagnosis_travel_error; // 行程偏差诊断 diagnosis_fun[DIAGNOSIS_OUTPUT_PRESS_LIMIT] = diagnosis_output_press_limit; // 输出压力限制诊断 diagnosis_fun[DIAGNOSIS_PRESS_ERROR] = diagnosis_press_error; // 压力偏差诊断 diagnosis_fun[DIAGNOSIS_UI_SATURATED_LOW] = diagnosis_ui_saturated_low; // 积分器饱和低报警 diagnosis_fun[DIAGNOSIS_UI_SATURATED_HIGH] = diagnosis_ui_saturated_high; // 积分器饱和高报警 diagnosis_fun[DIAGNOSIS_LIMIT_CUTOFF_LO] = diagnosis_limit_cutoff_lo; // 切割点下限诊断 diagnosis_fun[DIAGNOSIS_LIMIT_CUTOFF_HI] = diagnosis_limit_cutoff_hi; // 切割点上限诊断 diagnosis_fun[INDICATE_AUTO_CALIBRATION] = indicate_auto_calibration; // 自动校准正在进行指示 diagnosis_fun[INDICATE_PRESS_ACTIVE] = indicate_press_active; // 切换压力控制指示 diagnosis_fun[INDICATE_TEST_PROGRESS] = indicate_test_progress; // 诊断测试正在进行指示 diagnosis_fun[INDICATE_CALIBRATION] = indicate_calibration; // 校准正在进行指示 diagnosis_fun[INDICATE_ALERT_RECORD_NOT_EMPTY] = indicate_alert_record_not_empty; // 报警记录不为空指示 diagnosis_fun[INDICATE_ALERT_RECORD_FULL] = indicate_alert_record_full; // 报警记录已满指示 diagnosis_fun[INDICATE_OFFLINE] = indicate_offline; // 离线状态指示 diagnosis_fun[INDICATE_NVM_PROTECT_MODE] = indicate_nvm_protect_mode; // 存储器空间耗尽保护指示 diagnosis_fun[INDICATE_DIAG_DATA_AVAILABLE] = indicate_diag_data_available; // 诊断数据可用指示 diagnosis_fun[DIAGNOSIS_CPU_USAGE] = diagnosis_cpu_usage; // CPU使用率诊断 diagnosis_fun[DIAGNOSIS_MEM_USAGE] = diagnosis_mem_usage; // 内存使用率诊断 diagnosis_fun[DIAGNOSIS_TRAVEL_SUM] = diagnosis_travel_sum; // 行程累计诊断 diagnosis_fun[DIAGNOSIS_ACT_SUM] = diagnosis_act_sum; // 动作次数诊断 diagnosis_fun[DIAGNOSIS_DEV_REALTIME] = diagnosis_dev_realtime; // 设备时间诊断 init_flag = TRUE; }