目标:
车辆ECU需要更新软件,通过OBD口实现,通过CAN总线实现,编程语言是CAPL。
刷写流程基于ISO15765-3;应用层基于UDS(ISO14229)诊断协议;TP层基于ISO15765-2;数据链路层和物理层基于ISO11898
实现:
1.图形用户界面使用CANoe自带的panel来实现,用户可以选取刷写文件,ECU的地址等信息,这些信息通过环境变量被程序访问,环境变量在CANDB++中编辑生成。
2.软件架构:
刷写工具解析s19 app,如果没有s19 app,那么可以使用HexView将HEX,BIN等app转成s19文件
依据ISO15765-3编写刷写流程代码,将app数据扔给应用层
应用层是基于UDS编写的,应用层在将数据扔给TP层
TP层将数据扔给数据链路层
数据链路层将数据扔给物理层,数据通过CAN总线被ECU接收
代码:
工作保密原因,只贴出UDS层的代码,秘钥也删了
includes{
}
variables{
char gECU[7]="Tester";
int useExtendedId=0; //use standard Id
long useFC=1; //use flow control
long bs=8; //block size of FC
long stmin=20; //set STmin to 10 ms
dword tester_address=0x7c1; //tester address
dword target_ecu_address=0x7c9; //BCM address
char wait_rsp_text_event[18]="response received"; //used to wait for response
const int BUFFER_SIZE_2048=0x2048;
const int BUFFER_SIZE_1024=0x1024;
const int LENGTH_4=4;
byte rxBuffer[BUFFER_SIZE_2048]; //receive buffer
long rxBufferLen=0; //receive buffer length
dword timeout=5000;
dword min_request_distance=50; //minum distance between two request
dword dist_request = 10;
char gDebugBuffer[255];
}
/*
read fault memory
*/
int read_fault_memory(byte _sub_func,byte _status_mask){
byte request[3]={0x19,0x02,0x09};
rxBufferLen=0;
request[1]=_sub_func;request[2]=_status_mask;
OSEKTL_DataReq(request,elcount(request));
return wait_server_response(request,timeout);
}
/*
sessionControl
*/
int session_control(byte _session_type){
byte request[2]={0x10,0x01};
request[1]=_session_type;
OSEKTL_DataReq(request,elcount(request));
return wait_server_response(request,timeout);
}
/*
reset
*/
int reset(byte reset_type){
byte request[2]={0x11,0x01};
request[1]=reset_type;
OSEKTL_DataReq(request,elcount(request));
return wait_server_response(request,timeout);
}
/*
securityAccess
*/
int security_access(byte security_level,byte seed_szie,char ecu_name[]){
//actual size of Seed & Key Arrays depends on ECU
byte gSeedArray[2];
dword gSeedArraySize = 4;
char gVariant[9] = "Variant1";
char gOption[7] = "option";
dword gMaxKeyArraySize = 4;
dword gActualSize = 0;
byte request_seed[2]={0x27,0x01};
byte send_key[6]={0x27,0x02,0xAA,0xAA,0xAA,0xAA};
byte const_secu_flash[4]={}; //security const number for level flash for BCM
byte const_secu_level1[4]={}; //security const number for level 1 for BCM
byte const_secu_flash_rfcm[4]={}; //security const number for level flash for BCM
byte seed[4]={0xAA,0xAA,0xAA,0xAA}; //store the seed received from server
byte _key[4]={0xAA,0xAA,0xAA,0xAA}; //store the key generated by tester
int i=0;
request_seed[ 1 ] = security_level;send_key[ 1 ] = security_level + 0x01;
OSEKTL_DataReq(request_seed,elcount(request_seed));
if(wait_server_response(request_seed,timeout)!=0){
write("fail to retrive seed while unlocking ECU");
return -1;
}
for(i=0;i=0)
{
status=testWaitForTextEvent(wait_rsp_text_event,_tTime);
if(status<0){
write("service %x:fail to wait server response",request[0]);
return -1;
}else if(status==0){
write("service %x:timeout while waiting for server\'s response",request[0]);
return -1;
}
result=checkResponse(request);
if(result==-3){
write("response pending");
flag=5;
}
if(result==-2){
write("Warning:unexpected positive response");
flag--;
}
if(result==-1){
write("service %x:negative response received",request[0]);
break;
}
if(result==0){
//write("positive response received\n");
break;
}
}
if(result<0){
msgBeep(5);
return -1;
}
return 0;
}
/*
check response
return 0 if positive response received
otherwise return -1,-2,-3,0
*/
int checkResponse(byte request[]){
if(rxBufferLen<=0){
write("Error:empty response reveived\n");
return -1;
}
else{
if(rxBuffer[0]==request[0]+0x40){
//write("positive response received\n");
return 0;
}else if(rxBuffer[0]!=0x7F&&rxBuffer[0]!=(rxBuffer[0]+0x40)){
//unexpected positive response
return -2;
}
else if(rxBuffer[0]==0x7F&&rxBuffer[1]==request[0]){
if(rxBuffer[2]!=0x78)
{
//write("Error:negative response received\n");
return -1;
}else{
//response pending
return -3;
}
}
}
return 0;
}