Ethernet/IP#少し話しよ_07

Ethernet/IPについての第7話です。今回は実際CodesysのAPIのを使用しAdapterにExplicit Messageを送信し、Objectのデータをもらいます。使用するAdapterはPLCNEXTになりますが、別にCodesysでもTwinCATでもよいのです。PackagesをMirroringするためにPhonext Contact製のFL Switch 2008Fを使用します。

そしてTwinCATのAPIにかなりにていますので、また今度紹介させて頂きます。

Reference Link

Ethernet/IP関連の記事は以下のLinkでアクセスしてください↓

http://soup01.com/ja/category/protocol/ethernet-ip/

Configuration

こちらは今回の構成です。Raspberry piにCodesys Runtimeがインストールされ、EthernetIP Scannerを立ち上げています。AdapterはPhoenix Contact社のPLCNEXT AXCF-2152になります。そしてもう1台のパソコンはWiresharkを使用しPacketをMonitorします。すべてのネットワークはPhoenix Contact社のFL Swtich 2008Fに繋がります(そのスイッチはMirror機能があるので)

Switch Settings

PackageをMonitorするためにMirroring機能付きのスイッチを使用します。今回使用するのはPhoenix Contact製のFL SWITCH 2008Fです。

Access

スイッチを設定するにはまずWeb serverにアクセスする必要があります。IP・Host nameからも可能です。

by IP Address

IPからのアクセスはDefaultは169.254.2.1です。

もしSwtichのIPアドレスがわからないのならWiresharkを開いて、LLDP ProtocolのところにあるManagment AddressでSwtichのIPを確認できます。


By Host Name

もちろんHost Nameから直接アクセスできます。

アクセスするルールはswitch2000-xyzabcになります。

そのxyzabcはスイッチのMACアドレスの最後の6文字になります。

つまりこういうことですね。

Device Status

実際Webserver LoginしたらInfomrationでいまスイッチの情報を確認できます。

例えばDevice statusをクリックします。

HostNameが出てきますね!先のHost Nameからアクセスしたときとまったく一緒です。

Login

次はLoginしスイッチの設定を変更します。

Defaultでは、

Username:admin

password:private

になっています。

Loginが成功すれば、MenuからConfigurationとDiagnosticsの項目が表示されます。

Configure the Mirror Port

次はMirror Portを設定します。

Port Configurationをクリックします。

Port ConfigurationというPort設定画面が出てきます。

一番したにScrollすると、Port Mirroring のところにConfigure Port Mirroiringの項目があり、クリックしてください。

いよいよPort Mirroiringの構築画面でてきました。

まずGlobal StatusをEnableに変更します。

次はDestination Portを設定します。

Destination PortというのはMirroringされたPackageの行き先です。

今回はPort-8にします。

次はMirrored Port(Ingress)とMirrored Ports(Egress)を1,2,3,4のCheckboxに入れます。

そうすると、Port1,2,3,4の出入りしたPackagesがすべてPort8にMirrorするイメージです。ちなみに、IngressはRX Direction、EgressはTX Directionです。

最後はApply Changeを忘れずに。


PLCNEXT Side

0番目と127番目のWordに数字を書き込む、通信確認します。

Codesys API

Help>Contents>EtherNet/IP Configurator>LibrariesにCodesysのEthernet/ip APIの説明があります。

Get Scanner/Adapter Status

では最初ににScannerとAdpater Interfaceの状態をMonitorしてみましょう。

Sample Code

Adapterstatus:=AXC_F_2152_Adapter1.eState;

AdapterState 

This I/O Driver offers an EtherNet/IP Scanner and an EtherNet/IP Remote Adapter.

Adapter名はそのままEtherNet/IP IEC Objectとなり、プログラム内で使用できます。

,

Status Table

StatusDescription
DISABLED0デバイスが無効してる
NOT_CONFIGUREDIP_CONFIGがDefaultの状態
IP_CONIFGIPとPortがセットアップ中IPが無効であれば、BUS_ERRORの状態に移行IPが有効であれば、ENCAPSULATION_CONFIGの状態に移行
ENCAPSULATION_CONFIGClientにTCP Portが開きます正常なら、LIST_SERVICES状態に移行エラーなら、BUS_ERROR状態に移行
LIST_SERVICESREGISTER_SESSION状態移行まえのBuffer
PARAMETER_CONFIGUserパラメタが送信する状態エラーあってもログメッセージが生成するだけでそのままCONFIGURED状態に移行
CONFIGUREDForward openリクエストを処理します接続成功や場合によりMulticastアドレスに参加OKの場合、RUNNINGに移行します。ほかにForward OpenをRetryします。
RUNNINGすべてのConnectionが確立されました。IOデータは交換しています。
RESETRemoteAdapterにリセットTriggerする
RESET_SERVICEネットワーク全体にCIP Reset ServiceをTriggerする
CONNECTIVITY_CHECKAUTO_RESETが使用するとき、Connectionが切断した場合はその状態に移行します。そして復旧するとCONFIGURED状態にも戻ります。
BUS_ERRORAUTO_RESETが使用しないとき、Adapterがこの状態に移行します。
ERRORパラメタの不一致やメモリ足りないやConnectionに問題ある

