![]() |
Datenverlust bei ReadFile auf virtuellen COM-Port
Folgende Konfiguration:
Ich habe ein Gerät, das über USB an den PC angebunden wird. Das Gerät arbeitet als CDC-Device und die Einbindung erfolgt als virtueller serieller Port. Die Codeschnipsel verwende ich schon seit Jahren mit "richtigen" COM-Ports, ohne bisherige Probleme. Hier der Code:
Delphi-Quellcode:
Ich sende eine definierte Befehlssequenz zum Gerät, welches mir in einem binären Protokoll eine Antwort zurückliefert. Deswegen arbeite ich auch syncron, da ich genau weiß, wie viele Byte zurückkommen. Sind es weniger, dann liegt ein Fehler vor und dieser wird ausgewertet, wenn die Function ReadFile über einen Timeout beendet wird.
// initialisiert die serielle Schnittstelle COM[PCCOMM]
// Rückgabe = 0, wenn OK sonst <0 function TAPMLU.PortInit:Integer; var cid : THandle; m2 : THandle; port : PChar; merker1 : longbool; comst : tdcb; CommTimeouts: TCommTimeouts; begin cid:=Comm; {letzte genutzte Schnittstelle} if PC_Comm < 10 then begin port:=pChar('com'+IntToStr(PC_COMM)); end else begin port:=pChar('\\.\com'+IntToStr(PC_COMM)); end; if cid<>0 then closeHandle(cid); // letzte genutzte Schnittstelle schließen, falls geöffnet comst.flags:=0; comst.xonlim:=0; comst.xofflim:=0; comst.Baudrate:=CBR_256000; comst.parity:=NoPARITY; comst.Bytesize:=8; comst.stopbits:=1; comst.DCBlength:=SizeOf(comst); m2:=CreateFile(port ,GENERIC_READ or GENERIC_WRITE , 0, nil, OPEN_EXISTING, 0, 0); if (m2>0)and(SetupComm(m2,200,200)) then begin comm:=m2; CommTimeouts.ReadIntervalTimeout:=0; CommTimeouts.ReadTotalTimeoutMultiplier:=0; CommTimeouts.ReadTotalTimeoutConstant:=50; CommTimeouts.WriteTotalTimeoutMultiplier:=0; CommTimeouts.WriteTotalTimeoutconstant:=50; SetCommTimeouts(comm,CommTimeouts); merker1:=setcommstate(comm,comst); result:=0; ReadFail:=0; WriteFail:=0; end else begin result:=-1; Comm:=0; end; end; // Daten senden // SDaten enthalten Befehlsstring procedure TAPMLU.sendData(SDaten: array of Ansichar; Anzahl: SmallInt); var x: SmallInt; bcc : byte; test: longbool; len: DWord; s: String; begin SDaten[0]:=AnsiChar(Anzahl); SDaten[Anzahl]:=#0; bcc:=ord(SDaten[0]); for x:=1 to (anzahl-1) do bcc:=bcc xor ord(SDaten[x]); SDaten[anzahl]:=AnsiChar(bcc); for x:=0 to anzahl+1 do buff[x]:=SDaten[x]; Sended:=IntToStr(anzahl+1)+' Byte: '; for x:=0 to anzahl do Sended:=Sended+DecHex(ord(buff[x]))+' '; test:=WriteFile(Comm,buff,Anzahl+1,len,nil); if len<>(Anzahl+1) then begin inc(WriteFail); s:='W '+IntToStr(WriteFail)+': '+Sended; Writeln(DebugFile,s); end; end; function TAPMLU.GetData(Anzahl:SmallInt; Time :longint; var Daten: array of AnsiChar):integer; var x: longint; y: SmallInt; anz: DWord; Timeout: longint; bcc: byte; s: String; begin Daten[0]:=#0; x:=0; anz:=0; ReadFile(Comm,buff,Anzahl,anz,nil); buff[anz]:=#0; if anz>0 then for y:=1 to anz do daten[x+y-1]:=buff[y-1]; x:=x+anz; result:=0; bcc:=0; Recived:=IntToStr(x)+' Byte: '; for y:=0 to x-1 do Recived:=Recived+DecHex(ord(daten[y]))+' '; if Anzahl<>Anz then begin inc(ReadFail); s:='W '+IntToStr(ReadFail)+' send: '+Sended+' recived: '+Recived; Writeln(DebugFile,s); end; for y:=0 to x-2 do bcc:=bcc xor ord(daten[y]); result:=ord(Daten[1]); if x=0 then result:=-10; if (bcc<>ord(daten[x-1]))and(x>0)then result:=-30; end; Funktioniert auf meinem Notebook mit Windows 7 (64-Bit) ausgezeichnet. Unter Windows 8 (kann evtl. auch an der Rechnergeschwindigkeit liegen) gibt es Probleme. Es kommt des öfteren nicht die erwartete Anzahl an Datenbytes an. Ganz konkret erwarte ich 35 Byte. Mal kommen nur 34, mal nur 33 und auch mal weniger an. Es fehlen meist die letzten Bytes, manchmal aber auch das Erste. Sieht ganz so aus, als würden die noch irgendwo im Cache rumliegen.? Habe ich vielleicht irgendwo einen Denkfehler in meinem Programm? Irgend etwas falsch initialisiert? Am Readtimeout (50ms) liegt es nicht. Auch bei 1000 ist das Problem das Gleiche. Hatte vielleicht schon mal jemand ähnliche Probleme? Gruß BlackGuest |
AW: Datenverlust bei ReadFile auf virtuellen COM-Port
Du hast einen Mischmasch im Code!
Schreibe konsequent im Code, was Du willst: AnsiString und PAnsiChar, wo das erwartet wird! Wie sehen die Bytes am Schluss aus? Kommt da IMMER das gleiche Byte, dann kann man das als Ende der Übertragung auswerten. Nimm eine Komponente, wo die function GetTriggersOnRxChar: Boolean; oder etwas Ähnliches vorhanden ist. |
AW: Datenverlust bei ReadFile auf virtuellen COM-Port
Ok, der Mischmasch kommt daher, dass das Ganze nur schnell aus einer älteren Version übernommen wurde.
Hat aber nichts mit dem Problem zu tun. Nein, das letzte Byte ist nicht gleich aber die Anzahl der Datenbytes. Es geht darum, das Daten "verloren" gehen. Gruß BlackGuest |
AW: Datenverlust bei ReadFile auf virtuellen COM-Port
Schlechte Kabelverbindung ausgeschlossen?
Zu lang, zu alt, "wackelig"... CBR_256000 ist sehr hoch - geht es auch langsamer? Ein Computer macht eigentlich nichts zufällig, ausser mit "Random"... Ist das Device auch als HID vorhanden? |
AW: Datenverlust bei ReadFile auf virtuellen COM-Port
Ist auch klar, denn du liest nur das aus, was "aktuell" im Puffer ist, das können mehr oder wender sein, als das, was du jetzt auslesen willst.
Bei weniger mußt du entweder auf die fehlenden Daten warten oder die Daten sammeln und zusammensetzen, bis die Anzahl ausreicht. Ich würde dir aber eh empfehlen, eine Comport-Komponente zu benutzen. Ist bei sendData Length(SDaten) größer als Anzahl? -> Buffer-overrun? Zitat:
|
AW: Datenverlust bei ReadFile auf virtuellen COM-Port
Zitat:
PS: Daten am Port werden nicht gecachet, solange der Port nicht offen ist, also wenn Daten ankommen, bevor du den Port aufmachst, dann sind die weg. Das war übrigens auch einer der Gründe, warum ich meinte der Port solle besser offen bleiben. Wenn man den Port aufmacht, Daten anfragt und dann die Daten ausliest, dann OK, aber du willst etwas auslesen das "irgendwann" gesendet wird. |
AW: Datenverlust bei ReadFile auf virtuellen COM-Port
Zitat:
Zitat:
Evtl. könnte der Wert intern noch für irgendwelche Timings verwendet werde. Mit 9600 ist das Ergebnis aber das Gleiche. Zitat:
Zitat:
Ein Timeout tritt noch obigem Code nach 50ms ein. Selbst mit 1000ms habe ich das gleiche Problem. Beim Senden treten keine Fehler auf. Wenn, dann würde mein Device auch nicht antworten bzw. mit einer Fehlermeldung. Der Port wird beim Programmstart geöffnet und beim Beenden geschlossen. Ist also die ganze Zeit offen. Mein Device sendet nur Daten, wenn es vorher eine gültige Befehlssequenz empfangen hat. Ich hoffe ich konnte einige Unklarheiten ausräumen. Mein Programm läuft auf einigen Windows 7 PCs problemlos, unter Windows 8 kommt es zu dem Datenverlust, wobei ich da zu wenig Hardware hier habe um 100%-ig sagen zu können, dass es am Windows 8 liegt. Kann auch an der "PC"-Geschwindigkeit liegen. Mein Windows 8 Rechner ist ein Tablet. Gruß und danke für die bisherigen Hinweise. BlackGuest |
AW: Datenverlust bei ReadFile auf virtuellen COM-Port
Zitat:
Was empfiehlt der Hersteller des Gerätes oder des USB-COM-Wandlers? Da Deine "Selbstbau"-Software NICHT Event-gesteuert ist, hängt es vom Zufall ab, wann WINDOWS die Daten aus dem Buffer holt. Ich habe hier die Beschreibung eines CDC-Chips: 256 kommt da NICHT vor: The following baud rates are supported: 1200, 2400,4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, and 921600 bps. |
AW: Datenverlust bei ReadFile auf virtuellen COM-Port
Zitat:
Zitat:
Sollte, schon möglich das da das Problem liegt. Nur warum sollte ich auf jedes einzelnen Zeichen reagieren, wenn mich nur die Komplette Antwortsequenz interessiert, die nun mal x-Datenbyte lang ist? Wieso funktioniert das Ganze unter Windows 7 anscheinend völlig ohne Probleme? Gruß BlackGuest |
AW: Datenverlust bei ReadFile auf virtuellen COM-Port
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:20 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz