AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Zugriff auf RS232 über TApdComPort und Thread
Thema durchsuchen
Ansicht
Themen-Optionen

Zugriff auf RS232 über TApdComPort und Thread

Ein Thema von norwegen60 · begonnen am 7. Feb 2023 · letzter Beitrag vom 7. Feb 2023
Antwort Antwort
norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
505 Beiträge
 
Delphi 12 Athens
 
#1

Zugriff auf RS232 über TApdComPort und Thread

  Alt 7. Feb 2023, 16:46
Hallo zusammen,

ich handle die komplette RS232-Kommunikation in einem Thread.
Ziel ist:
  • Der Thread puffert alle eingehenden Befehle und sendet den nächsten erst, wenn der vorhergehende geantwortet hat oder keine Antwort erwartet wird
  • Der Thread wartet z.B, auf eine bestimmte Antwort. Das kann auch bedeutet, dass er laufend einen Status abfragt, bis der gewünschte Status erreicht ist.
  • Der Thread schickt den Befehl noch mal, wenn keine Antwort innerhalb eines definierten Timeouts kommt

Momentan habe ich aber das Problem, dass hin und wieder Antworten verloren gehen. Deshalb die Frage ob an meinem Konstrukt prinzipiell was falsch ist. Dieses sieht stark vereinfacht so aus:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Classes,
  AdPort;

type
  TThreadString = procedure(Value: String) of object;

  TMyComThread = class(TThread)
  private
    FCommand: String;
    FCommandList: TStringList;
    FComPort: TApdComPort;
    FBuf: String;
    FBusy: Boolean;
    FResponse: String;
    FSyncResponse: TThreadString;

    procedure Execute;

    procedure SyncResponseEvent;
    procedure SetResponse(const Value: String);
  protected
    procedure ComPortTriggerAvail(CP: TObject; Count: Word);
  public
    property Response: String write SetResponse;
    property SyncResponse: TThreadString read FSyncResponse write FSyncResponse;

    constructor Create(sEinst: String);
    destructor Destroy; override;

    procedure SendCommand(sValue: String);
  end;

implementation

procedure TMyComThread.ComPortTriggerAvail(CP: TObject; Count: Word);
var
  i: Integer;
  cBuf: Char;

begin
  for i := 1 to Count do
  begin
    cBuf := Char(FComPort.GetChar);

    if cBuf = #13 then
    begin
      Response := FBuf;
      FBuf := '';

      FBusy := False;
    end
    else
      FBuf := FBuf + cBuf;
  end;
end;

constructor TMyComThread.Create(sEinst: String);
begin
  FComPort := TApdComPort.Create(nil);
  FComPort.OnTriggerAvail := ComPortTriggerAvail;
end;

destructor TMyComThread.Destroy;
begin
  FComPort.Open := False;
  FComPort.Free;

  FCommandList.Free;

  inherited;
end;