Code

VAR
PROGRAM PLC_PRG
VAR
status:IoDrvEthernetip.AdapterState;
END_VAR
PROGRAM
status:=AXC_F_2152_Adapter1.eState;

Result

RUNNING

AdapterがRunningの状態です。

ERROR

AdapterがErrorの状態です。

ScannerState

StatusDescription
INITIALIZINGCIP Objectを初期化してます。IP_CONFIGに移行
DISABLEDScannerが無効になっています。
IP_CONFIG使用してるEthernet InterfaceにIP設定などを行い、IoDrvEthernet->EthernetState->RUNNINGまで待ちます。RUNNINGになるとUDP_CONFIG移行します。エラーになるとTCPIP_CONFIG_ERRORに移行します。
UDP_CONFIGUDPのDefault Port2222を開きます。エラーならScannerState.BUS_ERRORに移行します。
ENCAPSULATION_CONFIG
ADAPTER_CONFIGBuffer StatueでOPEN_CONNECTIONSに移行。
OPEN_CONNECTIONSCIP Identity StatusをConfiguredに変更し、StateをRUNNINGにします。
RUNNNINGAdapterと切断しOデータやExplict messageを処理する
DIAGNOSTIC_AVAILABLERunningと同じく、でも診断情報があり
BUS_ERRORUDP/TCP Portは開放できない。INITIALIZING状態に戻ります。
RESETCIP Identity ObjectにxResetが受信すると、この状態に移行します。
ERRORエラー

Code

VAR
PROGRAM PLC_PRG
VAR
Adapterstatus:IoDrvEthernetip.AdapterState;
Scannerstatus:IoDrvEthernetip.ScannerState;
END_VAR
PRGORAM
Adapterstatus:=AXC_F_2152_Adapter1.eState;
Scannerstatus:=EtherNet_IP_Scanner.eState;

Result

たとえばいまScannerが無効になっている状態です。

Get_Attribute_Single

Ethernet/IPのObjectにGet_Attribute_SingleのExplict Messageを送信します。

VAR_INPUT

NameTypeDescription
xExecuteBOOL立ち上げで実行
itfEtherNetIPDeviceIEtherNetIPService該当するEIP Object
eClassCIPClassServices対象のCIP Class
dwInstanceDWORDCIP ClassのInstance番号
wAttributeWORD該当するInstanceのAttribute番号
pDataPOINTER TO BYTE取得したデータ転送先のMemory Offset、ADR()関数を使用すればOK
udiDataSizeUDINTデータ転送先のMemorayサイズ、SizeOf()関数を使用すればOK

VAR_OUT

NameTypeDescription
eErrorERRORTrue=エラー発生
udiReceivedDataSizeUDINTEhternetIP Objectから取得したデータのサイズ(Byte)


Get_Attribute_All

Ethernet/IPのObjectにGet_Attribute_AllのExplict Messageを送信します。

VAR_INPUT

NameTypeDescription
xExecuteBOOL立ち上げで実行
itfEtherNetIPDeviceIEtherNetIPService該当するEIP Object
eClassCIPClassServices対象のCIP Class
dwInstanceDWORDCIP ClassのInstance番号
wAttributeWORD該当するInstanceのAttribute番号
pDataPOINTER TO BYTE取得したデータ転送先のMemory Offset、ADR()関数を使用すればOK
udiDataSizeUDINTデータ転送先のMemorayサイズ、SizeOf()関数を使用すればOK

VAR_OUT

NameTypeDescription
eErrorERRORTrue=エラー発生
udiReceivedDataSizeUDINTEhternetIP Objectから取得したデータのサイズ(Byte)


Code sys

各Objectは昔の記事で説明したことがありますので、ここで詳しく説明しません。

EIP Object

Object 0x01

DUT_EIP_Instance01

ObjectのAttribute構造に合わせてData Unit Typeを作成します。

TYPE DUT_EIP_Instance01 :
STRUCT
VendorID :UINT;
DeviceType :UINT;
ProductCode :UINT;
Revision_Major :USINT;
Revision_Minor :USINT;
Status :UINT;
SerialNumber :UINT;
ProductName :STRING(31);
State :UINT;
ConfigurationConsistencyValue             :UINT;
HeatbeatInterval       :UINT;
END_STRUCT
END_TYPE


Object 0xF5

ObjectのAttribute構造に合わせてData Unit Typeを作成します。

場合によってさらにSub-DUTを追加します。

DUT_EIP_InstanceF5_Attribute001 

TYPE DUT_EIP_InstanceF5_Attribute001 :
STRUCT
InterfaceConfigurationStatus                   :WORD;
MCastPending       :BIT;
InterfaceConfigurationPending                   :BIT;
ACDStatus       :BIT;
ACDFault       :BIT;
IANAPortAdminChangePending             :BIT;
IANAProtocolAdminChangePending             :BIT;
zzzb06 :BIT;
zzzb07 :BIT;
zzzb08 :BIT;
zzzb09 :BIT;
zzzb10 :BIT;
zzzb11 :BIT;
zzzb12 :BIT;
zzzb13 :BIT;
zzzb14 :BIT;
zzzb15 :BIT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute001

