针对诊断刷写的脚本,之前我讲到$27服务,27服务主要是种子的请求和密钥的计算,当仿真ECU经过逻辑判断,秘钥正确给出正响应,不正确给出负响应。以下是我之前文章的内容链接:
基于UDS编写的CANoe BootLoader刷写上位机测测试脚本
1、诊断的请求与响应实现
由于之前只给出了Tester和SimECU的节点代码,并没有对传输层代码进行介绍,本次对TP层代码进行介绍。在之前的测试用例当中,我应用了几个诊断服务,包括$10、$85、$28、$3E以及$27服务,分别对应的诊断函数为:DiagnosticSessionControl()、ControlDTCSetting()、CommunicationControl()、SecurityAccess()、TesterPresent()。下面是这几个函数的诊断代码:
variables
{
/* Create a Service DiagnosticSessionControl */
diagRequest DiagnosticSessionControl_Process DiagnosticSessionControlReq;
diagResponse DiagnosticSessionControl_Process DiagnosticSessionControlResp;
/* create a service for Security Access */
diagRequest SecurityAccess_Process SecurityAccessReq;
diagResponse SecurityAccess_Process SecurityAccessResp;
/* create a service for communication control */
diagRequest CommunicationControl_Process CommunicationControlReq;
diagResponse CommunicationControl_Process CommunicationControlResp;
/* create a service for tester present */
diagRequest TesterPresent_Process TesterPresentReq;
diagResponse TesterPresent_Process TesterPresentResp;
/* Create a service for control DTC Settings */
diagRequest ControlDTCSetting_Process ControlDTCSettingReq;
diagResponse ControlDTCSetting_Process ControlDTCSettingResp;
}
/* FUNCTIONAL DIAGNOSTOCS CONTROL */
long DiagnosticSessionControl(long diagnosticSessionType, char isFunctional, char isPRSuppress, char isNoResponse)
{
long LocalResponse;
if(isPRSuppress)
{
diagnosticSessionType = diagnosticSessionType + PResponseSuppressed;//正响应抑制,在响应类型基础上加0x80
}
DiagSetParameter(DiagnosticSessionControlReq, "diagnosticSessionType", diagnosticSessionType);
if (isFunctional)
{
diagSendFunctional(DiagnosticSessionControlReq);
}
else
{
DiagSendRequest(DiagnosticSessionControlReq); /* sending request */
}
/* write the request object in the test report */
testReportWriteDiagObject(DiagnosticSessionControlReq);
/* wait for the request is sent completely */
TestWaitForDiagRequestSent(DiagnosticSessionControlReq, TransferTime);
/* Wait for the response to be arrived */
LocalResponse = testWaitForDiagResponse(DiagnosticSessionControlReq,1000);
/* Case a response arrived (PR or NR) */
if (LocalResponse == ResponseArrived)
{
DiagnosticSessionControlReq.GetLastResponse(DiagnosticSessionControlResp);
LocalResponse = diagIsPositiveResponse(DiagnosticSessionControlResp);
/* write the response object in the test report */
testReportWriteDiagObject(DiagnosticSessionControlResp);
}
/* Case response not arrived and it was PR_Suppress */
else if (isPRSuppress)
{
LocalResponse = PRSuppress;
testCaseComment("Positive Response Suppressed as per Request");
}
/* Case expecting no response */
else if (isNoResponse)
{
LocalResponse = NoResponse;
testCaseComment("No Response arrived as expected per Request");
}
/* Case response not arrived (not expected) */
else
{
/* Time out occurred or faulty error */
LocalResponse = ResponseError;
}
return LocalResponse;
}
/* FUNCTIONAL CONTROL DTC SETTING */
long ControlDTCSetting (long dtcSettingType, char isFunctional, char isPRSuppress, char isNoResponse)
{
long LocalResponse;
byte LocalByte[1];
if (isPRSuppress)
{
dtcSettingType = dtcSettingType + PResponseSuppressed;
}
DiagSetParameter(ControlDTCSettingReq, "dtcSettingType", dtcSettingType);
diagSetParameterRaw(ControlDTCSettingReq, "dtcSettingControlOptionRecord", LocalByte, 0);
if (isFunctional)
{
diagSendFunctional(ControlDTCSettingReq);
}
else
{
DiagSendRequest(ControlDTCSettingReq);
}
/* write the request object in the test report */
testReportWriteDiagObject(ControlDTCSettingReq);
TestWaitForDiagRequestSent(ControlDTCSettingReq, TransferTime);
LocalResponse = testWaitForDiagResponse(ControlDTCSettingReq,1000);
if (LocalResponse == ResponseArrived)
{
ControlDTCSettingReq.GetLastResponse(ControlDTCSettingResp);
LocalResponse = diagIsPositiveResponse(ControlDTCSettingResp);
/* write the response object in the test report */
testReportWriteDiagObject(ControlDTCSettingResp);
}
else if (isPRSuppress)
{
LocalResponse = PRSuppress;
testCaseComment("Positive Response Suppressed as per Request");
}
/* Case expecting no response */
else if (isNoResponse)
{
LocalResponse = NoResponse;
testCaseComment("No Response arrived as expected per Request");
}
else
{
/* Time out occurred or faulty error */
LocalResponse = ResponseError;
}
return LocalResponse;
}
/* FUNCTIONAL COMMUNICATION CONTROL */
long CommunicationControl (
long controlType, long communicationType, char isFunctional, char isPRSuppress, char isNoResponse)
{
long LocalResponse;
if (isPRSuppress)
{
controlType = controlType + PResponseSuppressed;
}
diagSetParameter(CommunicationControlReq, "controlType", controlType);
diagSetParameter(CommunicationControlReq, "communicationType", communicationType);
if (isFunctional)
{
diagSendFunctional(CommunicationControlReq);
}
else
{
diagSendRequest(CommunicationControlReq);
}
testReportWriteDiagObject(CommunicationControlReq);
TestWaitForDiagRequestSent(CommunicationControlReq, TransferTime);
LocalResponse = testWaitForDiagResponse(CommunicationControlReq,1000);
if (LocalResponse == ResponseArrived)
{
CommunicationControlReq.GetLastResponse(CommunicationControlResp);
LocalResponse = diagIsPositiveResponse(CommunicationControlResp);
testReportWriteDiagObject(CommunicationControlResp);
}
else if(isPRSuppress)
{
LocalResponse = PRSuppress;
testCaseComment("Response Suppressed as per Request");
}
/* Case expecting no response */
else if (isNoResponse)
{
LocalResponse = NoResponse;
testCaseComment("No Response arrived as expected per Request");
}
else
{
/* Time out occurred or faulty error */
LocalResponse = ResponseError;
}
return LocalResponse;
}
/* FUNCTIONAL SECURITY ACCESS */
long SecurityAccess (long securityAccessType, char isFunctional, char isNoResponse)
{
long LocalResponse;
byte LocalSeed[4];
byte LocalKey[4];
char Stub[2] = "1";
char stub2[1]="" ;
int SeedSize = 4;
int KeySize = 4;
dword KeyActualSize;
int RepeatSeedRequest;
int iteration;
RepeatSeedRequest = 1;
/* Request Seed */
DiagSetParameter(SecurityAccessReq, "securityAccessType", securityAccessType);
DiagSetParameterRaw(SecurityAccessReq, "data", LocalSeed, 0);
/*Handling the delay mechanism "the NRC requiredTimeDelayNotExpired" with maximum blockage time 10 seconds */
for (iteration = 1; ( (iteration <= 6) && (RepeatSeedRequest == 1) ) ; iteration++)
{
RepeatSeedRequest = 0;
if (isFunctional)
{
diagSendFunctional(SecurityAccessReq);
}
else
{
DiagSendRequest(SecurityAccessReq); /* sending request */
}
testReportWriteDiagObject(SecurityAccessReq);
TestWaitForDiagRequestSent(SecurityAccessReq, TransferTime);
LocalResponse = testWaitForDiagResponse(SecurityAccessReq,1000);
write("LocalResponse is %d",LocalResponse);
if (LocalResponse == ResponseArrived)
{
/*A response was received*/
SecurityAccessReq.GetLastResponse(SecurityAccessResp);
if(diagIsNegativeResponse(SecurityAccessResp) != 0)
{
/*Negative response was received*/
NRC_Value = diagGetResponseCode(SecurityAccessResp);
if (NRC_Value == requiredTimeDelayNotExpired)
{
testWaitForTimeout(TransferTime);
RepeatSeedRequest = 1;
}
else
{
LocalResponse = ResponseError;
}
}
}
/* Case expecting no response */
else if (isNoResponse)
{
LocalResponse = NoResponse;
testCaseComment("No Response arrived as expected per Request");
}
else
{
/* Time out occurred or faulty error */
LocalResponse = ResponseError;
}
}
testReportWriteDiagObject(SecurityAccessResp);
if (LocalResponse !=0)
{
/* get the seed from response */
diagGetParameterRaw(SecurityAccessResp, "securitySeed", LocalSeed,4); //获取种子
//write("the seed is 0x%2X,0x%2X,0x%2X,0x%2X",LocalSeed[0],LocalSeed[1],LocalSeed[2],LocalSeed[3]);
/* Calculate the key from Seed */
diagGenerateKeyFromSeed(LocalSeed,SeedSize,securityAccessType,Stub,stub2,LocalKey,KeySize,KeyActualSize);//生成秘钥
//write("the key is 0x%2X,0x%2X,0x%2X,0x%2X",LocalKey[0],LocalKey[1],LocalKey[2],LocalKey[3]);
DiagSetParameter(SecurityAccessReq, "securityAccessType", (securityAccessType+1));
diagSetParameterRaw(SecurityAccessReq, "data", LocalKey, KeySize);
if (isFunctional)
{
diagSendFunctional(SecurityAccessReq);
}
else
{
DiagSendRequest(SecurityAccessReq); /* sending request */
}
testReportWriteDiagObject(SecurityAccessReq);
TestWaitForDiagRequestSent(SecurityAccessReq, TransferTime);
LocalResponse = testWaitForDiagResponse(SecurityAccessReq,1000);
if (LocalResponse == ResponseArrived)
{
SecurityAccessReq.GetLastResponse(SecurityAccessResp);
LocalResponse = diagIsPositiveResponse(SecurityAccessResp);
}
/* Case expecting no response */
else if (isNoResponse)
{
LocalResponse = NoResponse;
testCaseComment("No Response arrived as expected per Request");
}
else
{
/* Time out occurred or faulty error */
LocalResponse = ResponseError;
}
}
return LocalResponse;
}
/* FUNCTIONAL TESTER PRESENT */
long TesterPresent (long zeroSubFunction, char isFunctional, char isPRSuppress, char isNoResponse)
{
long LocalResponse;
if (isPRSuppress)
{
zeroSubFunction = zeroSubFunction + PResponseSuppressed;
}
DiagSetParameter(TesterPresentReq, "zeroSubFunction", zeroSubFunction);
if(isFunctional)
{
diagSendFunctional(TesterPresentReq);
}
else
{
DiagSendRequest(TesterPresentReq);
}
/* write the request object in the test report */
testReportWriteDiagObject(TesterPresentReq);
TestWaitForDiagRequestSent(TesterPresentReq, TransferTime);
LocalResponse = testWaitForDiagResponse(TesterPresentReq,1000);
if (LocalResponse == ResponseArrived)
{
TesterPresentReq.GetLastResponse(TesterPresentResp);
LocalResponse = diagIsPositiveResponse(TesterPresentResp);
/* write the response object in the test report */
testReportWriteDiagObject(TesterPresentResp);
}
else if (isPRSuppress)
{
LocalResponse = PRSuppress;
testCaseComment("Response Suppressed as per Request");
}
/* Case expecting no response */
else if (isNoResponse)
{
LocalResponse = NoResponse;
testCaseComment("No Response arrived as expected per Request");
}
else
{
/* Time out occurred or faulty error */
LocalResponse = ResponseError;
}
return LocalResponse;
}
2、TP层节点代码重塑
诊断功能函数写完以后,需要对TP层节点代码进行重写,以便在Write Window中能够看到相关数据及参数。代码如下:
_Diag_SendFunctional( BYTE data[])
{
CanTpSetPadding (gHandleFunctional, gOverwritePaddingMode);
// Send data on the functional TP connection created earlier
CanTpSendData( gHandleFunctional, data, elcount( data));
//write("_Diag_SendFunctional data[0]=%d", data[0]);
}
_Diag_DataRequest( BYTE data[], DWORD count, long furtherSegments)
{
char someBytes[24];
WORD pos, i, max;
BYTE val;
pos = 0;
max = elcount( someBytes)/3;
if( max < count)
--max;
else if( max > count)
max = count;
for( i = 0; i < max; ++i)
{
val = data[i] >> 4;
someBytes[pos++] = val + (val > 9 ? 'A' - 10 : '0');
val = data[i] & 0xF;
someBytes[pos++] = val + (val > 9 ? 'A' - 10 : '0');
someBytes[pos++] = ' ';
}
--pos; // points to the last space
if( i < count)
{
someBytes[pos++] = '.';
someBytes[pos++] = '.';
someBytes[pos++] = '.';
}
someBytes[pos] = 0;
gSentResponse = 1;
if( gSendNextRequestFunctionally)
{
if( !gHandleFunctional)
return; // Not configured, so make sure an error is reported!
writeDbgLevel(1, "(CanTP) %s: Functional DataRequest %d byte: %s",
gECU, count, someBytes);
CanTpSendData(gHandleFunctional, data, count);
gSendNextRequestFunctionally = 0;
return;
}
// Send physically
writeDbgLevel(1, "(CanTP) %s: DataRequest %d byte: %s",
gECU, count, someBytes);
CanTpSendData( gCANFDConnectionUsed ? gHandleFD : gHandle, data, count);
gCANFDConnectionUsed = 0;
}
_Diag_SetupChannelReq()
{
// This callback function is only necessary in tester nodes!
Diag_SetupChannelCon();
}
CanTp_SendCon( long handle, DWORD txCount)
{
writeDbgLevel(1,"(CanTP) %s: CanTp_SendCon", gECU);
Diag_DataCon( txCount);
}
CanTp_ErrorInd( long handle, long error)
{
char cErrorText[12][30] = {
"(no error)"
, "Timeout while waiting for CF" // 1
, "Timeout while waiting for FC" // 2
, "Wrong Sequence Number" // 3
, "TP_DLL busy" // 4
, "Unexpected PDU" // 5
, "Timeout waiting for Tx-Ack" // 6
, "WFT Overrun" // 7
, "Buffer overflow" // 8
, "Wrong parameter" // 9
, "Invalid FlowStatus received" // 10
, "Transfer abort requested" // 11
};
if( error < elcount(cErrorText))
writeDbgLevel( 1, "(CanTP) %s: CanTp_ErrorInd(%d): %s", gECU, error, cErrorText[error]);
else
writeDbgLevel( 1, "(CanTP) %s: CanTp_ErrorInd(%d): unknown error!", gECU, error);
Diag_ErrorInd( error);
}
CanTp_ReceptionInd( long handle, BYTE data[])
{
writeDbgLevel(1,"(CanTP) %s: CanTp_ReceptionInd", gECU);
gLastRequestWasReceivedFunctionally = (handle == gHandleFunctional ? 1 : 0);
gCANFDConnectionUsed = (handle == gHandleFD ? 1 : 0);
gSentResponse = 0;
/* callback function for the OBC_ECU.can file to handle Raw Frames */
RecieveRawData(data, elcount( data), CanTpGetSenderAddress());
Diag_DataInd( data, elcount( data), CanTpGetSenderAddress());
if( !cIsTester && !gSentResponse)
{
SendNegResFormat( data[0]);
}
}
CCI_SendNextRequestFunctionally()
{
gSendNextRequestFunctionally = 1;
}
CCI_CloseConnections()
{
CanTpCloseConnection( gHandle);
gHandle = 0;
CanTpCloseConnection( gHandleFD);
gHandleFD = 0;
CanTpCloseConnection( gHandleFunctional);
gHandleFunctional = 0;
}
CanTp_FirstFrameInd( long handle, DWORD length)
{
writeDbgLevel(1,"(CanTP) %s: CanTp_FirstFrameInd", gECU);
diag_FirstFrameInd( 0, 1, length);
}
SendNegResFormat( BYTE serviceId)
{
BYTE negResponse[3] = { 0x7f, 0, 0x12 };
writeDbgLevel(0,"(CanTP) %s: Sending TP level NR(%02x)", gECU, serviceId);
negResponse[1] = serviceId;
gSentResponse = 1;
CanTpSendData( gCANFDConnectionUsed ? gHandleFD : gHandle, negResponse, 3);
}
以上是部分内容,后面对$34-$36-$37服务进行介绍。