# mit OPC 4 DOUBLEWORD's auf einmal lesen



## D_Lar (6 Mai 2011)

Hallo,

Ich hab mal ne Frage: wie kann ich in einem Item mehrere Worte auslesen?
Ich habe mit VisualC++ und hab einen Client programmiert, der eigentlich ganz gut funktioniert. 
Mit der Adresse:

/PLC/DATABLOCK/DOUBLEWORD[C131,>28,#4]

werden 2 Doppelwörter angesprochen. Erstellen Klappt, aber wie kann ich es lesen??

muss ich etwas an der Datentyp-Einstellung (VT_I4) ändern?

D_Lar


----------



## Thomas_v2.1 (6 Mai 2011)

Was hast du denn für einen OPC-Server? 
Ich würde erstmal in der Dokumentation nachsehen wie die Item-Syntax für Array-Variablen aussieht, und ob diese überhaupt unterstützt werden.

Als Variant-Datentyp würde ich dann VT_I4 | VT_ARRAY annehmen.


----------



## D_Lar (6 Mai 2011)

Thomas_v2.1 schrieb:


> Was hast du denn für einen OPC-Server?
> Ich würde erstmal in der Dokumentation nachsehen wie die Item-Syntax für Array-Variablen aussieht, und ob diese überhaupt unterstützt werden.
> 
> Als Variant-Datentyp würde ich dann VT_I4 | VT_ARRAY annehmen.



Danke Thomas, 

der OPC-Server ist von Sinumerik auf einer 840 D von Siemens. Mit einem OPC-Editor habe ich Items erzeugen können, welche mehrere Doppelwörter einlesen. 
Dies möchte ich nun auch mit einem selbstprogrammierten Client tun, und es in meinem Programm zu benutzen. Dokumentation habe ich über den Server kaum. 

Hab hier mal den C++ Code mit dem ich das Item Erzeuge:


```
OPCITEMDEF ItemArray[1] = 
    {{ 
        /*szAccessPath*/ L"", 
        /*szItemID ITEM_ID*/(LPWSTR) L"/PLC/DATABLOCK/DOUBLEWORD[c131,>28,#4]", 
        /*bActive*/ FALSE, 
        /*hClient*/ 1, 
        /*dwBlobSize*/ 0, 
        /*pBlob*/ NULL, 
        /*vtRequestedDataType*/ VT_I4|VT_ARRAY, 
        /*wReserved*/0 
    }};
hr = pIOPCItemMgt->AddItems(1, ItemArray, &pAddResult, &pErrors);
```
Die Fehlermeldung bekomme ich dann, wenn ich den Wert des Items lesen will:


```
HRESULT hr = pIOPCSyncIO->Read(OPC_DS_DEVICE, 1, &hServerItemWahl, &pValue, &pErrors);
VARIANT varValue = pValue[0].vDataValue;
int MeinAnzeigeWert = varValue.intVal;
```
Wie gesagt, mit einem einfachen DOUBLEWORD funktioniert das auch ganz gut, nur mit mehreren DWörtern auf einmal bekomm ich den Fehler.

Wenn ihr mir helfen könnt, wäre das echt genial!!

D_Lar


----------



## Thomas_v2.1 (6 Mai 2011)

D_Lar schrieb:


> Die Fehlermeldung bekomme ich dann, wenn ich den Wert des Items lesen will:
> 
> 
> ```
> ...



Das ist aber keine Fehlermeldung, oder?

Wenn du meinst dass es am Typ liegt, könntest du bei dir auch VT_EMPTY setzen. Dann sollte der OPC-Server selber entscheiden können welchen Typ er die geben will. Den von ihm festgelegten Typ kannst du dann ja nochmal vor Weiterverwendung abfragen/prüfen.


----------



## D_Lar (6 Mai 2011)

Thomas_v2.1 schrieb:


> Das ist aber keine Fehlermeldung, oder?



Nein, dass ist der Code fürs lesen eines Items, bei dem das Programm abbricht. Das lag aber daran, dass vorher kein Item erzeugt wurde, hab ich grad herausgefunden. 

Danke, mit VT_EMPTY wird jetzt schon mal ein Item erzeugt, allerdings hab ich schon die nächste Frage, wie kann ich den Typ abfragen und auslesen? Ich finde irgendwie nichts gescheites im Netz darüber. Darum ganz herzlichen Dank für deine Hilfe!!

Gruß D_Lar


----------



## Thomas_v2.1 (6 Mai 2011)

D_Lar schrieb:


> Danke, mit VT_EMPTY wird jetzt schon mal ein Item erzeugt, allerdings hab ich schon die nächste Frage, wie kann ich den Typ abfragen und auslesen? Ich finde irgendwie nichts gescheites im Netz darüber. Darum ganz herzlichen Dank für deine Hilfe!!



Das solltest du in der Struktur OPCITEMRESULT finden.
Einen Zeiger darauf übergibst du bei AddItems() mit deiner pAddResult Variable.

Bei OPCITEMRESULT solltest du Imho unter vtCanonicalDataType den Typ finden. Laut OPC-DA-Spec ist es aber wohl zulässig, wenn der Server dieses Feld nicht nach dem ersten Aufruf vollständig ausfüllt.


----------



## D_Lar (9 Mai 2011)

Thomas_v2.1 schrieb:


> Das solltest du in der Struktur
> Bei OPCITEMRESULT solltest du Imho unter vtCanonicalDataType den Typ finden.



Danke Thomas,

hab jetzt die Werte auslesen können, ich bekomme für eine Variable den Wert
19 = VT_UI4, und für das Array:
8211 = 8192 (VT_ARRAY) + 19 (VT_UI4)  oder?

Wenn ich es richtig verstanden hab, habe ich jetzt ein Array von VT_UI4. Aber wie komme ich jetzt an den Inhalt ran?

Sorry, ich das ganze ist für mich echt Neuland. Darum vielen Dank für die Hilfe.

D_Lar


----------



## Thomas_v2.1 (9 Mai 2011)

D_Lar schrieb:


> hab jetzt die Werte auslesen können, ich bekomme für eine Variable den Wert
> 19 = VT_UI4, und für das Array:
> 8211 = 8192 (VT_ARRAY) + 19 (VT_UI4)  oder?


Wenn du das schon händisch ausrechnen willst, bietet sich hierfür die Hexadezimaldarstellung an. Dann sieht man ohne zu rechnen den Typen:

dez8211 = 0x2013
VT_ARRAY = 0x2000
VT_UI4     = 0x0013
VT_ARRAY | VT_UI4 -> 0x2013



D_Lar schrieb:


> Wenn ich es richtig verstanden hab, habe ich jetzt ein Array von VT_UI4. Aber wie komme ich jetzt an den Inhalt ran?



Das ist dann letztendlich 'nur' noch Umgang mit dem Variant-Datentyp.
Bei den elementaren Typen kommst du über Zugriff auf die passende Variable im union Feld direkt an den Wert heran.
Bei einem Array wird es etwas aufwändiger, denn da musst du über den SAFEARRAY-Zeiger gehen.
Dazu siehst du die am besten irgendwelche Beispielcodes an, z.B. hier gibt es eine Implementierung des Variant-Typs in C++

http://www.codeproject.com/KB/architecture/cvariant.aspx


----------