TYPE DUT_EIP_InstanceF5_Attribute001 :
STRUCT
InterfaceConfigurationStatus :WORD;
MCastPending :BIT;
InterfaceConfigurationPending :BIT;
ACDStatus :BIT;
ACDFault :BIT;
IANAPortAdminChangePending             :BIT;
IANAProtocolAdminChangePending             :BIT;
zzzb06 :BIT;
zzzb07 :BIT;
zzzb08 :BIT;
zzzb09 :BIT;
zzzb10 :BIT;
zzzb11 :BIT;
zzzb12 :BIT;
zzzb13 :BIT;
zzzb14 :BIT;
zzzb15 :BIT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute003

TYPE DUT_EIP_InstanceF5_Attribute003 :
STRUCT
ConfigurationMethodBit0             :BIT;
ConfigurationMethodBit1             :BIT;
ConfigurationMethodBit2             :BIT;
ConfigurationMethodBit3             :BIT;
DNSEnable       :BIT;
zzzb05 :BIT;
zzzb06 :BIT;
zzzb07 :BIT;
zzzb08 :BIT;
zzzb09 :BIT;
zzzb10 :BIT;
zzzb11 :BIT;
zzzb12 :BIT;
zzzb13 :BIT;
zzzb14 :BIT;
zzzb15 :BIT;
zzzw1       :WORD;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute004

TYPE DUT_EIP_InstanceF5_Attribute004 :
STRUCT
PathLength :WORD;
Path :ARRAY[0..5] OF BYTE;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute005 

TYPE DUT_EIP_InstanceF5_Attribute005 :
STRUCT
IPAddress :ARRAY[0..3]OF BYTE;
SubNetMask :ARRAY[0..3]OF BYTE;
GateWay :ARRAY[0..3]OF BYTE;
NameServer :ARRAY[0..3]OF BYTE;
NameServer2 :ARRAY[0..3]OF BYTE;
DominName :UINT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute006 

TYPE DUT_EIP_InstanceF5_Attribute006 :
STRUCT
Length :UINT;
HostName :STRING(30);
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute007 

TYPE DUT_EIP_InstanceF5_Attribute007 :
STRUCT
SafetyNetworkNumberTime :DINT;
SafetyNetworkNumberDate :INT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute008 

TYPE DUT_EIP_InstanceF5_Attribute008 :
STRUCT
TTL:BYTE;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute009 

TYPE DUT_EIP_InstanceF5_Attribute009 :
STRUCT
AllocControl :BYTE;
zz01 :BYTE;
NumMCast :UINT;
MCastStartAddr :ARRAY[0..3]OF BYTE;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute010 

TYPE DUT_EIP_InstanceF5_Attribute010 :
STRUCT
SelectACD :BYTE;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute011 

TYPE DUT_EIP_InstanceF5_Attribute011 :
STRUCT
ACDActivity :BYTE;
RemoteMac :ARRAY[0..5]OF BYTE;
ArpPDU :ARRAY[0..27]OF BYTE;

END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute012 

TYPE DUT_EIP_InstanceF5_Attribute012 :
STRUCT
EncapsulationTimeout :INT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5_Attribute013 

TYPE DUT_EIP_InstanceF5_Attribute013 :
STRUCT
QuickConnect :BYTE;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF5 

TYPE DUT_EIP_InstanceF5 :
STRUCT
Attribute001:DUT_EIP_InstanceF5_Attribute001;
Attribute002:DUT_EIP_InstanceF5_Attribute002;
Attribute003:DUT_EIP_InstanceF5_Attribute003;
Attribute004:DUT_EIP_InstanceF5_Attribute004;
Attribute005:DUT_EIP_InstanceF5_Attribute005;
Attribute006:DUT_EIP_InstanceF5_Attribute006;
Attribute007:DUT_EIP_InstanceF5_Attribute007;
Attribute008:DUT_EIP_InstanceF5_Attribute008;
Attribute009:DUT_EIP_InstanceF5_Attribute009;
Attribute010:DUT_EIP_InstanceF5_Attribute010;
Attribute011:DUT_EIP_InstanceF5_Attribute011;
Attribute012:DUT_EIP_InstanceF5_Attribute012;
Attribute013:DUT_EIP_InstanceF5_Attribute013;
END_STRUCT
END_TYPE

Object 0xF6

DUT_EIP_InstanceF6_Attribute001 

ObjectのAttribute構造に合わせてData Unit Typeを作成します。

場合によってさらにSub-DUTを追加します。

TYPE DUT_EIP_InstanceF6_Attribute001 :
STRUCT
InterfaceSpeed :UDINT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute002 

