Entwickler-Ecke

Sonstiges (Delphi) - Designfrage zu Applikationsentwurf


Arne - Mo 22.09.08 06:41
Titel: Designfrage zu Applikationsentwurf
Guten Morgen zusammen,

ich bin gerade dabei eine Applikation zu entwerfen, die zwei COM-Ports öffnet, um eine Datenkommunikation auf einer Seriellen Schnittstelle zu 'belauschen', aufzuzeichnen und auszuwerten. Sieht also etwa so aus:


Quelltext
1:
2:
3:
4:
5:
6:
7:
TxD (Master) o----------O-------------------------------o RxD (Slave)
                        |
RxD (Master) o-----------------------O------------------o TxD (Slave)
                        |            |
                        |            |
                        o            o
              RxD PC COM1            RxD PC COM2


Nun benutze ich für den Zugang zur RS-232 aus Delphi heraus die Unit nrcomm, die mir die Funktion WaitForBytes(count : Cardinal; timeout : Cardinal) bietet, die auf count Bytes im Eingangsringpuffer wartet bzw. nach timeout Millisekunden zurückkehrt, auch wenn weniger als count Bytes empfangen wurden. Nun die Designfrage: wie würdet Ihr das Programm aufbauen, daß ich die empfangenen Bytes auswerten und in 'Klartext' in einem StringGrid darstellen kann. Sollte ich zwei Threads mit je einer Endlosschleife bauen, die nur das WaitForBytes(..) beinhaltet und dann ein komplett empfangenes Kommando an die Hauptapplikation zur Auswertung und Darstellung sendet? Falls Multithreaded hier angebracht ist: gibt es dazu ein Tutorial, in dem die Interprozesskommunikation in Delphi erläutert wird?

Thanx, Arne


jaenicke - Mo 22.09.08 08:55

Da du ja zweimal darauf warten musst wird dir nichts anderes als mehrere Threads übrig bleiben. Du musst an die Unit ja sicherlich den Port weitergeben, der benutzt werden soll, und das kannst du dann auch beim Erzeugen des Threads an den jeweiligen Thread tun. So kannst du dann den selben Thread für beide Ports benutzen.

Grundsätzlich implementierst du eine Klasse, die du von TThread ableitest. Darin überschreibst du die Prozedur Execute, in die du den Code des Threads packst. Dafür gibt es auch ein Gerüst, wenn du Datei --> Neu --> Andere... --> Delphi Dateien --> Thread Objekt benutzt.

Ausführliches sehr gut beschriebenes Tutorial:
http://www.michael-puff.de/Developer/Delphi/Tutorials/
--> Threads_mit_Delphi.pdf [http://www.michael-puff.de/Developer/Delphi/Tutorials/Threads_mit_Delphi.pdf]
--> Threads_mit_Delphi_Demos.zip [http://www.michael-puff.de/Developer/Delphi/Tutorials/Threads_mit_Delphi_Demos.zip]

Beispiel:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
unit Unit78;

interface

uses
  Classes, Windows;

type
  TWaitThread = class(TThread)
  private
    { Private declarations }
    fMyTest: string;
    procedure UpdateCaption;
  protected
    procedure Execute; override;
  public
    constructor Create(uPort: string);
  end;

implementation

uses
  Unit77;

{ Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure TWaitThread.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }


{ TWaitThread }

constructor TWaitThread.Create(uPort: string);
begin
  fMyTest := uTest;
  inherited Create(False); // False --> der Thread wird auch sofort ausgeführt
  // Übergibst du stattdessen True, dann muss er manuell mit Resume gestartet werden.
end;

procedure TWaitThread.UpdateCaption;
begin
  Form77.Caption := 'Updated in a thread';
end;

procedure TWaitThread.Execute;
begin
  Sleep(2000);
  MessageBeep(0);
  Sleep(2000);
  MessageBeep(0);
  Synchronize(UpdateCaption);
end;

end.


Delphi-Quelltext
1:
2:
3:
4:
procedure TForm77.FormCreate(Sender: TObject);
begin
  TWaitThread.Create('xy');
end;


alzaimar - Mo 22.09.08 10:25

Die serielle Schnittstelle ist -wie unter Windows üblich- über Events anzusteuern. Man wartet also nicht, bis Daten ankommen, sondern wird benachrichtigt, wenn Daten angekommen sind. Somit kann deine Anwendung normal programmiert werden (GUI usw.) Ein Event ('OnDataAvail') wird bei Bedarf automatisch von Windows aufgerufen. Dort liest Du die Daten ein und entscheidest, was mit den Daten passieren soll.

Ich würde vielleicht eine andere Komponente verwenden, die Dir diese Funktionalität zur Verfügung stellt, anstatt über Threads ein schon verbogenes Verhalten (Blocking und Polling) wieder in ein Nonblocking-Verhalten umzubiegen.


Arne - Mo 22.09.08 11:32

Danke für Eure Antworten!
Hab mir jetzt die Komponente näher angeschaut und ein OnAfterReceive Ereignis gefunden, das wohl für meine Zwecke geeignet ist.

Thanx, Arne


jaenicke - Mo 22.09.08 11:35

Ja, das hört sich genau passend an, ich hatte mich zwar gewundert, dass so etwas bei deiner Unit zu fehlen scheint, hatte dann aber eben nur die Frage beantwortet.
Die Frage ist nur, wenn es diese warte-auf-Methode gibt, ob das Ding das intern auch beim Event so macht (mit einer reinen Warteschleife und ProcessMessages z.B.).
// EDIT:
Nein, die Beschreibung der Komponente klingt schon so, als ob das gut implementiert ist.