Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi ApdCOMPort: Daten gehen bei großen Datenmengen verloren (https://www.delphipraxis.net/133656-apdcomport-daten-gehen-bei-grossen-datenmengen-verloren.html)

Carsten1234 6. Mai 2009 14:20


ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Hallo zusammen,

ich habe mit der aktuellsten Version das Problem, dass mir offensichtlich Daten im Buffer verloren gehen oder überschrieben werden.
Vorab:
Über einen Virtual COM Port Treiber wird ein Gerät via USB angeschlossen. Schicke ich Daten an das Gerät, erfolgt von diesem eine Rückmeldung in einer bestimmten Art und Weise. Die ersten drei Zeichen, der sog. Kopfblock, enthält u.a. die Datenlänge. Diese wiederum bestimmt die Länge der nachfolgenden Daten.
In rudimentären Grundroutinen lesen ich zunächst die den Kopfblock aus und anhand der im Kopfblock übertragenen Länge anschliessend den Datenblock selbst.
Bsp. (stark vereinfacht):
Delphi-Quellcode:

const
  HEADBLOCKSIZE = 3;
  DATABLOCKSIZE = 4096;

var
  Head_Block = array[1..HEADBLOCKSIZE] of char;
  Data_Block = array[1..DATABLOCKSIZE] of char;

procedure GetHeadBlock;
begin
  repeat
    Application.ProcessMessages;
  until (TimeoutFlag) or (ApdComPort.InBuffUsed >= HEADBLOCKSIZE);
  if (not TimeoutFlag) then
  begin
    ApdComPort.GetBlock(Head_Block, HEADBLOCKSIZE);
  end;
end;

procedure GetDataBlock(ASize: word);
begin
  repeat
    Application.ProcessMessages;
  until (TimeoutFlag) or (ApdComPort.InBuffUsed >= ASize);
  if (not TimeoutFlag) then
  begin
    ApdComPort.GetBlock(Head_Block, ASize);
  end;
end;
Vorher wurde ein Timer gesetzt, der nach max. 3 Sek. anspringt und das TimeOutFlag auf TRUE setzt, so dass die Endlosschleife unterbrochen wird.
Diese (grob skizzierten) Routinen arbeiten eigentlich auch ganz wunderprächtig, so lange die Datenmenge zw. PC und Gerät rel. klein ist.

Nun sollen aber auch größere Datenmengen (Dateien) in Blöcke zu max. 4kB vom PC zum Gerät übertragen werden. Dazu wird über eine while not (EoF(...)) do die zu übertragene Datei in 4kB-Häppchen zerlegt und via ApdComPort.PutBlock an das Gerät übertragen.
Nachdem ein 4kB-Block übertragen wurde, warte ich über die beiden Routinen oben die Rückmeldung vom Gerät ab. Der Kopfblock bestimmt wieder die Länge der Rückmeldung und im Datenblock wiederum steht die Rückmeldung.
Leider kommt es mitunter und zu immer anderen Zeitpunkten vor, dass die Daten im InBuffer völlig zerschossen sind, wobei jedoch kurioserweise ein Mitschnitt auf dem USB-Port angibt, dass die Daten noch korrekt vom Gerät an die PC-Schnittstelle kommen. Der Mitschnitt bzw. die Hardware dazu ist ein Gerät, dass quasi in das USB-Kabel zw. Gerät und PC gehängt wird.
Ferner hatte ich festgestellt, dass es eine deutliche Besserung bringt, wenn ich in der while not (EoF(...)) do ein Delay von 30..40ms einbaue. De facto scheint es also irgendwo ein Buffer Overflow zu geben (meine Mutmassung).
Das PDF-Handbuch zu AsyncPro beschreibt diesbzgl. auf S. 31ff ein "eventually overflow the PC's input buffer and data would be lost".
Ein Hardware Flow Control scheidet auf jeden Fall aus, doch auch ein Software Flow Control sowohl über die Einstellungen bei ApdCOMPort als auch in den COM-Port Einstellungen über den Gerätemanager bringen nix. Ebenso wenig bringt ein 'Flushen' der beiden Buffer. :-(

Fragen:
1) Ist meine Mutmassung bzgl. Buffer overflow richtig?
2) Hat jemand noch eine gute Idee, das Problem in den Griff zu bekommen?

Dank vorab und Gruß, Carsten

user0815 6. Mai 2009 15:32

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Hast Du zum testen dazu mal die ApdDataPacket Komponente eingesetzt ?

Rechtsklick drauf und man kann die StartCond + EndCond setzen oder auch erstmal jeden String akzeptieren.
Evtl. den TimeOut auf 0 Stellen.
Ausgabe über das Event "ApdDataPacket1StringPacket"

Carsten1234 6. Mai 2009 16:30

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von user0815
Hast Du zum testen dazu mal die ApdDataPacket Komponente eingesetzt ?

Rechtsklick drauf und man kann die StartCond + EndCond setzen oder auch erstmal jeden String akzeptieren.
Evtl. den TimeOut auf 0 Stellen.
Ausgabe über das Event "ApdDataPacket1StringPacket"

Damit hatte ich es noch nicht versucht. Allerdings hatte ich noch vergessen zu erwähnen, dass ich sowohl den Log- als auch Trc-Mitschnitt aktiviert hatte und dort die Daten korrekt auftauchen.

Gruß, Carsten

Trigger2003 6. Mai 2009 16:51

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Was ich noch nicht erkennen kann:

Was hält denn den Sender (PC) davon ab, nach Senden der ersten 4K sofort den nächsten Datenblock zu übertragen, für den Du eigentlich doch nicht unmittelbar Platz hast (-> Overflow). Eine Art von Quittung, Handshake o.Ä. kann ich im Beispielcode nicht erkennen. Das würde auch erklären, warum sich die Situation mit Delays zwischen den Datenblocks bessert, weil das dem Empfänger Zeit verschafft, einen vollständigen Datenblock erstmal zu verarbeiten und den benötigten Empfangspuffer wieder freizugeben.

Ich denke, ohne eine Art Protokoll (positive oder negative Rückmeldung) wird es kaum sauber hinzukriegen sein. So in der Art des uralten XModem- oder ZModem-Protokolls..

Oder habe ich da was falsch verstanden?

taveuni 6. Mai 2009 16:55

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Jetzt mal ohne genau Deinen Code zu analysieren.
Wir arbeiten seit Jahren mit AsyncPro.

Allerdings empfangen wir im TriggerAvail.
Beispiel:

Delphi-Quellcode:
procedure TSickLMxDevice.TriggerAvail(CP: TObject; Count: Word);
var
  buffer : array [0..4095] of byte;
  crcBuffer : array[0..4095] of byte;
  i: Integer;
  dataLength : word;
  tmpBufferSize : Integer;
const
  minRXTelegramLength = 8;
begin
  try
    TApdComPort(CP).GetBlock(buffer, Count);
Kannst Du Dich da mal reinhängen und überprüfen ob der buffer dann immer
das gewünschte enthält? Falls ja machst Du was falsch.

Carsten1234 6. Mai 2009 17:22

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Trigger2003
Was ich noch nicht erkennen kann:

Was hält denn den Sender (PC) davon ab, nach Senden der ersten 4K sofort den nächsten Datenblock zu
(...)
Oder habe ich da was falsch verstanden?

Das Problem ist, dass es weder ein Hardware noch Software Flow Control mit dem Gerät gibt. Der PC (mein Programm) wartet in den genannten Schleifen max. 3 Sek. auf eine Rückmeldung bzw. darauf, dass Daten im InBuffer von ApdCOMPort liegen. Die Rückmeldung vom Gerät soll quasi (im übertragenen Sinne) der Handshake sein und das Zeichen dafür, dass vom Gerät die Daten verarbeitet wurden.
Ich vermute daher kein Overflow im Gerät, sondern im UART, der eine gewisse Zeit benötigt, die Daten zu verarbeiten.

