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
Status | Description | |
DISABLED | 0 | デバイスが無効してる |
NOT_CONFIGURED | IP_CONFIGがDefaultの状態 | |
IP_CONIFG | IPとPortがセットアップ中IPが無効であれば、BUS_ERRORの状態に移行IPが有効であれば、ENCAPSULATION_CONFIGの状態に移行 | |
ENCAPSULATION_CONFIG | ClientにTCP Portが開きます正常なら、LIST_SERVICES状態に移行エラーなら、BUS_ERROR状態に移行 | |
LIST_SERVICES | REGISTER_SESSION状態移行まえのBuffer | |
PARAMETER_CONFIG | Userパラメタが送信する状態エラーあってもログメッセージが生成するだけでそのままCONFIGURED状態に移行 | |
CONFIGURED | Forward openリクエストを処理します接続成功や場合によりMulticastアドレスに参加OKの場合、RUNNINGに移行します。ほかにForward OpenをRetryします。 | |
RUNNING | すべてのConnectionが確立されました。IOデータは交換しています。 | |
RESET | RemoteAdapterにリセットTriggerする | |
RESET_SERVICE | ネットワーク全体にCIP Reset ServiceをTriggerする | |
CONNECTIVITY_CHECK | AUTO_RESETが使用するとき、Connectionが切断した場合はその状態に移行します。そして復旧するとCONFIGURED状態にも戻ります。 | |
BUS_ERROR | AUTO_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
Status | Description |
INITIALIZING | CIP Objectを初期化してます。IP_CONFIGに移行 |
DISABLED | Scannerが無効になっています。 |
IP_CONFIG | 使用してるEthernet InterfaceにIP設定などを行い、IoDrvEthernet->EthernetState->RUNNINGまで待ちます。RUNNINGになるとUDP_CONFIG移行します。エラーになるとTCPIP_CONFIG_ERRORに移行します。 |
UDP_CONFIG | UDPのDefault Port2222を開きます。エラーならScannerState.BUS_ERRORに移行します。 |
ENCAPSULATION_CONFIG | |
ADAPTER_CONFIG | Buffer StatueでOPEN_CONNECTIONSに移行。 |
OPEN_CONNECTIONS | CIP Identity StatusをConfiguredに変更し、StateをRUNNINGにします。 |
RUNNNING | Adapterと切断しOデータやExplict messageを処理する |
DIAGNOSTIC_AVAILABLE | Runningと同じく、でも診断情報があり |
BUS_ERROR | UDP/TCP Portは開放できない。INITIALIZING状態に戻ります。 |
RESET | CIP 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
Name | Type | Description |
xExecute | BOOL | 立ち上げで実行 |
itfEtherNetIPDevice | IEtherNetIPService | 該当するEIP Object |
eClass | CIPClass | Services対象のCIP Class |
dwInstance | DWORD | CIP ClassのInstance番号 |
wAttribute | WORD | 該当するInstanceのAttribute番号 |
pData | POINTER TO BYTE | 取得したデータ転送先のMemory Offset、ADR()関数を使用すればOK |
udiDataSize | UDINT | データ転送先のMemorayサイズ、SizeOf()関数を使用すればOK |
VAR_OUT
Name | Type | Description |
eError | ERROR | True=エラー発生 |
udiReceivedDataSize | UDINT | EhternetIP Objectから取得したデータのサイズ(Byte) |
Get_Attribute_All
Ethernet/IPのObjectにGet_Attribute_AllのExplict Messageを送信します。
VAR_INPUT
Name | Type | Description |
xExecute | BOOL | 立ち上げで実行 |
itfEtherNetIPDevice | IEtherNetIPService | 該当するEIP Object |
eClass | CIPClass | Services対象のCIP Class |
dwInstance | DWORD | CIP ClassのInstance番号 |
wAttribute | WORD | 該当するInstanceのAttribute番号 |
pData | POINTER TO BYTE | 取得したデータ転送先のMemory Offset、ADR()関数を使用すればOK |
udiDataSize | UDINT | データ転送先のMemorayサイズ、SizeOf()関数を使用すればOK |
VAR_OUT
Name | Type | Description |
eError | ERROR | True=エラー発生 |
udiReceivedDataSize | UDINT | EhternetIP 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