Einzelnen Beitrag anzeigen

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