TYPE DUT_EIP_InstanceF6_Attribute002 :
STRUCT
LinkStatus :BIT;
Duplex :BIT;
NegotiationStatus1 :BIT;
NegotiationStatus2 :BIT;
NegotiationStatus3 :BIT;
ManualResetReq :BIT;
LocalHardwareFault :BIT;
zzzBit08 :BIT;
zzzBit09 :BIT;
zzzBit10 :BIT;
zzzBit11 :BIT;
zzzBit12 :BIT;
zzzBit13 :BIT;
zzzBit14 :BIT;
zzzBit15 :BIT;
zzzBit16 :BIT;
zzzBit17 :BIT;
zzzBit18 :BIT;
zzzBit19 :BIT;
zzzBit20 :BIT;
zzzBit21 :BIT;
zzzBit22 :BIT;
zzzBit23 :BIT;
zzzBit24 :BIT;
zzzBit25 :BIT;
zzzBit26 :BIT;
zzzBit27 :BIT;
zzzBit28 :BIT;
zzzBit29 :BIT;
zzzBit30 :BIT;
zzzBit31 :BIT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute003 

TYPE DUT_EIP_InstanceF6_Attribute003 :
STRUCT
PhysicalAddress :ARRAY[0..5]OF BYTE;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute004 

TYPE DUT_EIP_InstanceF6_Attribute004 :
STRUCT
InOctets :UDINT;
InUcastPackets :UDINT;
InNUcastPackets :UDINT;
InDiscords :UDINT;
InErrors :UDINT;
InUnknownProtos :UDINT;
OutOctets :UDINT;
OutUcastPackets :UDINT;
OutNUcastPackets :UDINT;
OutDiscords :UDINT;
OutErrors :UDINT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute005 

TYPE DUT_EIP_InstanceF6_Attribute005 :
STRUCT
AlignementErrors :UDINT;
FCSErrors :UDINT;
SingleCollisions :UDINT;
MultipleCollisions :UDINT;
SQETestErrors :UDINT;
DeferredTransission :UDINT;
LateCollisions :UDINT;
ExcessiveCollisions :UDINT;
MACTransmitErrors :UDINT;
CarrierSenseErrors :UDINT;
FrameTooLong :UDINT;
MACReceiveErrors :UDINT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute006 

TYPE DUT_EIP_InstanceF6_Attribute006 :
STRUCT
//Intetface Control
AutoNegotiate :BIT;
ForcedDuplexMode :BIT;
zzz002 :BIT;
zzz003 :BIT;
zzz004 :BIT;
zzz005 :BIT;
zzz006 :BIT;
zzz007 :BIT;
zzz008 :BIT;
zzz009 :BIT;
zzz010 :BIT;
zzz011 :BIT;
zzz012 :BIT;
zzz013 :BIT;
zzz014 :BIT;
zzz015 :BIT;
ForceInterfaceSpeed :UINT;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute007

TYPE DUT_EIP_InstanceF6_Attribute007 :
STRUCT
//Interface Type
TwistedPair :BYTE;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute008 

TYPE DUT_EIP_InstanceF6_Attribute008 :
STRUCT
//Interface State
InterfaceState :BYTE;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute009

TYPE DUT_EIP_InstanceF6_Attribute009 :
STRUCT
//Alarm State
AlarmState :BYTE;
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute010

TYPE DUT_EIP_InstanceF6_Attribute010 :
STRUCT
//Ethernet Label
PathLength :BYTE;
PathName :STRING(30);
END_STRUCT
END_TYPE

DUT_EIP_InstanceF6_Attribute011

TYPE DUT_EIP_InstanceF6_Attribute011 :
STRUCT
//Intetface Capability
ManualSettingReqReset             :BIT;
AutoNegotiate       :BIT;
AutoMDIX       :BIT;
ManualSpeed       :BIT;
zzz004 :BIT;
zzz005 :BIT;
zzz006 :BIT;
zzz007 :BIT;
zzz008 :BIT;
zzz009 :BIT;
zzz010 :BIT;
zzz011 :BIT;
zzz012 :BIT;
zzz013 :BIT;
zzz014 :BIT;
zzz015 :BIT;
zzz016 :BIT;
zzz017 :BIT;
zzz018 :BIT;
zzz019 :BIT;
zzz020 :BIT;
zzz021 :BIT;
zzz022 :BIT;
zzz023 :BIT;
zzz024 :BIT;
zzz025 :BIT;
zzz026 :BIT;
zzz027 :BIT;
zzz028 :BIT;
zzz029 :BIT;
zzz030 :BIT;
zzz031 :BIT;
SpeedArrayCount :BYTE;
END_STRUCT
END_TYPE


DUT_EIP_InstanceF6

TYPE DUT_EIP_InstanceF6 :
STRUCT
Attribute001 :DUT_EIP_InstanceF6_Attribute001;
Attribute002 :DUT_EIP_InstanceF6_Attribute002;
Attribute003 :DUT_EIP_InstanceF6_Attribute003;
Attribute004 :DUT_EIP_InstanceF6_Attribute004;
Attribute005 :DUT_EIP_InstanceF6_Attribute005;
Attribute006 :DUT_EIP_InstanceF6_Attribute006;
Attribute007 :DUT_EIP_InstanceF6_Attribute007;
Attribute008 :DUT_EIP_InstanceF6_Attribute008;
Attribute009 :DUT_EIP_InstanceF6_Attribute009;
Attribute010 :DUT_EIP_InstanceF6_Attribute010;
Attribute011 :DUT_EIP_InstanceF6_Attribute011;
END_STRUCT
END_TYPE

