基于CANoe的ECU Bootloader刷写软件
2016-02-23 14:24
881 查看
目标:
车辆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层的代码,秘钥也删了
车辆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<seed_szie;++i){ seed[i]=rxBuffer[i+2]; } gSeedArraySize = seed_szie;gMaxKeyArraySize = seed_szie; //generate_key(const_secu_flash_rfcm,seed,_key); diagSetTarget(ecu_name); DiagGenerateKeyFromSeed(seed, gSeedArraySize, security_level, gVariant, gOption, _key, gMaxKeyArraySize, gActualSize); for(i=0;i<gActualSize;++i){ send_key[i+2]=_key[i]; } OSEKTL_DataReq(send_key,2+gActualSize); return wait_server_response(send_key,timeout); } _Diag_GetError (char buffer[]) { //called if error in DiagGenerateKeyFromSeed occurs snprintf(gDebugBuffer,elcount(gDebugBuffer),"%s", buffer); write("CALLBACK %s", gDebugBuffer); } /* routineControl */ int routine_control(byte _routine_control_type,byte _routine_id[],byte data_record[],int data_record_length){ byte request[BUFFER_SIZE_1024]; int index=0; request[0]=0x31; request[1]=_routine_control_type; request[2]=_routine_id[0]; request[3]=_routine_id[1]; for(index=0;index<data_record_length;++index){ request[index+4]=data_record[index]; } OSEKTL_DataReq(request,data_record_length+4); return wait_server_response(request,timeout); } /* generate key according to the received seed */ void generate_key(byte const_secu[],byte seed_secu_flash[],byte securityKey[]){ byte key1_secu_flash[4]={0x00,0x00,0x00,0x00}; byte key2_secu_flash[4]={0x00,0x00,0x00,0x00}; int i=0; byte tmp=0x00; for(i=0;i<4;++i){ key1_secu_flash[i]=seed_secu_flash[i]^const_secu[i]; } for(i=0;i<2;++i){ tmp=seed_secu_flash[i]; seed_secu_flash[i]=seed_secu_flash[3-i]; seed_secu_flash[3-i]=tmp; } for(i=0;i<4;++i){ key2_secu_flash[i]=seed_secu_flash[i]^const_secu[i]; } for(i=0;i<4;++i){ securityKey[i]=key1_secu_flash[i]+key2_secu_flash[i]; } } /* communicationControl */ int communication_control(byte _control_type,byte _communication_type){ byte request[3]={0x28,0x00,0x00}; request[1]=_control_type;request[2]=_communication_type; OSEKTL_DataReq(request,elcount(request)); return wait_server_response(request,timeout); } /* controlDTCSetting */ int control_dtc_setting(byte _DTC_setting_type){ byte request[2]={0x85,0x00}; request[1]=_DTC_setting_type; OSEKTL_DataReq(request,elcount(request)); return wait_server_response(request,timeout); } /* tester Present */ int tester_present(byte sub_function){ byte request[2]={0x3e,0x00}; request[1]=sub_function; OSEKTL_DataReq(request,elcount(request)); return wait_server_response(request,timeout); } /* writeDataByID */ int write_data_by_id(byte did[],byte _data_record[],int _data_record_length){ byte request[256]; int i=0,_did_length=2; request[0]=0x2E; for(i=0;i<_did_length;++i){ request[1+i]=did[i]; } for(i=0;i<_data_record_length;++i){ request[1+_did_length+i]=_data_record[i]; } OSEKTL_DataReq(request,1+_did_length+_data_record_length); return wait_server_response(request,timeout); } /* requestDownload */ int request_download(byte _memory_address[],int _memory_address_length,byte _memory_size[],int __memory_size_length){ byte request[256]; int i=0; request[0]=0x34;request[1]=0x00;request[2]=0x44; for(i=0;i<_memory_address_length;++i){ request[3+i]=_memory_address[i]; } for(i=0;i<__memory_size_length;++i){ request[3+_memory_address_length+i]=_memory_size[i]; } OSEKTL_DataReq(request,3+_memory_address_length+__memory_size_length); return wait_server_response(request,timeout); } /* tansferData */ int transfer_data(byte _block_sequence,byte _upload_data[],int _upload_data_length){ byte request[BUFFER_SIZE_2048]; int i=0 , status = 0; request[0]=0x36;request[1]=_block_sequence; for(i=0;i<_upload_data_length;++i){ request[2+i]=_upload_data[i]; } OSEKTL_DataReq(request,_upload_data_length+2); status = wait_server_response(request,timeout); return status; } /* requstTransferExit */ int request_transfer_exit(){ byte request[1]={0x37}; OSEKTL_DataReq(request,elcount(request)); return wait_server_response(request,timeout); } int read_data_by_id(byte did[]){ byte request[3]={0x22,0x00,0x00}; request[1]=did[0]; request[2]=did[1]; OSEKTL_DataReq(request,elcount(request)); return wait_server_response(request,timeout); } OSEKTL_FirstFrameIndication( long sourceadr, long destadr, long rxCount ) { /* Print message to write window */ //write("CAPL: %s: FF indication called, SA= 0x%02lx, TA= 0x%02lx, RxCount = %ld (AE=%d)", gECU, sourceadr, destadr, rxCount, OSEKTL_GetRecentAE()); } //error handle OSEKTL_ErrorInd(int error) { switch (error) { case 1: write("----CAPL: Error (%d): Timeout while waiting for CF", error); break; case 2: write("----CAPL: Error (%d): Timeout while waiting for FC", error); break; case 3: write("----CAPL: Error (%d): Wrong Sequence Number", error); break; case 4: write("----CAPL: Error (%d): TP_DLL busy", error); break; case 5: write("----CAPL: Error (%d): Unexpected PDU", error);stop(); break; case 6: write("----CAPL: Error (%d): Timeout while waiting for Tx-Ack", error); break; case 7: write("----CAPL: Error (%d): WFT Overrun", error); break; case 8: write("----CAPL: Error (%d): Buffer overflow", error); break; case 9: write("----CAPL: Error (%d): Wrong parameter", error); break; default: write("----CAPL: Error (%d): unknown error", error); break; } } //request confirm OSEKTL_DataCon(long status) { if (status != 0) { //write("CAPL: %s: data sent using normal addressing", gECU); } else { write("----CAPL: %s: tx error, status is %d", gECU, status); } } OSEKTL_DataInd( long rxCount ) { dword glhandle=0; /* Get received data */ OSEKTL_GetRxData( rxBuffer, 4095 ); rxBufferLen=rxCount; //signal response received TestSupplyTextEvent(wait_rsp_text_event); } //process will suspend for tTime ms to wait for response int wait_server_response(byte request[],dword _tTime){ long status=0; int result=0; long flag=5; flag=2;result=0;status=0; //loop while response pending while(flag>=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; }
相关文章推荐
- 一条汇编指令引发的 蝴蝶效应
- DHCP、PXE的基础配置
- Git 操作整理
- HSU 2328 Corporate Identity
- QML的import目录爬坑记录
- 三表关联表中查询满足条件的语句
- linux 回收站的路径
- UIView和CALayer的区别 说的比较清楚了
- Swift:如何判断一个对象是否是某个类(或其子类)的实例
- 3DTouch简单实现
- Swift项目兼容Objective-C问题汇总
- iOS-UItableview 分割线(自定义+原生)方法总结
- 操作系统死锁
- 对MySQL的几个错误印象
- “同时”启动两个Activity
- Android的APK应用签名机制以及读取签名的方法
- JavaWeb实现用户登录的拦截
- Maven项目中log4j配置
- java之StringUtils
- 能发送http请求(get,post)的工具