基于CANoe实现的TBOX自动化测试(含代码)

直奔主题,搭个台架,编程自动化测试

1. 关联的ECU梳理与设计分析

罗列所有产生系统交互的控制器。设计思路如下4步,下文代码中会逐步说明。

  • 每个ECU的逻辑都是随CANoe启动,激活CAN通信;

  • 根据PEPS电源信号状态决定该ECU的活跃状态;

  • ECU 根据具体业务处理总线上的请求;

  • 设计仿真器的ECU则根据信号变化情况,更新仿真器的状态

2. 建立车内网络仿真模型

img

3. CAPL编程实现

3.1 环境变量定义

为实现控制面板输入输出与信号同步,实现仿真器的状态更新,先定义与信号成映射关系的环境变量。环境变量的定义主要根据各ECU的相关信号与业务的关联度决定。基本上与TSP业务挂钩的信号都应该设置相应的环境变量,监控信号变化,实时更新仿真器的状态。

3.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);
}
View Code
3.3 业务逻辑封装举例
  • ESC封装车速信号,处理行车过程中自动落锁的逻辑

此处详尽展现了章节1中的4步骤设计思路,后续举例的ECU实现代码只展现具体的业务处理,不再全部体现4点内容。

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);
}
View Code
3.4 系统时钟同步

若你的车联网系统的标准时钟来自其它ECU,则以该ECU的时间为参考。这涉及判断TSP业务的实时性与有效性逻辑。(注意:我所用的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;
}
View Code
3.5 车辆状态模拟

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激活,去激活,初始值,报文发送的函数
View Code

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 }
View Code
3.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 }
View Code

4. 总结

整个车辆网功能中涉及到整车中其它ECU相关的业务,也可参照以上实现逻辑去进行仿真。此处不一一举例。

我在台架中接入真实仪表验证我的仿真逻辑(节点支持热增减,没有ECU则使用仿真节点,有真实ECU则屏蔽)。

启动仿真程序后,操作控制器,验证车身仿真器的实现,可以检验出仿真代码实现的正确性

 

posted @ 2019-01-28 13:45  水一年  阅读(8231)  评论(0编辑  收藏  举报