图1: dependencies of the Diagnostic Event Manager to other software modules
report也就是SWC或者BSW给DEM报诊断事件的状态。它由两个部分组成,一个是诊断事件(diagnostic event),一个是滤波(debounce)。可以把应用层或者BSW监控(monitor)某个组件component叫做一个诊断事件(diagnostic event),DEM会给每个诊断事件分配一个独一无二的识别码(EventId),来区分不同的事件。如应用层周期监控(monitor)KL30电电压(component)是否过压叫做一个诊断事件。在这个诊断事件中检测电压是否超过正常值的上限,再通过
Std_ReturnType FiM_GetFunctionPermission(
FiM_FunctionIdType FID,
boolean* Permission )
判断是否该功能被抑制(即诊断KL30电压过压的功能[1]),如果没有被抑制且电压超过有效范围最大值,这时SWC调用
Dem_SetEventStatus(EventID, DEM_EVENT_STATUS_PREFAILED)[2]
接口把诊断事件及诊断事件状态报给DEM;如果没有被抑制且电压没有超过有效范围最大值,这时SWC调用
Dem_SetEventStatus(EventID, DEM_EVENT_STATUS_PREPASSED)
接口把诊断事件及状态报给DEM;如果被抑制了,SWC也应当给DEM提示当前的功能无法执行,DEM会在内部对debounce的一些数据进行处理,如把debounce的counter复位。伪代码如下:
注[1]:电压监控事件怎么还能被抑制呢?因为这种诊断功能(function)都会与其他的事件相关联,存在其他的功能失效导致该功能会被抑制,所以在执行前都需要调用FiM_GetFunctionPermission( FID, &Permission )获得执行的权利。可以防止由一个其他功能引起的另外一个功能异常的误报,如母线电压过低时,会导致抑制电机输出扭矩输出功能,诊断扭矩输出的功能也会被抑制。FIM功能多用于SWC,也可用于BSW。
注[2]:对于诊断事件发生故障时可以持续的给DEM发送DEM_EVENT_STATUS_PREFAILED状态,DEM内部debounce时,debounce counter不会重新计数;同样当每一次诊断事件结果passed时,可以持续的给DEM发送DEM_EVENT_STATUS_PREPASSED状态,DEM内部debounce时,debounce counter不会重新计数。具体详见下面的debounce章节。
void DiagOverVolt(void)
{
res = ChkOverVolt()
if(E_OK == Fim_GetFunctionPermission(diag_volt_fid, &permission))
{
if(*permission == TRUE)
{
if(res == True)
{
Dem_SetEventStatus(diag_volt_event_id, DEM_EVENT_STATUS_PREFAILED);
}
else
{
Dem_SetEventStatus(diag_volt_event_id, DEM_EVENT_STATUS_PREPASSED);
}
}
else
{
Dem_SetEventStatus(diag_volt_event_id, 0xff);//0xff means inhibition
}
}
else
{…}
}
诊断事件分为两种,一种是在SWC应用层的诊断事件,这种事件在report时使用的诊断接口为:
Std_ReturnType Dem_SetEventStatus(
Dem_EventIdType EventId,
Dem_EventStatusType EventStatus
)
还有一种诊断事件是在BSW中的诊断事件,这种事件在report时使用的诊断接口为:
void Dem_ReportErrorStatus(
Dem_EventIdType EventId,
Dem_EventStatusType EventStatus
)
如NVM的写入错误、读取错误、校验错误等,这些不需要debounce,可以直接判定是failed还是passed,直接调用Dem_ReportErrorStatus(NvmReadErrId, DEM_EVENT_STATUS_FAILED)。
当SWC通过Dem_SetEventStatus(EventId, EventStatus)把事件状态报给DEM后,剩下的工作全权由DEM处理。SWC是周期函数,一般在检测某个故障是否发生时,不会因为一个周期检测到失效,就判定该故障发生,而是故障发生持续一定的时间。而诊断事件状态从failed到passed也不是立即变化,也需要消抖(debounce)一定次数或时间。这也就是为什么需要debounce的原因。
消抖算法有基于时间的和基于次数的,两者可以统一于基于次数,因为对于诊断事件都是一个周期行的任务,消抖时间可以等于任务执行周期乘以次数,所以可以用消抖次数代替消抖时间。
debounce的几个参数
items |
description |
details |
step-size/ DemDebounceCounterIncrementStepSize/DemDebounceCounterDecrementStepSize |
步长 |
每次debounce counter增加或者减少的长度 |
debounce counter |
消抖计数器 |
sint16类型的 |
DemDebounceCounterFailedThreshold |
|
使得诊断事件状态为failed的debounce counter的阈值 |
DemDebounceCounterPassedThreshold |
|
使得诊断事件状态为passed的debounce counter的阈值 |
DemDebounceCounterJumpDownValue |
|
当debounce counter大于该值时,如果这时诊断事件的EventStatus是prefailed,那么debounce counter会被初始化为该值。这个机制是在DemDebounceCounterJumpDown为true的条件下使能。 |
DemDebounceCounterJumpUp |
|
当debounce counter小于该值时,如果诊断事件的EventStatus是prepassed,那么debounce counter会被复位为该值。这个机制是在DemDebounceCounterJumpUp为true的条件下使能。 |
可以从下图中(原图来自AUTOSAR_SWS_DiagnosticEventManager Figure 7.30)可以清晰地看出debounce counter的意义。
图2:Example of counter based debouncing
IncreatementStepSize和DecreasementStepSize长度可以不同,DFCmax和FDCmin也不用互为相反数,根据不同需求确定这些参数。
但是在实际应用中,我们更希望failed状态能够更快速地可靠地报出来,而从failed恢复正常到passed的状态是足够可靠,所以当EventStatus为prefailed变为prepassed时,让debounce counter自然地从当前的数值往下减少,不使用DemDebounceCounterJumpDown机制;DemDebounceCounterJumpUpValue设置为0,这样即使当前debounce counter小于0,即为prepassed的状态,当EventStatus变为prefailed时,debounce counter重新从0计数,然后再以IncrementStepSize向上增长;即使会中途出现prepassed状态,也不影响。如下图:
图3:实际应用中的debounce 方式
从两图中可以发现每次report的EventStatus都是Prefailed或者Prepassed,而不是Failed或者Passed,因为对于需要debounce的故障而言,每次SWC对component的监控结果为failed或者passed,都是瞬态的,即使这个故障发生时间很长,SWC依然可以report这个故障的状态为prefailed,因为在DEM的denounce模块,该故障的debounce counter早已超过FDCmax,故障状态早已是failed了。在autosar文档规定,当debounce counter大于等于DFCmax时,即使SWC继续report EventStatus为prefailed,debounce counter也不会继续增加,而是保持DFCmax,这样SWC和debounce counter两者都相得益彰,SWC也不用进行什么时候报prefailed什么时候报failed的逻辑。
对于不同的诊断事件,debounce counter范围可以是(-128~127),也可以是(-32768~32767),也可以不进行debounce,可以根据不同的需要,合理的使用debounce方式和FDCmax和FDCmin。
UDS的8个故障状态位为别为:
bit0 |
testFailed |
bit1 |
testFailedThisOperationCycle |
bit2 |
pendingDTC |
bit3 |
confirmedDTC |
bit4 |
testNotCompleteSinceLastClear |
bit5 |
testFailedSinceLastClear |
bit6 |
testNotCompleteThisOperationCycle |
bit7 |
warningIndicatorRequested |
依据AutoSAR描述,当event report的EventStatuse为passed或者failed或者bounce counter到达debounce counter的阈值时,UDS Status的bit0(TestFailed)、bit1(TestFailedThisOperationCycle)和bit6(TestNotCompletedThisOperationCycle)会发生变化,根据ISO14229-1_2013规定,bit4(testNotCompletedSinceLastClear)由“1”变为“0”的条件是“DTC测试的结果为passed或者failed”;bit5(testFailedSinceLastClear)由“1”变为“0”的条件是“从上一次诊断信息被清除之后的DTC测试结果为failed”。
translation |
condition |
0 -> 1 |
test Failed |
1 -> 0 |
test passed | 14 (FF FF FF) | reset |
bit1: testFailedThisOperationCycle
translation |
condition |
0 -> 1 |
test Failed |
1 -> 0 |
14 (FF FF FF) | operation cycle end -> start(KL15 off to on) |
bit2: pendingDTC
pending状态位的置位放在primary memory中处理,详见DEM之Event memory。
bit3: confirmedDTC
confirmedDTC状态位的置位放在primary memory中处理,详见DEM之Event memory。
bit4: testNotCompletedSinceLastClear
translation |
condition |
0 -> 1 |
test Failed |
1 -> 0 |
14 (FF FF FF) |
bit5: testFailedSinceLastClear
translation |
condition |
0 -> 1 |
test Failed |
1 -> 0 |
14 (FF FF FF) | replaced by other event in EventMemory | aged |
bit6: testNotCompletedThisOperationCycle
translation |
condition |
0 -> 1 |
test Failed |
1 -> 0 |
14 (FF FF FF) | operation cycle end -> start(KL15 off to on) | aged |
bit7 warningIndicatorRequested:
pending状态位的置位放在primary memory中处理,详见DEM之Event memory。
综上可知,在经过了debounce或者no debounce滤波之后的结果为failed时,bit4和bit6会被清零,bit5应当被置一;在经过debounce的或者no debounce滤波之后的结果为passed时,bit4和bit6会被清零。
而bit2(pendingDTC)、bit3(confirmedDTC)和bit7(warningIndicatorRequested)是需要在Fault memory中其他的条件去判断(具体的可以在Fault Memory章节和UDS Status大总结中看到),所以这3个位和debounce影响的4个UDS状态位是异步置位。由于诊断事件report故障及状态是独立于DEM模块,所以为了保存debounce之后的故障状态,可以给每个故障再给配一个变量记录debounce的状态。伪代码如下:
#define DEM_DEB_MASK_FAILED 0x01
#define DEB_DEB_MASK_FAILED_CYCLE 0x02
#define DEB_DEB_MASK_FAILED_NOT_COMPLETED_CLR 0x10
#define DEB_DEB_MASK_FAILED_NOT_COMPLETED_CYCLE 0x40
struct Dem_Deb_Cnf_Struct
{
uint16* Deb_DecSize;
uint16* Deb_IncSize;
uint16* Deb_MaxSize;
};
struct Dem_Deb_Info
{
uint8 status;
uint16 deb_ctr;
};
uint16 Dem_Deb_Dec[]={1,2,3,4};//for prepassed
uint16 Dem_Deb_Inc[]={1,2,3,4};//for prefailed
uint16 Dem_Deb_Max[]={10,8,9,8};
struct Dem_Deb_Cnf_Struct Dem_Deb_Cnf_Ptr;
void Dem_Deb_Init(void)
{
Dem_Deb_Cnf_Ptr->Deb_DecSize = Dem_Deb_Dec;
Dem_Deb_Cnf_Ptr->Deb_IncSize = Dem_Deb_Inc;
Dem_Deb_Cnf_Ptr->Deb_MaxSize = Dem_Deb_Max;
}
uint16 Dem_Deb_Prepass(Dem_Deb_Info* dem_deb_info_ptr, Dem_EventIdType EventId)
{
uint16 something;
tmp_deb_ctr=dem_deb_info_ptr->deb_ctr;
tmp_minux_max = (-1)*Dem_Deb_Cnf_Ptr->Deb_MaxSize[EventId];
if(tmp_deb_ctr<=tmp_minux_max)
{
Dem_Deb_Pass(dem_deb_info_ptr, EventId);
}
else
{
if(tmp_deb_ctr<=0)
{
tmp_deb_ctr -= Dem_Deb_Cnf_Ptr->Deb_IncSize;
}
else
{
tmp_deb_ctr -= Dem_Deb_Cnf_Ptr->Dem_Deb_Dec;
if(tmp_deb_ctr <= tmp_minux_max)
{
Dem_Deb_Pass(dem_deb_info_ptr, EventId);
}
}
}
dem_deb_info_ptr->deb_ctr = tmp_deb_ctr;
return something;
}
uint16 Dem_Deb_Pass(Dem_Deb_Info* dem_deb_info_ptr,, Dem_EventIdType EventId)
{
dem_deb_info_ptr->status &= (uint8)~DEM_DEB_MASK_FAILED;
dem_deb_info_ptr->status &= (uint8)~DEB_DEB_MASK_FAILED_NOT_COMPLETED_CLR;
dem_deb_info_ptr->status &= (uint8)(~DEB_DEB_MASK_FAILED_NOT_COMPLETED_CYCLE);
}
更多内容,可关注公众号“激活未来”。