【TBOX】基於CANoe實現的自動化測試方案


  為滿足項目過程中不同階段絕大部分測試需求,更方便快捷構造測試場景,支持異常場景測試。更早介入,不依賴周邊ECU的穩定情況,專注於被測ECU。更經濟,不加油,不充電,時間節省,物料節省等維度考慮。我們需要一個建設測試台架至少可覆蓋實車上80%的測試場景需求。

目標任務分解

1、車內網絡模型建立

模擬車內網絡通信模型,各節點信號仿真

2、業務關聯的ECU仿真

封裝ECU之間的業務交互邏輯,車身控制器,儀表台模擬等

a)每個ECU的邏輯都是隨CANoe啟動,激活CAN通信;

b)根據PEPS電源信號狀態決定該ECU的活躍狀態;

c)ECU 根據具體業務處理總線上的請求;

d)設計仿真器的ECU則根據信號變化情況,更新仿真器的狀態

CAPL編程實現

1、環境變量

為實現控制面板輸入輸出與信號同步,實現仿真器的狀態更新,先定義與信號成映射關系的環境變量。環境變量的定義主要根據各ECU的相關信號與業務的關聯度決定。基本上與T業務掛鈎的信號都應該設置相應的環境變量,監控信號變化,實時更新仿真器的狀態。

2、各ECU通用代碼塊

存儲一些全局變量,日志記錄等,各ECU可包含此文件調用


variables
{
  // 報文發送周期, 單位ms
  const int varCycTime10 = 10;
  const int varCycTime20 = 20;
  const int varCycTime50 = 50;
  const int varCycTime100 = 100;
  const int varCycTime200 = 200;
  const int varCycTime500 = 500;
  const int varCycTime1000 = 1000;
  
  // varCarType車型定義, 0=純油, 1=純電, 2=混動, others=error
  // 字母代碼 AFV=純油, EV=純電, HEV=混動(不區分直插式和充電樁式)
  // 全局LOG
  long mTrace = 0; 
  //severity
  dword INFO = 1;
  dword WARN = 2;
  dword ERROR = 3;
  // 鑒權秘鑰
  byte varESKCode[10][8] = {
    //。。。略
  }; 
  
  // varCarCode 標記當前被測車型, 用於選擇調用正確的鑒權碼
  int varESKNumber;
  // 記錄當前電源模式,0=OFF; 1=ACC; 2=ON; 3=reserved; 4=start; 5,6,7=reserved
  int varPowerMode=0;
  int lastPowerMode=0;
  // 發動機狀態
  int varEngineStatus;
  
  //總線報文管理,0=停發, 1=啟動
  int varNM;// 遠程控制請求中,啟動發動機的時間
  int varRmStartTime;
  // 遠程控制請求中,啟動發動機的時間長度 分級
  int varRmStartTimeLvl; ////0=No Req; 1=3min; 2=5min; 3=8min; 4=10min; 5,6,7=reserved
//  // 防盜報警定時器
//  timer BCM_ATWS_timer;
  //車速
  int varVelSpeed;
  
  //標記發動機是否已啟動
  int IsEngineWorking = 0;
}

/***********************************************************
* description  : 全局日志記錄函數
* parameter    : None
* creation date: 2018/10/26
* author       : xxx   
* revision date: 
* revision log : 
* modifier     : 
***********************************************************/
void InitLogging()
{
  mTrace = writeCreate("Logging");
  writeConfigure(mTrace,1024*1000,1,"..\\Proj\\Log\\write.txt");
  writeclear(1);
}

3、ESC封裝車速信號,處理行車過程中自動落鎖的邏輯

此處詳盡展現代碼實現段落開始處所描述的四點邏輯,后續ECU只展現具體的業務處理,不在代碼展示中繼續保留a)&  b),或 d)

includes
{
  #include "ECUsVar.can"
}

variables
{
  //本消息由ESC發出,包含ESC狀態,車速、以及剎車板狀態信號, 此處ID由我捏造為0x111
  message 0x111 ESC_Status; 
  msTimer ESC_timer;
}

on timer ESC_timer
{
  output(ESC_Status);
  setTimer(ESC_timer, varCycTime20);
}

//車速
on envVar ESC_VehicleSpeed
{ 
  float factor = 0.05625;
  int offset = 0;
  varVelSpeed = getValue(ESC_VehicleSpeed);
  
  //轉換成儀表顯示, KPH
  if(varPowerMode!=2)
  {
    writeDbgLevel(1, "PowerMode=OFF,車速調節無效");
    ESC_Status.ESC_VehicleSpeed = 0;
    putValue(ESC_VehicleSpeed, 0);
  }
  else
  {
    if(varVelSpeed!=0) //置位發動機轉速
    {
      writeDbgLevel(1, "點火狀態,車速不為零,設置發動機轉速");
      putValue(EMS_EngineSpeedRPM,3000);
    }
    else
    {
      putValue(EMS_EngineSpeedRPM,0);
    }
    if(varVelSpeed>25) //車速>25時,自動落鎖
    {
      writeDbgLevel(1,"車速>25碼,自動落鎖");
      putValue(LockDoors, 1);
    }
    ESC_Status.ESC_VehicleSpeed = (varVelSpeed-offset)/ factor;
  }
}

on envVar PEPS_PowerMode
{
  // 此處根據PEPS電源狀態封裝ESC在網絡上的活躍情況(是否對外發送信號和處理總線上的請求)
}


on start
{
  InitESCValue();
  ActiveESC();
}

//初始化
void InitESCValue()
{
  varPowerMode = getValue(PEPS_PowerMode);
  //以下兩行代碼初始化ESC信號,此處略去其它很多信號,自填......
  putValue(ESC_VehicleSpeed, 0);
  ESC_Status.xxx=0;
}

//激活
void ActiveESC()
{
  setTimer(ESC_timer, varCycTime20);
}
//去激活
void InactiveESC()
{
  cancelTimer(ESC_timer);
}

4、IPK實現同步系統時間

若你的車聯網系統的標准時鍾來自其它ECU,則以該ECU的時間為參考。這涉及判斷T業務的實時性與有效性邏輯。(注意:我所用的CANoe 8.5.98的調用getLocalTimeString獲取系統時間異常,我通過代碼矯正了一下,11.0版本則不用矯正)

variables
{
  const h_offset = 0;//5; //時差
  const m_offset = 0;//5; //分差
  // IPK提供日期時間信息, 年月日,時分秒;500ms
  message 0x222 IPK_DateTime;  //以下報文ID全由我捏造,可根據實際DBC中定義修改成相應ID
  
  // IPK提供純電續航里程、平均電耗、瞬時電耗、油耗, 1000ms
  message 0x223 IPK_Data;
  
  // 本消息由IPK發出,包含儀表的信息,100ms
  // 安全氣囊控制器狀態檢查反饋,剩余油量,平均車速,手剎狀態,保養提示報警,背光調節,機油壓力低報警狀態
  message 0x224 IPK_STS;
  
  // 本消息由IPK發出,包含總里程的信息,可續航里程,保養里程;1000ms
  message 0x225 IPK_Odometer;
  
  msTimer IPK_Date_timer;
  msTimer IPK_ODO_timer;
  msTimer IPK_Sts_timer;
  //當前時間提示器, 用來核對TBOX系統時間是否正確
  timer DateRemanderTimer;
  
  // 存放時間的數組,當IPK負載不存在時,仿真實現。傳遞時間到TBOX
  long tm[9];
  char t_canoe[26];
  char t_now[26];
}