Object 0x04

Object0x04 Assembly ObjectはSenderとReceiverお互いになにかやりとりするかをわかってる前提としなので、ここで特にDUTを定義する必要がありません。

注意するのはObject0x04からAttrbuteを取得するときはGET_Attribute_Singleを使用してください。

Assblemly_Out_FromExplictMessages:ARRAY[0..255]OF BYTE;
Assblemly_In_FromExplictMessages:ARRAY[0..255]OF BYTE;

Implementation

プログラムはInterfaceの初期化>自動エラーリセット>Get_Attribute_AllでObject 0x01,0xF5,0xF6を取得します。同時にGet_Attribute_SignleでObject0x04のAssembly ObjectのIO データを取得します。

VAR

PROGRAM PLC_PRG
VAR
//Get Attribute All
//Instance Data
Instance00:DUT_EIP_Instance00;
Instance01:DUT_EIP_Instance01;
InstanceF5:DUT_EIP_InstanceF5;
InstanceF6:DUT_EIP_InstanceF6;
RawData_GetAttribute_All:ARRAY[0..999]OF BYTE;
RawDataSize_GetAttribute_All:UDINT;
//FunctionBlock
Get_Attributes_All:enip.Get_Attributes_All;
//Flow Control
bFilled_GetAttribute_All:BOOL;
iStep_GetAttribute_All:INT:=0;
R_TRIG_Get_Attributes_All:R_TRIG;
bExecute_GetAttribute_All:BOOL;
TON_Get_Attribute_Flow_Init:TON;
SourceOffset:UDINT;
NumberOfBytes:UDINT;
//Get Attribute Single
//Instance Data
RawData_Get_Attribute_Single:ARRAY[0..999]OF BYTE;
RawDataSize_GetAttribute_Single:UDINT;
Assblemly_6E_DataSize_FromExplictMessages:UDINT;
Assblemly_64_DataSize_FromExplictMessages:UDINT;
Assblemly_Out_FromExplictMessages:ARRAY[0..255]OF BYTE;
Assblemly_In_FromExplictMessages:ARRAY[0..255]OF BYTE;
//Function Block
Get_Attribute_Single:ENIP.Get_Attribute_Single;
//Flow Control
bExecute_GetAttributeSignle:BOOL;
iStep_GetAttribute_Single:INT:=0;
bFilded_GetAttribute_Single:BOOL;
TON_Get_Attribute_Single_Flow_Init:TON;
//Information
Adapterstatus:IoDrvEthernetip.AdapterState;
Scannerstatus:IoDrvEthernetip.ScannerState;
status:IoDrvEthernet.EthernetState;
DeviceName:STRING;
IPAddress:STRING;
bReset:BOOL;
TON_AutoReset:TON;
//IO From/TO PLCNEXT
AssOut_FromImplictMessages:ARRAY[0..255]OF BYTE;
AssIn_FromImplicMessages:ARRAY[0..255]OF BYTE;
temp:BYTE;
END_VAR

VAR CONSTANT
ENIP_ClassInstance :INT:=0;
ENIP_Assblemly_OutputInstance :DWORD:=16#6E;
ENIP_Assblemly_InputInstance :DWORD:=16#64;
cStep_Init :INT:=0;
cStep_GetAttribute_00 :INT:=20;
cStep_GetAttribute_00_wait :INT:=25;
cStep_GetAttribute_01 :INT:=30;
cStep_GetAttribute_01_wait :INT:=35;
cStep_GetAttribute_F5 :INT:=40;
cStep_GetAttribute_F5_wait :INT:=45;
cStep_GetAttribute_F6 :INT:=50;
cStep_GetAttribute_F6_wait :INT:=60;
cStep_GetAttribute_Assembly_init :INT:=0;
cStep_GetAttribute_Assembly_Output :INT:=20;
cStep_GetAttribute_Assembly_Output_wait :INT:=25;
cStep_GetAttribute_Assembly_Input :INT:=30;
cStep_GetAttribute_Assembly_Input_wait :INT:=35;
END_VAR

PROGRAM

//Get the Ethernet,Scanner and Adapter Status
Adapterstatus:=AXC_F_2152_Adapter1.eState;
Scannerstatus:=EtherNet_IP_Scanner.eState;

//Get Ethernet Status
status:=Ethernet.eState;
DeviceName:=Ethernet.DeviceName;
IPAddress:=IoDrvEthernet.IPARRAY_TO_IPSTRING(Ethernet.IPAddress);

//Auto Reset
TON_AutoReset(
IN:= NOT TON_AutoReset.Q
AND  Adapterstatus <> IoDrvEthernetip.AdapterState.RUNNING
,PT:=T#0.2S
);
AXC_F_2152_Adapter1.xReset:=TON_AutoReset.Q;
AXC_F_2152_Adapter1.xAcknowledge:=TON_AutoReset.Q;