procedure TMyComThread.Execute;
begin
  FComPort.Open := True;
  FBusy := False;

  while not Terminated do
  begin
    if not FBusy and (FCommandList.Count > 0) then
    begin
      FCommand := FCommandList[0];
      FCommandList.Delete(0);
      FComPort.PutString(AnsiString(FCommand + #13 + #10));
      FBusy := True;
    end;

    TThread.Sleep(50);
  end;
end;

procedure TMyComThread.SendCommand(sValue: String);
begin
  FCommandList.Add(sValue);
end;

procedure TMyComThread.SetResponse(const Value: String);
begin
  FResponse := Value;
  Synchronize(SyncResponseEvent);
end;

procedure TMyComThread.SyncResponseEvent;
begin
  if Assigned(FSyncResponse) then
    FSyncResponse(FResponse);
end;

end.
und im Main Thread

Delphi-Quellcode:
  Com := TMyComThread.Create (sEinst);
  Com.SyncResponse:= SyncResponse;

procedure TForm1.SyncResponse(sMsg: String);
begin
  Edit1.Text:= sMsg;
end;

procedure TForm1.Button1ClickSender: TObject);
begin
  Com.SendCommand(Edit2.Text);
end;
Ich habe aus dem Code alles wie Timeout-Überwachung, unterbrochene Verbindung, wiederholtes senden, falsches Kommando, Kommando ohne Rückgabewert, korrektes beenden, .... raus gelassen

Es geht mir hauptsächlich darum
  1. Kann bei der Datenübergabe von Com.SendCommand(Edit2.Text); was schief gehen
  2. Ist sichergestellt dass ComPortTriggerAvail innerhalb des Threads läuft oder ist der von Haus aus an den Main-Thread gebunden? Wie könnte ich die Daten Threadsave aus TApdComPort empfangen
  3. Ist die Rückgabe der Antwort über Synchronize(SyncResponseEvent); eine gute Wahl
  4. Oder macht der Einsatz von TCriticalSection statt Synchronize Sinn

Vor allem bei 2. bin ich mir unsicher.

Um Verzögerungen aus dem Main-Thread zu verhindern, schreibe ich die Responses in TForm ebenfalls in eine Liste und arbeite die dann ab.


Grüße
Gerd
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.093 Beiträge
 
Delphi 12 Athens
 
#2

AW: Zugriff auf RS232 über TApdComPort und Thread

  Alt 7. Feb 2023, 18:09
Vielleicht hilft Dir dies weiter ?
https://en.delphipraxis.net/topic/36...#comment-30310
https://www.delphipraxis.net/205297-...fentlicht.html
https://blog.grijjy.com/2017/01/12/e...c-ring-buffer/
https://github.com/grijjy/GrijjyFoundation
https://en.delphipraxis.net/topic/37...#comment-32259
https://www.delphipraxis.net/126525-...am-memory.html
http://delphicodemonkey.blogspot.com/2015/


Ich nutze für Ähnliches einen auf einem TMemoryStream basierenden, Ringbuffer, könnte aber auch TBytes sein, der von RS232 beschrieben wird.
Dieser läuft in einem Thread und behandelt alle Write/Read Prozesse.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.062 Beiträge
 
Delphi 12 Athens
 
#3

AW: Zugriff auf RS232 über TApdComPort und Thread

  Alt 7. Feb 2023, 18:13
Das ist nicht im Thread.
Delphi-Quellcode:
constructor TMyComThread.Create(sEinst: String);
begin
  FComPort := TApdComPort.Create(nil);
  FComPort.OnTriggerAvail := ComPortTriggerAvail;
end;

destructor TMyComThread.Destroy;
begin
  FComPort.Open := False;
  FComPort.Free;

  FCommandList.Free;

  inherited;
end;
Aber FComPort.Open := False; und .PutString nicht.
-> NICHT thread-save

Der Zugriff auf FCommandList ist auch NICHT thread-save.

Und wo ist im Contructor das Inherited, bzw. inherited Create(False); // oder True ?

Vielen solcher Komponenten arbeien selbst mit einem Thread und synchronisieren dann die Events meistens in den Hauptthread. (aber nicht immer)
Prüfen wo ComPortTriggerAvail ausgeführt wird.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 7. Feb 2023 um 18:16 Uhr)
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.093 Beiträge
 
Delphi 12 Athens
 
#4

AW: Zugriff auf RS232 über TApdComPort und Thread

  Alt 7. Feb 2023, 19:45
Ich habe da eine eigene Lösung, basierend auf einem aufgebohrtem TMemoryStream, den Orginalink dazu finde ich gerade nicht mehr,
war was älteres Asiatisches.
Der war auch nicht Thread-Save, musste was drumrum gebaut werden.
Bei den ganzen Links könnte aber was Passendes für de Fragesteller dabei sein, wenn er sich auf RingBuffer einlassen möchte.
  Mit Zitat antworten Zitat
Antwort Antwort


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 08:45 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