2014-01-15 12 views
7

Ich habe eine Menge Probleme beim Versuch, einen seriellen Port zum Empfang der korrekten Nachricht zu bekommen. Es schneidet die Nachrichten weiterhin ab. Hier ist mein Code und ich werde versuchen, nach dem Code zu arbeiten.Probleme mit der SerialPort-Klasse

public SerialComms(SerialPort sp) 
{ 
    this.sp = sp; 
    this.sp.Open(); 
    this.sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived); 

    do 
    { 
     Console.WriteLine("port open waiting message"); 
     Console.ReadKey(); 
    } while(!_terminate); 

    this.sp.Close(); 
} 

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    string dataReceived; 
    StringComparer strComp = StringComparer.OrdinalIgnoreCase; 
    SerialPort sp = (SerialPort)sender; 
    int i = sp.BytesToRead; 
    byte[] _byte = new byte[i]; 
    char[] _char = new char[i]; 
    sp.read(_byte, 0, i); 
    dataReceived = Encoding.UTF8.GetString(_byte); 
    //dataReceived = new string(_char); 
    //dataReceived = sp.ReadExisting(); 

    if (strComp.Equals("00000000000000"), dataReceived)) 
     _terminate = true; 

    Console.WriteLine(dataReceived); 
} 

Jetzt habe ich ein Testprojekt, das wir zum Testen unserer seriellen Coms in der Produktion mit Legacy-Software verwenden - ich weiß, das läuft gut. Ich habe einen seriellen Monitor an den Port angeschlossen und die übermittelte Nachricht wird ohne Probleme übertragen. Wenn ich eine Nachricht wiedas erste Mal durch es schicke geht normalerweise gut durch, und auf der Empfängerseite, zeigt der Monitor es durch; Wenn es jedoch auf der Konsole gedruckt wird, wird es nach der ersten Nachricht abgeschnitten. Ich füge Screenshots der Nachricht auf dem Port-Monitor und die Konsole Ausgang (die Smiley und Herz, das der Präfix-Bytes sein converted- ist zeigen, warum es ein Herz und ein Smiley-Gesicht ist habe ich keine Ahnung) geht durch