Trigger2003 6. Mai 2009 17:29

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Fragen über Fragen zum besseren Verständnis:

Wer schickt denn jetzt wem (Nutz-)Daten? PC an Gerät oder umgekehrt? Beide? Ist da schon irgendein Protokoll mit Quittungsblocks implementiert/dokumentiert? Dein OP klingt ja so, aber in dem Fall vermisse ich eine Art Prüfsumme. Bei einem Block-orientierten Protokoll benötigst Du eigentlich keine Flow-Control, weil ja der Quittungsblock die erneute Empfangsbereitschaft melden soll.

Schreibst Du die Routinen für beide Seiten oder nur für die PC-Seite? Mit anderen Worten: Kannst Du den Aufbau des Protokolls beeinflussen?

Ist das "Gerät" irgendeine Blackbox (Meßgerät o.Ä.), die aufgezeichnete Daten/Meßwerte/wasauchimmer seriell (RS232/RS485) über einen USB-Schnittstellenwandler abliefert oder hat das Gerät ein echtes USB-Interface, das dann durch den VirtualComPort-Treiber wie eine zusätzliche RS232 erscheint? Mit welcher Baudrate wird übertragen (wg. Timings)?

Im ersten Fall würde ich mit einer "echten" RS232 testen, um Fehler im virtuellen ComPort-Treiber auszuschließen. Nach meiner Erfahrung ist die RS232-Emulation durch den Treiber keineswegs 100% kompatibel, gerade was das Zeitverhalten der Statusregister angeht.

Chemiker 6. Mai 2009 18:48

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Hallo Carsten1234,

wie user0815 bereits ausgeführt hat, bittet sich für Deine Aufgabe das ApdDataPacket an. Die Buffer-Verwaltung sollte man der Komponente überlassen. Wahrscheinlich wird schon der Buffer wieder beschrieben, wenn Dein Programm grade den Buffer ausliest.

Bis bald Chemiker

Carsten1234 7. Mai 2009 06:14

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Trigger2003
Fragen über Fragen zum besseren Verständnis:
(...)
Im ersten Fall würde ich mit einer "echten" RS232 testen, um Fehler im virtuellen ComPort-Treiber auszuschließen. Nach meiner Erfahrung ist die RS232-Emulation durch den Treiber keineswegs 100% kompatibel, gerade was das Zeitverhalten der Statusregister angeht.

Na, dann versuche ich mal Licht ins Dunkle zu bringen. :)
Bei dem Gerät handelt es sich um ein Gerät mit echter USB-Schnittstelle, wird allerdings wie bereits geschrieben via einem Virtual COM Port Treiber mit dem PC (Windows) verbunden. Die Erklärung, warum das so gemacht wird und nicht mit echtem USB würde den Rahmen sprengen.
Die Baudrate liegt bei 9600Baud, wobei die Einstellung keinen Einfluss auf die tatsächliche Geschwindigkeit hat, da die max. Übertragungsrate immer bei ~140kB/s liegt. Ob das jetzt nun schnell bzw. zu schnell für den UART und/oder den Treiber ist, kann ich nicht beurteilen.
Ich schreibe nur das Programm auf PC-Seite, für die Firmware ist eine andere Inhouse-Abteilung zuständig. Einfluss auf mögl. Änderungen im Gerät hätte ich aber, da alles, also auch die Hardwareentwicklung Inhouse geschieht.

Zum Protokoll (sofern man das so nennen will):
Im sog. Kopfblock, den ersten drei Bytes, steht als erstes Byte die sog. Befehlsfamilie, Byte 2 und Byte 3 bestimmen die Länge des nachfolgenden Datenblocks.

Schicke ich nun einen 4K-Häppchen an das Gerät, erzeuge ich ebenfalls diesen "Overhead" vorne dran, in dem ich die Befehlsfamilie und die Länge des nachfolgenden Datenblocks schicke. Im Pseudocode: "Gerät, jetzt kommen Binärdaten mit der Länge 4096 Bytes". Genau genommen schicke ich also 3 + 4096 Bytes. Wenn das Gerät die Daten empfangen hat, bekomme ich eine Antwort vom Gerät in derselben eben genannten Weise. Das erste Byte liefert mir wieder die Befehlsfamilie und Byte 2 und Byte 3 die Länge des Datenblock.
Wurden die von mir geschickten Daten vom Gerät korrekt empfangen und verstanden, ist die Datenlänge 1 und ich muss nur auf das ersten Byte des Datenblocks schauen, wobei dieses Byte einen bestimmten Wert für OK haben muss. Ist die gelieferte Länge > 1, liegt eine Fehlermeldung seitens des Geräts vor und die Bytes des Datenblock ab Position 2 bis {geschickte Datenlänge} liefern den Fehlercode (z.B. Gerät hat Daten nicht korrekt empfangen od. ähnl.).

Wir haben, wie weiter oben geschrieben, mal einen Datenlogger in die USB-Leitung gehängt. Über diesen sehen wir, dass bis zum Abbruch meinerseits das Gerät immer mit OK geantwortet hat. Ferner bietet ja ApdCOMPort ein Logging und Tracing und auch hier sind die vom Gerät empfangenen Daten noch i.O. Markant ist allerdings, dass alles sauber durchläuft, wenn ich zw. dem Versenden meines Datenpakets und dem Warten auf eine Antwort ein Delay von 30..40ms einbaue. Zudem ist dieser Effekt auch recht neu, nämlich erst seitdem die Übertragungsgeschwindigkeit aufgebohrt wurde.
Was jedoch wiederum gg. einen Fehler in meinen beiden Routinen spricht ist die Tatsache, dass über diese Routinen ALLE Kommunikationen mit dem Gerät laufen, also z.B. auch das Auslesen von Werten, Lesen und Schreiben von Konfig-Daten im Gerät usw.. Als dies läuft fehlerfrei, allerdings sind hier die übertragenen Datenmengen auch überschaubar klein (max. einmalig 1kB/Befehl). Ferner tritt der Effekt auch nicht bereits nach dem ersten übertragenen 4k-Block auf, sondern später, allerdings zu unterschiedlichen Zeitpunkten. Mal sind bereits 200kB übertragen, beim nächsten Mal 600kB, 1MB, .... Ich kann also noch nicht mal sagen, dass der Fehler immer nach xkB auftritt.
Und Debuggen ist auch nicht möglich, da es dann nicht mehr zeitkritisch ist und alles sauber durchläuft.

Zum Treiber:
Wird das Gerät erstmalig mit dem PC verbunden und Windows kennt das Gerät noch nicht, wird die INF-Datei angefordert. Diese INF-Datei stammt vom Chiphersteller, dessen Chip im Gerät werkelt. Was da dann genau abgeht bei der Treiberinstallation, vermag keiner so richtig zu sagen. Wir gehen allerdings davon aus, dass ein windowseigener Virtual COM Port Treiber installiert wird.

Gruß, Carsten

Carsten1234 7. Mai 2009 06:27

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von taveuni
Kannst Du Dich da mal reinhängen und überprüfen ob der buffer dann immer
das gewünschte enthält? Falls ja machst Du was falsch.

Das habe ich getan und bekomme schon nach rel. kurzer Zeit eine Exception, die da lautet:
Im Projekt ist eine Exception der Klasse EOutputBufferToSmall mit der Meldung 'Output buffer too small for small for block' aufgetreten.

Die Größen:
InSize:= 16384;
OuSize:= 16384;

Gruß, Carsten

Carsten1234 7. Mai 2009 06:36

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von user0815
Hast Du zum testen dazu mal die ApdDataPacket Komponente eingesetzt ?

Rechtsklick drauf und man kann die StartCond + EndCond setzen oder auch erstmal jeden String akzeptieren.
Evtl. den TimeOut auf 0 Stellen.
Ausgabe über das Event "ApdDataPacket1StringPacket"

Hhhmm, datt Ding will ja eine Start- und End-Condition. Als StartCond wähle ich 'scAnyData', doch was nehme ich als EndCond?
Ich weiß vorher weder etwas über das geschickte Ende noch etwas über die Datenlänge, die da kommt.
Halt, ich habe jetzt die ecPacketSize angeknipst und die Länge auf 3 gesetzt. Dann läuft es erstmal eine Weile bis zur genannten Exception ecOutputBufferTooSmall. :wall:

Gruß, Carsten

Chemiker 7. Mai 2009 06:56

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Hallo Carsten,

stelle mal InSize auf 2 ein.

InSize=2;

Da nicht bekannt ist wie viel Daten übertragen werden, ist die Einstellung 2 ganz gut.

Bis bald Chemiker

Carsten1234 7. Mai 2009 07:03

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Chemiker
stelle mal InSize auf 2 ein.

Teste ich mal.
BTW: Was ist der Unterschied zw. der TRC- und LOG-Datei? In der LOG-Datei sind die empfangenen Daten i.O., in der TRC-Datei allerdings sehe ich fehlerhafte Empfangsdaten. :gruebel:

Gruß, Carsten

Nachtrag:
Bei InSize:= 2 gibt es eine Exception.
Im Projekt ist eine Exception der Klasse EBadArgument mit der Meldung 'Bad argument passed to function' aufgetreten. :evil:

Nachtrag 2:
Es waren (wozu auch) keine HWFlowOptions gesetzt. Setze ich z.B. hwUseDTR, kommt die Excpetion nicht mehr. Allerdings bricht auch mit der Einstellung 2 der Datentransfer irgendwann ab.
BTW: Ich teste zZt. nicht im eigentlichen Programm, sondern mit einem kl. Testprogrämmchen, was ganz simpel gestrickt ist.

Carsten1234 7. Mai 2009 08:05

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Trigger2003
Im ersten Fall würde ich mit einer "echten" RS232 testen, um Fehler im virtuellen ComPort-Treiber auszuschließen. Nach meiner Erfahrung ist die RS232-Emulation durch den Treiber keineswegs 100% kompatibel, gerade was das Zeitverhalten der Statusregister angeht.

Hier nochmal nachgehakt:
Wie ist denn eigentlich der Datenverlauf durch den PC?

[ ] Gerät => Treiber => UART => ApdCOMPort => PC-Programm
[ ] Gerät => UART => Treiber => ApdCOMPort => PC-Programm

M.M.n. unterstützt ein Treiber die Hardware, insofern bin ich der Meinung, das erstgenannte ist richtig.

Gruß, Carsten

Trigger2003 7. Mai 2009 10:12

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Carsten1234
Wie ist denn eigentlich der Datenverlauf durch den PC?

[ ] Gerät => Treiber => UART => ApdCOMPort => PC-Programm
[ ] Gerät => UART => Treiber => ApdCOMPort => PC-Programm

IMHO Weder noch. In diesem speziellen Fall emuliert der Treiber nur einen UART, ist also eigentlich ein RS232-Emulator-Treiber und kein Gerätetreiber im klassischen Sinn.

also Gerät => Emulator/Treiber => ApdCOMPort => PC-Programm

Trigger2003 7. Mai 2009 10:33

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Carsten1234
BTW: Was ist der Unterschied zw. der TRC- und LOG-Datei? In der LOG-Datei sind die empfangenen Daten i.O., in der TRC-Datei allerdings sehe ich fehlerhafte Empfangsdaten. :gruebel:

