Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Tcommportdriver - die ersten Bytes fehlen


Rupert - So 14.11.10 20:52
Titel: Tcommportdriver - die ersten Bytes fehlen
Hi Miteinander!

Nachdem ich mich nun den ganzen Sonntag ohne Erfolgserlebnis gequält habe und sogar den F1-Grand Prix ausgelassen habe, poste ich hier mein Problem.

Hardwaretest:
Die Datenverbindung zwischen Sender unf Empfänger habe ich mittels Hyperterminal getestet. Hier werden alle Datenbytes übertragen.
Die Einstellungen sind 19200,N,8,1 RTS/CTS.

Methode:
Über das Ereignis Onreceivedata wird die Routine CommPortDriver1ReceiveData abgespult. Zuvor wird über einen Startbutton das Programm auf die Daten vorbereitet. (Schritt 1)
Sobald das sendende Gerät Daten schickt wird Onreceivedata ausgelöst (Schritt 2)und die empfangenen Bytes im Memo-Feld aufgelistet.

Symthom:
Ich verliere die ersten 64 Bytes, als kämen Sie nicht an. Dabei ist es egal, ob ich zuerst Die Daten Sende und meine Software wartet, oder ich die Software warten lasse und dann zu senden beginne. Sende ich z.B. nur 15 Zeichen, dann kommt in der SW gar nichts an.
Es sieht so aus, als würden diese Daten "verschluckt"

Diese Daten versende ich
Zitat:
no services pad
service timestamps debug uptime
service timestamps log uptime
no service password-encryption
!
hostname

und diese kommen an
Zitat:
s debug uptime
service timestamps log uptime
no service password-encryption
!
hostname


Vielleicht hat jemand eine Ahnung, oder sieht den Fehler weshalb die Daten verloren gehen ....

lg
Rupert


Schritt 1:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
    CommPortDriver1.CheckLineStatus:=true;
    CommPortDriver1.PacketMode:=pmDiscard; // default
    CommPortDriver1.InBufSize:=2048;
    CommPortDriver1.OutBufSize:=2048;
    CommPortDriver1.connect;
    CommPortDriver1.FlushBuffers( true,true);  // Beide SS-Speicher leeren
    if CommPortDriver1.connected then begin


Schritt 2:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
procedure TFormMain.CommPortDriver1ReceiveData(Sender: TObject; DataPtr: Pointer; DataSize: Cardinal);
var
i,check : integer;
Afilename:String;
nToRead  : UINT;


begin
  Afilename:=FileListBox1.Directory+'\'+Dateiname1.Text;
  AssignFile(f,Afilename);

    Rewrite(f,1);  // create new file
    while DataSize > 0 do begin
      Bytemenge_txt.caption:='   '+inttostr(datasize);
      Bytemenge_txt.refresh;
      sleep(20);
      CommPortDriver1.PausePolling; // Abfrage Stopp

      nToRead :=CommPortDriver1.CountRX;//Anzahl der zu empfangenen Bytes
      Setlength(msg,nToRead);//msg an die Bytelänge anpassen
      bytes_gelesen := CommPortDriver1.ReadData(pchar(msg),nToRead);//Daten nach msg kopieren

      CommPortDriver1.FlushBuffers( true,false);//Empfangsspeicher leeren
      CommPortDriver1.ContinuePolling;//Abfrage start

      For i := 1 to bytes_gelesen do
        BlockWrite(f,msg[i],1);
      Memo1.Lines.Add(msg);
      if bytes_gelesen=0 then Datasize:=0;
      DataSize:=DataSize-bytes_gelesen;
    end;

    CloseFile(f);  // close file

end;


glotzer - So 14.11.10 20:55

idee zur unschönen lösung:
64 byts müll senden, dann mit daten anfangen


Rupert - So 14.11.10 20:57

Wenns so einfach wär...
Die Daten , die (wenns funktioniert) zu empfangen sind, sind CNC-Programme.

Wenn ich übrigens gleich nochmals sende, fehlen "nur" 22!


jaenicke - So 14.11.10 21:12

Also wenn ich so den Quelltext von TCommPortDriver anschaue... Naja...

Nimm einfach einmal diese Komponente:
http://sourceforge.net/projects/comport/

Im Gegensatz zu der, die du benutzt, pollt die nicht nur (via Timer in diesem Fall), sondern benutzt die Warte-Routinen von Windows. Ich selbst benutze zum Zugriff auf den COM-Port auch WaitForMultipleObjects. Damit kannst du einmal auf ein COM-Event und andererseits auf einen Abbruch (beim Beenden des Programms bzw. des Lauschens) warten.

Ich habe jetzt nicht so viel Lust mir genauer anzuschauen was da passiert. Aber ich vermute das Problem innerhalb der Komponente, so dass es mit der neuen ohnehin erledigt sein dürfte.


Rupert - Mo 15.11.10 21:01

Wenn man auf das Ereignis OnReceiveData reagiert, dann fehlen tatsächlich immer einige Bytes.

Nachdem ich das Empfangen per Mausclick auslösen kann habe ich das Problem lösen können, indem ich auf das Ereignis verzichte.

Die Lösung ist eigentlcih ganz einfach...


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
{ ***********************************************************
                   Lies File - der Filename wird übergeben
  ***********************************************************}


procedure TFormMain.Readfile(AFileName: string);
var
  i    :integer;
  f    :file;
  pBuf :pointer;
  Buf  :array [0..65565of PAnsiChar;
  bytes_gelesen,zulesen       :UINT;

begin
  CommPortDriver1.CheckLineStatus:=true;
  if not CommPortDriver1.Connected then begin
    messagebeep(MB_ICONEXCLAMATION);
    MessageDlg(CommPortDriver1.PortName+' ist offline',mtConfirmation,[mbOK],0)
  end;
  begin
    pBuf:=@Buf;
    begin;
      AssignFile(f,Afilename);
      Rewrite(f,1);  // create the file
      repeat
        sleep(64);   // warten bis sich der Buffer "erhohlt"
        CommPortDriver1.PausePolling;
        zulesen :=CommPortDriver1.CountRX;//Anzahl der zu empfangenen Bytes
        bytes_gelesen := CommPortDriver1.ReadData(pbuf,zulesen);//Daten nach msg kopieren

        BlockWrite(f,Buf,bytes_gelesen);  // write data
        memo1.SetSelTextBuf(pbuf);        // im Memo-Block anzeigen

        CommPortDriver1.FlushBuffers( true,false);//Empfangsspeicher leeren
        CommPortDriver1.ContinuePolling;//Wieder auf Empfang gehen
      until bytes_gelesen <= 0;
      CloseFile(f);  // close file
    end;
  end;
end;


...und damit der Thread komplett ist und andere auch was davon haben, hier auch das Senden eines Files


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
{ ***********************************************************
                        Sende File
  ***********************************************************}


procedure TFormMain.SendFile(AFileName: string);
var
var
  i    :integer;
  f    :file;
  pBuf :pointer;
  Buf  :array [0..65565of PAnsiChar;
  zusenden  :UINT;
  BytesSend :Integer;
begin
  CommPortDriver1.CheckLineStatus:=true;
  if not CommPortDriver1.Connected then begin
    messagebeep(MB_ICONEXCLAMATION);
    MessageDlg(CommPortDriver1.PortName+' ist offline',mtConfirmation,[mbOK],0)
  end;
  pBuf:=@Buf;
  AssignFile(f,AFileName);
  Reset(f,1);
  BytesSend := 2048// standardmenge

  while (not EOF(f)) do begin
    BlockRead(f,Buf,BytesSend,zusenden);  // zusenden ist die tats. Bytemenge
    CommPortDriver1. SendData (pBuf,zusenden); // zusenden, weil der letzte Block sicher nicht voll ist
    CommPortDriver1.FlushBuffers( false,true);
    memo1.SetSelTextBuf(pbuf);
    memo1.Refresh;
  end;
  CloseFile(f);
end;


@jaenicke
Ich habe mir zwar den Cport Driver installiert, als ich aber sah, dass ich wieder alles umbauen muss (setup Dialog etc.) habe ich mich mit dieser Variante noch einmal auseinandergesetzt und das Problem lösen können - trotzdem vielen Dank...