*********************************************************** * description : 由IPK發出的系統時間,傳遞給TBOX同步此時間 * parameter : None * creation date: 2018/10/15 * author : xxx * revision date: * revision log : * modifier : ***********************************************************/ on timer IPK_Date_timer { output(IPK_DateTime); setTimer(IPK_Date_timer, varCycTime500); } /*********************************************************** * description : 由IPK發出的儀表盤信息 * parameter : None * creation date: 2018/10/15 * author : xxx * revision date: * revision log : * modifier : ***********************************************************/ on timer IPK_Sts_timer { GetSysTime(); output(IPK_STS); setTimer(IPK_Sts_timer, varCycTime100); } /*********************************************************** * description : 由IPK發出的里程相關信息,可能會根據油車,混動,純電,展示的信息不一致,根據DBC定義來實現 * parameter : None * creation date: 2018/10/15 * author : xxx * revision date: * revision log : * modifier : ***********************************************************/ on timer IPK_ODO_timer { output(IPK_Odometer); setTimer(IPK_AFV_ODO_timer, varCycTime1000); }/*********************************************************** * description : 獲取當前PC時間,作為IPK時間發布到CAN線上 * parameter : None * creation date: 2018/10/15 * author : xxx * revision date: * revision log : * modifier : ***********************************************************/ void GetSysTime() { getLocalTimeString(t_canoe); getLocalTime(tm); // year since 1900; month from 0-11 IPK_DateTime.IPK_Year = tm[5]-100; IPK_DateTime.IPK_Month = tm[4]+1; IPK_DateTime.IPK_Second = tm[0]; //以上API獲取的時間比北京時間快6h 5min if(tm[2]>=h_offset) //24小時制 { IPK_DateTime.IPK_Hour = tm[2]-h_offset; //減去快的6H IPK_DateTime.IPK_Day = tm[3]; } else { IPK_DateTime.IPK_Hour = tm[2] -h_offset+24; //當時間跳到第二天凌晨,逆向+18 IPK_DateTime.IPK_Day = tm[3] -1; // day-1 } if(tm[1]>=m_offset) //處理分鍾 { IPK_DateTime.IPK_Minute = tm[1] -m_offset; } else { IPK_DateTime.IPK_Minute = tm[1] -m_offset + 60; //此時小時跨度要再減一小時 IPK_DateTime.IPK_Hour = tm[2]-(h_offset+1); //減去快的6H and 跨時段1 } //格式化當前時間戳 snprintf(t_now, elcount(t_now),"%d/%d/%d %02d:%02d:%02d", tm[5]+1900, tm[4]+1, tm[3], IPK_DateTime.IPK_Hour,IPK_DateTime.IPK_Minute,tm[0]); } //log輸出 提示作用 on timer DateRemanderTimer { writeDbgLevel(1, "CANoe Time: %s", t_canoe); writeDbgLevel(1, "Now Time:%s", t_now); setTimer(DateRemanderTimer, varCycTime10); } //激活IPK(當電源ON時,觸發) //去激活IPK(當電源OFF時,停發IPK報文)// 設置每次啟動CANoe時,儀表盤的初值//電源模式變更時,處理IPK在總線上的活躍狀態 //以下代碼舉兩個例子描述,具體信號的變化,呈現在控制面板上的為物理值。其余信號可自己根據樣板添加 //平均油耗 L/100Km on envVar IPK_AverageFuelConsumption { int temp; //偏移量與精度值 float factor = 0.01; int offset = 0; temp = getValue(IPK_AverageFuelConsumption); IPK_Data.IPK_AverageFuelConsumption = (temp-offset)/factor; } //平均電耗 KWH/100km on envVar IPK_AveragePowerConsumption { int temp; //偏移量與精度值 float factor = 0.1; int offset = -99.9; temp = getValue(IPK_AveragePowerConsumption); IPK_Data.IPK_AveragePowerConsumption = (temp-offset)/factor; }

5、車身模擬器,BCM+EMS

EMS仿真實現,發動機狀態更新

 1 variables
 2 {
 3   char BCMStatusPanel[32] = "BCM狀態圖";
 4   char EMSCtrl[8] = "發動機";
 5   
 6   //本消息由EMS發出,包含引擎轉速、加速踏板狀態信號
 7   message 0x334 EMS_EngineRPM;
 8 
 9   msTimer EMS_timer;
10 }
11 
12 on envVar PEPS_PowerMode
13 {
14   //獲取電源模式 + 車速
15   varPowerMode = getValue(PEPS_PowerMode);
16   if(varPowerMode==3)
17   {
18     putValue(EMS_EngStatus, 0);//stop
19     putValue(EMS_EngineSpeedRPM,0);
20     InactiveEMS();
21     lastPowerMode = varPowerMode;
22   }
23   else
24   {
25     if(lastPowerMode==3 && varPowerMode==0)
26     {
27       ;
28     }
29     else
30     {
31       switch(varPowerMode)
32       {
33         case 0:
34           putValue(EMS_EngStatus, 0);//stop
35           putValue(EMS_EngineSpeedRPM,0);
36           break;
37         case 1:
38           putValue(EMS_EngStatus, 0);//stop
39           putValue(EMS_EngineSpeedRPM,0);
40           break;
41         case 2:
42           putValue(EMS_EngStatus, 3);
43           break;
44         case 4:
45           putValue(EMS_EngStatus, 1);//Cranking
46           putValue(EMS_EngineSpeedRPM,0);
47           break;
48         default:
49           break;
50       }
51       ActiveEMS();          
52     }
53   }
54 }
55 
56 //更新車身仿真器的狀態
57 on envVar EMS_EngStatus
58 {
59   int temp;
60   temp = getValue(EMS_EngStatus);
61   EMS_EngineRPM.EMS_EngStatus = temp;
62   if(temp==3)
63   {
64     IsEngineWorking = 1; //發動機工作中
65     setPictureBoxImage(BCMStatusPanel, EMSCtrl, "..\\Panels\\picture\\啟動中.bmp");
66   }
67   else if (temp==0)//油車
68   {
69     IsEngineWorking = 0;
70     setPictureBoxImage(BCMStatusPanel, EMSCtrl, "..\\Panels\\picture\\未啟動.bmp");
71   }
72   else if(temp==2) //PHEV
73   {
74     if(@GEEA1::varCarType == 2)
75     {
76       IsEngineWorking = 0;
77       setPictureBoxImage(BCMStatusPanel, EMSCtrl, "..\\Panels\\picture\\未啟動.bmp");
78     }
79   }
80 }
81 
82 //略去 EMS激活,去激活,初始值,報文發送的函數

BCM仿真器實現,四門六蓋,鎖狀態

  1 variables
  2 {
  3   char BCMCtrlPanel[32] = "ControlPanel";
  4   char BCMStatusPanel[32] = "BCM狀態圖";
  5   char BCMHoodCtrl[32]= "引擎蓋";
  6   char BCMTrunkCtrl[32]= "后備箱";
  7   char BCMLFDoorCtrl[32]= "左前門";
  8   char BCMLRDoorCtrl[32]= "左后門";
  9   char BCMRFDoorCtrl[32]= "右前門";
 10   char BCMRRDoorCtrl[32]= "右后門";
 11   char BCMSunroofCtrl[32]= "天窗";
 12   char BCMLockCtrl[32]= "";
 13   
 14   //本消息由BCM發出,包含BCM控制的各類開關以及加熱器繼電器開關信號
 15   message 0x1 BCM_StateUpdate;
 16   //左門窗
 17   message 0x2 BCM_LDoorWindowState;
 18   //右門窗
 19   message 0x3 BCM_RDoorWindowState;
 20   //本消息由BCM發出,包含前車窗狀態及天窗狀態信號
 21   message 0x4 BCM_SunroofState;
 22   // 發送100ms周期的報文
 23   msTimer BCM_WndsDoors_timer;
 24   
 25 }
 26 
 27 on start
 28 {
 29   InitBCMValue();
 30   InitBCMPanels();
 31   //BCM不受PEPS電源模式影響,所以啟動CANoe即可發出BCM報文
 32   ActiveBCM();
 33 }
 34 
 35 on timer BCM_WndsDoors_timer
 36 {
 37   output(BCM_SunroofState);
 38   output(BCM_StateUpdate);
 39   output(BCM_LDoorWindowState);
 40   output(BCM_RDoorWindowState);
 41   setTimer(BCM_WndsDoors_timer, varCycTime100);
 42 }
 43 
 44 //設置每次啟動CANoe時,BCM的初值
 45 void InitBCMValue()
 46 {
 47 }
 48 
 49 void InitBCMPanels()
 50 {
 51   //打開控制面板 capl function, 此處不指明路徑 直接遍歷工程目錄
 52   openPanel(BCMCtrlPanel);   
 53   openPanel(BCMStatusPanel);
 54 }
 55 
 56 //激活BCM往外發送報文
 57 void ActiveBCM()
 58 {
 59   setTimer(BCM_WndsDoors_timer, varCycTime100);
 60 }
 61 
 62 //停發BCM報文
 63 void InactiveBCM()
 64 {
 65   cancelTimer(BCM_WndsDoors_timer);
 66 }
 67 
 68 //預留一開關 停發所有報文
 69 on envVar PEPS_PowerMode
 70 {
 71   varPowerMode = getValue(PEPS_PowerMode);
 72   if(varPowerMode==3) //CAN-Sleep
 73   {
 74     InactiveBCM();
 75     lastPowerMode = varPowerMode;
 76   }
 77   else
 78   {
 79     if((varPowerMode==0)&&(lastPowerMode==3))
 80     {
 81       ;
 82     }
 83     else if((2==varPowerMode) || (1==varPowerMode) || (4==varPowerMode))
 84     {
 85       ActiveBCM(); //不是從3跳到0的模式,全激活
 86     }
 87     lastPowerMode = varPowerMode;
 88   }
 89 }
 90 //天窗
 91 on envVar BCM_SunroofAjarStatus
 92 {
 93   int temp;
 94   
 95   temp = getValue(BCM_SunroofAjarStatus);
 96   writeDbgLevel(1,"天窗信號=%d",temp);
 97   BCM_SunroofState.L_Sunroof_Position=temp;
 98   if(temp==0) //未知
 99   {
100     setPictureBoxImage(BCMStatusPanel,BCMSunroofCtrl,"..\\Panels\\picture\\天窗未知.bmp");  
101   }
102   else if(temp==1) //關閉
103   { 
104     setPictureBoxImage(BCMStatusPanel,BCMSunroofCtrl,"..\\Panels\\picture\\天窗關閉.bmp");  
105   }
106   else if(temp==2) //開啟
107   {
108     setPictureBoxImage(BCMStatusPanel,BCMSunroofCtrl,"..\\Panels\\picture\\天窗未關閉.bmp");  
109   }
110 }
111 //駕駛位車窗
112 on envVar BCM_Drv_Wdw_PositionSts
113 {
114   int x,y;
115   
116   x = getvalue(BCM_Drv_Wdw_PositionSts);
117   y = getvalue(BCM_FrontLeftDoorAjarStatus);
118   writeDbgLevel(1,"駕駛位車窗=%d",x);
119   BCM_LDoorWindowState.L_Drv_Wdw_PositionSts = x;
120   if((x==1)&&(y==0))
121   {
122    setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前窗開.bmp");  
123   }
124   else if((x==1)&&(y==1))
125   {
126    setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前門和窗未關閉.bmp");  
127   }
128   else if((x==2)&&(y==0))
129   {
130    setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前門關閉.bmp");  
131   }
132   else if((x==2)&&(y==1))
133   {
134    setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前門未關閉.bmp");  
135   }
136   else if((x==0)&&(y==0))
137   {
138    setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前窗透氣.bmp");  
139   }
140    else if((x==0)&&(y==1))
141   {
142    setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前門未關閉窗透氣.bmp");  
143   }
144 }
145 //左后窗
146 on envVar BCM_RLD_Wdw_PositionSts
147 {
148   int x, y;
149   x = getValue(BCM_RLD_Wdw_PositionSts);
150   y = getValue(BCM_RearLeftDoorAjarStatus);
151   writeDbgLevel(1,"左后車窗=%d",x);
152   BCM_LDoorWindowState.L_RLD_Wdw_PositionSts = x;
153   if((y==0) && (x==1))
154   {
155    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后窗開.bmp");  
156   }
157   else if((y==1) && (x==1))
158   {
159    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后門和窗未關閉.bmp");  
160   }
161    else if((y==0)&&(x==2))
162   {
163    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后門關閉.bmp");  
164   }
165    else if((y==1)&&(x==2))
166   {
167    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后門未關閉.bmp");  
168   }
169   else if((y==0)&&(x==0))
170   {
171    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后窗透氣.bmp");  
172   }
173   else if((y==1)&&(x==0))
174   {
175    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后門未關閉窗透氣.bmp");  
176   }
177 }
178 //左前門
179 on envVar BCM_FrontLeftDoorAjarStatus
180 {
181   int x, y, z;
182   x = getvalue(BCM_FrontLeftDoorAjarStatus);
183   y = getvalue(BCM_Drv_Wdw_PositionSts);
184   z = getValue(BCM_DoorLockStatusDrv);
185   BCM_LDoorWindowState.BCM_FrontLeftDoorAjarStatus = x;
186   if((x==1) && (z==1) && (varPowerMode==0))
187   { //防盜入侵報警,熄火OFF+鎖車+開左前門觸發,10s后恢復armed
188      putValue(BCM_ATWS_St,4);  //0x0: Armed0x1: Prearmed0x2: Disarmed0x3: Remind0x4: Alarm0x5: Partially Armed0x6: Not used0x7: Not used
189      BCM_StateUpdate.BCM_ATWS_St=getvalue(BCM_ATWS_St);
190      //setTimer(BCM_ATWS_timer, varCycTime10);
191   }  
192   if((y==1)&&(x==0))
193   {
194     setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前窗開.bmp");  
195   }
196   if((y==1)&&(x==1))
197   {
198     setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前門和窗未關閉.bmp");  
199   }
200   if((y==2)&&(x==0))
201   {
202     setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前門關閉.bmp");  
203   }
204   if((y==2)&&(x==1))
205   {
206     setPictureBoxImage(BCMStatusPanel, BCMLFDoorCtrl, "..\\Panels\\picture\\左前門未關閉.bmp");  
207   }
208 }
209 //左后門
210 on envVar BCM_RearLeftDoorAjarStatus
211 {
212   int x,y;
213   x = getvalue(BCM_RearLeftDoorAjarStatus);
214   y = getvalue(BCM_RLD_Wdw_PositionSts);
215   BCM_LDoorWindowState.BCM_RearLeftDoorAjarStatus=x;
216   if((x==0)&&(y==1))
217   {
218    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后窗開.bmp");  
219   }
220   else if((x==1)&&(y==1))
221   {
222    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后門和窗未關閉.bmp");  
223   }
224    else if((x==0)&&(y==2))
225   {
226    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后門關閉.bmp");  
227   }
228    else if((x==1)&&(y==2))
229   {
230    setPictureBoxImage(BCMStatusPanel, BCMLRDoorCtrl, "..\\Panels\\picture\\左后門未關閉.bmp");  
231   }
232 
233 }
234 //駕駛側鎖
235 on envVar BCM_DoorLockStatusDrv
236 {
237   int temp;
238   temp=getValue(BCM_DoorLockStatusDrv);
239   writeDbgLevel(1,"門鎖信號=%d",temp);
240   BCM_LDoorWindowState.BCM_DoorLockStatusDrv=temp;
241   if(temp==0)
242   {
243     setPictureBoxImage(BCMStatusPanel,BCMLockCtrl,"..\\Panels\\picture\\鎖開.bmp");  
244   }
245   else
246   {
247     setPictureBoxImage(BCMStatusPanel,BCMLockCtrl,"..\\Panels\\picture\\鎖閉.bmp");  
248   }
249 }
250 //左后門鎖
251 on envVar BCM_DoorLockStatusRL
252 {
253   BCM_LDoorWindowState.BCM_DoorLockStatusRL=getValue(BCM_DoorLockStatusRL);
254 }
255 //右前窗
256 on envVar BCM_Pas_Wdw_PositionSts
257 {
258   int x,y;
259   x = getvalue(BCM_Pas_Wdw_PositionSts);
260   y = getvalue(BCM_FrontRightDoorAjarStatus);
261   writeDbgLevel(1,"副駕車窗=%d",x);
262   BCM_RDoorWindowState.L_Pas_Wdw_PositionSts=x;
263   if((y==0)&&(x==1))
264   {
265    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前窗開.bmp");  
266   }
267   else if((y==1)&&(x==1))
268   {
269    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前門和窗未關閉.bmp");  
270   }
271   else if((y==0)&&(x==2))
272   {
273    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前門關閉.bmp");  
274   }
275   else if((y==1)&&(x==2))
276   {
277    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前門未關閉.bmp");  
278   }
279    else if((y==0)&&(x==0))
280   {
281    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前窗透氣.bmp");  
282   }
283    else if((y==1)&&(x==0))
284   {
285    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前門未關閉窗透氣.bmp");  
286   }
287 }
288 //右后窗
289 on envVar BCM_RRD_Wdw_PositionSts
290 {
291   int x,y;
292   x = getvalue(BCM_RRD_Wdw_PositionSts);
293   y = getvalue(BCM_RearRightDoorAjarStatus);
294   
295   writeDbgLevel(1,"右后車窗=%d",x);
296   BCM_RDoorWindowState.L_RRD_Wdw_PositionSts=x;
297   if((y==0)&&(x==1))
298   {
299    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后窗開.bmp");  
300   }
301   if((y==1)&&(x==1))
302   {
303    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后門和窗未關閉.bmp");  
304   }
305   if((y==0)&&(x==2))
306   {
307    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后門關閉.bmp");  
308   }
309   if((y==1)&&(x==2))
310   {
311    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后門未關閉.bmp");  
312   }
313   if((y==0)&&(x==0))
314   {
315    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后窗透氣.bmp");  
316   }
317   if((y==1)&&(x==0))
318   {
319    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后門未關閉窗透氣.bmp");  
320   }
321 }
322 //副駕門鎖
323 on envVar BCM_DoorLockStatusPassenger
324 {
325   BCM_RDoorWindowState.BCM_DoorLockStatusPass=getValue(BCM_DoorLockStatusPassenger);
326 }
327 //右后門鎖
328 on envVar BCM_DoorLockStatusRR
329 {
330   BCM_RDoorWindowState.BCM_DoorLockStatusRR=getValue(BCM_DoorLockStatusRR);
331 }
332 //右前門
333 on envVar BCM_FrontRightDoorAjarStatus
334 {
335   int x,y;
336   x = getvalue(BCM_Pas_Wdw_PositionSts);;
337   y = getvalue(BCM_FrontRightDoorAjarStatus);
338   BCM_RDoorWindowState.BCM_FrontRightDoorAjarStatus=y;
339   if((y==0)&&(x==1))
340   {
341    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前窗開.bmp");  
342   }
343   else if((y==1)&&(x==1))
344   {
345    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前門和窗未關閉.bmp");  
346   }
347   else if((y==0)&&(x==2))
348   {
349    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前門關閉.bmp");  
350   }
351   else if((y==1)&&(x==2))
352   {
353    setPictureBoxImage(BCMStatusPanel, BCMRFDoorCtrl, "..\\Panels\\picture\\右前門未關閉.bmp");  
354   }
355 }
356 //右后門
357 on envVar BCM_RearRightDoorAjarStatus
358 {
359   int x, y;
360   y = getvalue(BCM_RearRightDoorAjarStatus);
361   x = getvalue(BCM_RRD_Wdw_PositionSts);
362   BCM_RDoorWindowState.BCM_RearRightDoorAjarStatus=y;
363  if((y==0)&&(x==1))
364   {
365    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后窗開.bmp");  
366   }
367  if((y==1)&&(x==1))
368   {
369    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后門和窗未關閉.bmp");  
370   }
371   if((y==0)&&(x==2))
372   {
373    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后門關閉.bmp");  
374   }
375   if((y==1)&&(x==2))
376   {
377    setPictureBoxImage(BCMStatusPanel, BCMRRDoorCtrl, "..\\Panels\\picture\\右后門未關閉.bmp");  
378   }
379 }
380 
381 //一鍵關門
382 on envVar CloseDoors
383 {
384   int temp;
385   temp = getValue(CloseDoors);
386   if(temp==0) //關閉 
387   { 
388     putValue(BCM_FrontLeftDoorAjarStatus,0);
389     putValue(BCM_FrontRightDoorAjarStatus,0);
390     putValue(BCM_RearLeftDoorAjarStatus,0);
391     putValue(BCM_RearRightDoorAjarStatus,0);
392     
393   }
394   else //開啟
395   {
396     putValue(BCM_FrontLeftDoorAjarStatus,1);
397     putValue(BCM_FrontRightDoorAjarStatus,1);
398     putValue(BCM_RearLeftDoorAjarStatus,1);
399     putValue(BCM_RearRightDoorAjarStatus,1);
400   }
401 }
402 //一鍵關窗
403 on envVar CloseWnds
404 {
405   int temp;
406   temp = getValue(CloseWnds);
407   //writeDbgLevel(1,"一鍵關窗=%d",temp);
408   if(temp==0) //關閉
409   {
410     putValue(BCM_Drv_Wdw_PositionSts,2);
411     putValue(BCM_Pas_Wdw_PositionSts,2);
412     putValue(BCM_RLD_Wdw_PositionSts,2);
413     putValue(BCM_RRD_Wdw_PositionSts,2);
414     
415     //天窗
416     putValue(BCM_SunroofAjarStatus, 1);
417     //開度值=0
418     putValue(BCM_Val_Wdw_Opened,0);
419   }
420   else //全開
421   {
422     putValue(BCM_Drv_Wdw_PositionSts,1);
423     putValue(BCM_Pas_Wdw_PositionSts,1);
424     putValue(BCM_RLD_Wdw_PositionSts,1);
425     putValue(BCM_RRD_Wdw_PositionSts,1);
426     
427     //可屏蔽天窗
428     putValue(BCM_SunroofAjarStatus, 2);
429     //開度值=100
430     putValue(BCM_Val_Wdw_Opened,100);
431   }
432 }
433 //一鍵鎖止
434 on envVar LockDoors
435 {
436   int temp;
437   temp = getValue(LockDoors);
438   if(1==temp)//
439   {
440     putValue(BCM_DoorLockStatusDrv,1);
441     putValue(BCM_DoorLockStatusRL,1);
442     putValue(BCM_DoorLockStatusPassenger,1);
443     putValue(BCM_DoorLockStatusRR,1);
444     setPictureBoxImage(BCMStatusPanel,BCMLockCtrl,"..\\Panels\\picture\\鎖閉.bmp");  
445   }
446   else //未鎖
447   {
448     putValue(BCM_DoorLockStatusDrv,0);
449     putValue(BCM_DoorLockStatusRL,0);
450     putValue(BCM_DoorLockStatusPassenger,0);
451     putValue(BCM_DoorLockStatusRR,0);
452     setPictureBoxImage(BCMStatusPanel,BCMLockCtrl,"..\\Panels\\picture\\鎖開.bmp");  
453   }
454 }
455 
456 //防盜報警狀態
457 on envVar BCM_ATWS_St
458 {
459   BCM_StateUpdate.BCM_ATWS_St = getValue(BCM_ATWS_St);
460 }
461 
462 //BCM信號提示后蓋箱/后車門開啟/關閉
463 on envVar BCM_TrunkAjarStatus
464 {
465   int temp;
466   
467   temp = getValue(BCM_TrunkAjarStatus);
468   BCM_StateUpdate.BCM_TrunkAjarStatus=temp;
469   if(temp==0) //關閉
470   {
471     setPictureBoxImage(BCMStatusPanel,BCMTrunkCtrl,"..\\Panels\\picture\\后備箱關閉.bmp");  
472   }
473   else{ //開啟
474     setPictureBoxImage(BCMStatusPanel,BCMTrunkCtrl,"..\\Panels\\picture\\后備箱未關閉.bmp");  
475   }
476 }
477 
478 //BCM信號提示引擎蓋開啟/關閉
479 on envVar BCM_HoodAjarStatus
480 {
481   int temp;
482   
483   temp = getValue(BCM_HoodAjarStatus);
484   BCM_StateUpdate.BCM_HoodAjarStatus=temp;
485   if(temp==0)
486   {
487     setPictureBoxImage(BCMStatusPanel, BCMHoodCtrl, "..\\Panels\\picture\\引擎蓋關閉.bmp");  
488   }
489   else if(temp==1)
490   {
491     setPictureBoxImage(BCMStatusPanel, BCMHoodCtrl, "..\\Panels\\picture\\引擎蓋未關閉.bmp");  
492   }
493   else
494   {
495     writeDbgLevel(1, "預留值,無定義");
496   } 
497 }
498 
499 on envVar  BCM_Val_Wdw_Opened
500 {
501   int temp; 
502   temp = getValue(BCM_Val_Wdw_Opened);
503   writeDbgLevel(1, "窗戶開度值=%d", temp);
504   BCM_RDoorWindowState.L_Pas_Val_Wdw_Opened=temp;
505   BCM_RDoorWindowState.L_RRD_Val_Wdw_Opened=temp;
506   BCM_LDoorWindowState.L_Drv_Val_Wdw_Opened=temp;
507   BCM_LDoorWindowState.L_RLD_Val_Wdw_Opened=temp;
508 }

6、PEPS仿真+T業務主邏輯實現

 T業務,處理遠程業務時,需根據產品的DBC中定義的報文去解讀信號,判斷業務邏輯。(示例代碼中處理業務邏輯的信號解析規則屬於隨便舉例,實際應用時根據DBC定義進行解讀)

  1 variables
  2 {
  3   char log[128];
  4   float tFactor = 100000.0;  //時間精度值
  5   //本消息由PEPS發出, 鑒權
  6   message 0x5 PEPS_TELChallengeCode;
  7   //本消息由GW發送,包括PEPS的電源模式及報警信號等
  8   message 0x6 GW_Info;
  9   //由TBOX反饋的應答碼
 10   message 0x7 TBOX_ResponseCode;
 11   
 12   msTimer GW_PEPS_Timer;
 13   //遠程控制的PEPS響應定時器
 14   msTimer GW_PEPS_TimerRespSuccess;
 15   //接收到報文的定時器
 16   msTimer GW_PEPS_TimerRespReceived;
 17   //PEPS啟動認證碼的定時器,只發三幀
 18   msTimer GW_PEPS_TimerSendChallengeCode;
 19   //遠程啟動定時器
 20   timer RespRmtEngineWorkingTimer;
 21   
 22   //PM 凈化定時器
 23   timer RmtAirCleanTimer;
 24   //加熱定時器
 25   timer RmtDrvHeatTimer;
 26   timer RmtPasHeatTimer;
 27   //空調允許時間
 28   timer RmtACOnTimer;
 29   //
 30   timer UpdateStatusTimer;
 31   
 32   //以下內容屬於PEPS加密算法的內容
 33   const dword SC32 = 0x00112233;
 34   const qword CC64 = 0x94254547464A5B7DLL; //后最LL
 35   //SK128 無法獲取; RN32 每次鑒權隨機生成;
 36   dword RN32;
 37   //設別遠程啟動的類型;在發生鑒權行為的時候會使用到
 38   //1=啟動;2=熄火;3=使能;4=禁止;0 預留
 39   int rmtReqTpye=0;
 40   //是否已認真過
 41   int IsAuthed = 0;
 42   
 43   
 44   //遠程控制請求
 45   byte rmtCtrlReq;
 46   // 遠程查詢PM2.5
 47   byte rmtReqPM;
 48   //遠程查詢
 49   byte rmtReqQ;
 50   //遠程啟動
 51   byte rmtStartReq;
 52   byte rmtStopReq;
 53   //遠程加熱座椅
 54   byte rmtHeatDrvSeat;
 55   byte rmtHeatPasSeat;
 56   
 57   //遠程開關空調
 58   byte rmtACReq; //byte(3) 溫度值+空調的啟停狀態
 59   byte acReq;
 60   byte acTemp;
 61   
 62   //遠程空氣凈化
 63   byte rmtAirCleanerReq;
 64   
 65   //發動機運行時長 分級
 66   byte rmtEngWorkTimeLvl = 0;
 67   int rmtEngWorkTime = 0;  //遠程發動機啟動時長, 單位s
 68   //延時
 69   byte rmtEngWorkDelayTimeLvl = 0;
 70   //遠程運行時間
 71   int rmtWorkTime = 0; //包含啟動空調,加熱,綠凈的時長
 72   int tempWorkTime; //臨時變量 存放rmtworkTime
 73   //遠程禁允發動機
 74   byte rmtForbidEngReq;
 75   byte rmtPermitEngReq;
 76   
 77   //記憶PEPS應答報文的發送次數
 78   int pepsRespCnt=0;
 79   //記憶PEPS認證報文的發送次數
 80   int pepsAuthCnt=0;
 81   //
 82   int pepsRecvCnt=0;
 83 }
 84 
 85 on start
 86 {
 87   InitLogging();
 88   InitPEPSValue();
 89   ActivePEPS();
 90   
 91 }
 92 
 93 //關閉CANoe時 停止記錄LOG
 94 on stopMeasurement
 95 {
 96   writeDestroy(mTrace);
 97 }
 98 
 99 //標記當前電源模式, 3=休眠開關, KL15電源通斷可使用VT板卡實現,否則手動操作實現為半自動化方案
100 on envVar PEPS_PowerMode
101 {
102   varPowerMode = getValue(PEPS_PowerMode);
103   //刷新報文值
104   GW_Info.PEPS_PowerMode = varPowerMode;
105   if(varPowerMode==3)
106   {
107     InactivePEPS();
108     lastPowerMode = varPowerMode;
109   }
110   else
111   {
112     if((varPowerMode==0)&&(lastPowerMode==3))
113     {
114       ;
115     }
116     else if((2==varPowerMode) || (1==varPowerMode) || (4==varPowerMode))
117     {
118       ActivePEPS(); //不是從3跳到0的模式,全激活
119     }
120     lastPowerMode = varPowerMode;
121   }
122 }
123 
124 
125 //標記PEPS應答的錯誤碼
126 on envVar PEPS_FailReason2TBOX
127 {
128   int temp;
129   temp = getValue(PEPS_FailReason2TBOX);
130   writeDbgLevel(1,"PEPS_FailReason2TBOX=0x%x",temp);  
131   GW_Info.PEPS_FailReason2TBOX = temp;
132 }
133 //標記PEPS應答的成功與否
134 on envVar PEPS_StatusResponse2TBOX
135 {
136   GW_Info.PEPS_StatusResponse2TBOX = getValue(PEPS_StatusResponse2TBOX);
137 }
138 //標記發動機的啟動模式
139 on envVar PEPS_RemoteControlSt
140 {
141   GW_Info.PEPS_RemoteControlSt=getValue(PEPS_RemoteControlSt);
142 }
143 
144 /***********************************************************
145 * description  : TBOX響應T業務的請求的報文
146 * parameter    : None
147 * creation date: 2018/10/17
148 * author       : xxx         
149 * revision date: 
150 * revision log : 
151 * modifier     : 
152 ***********************************************************/
153 on message TBOX_RmtCtrlInfo  //此消息由DBC中定義的遠程控制報文可獲取, 具體的報文解析,字節信號位等由DBC定義
154 {
155   rmtReqQ = (this.byte(1) & 0x03);
156   //遠程控制 + 查詢類
157   rmtCtrlReq = this.TBOX_DoorsLock;
158   rmtReqPM = this.TBOX_PM25;
159 
160   //遠程發動機延時等級
161   rmtEngWorkDelayTimeLvl = this.TBOX_EngineDelayTime;
162   rmtStartReq = this.TBOX_EngineStartReq;
163   rmtStopReq = this.TBOX_EngineStopReq;
164   rmtACReq = this.byte(3);
165   rmtAirCleanerReq = this.TBOX_AirCleanerReq;
166   rmtForbidEngReq = this.TBOX_EngineForbidReq;
167   rmtPermitEngReq = this.TBOX_EnginePermitReq;
168   //PEPSRespReceived(); //只要一接到接收指令 立即回復處理中
169   //遠程控制
170   RespRmtCtrlCmd(rmtCtrlReq);
171   if(0 != rmtEngWorkDelayTimeLvl) //如果不等於0, 有控制請求
172   {
173     PEPSRespReceived();
174     switch(rmtEngWorkDelayTimeLvl)
175     {
176       case 0x1://1min
177         rmtWorkTime = 60;
178         break;
179       case 0x2://3min
180         rmtWorkTime = 180;
181         break;
182       case 0x3://5min
183         rmtWorkTime = 300;
184         break;
185       case 0x4://10min
186         rmtWorkTime = 600;
187         break;
188       default:
189         break;
190     }
191     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令,發動機運行時間延長%d", timeNow()/tFactor, rmtWorkTime);
192     writeLineEx(mTrace, INFO, log);
193     PEPSRespSuccess();
194   }
195   //遠程查詢
196   if(1 == rmtReqPM)
197   {
198     PEPSRespReceived();
199     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令,PM2.5查詢", timeNow()/tFactor);
200     writeLineEx(mTrace, INFO, log);
201     putValue(AC_PM25Sts, 2);//complate
202     PEPSRespSuccess();
203   }
204   if(3 == rmtReqQ)
205   {
206     PEPSRespReceived();
207     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令,查詢天窗車窗", timeNow()/tFactor);
208     writeLineEx(mTrace, INFO, log);
209     PEPSRespSuccess();
210   }
211   //遠程啟動
212   if(1 == rmtStartReq)
213   {
214     PEPSRespReceived(); 
215     rmtReqTpye = 1;
216     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令,啟動發動機", timeNow()/tFactor);
217     writeLineEx(mTrace, INFO, log);
218     rmtEngWorkTimeLvl = this.TBOX_EngineStartTime;
219     switch(rmtEngWorkTimeLvl)
220     {
221       case 0x1://1min
222         rmtEngWorkTime = 60;
223         break;
224       case 0x2://3min
225         rmtEngWorkTime = 180;
226         break;
227       case 0x3://5min
228         rmtEngWorkTime = 300;
229         break;
230       case 0x4://10min
231         rmtEngWorkTime = 600;
232         break;
233       default:
234         break;
235     }
236     snprintf(log, elcount(log),"%f <- TBOX, 啟動發動機時長%d", timeNow()/tFactor, rmtEngWorkTime);
237     writeLineEx(mTrace, INFO, log);
238     PEPSReqAuth();
239   }
240   
241   //遠程停止
242   if(rmtStopReq==1)
243   {
244     rmtReqTpye = 2;
245     PEPSRespReceived();
246     
247     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令,停止發動機", timeNow()/tFactor);
248     writeLineEx(mTrace, INFO, log);
249     
250     PEPSRespSuccess();
251     RespRmtStop();
252   }
253    //遠程禁止發動機
254   if(1 == rmtForbidEngReq)
255   {
256     rmtReqTpye = 4;
257     PEPSRespReceived();
258     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令,禁止啟動", timeNow()/tFactor);
259     writeLineEx(mTrace, INFO, log);
260     
261     PEPSReqAuth();
262   }
263   //遠程使能發動機
264   if(1 == rmtPermitEngReq) 
265   {
266     rmtReqTpye = 3;
267     PEPSRespReceived();
268     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令,允許啟動", timeNow()/tFactor);
269     writeLineEx(mTrace, INFO, log);
270     
271     PEPSReqAuth();
272   }
273   //PM 凈化  
274   if(2==rmtAirCleanerReq) //2=ON , 1=OFF, 0=No Req
275   {
276     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令,空氣凈化開啟", timeNow()/tFactor);
277     writeLineEx(mTrace, INFO, log);
278     
279     PEPSRespReceived();
280     PEPSRespSuccess();
281     RespRmtOpenAirClean();  //區分
282   }
283   else if(1==rmtAirCleanerReq)
284   {
285     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令,空氣凈化關閉", timeNow()/tFactor);
286     writeLineEx(mTrace, INFO, log);
287     
288     PEPSRespReceived();
289     PEPSRespSuccess();
290     RespRmtCloseAirClean();
291   }
292   
293   //遠程空調
294   if(0x1F != rmtACReq) //2=ON , 1=OFF, 0=No Req
295   {
296     PEPSRespReceived();
297     acReq = ((rmtACReq >> 6) & 0x3);
298     acTemp = (rmtACReq & 0x1F);
299     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令, 操作空調req=%d, temp=%d", timeNow()/tFactor,acReq,acTemp);
300     writeLineEx(mTrace, INFO, log);
301   
302     PEPSRespSuccess();
303     if(2==acReq)
304     {
305       RespRmtOpenAC();  //open
306     }
307     else if(1==acReq)
308     {
309       RespRmtCloseAC();  //close
310     }
311   }
312   if(this.byte(4)!=0xE7)
313   {
314     rmtHeatDrvSeat = this.TBOX_DrvHeatReq;
315     rmtHeatPasSeat = this.TBOX_PassHeatReq;
316     
317     snprintf(log, elcount(log),"%f <- TBOX, 接收到指令, 座椅加熱Drv=%d,Pas=%d", timeNow()/tFactor,rmtHeatDrvSeat, rmtHeatPasSeat);
318     writeLineEx(mTrace, INFO, log);
319     
320     PEPSRespReceived();
321     PEPSRespSuccess();
322     //主駕
323     switch(rmtHeatDrvSeat)
324     {
325       case 0x0:
326         RespRmtCloseDrvHeat();
327         break;
328       case 0x1:
329         RespRmtOpenDrvHeat(rmtHeatDrvSeat);
330         break;
331       case 0x2:
332         RespRmtOpenDrvHeat(rmtHeatDrvSeat);
333         break;
334       default:
335         break;
336     }
337     
338     //副駕
339     switch(rmtHeatPasSeat)
340     {
341       case 0x0:
342         RespRmtClosePasHeat();
343         break;
344       case 0x1:
345         RespRmtOpenPasHeat(rmtHeatPasSeat);
346         break;
347       case 0x2:
348         RespRmtOpenPasHeat(rmtHeatPasSeat);
349         break;
350       default:
351         break;
352     }
353   }
354 }
355 
356 //TBOX響應PEPS挑戰碼,發出的認證碼
357 on message TBOX_ResponseCode
358 {
359   snprintf(log, elcount(log),"%f <- TBOX, response peps auth request", timeNow()/tFactor);
360   writeLineEx(mTrace, INFO, log);
361   //PEPS回復控制成功通過
362   PEPSRespSuccess();
363   if(rmtReqTpye == 1){
364     RespRmtStart();
365     //設置發動機的運行模式與運行時長,啟動定時器
366     snprintf(log, elcount(log),"%f <- TBOX, engine work time=%d", timeNow()/tFactor, rmtEngWorkTime);
367     writeLineEx(mTrace, INFO, log);
368     setTimer(RespRmtEngineWorkingTimer, rmtEngWorkTime);
369   }
370   else if(rmtReqTpye == 2) //實測關閉發動機不需要鑒權
371   {
372     RespRmtStop();
373   }
374   else if(3 == rmtReqTpye) //使能
375   {
376     RespRmtPermit();
377   }
378   else if(4 == rmtReqTpye) //禁止
379   {
380     RespRmtForbidden();
381   }
382 }
383 
384 //遠程啟動發動機運行時長定時器
385 on timer RespRmtEngineWorkingTimer
386 {
387   //發動機置位遠程啟動模式
388   putValue(PEPS_RemoteControlSt,0);
389   //電源置為ON
390   putValue(PEPS_PowerMode, 0);
391   //發動機置位running
392   putValue(EMS_EngStatus,0);
393 }
394 
395 //空調開啟一段時間后 更新溫度傳感器信號
396 on timer UpdateStatusTimer
397 {
398   ; //未實現
399 }
400 
401 //空調運行時長定時器
402 on timer RmtACOnTimer
403 {
404   putValue(AC_OnState, 0);
405 }
406 
407 //空氣凈化運行時長定時器
408 on timer RmtAirCleanTimer
409 {
410   putValue(AC_AirCleanState, 0);
411   putValue(AC_OnState,0); 
412 }
413 
414 //主駕加熱運行時長定時器
415 on timer RmtDrvHeatTimer
416 {
417   putValue(HVSM_DrvHeatSts, 0);
418 }
419 
420 //副駕加熱運行時長定時器
421 on timer RmtPasHeatTimer
422 {
423   putValue(HVSM_PassHeatSts,0);
424 }
425 
426 //響應遠程加熱主駕座椅
427 void RespRmtOpenDrvHeat(int level)
428 {
429   putValue(HVSM_DrvHeatSts,level);
430   if((1==IsEngineWorking) && (rmtWorkTime!=0))
431   {
432     snprintf(log, elcount(log),"%f -> HVSM, 先啟動發動機,再開啟座椅加熱,延長發動機運行時長%d", timeNow()/tFactor, rmtWorkTime);
433     writeLineEx(mTrace, INFO, log);
434     tempWorkTime = rmtWorkTime;
435     cancelTimer(RespRmtEngineWorkingTimer); //取消原定時器
436     setTimer(RespRmtEngineWorkingTimer, tempWorkTime); //重置發動機定時器
437     setTimer(RmtDrvHeatTimer, tempWorkTime);
438     rmtWorkTime=0; 
439   }
440   else
441   {
442     snprintf(log, elcount(log),"%f -> HVSM, 直接座椅加熱,發動機運行時長%d", timeNow()/tFactor, rmtEngWorkTime);
443     writeLineEx(mTrace, INFO, log);
444     setTimer(RmtDrvHeatTimer, rmtEngWorkTime);
445   }
446 }
447 
448 //響應遠程加熱副駕座椅
449 void RespRmtOpenPasHeat(int level)
450 {
451   putValue(HVSM_PassHeatSts,level);
452   if((1==IsEngineWorking) && (rmtWorkTime!=0))
453   {
454     snprintf(log, elcount(log),"%f -> HVSM, 先啟動發動機,再加熱座椅,延長發動機運行時長%d", timeNow()/tFactor, rmtWorkTime);
455     writeLineEx(mTrace, INFO, log);
456     tempWorkTime = rmtWorkTime;
457     cancelTimer(RespRmtEngineWorkingTimer); //取消原定時器
458     setTimer(RespRmtEngineWorkingTimer, tempWorkTime); //重置發動機定時器
459     setTimer(RmtPasHeatTimer, tempWorkTime); 
460     rmtWorkTime=0; //用完后歸零
461   }
462   else
463   {
464     snprintf(log, elcount(log),"%f -> HVSM, 直接加熱座椅,發動機運行時長%d", timeNow()/tFactor, rmtEngWorkTime);
465     writeLineEx(mTrace, INFO, log);
466     setTimer(RmtPasHeatTimer, rmtEngWorkTime); 
467   }
468 }
469 
470 //響應關閉座椅加熱
471 void RespRmtCloseDrvHeat()
472 {
473   cancelTimer(RmtDrvHeatTimer);
474   putValue(HVSM_DrvHeatSts, 0);
475 }
476 
477 //響應關閉座椅加熱
478 void RespRmtClosePasHeat()
479 {
480   cancelTimer(RmtPasHeatTimer);
481   putValue(HVSM_PassHeatSts, 0);
482 }
483 
484 //響應開啟空調
485 void RespRmtOpenAC()
486 {
487   putValue(AC_OnState, 1);
488   if((1==IsEngineWorking) && (rmtWorkTime!=0))
489   {
490     //先啟動發動機 后啟動空調
491     snprintf(log, elcount(log),"%f -> AC, 先啟動發動機,再開啟空調,延長發動機運行時長%d", timeNow()/tFactor, rmtWorkTime);
492     writeLineEx(mTrace, INFO, log);
493     tempWorkTime = rmtWorkTime;
494     cancelTimer(RespRmtEngineWorkingTimer); //取消原定時器
495     setTimer(RespRmtEngineWorkingTimer, tempWorkTime); //重置發動機定時器
496     setTimer(RmtACOnTimer, tempWorkTime);
497     rmtWorkTime=0; //用完后歸零
498   }
499   else
500   {
501     //直接啟動空調
502     snprintf(log, elcount(log),"%f -> AC, 直接啟動空調,發動機運行時長%d", timeNow()/tFactor, rmtEngWorkTime);
503     writeLineEx(mTrace, INFO, log);
504     setTimer(RmtACOnTimer, rmtEngWorkTime);
505   }
506 }
507 
508 //響應關閉空調
509 void RespRmtCloseAC()
510 {
511   cancelTimer(RmtACOnTimer);
512   putValue(AC_OnState, 0);
513 }
514 
515 //響應關閉空氣凈化
516 void RespRmtCloseAirClean()
517 {
518   cancelTimer(RmtAirCleanTimer);
519   putValue(AC_AirCleanState, 0);
520   putValue(AC_OnState, 0);
521   
522 }
523 
524 //響應開啟PM凈化
525 void RespRmtOpenAirClean()
526 {
527   putValue(AC_OnState, 1);
528   putValue(AC_AirCleanState, 1);
529   if((1==IsEngineWorking)  && (rmtWorkTime!=0))
530   {
531     //先啟動發動機 后啟動PM凈化
532     snprintf(log, elcount(log),"%f -> AC, 先啟動發動機 再開空氣凈化,延長發動機運行時間%d", timeNow()/tFactor, rmtWorkTime);
533     writeLineEx(mTrace, INFO, log);
534     tempWorkTime = rmtWorkTime;
535     cancelTimer(RespRmtEngineWorkingTimer); //取消原定時器
536     setTimer(RespRmtEngineWorkingTimer, rmtWorkTime); //重置發動機定時器
537     setTimer(RmtAirCleanTimer, rmtWorkTime); //置位空氣凈化定時器
538     rmtWorkTime = 0;
539   }
540   else
541   {
542     //直接啟動PM凈化
543     snprintf(log, elcount(log),"%f -> AC, 直接開啟空氣凈化,發動機運行時間%d", timeNow()/tFactor, rmtEngWorkTime);
544     writeLineEx(mTrace, INFO, log);
545     setTimer(RmtAirCleanTimer, rmtEngWorkTime); //置位空氣凈化定時器
546   }
547   
548 }
549 
550 //響應遠程控制指令
551 void RespRmtCtrlCmd(int cmd)
552 {
553   //判斷遠程控制類邏輯
554   switch(cmd){
555     case 0x0://No command
556       break;
557     case 0x1://All door lock
558       snprintf(log, elcount(log),"%f <- TBOX, 接收上鎖指令", timeNow()/tFactor);
559       writeLineEx(mTrace, INFO, log);
560       SetDoorsLocked();
561       PEPSRespSuccess();
562       break;
563     case 0x2://Blink lamp  閃燈
564       break;  //APP未實現單獨指令
565     case 0x3://All door unlock
566       snprintf(log, elcount(log),"%f <- TBOX, 接收解鎖指令", timeNow()/tFactor);
567       writeLineEx(mTrace, INFO, log);
568       SetDoorsUnlocked();
569       PEPSRespSuccess();
570       break;
571     case 0x4://Whistle    鳴笛
572       break;  //APP未實現單獨指令    
573     case 0x5://Global closing-window up
574       snprintf(log, elcount(log),"%f <- TBOX, 接收關窗指令", timeNow()/tFactor);
575       writeLineEx(mTrace, INFO, log);
576       SetWndsClosed();
577       PEPSRespSuccess();
578       break;
579     case 0x6://Closing window
580       break; //APP未實現單獨指令
581     case 0x7: //Closing sunroof
582       break;    //APP未實現單獨指令
583     case 0x8://Global opening-window down
584       snprintf(log, elcount(log),"%f <- TBOX, 接收開窗指令", timeNow()/tFactor);
585       writeLineEx(mTrace, INFO, log);
586       SetWndsOpened();
587       PEPSRespSuccess();
588       break;      
589     case 0x9://Vehicle search
590       snprintf(log, elcount(log),"%f <- TBOX, 接收尋車指令", timeNow()/tFactor);
591       writeLineEx(mTrace, INFO, log);
592       PEPSRespSuccess();
593       break;      
594     case 0xA://Trunk unlock
595       snprintf(log, elcount(log),"%f <- TBOX, 接收開啟后備箱指令", timeNow()/tFactor);
596       writeLineEx(mTrace, INFO, log);
597       SetTrunkOpened();
598       PEPSRespSuccess();
599       break;
600     case 0xB://Window ventilate
601       snprintf(log, elcount(log),"%f <- TBOX, 接收透氣指令", timeNow()/tFactor);
602       writeLineEx(mTrace, INFO, log);
603       SetWndsVentilate();
604       PEPSRespSuccess();
605       break;
606     case 0xC://Opening sunroof
607       break;   //APP未實現單獨指令
608     default://others are reserved
609       break;   //預留指令
610   }
611 }
612 
613 //遠程禁止啟動發動機
614 void RespRmtForbidden()
615 {
616   GW_Info.PEPS_EngineforbidSt=1;
617 }
618 
619 //遠程允許啟動發動機
620 void RespRmtPermit()
621 {
622   GW_Info.PEPS_EngineforbidSt=0;
623 }
624 
625 
626 //遠程停止發動機
627 void RespRmtStop()
628 {
629   cancelTimer(RespRmtEngineWorkingTimer); 
630 
631   putValue(PEPS_RemoteControlSt,0); 
632   putValue(EMS_EngStatus, 0);
633   putValue(PEPS_PowerMode, 0);
634   //停止發動機后  所有控制器開的狀態都歸零
635   putValue(AC_AirCleanState, 0);
636   putValue(AC_OnState,0); 
637   putValue(HVSM_DrvHeatSts, 0);
638   putValue(HVSM_PassHeatSts, 0);
639 }
640 
641 //響應遠程啟動
642 void RespRmtStart()
643 {
644   IsAuthed =0;
645   putValue(EMS_EngStatus, 0);
646 
647   //發動機置位遠程啟動模式
648   putValue(PEPS_RemoteControlSt,1); 
649   //發動機置位running
650   putValue(EMS_EngStatus, 3);
651   //電源置為ON
652   putValue(PEPS_PowerMode, 2);
653   IsEngineWorking = 1; //標記發動機已經工作中, Delay時間不會發出
654   snprintf(log, elcount(log),"%f <- EMS PEPS, Engine running, Power on", timeNow()/tFactor);
655   writeLineEx(mTrace, INFO, log);
656   //TestWaitForTimeout(3000);//延時函數在純CAPL程序中不能使用
657 }
658 
659 //初始化電源模式
660 void InitPEPSValue()
661 {
662   putValue(PEPS_PowerMode, 0);
663   putValue(PEPS_StatusResponse2TBOX,0);
664   putValue(PEPS_FailReason2TBOX,0);
665   putValue(PEPS_RemoteControlSt,0);
666   GW_Info.PEPS_PowerModeValidity = 2;
667   GW_Info.PEPS_EngineforbidSt=0;  //發動機允許遠程使能狀態
668 }
669 
670 void ActivePEPS()
671 {
672   setTImer(GW_PEPS_Timer, varCycTime100);
673 }
674 
675 void InactivePEPS()
676 {
677   cancelTimer(GW_PEPS_Timer);
678 }
679 
680 //每次鑒權生成隨機認證碼
681 void GenerateRN32()
682 {
683   RN32 = random(0xFFFFFFFF);
684 }
685 
686 //窗戶透氣響應
687 void SetWndsVentilate()
688 {
689   //窗戶開
690   putValue(BCM_Drv_Wdw_PositionSts,0);
691   putValue(BCM_RLD_Wdw_PositionSts,0);
692   putValue(BCM_Pas_Wdw_PositionSts,0);
693   putValue(BCM_RRD_Wdw_PositionSts,0);
694   putValue(BCM_Val_Wdw_Opened, 20); //開度值20%
695 }
696 
697 //響應遠程關閉車窗指令
698 void SetWndsClosed()
699 {
700 //  putValue(CloseWnds,0);
701   putValue(BCM_Drv_Wdw_PositionSts,2);
702   putValue(BCM_RLD_Wdw_PositionSts,2);
703   putValue(BCM_Pas_Wdw_PositionSts,2);
704   putValue(BCM_RRD_Wdw_PositionSts,2);
705   putValue(BCM_Val_Wdw_Opened, 0);
706 }
707 
708 //響應遠程上鎖指令
709 void SetDoorsLocked()
710 {
711   putValue(LockDoors,1);
712 }
713 
714 //響應遠程解鎖指令
715 void SetDoorsUnlocked()
716 {
717   putValue(LockDoors,0);
718 }
719 
720 //響應遠程開窗指令
721 void SetWndsOpened()
722 {
723 //  putValue(CloseWnds,1);//開啟
724   putValue(BCM_Drv_Wdw_PositionSts,1);
725   putValue(BCM_RLD_Wdw_PositionSts,1);
726   putValue(BCM_Pas_Wdw_PositionSts,1);
727   putValue(BCM_RRD_Wdw_PositionSts,1);
728   putValue(BCM_Val_Wdw_Opened, 100);
729 }
730 
731 //響應遠程打開后備箱
732 void SetTrunkOpened()
733 {
734   putValue(BCM_TrunkAjarStatus, 1); //開啟后備箱
735 }
736 
737 //PEPS回復控制成功報文
738 void PEPSRespSuccess()
739 {
740   setTimer(GW_PEPS_TimerRespSuccess, varCycTime100); 
741 }
742 
743 void PEPSRespReceived()
744 {
745 //  setTimer(GW_PEPS_TimerRespReceived, varCycTime20); 
746 }
747 
748 //PEPS發起認證請求
749 void PEPSReqAuth()
750 {
751   //算法不實現!
752   //若實際環境中接入了PEPS設備,則需實車抓取報文使用固定一組報文訪問
753   //安全隱患,PEPS入侵(可能設計:每次隨機的挑戰碼,攜帶當前時間,設置計數器和校驗位驗證有效性,限定時間內的重復報文無效)
754   if(rmtReqTpye ==1)
755   {
756     GenerateChallengeCode4Start();
757   }
758   else if(rmtReqTpye ==2)
759   {
760     GenerateChallengeCode4Stop();
761   }
762   
763   setTimer(GW_PEPS_TimerSendChallengeCode, varCycTime20);
764   IsAuthed = 1; //已經發起過鑒權
765 }
766 
767 void GenerateChallengeCode4Stop()
768 {
769   //關閉發動機鑒權
770 }
771 //生成PEPS挑戰碼,啟動發動機鑒權
772 void GenerateChallengeCode4Start()
773 {
774   if(pepsAuthCnt==0)
775   {
776     PEPS_TELChallengeCode.PEPS_TELchallengeCode_Byte0 = random(0xff);
777     PEPS_TELChallengeCode.PEPS_TELchallengeCode_Byte1 = random(0xff);
778     PEPS_TELChallengeCode.PEPS_TELchallengeCode_Byte2 = random(0xff);
779     PEPS_TELChallengeCode.PEPS_TELchallengeCode_Byte3 = random(0xff);
780     PEPS_TELChallengeCode.PEPS_TELchallengeCode_Byte4 = random(0xff);
781     PEPS_TELChallengeCode.PEPS_TELchallengeCode_Byte5 = random(0xff);
782     PEPS_TELChallengeCode.PEPS_TELchallengeCode_Byte6 = random(0xff);
783     PEPS_TELChallengeCode.PEPS_TELchallengeCode_Byte7 = random(0xff);
784   }
798 }
799 
800 //TBOX預約充電請求(電動車)/
801 on message TBOX_ReservationChgSet
802 {
803   //線束不支持雙路CAN 暫且無法實現
804 }
805 
806 //TBOX被喚醒的原因指示
807 on message NWM_TBOX_Information
808 {
809   int reasons;
810   reasons = this.TBOX_Wakeup_reasons;
811   switch(reasons){
812     case 0x2:
813       writeLineEx(mTrace, 1, "NM PDU Received");
814       break;
815     case 0x5:
816       writeLineEx(mTrace, 1, "KL15 On");
817       break;
818     case 0x06:
819       writeLineEx(mTrace, 1, "Telematics service");
820       break;
821     default:
822       break;
823   }
824 }
825 
826 //PEPS周期報文發送
827 on timer GW_PEPS_Timer
828 {
829   output(GW_Info);
830   setTimer(GW_PEPS_Timer, varCycTime100);
831 }
832 
833 //響應遠程請求,PEPS反饋Received
834 on timer GW_PEPS_TimerRespReceived
835 {
836   pepsRecvCnt+=1;
837   if(pepsRecvCnt<2)
838   {
839     snprintf(log, elcount(log),"%f -> PEPS, response 'in progress'", timeNow()/tFactor);
840     writeLineEx(mTrace, INFO, log);
841     putValue(PEPS_FailReason2TBOX,  0);
842     putValue(PEPS_StatusResponse2TBOX, 1);
843     setTimer(GW_PEPS_TimerRespReceived, varCycTime20); //200ms一幀
844   }
845   else
846   {
847     cancelTimer(GW_PEPS_TimerRespReceived);
848     putValue(PEPS_FailReason2TBOX, 0);
849     putValue(PEPS_StatusResponse2TBOX, 0);
850     pepsRecvCnt = 0;
851   }  
852 }
853 
854 //響應遠程請求,PEPS反饋Success
855 on timer GW_PEPS_TimerRespSuccess
856 {
857   pepsRespCnt+=1;
858   if(pepsRespCnt<2)
859   {
860     snprintf(log, elcount(log),"%f -> PEPS, response 'success'", timeNow()/tFactor);
861     writeLineEx(mTrace, INFO, log);
862     putValue(PEPS_FailReason2TBOX,  0);
863     putValue(PEPS_StatusResponse2TBOX, 2);
864     setTimer(GW_PEPS_TimerRespSuccess, varCycTime100);
865   }
866   else
867   {
868     cancelTimer(GW_PEPS_TimerRespSuccess);
869     putValue(PEPS_FailReason2TBOX, 0);
870     putValue(PEPS_StatusResponse2TBOX, 0);
871     pepsRespCnt = 0;
872   }
873 }
874 
875 //響應遠程啟動請求, PEPS發出挑戰碼
876 on timer GW_PEPS_TimerSendChallengeCode
877 {
878   
879   pepsAuthCnt+=1;
880   if(pepsAuthCnt<2)
881   {
882     snprintf(log, elcount(log),"%f -> PEPS, send challenge code", timeNow()/tFactor);
883     writeLineEx(mTrace, INFO, log);
884     
885     output(PEPS_TELChallengeCode);
886     setTimer(GW_PEPS_TimerSendChallengeCode, varCycTime20);//遞歸 發三幀,20ms一幀
887   }
888   else
889   {
890     cancelTimer(GW_PEPS_TimerSendChallengeCode);
891     pepsAuthCnt = 0;
892   }
893 }

 

7、效果展示

整個車輛網功能中涉及到整車中其它ECU相關的業務,也可參照以上實現邏輯去進行仿真。此處不一一舉例。

我在台架中接入真實儀表驗證我的仿真邏輯(節點支持熱增減,沒有ECU則使用仿真節點,有真實ECU則屏蔽)。

啟動仿真程序后,操作控制器,驗證車身仿真器的實現,可以檢驗出仿真代碼實現的正確性

--------------------------以上T業務自動化仿真測試台架全內容完結-----------------------------


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM