Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Tcomport on RXChar Problem (https://www.delphipraxis.net/170836-tcomport-rxchar-problem.html)

PhilmacFLy 5. Okt 2012 07:38

Tcomport on RXChar Problem
 
Moin DPler
Ich habe folgendes Problem, ich bekommen über einen virtuellen Comport Daten zu gesendet mit 115200 Baud. Nun wollte ich mit dem OnRxChar event der Komponente arbeiten. Nur leider feuert die keine Events. Wenn ich aber über einen Timer
Delphi-Quellcode:
procedure TForm2.Timer1Timer(Sender: TObject);
var
  Str: String;
begin
  ComPort1.ReadStr(Str, 10);
  if str <>'' then
  memo2.Lines.Add(stringtohex(str));
end;
die Daten ausles, ist was da.
Jemand eine Idee woran das liegen könnte?

PhilmacFLy 10. Okt 2012 09:56

AW: Tcomport on RXChar Problem
 
Ich push das hier nochmal aus gegebenen Anlass
Tante Edit meinte noch:
Grad hats mal kurz funktioniert, hatte die Buffer size in der Tcomport auf 4096 hoch gestellt, dann hats kurz geklappt, jetzt aber wieder tote hose.

Tante Edit mütterlicher seits meinte:
Hab grad in den Gerätemanager geschaut, der hatte Probleme mit dem Gerät angezeigt. Hab jetzt die latencytime auf 1 gesetzt und vorher neu angesteckt. Jetzt wuppts

Edit 3:
Glück war nur von kurzer dauer, kaum hatte ich den 2 Edit verfasst hats wieder einfach aufgehört zu laufen.

divBy0 10. Okt 2012 10:21

AW: Tcomport on RXChar Problem
 
Hast du denn einen EventChar definiert, damit das OnRxChar gefeuert wird?

So reagiere ich auf neue Daten:

Delphi-Quellcode:
procedure TRS232Thread.ComPortRxChar(Sender: TObject; Count: Integer);
var
  Received: string;
  CRPosition: Integer;
begin
  (Sender as TComPort).ReadStr(Received, Count);
  FResponse := FResponse + Received;
  CRPosition := Pos(Chr(13), FResponse);
  if CRPosition > 0 then
  begin
    FReceivedStr := Copy(FResponse, 1, CRPosition);
    FResponse := '';
    if MeasureDataValid(FReceivedStr, FValue1, FValue2) then
      Synchronize(DoOnDataRead);
  end;
  FCycles := 0;
end;
Versuchs mal so, ich weiß ja nicht wie das Intervall deines Timer ist:

Delphi-Quellcode:
procedure TForm2.Timer1Timer(Sender: TObject);
var
  Str: String;
begin
  (Sender as TTimer).Enabled := False;
  try
    ComPort1.ReadStr(Str, 10);
    if str <>'' then
      memo2.Lines.Add(stringtohex(str));
  finally
    (Sender as TTimer).Enabled := True;
  end;
end;

PhilmacFLy 10. Okt 2012 10:47

AW: Tcomport on RXChar Problem
 
Ich reagier jetzt so drauf

Delphi-Quellcode:
procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
var
  Str: String;
  first, last: Integer;
begin
  (Sender as TComport).ReadStr(Str, Count);
  if str <>'' then
  begin
  empf := empf + stringtohex(str);
  end;
  if pos('BB BB', empf) > 0 then
  begin
    first := pos('AA AA', empf);
    last := pos('BB BB', empf);
    if last < first then
      begin
      delete(empf, 1, last+5);
      end
    else
      begin
        memo1.Lines.Add(Copy(empf, first+5, last-7));
        //parser.push(empf);
        with TParserthread.Create(empf) do
          begin
            Priority := tpHighest;
            Resume;
          end;
        delete(empf, 1, last+5);
      end;
  end;

end;
Und das scheint zu funktionieren.
Ich lass es jetzt noch n bisschen länger laufen und meld mich nochmal.

divBy0 10. Okt 2012 11:21

AW: Tcomport on RXChar Problem
 
So wie beschrieben nutze ich das einem Thread und lesen Daten von mehreren Messgeräten. Die Variante läuft in verschiedenen Anwendungen 24/7 und es gab noch keine Probleme.

BergLoewe 10. Jun 2022 09:01

AW: Tcomport on RXChar Problem
 
Hallo,


ich greif mal den alten Tröt auf, weil er meinem aktuellen Problem am nächsten kommt.

Ich habe eine FMX-Anwednung und dazu die Winsoft-Komponente installiert:
https://www.winsoft.sk/comport.htm

Nun will ich Hex-Daten zu einem Controller schicken und welche empfangen. Nur Hex, also Bytes, keine Ansi-Chars oder ähnliches. Weshalb ich keine Ende-Erkennung habe. Das Protokoll, das der Controller verwendet, läßt sich nicht ändern, weil ich Geräte mit einbeziehen muß, die seit Jahren im Feld sind.

Nun hab ich das Problem, dass OnRxChar eigentlich das einzige Event ist, das sich zum Empfang nutzen läßt. Aber es tritt nach jedem empfangenen Byte auf. Nur, wenn ich nach jedem Byte selbiges einsammeln und in ein TByte-Array oder ähnliches schreiben will, tritt zwangsläufig der Fall auf, dass während des Ausführens dieser Routine der Empfang ja weiterläuft und sich die empfangenen Daten ändern. Das führt zu Fehlern.
Weshalb ich nun die Erleuchtung hatte, die einem der obigen Kommentatoren auch kam - ich setze einen Timer auf 100ms und lese dann erst die Daten aus. Nach 100ms müßte jede denkbare Sendung durch sein. Das hieße, dass OnRxChar meinen Timer starten müßte.

UNd da kommt das Problem: In dieser OnRxChar-Routine reagiert der Timer.Enable nicht.
Code:
procedure TForm1.CP1RxChar(Sender: TObject);
begin
     Timer1.Enabled := True;
end;
Das macht der nicht.

Nehm ich einen Button, kann ich den Enabled ein- und ausschalten, wie ich will.
Code:
procedure TForm1.Button1Click(Sender: TObject);
begin
    Timer1.Enabled := not Timer1.Enabled;
end;
Da klappt das bestens. Aber in der OnRxChar gar nicht. Genau genommen ändert sich das Property auf True aber der Timer löst kein Event aus.

Gäb's dazu eine Erklärung?

himitsu 10. Jun 2022 09:15

AW: Tcomport on RXChar Problem
 
Warum nicht die Daten auslesen, merken und wenn genug verarbeiten? (siehe #3)




Kommt das Event in einem Thread an? (glaub schon)

wenn ja, dann TThread.Synchronize oder besser TThread.Queue


Die Memo1.Lines.Add, in den oberen Antworten, funktionieren "zufällig", da sie intern SendMessage nutzen und sich so indirekt synchronisieren.

BergLoewe 10. Jun 2022 09:44

AW: Tcomport on RXChar Problem
 
Es ist ja blöderweise nicht bekannt, wann die Sendung zu Ende ist. Keine Anzahl an Bytes, keine Ende-Erkennung durch ein bestimmtes Zeichen. Den Kommentar #3 hatte ich so verstanden, dass der nach "CHR(13)" sucht und damit sein Ende definiert. Bzw. eben auch mit einem Timer arbeitet, wie ich es vorhabe.


Hinsichtlich Threads muß ich ehrlich eingestehen, dass mein Wissen in solche Tiefen nicht reicht. Ich habe in der Anwendung keine Threads vereinbart. Wenn Delphi hier selbstständig auf verschiedene Threads verteilt, weiß ich nicht, wie genau ich das auseinanderhalten oder auf einen anderen Thread zugreifen soll.
Dann aber wär's dennoch irgendwie komisch. Schalte ich den Timer per Button-Click ein, geht's. Schalte ich den in der OnRxChar ein, reagiert der Timer nicht auf den dann wahren Enabled, bzw. läßt das Timer-Event im gleichen Thread aufschlagen.

himitsu 10. Jun 2022 10:12

AW: Tcomport on RXChar Problem
 
Du brauchst so oder so eine Ende-Erkennung, bzw. ob es (mindestens) genug Daten sind.

erstmal irgendwie alles mitschneiden
Delphi-Quellcode:
(Sender as TComPort).ReadStr(Received, Count);
FResponse := FResponse + Received;
oder eben Binär als ByteArray oder Stream lesen+speichern



bezüglich des Timers mußt du ihn im Event beenden und neu starten, damit die Zeit erst nach dem letzten Empfang, im Intervall, verarbeitet wird.
"Nochmal" auf True setzen, wenn schon True war, startet die Zeit nicht neu.

Oder den Timer immer laufen lassen, bzw. beim ersten Empfangen starten
dann auch noch die Empfangszeit merken oder im Timer prüfen, ob sich seit dem letzten OnTimer etwas (Zeit oder Daten im Puffer) geändert hat
und wenn vorher, aber nicht beim letzten Mal, geändert, dann erst verarbeiten (und im Notfall auch noch wenn "zuviele" Daten vorhanden sind, die auf jeden Fall ausreichen, falls etwas hing)




In einem ähnlichen Fall hatte ich bei jedem Empfang geprüft ob eine Mindestmenge an Daten vorhanden sind (der Header)
und dann versucht die Daten zu dekodieren ... gab es Probleme, weil noch was fehlt, dann Abbruch und später nochmal, wenn wieder Neues rein kommt. (wenn erfolgreich verarbeitet, dann diese Daten aus dem Puffer löschen)

TurboMagic 10. Jun 2022 19:09

AW: Tcomport on RXChar Problem
 
Hallo,

muss es diese Komponente sein?
Alternativ mal TComPortDrv aus GetIt probiert?

Die liefert nicht nur Zeichen für Zeichen...

Grüße
TurboMagic

himitsu 10. Jun 2022 21:39

AW: Tcomport on RXChar Problem
 
macht TComPort auch nicht ... es liefert garkeine Zeichen. (es sagt, gerade war was reingekommen und x Zeichen sind aktuell im Puffer)

OnRxChar liefert quasi 1 bis x Zeichen, je nach dem, wieviel bereits im Buffer gelandet ist und noch nicht abgeholt wurde, z.B. mit ReadStr.

BergLoewe 13. Jun 2022 10:02

AW: Tcomport on RXChar Problem
 
Hallo,


vielen Dank erst mal, dass Ihr Euch meiner Probleme annehmt! Ich hatte am Wochenende leider keine Zeit, da meine Enkelin ihren großen Tag hatte und meine Angetraute etliches am Haus gemacht haben wollte. Daher erst jetzt ein Response.

Ich habe es jetzt zunächst mal so gemacht, dass ich den Timer beim Senden starte. Das ist nicht ideal, weil damit die Reaktionszeit der Gegenseite mit berücksichtigt werden müßte und die kann sehr unterschiedlich sein. Aber jetzt zum reinen Testen erst nmal so.
Im Prinzip geht das so. Leider aber nicht immer. Stochastisch zeigt der mir mitunter falsche Daten und vor allem falsch Byte-Anzahlen an. Und irgendwann hängt sich die App dann ganz auf.

Ich versuch's jetzt doch erst mal mit einer anderen Komponente. Aber ich nehm die ASync von TMS. MIt der habe ich vor 10 oder 12 Jahren schon mal sowas gemacht, damals unter Delphi2005. Die Winsoft wollte ich, weil die auch unter FMX läuft, die TMS wohl nicht. Die Anwendung soll später mal auch auf anderen Platformen laufen. Dann auch per WLAN oder Bluetooth. Deshalb habe ich das -was mir völliges Neuland ist- unter FireMonkey angefangen und wollte eben zunächst einmal das ganze via USB/RS232 aufbauen.

himitsu 13. Jun 2022 10:52

AW: Tcomport on RXChar Problem
 
Wenn garnichts geht, dann kannst du es auch selbst machen ... am Besten in einem Thread, falls zwischen zwei Empfängen zu viel Zeit vergeht und der Haupthtread dann immer wieder etwas hängt.


CreateFile+ReadFile, wobei man ReadFile+Overlapped auch im Hauptthread asynchron nutzen könnte (ohne hängen)
oder TFileStream, bzw. THandleStream+CreateFile und Stream.Read***
oder Assign+Read (das alte Pascalzeugs)
oder ...

und als Dateiname z.B. 'COM1' bis 'COM9'
so lange im Windows als Standard bereits die richtige Config (Baud, StopBits, Parität usw.) eingestellt ist, mußt du im Programm nichts weiter machen.
wenn doch nicht, dann MSDN-Library durchsuchenSetCommState nach dem CreateFile -> https://docs.microsoft.com/de-de/win...tions-resource


also im Thread die "Datei" (Gerät) öffnen
ein oder mehere Byte auslesen (read) ... es wird ohne Overlapped bestimmt gewartet, bis diese x Bytes da und gelesen sind (darum im Thread)
eventuell die Bytes in einer Variable (TBytes bzw. TArray<Byte>) zwischenspeichern
und dann via Synchronize oder Queue in den Haupthtead damit (oder wenn möglich auch direkt im Thread verarbeiten und das Ergebnis in den Hauptthread)

BergLoewe 21. Jun 2022 13:32

AW: Tcomport on RXChar Problem
 
Moin,

nachdem ich nun fluchend Tage damit verlebte, andere Komponenten zu installieren und festzustellen, dass die in FMX nicht laufen, kam ich zur ursprünglichen Winsoft-Komponente zurück.

Naja, was soll ich sagen - vielleicht bin ich zu blöd, zu alt, zu blind(leider nicht zu besoffen, dann hätt ich was davon) aber jetzt läßt sich der Timer plötzlich aus der OnRxChar-Funktion heraus starten. Was er letzte Woche ums Verrecken nicht machen wollte.

Also vielen Dank dennoch, für Eure Hilfe und Eurer Verständnis.

Rollo62 21. Jun 2022 17:02

AW: Tcomport on RXChar Problem
 
Zitat:

Zitat von BergLoewe (Beitrag 1507134)
... empfangenen Byte auf. Nur, wenn ich nach jedem Byte selbiges einsammeln und in ein TByte-Array oder ähnliches schreiben will, tritt zwangsläufig der Fall auf, dass während des Ausführens dieser Routine der Empfang ja weiterläuft und sich die empfangenen Daten ändern. Das führt zu Fehlern.

TL;DR;
Ist vielleicht schon beantwortet.

Im Prinzip ist das richtig so wie Du oben schreibst:
1a.) Schnell sammeln
1b.) LOCK
1c.) Daten in einen Speicher schreiben, möglichst kurz
1d.) UNLOCK
1e.) Und schnell wieder raus

