AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delphi

Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delphi

Ein Thema von Moien · begonnen am 24. Feb 2020 · letzter Beitrag vom 25. Feb 2020
Antwort Antwort
Seite 1 von 2  1 2   
Moien

Registriert seit: 20. Feb 2020
6 Beiträge
 
#1

Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delphi

  Alt 24. Feb 2020, 09:02
Delphi-Version: 10.2 Tokyo
Hallo Zusammen,

ich versuche, ein Array von Byte aus einer S7-SPS über eine OPC-UA-Verbindung aus meinem Delphi-Programm zu lesen. Dieses Byte-Array besteht aus allen möglichen Variablen wie Bool, Real, DateTime, Integer und ... aus der SPS (aber alle als ein kompaktes Byte-Array). Ich muss die Einträge dieses Arrays in interne Delphi-Variablen konvertieren. Das bedeutet, dass z.B. die ersten vier Bytes (0..3) des SPS Byte-Arrays zur ersten Integer-Variable in Delphi gehören und die nächsten acht Bytes (4..11) zur zweiten Variable in Delphi, nämlich TDateTime. Gibt es eine Idee, wie dieses Typecasting effizient durchgeführt werden kann? Ich kenne die Reihenfolge und den Typ der internen Variablen in delphi. Ich habe ein dynamisches Array in delphi "OPCServerItemArray" und habe alle Variablen mit den entsprechenden Namen und Typen darin abgelegt.
Delphi-Quellcode:
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 --> 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;
mfg,
Moien
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.619 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#2

AW: Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delp

  Alt 24. Feb 2020, 09:51
Ich würde als erstes versuchen, einen packed Record mit den passenden Feldern zu deklarieren und dann mittels Move die Bytes dort hinein zu kopieren. Ob das funktioniert, hängt davon ab, ob die Bytereihenfolge der Quelle mit der von Delphi / Intel übereinstimmt (Stichwort: Big Endian vs. Little Endian).

Wenn nicht, wird es knifflig.
Thomas Mueller
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.173 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delp

  Alt 24. Feb 2020, 09:59
Also wenn du wirklich eine Struktur (packed record) hast die sich 1:1 auf die Bytes abbilden lässt die du bekommst dann gibt es das schon fertig mit TBitConverter aus System.Types :

Delphi-Quellcode:
uses
   System.SysUtils,
   System.Types;

type
   TAppData = packed record
      someInteger:   Int32;
      someTimestamp:   TDateTime;
      // usw.
   end;

procedure p();
const
   data: TBytes =
      [103, 18, 0, 0] // 4711
      +
      [0, 0, 0, 0, 160, 109, 229, 64]; // 2020, 02, 24
var
   appData: TAppData;
begin
   appData := TBitConverter.InTo<TAppData>(data);
end;

Um ganz ehrlich zu sein habe ich das früher auch so gemacht, mir es aber mittlerweile abgewöhnt. Am besten gönnt man sich das Getippe von ein paar Zeilen für die Konvertierung zwischen den rohen Bytes und der Datenstruktur wie man sie in seinem Programm abbilden möchte. Da lässt sich auch wesentlich besser testen und auf Sonderfälle reagieren.

