Einzelnen Beitrag anzeigen

BlackGuest

Registriert seit: 30. Jan 2009
52 Beiträge
 
Delphi XE7 Professional
 
#1

Datenverlust bei ReadFile auf virtuellen COM-Port

  Alt 3. Nov 2014, 07:01
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:
// 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;
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.

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

Geändert von BlackGuest ( 3. Nov 2014 um 07:13 Uhr)
  Mit Zitat antworten Zitat