//Using Explict Message to send the GetAttributeAll messages
CASE iStep_GetAttribute_All OF
//Init
cStep_Init:
bFilled_GetAttribute_All:=FALSE;
TON_Get_Attribute_Flow_Init(
IN:=TRUE
,PT:=T#0.2S
);
IF TON_Get_Attribute_Flow_Init.Q  THEN
TON_Get_Attribute_Flow_Init(
IN:=FALSE
);
iStep_GetAttribute_All:=cStep_GetAttribute_01;
END_IF
//0x01 IdentityObject
cStep_GetAttribute_01:
Get_Attributes_All.dwInstance:=1;
bExecute_GetAttribute_All:=TRUE;
Get_Attributes_All.eClass:= ENIP.CIPClass.IdentityObject;
iStep_GetAttribute_All:=cStep_GetAttribute_01_wait;

cStep_GetAttribute_01_wait:
IF bFilled_GetAttribute_All THEN
bFilled_GetAttribute_All:=FALSE;
iStep_GetAttribute_All:=cStep_GetAttribute_F5;
END_IF
//0xF5 TCPIPInterfaceObject
cStep_GetAttribute_F5:
Get_Attributes_All.dwInstance:=1;
bExecute_GetAttribute_All:=TRUE;
Get_Attributes_All.eClass:= ENIP.CIPClass.TCPIPInterfaceObject;
iStep_GetAttribute_All:=cStep_GetAttribute_f5_wait;
cStep_GetAttribute_F5_wait:
IF bFilled_GetAttribute_All THEN
bFilled_GetAttribute_All:=FALSE;
iStep_GetAttribute_All:=cStep_GetAttribute_F6;
END_IF
//0xF6 EthernetLinkObject
cStep_GetAttribute_F6:
Get_Attributes_All.dwInstance:=1;
bExecute_GetAttribute_All:=TRUE;
Get_Attributes_All.eClass:= ENIP.CIPClass.EthernetLinkObject;
iStep_GetAttribute_All:=cStep_GetAttribute_F6_wait;
cStep_GetAttribute_F6_wait:
IF bFilled_GetAttribute_All THEN
bFilled_GetAttribute_All:=FALSE;
iStep_GetAttribute_All:=cStep_GetAttribute_01;
END_IF
END_CASE



//Get Attribute All Function block
Get_Attributes_All(
itfEtherNetIPDevice:=AXC_F_2152_Adapter1
,xExecute:=bExecute_GetAttribute_All
,pData:=ADR(RawData_GetAttribute_All)
,udiDataSize:=SIZEOF(RawData_GetAttribute_All)
,udiReceivedDataSize=>RawDataSize_GetAttribute_All
);
//If Function Block is Done
R_TRIG_Get_Attributes_All(
CLK:=Get_Attributes_All.xDone
);

//Data Encode
IF Get_Attributes_All.xDone
OR Get_Attributes_All.xError 
THEN
CASE Get_Attributes_All.eClass OF
//Global Class Instance,Not used in this program
ENIP_ClassInstance    :
SourceOffset:=0;
MEM.MemFill(
pMemoryBlock:=ADR(Instance00)
,uiLength:=SIZEOF(Instance00)
,byFillValue:=0
);
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All)
,pDestination:=ADR(Instance00)
,uiNumberOfBytes:= TO_UINT(Get_Attributes_All.udiReceivedDataSize)
);
//Class 0x01 Identity Object
ENIP.CIPClass.IdentityObject:
SourceOffset:=0;
MEM.MemFill(
pMemoryBlock:=ADR(Instance01)
,uiLength:=SIZEOF(Instance01)
,byFillValue:=0
);
//The first 14 Bytes
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All)
,pDestination:=ADR(Instance01)
,uiNumberOfBytes:=TO_UINT(14)
);
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[15])
,pDestination:=ADR(Instance01.ProductName)
,uiNumberOfBytes:=TO_UINT(RawData_GetAttribute_All[14])
);
//13=Frame Bytes size before Product Name
//+1 is mean the Data[14] is the data leneght of Product Name, but not include this byte
SourceOffset:=13+RawData_GetAttribute_All[14]+1;
NumberOfBytes:=Get_Attributes_All.udiReceivedDataSize-SourceOffset;
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(Instance01.State)
,uiNumberOfBytes:=TO_UINT(NumberOfBytes)
);
//Class 0xF5
ENIP.CIPClass.TCPIPInterfaceObject:
SourceOffset:=0;
MEM.MemFill(
pMemoryBlock:=ADR(InstanceF5)
,uiLength:=SIZEOF(InstanceF5)
,byFillValue:=0
);
//Attribute1-3 Status,Configuration Capability,Configuration Control
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All)
,pDestination:=ADR(InstanceF5)
,uiNumberOfBytes:=12
);
//Attribute4 Physical Link Object
//Path Length
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[12])
,pDestination:=ADR(InstanceF5.Attribute004.PathLength)
,uiNumberOfBytes:=2
);
//Ethernet Link Object
SourceOffset:=14;
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute004.Path)
,uiNumberOfBytes:=InstanceF5.Attribute004.PathLength*2
);
SourceOffset:=SourceOffset+InstanceF5.Attribute004.PathLength*2;
//Attribute5 Interface Configuration
//IP,Mac..Etc
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute005)
,uiNumberOfBytes:=20
);
SourceOffset:=SourceOffset+20;
//DominName Name
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute005.DominName)
,uiNumberOfBytes:=2
);
IF InstanceF5.Attribute005.DominName = 0 THEN
SourceOffset:=SourceOffset+2;
END_IF
//Attribute6 Host Name
//Path Length
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute006.Length)
,uiNumberOfBytes:=SIZEOF(InstanceF5.Attribute006.Length)
);
SourceOffset:=SourceOffset+2;
//Path Name
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute006.HostName)
,uiNumberOfBytes:=InstanceF5.Attribute006.Length
);
SourceOffset:=SourceOffset+InstanceF5.Attribute006.Length;
//Attribute7 Safety Network Number
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute007)
,uiNumberOfBytes:=SIZEOF(InstanceF5.Attribute007)
);
SourceOffset:=SourceOffset+6;
//Attribute8 TTL Value
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute008)
,uiNumberOfBytes:=SIZEOF(InstanceF5.Attribute008)
);
SourceOffset:=SourceOffset+1;
//Attribute9 Multicast Configuration
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute009)
,uiNumberOfBytes:=SIZEOF(InstanceF5.Attribute009)
);
SourceOffset:=SourceOffset+8;
//Attribute10 Select ACD
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute010)
,uiNumberOfBytes:=SIZEOF(InstanceF5.Attribute010)
);
SourceOffset:=SourceOffset+1;
//Attribute11 Last Conflict Detected
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute011)
,uiNumberOfBytes:=SIZEOF(InstanceF5.Attribute011)
);
SourceOffset:=SourceOffset+35;
//Attribute12 Quick Connect
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute012)
,uiNumberOfBytes:=1
);
SourceOffset:=SourceOffset+1;
//Attribute13 Encapsulation Inactivity Timeout
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF5.Attribute013)
,uiNumberOfBytes:=SIZEOF(InstanceF5.Attribute013)
);
SourceOffset:=SourceOffset+2;
//Class 0xF6 EthernetLinkObject
ENIP.CIPClass.EthernetLinkObject:
SourceOffset:=0;
MEM.MemFill(
pMemoryBlock:=ADR(InstanceF6)
,uiLength:=SIZEOF(InstanceF6)
,byFillValue:=0
);
//Attribute1,InterfaceSpeed
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[0])
,pDestination:=ADR(InstanceF6.Attribute001)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute001)
);
SourceOffset:=SIZEOF(InstanceF6.Attribute001)+SourceOffset;
//Attribute2,Interface Flags
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute002)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute002)
);
SourceOffset:=SIZEOF(InstanceF6.Attribute002)+SourceOffset;
//Attribute3,Physical Address
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute003)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute003)
);
SourceOffset:=SIZEOF(InstanceF6.Attribute003)+SourceOffset;
//Attribute4,Interface Counter
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute004)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute004)
);
SourceOffset:=SIZEOF(InstanceF6.Attribute004)+SourceOffset;
//Attribute5,Media Counter
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute005)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute005)
);
SourceOffset:=SIZEOF(InstanceF6.Attribute005)+SourceOffset;
//Attribute6,Interface Control
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute006)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute006)
);
SourceOffset:=SIZEOF(InstanceF6.Attribute006)+SourceOffset;
//Attribute7,Interface Type
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute007)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute007)
);
SourceOffset:=SIZEOF(InstanceF6.Attribute007)+SourceOffset;
//Attribute8,Interface State
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute008)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute008)
);
SourceOffset:=SIZEOF(InstanceF6.Attribute008)+SourceOffset;
//Attribute9,Alarm State
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute009)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute009)
);
SourceOffset:=SIZEOF(InstanceF6.Attribute009)+SourceOffset;
//Attribute10,Interface Label
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute010)
,uiNumberOfBytes:=(RawData_GetAttribute_All[SourceOffset]+1)
);
SourceOffset:=(RawData_GetAttribute_All[SourceOffset]+1)+SourceOffset;
//Attribute11,Interface Capability
MEM.MemMove(
pSource:=ADR(RawData_GetAttribute_All[SourceOffset])
,pDestination:=ADR(InstanceF6.Attribute011)
,uiNumberOfBytes:=SIZEOF(InstanceF6.Attribute011)
);
END_CASE
//Clear Data
bExecute_GetAttribute_All:=FALSE;
mem.MemFill(
pMemoryBlock:=ADR(RawData_GetAttribute_All)
,uiLength:=SIZEOF(RawData_GetAttribute_All)
,byFillValue:=0
);
bFilled_GetAttribute_All:=TRUE;
END_IF