2a.) Später in Ruhe, Analyse
2b.) TRY-LOCK
2c.) Schnell Arbeitskopie holen, möglichst kurz
2d.) UNLOCK
2e.) Check in Ruhe an der Aerbeitskopie ob ein Datensatz fertig ist
2f.) - wenn ja, Auswerten
2g.) - ausgewertetes Kommando ( Ende-Position merken )
2h.) LOCK
2i.) Aktuelles Kommando im Arbeitsspeicher schnell löschen, bis zur Ende-Position
2h.) UNLOCK

So oder so ähnlich, möglicherweise auch mit Umschaltung von zwei Speicherbereichen.
Ich nutze dafür einen RingBuffer mit gelocktem Read und Write.

Dabei sollten man die Umschaltstellen besonders beachten und sauber kapseln, vielleicht liegt das Problem irgendwo da.
Gerade die sichere Übergabe der Daten ist kritisch.

BergLoewe 27. Jun 2022 18:26

AW: Tcomport on RXChar Problem
 
Also nachdem der Timer -warum auch immer erst so spät- einsieht, dass er sich in der Empfangsroutine starten lassen soll, geht's eigentlich.
Wobei:
Erstens wird das Event OnRxChar nicht mehrfach aufgerufen, sondern immer nur einmal. Ich hatte da einen Zähler laufen, der zeigt nur "1" an.
Zweitens -ich sende/empfange ja ausschließlich Bytes, also keine Chars oder Strings oder Ascii oder so- Auslesen des COMPORT-Buffers funktioniert nur mit ReadBytes. Aber das geht dann. Ich mach das final im Timer-Event.
Eines ist aber doch ganz komisch:
Die Gegenseite ist zunächst eine Sensor-/Kommunikationsbaugruppe mit einem Mikrocontroler, der via USB über einen CP210 und dessen RS232 angesprochen wird. Da hab ich noch Zugriff auf die Software, kann also das Prtokoll bestimmen. Die Baugruppe soll sich zunächst melden, sagen, wie sie heißt und auf weitere Anfrage ihre Software-Versionen bekannt geben. Nun hatte ich offensichtlich Übertragungsfehler, so dass das Delphi-Programm sehr oft zu wenig oder was falsches verstand. Im Controler hab ich deshalb eine Verzögerung zwischen den Sende-Bytes eingebaut, seither geht's mit der eigentlich drei Byte längeren Versions-Abfrage super. Sowohl in 9600 Baud, als auch 19200Baud. Die kürzere Sendung mit der Typnummer aber, da sind die Übertragungsfehler nicht wegzukriegen. Der Fehler liegt aber im PC/Delphiprogramm. Auf dem Oszi gibt's da keine Abweichungen. Ich hoffe nur, dass sich das nicht mit anderen Geschichten fortsetzt, da sollen später 64Byte lange Blöcke über einige hundert Kilobyte übertragen werden. Soweit bin ich aber momentan noch nicht.

Aber noch eine ganz andere Frage, die eigentlich nichts mit der COMPORT-Schnittstelle zu tun hat:
Ich sende an die Baugruppe bestimmte Dinge, die bestimmte Antworten erbringen sollen. Die sind dann recht kompliziert auszuwerten und dann geht das ganze wieder von vorn los. Das heißt, im Timer_Event, was dem Empfang folgt, wird eine Auswerte-Routine aufgerufen, die dann wieder den nächsten Schritt sendet. Was aber eben wieder Empfangs- und Timer-Event aufruft. Wenn jetzt der Quittungssempfang nach dem Senden einer Zeile schon fertig ist, bevor die Auswerteroutine und die Timer-Event-Roiutine abgeschlossen wurden, dann wird das Ding doch rekursiv - oder? Erstens, verträgt Delphi überhaupt sowas und zweitens gibt's da im Delphi so'ne Tricks, wie man eine Art Hauptschleife simuliert?

BergLoewe 28. Jun 2022 08:38

AW: Tcomport on RXChar Problem
 
Also diese Übertragungsfehler sind definitiv eine Zeitfrage. Wenn der Controller schneller als binnen 3ms antwortet, verschluckt der Delphi-PC gerne mal die Hälfte.
Hätt ich nicht gedacht.


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