zhuanzai:https://www.cnblogs.com/yao-zhang/p/10329922.html
为满足项目过程中不同阶段绝大部分测试需求,更方便快捷构造测试场景,支持异常场景测试。更早介入,不依赖周边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业务自动化仿真测试台架全内容完结
车联网仿真测试台架搭建
549

被折叠的 条评论
为什么被折叠?



