|
楼主 |
发表于 2009-3-27 15:16:59
|
显示全部楼层
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称:=ICAN_ObjIDRestore
//功能描述:ICAN报文标识码还原
// 将long型变量Receive_ObjID中保存的iCAN报文标识码分离到结构体指针*ICAN_ObjID。
///////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
// Receive_ObjID=ICAN报文标识码
//出口参数:
// * ICAN_ObjID=结构体指针
///////////////////////////////////////////////////////////////////////////////////////////
void ICAN_ObjIDRestore(ICAN_OBJ *ICAN_ObjID, uint32 Receive_ObjID)
{
ICAN_ObjID->SrcMACID = (Receive_ObjID >> 21) & 0x000000FF; // 源节点编号(ID28-ID21)
ICAN_ObjID->DestMACID = (Receive_ObjID >> 13) & 0x000000FF; // 目标节点编号(ID20-ID13)
ICAN_ObjID->ACK = (Receive_ObjID >> 12) & 0x00000001; // 应答标志(ID12)
ICAN_ObjID->FUNCID = (Receive_ObjID >> 8) & 0x000000F; // 功能码(ID11-ID8)
ICAN_ObjID->SourceID = (Receive_ObjID) & 0x000000FF; // 资源节点编号(ID7-ID0)
}
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称:=ICAN_ObjByte0Manage
//功能描述:生成iCAN报文数据段0字节BYTE0(SegFlag,多帧传输及单帧传输)
///////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
// TxCtr=读数据指针????????????????????????????????????
// Lenth=报文长度(数据场长度)
//出口参数:
// CAN报文数据段0字节(BYTE0)=SegFlag
///////////////////////////////////////////////////////////////////////////////////////////
uchar ICAN_ObjByte0Manage(uint TxCtr, uint Lenth)
{
uchar ucTemp;
//--------------------------------------------------------------------------
//小于8字节,本次数据传输没有分段,分段标志SegFlag=0(iCAN报文一次最多只能传输7个字节)
//--------------------------------------------------------------------------
if (Lenth < 8)
{
ucTemp = 0; // BYTE0=0x00
}
else
{
//--------------------------------------------------------------------------
//批量数据的第一个分段(SegPolo=01=0x40《bit7,bit6》,批量数据传输的第1个分段;此时,SegNum=0x00值)
//--------------------------------------------------------------------------
if (TxCtr == 0) // 如果读数据指针=0
{
ucTemp = 0x40; // BYTE0=0x40
}
//--------------------------------------------------------------------------
//批量数据的最后一个分段(SegPolo=11=0xC0《bit7,bit6》,最后分段)
//--------------------------------------------------------------------------
else if (TxCtr + 7 >= Lenth) // 如果读数据指针+7>=报文长度
{
ucTemp = 0xC0; // BYTE0=0xC0
}
else
{
if (TxCtr > 448) // 发送数据超过448字节
{
return (0xFF);
}
//--------------------------------------------------------------------------
//中间数据段(中间分段SegPolo=10。SegNum值从0x01起,每次加1,以区分段数)
//--------------------------------------------------------------------------
ucTemp = TxCtr / 7 + 0x80; // 计数对应的段数,并标识为中间段
} // BYTE0=0x80+分段编号(读数据指针/7)
}
return (ucTemp); // 生成标识符
}
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称:=CAN_ObjByte0Restore
//功能描述:iCAN报文数据段0字节生成(获取分段标识)
// 应用于连续写端口命令。根据接收报文中的第一个字节(分段码)来区分多帧数据中到底是
// 哪一帧。(参见iCAN协议)
///////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
// *RxCtr=接收缓冲区数据接收指针
// segflag=接收报文第一字节=分段码
//出口参数:
// *RxCtr=数据接收指针
// ucTemp:
// 0=接收的报文中没有分段
// 1=当前是接收报文的第一分段
// segflag & 0x3f=当前是接收报文的中间分段(因为SegPolo占用bit7,bit6,分段号占用bit5,bit4,bit3,bit2,bit1,bit0,因此用0x3F分离出分段号)
// 65=当前是接收报文的最后一个分段
//-----------------------------------------------------------------------------
uchar ICAN_ObjByte0Restore(uint * RxCtr, uchar segflag)
{
uchar ucTemp;
//-----------------------------------------------------------------------------
//无分段标识(SegPolo=00)
//-----------------------------------------------------------------------------
if (segflag == 0) // 没有分段
{
*RxCtr = 0x00; // 接收数据指针指向零
ucTemp = 0x00; // 0=没有分段
}
//-----------------------------------------------------------------------------
//最后分段标识(SegPolo=11)
//-----------------------------------------------------------------------------
else if ((segflag & 0xC0) == 0xC0) // 批量数据的最后一个分段
{
ucTemp = 65; // 65=最后一个分段
}
//-----------------------------------------------------------------------------
//第一分段标识(SegPolo=01)
//-----------------------------------------------------------------------------
else if ((segflag & 0x40) == 0x40) // 启始段,批量数据的第一个分段
{
*RxCtr = 0x00; // 接收数据指针指向零
ucTemp = 0x01; // 1=第一分段
}
//-----------------------------------------------------------------------------
//中间分段标识(SegPolo=10)
//-----------------------------------------------------------------------------
else // 中间数据段
{
ucTemp = segflag & 0x3f; // 返回中间分段号
*RxCtr = (segflag&0x3f)*7; // 接收数据指针
}
return (ucTemp); // 生成标识符
}
//*********************************************************************************************************
//定义iCAN帧ID码节点结构体
// ********************************************************************************************************
//typestruct { // 帧ID码
//
// uint32 SrcMACID;
// uint32 DestMACID;
// uint32 ACK;
// uint32 FUNCID;
// uint32 SourceID;
//} ICAN_OBJ;
//typestruct { // ICAN读写缓冲
//
// uint32 ulID; // 发送的ID代码
// uint ucDataLenth; // 数据场长度
// uint ucDataCtr; // 读数据指针
// uchar ucXID; // 0 标准帧;1 扩展帧
// uchar TrBegin;
// uchar ucDataBuff[8]; // 数据缓冲(32)字节
//} tICAN_TRBUFF;
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=ICAN_ErrIDACK(uchar order)
//功能描述=填写错误报文
//-----------------------------------------------------------------------------------------
// 1、从iCAN帧头结构体(ICANSlav_ObjID)取出“资源节点编号”-------
// “源节点编号” |------>填写到结构体ICAN_ObjIDTmp
// “目标节点编号”-------
//
// “应答”=1 -------
// |------>填写到结构体ICAN_ObjIDTmp
// “功能码”=0x0F-------
// 其中结构体ICAN_ObjIDTmp保存iCAN帧头信息,包括如下:
// 源节点编号、目标节点编号、应答位、功能码、资源节点编号
// 2、填写iCAN读写缓冲结构体
// (1)、填写发送的ID代码=(源节点编号、目标节点编号、应答位、功能码、资源节点编号)
// (2)、填写扩展帧
// (3)、填写数据缓冲区=错误代码(只填写一个字节)
// (4)、填写发送报文长度=2字节(一个字节用来标识单帧/多帧,另一个字节=错误码)
// (5)、填写读数据指针=0
// (6)、填写发送开始标志
//-----------------------------------------------------------------------------------------
//入口参数:
// order=
// ErrID=错误号
///////////////////////////////////////////////////////////////////////////////////////////
void ICAN_ErrorIDACK(uchar order, uchar ErrID)
{
ICAN_OBJ xdata ICAN_ObjIDTmp;
ICAN_ObjIDTmp.SourceID = ICANSlav_ObjID[order].SourceID; // 资源节点编号
ICAN_ObjIDTmp.FUNCID = 0x0F; // 功能码
ICAN_ObjIDTmp.ACK = 1; // 应答标志
ICAN_ObjIDTmp.DestMACID = ICANSlav_ObjID[order].SrcMACID; // 目标节点编号
ICAN_ObjIDTmp.SrcMACID = ICANSlav_ObjID[order].DestMACID; // 源节点编号
ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp); // 生成ICAN报文ID
ICAN_TrBuff[order].ucXID = 1; // 0 标准帧;1 扩展帧
ICAN_TrBuff[order].ucDataBuff[0] = ErrID; // 返回对应的错误代码
ICAN_TrBuff[order].ucDataLenth = 2; // 数据场长度1字节
ICAN_TrBuff[order].ucDataCtr = 0; // 读数据指针指0字节
ICAN_TrBuff[order].TrBegin = 1; // 发送开始标志置位
}
uchar function = 0;
//*********************************************************************************************************
//定义CAN报文结构体
// ********************************************************************************************************
//typestruct _tCANFrame {
// uchar ucXID; // 0 标准帧(CAN2.0A);1 扩展帧(CAN2.0B)
// uchar ucDLC; // 数据场长度(DLC)
// uint32 ulID; // CAN报文ID(iCAN帧标识符)
// uchar ucDataBuff[8]; // 报文数据场
} tCANFrame;
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_ConnectACK(uchar order, tCANFrame *pCANFrame)
//功能描述=建立连接命令(功能码=0x04,用于和iCAN从站建立通讯连接)
//★★★命令帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=0 功能码=0x04 资源节点=0xF7 | 分段码=0x00 MasterMACID CyclicMaster
//
//★★★正常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x04 资源节点=0xF7 | 分段码=0x00 DILen DOLen AILen AOLen
//
//★★★异常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x0F 资源节点=0xF7 | 分段码=0x00 ERRID
//说明:
//(1)、
// 在“建立连接”命令帧中源节点地址为主站 MACID,报文数据长度为 3 个字节。报文数据部分第一个字节表示分段码
// (固定为 0x00) ;报文数据第二个字节表示主站 MACID;报文数据的第三个字节表示主站定时循环参数(CyclicMaster)
//(2)、CyclicMaster的单位为 10ms,当 CyclicMaster > 0时, (CyclicMaster*4)时间为从站判断主站发送通讯报文
// 的是否超时的时间间隔,在通讯过程中,如果从站在(CyclicMaster*4)时间内未收到主站的命令报文,将自动删除连接,
// 退出通讯。当CyclicMaster为 0 时,从站不检测通讯超时,直到收到正确的“删除连接”命令帧时,才删除与主站的连接。
//----------------------------------------------------------------------------------------------------------------
//入口参数:
// order=
// *pCANFrame=CAN报文结构体指针(保存DLC、iCAN帧头、iCAN报文)
//出口参数:
// 无
//-----------------------------------------------------------------------------
void iCAN_ConnectACK(uchar order, tCANFrame *pCANFrame)
{
ICAN_OBJ xdata ICAN_ObjIDTmp; // iCAN帧头结构体
//----------------------------------------------------------------------------
//检测之前是否已经建立连接成功
//----------------------------------------------------------------------------
if (function >= 1) // 如果之前已经建立过连接,两次建立连接则报错
{
ICAN_ErrorIDACK(order,ErrID_NotCommand);
}
//----------------------------------------------------------------------------
//检测功能码=0x04
//----------------------------------------------------------------------------
else if (pCANFrame->ulID&0x00000400!=0x00000400)
{
ICAN_ErrorIDACK(order,ErrID_NotFunctionID); // 功能码不对;
}
/* else if(ICAN_Source[order].Area[MasterMACID]!=pCANFrame->ucDataBuff[1])
{
ICAN_ErrorIDACK(order,ErrID_NotCommand);//错误代码返回报文(命令不技持,主站ID不对);
}
*/
//----------------------------------------------------------------------------
//检测分段码=0(主站请求报文的第一个字节必须=0,即分段码=0)
//----------------------------------------------------------------------------
else if ((pCANFrame->ucDataBuff[0]!=0))
{
ICAN_ErrorIDACK(order,ErrID_ParameterError); // 错误代码返回报文(参数非法)
}
//----------------------------------------------------------------------------
//填写应答报文给主站分三步骤:
//(1)、从报文中读取主站节点的MACID和通信节拍数
//(2)、填写iCAN报文帧头结构体ICAN_ObjIDTmp
// SrcMACID=源结点编号
// DestMACID=目标结点编号
// ACK=1
// FUNCID=0x04=功能码
// SourceID=0xF7=资源节点编号
//(3)、填写iCAN读写缓冲区结构体ICAN_TrBuff
// ulID=iCAN帧头格式合成(ID28-ID0)
// ucXID = 1(扩展帧),iCAN只支持扩展帧
// ucDataLenth=5,发送报文长度(DLC=5);分段码占用一字节,DIlen占用一字节,DOlen占用一字节,AIlen占用一字节,AOlen占用一字节(共计5字节)
// ucDataBuff[0]=报文数据场2字节(DI资源数量)
// ucDataBuff[1]=报文数据场3字节(DO资源数量)
// ucDataBuff[2]=报文数据场4字节(AI资源数量)
// ucDataBuff[3]=报文数据场5字节(AO资源数量)
// TrBegin=发送报文标志
//----------------------------------------------------------------------------
else
{
ICAN_Source[order].Area[MasterMACID] = pCANFrame->ucDataBuff[1]; // 读取主站节点的MACID
ICAN_Source[order].Area[CyclicMaster] = pCANFrame->ucDataBuff[2]; // 读取主站节点定时通信节拍数
//----------------------------------
//填写iCAN帧头结构体信息
//----------------------------------
ICAN_ObjIDTmp.SourceID = 0xF7; // 资源节点编号
ICAN_ObjIDTmp.FUNCID = 0x04; // 功能码
ICAN_ObjIDTmp.ACK = 1; // 应答标志(从站返回应答报文)
ICAN_ObjIDTmp.DestMACID = ICAN_Source[order].Area[MasterMACID]; // 目标节点编号
ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID]; // 源节点编号
//------------------------------------
//填写iCAN读写缓冲区结构体
//------------------------------------
ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp); // 生成ICAN报文ID
ICAN_TrBuff[order].ucXID = 1; // 0 标准帧;1 扩展帧
ICAN_TrBuff[order].ucDataLenth = 5; // 数据场长度5字节
ICAN_TrBuff[order].ucDataCtr = 0; // 读数据指针指0字节
ICAN_TrBuff[order].ucDataBuff[0] = SourceType[order][0]; // 报文数据场2字节(DI资源数量)
ICAN_TrBuff[order].ucDataBuff[1] = SourceType[order][1]; // 报文数据场3字节(DO资源数量)
ICAN_TrBuff[order].ucDataBuff[2] = SourceType[order][2]; // 报文数据场4字节(AI资源数量)
ICAN_TrBuff[order].ucDataBuff[3] = SourceType[order][3]; // 报文数据场5字节(AO资源数量)
ICAN_TrBuff[order].TrBegin = 1; // 发送开始标志置位
}
//----------------------------------------------------------------------------
//设置建立连接成功
//----------------------------------------------------------------------------
function++;
}
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_MACIDTest(uchar order, uchar ack)
//功能描述=MACID检测命令(从站上电发送MACID检测命令),功能码=0x07
// “MAC ID检测”命令帧用于检测网络中是否存在指定“节点地址”的从站。在 iCAN
// 网络中,具有该“节点地址”的从站在接收到“MAC ID检测”命令帧后给出响应,告
// 知命令发送节点,该“节点地址”已经存在。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★命令帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=0 功能码=0x07 资源节点=随机数 | 分段码=0x00 MAC ID 序列号(4字节)
//
//★★★响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x07 资源节点=随机数 | 分段码=0x00 MAC ID 序列号(4字节)
//说明:
//(1)、在“MAC ID检测”命令帧中资源节点为随机数。报文数据长度为 6 个字节,报文数据第一个字节表示分段码(固定为 0) ;
// 第二个字节表示要检测的“节点地址” ;第三至六字节为发送命令节点的设备序列号。
//(2)、从站在收到格式正确的“MACID检测”命令帧后,如果命令帧中的 MAC ID与自身的“节点地址”相同,从站发送“MAC ID
// 检测”响应帧。对格式不正确的“MACID检测” 命令帧或命令帧中的 MAC ID与自身的 “节点地址”不同,从站忽略该 “MAC
// ID检测”命令帧,不产生任何响应报文。
//(3)、“MAC ID检测”响应帧数据部分的“MAC ID”表示发送响应报文节点的“节点地址” ,4 字节的“产品序列号”为发送
// 响应的节点的设备序列号。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
// order=
// ack=
// 0:
// 1:
//出口参数:
// 无
//-----------------------------------------------------------------------------
void iCAN_MACIDTest(uchar order, uchar ack)
{
ICAN_OBJ xdata ICAN_ObjIDTmp; // iCAN帧头结构体
ICAN_ObjIDTmp.SourceID = 0xEE; // 资源节点编号(随机)
ICAN_ObjIDTmp.FUNCID = 0x07; // 功能码
ICAN_ObjIDTmp.ACK = ack; // 应答标志
//------------------------------------------------------------------------------------------------
//为了探测网络上是否有相同的节点编号,故源节点编号=目标节点编号,都从0xEE中获取
//------------------------------------------------------------------------------------------------
ICAN_ObjIDTmp.DestMACID = ICAN_Source[order].Area[MACID]; // 目标节点编号
ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID]; // 源节点编号
ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp); // 生成ICAN报文ID
ICAN_TrBuff[order].ucXID = 1; // 0 标准帧;1 扩展帧
ICAN_TrBuff[order].ucDataLenth = 6; // 数据场长度6字节
ICAN_TrBuff[order].ucDataCtr = 0; // 读数据指针指0字节
ICAN_TrBuff[order].ucDataBuff[0] = ICAN_Source[order].Area[MACID]; // 报文数据场2字节(MACID)
ICAN_TrBuff[order].ucDataBuff[1] = ICAN_Source[order].Area[SerialNumber]; // 报文数据场3字节(SN第1字节)
ICAN_TrBuff[order].ucDataBuff[2] = ICAN_Source[order].Area[SerialNumber+1]; // 报文数据场4字节(SN第2字节)
ICAN_TrBuff[order].ucDataBuff[3] = ICAN_Source[order].Area[SerialNumber+2]; // 报文数据场5字节(SN第3字节)
ICAN_TrBuff[order].ucDataBuff[4] = ICAN_Source[order].Area[SerialNumber+3]; // 报文数据场5字节(SN第4字节)
ICAN_TrBuff[order].TrBegin = 1; // 发送开始标志置位
}
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_UnConnectACK(uchar order, tCANFrame *pCANFrame)
//功能描述=删除连接命令(功能码=0x05)
// “删除连接”命令帧用于主站撤销与从站建立的通讯。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★命令帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=0 功能码=0x05 资源节点=0xF7 | 分段码=0x00 Master MACID
//
//★★★正常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x05 资源节点=0xF7 | 分段码=0x00
//★★★异常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x0F 资源节点=0xF7 | 分段码=0x00 ERRID
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
// order=
// *pCANFrame=CAN报文结构体(保存iCAN帧头、DLC、报文数据场数据)
//出口参数:
// 无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_UnConnectACK(uchar order, tCANFrame *pCANFrame)
{
ICAN_OBJ xdata ICAN_ObjIDTmp;
//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
if (function ==0 )
{
ICAN_ErrorIDACK(order, ErrID_NotConnect) ; // 错误代码返回报文连接不存在
}
//----------------------------------------------------------------------------------------------------------------
//检测命令帧报文第二字节的Master MACID是否和从站保存的Master MACID相同,若不相同,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
else if (pCANFrame->ucDataBuff[1] != ICAN_Source[order].Area[MasterMACID])
{
ICAN_ErrorIDACK(order, ErrID_NotConnect) ; // 错误代码返回报文连接不存在
return;
}
//----------------------------------------------------------------------------------------------------------------
//检测命令帧报文第一字节的分段码=0,若不等于0,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
else if ((pCANFrame->ucDataBuff[0]!=0))
{
ICAN_ErrorIDACK(order,ErrID_ParameterError); // 错误代码返回报文(参数非法)
}
//----------------------------------------------------------------------------------------------------------------
//取消建立连接,发送正常响应帧报文给主站
//----------------------------------------------------------------------------------------------------------------
else
{
function=0; // 取消建立连接
ICAN_ObjIDTmp.SourceID = 0xF7; // 资源节点编号
ICAN_ObjIDTmp.FUNCID = 0x05; // 功能码
ICAN_ObjIDTmp.ACK = 1; // 应答标志
ICAN_ObjIDTmp.DestMACID = ICAN_Source[order].Area[MasterMACID]; // 目标节点编号
ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID]; // 源节点编号
ICAN_Source[order].Area[MasterMACID] = NOMASTER; // 清除目标主站节点的MACID
ICAN_Source[order].Area[CyclicMaster] = 0; // 清除目标主站节点定时通信节拍数
ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp); // 生成ICAN报文ID
ICAN_TrBuff[order].ucXID = 1; // 0 标准帧;1 扩展帧
ICAN_TrBuff[order].ucDataLenth = 1; // 数据场长度1字节
ICAN_TrBuff[order].ucDataCtr = 0; // 读数据指针指0字节
ICAN_TrBuff[order].TrBegin = 1; // 发送开始标志置位
}
}
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_ResetACK(uchar order, tCANFrame *pCANFrame)
//功能描述=设备复位命令(功能码=0x06)
// “设备复位”命令帧用于复位从站设备。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★命令帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=0 功能码=0x06 资源节点=随机数 | 分段码=0x00 Master MACID
//
//★★★正常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x06 资源节点=随机数 | 分段码=0x00
//★★★异常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x0F 资源节点=随机数 | 分段码=0x00 ERRID
//
//说明:
//(1)、在“设备复位”命令帧中资源节点可以为任意地址,报文数据长度为 2 个字节,报文数据第一个字节表示分段码,
// 报文数据第二个字节表示目标节点 MAC ID。
//(2)、从站收到正确的“设备复位”命令后,如果从站支持命令复位功能,返回正常响应,随后设备重启。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
// order=
// *pCANFrame=CAN报文结构体(保存iCAN帧头、DLC、报文数据场数据)
//出口参数:
// 无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_ResetACK(uchar order, tCANFrame *pCANFrame)
{
ICAN_OBJ xdata ICAN_ObjIDTmp;
//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
if (function==0)
{
ICAN_ErrorIDACK(order, ErrID_NotConnect) ; // 错误代码返回报文连接不存在
return;
}
//----------------------------------------------------------------------------------------------------------------
//ICANSlav_ObjID=iCAN帧头的结构体(包含:源节点、目的节点、功能码、ACK、资源节点地址)
//如果iCAN帧头结构体中包含的源结点编号≠从站保存的Master MACID ,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
//这段指令的含义是判断连接是否存在,因为删除连接时,会将从站保存的Master MACID设置为不可能的节点编号(120)
//因此可能通过检测从站内部保存的Master MACID和iCAN帧头中的源节点编号是否相同来检测连接是否已经建立。
//----------------------------------------------------------------------------------------------------------------
if (ICAN_Source[order].Area[MasterMACID]!= ICANSlav_ObjID[order].SrcMACID)
{
ICAN_ErrorIDACK(order, ErrID_NotConnect) ; // 错误代码返回报文连接不存在
return;
}
//----------------------------------------------------------------------------------------------------------------
//检测命令帧报文第二字节的Master MACID是否和从站保存的Master MACID相同,若不相同,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
if ((pCANFrame->ucDataBuff[1] != ICAN_Source[order].Area[MACID]))
{
ICAN_ErrorIDACK(order, ErrID_ParameterError) ; // 错误代码返回报文参数非法(参数非法 错误码命令处理)
return;
}
//----------------------------------------------------------------------------------------------------------------
//如果不支持复位命令,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
if (FlagSystemResetEn)
{
ICAN_ErrorIDACK(order, ErrID_NotCommand) ; // 错误代码返回不支持复位命令
return;
}
ICAN_ObjIDTmp.SourceID = 0xF7; // 资源节点编号
ICAN_ObjIDTmp.FUNCID = 0x06; // 功能码
ICAN_ObjIDTmp.ACK = 1; // 应答标志
ICAN_ObjIDTmp.DestMACID = ICAN_Source[order].Area[MasterMACID]; // 目标节点编号
ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID]; // 源节点编号
ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp); // 生成ICAN报文ID
ICAN_TrBuff[order].ucXID = 1; // 0 标准帧;1 扩展帧
ICAN_TrBuff[order].ucDataLenth = 1; // 数据场长度1字节
ICAN_TrBuff[order].ucDataCtr = 0; // 读数据指针指0字节
ICAN_TrBuff[order].TrBegin = 1; // 发送开始标志置位
//复位的节点是本节点
//SystemReset();//系统复位标志
}
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_ReadACK(uchar order, uchar sourceID, tCANFrame *pCANFrame)
//功能描述=连续读端口命令(功能码=0x02)
// “连续读端口”命令帧用于读取指定资源节点中的数据。在命令帧中指定了所要读取的资源
// 节点首地址和读取的数据长度。从站接收到“连续读端口”命令后,如果判断命令帧有效,
// 就会将资源中的数据返回给主站。。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★访问资源节点命令帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=0 功能码=0x02 资源节点 | 分段码=0x00 Length
//
//说明:
//(1)、访问资源节点的“连续读端口”命令用于访问资源节点 0x00~0xF8。
//(2)、在访问资源节点的“连续读端口”命令帧中,报文数据部分第一个字节表示分段码(固定为 0x00) ,
// 第二个字节为所要读出的数据长度(Length<=32) 。使用“连续读端口”命令访问资源节点时,最
// 多允许读出 32个资源节点的数据。如果所读的字节数据超过 7 个字节,则从站使用分帧响应。
//
//★★★访问资源子节点命令帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=0 功能码=0x02 资源节点 | 分段码=0x00 SubIndex Length
//
//说明:
//(1)、访问资源子节点的“连续读端口”命令用于访问资源节点 0xF9~0xFF处的资源子节点。
//(2)、在访问资源子节点的“连续读端口”命令帧中,报文数据部分第一个字节表示分段码(固定为 0x00) ;
// 第二个字节为所要读的资源子节点;第三个字节为所要读出的数据长度(Length<=32) 。使用“连续
// 读端口”命令访问资源子节点时,最多允许读出 32个资源子节点的数据。如果所读的字节数据超过7个
// 字节,则从站使用分帧响应。
//
//★★★正常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x02 资源节点 | 分段码 1-7个字节
//
//说明:
//(1)、如果“连续读端口”命令帧中指定的资源段范围在从站中有效,从站使用正常响应返回主站读取的数据;
// 当主站请求的数据超过7个字节时,从站使用分段传输。“连续读端口”命令最多允许读出 32个资源节
// 点的数据。
//
//★★★异常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x0F 资源节点 | 分段码=0x00 ERRID
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
// order=
// *pCANFrame=CAN报文结构体(保存iCAN帧头、DLC、报文数据场数据)
//出口参数:
// 无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_ReadACK(uchar order, uchar sourceID, tCANFrame *pCANFrame)
{
ICAN_OBJ xdata ICAN_ObjIDTmp; // iCAN帧头的结构体
uchar i, j, k, l;
//----------------------------------------------------------------------------------------------------------------
//ICANSlav_ObjID=iCAN帧头的结构体(包含:源节点、目的节点、功能码、ACK、资源节点地址)
//如果iCAN帧头结构体中包含的源结点编号≠从站保存的Master MACID ,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
//这段指令的含义是判断连接是否存在,因为删除连接时,会将从站保存的Master MACID设置为不可能的节点编号(120)
//因此可能通过检测从站内部保存的Master MACID和iCAN帧头中的源节点编号是否相同来检测连接是否已经建立。
//----------------------------------------------------------------------------------------------------------------
if (ICAN_Source[order].Area[MasterMACID]!= ICANSlav_ObjID[order].SrcMACID) // 连接不存在 错误码命令处理
{
ICAN_ErrorIDACK(order, ErrID_NotConnect) ; // 错误代码返回报文连接不存在
return;
}
//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
if (function==0) // 连接不存在 错误码命令处理
{
ICAN_ErrorIDACK(order, ErrID_NotConnect) ; // 错误代码返回报文连接不存在
return;
}
//---------------------------------------------------------------------------------------------------------
//资源检测,返回1=资源非法,返回0=资源合法
//sourceID=资源节点编号
//pCANFrame->ucDataBuff[1]=iCAN命令帧第二字节(=访问资源节点Length)
//0=连续读端口标志
//---------------------------------------------------------------------------------------------------------
if (ICAN_SourceTest(order,sourceID,pCANFrame->ucDataBuff[1],0)) // 资源检测
{
ICAN_ErrorIDACK(order, ErrID_NotSourceID) ; // 错误代码返回报文资源不存在
return;
}
//-----------------------------------------------------------------------------------
//填写iCAN帧头结构体相关信息
//-----------------------------------------------------------------------------------
ICAN_ObjIDTmp.SourceID = ICANSlav_ObjID[order].SourceID; // 资源节点编号
ICAN_ObjIDTmp.FUNCID = 0x02; // 读功能码
ICAN_ObjIDTmp.ACK = 1; // 应答标志
ICAN_ObjIDTmp.DestMACID = ICAN_Source[order].Area[MasterMACID]; // 目标节点编号???????????????
ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID]; // 源节点编号?????????????????
//-----------------------------------------------------------------------------------
//填写iCAN读写缓存结构体
//-----------------------------------------------------------------------------------
ICAN_TrBuffR[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp); // 生成ICAN报文ID(iCAN帧头合成)
ICAN_TrBuffR[order].ucXID = 1; // 0 标准帧;1 扩展帧
i = sourceID; // 获取资源节点的地址
//------------------------------------------------------------------------------------------
//根据接收报文的帧头中的资源节点地址来判断当前是“连续读资源节点”还是“连续读资源子节点”
//------------------------------------------------------------------------------------------
if (i >= 0xF9)
{
k = pCANFrame->ucDataBuff[1]; // 读取资源节点的子地址(SubIndex)
j = pCANFrame->ucDataBuff[2]; // 读取资源长度(Length)
if (j >= 32) // 一次最多能读32单元超过则为无效,参数非法
{
ICAN_ErrorIDACK(order, ErrID_ParameterError); // 错误代码返回报文
return;
}
if ((i+j) > 0xFF) // 要读取的资源节点数量超过255,参数非法
{
ICAN_ErrorIDACK(order, ErrID_NotSourceID) ; // 错误代码返回报文
return;
}
//---------------------------------------------------------------------------------------------
//#define IOParameter 0xF8 // 输入/输出通道参数
//---------------------------------------------------------------------------------------------
if (i==IOParameter) // IO参数
{
if (j < 4) // 读取资源长度(Length)<4吗?
{ // 因为输入/输出通道参数只包含DILen,DOLen,AILen,AOLen=4
for (l = 0,k=0; l < j; l++, k++)
{
//将数据送入接收缓冲
ICAN_TrBuffR[order].ucDataBuff[l] = SourceType[order][k]; //读取指定单元的地址
}
}
else
{
ICAN_ErrorIDACK(order, ErrID_NotSourceID); // 错误代码返回报文,参数非法
return;
}
//---------------------------------------------------------------------------------------------
//#define IOConfigure 0xF9 // 输入/输出配置参数
//---------------------------------------------------------------------------------------------
//“配置资源” 用于设备标识、 通讯参数以及 I/O单元的配置, 占用资源节点 0xE0~0xFF。“配置资源”
//包括设备标识、通讯参数、I/O 属性和 I/O 配置,通过配置资源节点可以获取iCAN 从站设备的各种信息。
//---------------------------------------------------------------------------------------------
}
else if (i == IOConfigure) // IO配置
{
if (j < 32)
{
for (l = 0; l < j; l++, k++)
{
//将数据送入接收缓冲
ICAN_TrBuffR[order].ucDataBuff[l] = ICAN_IOconfig[order][k]; //读取指定单元的地址
}
}
else
{
ICAN_ErrorIDACK(order, ErrID_NotSourceID); // 错误代码返回报文,参数非法
return;
}
}
//---------------------------------------------------------------------------------------------
//读资源子节点的保留数据
//---------------------------------------------------------------------------------------------
else
{
}
}
//---------------------------------------------------------------------------------------------
//读取正常数据
//---------------------------------------------------------------------------------------------
else
{
j = pCANFrame->ucDataBuff[1]; // 读取资源节点长度
if (j >= 32) // 一次最多能读32单元超过则为无效,参数非法
{
ICAN_ErrorIDACK(order, ErrID_ParameterError); // 错误代码返回报文,参数非法
return;
}
if ((i+j) >0xFF) // 资源节点超过255,参数非法
{
ICAN_ErrorIDACK(order, ErrID_NotSourceID) ; // 错误代码返回报文,参数非法
return;
}
for (l = 0; l < j; l++, i++) // 将数据送入接收缓冲
{
ICAN_TrBuffR[order].ucDataBuff[l] = ICAN_Source[order].Area; //读取指定单元的地址
}
}
ICAN_TrBuffR[order].ucDataLenth = j + 1; // 数据场长度k字节
ICAN_TrBuffR[order].ucDataCtr = 0; // 读数据指针指0字节
ICAN_TrBuffR[order].TrBegin = 1; // 发送开始标志置位
}
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_WriteACK(uchar order, uchar sourceID, tCANFrame *pCANFrame)
//功能描述=连续写端口命令(功能码=0x01)
// “连续写端口”命令帧用于修改指定资源节点中的数据。在命令帧中指定了所要进行操
// 作的资源的首地址以及数据。从站接收到“连续写端口”命令后,如果判断命令帧有效,
// 就会保存命令中的数据到相应的资源节点位置。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★访问资源节点命令帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=0 功能码=0x01 资源节点 | 分段码 1~7个字节
//
//说明:
//(1)、访问资源节点的“连续写端口”命令用于访问资源节点 0x00~0xF8。
//(2)、在访问资源节点的“连续写端口”命令帧中,报文数据部分第一个字节为分段码,第二个字节
// 开始为所要写入的数据,当所要写入的数据超过 7 个字节时,则要使用分段传输。使用连续写
// 端口命令访问资源节点时,最多允许修改 32 个资源节点的数据。
//
//★★★访问资源子节点命令帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=0 功能码=0x01 资源节点 | 分段码 资源子节点 1~6个字节
//
//说明:
//(1)、访问资源子节点的“连续写端口”命令用于访问资源节点 0xF9~0xFF处的资源子节点。
//(2)、在访问资源子节点的“连续写端口”命令帧中,报文数据部分第一个字节为分段码,第二个字节为
// 要访问的资源子节点,第三个字节开始为所要写入的数据。当所要写入的数据超过 6个字节时,则
// 要使用分段传输,使用分段传输时,只有第一段命令帧的数据部分包含资源子节点,中间和结尾段
// 的命令帧的数据部分只包含分段码和传输的数据。使用连续写端口命令访问资源子节点时,最多允
// 许修改 32个资源子节点的数据。
//
//★★★正常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x01 资源节点 | 分段码=0x00
//
//说明:
//(1)、 如果“连续写端口”命令帧中指定的资源段范围在从站中有效,从站在正确处理接收到的数据后
// 返回正常响应。使用多段传输时,从站只有在接收完最后一段命令帧后才作出响应。
//
//★★★异常响应帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x0F 资源节点 | 分段码=0x00 ERRID
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
// order=
// *pCANFrame=CAN报文结构体(保存iCAN帧头、DLC、报文数据场数据)
//出口参数:
// 无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_WriteACK(uchar order, uchar sourceID, tCANFrame *pCANFrame)
{
static uchar WriteTest=0; // 全局变量,记录多帧传输前一分段编号
ICAN_OBJ xdata ICAN_ObjIDTmp; // iCAN帧头结构体
uchar i, j, l;
//----------------------------------------------------------------------------------------------------------------
//ICANSlav_ObjID=iCAN帧头的结构体(包含:源节点、目的节点、功能码、ACK、资源节点地址)
//如果iCAN帧头结构体中包含的源结点编号≠从站保存的Master MACID ,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
//这段指令的含义是判断连接是否存在,因为删除连接时,会将从站保存的Master MACID设置为不可能的节点编号(120)
//因此可能通过检测从站内部保存的Master MACID和iCAN帧头中的源节点编号是否相同来检测连接是否已经建立。
//----------------------------------------------------------------------------------------------------------------
if (ICAN_Source[order].Area[MasterMACID]!= ICANSlav_ObjID[order].SrcMACID) // 连接不存在,错误码命令处理
{
ICAN_ErrorIDACK(order, ErrID_NotConnect) ; // 错误代码返回报文连接不存在
return;
}
//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
if (function == 0) // 还没有建立连接, 错误码命令处理
{
ICAN_ErrorIDACK(order, ErrID_NotConnect); // 错误代码返回报文连接不存在
return;
}
//----------------------------------------------------------------------------------------------------------------
//获取分段标识子程序,入口参数如下:
//ICAN_ReBuff[order].ucDataCtr=接收缓冲区结构体读数据指针
//pCANFrame->ucDataBuff[0]=CAN报文结构体第一字节(存储分段码)
//返回:0=无分段
// 65=最后分段
// 1=第一分段
// 其它=中间分段
//----------------------------------------------------------------------------------------------------------------
i = ICAN_ObjByte0Restore(&ICAN_ReBuff[order].ucDataCtr, pCANFrame->ucDataBuff[0]); // 获取分段标识
//----------------------------------------------------------------------------------------------------------------
//数据接收完毕或者没有分段报文
//----------------------------------------------------------------------------------------------------------------
if (i == 65 || i == 0)
{
for (l = 1; l < pCANFrame->ucDLC; l++) // 将最后一帧或唯一的数据送入接收缓冲
{
ICAN_ReBuff[order].ucDataBuff[ICAN_ReBuff[order].ucDataCtr++] =pCANFrame->ucDataBuff[l]; // 读取CAN结构体中的数据到接收缓冲区
}
if (ICAN_ReBuff[order].ucDataCtr >= 32) //一次最多能读32单元超过则为无效,资源节点超过255也是非法
{
ICAN_ErrorIDACK(order, ErrID_ParameterError); // 错误代码返回报文,参数非法
return;
}
if (ICAN_SourceTest(order,ICANSlav_ObjID[order].SourceID,ICAN_ReBuff[order].ucDataCtr,1))
{ // 写端口时,资源检测
ICAN_ErrorIDACK(order, ErrID_NotSourceID); // 错误代码返回报文资源不存在
return;
}
if (ICANSlav_ObjID[order].SourceID >= 0xF9) // 写资源字节点地址
{
l = ICAN_ReBuff[order].ucDataBuff[0];//资源地址的子地址
if (i == IOParameter)
{//IO参数
if (ICAN_ReBuff[order].ucDataCtr < 5)
{//资源配置数量为4字节
for (j=1;j<ICAN_ReBuff[order].ucDataCtr;j++,l++){
//将接收缓冲数据送入目标资源
SourceType[order][l] = ICAN_TrBuff[order].ucDataBuff[j]; //读取指定单元的地址
}
}else{
//参数非法
ICAN_ErrorIDACK(order, ErrID_ParameterError) ;//错误代码返回报文//参数非法
return;
}
}else if(i==IOConfigure){//IO配置
if(ICAN_ReBuff[order].ucDataCtr<32){//资源配置数量为4字节
for(j=1;j<ICAN_ReBuff[order].ucDataCtr;j++,l++){
//将接收缓冲数据送入目标资源
ICAN_IOconfig[order][l] = ICAN_TrBuff[order].ucDataBuff[j]; //读取指定单元的地址
}
}else{
//参数非法
ICAN_ErrorIDACK(order, ErrID_ParameterError) ;//错误代码返回报文//参数非法
return;
}
}else{//其他资源子地址无效
//参数非法
ICAN_ErrorIDACK(order, ErrID_NotSourceID) ;//错误代码返回报文//参数非法
return;
}
}else{//写普通资源节点
i = sourceID; //获取资源节点的地址
if((i<0x20)||((i>=40)&&(i<60))){//只读区进行写
ICAN_ErrorIDACK(order, ErrID_OprationInvalid) ;//错误代码返回报文//操作无效
return;
}
for(j=0;j<ICAN_ReBuff[order].ucDataCtr;j++,i++){
ICAN_Source[order].Area=ICAN_ReBuff[order].ucDataBuff[j];//将数据写入对应的资源区
}
}
ICAN_ObjIDTmp.SourceID = ICANSlav_ObjID[order].SourceID; //资源节点编号
ICAN_ObjIDTmp.FUNCID = 0x01; //写功能码
ICAN_ObjIDTmp.ACK = 1; //应答标志
ICAN_ObjIDTmp.DestMACID = ICAN_Source[order].Area[MasterMACID]; //目标节点编号
ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID]; //源节点编号
ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp); //生成ICAN报文ID
ICAN_TrBuff[order].ucXID = 1; // 0 标准帧;1 扩展帧//
ICAN_TrBuff[order].ucDataLenth = 1; // 数据场长度1字节//
ICAN_TrBuff[order].ucDataCtr = 0; // 读数据指针指0字节//
ICAN_TrBuff[order].TrBegin = 1; //发送开始标志置位
WriteTest=0;//保护标志无效
}
//----------------------------------------------------------------------------------------------------------------
//接收到第一个段
//----------------------------------------------------------------------------------------------------------------
else if (i == 1)
{
if (WriteTest!=0) // 接收过程被重刷新
{
ICAN_ErrorIDACK(order, ErrID_WriteError) ; //错误代码返回报文,参数非法
return;
}
for (l = 1; l < 8; l++)
{
ICAN_ReBuff[order].ucDataBuff[ICAN_ReBuff[order].ucDataCtr++] =pCANFrame->ucDataBuff[l]; //读取缓冲区中的数据
}
WriteTest = 2; // 下一段为02段
}
//----------------------------------------------------------------------------------------------------------------
//数据接收中间段
//----------------------------------------------------------------------------------------------------------------
else
{
if (WriteTest != i) // 接收过程帧格式不正确
{
ICAN_ErrorIDACK(order, ErrID_ParameterError); // 错误代码返回报文//参数非法
return;
}
WriteTest++; // 指向下一个帧
for (l = 1; l < 8; l++) // 将数据送入接收缓冲
{
ICAN_ReBuff[order].ucDataBuff[ICAN_ReBuff[order].ucDataCtr++] =pCANFrame->ucDataBuff[l]; //读取缓冲区中的数据
}
if (ICAN_ReBuff[order].ucDataCtr >= 32) // 一次最多能读32单元超过则为无效,资源节点超过255也是非法
{
ICAN_ErrorIDACK(order, ErrID_ParameterError); // 错误代码返回报文,参数非法
return;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_CyclicACK(uchar order)
//功能描述=事件触发传送命令(功能码=0x03)
// 事件触发传送”命令用于 iCAN 从站主动向已建立连接的主站发送数据。iCAN 从站的
// “定时循环传送”和“事件触发传送”都使用该命令帧格式。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★命令帧格式
// CAN帧ID CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
// 源节点 目标节点 ACK=1 功能码=0x03 资源节点 | 分段码 输入端口数据
//
//说明:
//(1)、iCAN 从站根据输入端口的数据长度,决定是否采用分段传输。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
// order=
//出口参数:
// 无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_CyclicACK(uchar order)
{
ICAN_OBJ xdata ICAN_ObjIDTmp;
uchar i, j, l;
//----------------------------------------------------------------------------------------------------------------
//这段指令的含义是判断连接是否存在,因为删除连接时,会将从站保存的Master MACID设置为不可能的节点编号(120)
//因此可能通过检测从站内部保存的Master MACID和iCAN帧头中的源节点编号是否相同来检测连接是否已经建立。
//----------------------------------------------------------------------------------------------------------------
if (ICAN_Source[order].Area[MasterMACID] == NOMASTER )
{
ICAN_ErrorIDACK(order, ErrID_NotConnect); // 错误代码返回报文连接不存在
return;
}
// i=0x00; // (DI区)
// j = SourceType[order][0]; // 获取资源节点的地址(DI区)
i=0x40; // (AI区)
j = SourceType[order][2]; // 获取资源节点的地址(AI区)
ICAN_ObjIDTmp.SourceID =i; // 资源节点编号(AI区)
ICAN_ObjIDTmp.FUNCID = 0x03; // 事件触发传送命令功能码
ICAN_ObjIDTmp.ACK = 1; // 应答标志
ICAN_ObjIDTmp.DestMACID = ICAN_Source[order].Area[MasterMACID]; // 目标节点编号
ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID]; // 源节点编号
ICAN_TrBuffC[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp); // 生成ICAN报文ID
ICAN_TrBuffC[order].ucXID = 1; // 0 标准帧;1 扩展帧
for (l = 0; l < j; l++, i++) // 读取正常数据,最多读取32字节,将数据送入接收缓冲
{
ICAN_TrBuffC[order].ucDataBuff[l] = ICAN_Source[order].Area; // 读取指定单元的地址
}
ICAN_TrBuffC[order].ucDataLenth = j + 1; // 数据场长度k字节
ICAN_TrBuffC[order].ucDataCtr = 0; // 读数据指针指0字节
ICAN_TrBuffC[order].TrBegin = 1; // 发送开始标志置位
}
///////////////////////////////////////////////////////////////////////////////////////////
//ICAN模块从机通信接收子程序(Explain=解释, 说明)
///////////////////////////////////////////////////////////////////////////////////////////
void ICANRxMsgObjExplain(uchar order)
{
tCANFrame xdata CANFrame; // CAN报文结构体(存储CAN报文信息:DLC、DATA[0]-DATA[7],扩展帧=1,iCAN报文帧头合成)
//----------------------------------------------------------------------------------------------------------------
//有数据处理,需要处理数据
//----------------------------------------------------------------------------------------------------------------
if (ICAN_ControlInfo[order].ReDataCtr)
{
ICAN_ControlInfo[order].ReDataCtr--;
//----------------------------------------------------------------------------------------------------------------
//需要加入你的代码======
//----------------------------------------------------------------------------------------------------------------
// ?????需要加入你的代码
// ?????需要加入你的代码
// ?????需要加入你的代码
if (CAN_ucReadBuffer(pReceFrameBuff[order],&CANFrame) != EMPTY) //
{
// if (1)
{//如果到数据
//需要加入你的代码===================================================================
//如果数据不为空则处理
//----------------------------------------------------------------------------------------------------------------
//结构体CANFrame中保存的iCAN帧头合成信息--->结构体指针ICANSlav_ObjID
//----------------------------------------------------------------------------------------------------------------
ICAN_ObjIDRestore(&ICANSlav_ObjID[order], CANFrame.ulID); // ICAN报文标识码还原
switch (ICANSlav_ObjID[order].FUNCID)
{
case 0x01: // 用于对单个或者多个资源节点的数据写入
iCAN_WriteACK(order, ICANSlav_ObjID[order].SourceID, &CANFrame); // 写数据命令命令
break;
case 0x02: // 用于对单个或者多个资源节点的数据读取
iCAN_ReadACK(order, ICANSlav_ObjID[order].SourceID, &CANFrame); // 读数据命令命令
break;
case 0x03: // 返回0X0F出错响应
ICAN_ErrorIDACK(order, ErrID_NotFunctionID); // 错误代码返回报文
//iCAN_CyclicACK(order);
break;
case 0x04: // 用于和iCAN节点建立连接
iCAN_ConnectACK(order, &CANFrame); // 建立连接命令
break;
case 0x05: // 用于删除与iCAN节点建立的连接
iCAN_UnConnectACK(order, &CANFrame); // 建立连接命令
break;
case 0x06: // 用于复位iCAN节点
iCAN_ResetACK(order, &CANFrame); // 复位设备命令
break;
case 0x07: // MACID检测命令
if (ICANSlav_ObjID[order].ACK == 0) // ACK == 0(接收到检测命令)
{ // 用于响应网络上是否有相同MACID节点的检测
iCAN_MACIDTest(order,1); // 接收到MACID检测命令并返回响应命令
}
else // ACK == 1(接收到响应命令)
{
MACIDTemp = ICAN_Source[order].Area[MACID]; // 记录当前的MACID
ICAN_ControlInfo[order].MACIDTestStep = 9; // 检测到相同的MACID节点
}
break;
default:
ICAN_ErrorIDACK(order, ErrID_NotFunctionID) ; // 错误代码返回报文
break;
}
}
}
}
//-----------------------------------------------------------------------------
// ICAN模块从机通信处理程序
//-----------------------------------------------------------------------------
/*
void ICANSlaveISR(uchar order, unsigned long ulMsgObjID)
{
tCANFrame xdata CANFrame;
if (ulMsgObjID) {
//有中断产生
// 中断接收数据
for (i = 0; i < 4; i++) {
//对4个接收邮箱进行读数据处理
if (ulMsgObjID & (0x00000001 << (ulICANRxMsgNbrTbl - 1))) {
//只要有一个邮箱接收数据则进行处理
MsgObjectBuf.pucMsgData = CANFrame.ucDataBuff; //获取数据指针
CANMessageGet(pCAN_Node_Info[order]->ulChNr, ulICANRxMsgNbrTbl, &MsgObjectBuf, 1); //读取邮箱数据
if (pReceFrameBuff[order]->ucBufFull != 0) {
//接收缓冲区未满
CANFrame.ucXID = 1; //扩展ID
CANFrame.ulID = (MsgObjectBuf.ulMsgID & 0x1FFFFFFF); //读取ID内容
CANFrame.ucDLC = MsgObjectBuf.ulMsgLen; //获取数据长度
CAN_ucWriteBuffer(pReceFrameBuff[order], &CANFrame);// 把接收的数据写入指定的接收缓存
}
ICAN_ControlInfo[order].ReDataCtr++;
}
}
*/
/*
* 中断发送数据
for (i = 0; i < 4; i++) {
//对4个发送邮箱进行读数据处理
if ((ulMsgObjID & (0x00000001 << (pCAN_Node_Info[order]->ulTxMsgObjNr - 1)))) {//有中断生产
ClearIntFlag(pCAN_Node_Info[order], pCAN_Node_Info[order]->ulTxMsgObjNr);//清除发送中断标志
// if ((SendBuffToBus((void*)pCAN_Node_Info[order])) == 0) {
// //总线不忙
ICAN_ControlInfo[order].Idle = 0;
// }
}
}
}
} */
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//ICAN模块从机通信发送子程序(单帧发送报文)
//-----------------------------------------------------------------------------------------------------------------
//(1)、ICAN_TrBuff=通用报文发送缓冲区
//(2)、ICAN_TrBuffR=读应答报文发送缓冲区(专门应用于连续读端口命令,功能码=0x02)
//(3)、ICAN_TrBuffC=循环应答报文发送(专门应用于事件触发传送命令,功能码=0x03)
//(4)、ICAN_ControlInfo[order].Idle = 0(发送模块空闲)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ICANTxMsgObjSend(uchar order)
{
tCANFrame xdata CANFrame; // 定义CAN报文结构体
tICAN_RWBUFF *pICAN_TrBuff; // 定义一个从机ICAN节点资源读缓冲
uchar i;
if ((ICAN_TrBuff[order].TrBegin || ICAN_TrBuffR[order].TrBegin || ICAN_TrBuffC[order].TrBegin) && (ICAN_ControlInfo[order].Idle == 0))
{
//-----------------------------------------------------------------------------------------------------------------
//通用报文发送
//-----------------------------------------------------------------------------------------------------------------
if (ICAN_TrBuff[order].TrBegin)
{
pICAN_TrBuff = (tICAN_RWBUFF *)(&ICAN_TrBuff[order]);
}
//-----------------------------------------------------------------------------------------------------------------
//读应答报文发送
//-----------------------------------------------------------------------------------------------------------------
else if(ICAN_TrBuffR[order].TrBegin)
{
pICAN_TrBuff = &ICAN_TrBuffR[order];
}
//-----------------------------------------------------------------------------------------------------------------
//循环应答报文发送
//-----------------------------------------------------------------------------------------------------------------
else
{
pICAN_TrBuff = &ICAN_TrBuffC[order];
}
//-----------------------------------------------------------------------------------------------------------------
//下面开始将
//-----------------------------------------------------------------------------------------------------------------
//发送标志有效并且总组空闲
CANFrame.ulID = pICAN_TrBuff->ulID; // 生成ICAN报文ID(iCAN报文帧头)
CANFrame.ucXID = pICAN_TrBuff->ucXID; // 0 标准帧;1 扩展帧
CANFrame.ucDataBuff[0] = ICAN_ObjByte0Manage(pICAN_TrBuff->ucDataCtr, pICAN_TrBuff->ucDataLenth); // 生成分段码
if ((CANFrame.ulID & 0x00000F00) != 0x00000F00) // 如果当前不是发送《异常响应帧》
{
ICAN_ControlInfo[order].ConnectTOTimer = 0; // 连接超时定时清零(为正常功能码时,定时清0;为异常功能码时,不清0)
}
for (i = 1; i < 8; i++)
{
CANFrame.ucDataBuff = pICAN_TrBuff->ucDataBuff[pICAN_TrBuff->ucDataCtr]; // 获取8个字节(读取报文数据场1字节)
pICAN_TrBuff->ucDataCtr++; // 数据指针加1
if (pICAN_TrBuff->ucDataCtr >= pICAN_TrBuff->ucDataLenth)
{
//发送缓冲的数据没读取完毕
pICAN_TrBuff->TrBegin = 0; // 数据发送完毕
break; //退出
}
}
CANFrame.ucDLC = i; // 写入数据场长度
//===================================================================================================================
//加入你的发送缓冲代码
//===================================================================================================================
CAN_ucWriteBuffer(pSendFrameBuff[order], &CANFrame); // 将数据帧写入发送缓冲
if (SendBuffToBus((void*)pSendFrameBuff[order]))
{//数据发送
ICAN_ControlInfo[order].CyclicTimer = 0; // 此句为自己添加的,
//循环传送定时器清零,如果是循环发送数据的话,将从发送完应答信息之后开始;
ICAN_ControlInfo[order].Idle = 0; // 发送成功总线忙
SFRPAGE = CONFIG_PAGE;
P7MDOUT=0x03;
led0 =~led0; // 通信时,灯(P7.0)闪烁;
}
else
{//没有发送成功则继续
ICAN_ControlInfo[order].Idle = 2;
}
//===================================================================================================================
//===================================================================================================================
}
if (ICAN_ControlInfo[order].Idle == 2)
{//没有发送成功继续发送
if (SendBuffToBus((void*)pCAN_Node_Info[order]))
{//数据发送
ICAN_ControlInfo[order].Idle = 0; // 发送成功总线忙
SFRPAGE = CONFIG_PAGE;
P7MDOUT=0x03;
led0 =~led0; //通信时,灯(P7.0)闪烁;
}
}
}
uchar ICANTime1ms; // 处理通信延时计数器
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 定时器处理程序
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ICAN_DlyCtr(uchar order)
{
ICANTime1ms++; // 毫秒计数器加1
if (ICANTime1ms >= 10)
{
//累积到10MS(ICAN时间片单位)
ICANTime1ms -= 10; // 毫秒计数器减10
//ICANTime1ms = 0;
//----------------------------------------------------------------------------------------------------------------
//ICAN_ControlInfo[order].MACIDTestStep = 10,表示:MACID检测完成,正常通信
//----------------------------------------------------------------------------------------------------------------
if (ICAN_ControlInfo[order].MACIDTestStep == 10)
{
//----------------------------------------------------------------------------------------------------------------
//CyclicMaster的单位为 10ms,当 CyclicMaster > 0时, (CyclicMaster*4)时间为从站判断主站发送通讯报文的是否超时的时
//间间隔,在通讯过程中,如果从站在(CyclicMaster*4)时间内未收到主站的命令报文,将自动删除连接,退出通讯。当
//CyclicMaster为 0 时,从站不检测通讯超时,直到收到正确的“删除连接”命令帧时,才删除与主站的连接。
//----------------------------------------------------------------------------------------------------------------
if (ICAN_Source[order].Area[CyclicMaster]) // IF CyclicMaster > 0(如果不为0,则有连接超时)
{
if ((ICAN_ControlInfo[order].ConnectTOTimer >> 2) > ICAN_Source[order].Area[CyclicMaster])
{
//超过连接超时时间//连接定时器
ICAN_ControlInfo[order].ConnectTOFlag = 1; // 连接超时标志置位
}
else
{//连接未超时
ICAN_ControlInfo[order].ConnectTOFlag = 0; // 连接超时标志清零
ICAN_ControlInfo[order].ConnectTOTimer++; // 连接定时器+1
}
}
else // 没有连接超时
{
ICAN_ControlInfo[order].ConnectTOFlag = 0; // 连接超时标志清零
ICAN_ControlInfo[order].ConnectTOTimer = 0; // 连接超时定时器清零
}
//----------------------------------------------------------------------------------------------------------------
// CyclicParameter:定时循环参数, 当 CyclicParameter>0 时,按照 CyclicParameter设定定时参数,循环传送 I/O数据值;
// CyclicMaster:主站通讯定时参数,当 CyclicMaster>0 时, (CyclicMaster*4)时间为从站判断主站发送通讯报文的是否超时的时间间隔;
//----------------------------------------------------------------------------------------------------------------
if (ICAN_Source[order].Area[CyclicParameter])
{
//基于时间触发的通信//循环传送定时器
ICAN_ControlInfo[order].CyclicTimer++; // 循环传送定时器+1
if (ICAN_ControlInfo[order].CyclicTimer > ICAN_Source[order].Area[CyclicParameter])
{
//循环传送时间//循环传送定时器
ICAN_ControlInfo[order].CyclicParameterFlag = 1;// 循环传送标志置位
ICAN_ControlInfo[order].CyclicTimer = 0; // 循环传送定时器清零
}
}
else
{
//不存在基于时间触发的通信
ICAN_ControlInfo[order].CyclicParameterFlag = 0;// 循环传送标志清零
ICAN_ControlInfo[order].CyclicTimer = 0; // 循环传送定时器清零
}
}
else if (ICAN_ControlInfo[order].MACIDTestStep < 10)
{
//检测MACID两次
if (ICAN_ControlInfo[order].MACIDTestTimer < 101)
{
//MACID检测定时器小于1S
ICAN_ControlInfo[order].MACIDTestTimer++; // MACID检测定时器+1
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ican通信调度程序
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ICAN_Schedul(uchar order)
{
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo[order].MACIDTestStep = 10(进入正常通信)
//----------------------------------------------------------------------------------------
if (ICAN_ControlInfo[order].MACIDTestStep == 10)
{
if (ICAN_ControlInfo[order].CyclicParameterFlag) // 循环传送标志置位(定时传送时间到)
{
iCAN_CyclicACK(order); // 输入端口定时循环或者状态改变传送命令
ICAN_ControlInfo[order].CyclicParameterFlag = 0;
}
ICANRxMsgObjExplain(order); // ICAN模块从机通信接收子程序
ICANTxMsgObjSend(order); // ICAN模块从机通信发送子程序
}
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo[order].MACIDTestStep = 0(第一次正在生成MACID检测报文)
//----------------------------------------------------------------------------------------
else if (ICAN_ControlInfo[order].MACIDTestStep == 0) // 目的=检测有没有与自己相同的MACID
{
iCAN_MACIDTest(order,0); // 第一次生成MACID检测报文(发送方)
ICANTxMsgObjSend(order); // ICAN模块从机通信发送子程序
if (ICAN_ControlInfo[order].Idle == 0) // 如果发送成功
{
ICAN_ControlInfo[order].MACIDTestTimer=0; // MACID定时器清零
ICAN_ControlInfo[order].MACIDTestStep = 1; // 第一次等待超时
}
}
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo[order].MACIDTestStep = 1(第一次正在等等接收MACID应答报文过程)
//----------------------------------------------------------------------------------------
else if (ICAN_ControlInfo[order].MACIDTestStep == 1)
{
if (ICAN_ControlInfo[order].MACIDTestTimer > 100) // 超时时间到没有检测到响应报文
{
ICAN_ControlInfo[order].MACIDTestStep = 2; // 再检测一次
}
}
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo[order].MACIDTestStep = 2(第二次正在生成MACID检测报文)
//----------------------------------------------------------------------------------------
else if (ICAN_ControlInfo[order].MACIDTestStep == 2)
{
iCAN_MACIDTest(order,0); // 第二次生成MACID检测报文(发送方)
ICANTxMsgObjSend(order); // ICAN模块从机通信发送子程序
if (ICAN_ControlInfo[order].Idle == 0) // 如果发送成功
{
ICAN_ControlInfo[order].MACIDTestTimer=0; // MACID定时器清零
ICAN_ControlInfo[order].MACIDTestStep = 3; // 第二次等待超时
}
}
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo[order].MACIDTestStep = 3(第二次正在等等接收MACID应答报文过程)
//----------------------------------------------------------------------------------------
else if (ICAN_ControlInfo[order].MACIDTestStep == 3)
{
if (ICAN_ControlInfo[order].MACIDTestTimer > 100) // 超时时间到没有检测到响应报文
{
ICAN_ControlInfo[order].MACIDTestStep = 10; // 进入正常通信
}
}
//----------------------------------------------------------------------------------------
//其他情况(预操作状态)????????????????????????????????????????????????????????????????????
//----------------------------------------------------------------------------------------
else
{
if (MACIDTemp != ICAN_Source[order].Area[MACID]) // 等待MACID的改变
{
ICAN_ControlInfo[order].MACIDTestStep = 0; // 继续检测是否相同的MACID
}
}
} |
|