本文主要介绍了如何通过Anybus CompactCom 40 驱动程序设置与获取模块的MAC地址,首先是介绍了与MAC地址相关的对象、实例与属性,随后构建了获取模块MAC地址的命令序列。
适用产品
AB6605、AB6675、AB6604、AB6674、AB6603、AB6673
AB6610(烧写PROFINET、EtherNet/IP、Modbus TCP协议固件)、AB6680(烧写PROFINET、EtherNet/IP、Modbus TCP协议固件)
注意事项
本文简要的介绍了如何通过Anybus CompactCom 40驱动程序设置/获取模块MAC地址,更多详细信息请参考官网手册:
《Anybus CompactCom 40 - Software Design Guide》
《Anybus CompactCom 40 - Host Application Implementation Guide》
《Anybus CompactCom 40 - PROFINET IRT Network Guide》
PROFINET设备本身具有MAC地址,设备的每一个以太网端口也具有一个MAC地址,因此Anybus CompactCom M40/B40运行PROFINET协议接口时,具有一个设备MAC地址与2个端口MAC地址。
目录
- 与MAC地址有关的对象、实例、属性
- 设置模块MAC地址
- 获取模块MAC地址
与MAC地址有关的对象、实例、属性
- Anybus CompactCom 40模块固件中,已经预置了MAC地址,模块预置的MAC地址可以通过访问 Network Ethernet Object (0Ch)的实例1~3获取,实例2~3,PORT 1/2 MAC Address 仅适用于PROFINET协议。
-
模块预置的MAC地址可被驱动程序中 Ethernet Host Object (F9h)对象中设置的MAC地址覆盖,当Anybus CompactCom 40作为PROFINET协议接口时,设备MAC地址与端口地址值满足连续递增加一的关系,详情请参考《Anybus CompactCom 40 - PROFINET IRT Network Guide》14.8小节。
设置MAC地址
- 在驱动程序示例代码的\abcc_adapt\abcc_obj_cfg.h中,使能ETN_OBJ_ENABLE开关。
-
在\abcc_adapt\abcc_identification.h文件中找到ETN_IA_MAC_ADDRESS_ENABLE宏,并使能,将ETN_IA_MAC_ADDRESS_VALUE赋值为需要设置的MAC地址
-
- 如果模块运行PROFINET协议,在\abcc_adapt\abcc_obj_cfg.h中找到ETN_IA_PORT1_MAC_ADDRESS_ENABLE、ETN_IA_PORT2_MAC_ADDRESS_ENABLE宏定义并设置为TRUE,向ETN_IA_PORT1_MAC_ADDRESS_VALUE、ETN_IA_PORT1_MAC_ADDRESS_VALUE赋值,并注意其值与模块MAC地址的连续性。
-
-
设置完毕,模块上电后MAC地址会被驱动程序中设置的MAC地址覆盖。
获取MAC地址
通过驱动程序获取模块MAC地址,需要驱动发送Get_Attribute 命令到模块的Network Ethernet Object (0Ch)对象,首先定义获取模块MAC地址的命令序列(命令序列(Command sequencer)说明请参考《Anybus Compact 40 Host application implementation guide》第40页)。命令序列通过ABCC_CMD_SEQ( CmdBuilder1, RespHandler1 )方法添加命令序列中的单个命令。CmdBuilder1为命令构建函数的指针,RespHandler1为模块回复消息处理函数指针,无需处理命令的消息回复时可设置为NULL。
- 获取MAC地址可在模块初始化的过程中,也可在模块初始化完成后,根据实际需要选择,如果在驱动程序中使能了 Ethernet Host Object (F9h)对象定义的MAC地址设置宏,则在模块初始化时读取MAC地址是模块固件预置的,会被覆盖,若无需设置模块MAC地址且需要在模块上电后获取其MAC地址,可在用户初始化命令序列中添加获取模块MAC地址的命令,该命令序列已在驱动示例程序中定义。
-
static const ABCC_CmdSeqType appl_asUserInitCmdSeq[] =
{
ABCC_CMD_SEQ( UpdateIpAddress, NULL ),
ABCC_CMD_SEQ( UpdateNetmask, NULL ),
ABCC_CMD_SEQ( UpdateGateway, NULL ),
ABCC_CMD_SEQ( UpdateDhcp, NULL ),
ABCC_CMD_SEQ( UpdateNodeAddress, NULL ),
ABCC_CMD_SEQ( UpdateBaudRate, NULL ),
ABCC_CMD_SEQ( GetDeviceMAC, HandleGetDeviceMACResponse ),
ABCC_CMD_SEQ( GetPort1MAC, HandleGetport1MACResponse ),
ABCC_CMD_SEQ( GetPort2MAC, HandleGetport2MACResponse ),
ABCC_CMD_SEQ_END()
};
-
- 实现获取模块MAC地址的命令构建函数
-
ABCC_CmdSeqCmdStatusType GetDeviceMAC(ABP_MsgType* psMsg )函数:为提高命令执行的可靠性,可在函数中设置命令执行的判定条件,并通过函数返回值告知驱动该命令是否需要执行。命令构建函数返回值类型必须为ABCC_CmdSeqCmdStatusType,为一个枚举类型,其定义如下:
-
typedef enum ABCC_CmdSeqCmdStatus
{
ABCC_SEND_COMMAND,
ABCC_SKIP_COMMAND,
ABCC_CMD_ABORT_SEQ
}
ABCC_CmdSeqCmdStatusType;
-
-
ABCC_CmdSeqCmdStatusType GetDeviceMAC(ABP_MsgType* psMsg )
-
/*------------------------------------------------------------------------------
** Get Device MAC.
**------------------------------------------------------------------------------
*/
static ABCC_CmdSeqCmdStatusType GetDeviceMAC( ABP_MsgType* psMsg)
{
if((appl_fNwSupportsEthernetMAC)&&(appl_fNwGetEthernetMAC))
{
/*
**0x0c :Network Ethernet Object (0Ch)
**1:Instance code 1
**1:Attribute code 1
*/
ABCC_GetAttribute( psMsg, 0x0C, 1, 1, ABCC_GetNewSourceId() );
return ( ABCC_SEND_COMMAND );
}
else
return ( ABCC_SKIP_COMMAND );
}
-
-
由于MAC地址是驱动程序向模块读取,因此需要在驱动程序中处理获取的数据,构建模块响应消处理函数,该函数在命令执行完成后被驱动程序调用。
-
static ABCC_CmdSeqRespStatusType HandleGetDeviceMACResponse( ABP_MsgType* psMsg ),该函数的返回值固定为ABCC_CmdSeqRespStatusType,其值定义如下
-
typedef enum ABCC_CmdSeqRespStatus
{
ABCC_EXEC_NEXT_COMMAND,//执行命令序列中的下一个命令
ABCC_EXEC_CURR_COMMAND,//再次执行本命令
ABCC_RESP_ABORT_SEQ//终止整个命令序列
}
ABCC_CmdSeqRespStatusType;
-
- 函数代码示例,作为测试,此函数仅将MAC地址打印至驱动运行的log中。
-
/*------------------------------------------------------------------------------
** Handler Device MAC.
**------------------------------------------------------------------------------
*/
static ABCC_CmdSeqRespStatusType HandleGetDeviceMACResponse( ABP_MsgType* psMsg )
{
UINT8 bException;
if( ABCC_VerifyMessage( psMsg ) != ABCC_EC_NO_ERROR )
{
APPL_UnexpectedError();
return( ABCC_EXEC_NEXT_COMMAND );
}
/*
**user handler MAC
*/
/********eg:printf to log*******/
for(int i=0;i<6;i++)
{
if(i==0)
{
ABCC_PORT_DebugPrint( ( "Device MAC address is[0x%02X ", psMsg->abData[i] ) );
}
else if(i>0&&i<5)
{
ABCC_PORT_DebugPrint( ( "0x%02X ", psMsg->abData[i] ) );
}
else if(i==5)
{
ABCC_PORT_DebugPrint( ( "0x%02X]:\n\n", psMsg->abData[i] ) );
}
}
return ( ABCC_EXEC_NEXT_COMMAND );//ABCC_EXEC_NEXT_COMMAND
}
-
-
ABCC_CmdSeqCmdStatusType GetDeviceMAC(ABP_MsgType* psMsg )函数:为提高命令执行的可靠性,可在函数中设置命令执行的判定条件,并通过函数返回值告知驱动该命令是否需要执行。命令构建函数返回值类型必须为ABCC_CmdSeqCmdStatusType,为一个枚举类型,其定义如下:
-
如果模块运行PROFINET协议,则再分别实现获取端口1与端口2MAC地址的函数。
-
/*------------------------------------------------------------------------------
** Get Port1 MAC.
**------------------------------------------------------------------------------
*/
static ABCC_CmdSeqCmdStatusType GetPort1MAC( ABP_MsgType* psMsg)
{
UINT16 iNetworkType;
BOOL f_isPROFINET=0;
iNetworkType=ABCC_NetworkType();
if((iNetworkType==ABP_NW_TYPE_PIR)||
(iNetworkType==ABP_NW_TYPE_PRT))
{
f_isPROFINET=1;
}
if((appl_fNwSupportsEthernetMAC)&&(appl_fNwGetEthernetMAC)&&(f_isPROFINET))
{
ABCC_GetAttribute( psMsg, 0x0C, 1, 2, ABCC_GetNewSourceId() ); //port1 MAC
return ( ABCC_SEND_COMMAND );
}
else
return ( ABCC_SKIP_COMMAND );
}
/*------------------------------------------------------------------------------
** Get Port2 MAC.
**------------------------------------------------------------------------------
*/
static ABCC_CmdSeqCmdStatusType GetPort2MAC( ABP_MsgType* psMsg) //port2 MAC
{
UINT16 iNetworkType;
BOOL f_isPROFINET=0;
iNetworkType=ABCC_NetworkType();
if((iNetworkType==ABP_NW_TYPE_PIR)||
(iNetworkType==ABP_NW_TYPE_PRT))
{
f_isPROFINET=1;
}
if((appl_fNwSupportsEthernetMAC)&&(appl_fNwGetEthernetMAC)&&(f_isPROFINET))
{
ABCC_GetAttribute( psMsg, 0x0C, 1, 3, ABCC_GetNewSourceId());
return ( ABCC_SEND_COMMAND );
}
else
return ( ABCC_SKIP_COMMAND );
} - 消息处理函数
-
/*------------------------------------------------------------------------------
** Handler Port1 MAC.
**------------------------------------------------------------------------------
*/
static ABCC_CmdSeqRespStatusType HandleGetport1MACResponse( ABP_MsgType* psMsg )
{
UINT8 bException;
if( ABCC_VerifyMessage( psMsg ) != ABCC_EC_NO_ERROR )
{
APPL_UnexpectedError();
return( ABCC_EXEC_NEXT_COMMAND );
}
/******
user handler MAC
******/
/********eg:printf to log*******/
for(int i=0;i<6;i++)
{
if(i==0)
{
ABCC_PORT_DebugPrint( ( "PORT1 MAC address is[0x%02X ", psMsg->abData[i] ) );
}
else if(i>0&&i<5)
{
ABCC_PORT_DebugPrint( ( "0x%02X ", psMsg->abData[i] ) );
}
else if(i==5)
{
ABCC_PORT_DebugPrint( ( "0x%02X]:\n\n", psMsg->abData[i] ) );
}
}
return ( ABCC_EXEC_NEXT_COMMAND );//ABCC_EXEC_NEXT_COMMAND
/*------------------------------------------------------------------------------
** Handler Port2 MAC.
**------------------------------------------------------------------------------
*/
static ABCC_CmdSeqRespStatusType HandleGetport2MACResponse( ABP_MsgType* psMsg )
{
UINT8 bException;
if( ABCC_VerifyMessage( psMsg ) != ABCC_EC_NO_ERROR )
{
APPL_UnexpectedError();
return( ABCC_EXEC_NEXT_COMMAND );
}
/******
user handler MAC
******/
/********eg:printf to log*******/
for(int i=0;i<6;i++)
{
if(i==0)
{
ABCC_PORT_DebugPrint( ( "PORT2 MAC address is[0x%02X ", psMsg->abData[i] ) );
}
else if(i>0&&i<5)
{
ABCC_PORT_DebugPrint( ( "0x%02X ", psMsg->abData[i] ) );
}
else if(i==5)
{
ABCC_PORT_DebugPrint( ( "0x%02X]:\n\n", psMsg->abData[i] ) );
}
}
return ( ABCC_EXEC_NEXT_COMMAND );//ABCC_EXEC_NEXT_COMMAND ABCC_RESP_ABORT_SEQ
}
-
- 定义获取模块MAC地址命令序列执行条件判断的函数。
-
void Sdef_GetDeviceMAC(void)
{
UINT16 iNetworkType;
iNetworkType=ABCC_NetworkType();
if(iNetworkType==ABP_NW_TYPE_CCL||
iNetworkType==ABP_NW_TYPE_COP||
iNetworkType==ABP_NW_TYPE_PDPV0||
iNetworkType==ABP_NW_TYPE_PDPV1||
iNetworkType==ABP_NW_TYPE_COP||
iNetworkType==ABP_NW_TYPE_DEV||
iNetworkType==ABP_NW_TYPE_RTU||
iNetworkType==ABP_NW_TYPE_CNT)
{
appl_fNwSupportsEthernetMAC=FALSE;
}
else
{
appl_fNwSupportsEthernetMAC=TRUE;
}
-
- 定义应用层函数,用于驱动程序的主循环调用
-
void APPL_GetDeviceMAC_InInit(void)
{
if( appl_fUserInitDone == FALSE )
{
appl_fNwGetEthernetMAC=TRUE;
Sdef_GetDeviceMAC();
}
}
-
- 在main.c主循环中调用void APPL_GetDeviceMAC_InInit(void),调用位置如代码所示。
-
while(eAbccHandlerStatus == APPL_MODULE_NO_ERROR )
{
APPL_GetDeviceMAC_InInit();
eAbccHandlerStatus = APPL_HandleAbcc();
}
-
- 如果需要在模块运行过程中获取模块MAC地址,则需要用户自行定义命令序列,并调用。
- 命令序列定义如下
-
static const ABCC_CmdSeqType Sdef_GetDeviceMAC[] =
{define
ABCC_CMD_SEQ( GetDeviceMAC, HandleGetDeviceMACResponse ),
ABCC_CMD_SEQ( GetPort1MAC, HandleGetport1MACResponse ),
ABCC_CMD_SEQ( GetPort2MAC, HandleGetport2MACResponse ),
ABCC_CMD_SEQ_END()
};
-
- 命令序列定义如下
- 定义应用层函数,void APPL_GetDeviceMAC(void),用于调用自定义命令序列。
-
void APPL_GetDeviceMAC(void)
{
if( appl_fUserInitDone == TRUE )
{
appl_fNwGetEthernetMAC=TRUE;
Sdef_GetDeviceMAC();
ABCC_AddCmdSeq(Sdef_GetDeviceMAC,NULL);
}
}
-
- 在主循环中调用void APPL_GetDeviceMAC(void),本示例中通过模拟外部条件触发(如HMI、设备配置上位机软件等)的方式判断执行命令,本示例中的外部触发条件为串口接收触发指令(用户请根据需求自行实现触发方式),并在程序主循环中通过Switch语句判断指令类型并执行相应命令。
-
while(eAbccHandlerStatus == APPL_MODULE_NO_ERROR )
{
eAbccHandlerStatus = APPL_HandleAbcc();
//set attribute after abbc init through UART1 Command protocal further information in usart.c
if(appl_fUserInitDone==TRUE&&Sdef_NewCommandFlag==1)
{
switch(Sdef_setcommand)
{
case Sdef_GetDeviceMAC_Cmd://Get module MAC
APPL_GetDeviceMAC();
Sdef_NewCommandFlag=0;
break;
default:
def_NewCommandFlag=0;
break;
}
}
调用
-
- Message log
附加信息
以上代码仅作参考,不作为功能的最终实现,最终实现需要根据实际情况而定,请您先梳理该功能实现的流程,并参考官网英文手册实现功能需求。
官网手册下载地址如下: