Delphi-PRAXiS
Seite 1 von 3  1 23      

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


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:11 Uhr.
Seite 1 von 3  1 23      

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