2010-03-22 6 views
5

Ich habe zwei Geräte, die ich über eine serielle Schnittstelle verbinden möchte, aber sie haben inkompatible Verbindungen. Um dieses Problem zu umgehen, habe ich beide mit meinem PC verbunden und arbeite an einem C# -Programm, das den Verkehr von COM-Port X zu COM-Port Y und umgekehrt leitet.C# SerialPort - Probleme beim Mischen von Ports mit unterschiedlichen Baudraten

Das Programm verbindet sich mit zwei COM-Ports. Im Datenempfangs-Handler lese ich eingehende Daten ein und schreibe sie an den anderen COM-Port. Um dies zu tun, ich habe den folgenden Code:

private void HandleDataReceived(SerialPort inPort, SerialPort outPort) 
    { 
     byte[] data = new byte[1]; 

     while (inPort.BytesToRead > 0) 
     { 
      // Read the data 
      data[0] = (byte)inPort.ReadByte(); 

      // Write the data 
      if (outPort.IsOpen) 
      { 
       outPort.Write(data, 0, 1); 
      } 
     } 
    } 

Dieser Code funktioniert gut, solange der scheidende COM-Port mit einer höheren Baudrate als die eingehenden COM-Port betrieben. Wenn der eingehende COM-Port schneller als der ausgehende COM-Port war, begann ich Daten zu verpassen. Ich musste den Code wie folgt korrigieren:

private void HandleDataReceived(SerialPort inPort, SerialPort outPort) 
    { 
     byte[] data = new byte[1]; 

     while (inPort.BytesToRead > 0) 
     { 
      // Read the data 
      data[0] = (byte)inPort.ReadByte(); 

      // Write the data 
      if (outPort.IsOpen) 
      { 
       outPort.Write(data, 0, 1); 
       while (outPort.BytesToWrite > 0); //<-- Change to fix problem 
      } 
     } 
    } 

Ich verstehe nicht, warum ich diesen Fix brauche. Ich bin neu in C# (das ist mein erstes Programm), also frage ich mich, ob ich etwas vermisse. Der SerialPort verwendet standardmäßig einen Schreibpuffer von 2048 Byte, und meine Befehle sind kleiner als zehn Byte. Der Schreibpuffer sollte die Möglichkeit haben, die Daten zu puffern, bis sie in einen langsameren COM-Port geschrieben werden können.

Zusammenfassend erhalte ich Daten über COM X und schreibe die Daten an COM Y. COM X ist mit einer höheren Baudrate als COM Y verbunden. Warum behandelt die Pufferung im Schreibpuffer diesen Unterschied nicht? Warum scheint es, dass ich auf den Schreibpuffer warten muss, um Datenverlust zu vermeiden?

Danke!

* Update *

Wie bereits erwähnt, kann dieser Code sehr leicht in einen Überlaufzustand läuft mit großen und/oder schnell eingehenden Datenübertragungen. Ich hätte mehr über meinen Datenstrom schreiben sollen. Ich erwarte < 10-Byte-Befehle (mit < 10-Byte-Antworten) bei 10 Hz. Außerdem sehe ich Fehler beim ersten Befehl.

Also während ich weiß, dass dieser Code nicht skaliert und weniger als optimal ist, frage ich mich, warum die 2-4K Lese-/Schreibpuffer nicht einmal den ersten Befehl verarbeiten konnten. Ich frage mich, ob es einen Fehler beim Schreiben eines einzelnen Bytes von Daten oder etwas mit dem Ereignishandler gibt, die ich nicht verstehe. Vielen Dank.

* Update *

Hier ist ein Beispiel für das Scheitern:

Sagen wir, mein Befehl vier Bytes ist: 0x01 0x02 0x3 0x4. Das Gerät auf COM X sendet den Befehl. Ich kann sehen, dass das C# -Programm vier Bytes empfängt und sie an das Gerät an COM Y sendet. Das Gerät an COM Y empfängt zwei Bytes: 0x01 0x03. Ich weiß, dass das Gerät auf COM Y zuverlässig ist, also frage ich mich, wie die zwei Bytes fallen gelassen wurden.

Übrigens, kann mich jemand wissen lassen, ob es besser ist, Antworten mit Kommentaren zu beantworten oder ob ich die ursprüngliche Frage weiter bearbeiten soll? Was ist hilfreicher?

Antwort

0

Sie sollten sicherstellen, dass outPort.WriteBufferSize größer als der größte Puffer ist, den Sie voraussichtlich senden. Außerdem wird das Aufrufen von ReadByte und WriteByte in einer Schleife im Allgemeinen langsam sein.Wenn Sie Ihre Handler in etwas wie ändern:

int NumBytes = 20; //or whatever makes sense 
byte[] data = new byte[NumBytes]; 

while (inPort.BytesToRead > 0) 
{ 
    // Read as much data as possible at once 
    count = inPort.Read(data, 0, min(NumBytes, inPort.BytesToRead)); 

    // Write the data 
    if (outPort.IsOpen) 
    { 
     outPort.Write(data, 0, count); 
    } 
} 

wird dies den Aufwand reduzieren, der helfen sollte. Der Schreibpuffer wird dann (hoffentlich) das Timing wie erwartet handhaben.

2

Was Sie versuchen zu tun, entspricht dem Trinken aus einem Feuerwehrschlauch. Sie sind auf den Empfangspuffer angewiesen, um das Wasser zu speichern, es wird nicht lange dauern, wenn jemand den Wasserhahn nicht ausdreht. Mit Ihrer Problemumgehung stellen Sie sicher, dass der Empfangspuffer automatisch überläuft, Sie haben wahrscheinlich das ErrorReceived-Ereignis nicht implementiert.

Damit dies funktioniert, müssen Sie dem Eingabegerät mitteilen, dass es nicht mehr senden soll, wenn der Puffer voll ist. Tun Sie das, indem Sie die Handshake-Eigenschaft festlegen. Legen Sie zuerst Handshake.RequestToSend fest. Verwenden Sie XOnXOff als nächstes. Es hängt vom Gerät ab, ob es die Handshake-Signale richtig verwendet.

Verwenden Sie die Read() - Methode, um dies ein wenig effizienter zu machen.


Okay, nicht Feuerwehrschlauch. Ich kann mir nur eine andere Möglichkeit vorstellen. Ein häufiges Problem bei frühen UART-Chip-Designs war, dass sie einen On-Chip-Empfangspuffer hatten, der nur ein Byte speichern konnte. Was bedeutete, dass die Interrupt-Service-Routine dieses Byte lesen musste, bevor das nächste kam. Wenn der ISR nicht schnell genug ist, schaltet der Chip den SerialError.Overrun-Status ein und das Byte ist unwiederbringlich verloren.

Eine Umgehung für dieses Problem bestand darin, künstlich eine Verzögerung zwischen jedem übertragenen Byte zu setzen, was dem ISR im Gerät mehr Zeit gibt, das Byte zu lesen. Was ist Ihr Workaround-Code als Nebeneffekt?

Es ist keine großartige Erklärung, moderne Chip-Designs haben einen FIFO-Puffer, der mindestens 8 Bytes tief ist. Wenn überhaupt etwas wahr ist, sollte das Problem verschwinden, wenn Sie die Baudrate verringern. Außerdem sollte die Verwendung von Read() anstelle von ReadByte() das Problem verschlimmern, da Ihr Write() - Aufruf jetzt mehr als ein Byte gleichzeitig übertragen kann, wodurch die Verzögerung zwischen Zeichen vermieden wird. Um es klar zu sagen, ich spreche über das Ausgabegerät.

+0

Ja, Sie haben Recht, dass dieser Code ist wie aus einem Feuerwehrschlauch trinken. Leider hätte ich mehr über den mit diesem Code verbundenen Schlauch schreiben sollen. Ich sende <10 Byte Befehle (mit <10 Byte Antworten) bei 10 Hz. Ich würde 2-4K lesen/schreiben Puffer für mich mehr als ausreichend erwarten. Außerdem sehe ich Fehler beim ersten Befehl. Obwohl ich weiß, dass dieser Code nicht auf größere/schnellere Datenübertragungen skaliert, bin ich neugierig, warum es nicht mit kleinen/langsamen Übertragungen funktioniert hat. Tut mir leid, dass ich nicht klarer bin. – GrandAdmiral

+0

Okay, sollte funktionieren. Bitte sei explizit "Ich sehe Fehler". –

+0

Sicher. Nehmen wir an, mein Befehl besteht aus vier Bytes: 0x01 0x02 0x3 0x4. Das Gerät auf COM X sendet den Befehl. Ich kann sehen, dass das C# -Programm vier Bytes empfängt und sie an das Gerät an COM Y sendet. Das Gerät an COM Y empfängt zwei Bytes: 0x01 0x03. Ich weiß, dass das Gerät auf COM Y zuverlässig ist, also frage ich mich, wie die zwei Bytes fallen gelassen wurden. – GrandAdmiral