//Get Attribute Signle
CASE iStep_GetAttribute_Single OF
//Init
cStep_GetAttribute_Assembly_init:
bExecute_GetAttributeSignle:=FALSE;
bFilded_GetAttribute_Single:=FALSE;
TON_Get_Attribute_Single_Flow_Init(
IN:=TRUE
,PT:=T#0.2S
);
IF TON_Get_Attribute_Single_Flow_Init.Q  THEN
TON_Get_Attribute_Single_Flow_Init(
IN:=FALSE
);
iStep_GetAttribute_Single:=cStep_GetAttribute_Assembly_Output;
END_IF
//0x04 Instance#6E Attribute#3
cStep_GetAttribute_Assembly_Output:
Get_Attribute_Single.wAttribute:=3;
Get_Attribute_Single.eClass:=ENIP.CIPClass.AssemblyObject;
Get_Attribute_Single.dwInstance:=ENIP_Assblemly_OutputInstance;
bExecute_GetAttributeSignle:=TRUE;
iStep_GetAttribute_Single:=cStep_GetAttribute_Assembly_Output_wait;

cStep_GetAttribute_Assembly_Output_wait:
IF bFilded_GetAttribute_Single THEN
bFilded_GetAttribute_Single:=FALSE;
iStep_GetAttribute_Single:=cStep_GetAttribute_Assembly_Input;
END_IF
//0x04 Instance#64 Attribute#3
cStep_GetAttribute_Assembly_Input:
Get_Attribute_Single.wAttribute:=3;
Get_Attribute_Single.eClass:=ENIP.CIPClass.AssemblyObject;
Get_Attribute_Single.dwInstance:=ENIP_Assblemly_InputInstance;
bExecute_GetAttributeSignle:=TRUE;
iStep_GetAttribute_Single:=cStep_GetAttribute_Assembly_input_wait;

cStep_GetAttribute_Assembly_Input_wait:
IF bFilded_GetAttribute_Single THEN
bFilded_GetAttribute_Single:=FALSE;
iStep_GetAttribute_Single:=cStep_GetAttribute_Assembly_Output;
END_IF
END_CASE
//Get Attribute Signle Function Block
Get_Attribute_Single(
itfEtherNetIPDevice:=AXC_F_2152_Adapter1
,xExecute:=bExecute_GetAttributeSignle
,pData:=ADR(RawData_Get_Attribute_Single)
,udiDataSize:=SIZEOF(RawData_Get_Attribute_Single)
,udiReceivedDataSize=>RawDataSize_GetAttribute_Single
);
//Data Encode
IF Get_Attribute_Single.xDone OR Get_Attribute_Single.xError THEN
IF Get_Attribute_Single.xDone AND NOT Get_Attribute_Single.xError THEN

CASE Get_Attribute_Single.dwInstance OF
ENIP_Assblemly_OutputInstance:
MEM.MemMove(
pSource:=ADR(RawData_Get_Attribute_Single)
,pDestination:=ADR(Assblemly_Out_FromExplictMessages)
,uiNumberOfBytes:=TO_UINT(RawDataSize_GetAttribute_Single)
);
Assblemly_6E_DataSize_FromExplictMessages:=RawDataSize_GetAttribute_Single;
ENIP_Assblemly_InputInstance:
MEM.MemMove(
pSource:=ADR(RawData_Get_Attribute_Single)
,pDestination:=ADR(Assblemly_In_FromExplictMessages)
,uiNumberOfBytes:=TO_UINT(RawDataSize_GetAttribute_Single)
);
Assblemly_64_DataSize_FromExplictMessages:=RawDataSize_GetAttribute_Single;
END_CASE

END_IF
bExecute_GetAttributeSignle:=FALSE;
//Clear Data
mem.MemFill(
pMemoryBlock:=ADR(RawData_Get_Attribute_Single)
,uiLength:=SIZEOF(RawData_Get_Attribute_Single)
,byFillValue:=0
);
bFilded_GetAttribute_Single:=TRUE;
END_IF


//For trigger the Codesys Update Cycle and Check the variables
AssOut_FromImplictMessages[0]:=16#93;
AssOut_FromImplictMessages[255]:=16#54;
temp:=AssIn_FromImplicMessages[0];

Result

Wiresharkからみますと異なるAssemblyデータがExplict Message使って送信してるとわかります。

.

そしてByte順に沿ってデータを格納しています。

こちらはAssembly#4のIO データをExplict Message使用し取得します。

Sample Code

こちらでProjectをダウンロードしてください。

https://github.com/soup01Threes/Codesys/blob/main/Codesys_EIP_Scanner_ExplictMessage.projectarchive

Footer_Basic

Please Support some devices for my blog

Amazon Gift List

Find ME

Twitter:@3threes2
Email:soup01threes*gmail.com (* to @)
YoutubeChannel:https://www.youtube.com/channel/UCQ3CHGAIXZAbeOC_9mjQiWQ

シェアする

  • このエントリーをはてなブックマークに追加

フォローする