TRC ist die Aufzeichnung der Kommunikation zwischen APro und dem Windows-Treiber, Du kannst nur sehen, wie Transmit und Receive grob chronologisch abgelaufen sind, aber z.B. keine genauen Timinginformationen sehen.

LOG ist die Aufzeichnung der Kommunikation und Aktionen der APro-Komponenten untereinander mit genauen Timingangaben.

Siehe auch Apro Reference Guide, Kapitel 2

Carsten1234 7. Mai 2009 10:44

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Vielen Dank für die Erklärung. Demzufolge ist also dir Trace-Datei maßgebend zur Fehlersuche.
Und hier sind ja die empfangenen Daten verkehrt, demzufolge kommen also schon die Daten "von unten irgendwo her" falsch bei mir an.

Carsten1234 8. Mai 2009 05:51

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Hallo zusammen!

So, nach einer 'etwas längeren' Debug-Session und Codeanalyse mit einem Kollegen sind wir dem Übel auf die Spur gekommen, wobei wir der Ansicht sind, dass es sich um einen Bug in ApdCOMPort (v4.07) handelt. Aber der Reihe nach:

Das Übel beginnt mit dem ApdCOMPort.GetChar in meinem Programm. Nach Aufruf des Befehls wird in die Datei 'AwUser.pas' in Zeile 1570ff verzweigt. Hier wird normalerweise im ELSE-Zweig ab Zeile 1588ff genau ein Zeichen geholt und dieses auch aus dem Empfangspuffer gelöscht. Manchmal aber kommt es vor, dass in "InAvailMessage" TRUE ist. In diesem Fall wird zwar auch ein bzw. das letzte Zeichen aus dem Empfangspuffer (PeekCharPrim(C, GetCount);) geholt, es wird aber nicht gelöscht. So kann es also vor kommen, dass ein Zeichen doppelt empfangen bzw. ausgelesen wird.
Wann jedoch wird nun "InAvailMessage" TRUE?
Die Antwort dazu findet sich in derselben Datei ab Zeile 2123ff bzw. 2146ff. Das Problem bei dieser ganzen Routine ist unserer Meinung nach: Es wird zwar hier und da mit CriticalSection gearbeitet, doch ausgerechnet die Zeile, in der "InAvialMessage" auf TRUE gehen kann (Zeile 2146), befindet sich ausserhalb einer CriticalSection. Und dies ist u.M.n. der Bug selbst.

Mit anderen Worten: Ich darf via GetChar/GetBlock nicht auf den Empfangspuffer zugreifen, so lange noch Daten eintrudeln (könnten). Dummerweise nur weiß ich leider nicht, wann die Übertragung tatsächlich beendet wurde und nix mehr kommt.
ApdDataPacket ist auch irgendwo nur eine halbherzige Lösung, denn die EndCond könnte ja auch rein zufällig in den Binärdaten vorhanden sein.

Geändert habe ich die Routine für den Kopfblock erstmal wie folgt:
Delphi-Quellcode:
procedure TForm1.GetHeadBlock;
var x            : word;
    OldBuffInSize : integer;
begin
  OldBuffInSize:= -1;
  while (OldBuffInSize < 0) or
        (OldBuffInSize <> ApdComPort.InBuffUsed) or
        (ApdComPort.InBuffUsed = 0) do
  begin
    Application.ProcessMessages;
    Delay(30);
    OldBuffInSize:= ApdComPort.InBuffUsed;
    if (TimeoutFlag) then
      Break;
  end;

  if (not TimeoutFlag) then
  begin
    ApdComPort.GetBlock(Head_Block, HEADBLOCKSIZE);
  end
  else
    Memo.Lines.Add('Timeout beim Warten auf Kopfblock');
end;
Hierbei ist allerdings auch nur das Delay verschoben aus der Hauptroutine zum Empfang und zur Auswertung aller empfangenen Daten.

Eure Meinungen?

Gruß, Carsten

Trigger2003 8. Mai 2009 07:59

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Die Antwort, warum bei InAvailMessage das Zeichen nur gelesen, aber nicht entfernt wird, steht doch im Quelltext von GetChar...oder bin ich noch zu müde? :gruebel:

Versuch: Füge mal ApdCOMPort.ProcessCommunications nach Application.ProcessMessages ein und schmeiß das Delay raus

Carsten1234 8. Mai 2009 08:27

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Trigger2003
Die Antwort, warum bei InAvailMessage das Zeichen nur gelesen, aber nicht entfernt wird, steht doch im Quelltext von GetChar...oder bin ich noch zu müde? :gruebel:

Als Kommentar, richtig. Nur muss man den erstmal gelesen haben. :P

Zitat:

Zitat von Trigger2003
Versuch: Füge mal ApdCOMPort.ProcessCommunications nach Application.ProcessMessages ein und schmeiß das Delay raus

Sah jetzt bei 2 Versuchen ganz brauchbar aus. Danke erstmal für den Tipp, ich werde weiter testen.

Gruß, Carsten


Grrmmpppf - NÖ! :evil:

Trigger2003 8. Mai 2009 08:28

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Carsten1234
ApdDataPacket ist auch irgendwo nur eine halbherzige Lösung, denn die EndCond könnte ja auch rein zufällig in den Binärdaten vorhanden sein.

Halbherzig? Wieso das?
Für Binärdaten kann die End-Condition doch genausogut auch durch die Blockgröße definiert sein. Kommt ganz auf die Art der Daten an....

Carsten1234 8. Mai 2009 08:33

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Trigger2003
Halbherzig? Wieso das?
Für Binärdaten kann die End-Condition doch genausogut auch durch die Blockgröße definiert sein. Kommt ganz auf die Art der Daten an....

Also jedes Mal umschalten in Abhängigkeit der Daten bzw. des Datentransfer. Lässt sich das bewerkstelligen, wenn der Port offen ist?

Trigger2003 8. Mai 2009 08:37

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Carsten1234
Also jedes Mal umschalten in Abhängigkeit der Daten bzw. des Datentransfer. Lässt sich das bewerkstelligen, wenn der Port offen ist?

Weiß ich nicht mehr auswendig. Versuch macht kluch...

Laß das ApdComPort.ProcessCommunications aber trotzdem drin, gehört einfach in die Warteschleife

Carsten1234 8. Mai 2009 08:43

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von Trigger2003
Laß das ApdComPort.ProcessCommunications aber trotzdem drin, gehört einfach in die Warteschleife

Gut, mache bzw. lasse ich. Trotzdem überlege ich noch, die Komponente dahingehend zu erweitern, entweder den Status von InAvailMessage über eine Funktion nach außen zu führen und/oder GetChar mit einem booleanschen Flag ReadOnly:= true/false zu erweitern - oder beides. :gruebel:

Delphi-Quellcode:
function TApdBaseDispatcher.GetChar(var C : Char; AReadOnly: boolean = false) : Integer;
    {-Return next char and remove it from buffer}
  begin
    EnterCriticalSection(DispSection);
    try
(...)
      if (InAvailMessage) or (AReadOnly) then begin
        Inc(GetCount);
        Result := PeekCharPrim(C, GetCount);
        if Result < ecOK then begin
          Dec(GetCount);
          Exit;
        end;
      end else begin
(...)
    finally
      LeaveCriticalSection(DispSection);
    end;
  end;
Gruß, Carsten

