汽车电子技术论坛
登录
直播中
王锐
8年用户
7经验值
擅长:嵌入式技术 处理器/DSP 控制/MCU
私信
关注
[资料]
基于.net2.0的汽车电子***协议的封装
汽车电子
CCP
从事汽车
电子
的人应该都知道CCP协议,这是我半年从事汽车电子测试软件开发所熟悉知道的协议。
CCP(CAN Calibra
ti
on Protocol)是一种基于CAN总线的ECU(Electronic Control Unit)标定协议,汽车上的助力转向系统EPS就用到CCP协议通过CAN进行传输。
CCP协议里面有很多指令,每一条指令都有对应的捂手信号,通过捂手来保证数据传输的正确性。我们经常用到的CCP指令主要有如下指令:
1、连接指令,主要包括Polling模式和DAQ模式以及正常模式(可能这边表述不是很专业)的连接指令。
正常模式连接指令:主要发送三条指令进行连接:第一条:SendMessageD(newbyte[] { 0x01, Ctr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, id, 8, 10)、
第二条:SendMessageD(new byte[] { 0x14, Ctr,0x00, 0x00, 0x00, 0x00, 0x00, 0x36 }, id, 8, 10)、第三条:SendMessageD(newbyte[] { 0x14, Ctr, 0x01, 0x00, 0x00, 0x00, 0x00, 0x36 }, id, 8, 10)。这三条指令都有各自对应的捂手信号,进行连接的时候依次发送。
Polling模式指令:主要发送五条指令:依次是SendMessageD(newbyte[] { 0x01, Ctr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, id, 8, 10)、SendMessageD(new byte[] { 0x12, Ctr, 0x01, 0x00, 0x00,0x00, 0x00, 0x00 }, id, 8, 10)、SendMessageD(newbyte[] { 0x13, Ctr, pSeed[0], pSeed[1], pSeed[2], pSeed[3], 0x00, 0x00 }, id,8, 10)、SendMessageD(new byte[] { 0x14, Ctr, 0x00, 0x00, 0x00,0x00, 0x01, 0x10 }, id, 8, 10)、SendMessageD(newbyte[] { 0x14, Ctr, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01 }, id, 8, 10),发送的时候依次发送,没发送一条都会有对应的握手信号。发送第三条指令时,涉及到一个地址解密算法,这个算法是通过调用C++封装的一个非托管dll文件来进行解密的,发送第三条数据时,要先进行解密,然后将解密好的4个字节的数组放在第三条指令的地址位进行发送。
DAQ模式连接:主要发送五条指令:依次是SendMessageD(newbyte[] { 0x01, Ctr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, id, 8, 10)、SendMessageD(new byte[] { 0x12, Ctr, 0x01, 0x00, 0x00,0x00, 0x00, 0x00 }, id, 8, 10)、SendMessageD(newbyte[] { 0x13, Ctr, pSeed[0], pSeed[1], pSeed[2], pSeed[3], 0x00, 0x00 }, id,8, 10)、SendMessageD(new byte[] { 0x14, Ctr, 0x00, 0x00, 0x00,0x00, 0x01, 0x10 }, id, 8, 10)、SendMessageD(newbyte[] { 0x14, Ctr, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01 }, id, 8, 10),发送的指令和Polling模式指令一样,仅仅可能是解密的算法可能会不同,这个每一家都可以自己进行设计,同样调用解密的dll文件也是一样同Polling模式指令。
2、写入数据指令:写入数据主要有两条指令:SendMessageD(new byte[] { 0x02, Ctr,0x00, 0x00, (byte)(0xFF & (address >> 24)), (byte)(0xFF &(address >> 16)), (byte)(0xFF & (address >> 8)), (byte)(0xFF& address) }, id, 8, 10),这一条指令主要是发送要写入数据的变量的地址,指令最后四个字节的地址主要根据变量的大小端以及变量的大小进行计算;SendMessageD(newbyte[] { 0x03, Ctr, AnalysisVarS.Size, bytedata[0], bytedata[1], bytedata[2],bytedata[3], bytedata[4] }, id, 8, 10),这条指令主要发送要写入的数据,数据要根据变量的大小、类型、以及变量的算法进行处理过后才能够进行发送。
3、读取数据指令:读取数据只有一条指令:SendMessageD(new byte[] { 0x0F, Ctr,AnalysisVarS.Size, 0x00, (byte)(0xFF & (address >> 24)), (byte)(0xFF& (address >> 16)), (byte)(0xFF & (address >> 8)),(byte)(0xFF & address) }, id, 8, 10),只需要发送要读取的变量的地址就可以,返回的握手信号中会有要读取的变量的值。
下面是我基于.net2.0封装的CCP的一些常用的指令,已经在我们公司的EPS测试软件上验证过,目前没有出现问题。下面是源码:
public static classCCP
{
#region 构造函数
static CCP()
{
_ctr = 0;
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.NullCCPOrderState;
AutoResetEvent = newAutoResetEvent(true);
PollingPath = null;
DAQPath = null;
}
#endregion
#region 私有变量
///
/// 用于存储地址
///
private static int address = 0;//地址大小
///
/// 用于CCP
通信
延迟计数
///
private static int count = 0;
///
/// 用于存储解密数据
///
private static byte[] pSeed = newbyte[4];
///
/// 用于存储上传或是下传的数据
///
private static byte[] bytedata = newbyte[5];
///
/// 存储上传数据临时数组
///
private static byte[] TempBuf;
///
/// 存储A2L文件中解析好的字节地址、变量大小、数组大小、地址类型
///
private static AnalysisVarStructAnalysisVarS = new AnalysisVarStruct();
#endregion
#region AutoResetEvent
///
/// 线程同步,并将其状态设置为有信号(每一次只允许一个线程工作,每次开线程前都要Set一下。)
///
public static AutoResetEventAutoResetEvent;
#endregion
#region 定义命令序号Ctr属性
///
/// 命令序号_ctr字段
///
private static byte _ctr;
///
/// 命令序号Ctr属性
///
public static byte Ctr
{
get
{
if (_ctr >= 255) _ctr = 0;
return _ctr;
}
set
{
_ctr = value;
if (_ctr >= 255) _ctr = 0;
}
}
#endregion
#region SeedKey状态标志
///
/// 打开Polling功能的DLL路径
///
public static string PollingPath;
///
/// 打开DAQ功能的DLL路径
///
public static string DAQPath;
#endregion
#region CCP枚举状态
#region CPP指令枚举状态
///
/// CPP指令枚举状态
///
public enum CPPOrderStateEnum
{
#region MCU和PC连接功能枚举状态
Send0x01CCPOrderState = 1,
Send0x01CCPOrderStateSuccess = 2,
Send0x12CCPOrderPollingState = 3,
Send0x12CCPOrderPollingStateSuccess= 4,
Send0x13CCPOrderPollingState = 5,
Send0x13CCPOrderPollingStateSuccess= 6,
Send0x12CCPOrderDAQState = 7,
Send0x12CCPOrderDAQStateSuccess =8,
Send0x13CPPOrderDAQState = 9,
Send0x13CPPOrderDAQStateSuccess =10,
Send0x14CCPOrderOneState = 11,
Send0x14CCPOrderOneStateSuccess =12,
Send0x14CCPOrderTwoState = 13,
Send0x14CCPOrderTwoStateSuccess =14,
MCULinkPCStateSuccess = 15,
#endregion
#region Polling模式枚举状态(采集量上传数据枚举状态;标定量下发数据枚举状态)
Send0x0FCCPOrderState = 23,
Send0x0FCCPOrderStateSuccess = 24,
CCPUpDataStateSuccess = 25,
Send0x02CCPOrderState = 26,
Send0x02CCPOrderStateSuccess = 27,
Send0x03CCPOrderState = 28,
Send0x03CCPOrderStateSuccess = 29,
CCPDownDataStateSuccess = 30,
#endregion
#region 没有发送任何CPP指令(空状态)
NullCCPOrderState = 100,
#endregion
}
#endregion
#region MCU和PC连接CCP指令枚举状态
///
/// MCU和PC连接CCP指令枚举状态
///
private static CPPOrderStateEnumMCUAndPCLinkCPPStateE;
#endregion
#region 下传数据CCP指令枚举状态
///
/// 下传数据CCP指令枚举状态
///
private static CPPOrderStateEnumDownDataCCPStateE;
#endregion
#region 上传数据CCP指令枚举状态
///
/// 上传数据CCP指令枚举状态
///
private static CPPOrderStateEnumUpDataCCPStateE;
#endregion
#endregion
#region 定义存储A2L文件中的变量、算法集合的变量
///
/// 存储采集变量信息的结构体
///
public struct VariableInformationStruct
{
///
/// 采集变量的名字
///
public string Name;//采集变量的名字
///
/// 采集变量的地址
///
public string Address;//采集变量的地址
///
/// 采集变量的地址类型
///
public string Address_Type;//采集变量的地址类型
///
/// 采集变量的数据类型
///
public string Type;//采集变量的数据类型
///
/// 采集变量的数据类型的大小
///
public string Size;//采集变量的数据类型的大小
///
/// 采集变量的算法
///
public string Conversion;//采集变量的算法
///
/// 数组变量的数组大小(如果是数组类型的变量)
///
public string Array_Size;//数组变量的数组大小(如果是数组类型的变量)
///
/// 变量类型的名字
///
public string Variable_Type_Name;//变量类型的名字
}
#endregion
#region 将A2L文件中变量的地址、变量大小、数组大小、地址类型字符串解析成字节存储在AnalysisVarStruct结构体中
///
/// 存储A2L文件中解析好的字节地址、变量大小、数组大小、地址类型
///
public struct AnalysisVarStruct
{
///
/// 变量地址
///
public byte[] Address;
///
/// 变量大小
///
public byte Size;
///
/// 数组大小
///
public byte Array_Size;
///
/// 算法
///
public double Conversion;
///
/// 地址类型,即大小端
///
public string Address_Type;
}
///
/// 将A2L文件中变量的地址、变量大小、数组大小、地址类型字符串解析成字节存储在AnalysisVarStruct结构体中
///
///
输入的结构体变量信息,里面包括地址、变量大小、数组大小、地址类型
///
将字符串地址、变量大小、数组大小、地址类型解析成字节存储到AnalysisVarStruct结构体当中
public static bool Deal_Dictionary_Data(out AnalysisVarStructAnalysisVarS, VariableInformationStruct VariableInformationS)
{
AnalysisVarS = newAnalysisVarStruct();
try
{
AnalysisVarS.Address = newbyte[4];
AnalysisVarS.Size =Convert.ToByte(VariableInformationS.Size);
for (int i = 1; i
{
AnalysisVarS.Address[i - 1]= Convert.ToByte(VariableInformationS.Address.Substring(i * 2, 2), 16);
}
AnalysisVarS.Array_Size =Convert.ToByte(VariableInformationS.Array_Size);
if(VariableInformationS.Conversion != "NULL METHOD")
{
AnalysisVarS.Conversion =Convert.ToDouble(VariableInformationS.Conversion.Substring(2));
}
else
{
AnalysisVarS.Conversion =1;
}
AnalysisVarS.Address_Type =VariableInformationS.Address_Type;
return true;
}
catch
{
return false;
}
}
#endregion
#region 接收CAN发送的数据信息结构体
///
/// 接收CAN发送的数据信息结构体
///
public struct CanRecDataStruct
{
///
/// 存储CAN接收到的8个字节数据
///
public byte[] bytedata;
///
/// true表示CAN接收到信息;false表示CAN没有接收到信息
///
public bool status;
///
/// ID号
///
public int id;
}
///
/// 定义CAN发接收数据信息结构体变量
///
public static CanRecDataStructCanRecDataS;
#endregion
#region CAN发送数据事件
///
/// 定义CAN发送数据委托
///
///
要发送的8个字节的数据
///
PC端CAN的ID号
///
///
发送等待接收时间
///
true:发送成功;false:发送失败
public delegate boolSendMessageDelegate(byte[] can_send_byte, int id, int dlc, long timeout);
///
/// CAN发送数据事件
///
public static event SendMessageDelegateSendMessageD;
#endregion
#region 处理要下传的数据
///
/// 处理要下传的数据
///
///
要处理的数据
///
处理之后的数据
///
要处理的数据对应的变量的结构体信息
public static void DealDownData(outbyte[] bytedata, double data, VariableInformationStruct VariableInformationS)
{
#region 定义变量
double match = 0;
bytedata = new byte[5];
Int64 datavalue = 0;
#endregion
#region 根据算法处理数据
if (VariableInformationS.Conversion!= "NULL METHOD")
match =Convert.ToDouble(VariableInformationS.Conversion.Substring(2));
else match = 1;
data = data * match;
#endregion
#region 判断变量类型判断数据是否溢出,并作出处理
switch (VariableInformationS.Type)
{
case "SBYTE":
if (data > ((0xFF - 1) /2))
{
data = data - 0xFF - 1;
}
break;
case "SWORD":
if (data > ((0xFFFF - 1)/ 2))
{
data = data - 0xFFFF -1;
}
break;
case "SLONG":
if (data > ((0xFFFFFFFF- 1) / 2))
{
data = data -0xFFFFFFFF - 1;
}
break;
}
#endregion
datavalue = (Int64)data;
#region 根据大小端处理数据,并将其赋值给bytedata数组
if(VariableInformationS.Address_Type == "BYTE_ORDER MSB_FIRST")
{//大端高字节在前对应第一个元素
switch(VariableInformationS.Size)
{//高字节在前
case "1":
bytedata[0] =(byte)(0xFF & (datavalue >> 0));
bytedata[1] =bytedata[2] = bytedata[3] = bytedata[4] = 0x00;
break;
case "2":
bytedata[0] =(byte)(0xFF & (datavalue >> 8));
bytedata[1] =(byte)(0xFF & (datavalue >> 0));
bytedata[2] =bytedata[3] = bytedata[4] = 0x00;
break;
case "4":
bytedata[0] =(byte)(0xFF & (datavalue >> 24));
bytedata[1] =(byte)(0xFF & (datavalue >> 16));
bytedata[2] =(byte)(0xFF & (datavalue >> 8));
bytedata[3] = (byte)(0xFF &(datavalue >> 0));
bytedata[4] = 0x00;
break;
}
}
else if(VariableInformationS.Address_Type == "BYTE_ORDER MSB_LAST")
{
switch(VariableInformationS.Size)
{//低字节在前对应第一个元素
case "1":
bytedata[0] =(byte)(0xFF & (datavalue >> 0));
bytedata[1] =bytedata[2] = bytedata[3] = bytedata[4] = 0x00;
break;
case "2":
bytedata[0] =(byte)(0xFF & (datavalue >> 0));
bytedata[1] =(byte)(0xFF & (datavalue >> 8));
bytedata[2] =bytedata[3] = bytedata[4] = 0x00;
break;
case "4":
bytedata[0] =(byte)(0xFF & (datavalue >> 0));
bytedata[1] =(byte)(0xFF & (datavalue >> 8));
bytedata[2] = (byte)(0xFF &(datavalue >> 16));
bytedata[3] =(byte)(0xFF & (datavalue >> 24));
bytedata[4] = 0x00;
break;
}
}
#endregion
}
#endregion
#region 处理上传数据
public static void DealUpData(byte[]bytedata, out double data, VariableInformationStruct VariableInformationS)
{
#region 定义变量
double match = 0;
data = 0;
#endregion
#region 根据大小端处理数据,并将其赋值给bytedata数组
if(VariableInformationS.Address_Type == "BYTE_ORDER MSB_FIRST")
{//大端高字节在前对应第一个元素
switch(VariableInformationS.Size)
{//高字节在前
case "1":
data = bytedata[0];
break;
case "2":
data = ((bytedata[0]<< 8) | bytedata[1]);
break;
case "4":
data = ((bytedata[0]<< 24) | (bytedata[1] << 16) | (bytedata[2] << 8) |bytedata[3]);
break;
}
}
else if(VariableInformationS.Address_Type == "BYTE_ORDER MSB_LAST")
{
switch(VariableInformationS.Size)
{//低字节在前对应第一个元素
case "1":
data = bytedata[0];
break;
case "2":
data = ((bytedata[1] << 8)| bytedata[0]);
break;
case "4":
data = ((bytedata[3]<< 24) | (bytedata[2] << 16) | (bytedata[1] << 8) |bytedata[0]);
break;
}
}
#endregion
#region 判断变量类型判断数据是否溢出,并作出处理
switch (VariableInformationS.Type)
{
case "SBYTE":
if (data > ((0xFF - 1) /2))
{
data = data - 0xFF - 1;
}
break;
case "SWORD":
if (data > ((0xFFFF - 1)/ 2))
{
data = data - 0xFFFF -1;
}
break;
case "SLONG":
if (data > ((0xFFFFFFFF- 1) / 2))
{
data = data -0xFFFFFFFF - 1;
}
break;
}
#endregion
#region 根据算法处理数据
if (VariableInformationS.Conversion!= "NULL METHOD")
match =Convert.ToDouble(VariableInformationS.Conversion.Substring(2));
else match = 1;
data = (data / match);
#endregion
}
#endregion
#region MCU和PC进行连接
///
/// MCU和PC进行连接
///
///
PC端CAN的ID号
///
pollingPath路径
///
dAQPath路径
///
true:连接成功;false:连接失败
public static bool MCUAndPCLink(int id,string pollingPath, string dAQPath)
{
try
{
#region 等待线程信号
AutoResetEvent.WaitOne();
#endregion
#region 定义变量
count = 0;
byte pKey = 10;
UInt16 sizeKey = 10;
#endregion
#region 获取.dll解密文件路径
if (pollingPath == null)PollingPath = "";
else PollingPath = pollingPath;
if (dAQPath == null) DAQPath ="";
else DAQPath = dAQPath;
#endregion
#region 初始化状态机
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x01CCPOrderState;
#endregion
#region 没有SeedKey连接
if (PollingPath == ""&& DAQPath == "")
{
while (true)
{
switch(MCUAndPCLinkCPPStateE)//发送0x01和0x14指令给下位机创建连接
{
#region 发送0x01CPP指令
caseCPPOrderStateEnum.Send0x01CCPOrderState:
count = 0;
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x01CCPOrderStateSuccess;
if(!SendMessageD(new byte[] { 0x01, Ctr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },id, 8, 10))//发送连接的第一条指令
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
break;
#endregion
#region 发送两次0x14CPP指令
caseCPPOrderStateEnum.Send0x14CCPOrderOneState:
count = 0;
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x14CCPOrderOneStateSuccess;
if(!SendMessageD(new byte[] { 0x14, Ctr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36 }, id,8, 10))
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
break;
caseCPPOrderStateEnum.Send0x14CCPOrderTwoState:
count = 0;
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x14CCPOrderTwoStateSuccess;
if (!SendMessageD(new byte[] {0x14, Ctr, 0x01, 0x00, 0x00, 0x00, 0x00, 0x36 }, id, 8, 10))
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
return false;
}
break;
#endregion
}
if(MCUAndPCLinkCPPStateE == CPPOrderStateEnum.MCULinkPCStateSuccess)
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
return true;
}
#region 循环超时
if (count > 1000)
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
return false;
}
#endregion
#region 线程休眠,循环次数++
Thread.Sleep(1);
count++;
#endregion
}
}
#endregion
#region 有SeedKey连接
else if (PollingPath !="" || DAQPath != "")
{
while (true)
{
switch(MCUAndPCLinkCPPStateE)
{
#region 发送0x01CPP指令
caseCPPOrderStateEnum.Send0x01CCPOrderState:
count = 0;
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x01CCPOrderStateSuccess;
if(!SendMessageD(new byte[] { 0x01, Ctr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },id, 8, 10))//发送连接的第一条指令
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
break;
#endregion
#region Polling模式
caseCPPOrderStateEnum.Send0x12CCPOrderPollingState:
count = 0;
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x12CCPOrderPollingStateSuccess;
if(!SendMessageD(new byte[] { 0x12, Ctr, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 },id, 8, 10))
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
break;
caseCPPOrderStateEnum.Send0x13CCPOrderPollingState:
count = 0;
Array.Copy(CanRecDataS.bytedata, 4, pSeed, 0, 4);
CallDll.Function_Dll(PollingPath,"ASAP1A_CCP_ComputeKeyFromSeed", pSeed, 10, out pKey, 10, outsizeKey);
CallDll.Achieve_Secret_Key(ref pKey, out pSeed, sizeKey);
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x13CCPOrderPollingStateSuccess;
if(!SendMessageD(new byte[] { 0x13, Ctr, pSeed[0], pSeed[1], pSeed[2], pSeed[3],0x00, 0x00 }, id, 8, 10))
{
MCUAndPCLinkCPPStateE= CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
break;
#endregion
#region DAQ模式
caseCPPOrderStateEnum.Send0x12CCPOrderDAQState:
count = 0;
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x12CCPOrderDAQStateSuccess;
if (!SendMessageD(new byte[] {0x12, Ctr, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }, id, 8, 10))
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
return false;
}
break;
caseCPPOrderStateEnum.Send0x13CPPOrderDAQStateSuccess:
count = 0;
PollingPath = "";
Array.Copy(CanRecDataS.bytedata, 4, pSeed, 0, 4);
CallDll.Function_Dll(DAQPath, "ASAP1A_CCP_ComputeKeyFromSeed",pSeed, 0, out pKey, 0, out sizeKey);
CallDll.Achieve_Secret_Key(refpKey, out pSeed, sizeKey);
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x13CPPOrderDAQStateSuccess;
if(!SendMessageD(new byte[] { 0x13, Ctr, pSeed[0], pSeed[1], pSeed[2], pSeed[3],0x00, 0x00 }, id, 8, 10))
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
break;
#endregion
#region 发送两次0x14CPP指令
caseCPPOrderStateEnum.Send0x14CCPOrderOneState:
count = 0;
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x14CCPOrderOneStateSuccess;
if(!SendMessageD(new byte[] { 0x14, Ctr, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10 },id, 8, 10))
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
break;
caseCPPOrderStateEnum.Send0x14CCPOrderTwoState:
count = 0;
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x14CCPOrderTwoStateSuccess;
if (!SendMessageD(newbyte[] { 0x14, Ctr, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01 }, id, 8, 10))
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
break;
#endregion
}
if(MCUAndPCLinkCPPStateE == CPPOrderStateEnum.MCULinkPCStateSuccess)
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
return true;
}
#region 循环超时
if (count > 1000)//连接失败
{
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.NullCCPOrderState;
return false;
}
#endregion
#region 线程休眠,循环次数++
Thread.Sleep(1);
count++;
#endregion
}
}
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.NullCCPOrderState;
return true;
#endregion
}
catch { MCUAndPCLinkCPPStateE =CPPOrderStateEnum.NullCCPOrderState; return false; }
finally { AutoResetEvent.Set(); }
}
#endregion
#region 下发数据
#region 下发选中的单个标定量
///
/// 下发选中的单个标定量
///
///
PC端CAN的ID号
///
下传的数据
///
需要下传的A2L文件里的结构体变量
///
true:下传成功;false:下传失败
public static bool CCPDownOneData(intid, double data, VariableInformationStruct VariableInformationS)
{
try
{
#region 等待线程信号
AutoResetEvent.WaitOne();
#endregion
#region 定义变量
count = 0;
address = 0;//地址大小
int firstFew = 0;//第几个数组元素
#endregion
#region 数据处理
//AnalysisVarStruct AnalysisVarS = newAnalysisVarStruct();//清除上次数据记录
Deal_Dictionary_Data(outAnalysisVarS, VariableInformationS);
//byte[] bytedata = newbyte[5];
DealDownData(out bytedata,data, VariableInformationS);
#endregion
#region 地址处理
address =(AnalysisVarS.Address[0] << 24) + (AnalysisVarS.Address[1] << 16) +(AnalysisVarS.Address[2] << 8) + AnalysisVarS.Address[3];
if (VariableInformationS.Name.Contains("--"))
{
firstFew =Convert.ToInt32(VariableInformationS.Name.Substring(VariableInformationS.Name.LastIndexOf("--")+ 2));
address +=AnalysisVarS.Size * firstFew;
}
if(VariableInformationS.Address_Type == "BYTE_ORDER MSB_LAST")
{
address = ((address &0x000000FF) << 24) + ((address & 0x0000FF00) << 8) + ((address& 0x00FF0000) >> 8) + ((address & 0x00FF0000) >> 24);
}
#endregion
DownDataCCPStateE =CPPOrderStateEnum.Send0x02CCPOrderState;
while (true)
{
switch (DownDataCCPStateE)
{
caseCPPOrderStateEnum.Send0x02CCPOrderState:
DownDataCCPStateE =CPPOrderStateEnum.Send0x02CCPOrderStateSuccess;//标记0x02指令已经开始发送
if(!SendMessageD(new byte[] { 0x02, Ctr, 0x00, 0x00, (byte)(0xFF & (address>> 24)), (byte)(0xFF & (address >> 16)), (byte)(0xFF &(address >> 8)), (byte)(0xFF & address) }, id, 8, 10))
{
DownDataCCPStateE = CPPOrderStateEnum.NullCCPOrderState;
return false;
}
count = 0;
break;
caseCPPOrderStateEnum.Send0x03CCPOrderState:
DownDataCCPStateE =CPPOrderStateEnum.Send0x03CCPOrderStateSuccess;//标记0x02指令已经开始发送
if(!SendMessageD(new byte[] { 0x03, Ctr, AnalysisVarS.Size, bytedata[0],bytedata[1], bytedata[2], bytedata[3], bytedata[4] }, id, 8, 10))
{
DownDataCCPStateE = CPPOrderStateEnum.NullCCPOrderState;
return false;
}
count = 0;
break;
}
if (DownDataCCPStateE ==CPPOrderStateEnum.CCPDownDataStateSuccess)//下传数据成功
{
count = 0;
DownDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState;
return true;
}
if (count >= 1000)//下传数据失败
{
DownDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState;
return false;
}
Thread.Sleep(1);
count++;
}
}
catch { DownDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState; return false; }
finally { AutoResetEvent.Set(); }
}
#endregion
#region 下发选中的多个标定量
///
/// 下发选中的多个标定量
///
///
PC端CAN的ID号
///
存储需要下传数据的泛型集合
///
存储需要下传的A2L文件变量的泛型集合
///
true:下传成功;false:下传失败
public static bool CCPDownManyData(intid, Dictionary
dicData, Dictionary
VariableInformationDic)
{
try
{
#region 等待线程信号
AutoResetEvent.WaitOne();
#endregion
#region 定义变量
count = 0;
address = 0;//地址大小
int firstFew = 0;//第几个数组元素
#endregion
foreach (KeyValuePair
dic in VariableInformationDic)
{
#region 数据处理
//AnalysisVarStruct AnalysisVarS= new AnalysisVarStruct();//清除上次数据记录
Deal_Dictionary_Data(outAnalysisVarS, dic.Value);
//byte[] bytedata = newbyte[5];
DealDownData(out bytedata,dicData[dic.Key], dic.Value);
#endregion
#region 地址处理
address =(AnalysisVarS.Address[0] << 24) + (AnalysisVarS.Address[1] << 16) +(AnalysisVarS.Address[2] << 8) + AnalysisVarS.Address[3];
if (dic.Value.Name.Contains("--"))
{
firstFew =Convert.ToInt32(dic.Value.Name.Substring(dic.Value.Name.LastIndexOf("--")+ 2));
address +=AnalysisVarS.Size * firstFew;
}
if (dic.Value.Address_Type== "BYTE_ORDER MSB_LAST")
{
address = ((address& 0x000000FF) << 24) + ((address & 0x0000FF00) << 8) +((address & 0x00FF0000) >> 8) + ((address & 0x00FF0000) >>24);
}
#endregion
DownDataCCPStateE =CPPOrderStateEnum.Send0x02CCPOrderState;
while (true)
{
switch(DownDataCCPStateE)
{
caseCPPOrderStateEnum.Send0x02CCPOrderState:
DownDataCCPStateE = CPPOrderStateEnum.Send0x02CCPOrderStateSuccess;//标记0x02指令已经开始发送
if(!SendMessageD(new byte[] { 0x02, Ctr, 0x00, 0x00, (byte)(0xFF & (address>> 24)), (byte)(0xFF & (address >> 16)), (byte)(0xFF &(address >> 8)), (byte)(0xFF & address) }, id, 8, 10))
{
DownDataCCPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
count = 0;
break;
caseCPPOrderStateEnum.Send0x03CCPOrderState:
DownDataCCPStateE = CPPOrderStateEnum.Send0x03CCPOrderStateSuccess;//标记0x02指令已经开始发送
if(!SendMessageD(new byte[] { 0x03, Ctr, AnalysisVarS.Size, bytedata[0],bytedata[1], bytedata[2], bytedata[3], bytedata[4] }, id, 8, 10))
{
DownDataCCPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
count = 0;
break;
}
if (DownDataCCPStateE== CPPOrderStateEnum.CCPDownDataStateSuccess)//下传数据成功
{
DownDataCCPStateE =CPPOrderStateEnum.Send0x02CCPOrderState;
count = 0;
break;
}
if (count >= 1000)//下传数据失败
{
DownDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState;
return false;
}
Thread.Sleep(1);
count++;
}
}
DownDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState;
return true;
}
catch
{
DownDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState;
return false;
}
finally { AutoResetEvent.Set(); }
}
#endregion
#endregion
#region 上传数据
#region 上传单个数据
///
/// 上传单个数据
///
///
PC端CAN的ID号
///
上传的数据
///
需要上传的A2L文件里的结构体变量
///
true:上传成功;false:上传失败
public static bool CCPUpOneData(int id,out double dicData, VariableInformationStruct VariableInformationS)
{
dicData = 0;
try
{
#region 等待线程信号
AutoResetEvent.WaitOne();
#endregion
#region 定义变量
count = 0;
int firstFew = 0;//第几个数组元素
address = 0;//地址大小
#endregion
#region 获取地址
//AnalysisVarStructAnalysisVarS = new AnalysisVarStruct();//清除上次数据记录
Deal_Dictionary_Data(out AnalysisVarS,VariableInformationS);
address =(AnalysisVarS.Address[0] << 24) + (AnalysisVarS.Address[1] << 16) +(AnalysisVarS.Address[2] << 8) + AnalysisVarS.Address[3];
if(VariableInformationS.Name.Contains("--"))
{
firstFew =Convert.ToInt32(VariableInformationS.Name.Substring(VariableInformationS.Name.LastIndexOf("--")+ 2));
address +=AnalysisVarS.Size * firstFew;
}
if (VariableInformationS.Address_Type== "BYTE_ORDER MSB_LAST")
{
address = ((address &0x000000FF) << 24) + ((address & 0x0000FF00) << 8) + ((address& 0x00FF0000) >> 8) + ((address & 0x00FF0000) >> 24);
}
#endregion
UpDataCCPStateE =CPPOrderStateEnum.Send0x0FCCPOrderState;
while (true)
{
switch (UpDataCCPStateE)
{
caseCPPOrderStateEnum.Send0x0FCCPOrderState:
UpDataCCPStateE =CPPOrderStateEnum.Send0x0FCCPOrderStateSuccess;
if(!SendMessageD(new byte[] { 0x0F, Ctr, AnalysisVarS.Size, 0x00, (byte)(0xFF& (address >> 24)), (byte)(0xFF & (address >> 16)),(byte)(0xFF & (address >> 8)), (byte)(0xFF & address) }, id, 8,10))
{
UpDataCCPStateE= CPPOrderStateEnum.NullCCPOrderState;
return false;
}
count = 0;
break;
}
if (UpDataCCPStateE ==CPPOrderStateEnum.CCPUpDataStateSuccess)//成功
{
count = 0;
DealUpData(TempBuf, outdicData, VariableInformationS);
UpDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState;
return true;
}
if (count >= 1000)//失败
{
count = 0;
UpDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState;
return false;
}
Thread.Sleep(1);//让线程休息50ms
count++;
}
}
catch { UpDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState; return false; }
finally { AutoResetEvent.Set(); }
}
#endregion
#region 上传多个数据
///
/// 上传多个数据
///
///
PC端CAN的ID号
///
存储上传的数据的泛型集合
///
存储需要上传的A2L文件变量的泛型集合
///
public static bool CCPUpManyData(intid, out Dictionary
dicData, Dictionary
variableInformationStructDic)
{
dicData = new Dictionary
();
try
{
#region 等待线程信号
AutoResetEvent.WaitOne();
#endregion
#region 定义变量
count = 0;
int firstFew = 0;//第几个数组元素
address = 0;//地址大小
double data = 0;
#endregion
UpDataCCPStateE =CPPOrderStateEnum.Send0x0FCCPOrderState;
foreach (KeyValuePair
dic in variableInformationStructDic)
{
#region 获取地址
//AnalysisVarStructAnalysisVarS = new AnalysisVarStruct();//清除上次数据记录
Deal_Dictionary_Data(outAnalysisVarS, dic.Value);
address = (AnalysisVarS.Address[0]<< 24) + (AnalysisVarS.Address[1] << 16) + (AnalysisVarS.Address[2]<< 8) + AnalysisVarS.Address[3];
if(dic.Value.Name.Contains("--"))
{
firstFew =Convert.ToInt32(dic.Value.Name.Substring(dic.Value.Name.LastIndexOf("--")+ 2));
address +=AnalysisVarS.Size * firstFew;
}
if (dic.Value.Address_Type== "BYTE_ORDER MSB_LAST")
{
address = ((address & 0x000000FF)<< 24) + ((address & 0x0000FF00) << 8) + ((address &0x00FF0000) >> 8) + ((address & 0x00FF0000) >> 24);
}
#endregion
while (true)
{
switch(UpDataCCPStateE)
{
caseCPPOrderStateEnum.Send0x0FCCPOrderState:
UpDataCCPStateE= CPPOrderStateEnum.Send0x0FCCPOrderStateSuccess;
if (!SendMessageD(newbyte[] { 0x0F, Ctr, AnalysisVarS.Size, 0x00, (byte)(0xFF & (address>> 24)), (byte)(0xFF & (address >> 16)), (byte)(0xFF &(address >> 8)), (byte)(0xFF & address) }, id, 8, 10))
{
count = 0;
UpDataCCPStateE = CPPOrderStateEnum.NullCCPOrderState;
returnfalse;
}
count = 0;
break;
}
if (UpDataCCPStateE ==CPPOrderStateEnum.CCPUpDataStateSuccess)
{
UpDataCCPStateE =CPPOrderStateEnum.Send0x0FCCPOrderState;
DealUpData(TempBuf,out data, dic.Value);
dicData.Add(dic.Key, data);
count = 0;
break;
}
if (count >= 1000)
{
count = 0;
UpDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState;
return false;
}
Thread.Sleep(1);//让线程休息50ms
count++;
}
}
UpDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState;
return true;
}
catch { UpDataCCPStateE =CPPOrderStateEnum.NullCCPOrderState; return false; }
finally { AutoResetEvent.Set(); }
}
#endregion
#endregion
#region 响应CPP指令
#region 响应CPP指令线程
///
/// 响应CPP指令线程
///
public static ThreadCCPOrderResponseThread;
#endregion
#region 响应CPP指令
///
/// 响应CPP指令
///
public static void CCPOrderResponse()
{
while (true)
{
try
{
if (CanRecDataS.status)//表示CAN收到数据了
{
CanRecDataS.status =false;
switch(MCUAndPCLinkCPPStateE)
{
#region 发送0x01CPP指令
caseCPPOrderStateEnum.Send0x01CCPOrderStateSuccess:
if (PollingPath!= "" && PollingPath != null)
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x12CCPOrderPollingState;
else if(DAQPath != "" && DAQPath != null)
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x12CCPOrderDAQState;
else
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x14CCPOrderOneState;
break;
#endregion
#region Polling模式
caseCPPOrderStateEnum.Send0x12CCPOrderPollingStateSuccess:
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x13CCPOrderPollingState;
break;
caseCPPOrderStateEnum.Send0x13CCPOrderPollingStateSuccess:
if (DAQPath !="" && DAQPath != null)
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x12CCPOrderDAQState;
else
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x14CCPOrderOneState;
break;
#endregion
#region DAQ模式
caseCPPOrderStateEnum.Send0x12CCPOrderDAQStateSuccess:
MCUAndPCLinkCPPStateE =CPPOrderStateEnum.Send0x13CPPOrderDAQStateSuccess;
break;
caseCPPOrderStateEnum.Send0x13CPPOrderDAQStateSuccess:
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x14CCPOrderOneState;
break;
#endregion
#region 发送两次0x14CCP指令
caseCPPOrderStateEnum.Send0x14CCPOrderOneStateSuccess:
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.Send0x14CCPOrderTwoState;
break;
caseCPPOrderStateEnum.Send0x14CCPOrderTwoStateSuccess://连接成功
MCUAndPCLinkCPPStateE = CPPOrderStateEnum.MCULinkPCStateSuccess;
break;
#endregion
}
switch(DownDataCCPStateE)
{
caseCPPOrderStateEnum.Send0x02CCPOrderStateSuccess:
DownDataCCPStateE= CPPOrderStateEnum.Send0x03CCPOrderState;
break;
caseCPPOrderStateEnum.Send0x03CCPOrderStateSuccess:
DownDataCCPStateE = CPPOrderStateEnum.CCPDownDataStateSuccess;
break;
}
switch(UpDataCCPStateE)
{
caseCPPOrderStateEnum.Send0x0FCCPOrderStateSuccess:
TempBuf = new byte[5];
Array.Copy(CanRecDataS.bytedata, 3, TempBuf, 0, 5);
UpDataCCPStateE= CPPOrderStateEnum.CCPUpDataStateSuccess;
break;
}
}
Thread.Sleep(1);
}
catch { }
}
}
#endregion
#region 打开响应CPP指令线程
///
/// 打开响应CPP指令线程
///
///
public static boolOpenCCPOrderResponseThread()
{
try
{
//打开CCP响应线程
if (CCPOrderResponseThread !=null) CCPOrderResponseThread.Abort();
CCPOrderResponseThread = new Thread(new ThreadStart(CCPOrderResponse));
CCPOrderResponseThread.IsBackground = true;
CCPOrderResponseThread.Start();
while(!CCPOrderResponseThread.IsAlive == true) Thread.Sleep(1);
return true;
}
catch { return false; }
}
#endregion
#region 关闭响应CPP指令线程
///
/// 关闭响应CPP指令线程
///
///
public static boolCloseCCPOrderResponseThread()
{
try
{
if (CCPOrderResponseThread !=null)
{
if(CCPOrderResponseThread.IsAlive==true)CCPOrderResponseThread.Abort();
}
return true;
}
catch { return false; }
}
#endregion
#endregion
}
调用很简单,里面有一个发送数据的委托事件,只需要将
CAN
发送数据的函数添加到该时间里,然后调用对应的静态函数来实现数据的读写以及连接。这个静态内中添加了线程互斥信号
AutoResetEvent AutoResetEvent
,通过
AutoResetEvent AutoResetEvent
可以实现多线程共同访问该静态类,不会出现资源被无端修改等情况的发生,它能确保线程的互斥和同步,这个已经在我们公司生产
EPS
的生产线软件中做过验证,通过上位机软件利用
CAN
同时测试
4
个
EPS
模块,大大的节省了时间。
有兴趣的可以加我:
QQ:1343263021 微信:18862121743 QQ群:100300621
寻求项目合作:
单片机
、上位机
联系电话:18862121743
回帖
(2)
abc
2017-9-7 08:37:49
學習了,謝謝~~
學習了,謝謝~~
举报
贾梦琦
2018-9-15 16:56:08
受到警告
提示:
作者被禁止或删除 内容自动屏蔽
举报
更多回帖
rotate(-90deg);
回复
相关帖子
汽车电子
CCP
USB
2.0
协议
2022-03-13
36480
10Mbps多
协议
串行芯片组:
Net
1和
Net
2符合设计要求
2019-05-30
1061
怎么在Vee 9.3程序中使用.
NET
2.0
.dll
2018-09-25
1249
《ASP.
NET
2.0
网络开发技术》 走进ASP.
NET
2.0
.pdf
2018-06-22
1651
《ASP.
NET
2.0
网络开发技术》 ASP.
NET
2.0
核心对象.pdf
2018-06-19
1530
ASP.
NET
2.0
网络开发技术.zip
2018-06-19
930
.
Net
Micro Framework 快速入门
2014-05-29
3040
.
NET
Micro Framework简介
2014-05-27
3330
asp.
net
2.0
编程珠玑下载
2008-09-19
3545
MICROSOFT .
NET
FRAMEWORK
2.0
2008-06-25
12591
发帖
登录/注册
20万+
工程师都在用,
免费
PCB检查工具
无需安装、支持浏览器和手机在线查看、实时共享
查看
点击登录
登录更多精彩功能!
首页
论坛版块
小组
免费开发板试用
ebook
直播
搜索
登录
×
20
完善资料,
赚取积分