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