Carsten1234 8. Mai 2009 09:59

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
So, mit den beiden von mir genannten Erweiterungen geht es.
In der repeat..until-Schleife zum Auslesen der Kopfdaten weiß ich, dass deren Länge 3 Zeichen haben muss. Ich warte also so lange, bis drei Zeichen im InBuffer liegen und hole sie mir dann via GetChar raus, wobei ich diese Zeichen NICHT aus dem InBuffer lösche bzw. löschen lasse. So habe ich die Länge und kann in der nachfolgenden Schleife warten, bis 3 + errechnete Zeichenlänge im InBuffer sind.
Dann lese ich alle Zeichen aus und lasse sie löschen.
Die zweite Erweiterung der Komponenten ist die Abfrage von InAvailMessage. Ist in meinen Schleifen der Wert true, warte ich weiter.


Delphi-Quellcode:
repeat
  Application.ProcessMessages;
  ApdCOMPort.ProcessCommunications;
  if ApdComPort.Dispatcher.GetInAvailMessageState then // true, wenn InAvailMessage = true
    Continue;
until (TimeoutFlag) or (ApdComPort.InBuffUsed >= ASize);
if (not TimeoutFlag) then
begin
  ApdComPort.GetChar({true} oder {false});
end;

Gruß, Carsten

Carsten1234 28. Mai 2009 07:24

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Zitat:

Zitat von taveuni
Allerdings empfangen wir im TriggerAvail.

Das muss ich nochmal aufgreifen.
Könnte man diesen Trigger aufgreifen und auf Count triggern, wenn mind. x Zeichen im Puffer liegen?
Wie oft fällt dieser Trigger eigentlich? Immer dann, wenn wieder ein Zeichen im Puffer dazu gekommen ist?

Gruß, Carsten

taveuni 28. Mai 2009 14:51

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Hmmh..
Ich weiss nicht genau was Du damit meinst.
TriggerAvail ist vergleichbar mit DataAvailable einer Socket Komponente.
Wenn Daten im Empfangsbuffer ankommen wird dieser Event ausgelöst.
Wieviele das sind hängt vom Sender, der Baudrate und den Einstellungen ab.

Wenn Du in diesem Event nun GetBlock ausführst erhältst Du den Inhalt des Buffers.
Danach wird dieser automatisch für den nächsten Event gelöscht.
Die erhaltenen Daten musst Du nun verarbeiten.

Also Pseudocode:
Delphi-Quellcode:
procedure MyComport.TriggerAvail(CP: TObject; Count: Word);
var
  buffer : array [0..4095] of byte;
  i : Integer;
  s : String;
begin
  s := '';
  TApdComPort(CP).GetBlock(buffer, Count);
  for i:=0 to Count-1 do
  begin
    // falls es ein Ascii Protokoll ist:
    s := s+char(buffer[i])
  end;
  VerarbeiteString(s);
  // oder kopiere den Inhalt des Buffers in einen temp Buffer und rufe eine Funktion auf um diesen zu verarbeiten.
end;
So verarbeiten wir die gesamte RS232 Kommunikation Ereignis gesteuert und hatten damit noch nie Probleme.
Allerdings glaube ich mich zu erinnern dass Du USB-RS232 wandelst oder sogar simulierst.
Kann sein dass die anfallenden Daten dann von der Kompenente gar nicht verabeitet werden können?
Keine Ahnung. Bis zur "normalen" Höchstrate von 115'200 Baud funktioniert das einwandfrei.

arnold mueller 29. Mai 2009 20:30

Re: ApdCOMPort: Daten gehen bei großen Datenmengen verloren
 
Ich hatte vor einiger Zeit das gleiche Problem. Laut Sysinternals Portmon kamen die Daten korrekt am PC an, der Buffer in der APDComPort Komponente enthielt aber doppelte Zeichen. Sporadisch versteht sich ... Ich konnte die ganze Sache soweit eingrenzen, dass es nur auf Maschinen mit Hyperthreading oder DualCore Prozessor auftrat.

Für mich war der Weg mit Apro damit zuende. Ich habe mir eine eigene ComPort Klasse geschrieben, die nun auch tadellos ihren Dienst tut.

-
arno


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