Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   DataChannels (https://www.delphipraxis.net/168963-datachannels.html)

snook 20. Jun 2012 17:32

DataChannels
 
Hallo alle miteinander,

Ich habe die Vorgabe bekommen eine Datenübertragung zwischen den DataSockets von National Instrument und Delphi umzusetzen. Da ich das ganze aber gerne über diese Grenzen hinaus erweiterbar gestalten möchte, soll es eine generelle DataChannel-DataSocket-DataProducer Struktur werden. Im groben dachte ich an Objekte, welche in Form eines DataChannels Werte von einem Socket Ein- und Auslesen können. Mehrere solcher Channels können an einen Socket gebunden werden, und dieser Socket redet dann über einen Übersetzer mit dem Datenproduzenten. Um das alles noch dynamischer zu gestalten, soll ein Channel nun nicht fest mit einem Socket verdrahtet werden, sondern je nach Wunsch einem speziellen Socket zugeordnet werden können. Letztendlich muss zum erzeugen neuer Datenquellen nur noch ein neuer Produzent registriert werden, sowie ein zugehöriger Übersetzer (der die Kommandos der Sockets in Befehle für die Datenquelle übersetzt). Nun die wichtigste Anforderung: Die Daten, welche übertragen werden sollen, können die verschiedensten Typen haben. Das reicht von einfachen Gleitkommazahlen bis hin zu mehrdimensionalen Arrays. Dabei können die Datenproduzenten z.B. in LabView arbeiten, sie können als PlugIns in die laufende Anwendung eingebunden werden usw.

Soweit die Theorie. Ich habe mir jetzt schon meine Gedanken dazu gemacht allerdings würde ich mich freuen, falls einer von euch evtl mal ein ähnliches Projekt realisiert hat und mir seine Idee der Umsetzung kurz schildern könnte. Besonders bin ich gerade noch am Grübeln, wie ich die verschiedenen Datentypen auf der Channel-Seite handhabe. Die Datachannels sollen dabei mit möglichst vielen Datentypen umgehen können und evtl bereits formattiert zurückgeben können.

Viele Grüße

Sebastian

NickelM 20. Jun 2012 17:53

AW: DataChannels
 
Also bezüglich der verschiedenen Typen, würd ich sagen du hast eine Funktion mit der du deinen "Commande" sendest. Diese Funktion, gibt einen von dir deklarierten Typ zurück. Dan übergibst du das an die Richtige Funktion. Anhand des Typst kannst du dann auch "falschaufrufe" verhindern. Von LabView hab ich keine Ahnung.

Kleines Beispiel:
Delphi-Quellcode:
type
  TResultTyp = (rtText,rtArray,rtGleitkomma);
//...
function SendCommand({...ka, wie du das Commande sendest must als Text oder sonstwas}) : TResultTyp;
begin
  //Commando senden; Resultat irgendwo speichern; Das Resultat-Format, solltest du denk ich mal, wissen anhand des Commandes oder sonstwa.
  Result := rtText; //Als Beispiel
end;

function GetText(ResultTyp : TResultTyp): String;
begin
  If ResultTyp = rtText then
  begin
    //Als Text zurückgeben
  end else //Error ausgeben, das diese Format nicht unterstützt wird
end;
Soweit vom Empfangen. Sowas fürs Senden wird schwieriger. Keine Ahnung, ob man sowas in der richtung auch fürs Senden machen könnte. Was Empfängst du eigentlich? Direkt die Bytes oder nur Texte?

Gruß NickelM

snook 20. Jun 2012 18:18

AW: DataChannels
 
Tja das ist eigentlich das, was der User dann erweitern soll^^. Nee im Ernst, dass ist ja gerade der Witz an der Sache, die "Empfänger" der Daten dachte ich mir als eine BasisKlasse, die eine Methode zum Übersetzen der Daten bereitstellt. Für eine neue Datenquelle muss dann nur diese Methode überschrieben werden. Der Witz ist vielmehr der, dass dieser "Empfänger", oben nannte ich die Teile Übersetzer, einen beliebigen Socket füttern soll. Was dann am Ende der Sockets dranhängt, also ein Channel der nen String zurückgibt, oder einen der nen Array zurückgibt, darüber habe ich keine Macht. Es wäre daher großartig, wenn es generische Datentypen geben würde, die ich dazu auch noch über Programmmodule hinweg (denn der Übersetzer ist ein PlugIn) weiterreichen könnte, sodass am Ende bei dem Channel der gerade am Socket horcht, der richtige Datentyp ankommt.

Wo cih gerade dabei bin, ich habe da eine interessante Konstruktion gefunden, kann die evtl jemand erklären, besonders warum das Interface als Variant verwendet wird und wie ich sowas evtl selber verwenden könnte?

Delphi-Quellcode:
// Dies ist ein Auszug aus der Unit zur Kommunikation mit LabView
type
  CWData = ICWData;
  CWDataSocket = INIDSCtl;


// *********************************************************************//
// Interface: ICWData
// Flags:    (4432) Hidden Dual OleAutomation Dispatchable
// GUID:     {AC74EF34-F94C-11D0-80F9-00A02454310A}
// *********************************************************************//
  ICWData = interface(IDispatch)
    ['{AC74EF34-F94C-11D0-80F9-00A02454310A}']
    function Get_Value: OleVariant; safecall;
    procedure Set_Value(pVal: OleVariant); safecall;
    function Get__Value: OleVariant; safecall;
    procedure Set__Value(pVal: OleVariant); safecall;
    function GetAttribute(Name: OleVariant; Default: OleVariant): CWData; safecall; //<-- diese Stelle
    procedure SetAttribute(Name: OleVariant; Value: OleVariant); safecall;
    function HasAttribute(Name: OleVariant): WordBool; safecall;
    procedure DeleteAttribute(Name: OleVariant); safecall;
    procedure CopyFrom(const Source: CWData); safecall;
    procedure Reset; safecall;
    function GetAttributeNames: OleVariant; safecall;
    function GetFlexString: OleVariant; safecall;
    procedure SetFromFlexString(FlexString: OleVariant); safecall;
    procedure Set__SetOPCQuality(Param1: CWDSOPCQuality); safecall;
    property Value: OleVariant read Get_Value write Set_Value;
    property _Value: OleVariant read Get__Value write Set__Value;
    property _SetOPCQuality: CWDSOPCQuality write Set__SetOPCQuality;
  end;

// jetzt kann ich sowas anstellen

function TLabViewSocket.ReceiveData(out AData: IComDataStruct): integer;
var
  LVar: Array[0..4] of Variant;
  LAttribute:string;
  i: integer;
  pData: PSocketData;
begin
  if FAcces = atRead then
  begin
    for i := 0 to 4 do
      begin
        case i of
          0: LAttribute:='ChannelName';
          1: LAttribute:='Value';
          2: LAttribute:='UnitString';
          3: LAttribute:='TimeStamp';
          4: LAttribute:='OwningVI';
        end;
      LVar[i]:=FSocket.Data.GetAttribute(LAttribute,'0'); //<-- hier wird aus dem interface ein string
    end;
  end;
end;

NickelM 20. Jun 2012 19:09

AW: DataChannels
 
Hm, also mit solche ActiveX-Dlls habe ich selber noch nie mit gearbeitet, also noch keine programmiert, aber OleVariant, kannst du alles zuweisen, was die größe von 4 Bytes hat. Interfaces sind Pointer, also nur Zeiger. Also ich Bezweifle das du so an den String kommst. So wie ich das verstehe übergibt er dir eine Pointer zu ICWData. Und bei ICWData gibt es die Funktion Value. Die wiederum einen OleVariant zurückgibt. Wie schon gesagt, da kann alles drinliegen, was die größe von 4 Bytes hat. Delphi bzw. die OLE-Schnittstelle wandelt das beim zuweisen in den richtig Typ um.

Wenn du einen String zu OleVariant zuweisst, weis ich jetzt nicht 100% aber vermute ich. Wird daraus ein PChar. Also ein Zeiger auf die Daten von dem Text.
Wenn du dan diese OleVariant bekommst, musst du Wissen als was du das Interpretieren musst. In diesem Beispiel, weis die Funktion
Delphi-Quellcode:
function Get__Value: OleVariant; safecall;
, dass der Wert ('ChannelName') ein String ist. Also ist OleVariant ein PChar.

Im Klartext zusagen, du müsstest mit OleVariant arbeiten und eine Liste der Kommandos haben und in welchem Typ die sind. In diesem Beispiel übernihmt das ICWData Interfaces das für dich.

Und der User müsste eine Funktion aufrufen, wo er die Typbezeichnung sowie den eigentliche Typ, da kommt wieder mein Beispiel ins Spiel, hinzufügen kann. Dadurch weis deine Anwendung wie er den Typ OleVariant interpretieren muss.

Gruß NickelM

BUG 20. Jun 2012 19:31

AW: DataChannels
 
Ehrlich gesagt finde ich deine Erläuterung des Problems etwas verwirrend:
Was ist zB. der Unterschied zwischen einem Daten-Produzent und einer Daten-Quelle bzw. eines Daten-Channels und einem Daten-Socket? Oder ist das LabView-Terminologie?

Zu deinem beliebige-Daten-in-einen-Datentypen-Problem:
Für einen einfachen Austausch von hierarchisch strukturierten Daten würde ich zu einer JSON-Repräsentation greifen. Die Daten lassen sich damit natürlich gut zu JSON serialisieren, was das Verschicken oder den Austausch mit den üblichen Scriptsprachen hin einfach machen sollte.

snook 20. Jun 2012 20:12

AW: DataChannels
 
ja das tut mir leid, ich hab häufiger das problem dass meine erläuterungen zu konfus sind. da schwirren mir meistens zu viele sachen im kopf herum. Datenproduzent und DatenQuelle waren gleichbedeutend gemeint, was datachannels und datasockets betrifft, das scheint wirklich von LabView zu stammen. In meinem Fall ist mit DataChannel ein Kanal gemeint, der dem Benutzer für irgendwelche Zwecke Daten bereitstellt, oder Daten an andere Orte verschicken kann. Ein DataSocket ist als Synonym für einen Stecker gedacht, der mehrere DataChannels verwaltet und die Anfragen an den gewünschten Addressaten weiterleitet.

@NickelM: super, ich glaub ich habs kapiert. das klingt wirklich gut. Dann würde ich einfach eine Schnittstelle bereitstellen, in der die Benutzer neue Datentypen registrieren. Das kann dann dynamisch eingebunden werden und wenn ich den Datentyp hab kann ich sogar checken ob Channel und Socket zusammen passen. Dank dir :thumb:

sx2008 21. Jun 2012 03:25

AW: DataChannels
 
Vielleicht suchst du ja einfach nur Open Wire.
Zitat:

The purpose of the OpenWire project is to introduce a unified, easy way to transfer data among different VCL or FireMonkey components. This is very similar to the way that products like LabView and HP VEE work. For example, you could quickly build an application with a sine wave generator, which streams out to a chart and in parallel to a filter, which streams out to another chart and in parallel to a file logger, as well as to a serial communication sending the data to another system. And what makes this easy is that you do not write code: You build streams by connecting an OutputPin to one or more InputPins. The unerlying technology pumps your data from pin to pin, using multiple threads for high performance.

snook 21. Jun 2012 09:19

AW: DataChannels
 
das ist sogar genau was ich suche, falls diese netze zur laufzeit erweitert werden können. ich schau's mir mal an vielen dank.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:16 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