Ok, ich kann das Bild nicht posten, weil ich nicht genug Reputation dafür habe. Ich werde schreiben, wie die Ausgabe auf der Konsole unten aussieht (in diesem Fall hat es auch die erste Nachricht gekürzt :()

Auf dem Monitor des seriellen Anschlusses wird die Nachricht wie folgt übertragen (ich schickte es drei Zeiten mit ein paar Sekunden 'Verzögerungszeit' zwischen jeder Nachricht senden:
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 .123456789.
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 0,123456789.
02 31 32 33 34 35 36 37 38 39 30 31 32 33 34 03 .123456789.

Auf der Konsole erhielt ich folgende (die ☺ ♥ und Zeichen sind 02 und 03 , sie sind ein STX und ETX-Nachricht, die für unsere Getriebe) Standard ist:
☺123456
78.901.234 ♥

4 ♥

4 ♥

Dieses Problem mich verrückt fährt !!! Bitte helfen Sie! Das Erbe wird mit dem veralteten MSCommLib und wir bewegen sich eine mögliche Kombination von zwei Fragen auf .NET 4

+0

Ich ersetzte Ihre Platzhalter durch die echten Symbole, wenn ich sie umgekehrt habe, bitte korrigieren. Für die Screenshots können Links zu einer Website wie http://imgur.com/ und einem Benutzer mit höherem Wiederholungsstatus Links zu Bildern anzeigen. –

Antwort

5

Dies ist völlig normal und in jedem Kommunikationsprotokoll üblich. TCP über ein Netzwerk verfügt ebenfalls über diese Eigenschaft. Bytes werden als Stream, kein Paket von Daten übertragen. Wenn Ihr DataReceived-Ereignishandler ausgelöst wird, wissen Sie nur, dass Sie einige Bytes verfügbar haben. Es liegt an Ihnen, die empfangenen Bytes zu einer vollständigen Antwort zusammenzufassen, bevor Sie sie verarbeiten.

Dies erfordert ein Protokoll, eine Möglichkeit zu erkennen, dass Sie eine vollständige Antwort erhalten haben. Sie haben einen, diese STX- und ETX-Bytes sagen Ihnen. Insbesondere bei ETX ist der STX eine Möglichkeit, Rauschbytes herauszufiltern, die Sie beim Anschließen des Geräts erhalten könnten.

Ein sehr einfacher Weg, um es in Gang zu bringen, ist die NewLine-Eigenschaft auf (char)3 setzen und rufen Sie einfach ReadLine().

Ein besserer Weg, dies zu tun ist, um auch den Lärm zu filtern, dass STX Sie vermeidet ein Deadlock-Szenario auch hilft bei der Beseitigung:

private const int MaxResponse = 42; 
private const int STX = 2; 
private const int ETX = 3; 
private byte[MaxResponse] response; 
private int responseLength; 

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    var sp = (SerialPort)sender; 
    int cnt = sp.BytesToReceive; 
    for (int ix = 0; ix < cnt; ++ix) { 
     byte b = (byte)sp.ReadByte(); 
     if (responseLength == 0 && b != STX) continue; 
     if (b != ETX) response[responseLength++] = b; 
     else { 
      var str = Encoding.ASCII.GetString(response, 0, responseLength); 
      HandleResponse(str); 
      responseLength = 0; 
     } 
    } 
} 

Und schreiben die handle() Methode, um die Daten, die Sie empfangen zu verarbeiten.

+0

Danke, das gibt mir so viel zu arbeiten! Frage? Warum hast du ++ die Antwortlänge und versetze den Index der Antwort [] um 1? Um zu vermeiden, dass die Antwort [] versehentlich gelöscht wird (in dem Fall, dass sie nur den ersten Teil der Übertragung empfängt und dann wieder mit einem anderen dataReceived-Aufruf durchkommt) sollte das else nicht ein if (b == ETX) und dann der sein sonst sei sonst weiter; ? Danke nochmal, das war ein großer Einblick! – alykins

+0

Auch ich weiß, dass unsere Nachrichten von den PLCs immer 16 Bytes sein werden (2 Bytes für stx/etx und dann 14 Byte Nachricht) ... Wird das Problem verursachen, die MaxREsponse Int zu ändern, um 16 statt 42 zu sein? – alykins

+0

Ich versetze nichts um 1, es wird * nachher * erhöht. Die Verwendung der Antwort [++ responseLength] wäre falsch. Nichts ist ausgelöscht, Antwort [] ist keine lokale Variable. Ich habe b! = ETX für die Lesbarkeit verwendet. Natürlich, benutze 16. 42 ist nur die Antwort auf das Leben, das Universum und alles. –

3

Es gibt.

Zuerst wird ein häufiger Fehler, wenn sie mit Strömen arbeiten, ist, dass, nur weil Sie i Bytes von Read verlangen, bedeutet nicht, dass Read tatsächlich, dass viele Bytes lesen, ist es nicht wahrscheinlich, dass Ihr Problem ist, aber Sie sollten sich dessen bewusst sein, see this question's answer for the proper pattern .

Zweite Ausgabe ist Ströme Ströme sind, keine Nachrichten. Er weiß nicht, dass Sie ☺123456789♥ geschickt, er weiß nur, dass es ☺123456 zwischen der letzten Zeit erhalten geprüft und jetzt, und es sollten diese Informationen an den Benutzer melden.

Sie müssen Ihren Lesecode ändern, um die Daten zwischenzuspeichern, bis sie die nächste empfangen, dann nehmen Sie das gesamte gepufferte Byte-Array und senden es an den Benutzer.Das ist der ganze Grund für die und entlang der Leitung gesendet wird, ermöglicht es dem Empfänger in der Lage zu erkennen, wenn es den Anfang oder das Ende einer Nachricht getroffen hat.

+0

+1 Genau das wollte ich vorschlagen. Aber warum poste es, wenn es jemand schon so eloquent ausgedrückt hat? :) – itsme86

+0

Vielen Dank für Ihr Feedback! Ich schließe mich dieser Theorie mit dem obigen Codebeispiel an - es macht jetzt viel mehr Sinn! Ich dachte über das Mittagessen nach, dass ich vielleicht nach dem Start/Stop-Byte suchen sollte, was ziemlich genau das ist, was du gesagt hast: P – alykins