Autor Beitrag
Arne
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 26



BeitragVerfasst: Mo 22.09.08 07:41 
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:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 22.09.08 09: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:
www.michael-puff.de/...er/Delphi/Tutorials/
--> Threads_mit_Delphi.pdf
--> Threads_mit_Delphi_Demos.zip

Beispiel:
ausblenden volle Höhe 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.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure TForm77.FormCreate(Sender: TObject);
begin
  TWaitThread.Create('xy');
end;
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Mo 22.09.08 11: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.

_________________
Na denn, dann. Bis dann, denn.
Arne Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 26



BeitragVerfasst: Mo 22.09.08 12: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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 22.09.08 12: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.