Geändert von Der schöne Günther (24. Feb 2020 um 10:02 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.800 Beiträge
 
Delphi 12 Athens
 
#4

AW: Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delp

  Alt 24. Feb 2020, 10:18
Ich verlasse mich auch lieber nicht auf konstante Bytelängen. Spätestens mit Strings wars das nämlich. Schöner wartbar und zuverlässiger ist eine Analyse der Bytefolgen, wie Günther es bereits beschrieben hat.

Sherlock
Oliver
Geändert von Sherlock (Morgen um 16:78 Uhr) Grund: Weil ich es kann
  Mit Zitat antworten Zitat
Moien

Registriert seit: 20. Feb 2020
6 Beiträge
 
#5

AW: Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delp

  Alt 24. Feb 2020, 10:25
Vielen Dank für alle Antworten.
Ehrlich gesagt, ich habe nicht genau verstanden was ihr mit " eine Analyse der Bytefolgen" meint. Habt ihr ein Beispiel?

LG;
Moien
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delp

  Alt 24. Feb 2020, 10:26
Um ganz ehrlich zu sein habe ich das früher auch so gemacht, mir es aber mittlerweile abgewöhnt. Am besten gönnt man sich das Getippe von ein paar Zeilen für die Konvertierung zwischen den rohen Bytes und der Datenstruktur wie man sie in seinem Programm abbilden möchte. Da lässt sich auch wesentlich besser testen und auf Sonderfälle reagieren.
Um bei deinen Beispiel zu bleiben, dann also so wie in p3(); gezeigt?


Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
   System.SysUtils,
   System.Types;

type
   TAppData = packed record
      someInteger: Int32;
      someTimestamp: TDateTime;
      // usw.
   end;
   PAppData = ^TAppData;

const
   data: TBytes =
      [103, 18, 0, 0] // 4711
      +
      [0, 0, 0, 0, 160, 109, 229, 64]; // 2020, 02, 24

procedure p;
var
   appData: TAppData;
begin
   appData := TBitConverter.InTo<TAppData>(data);
end;

procedure p2;
var
   appData2: TAppData;
begin
   appData2 := (PAppData(@data[0]))^;
end;

procedure p3;
var
   appData3: TAppData;
begin
   appData3.someInteger := (PInteger(@data[0]))^;
   appData3.someTimestamp := (PDateTime(@data[4]))^;
end;

begin
  try
    p;
    p2;
    p3;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.173 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delp

  Alt 24. Feb 2020, 10:35
Der Unterschied bei p3() ist im Endeffekt dass die einzelnen Felder zugewiesen werden und nicht alles auf einen Rutsch.

Das ist natürlich schon einmal gut, damit muss der Record z.B. nicht mehr packed sein und man kann sich die Reihenfolge der Felder selbst aussuchen.

Ich würde noch einen Schritt weitergehen:

Ob man die einzelnen Bytes da jetzt mit wilden Zeigerzugriffen, mit TBitConverter oder sonst womit rausholt ist ja im Endeffekt egal, aber z.B. bei einem TDateTime (das ja nur ein Double ist) bieten sich noch Gültigkeitsprüfungen an. Akzeptiere ich nur Zeitstempel nach 1970? Was wenn ich eine ungültige Fließkommazahl erhalten habe?
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.173 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delp

  Alt 24. Feb 2020, 10:37
ich habe nicht genau verstanden was ihr mit " eine Analyse der Bytefolgen" meint. Habt ihr ein Beispiel?
In deinem Beispiel ist ReadVar_vonSPS doch ein Byte-Array. Dein OPCServerItemArray scheint ein Array von irgendwas zu sein, und du willst von deinem Byte-Array (oder "Bytefolge") aus die Daten in deinem OPCServerItemArray setzen. Mehr war nicht gemeint 😉
  Mit Zitat antworten Zitat
Moien

Registriert seit: 20. Feb 2020
6 Beiträge
 
#9

AW: Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delp

  Alt 25. Feb 2020, 10:48
Nochmal vielen Dank für eure Unterstützung
Ich habe schon ein Extra Unit definiert (UnitTypecasting). Und dann sortiere ich die Werte entwieder mit procedure Typecasting oder procedure P2 . Ich erhalte von beiden die gleichen Werte. Aber irgendwie sind die Werte nicht die gleichen, wie sie in der SPS definiert sind. Ich glaube, es gibt einige Probleme mit der Byte-Ordnung (Big-Endian und Little-Endian). Habt ihr eine Idee, wie man die Byte-Reihenfolge ändern kann?

Delphi-Quellcode:
unit UnitTypecasting;

interface

uses
   System.SysUtils,
   System.Types;

type
   TAppData = packed record

        //[variable_0]
        S1_PIn_00_bar : Single;

        //[variable_1]
        S1_PIn_DateTime_00_time : UInt32;

        //[variable_2]
        S1_PIn_01_bar : Single;

        //[variable_3]
        S1_PIn_DateTime_01_time : UInt32;

        //[variable_4]
        S1_PIn_02_bar : Single;

        //[variable_5]
        S1_PIn_DateTime_02_time : UInt32;

        //[variable_6]
        S1_PIn_03_bar : Single;
        .
        .
        .

        //[variable_227]
        RDT_P1_Enabled : Boolean;

        //[variable_228]
        RDT_P2_Enabled : Boolean;

        //[variable_229]
        RDT_P3_Enabled : Boolean;


   end;
   PAppData = ^TAppData;

   procedure Typecasting(var data : TBytes);
   procedure p2(var data2 : TBytes);

implementation

procedure Typecasting(var data : TBytes);
var
   appData: TAppData;
begin
   appData := TBitConverter.InTo<TAppData>(data);
end;

procedure p2(var data2 : TBytes);
var
   appData2: TAppData;
begin
   appData2 := (PAppData(@data2[0]))^;
end;

end.
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.173 Beiträge
 
Delphi 10 Seattle Enterprise
 
#10

AW: Typecasting eines Arrays von Byte und Schreiben in verschiedene Variablen in Delp

  Alt 25. Feb 2020, 12:36
Wenn du dir sicher bist dass es ein Big/Little-Endian Problem ist:

Ich habe in der Delphi-Standard-Bibliothek komischerweise nie etwas gefunden wie man die Endianess von Dingen wie z.B. einem Word ändern kann. Ich habe es dann ganz billig von Hand gemacht. Hier ein Beispiel:

https://gist.github.com/JensMertelme...1297748f61c91b

Geändert von Der schöne Günther (25. Feb 2020 um 12:39 Uhr)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:36 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz