Professional OPC
Development Tools

logos

Typecasting using Genericdata in Delphi

More
20 Feb 2020 08:21 #8237 by support
In this case, it looks like that the server really provides just an array of bytes. Therefore the UA complex data approach (with GenericData, in QuickOPC) does not apply and cannot be used.

So, it's up to you to decode the byte array - doing so actually falls outside of our product's scope. But it should be quite easy. I myself was doing Object Pascal/Delphi programming only many years ago, but I believe that in principle you will use one of the functions like CopyMemory to either

- Copy the whole array to a 'record' which you will define and that will have the right structure. In this case, care needs to be made about record packing/field alignment ( docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/He...n/compdirsalignfields_xml.html )
- Do it repeatedly and copy just parts of the byte array to the "target" variables individually.

In both cases, if types with more than one byte in length are involved, additional consideration is whether the endianness is the same between the returned structure, and the one used in Delphi (which is "little endian" on Intel/AMD processors). If it is not the same, the byte order will need to be swapped as well.

Best regards

Please Log in or Create an account to join the conversation.

More
19 Feb 2020 12:54 #8235 by Moien
I was reading the QuickOPC User's Guide and I saw some examples in the 13.2.1.2.1 section which triggered the idea of using Genericdata for Typecasting. I was not sure how it is working in Delphi.

As far as I know the server is exposing the variable as an array of bytes. It just transfers the array from PLC to the client without any knowledge of the content.

Best regards,
Moien

Please Log in or Create an account to join the conversation.

More
19 Feb 2020 11:50 #8234 by support
Hello, welcome back. I have noticed you have posted a related (same?) question on StackOverflow.

First, I have a question. What leads you to believe that that the solution should involve the GenericData? It might, or it might not. It depends. Let me explain:

If the server supports OPC UA complex data types and the variable you read is of such complex data type, then it is passed as array of bytes on the wire, but QuickOPC has feature to decode it into its fields automatically - based on the "metadata" that it gets from the same server. This is the GenericData thing.

Or, the server may be truly exposing the variable *only* as an array/strring of Bytes. In such case the decoding needs to be done "manually".

Do you know which of these two cases are we dealing with?
Regards

Please Log in or Create an account to join the conversation.

More
19 Feb 2020 11:13 - 19 Feb 2020 11:40 #8233 by Moien
Hi again,

I am again here but this time with a new topic. We had lots of challenges regarding the previous topic. Hopefully, this one is more easygoing.
I am reading the values from PLC using Read function. These values are all defined in just one Array in Byte format which I get directly from OPC UA Server.
I have to write the values of this Single Array from PLC into multiple variables inside my Delphi application. I know the orders and types of variables inside delphi definde in an array of record as "OPCServerItemArray". In other words, as an example the first variable in my "OPCServerItemArray" is a Real variable with 4 Bytes and the corresponding value from the PLC is the entry of the first 4 Bytes of the array which comes from PLC (Bytes[0..3]). The second variable in "OPCServerItemArray" is a DateTime variable (8 Bytes) and the corresponding variable from PLC Array is the entries of Bytes[4..11] and so on. How can I do Typecasting using Genericdata?
I coppied part of my code here:
Procedure TOPCClient.ReadAllItems;
 var
 ReadVar_vonSPS : Array of Byte;
 AttributeSPSData : UAAttributeData;
 I: Integer;
 ItemRead : Boolean;
 Name : String;
 OPCUAResult: _UAAttributeDataResult;
 OPCUAResults: OleVariant;
 J,K: Cardinal;
 
 begin
   SetLength(ReadOPCUAArguments,Length(OPCServerItemArray)-NoV_DB100);
   try
 
     if (Connected) then begin
        AttributeSPSData := OPCUAClientSPS.Read(Url_String,'nsu=Siemens1' + ';s=' + S0);
        ReadVar_vonSPS := AttributeSPSData.Value;
        for I := 0 to NoV_DB100-1 do begin
           OPCServerItemArray[I].Value    := //??? Typecasting using GenericData --> ReadVar_vonSPS
           OPCServerItemArray[I].ItemQuality := AttributeSPSData.StatusCode;
           OPCServerItemArray[I].TimeStamp := AttributeSPSData.ServerTimestamplocal;
        end;
 
        if (FirstCylyle) then begin
 
          for J := NoV_DB100 to Length(OPCServerItemArray)-1 do begin
             Name := OPCServerItemArray[J].Source + '.' + OPCServerItemArray[J].ItemName;
             ReadOPCUAArguments[J-NoV_DB100] := CoUAReadArguments.Create;
             ReadOPCUAArguments[J-NoV_DB100].ReadParameters.MaximumAge := 100;
             ReadOPCUAArguments[J-NoV_DB100].EndpointDescriptor.UrlString := Url_String;
             ReadOPCUAArguments[J-NoV_DB100].NodeDescriptor.NodeId.ExpandedText := 'nsu='+ nsu + ';s=Local Items.' + Name;
          end;
 
          OPCUAArguments := VarArrayCreate([0, Length(OPCServerItemArray)-NoV_DB100-1], varVariant);
          for I := 0 to Length(OPCServerItemArray)-NoV_DB100-1 do begin
             OPCUAArguments[I] := ReadOPCUAArguments[I];
          end;
          FirstCylyle := False;
        end;
        // Perform the operation
        TVarData(OPCUAResults).VType := varArray or varVariant;
        TVarData(OPCUAResults).VArray := PVarArray(OPCUAClientRead.ReadMultiple(      //OPVLabs 2019.1 Version
        PSafeArray(TVarData(OPCUAArguments).VArray)));
 
        // Writing the results in Delphi internal Array
        for K := VarArrayLowBound(OPCUAResults, 1) to VarArrayHighBound(OPCUAResults, 1) do
        begin
           OPCUAResult := IInterface(OPCUAResults[K]) as _UAAttributeDataResult;
           OPCServerItemArray[NoV_DB100+K].Value    := OPCUAResult.AttributeData.value;
           OPCServerItemArray[NoV_DB100+K].ItemQuality := OPCUAResult.AttributeData.StatusCode;
           OPCServerItemArray[NoV_DB100+K].TimeStamp := OPCUAResult.AttributeData.ServerTimestamplocal;
        end;
 
     end else begin
         Meldung(0,'TOPCClient.ReadAllItems: (Not connected to the OPC UA Server!)');
     end;
 
   except
     on E: Exception do begin
       Meldung(0,'TOPCClient.ReadAllItems - Exception: ' + E.Message);
     end;
 
   end;
 
 end;
Regards,
Moien
Last edit: 19 Feb 2020 11:40 by support. Reason: formatted code as code

Please Log in or Create an account to join the conversation.

Moderators: support
Time to create page: 0.175 seconds

      

 Recommend this on Google