みんなさんこんばんわ。あっという間にTwinCAT OPCUA TF6100の第4話になりました。
今回はPLC OPENライブラリ経由しOPC UA Serverを接続・Node読み書き・Method 呼び出しの方法を紹介したいと思います。まずこちらは各機能を使うにはどんなFunction Blocksが必要になるか、の一覧表になります。
このPLC OPEN ライブラリの使い方なれますと、Siemensなど他にPLC OPENライブラリが対応してるPLCメーカならやりかたほぼ同じなので、無理やゆるゆるで覚えましょう。
Support DataType
ライブラリ追加
先いった通り、今回はPLC Open function blockを使用しOPC UA サーバと接続やデータやりとりしますので、まずライブラリを追加しましょう。
PLC>Your Project>Refenerce>Add libraryします。
PLCOPEN_OPCUAを検索し、Tc3_PLCopen_OpcUA,3.x.x.xが出てきます。
そのライブラリ選び、OKします。
Connect/Disconnenct
では最初には一番簡単な機能のConnect・Disconnectから説明しましょう。使うFunction BlockはUA_ConnectとUA_Disconnectになります。
UA_Connect
VAR_INPUT | ||
Execute | BOOL | 立ち上げてコマンド実行 |
ServerUrl | STRING(MAX_STRING_LENGTH) | OPC UA Server URL |
SessionConnectInfo | ST_UASessionConnectInfo | 接続用の設定データ |
Timeout | TIME | 接続Timeout設定 |
VAR_OUTPUT | ||
ConnectionHdl | DWORD | OPCUA Connection Handle大事な変数で他のBlockも使われます。 |
Done | BOOL | エラーなしで実行OK |
Busy | BOOL | 実行中 |
Error | BOOL | エラーあり |
ErrorID | DWORD | エラーID |
UA_Disconnect
VAR_INPUT | ||
Execute | BOOL | 立ち上げてコマンド実行 |
ConnectionHdl | DWORD | OPCUA Connection Handle |
Timeout | TIME | Disconnect Timeout設定 |
VAR_OUTPUT | ||
Done | BOOL | エラーなしで実行OK |
Busy | BOOL | 実行中 |
Error | BOOL | エラーあり |
ErrorID | DWORD | エラーID |
うん?一気にNode値読みのプログラム解析まで進めばいいじゃない?と思う人がいるかもしれませんが、なにことも簡単から始まります、と私が思っています。そしてゆっくりゆっくり中にの理論や原理わかってって、このプロセスは別の”新しい”ことやるときにもきっと役にたちます。
なので、下図も書いてますが、まず:
- ”UA_Connect”で接続準備
- なにかしらのFunction BlockでOPC Serverとやり取り
- ”UA_Disconnect”でServerと切断
まずConnectとDisconnectをクリア行きましょう。
そして、UA_Connectを使うとき、OPC UA Serverにまずその2つ大事な情報が必要です。
- Server URL
- Session Connect Information
です。
Server URL
Server URLはどこで探せば良い?だと思いますね。客から情報もらうかもしれませんし、前回と同じのOPC UA Server Demoを使っていますので、
URLはopc.tcp://DESKTOP-7FE1JP2:48010になりますね。
Session Connect Information
Session Connect Informationは、先程紹介したUA_ConnectのFunction Blocks内にも紹介しましたよね。
ST_UASessionConnectInfo | ||
sApplicationUri | STRING(MAX_STRING_LENGTH) | アプリケーションURL(<=255文字) |
sApplicationName | STRING(MAX_STRING_LENGTH) | アプリケーション名(<=255文字) |
eSecurityMode | E_UASecurityMsgMode | セキュリティMode設定 |
eSecurityPolicyUri | E_UASecurityPolicy | セキュリティPolicy設定 |
eTransportProfileUri | E_UATransportProfile | TrasportのProfile設定 |
tSessionTimeout | TIME | Session Timeout時間 |
tConnectTimeout | TIME | 接続Timeout時間 |
E_UASecurityMsgMode
- eUASecurityMsgMode_BestAvailable := 0,
- eUASecurityMsgMode_None := 1,
- eUASecurityMsgMode_Sign := 2,
- eUASecurityMsgMode_Sign_Encrypt := 3;
E_UASecurityPolicy
- eUASecurityPolicy_BestAvailable := 0
- eUASecurityPolicy_None := 1,
- eUASecurityPolicy_Basic128 := 2,
- eUASecurityPolicy_Basic128Rsa15 := 3,
- eUASecurityPolicy_Basic256 := 4
E_UATransportProfile
- eUATransportProfileUri_UATcp := 1,
- eUATransportProfileUri_WSHttpBinary := 2,
- eUATransportProfileUri_WSHttpXmlOrBinary := 3,
- eUATransportProfileUri_WSHttpXml := 4
Code
説明はそこまでです。プログラムを書き始まりましょう。
どうしてもながらくなりますので、最後まで一緒に見ましょう。
そしてInterfaceとProgramは分けて説明します。
VAR
UA_CONNECTとUA_DisconnectのInstanceの定義します。
UASessionInfoはUA_Connect Blockを使うのに必要な変数です、にも前書きました。
そしてiStateは接続>なにかやる>Disconnectの流れを管理する変数です。
Block実行状態を示すbErrorなどもあります。
配列のTimerはDisconnectから再接続するまでのDelayなど使われています。
VAR UA_CONNENT :UA_CONNECT; UASessionInfo :ST_UASessionConnectInfo; UA_Disconnect :UA_Disconnect; iState :INT; bError :BOOL; bDone :BOOL; bBusy :BOOL; bReset :BOOL; nErrorID :DWORD; nConnectionHdi :DWORD; arrTON :ARRAY[0..3]OF TON; END_VAR |
VAR CONSTANT
こちらはiStateのStep番号・Timeout・OPCUA ServerのURLを定数化してたものです。
VAR CONSTANT ciStep_Parameters_Initlize :INT :=0; ciStep_UAConnect :INT :=10; ciStep_UADIsconnect :INT :=20; ciStep_End :INT :=7000; ciStep_UAError :INT :=9000; ctUASession_Connect_Timeout :TIME :=T#1M; ctUASession_Session_Timeout :TIME :=T#1M; ctUAConnect_Timeout :TIME :=T#5S; cstServerURL :STRING :=’opc.tcp://DESKTOP-7FE1JP2:48010′; END_VAR |
PROGRAM
こちらはIStateの番号によって違うBlockを呼び出します。
流れはFlow Chartと変わりませんので読めばみんなさんもわかると思います。
CASE iState OF ciStep_Parameters_Initlize: bError:=FALSE; bDone:=FALSE; bBusy:=FALSE; nErrorID:=0; UASessionInfo.tConnectTimeout:=ctUASession_Connect_Timeout; UASessionInfo.tSessionTimeout:=ctUASession_Session_Timeout; UASessionInfo.eSecurityMode:=eUASecurityMsgMode_None; UASessionInfo.eSecurityPolicyUri:=eUASecurityPolicy_None; UASessionInfo.eTransportProfileUri:=eUATransportProfileUri_UATcp; iState:=ciStep_UAConnect; ciStep_UAConnect: UA_CONNENT( Execute:=TRUE ,ServerUrl:=cstServerURL ,SessionConnectInfo:=UASessionInfo ,Timeout:=ctUAConnect_Timeout ,ConnectionHdl=>nConnectionHdi ); IF UA_CONNENT.Done AND NOT UA_CONNENT.Error THEN iState:=ciStep_UADIsconnect; UA_CONNENT( Execute:=FALSE ); ELSIF UA_CONNENT.Error THEN iState:=ciStep_UAError; nErrorID:=UA_CONNENT.ErrorID; END_IF |
ciStep_UADIsconnect: UA_Disconnect( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ); IF UA_Disconnect.Done AND NOT UA_Disconnect.Error THEN iState:=ciStep_End; ELSIF UA_Disconnect.Error THEN iState:=ciStep_UAError; nErrorID:=UA_Disconnect.ErrorID; END_IF ciStep_End: arrTON[0]( IN:=TRUE ,PT:=T#2S ); IF arrton[0].Q THEN arrton[0]( IN:=FALSE ); iState:=ciStep_UAConnect; END_IF ciStep_UAError: bError:=TRUE; IF bReset THEN iState:=ciStep_Parameters_Initlize; END_IF; END_CASE |
Polling (Read)
ConnectとDisconnectができたところで、次はPollingをやりますね。
つまりUA Name spaceからNodeを読み書きを行います。
実際の流れだとUA_ConnectでConnectionを確立し、UA_GetNamespaceIndexをNamespaceもらい>Handleをもらい>Node値を読む>Handleをリリース>Disconnectになりますね。
UA_GetNamespaceIndex
VAR_INPUT | ||
Execute | BOOL | 立ち上げてコマンド実行 |
ConnectionHdl | DWORD | OPCUA Connection Handle |
NamespaceUri | STRING(MAX_STRING_LENGTH) | NamespaceURL指定します。TwinCAT Serverならurn:BeckhoffAutomation:Ua:PLC1 |
Timeout | TIME | Disconnect Timeout設定 |
VAR_OUTPUT | ||
NamespaceIndex | UINT | Namespace番号。UA_Readなどは使わてています |
Done | BOOL | エラーなしで実行OK |
Busy | BOOL | 実行中 |
Error | BOOL | エラーあり |
ErrorID | DWORD | エラーID |
UA_NodeGetHandle
VAR_INPUT | ||
Execute | BOOL | 立ち上げてコマンド実行 |
ConnectionHdl | DWORD | OPCUA Connection Handle |
NodeID | ST_UANodeID | 先のUA_GetNamesapceIndexでもらったIndexです。 |
Timeout | TIME | Disconnect Timeout設定 |
VAR_OUTPUT | ||
NamespaceIndex | UINT | Namespace番号。UA_Readなどは使わてています |
Done | BOOL | エラーなしで実行OK |
Busy | BOOL | 実行中 |
Error | BOOL | エラーあり |
ErrorID | DWORD | エラーID |
UA_Read
VAR_INPUT | ||
Execute | BOOL | 立ち上げてコマンド実行 |
ConnectionHdl | DWORD | OPCUA Connection Handle |
NodeHdl | ST_UANodeID | 先のUA_GetNamesapceIndexでもらったIndexです。 |
stNodeAddInfo | ST_UANodeAdditionalInfo | Nodeの設定定義 例えばattribute内でどんな値を読むか |
pVariable | PVOID | Memory Pointer |
cbData | UDINT | 読むNodeのData Size |
Timeout | TIME | Timeout設定 |
VAR_OUTPUT | ||
Done | BOOL | エラーなしで実行OK |
Busy | BOOL | 実行中 |
Error | BOOL | エラーあり |
ErrorID | DWORD | エラーID |
cbData_R | UDINT | 何Byte読んでたか |
UA_NodeReleaseHandle
VAR_INPUT | ||
Execute | BOOL | 立ち上げてコマンド実行 |
ConnectionHdl | DWORD | OPCUA Connection Handle |
NodeHdl | ST_UANodeID | 先のUA_GetNamesapceIndexでもらったIndexです。 |
Timeout | TIME | Timeout設定 |
VAR_OUTPUT | ||
Done | BOOL | エラーなしで実行OK |
Busy | BOOL | 実行中 |
Error | BOOL | エラーあり |
ErrorID | DWORD | エラーID |
NamespaceURI
先UA_GetNamesapceIndexのFunction Blockをみたとき、NamespaceUriのパラメターがありますよね。
それが間違えますと、あとのHandleやReadのFunction Blockが実行エラーになりますので、ここで説明させていただきたいと思います。
UAExpertを開いて、OPC UA Serverと繋がります。
Server>NamespaceArrayをBrowseしてください。
そうすると文字列の配列が出てきます。のちほどでアクセスしたいNodeによってそのNamespaceが変わりますので、注意してください。
例えば、私はDemo>000_Static>Scalar>Int16をアクセスしたいと考えています。
このNodeをBrowseしますと、NamespaceIndexは2が入っていますよね。
つまり、NamespaceUrlは2番目のURLはを使用することになります。
Node Identifier
次は、UA_NodeGetHandleにはNodeIDというパラメタがあります。そのNodeIDはST_UANodeIDというDUTから定義されています。
ST_UANodeID
- nNamespaceIndex : UINT;
- nReserved : ARRAY [1..2] OF BYTE; //fill bytes
- sIdentifier : STRING(MAX_STRING_LENGTH);
- eIdentifierType : E_UAIdentifierType;
- E_UAIdentifierType
- eUAIdentifierType_String := 1,
- eUAIdentifierType_Numeric := 2,
- eUAIdentifierType_GUID := 3,
- eUAIdentifierType_Opaque := 4
- E_UAIdentifierType
その中に、nNamespaceIndexはUA_GetNamesapceIndexからもらったNameIndexを入れます。
eIdentifierTypeはStringか、Numberから定義すると設定します。(下図のIdentifierType)
sIdentifierは下図のIdentifierのValueをそのままCopyすればよいです。
Code
こちらはNode ReadのFlowになります。
VAR
VAR //Connect/DisConnect Functionality UA_CONNENT :UA_CONNECT; UASessionInfo :ST_UASessionConnectInfo; UA_Disconnect :UA_Disconnect; //Polling Functionlity //Get NameIndex UA_GetNamespaceIndex:UA_GetNamespaceIndex; nNameSpaceIndex :UINT; //Get Handle UA_NodeGetHandle:UA_NodeGetHandle; NodeID :ST_UANodeID; nNodeHdl :DWORD; //UA Read UA_Read :UA_Read; stIndexRange : ARRAY [1..nMaxIndexRange] OF ST_UAIndexRange; nIndexRangeCount : UINT; stNodeAddInfo : ST_UANodeAdditionalInfo; nReadData : INT; cbDataRead : UDINT; //UA Node Release Handle UA_NodeReleaseHandle : UA_NodeReleaseHandle; iState :INT; bError :BOOL; bDone :BOOL; bBusy :BOOL; bReset :BOOL; bInit :BOOL; nErrorID :DWORD; nConnectionHdi :DWORD; arrTON :ARRAY[0..3]OF TON; END_VAR |
VAR_CONSTANT
VAR CONSTANT ciStep_Parameters_Initlize :INT :=0; ciStep_UAConnect :INT :=10; ciStep_UAGetNamespaceIndex :INT :=20; ciStep_UAGetHandle :INT :=30; ciStep_UARead :INT :=40; ciStep_UARelease :INT :=50; ciStep_UADIsconnect :INT :=100; ciStep_End :INT :=7000; ciStep_UAError :INT :=9000; ctUASession_Connect_Timeout :TIME :=T#1M; ctUASession_Session_Timeout :TIME :=T#1M; ctUAConnect_Timeout :TIME :=T#5S; cstServerURL :STRING :=’opc.tcp://DESKTOP-7FE1JP2:48010′; END_VAR |
PROGRAM
CASE iState OF ciStep_Parameters_Initlize: bError:=FALSE; bDone:=FALSE; bBusy:=FALSE; nErrorID:=0; UASessionInfo.tConnectTimeout:=ctUASession_Connect_Timeout; UASessionInfo.tSessionTimeout:=ctUASession_Session_Timeout; UASessionInfo.eSecurityMode:=eUASecurityMsgMode_None; UASessionInfo.eSecurityPolicyUri:=eUASecurityPolicy_None; UASessionInfo.eTransportProfileUri:=eUATransportProfileUri_UATcp; stNodeAddInfo.nIndexRangeCount := nIndexRangeCount; stNodeAddInfo.stIndexRange := stIndexRange; UA_CONNENT( Execute:=FALSE ); UA_Disconnect( Execute:=FALSE ); UA_GetNamespaceIndex( Execute:=FALSE ); UA_NodeGetHandle( Execute:=FALSE ); UA_Read( Execute:=FALSE ); UA_NodeReleaseHandle( Execute:=FALSE ); IF NOT UA_CONNENT.Busy AND NOT UA_Disconnect.Busy AND NOT UA_GetNamespaceIndex.Busy AND NOT UA_NodeGetHandle.Busy AND NOT UA_Read.Busy AND NOT UA_NodeReleaseHandle.Busy THEN iState:=ciStep_UAConnect; END_IF; ciStep_UAConnect: UA_CONNENT( Execute:=TRUE ,ServerUrl:=cstServerURL ,SessionConnectInfo:=UASessionInfo ,Timeout:=ctUAConnect_Timeout ,ConnectionHdl=>nConnectionHdi ); IF UA_CONNENT.Done AND NOT UA_CONNENT.Error THEN iState:=ciStep_UAGetNamespaceIndex; UA_CONNENT( Execute:=FALSE ); ELSIF UA_CONNENT.Error THEN iState:=ciStep_UAError; nErrorID:=UA_CONNENT.ErrorID; END_IF ciStep_UAGetNamespaceIndex: UA_GetNamespaceIndex( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ,NamespaceUri :=’http://www.unifiedautomation.com/DemoServer/’ ,NamespaceIndex=>nNameSpaceIndex ); IF UA_GetNamespaceIndex.Done AND NOT UA_GetNamespaceIndex.Error THEN UA_GetNamespaceIndex( Execute:=FALSE ); iState:=ciStep_UAGetHandle; ELSIF UA_GetNamespaceIndex.Error THEN nErrorID:=UA_GetNamespaceIndex.ErrorID; iState:=ciStep_UAError; END_IF ciStep_UAGetHandle: NodeID.eIdentifierType:=eUAIdentifierType_String; NodeID.nNamespaceIndex:=nNameSpaceIndex; NodeID.sIdentifier:=’Demo.Static.Scalar.Int16′; UA_NodeGetHandle( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ,NodeID:=NodeID ,NodeHdl=>nNodeHdl ); IF UA_NodeGetHandle.Done AND NOT UA_NodeGetHandle.Error THEN UA_NodeGetHandle( Execute:=FALSE ); iState:=ciStep_UARead; ELSIF UA_NodeGetHandle.Error THEN nErrorID:=UA_NodeGetHandle.ErrorID; iState:=ciStep_UAError; END_IF ciStep_UARead: UA_Read( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ,NodeHdl:=nNodeHdl ,cbData:=SIZEOF(nReadData) ,stNodeAddInfo:=stNodeAddInfo ,pVariable:=ADR(nReadData) ); IF UA_Read.Done AND NOT UA_Read.Error THEN UA_Read( Execute:=FALSE ,cbData_R=>cbDataRead ); iState:=ciStep_UARelease; ELSIF UA_Read.Error THEN nErrorID:=UA_Read.ErrorID; iState:=ciStep_UAError; END_IF; ciStep_UARelease: UA_NodeReleaseHandle( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ,NodeHdl:=nNodeHdl ); IF UA_NodeReleaseHandle.Done AND NOT UA_NodeReleaseHandle.Error THEN UA_NodeReleaseHandle( Execute:=FALSE ); iState:=ciStep_End; ELSIF UA_NodeReleaseHandle.Error THEN nErrorID:=UA_NodeReleaseHandle.ErrorID; iState:=ciStep_UAError; END_IF ciStep_UADIsconnect: UA_Disconnect( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ); IF UA_Disconnect.Done AND NOT UA_Disconnect.Error THEN iState:=ciStep_End; ELSIF UA_Disconnect.Error THEN iState:=ciStep_UAError; nErrorID:=UA_Disconnect.ErrorID; END_IF ciStep_End: arrTON[0]( IN:=TRUE ,PT:=T#2S ); IF arrton[0].Q THEN arrton[0]( IN:=FALSE ); iState:=ciStep_UAConnect; END_IF ciStep_UAError: bError:=TRUE; IF bReset THEN iState:=ciStep_Parameters_Initlize; END_IF; END_CASE |
結果
いまOPC UA Demo ServerではNode値は99です。
同じくUA_Read()からのnReadDataも99になります。
Polling(Write)
読み終わったら、次は書き込みですね。
UA_Readと同じの流れで、呼び出しのFunction BlockがUA_Write()に変わっただけになります。
UA_Write
VAR_INPUT | ||
Execute | BOOL | 立ち上げてコマンド実行 |
ConnectionHdl | DWORD | OPCUA Connection Handle |
NodeHdl | ST_UANodeID | 先のUA_GetNamesapceIndexでもらったIndexです。 |
stNodeAddInfo | ST_UANodeAdditionalInfo | Nodeの設定定義 例えばattribute内でどんな値を読むか |
pVariable | PVOID | Memory Pointer |
cbData | UDINT | 読むNodeのData Size |
Timeout | TIME | Timeout設定 |
VAR_OUTPUT | ||
Done | BOOL | エラーなしで実行OK |
Busy | BOOL | 実行中 |
Error | BOOL | エラーあり |
ErrorID | DWORD | エラーID |
cbData_R | UDINT | 何Byte読んでたか |
Code
こちらはNode ReadのFlowになります。
VAR
VAR //Connect/DisConnect Functionality UA_CONNENT :UA_CONNECT; UASessionInfo :ST_UASessionConnectInfo; UA_Disconnect :UA_Disconnect; //Polling Functionlity //Get NameIndex UA_GetNamespaceIndex:UA_GetNamespaceIndex; nNameSpaceIndex :UINT; //Get Handle UA_NodeGetHandle:UA_NodeGetHandle; NodeID :ST_UANodeID; nNodeHdl :DWORD; //UA Read UA_Read :UA_Read; stIndexRange : ARRAY [1..nMaxIndexRange] OF ST_UAIndexRange; nIndexRangeCount : UINT; stNodeAddInfo : ST_UANodeAdditionalInfo; nReadData : INT; cbDataRead : UDINT; //UA Write UA_Write : UA_Write; nWriteData: INT := 0; //UA Node Release Handle UA_NodeReleaseHandle : UA_NodeReleaseHandle; iState :INT; bError :BOOL; bDone :BOOL; bBusy :BOOL; bReset :BOOL; bInit :BOOL; nErrorID :DWORD; nConnectionHdi :DWORD; arrTON :ARRAY[0..3]OF TON; END_VAR |
VAR_CONSTANT
VAR CONSTANT ciStep_Parameters_Initlize :INT :=0; ciStep_UAConnect :INT :=10; ciStep_UAGetNamespaceIndex :INT :=20; ciStep_UAGetHandle :INT :=30; ciStep_UARead :INT :=40; ciStep_UARelease :INT :=50; ciStep_UAWrite :INT :=60; ciStep_UADIsconnect :INT :=100; ciStep_End :INT :=7000; ciStep_UAError :INT :=9000; ctUASession_Connect_Timeout :TIME :=T#1M; ctUASession_Session_Timeout :TIME :=T#1M; ctUAConnect_Timeout :TIME :=T#5S; cstServerURL :STRING :=’opc.tcp://DESKTOP-7FE1JP2:48010′; END_VAR |
PROGRAM
CASE iState OF ciStep_Parameters_Initlize: bError:=FALSE; bDone:=FALSE; bBusy:=FALSE; nErrorID:=0; UASessionInfo.tConnectTimeout:=ctUASession_Connect_Timeout; UASessionInfo.tSessionTimeout:=ctUASession_Session_Timeout; UASessionInfo.eSecurityMode:=eUASecurityMsgMode_None; UASessionInfo.eSecurityPolicyUri:=eUASecurityPolicy_None; UASessionInfo.eTransportProfileUri:=eUATransportProfileUri_UATcp; stNodeAddInfo.nIndexRangeCount := nIndexRangeCount; stNodeAddInfo.stIndexRange := stIndexRange; UA_CONNENT( Execute:=FALSE ); UA_Disconnect( Execute:=FALSE ); UA_GetNamespaceIndex( Execute:=FALSE ); UA_NodeGetHandle( Execute:=FALSE ); UA_Read( Execute:=FALSE ); UA_NodeReleaseHandle( Execute:=FALSE ); IF NOT UA_CONNENT.Busy AND NOT UA_Disconnect.Busy AND NOT UA_GetNamespaceIndex.Busy AND NOT UA_NodeGetHandle.Busy AND NOT UA_Read.Busy AND NOT UA_NodeReleaseHandle.Busy THEN iState:=ciStep_UAConnect; END_IF; ciStep_UAConnect: UA_CONNENT( Execute:=TRUE ,ServerUrl:=cstServerURL ,SessionConnectInfo:=UASessionInfo ,Timeout:=ctUAConnect_Timeout ,ConnectionHdl=>nConnectionHdi ); IF UA_CONNENT.Done AND NOT UA_CONNENT.Error THEN iState:=ciStep_UAGetNamespaceIndex; UA_CONNENT( Execute:=FALSE ); ELSIF UA_CONNENT.Error THEN iState:=ciStep_UAError; nErrorID:=UA_CONNENT.ErrorID; END_IF ciStep_UAGetNamespaceIndex: UA_GetNamespaceIndex( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ,NamespaceUri :=’http://www.unifiedautomation.com/DemoServer/’ ,NamespaceIndex=>nNameSpaceIndex ); IF UA_GetNamespaceIndex.Done AND NOT UA_GetNamespaceIndex.Error THEN UA_GetNamespaceIndex( Execute:=FALSE ); iState:=ciStep_UAGetHandle; ELSIF UA_GetNamespaceIndex.Error THEN nErrorID:=UA_GetNamespaceIndex.ErrorID; iState:=ciStep_UAError; END_IF ciStep_UAGetHandle: NodeID.eIdentifierType:=eUAIdentifierType_String; NodeID.nNamespaceIndex:=nNameSpaceIndex; NodeID.sIdentifier:=’Demo.Static.Scalar.Int16′; UA_NodeGetHandle( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ,NodeID:=NodeID ,NodeHdl=>nNodeHdl ); IF UA_NodeGetHandle.Done AND NOT UA_NodeGetHandle.Error THEN UA_NodeGetHandle( Execute:=FALSE ); iState:=ciStep_UAWrite; ELSIF UA_NodeGetHandle.Error THEN nErrorID:=UA_NodeGetHandle.ErrorID; iState:=ciStep_UAError; END_IF ciStep_UAWrite: nWriteData:=nWriteData+1; UA_Write( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ,NodeHdl:=nNodeHdl ,stNodeAddInfo:=stNodeAddInfo ,pVariable:=ADR(nWriteData) ,cbData:=SIZEOF(nWriteData) ); IF UA_Write.Done AND NOT UA_Read.Error THEN UA_Write( Execute:=FALSE ,pVariable:=ADR(nWriteData) ); iState:=ciStep_UARelease; ELSIF UA_Write.Error THEN nErrorID:=UA_Write.ErrorID; iState:=ciStep_UAError; END_IF; ciStep_UARelease: UA_NodeReleaseHandle( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ,NodeHdl:=nNodeHdl ); IF UA_NodeReleaseHandle.Done AND NOT UA_NodeReleaseHandle.Error THEN UA_NodeReleaseHandle( Execute:=FALSE ); iState:=ciStep_End; ELSIF UA_NodeReleaseHandle.Error THEN nErrorID:=UA_NodeReleaseHandle.ErrorID; iState:=ciStep_UAError; END_IF ciStep_UADIsconnect: UA_Disconnect( Execute:=TRUE ,ConnectionHdl:=nConnectionHdi ); IF UA_Disconnect.Done AND NOT UA_Disconnect.Error THEN iState:=ciStep_End; ELSIF UA_Disconnect.Error THEN iState:=ciStep_UAError; nErrorID:=UA_Disconnect.ErrorID; END_IF ciStep_End: arrTON[0]( IN:=TRUE ,PT:=T#2S ); IF arrton[0].Q THEN arrton[0]( IN:=FALSE ); iState:=ciStep_UAConnect; END_IF ciStep_UAError: bError:=TRUE; IF bReset THEN iState:=ciStep_Parameters_Initlize; END_IF; END_CASE |
結果
Sample Codeは以下でダウンロードしてください。
はーい、お疲れ様です。
もしなにか質問あれば、メール・コメント・Twitterなどでもどうぞ!
Twitterのご相談:@3threes2
メールのご相談:soup01threes*gmail.com (*を@に)