Laden...

Serial Port: Daten werden nicht mehr empfangen und Prog. hängt sich auf.

Erstellt von Cronnok vor 10 Jahren Letzter Beitrag vor 10 Jahren 2.974 Views
C
Cronnok Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren
Serial Port: Daten werden nicht mehr empfangen und Prog. hängt sich auf.

Hey ho Coder,
ich programmiere nun schon länger an einem Projekt bei dem nun ein Problem aufgetreten ist.
Mein Programm hängt sich nach kurzer Zeit schon auf, und zwar erstelle ich zu Anfang einen Serial Port also, soweit ich es verstanden hab sind die Ports in C# nur eine Art Schnittstelle die zur Kommunikation zwischen dem Prog und dem Treiber fungieren.
Diesem Port gebe ich auch ein DataReceive Event mit, damit dieser auf Daten vom Scanner(Personalausweis-Scanner) reagiert.
Der Port auf dem das ganzen dann laufen soll ist ein virtueller ComPort(COM6).
Nun habe ich nachdem ich gemerkt habe das die Daten nicht ankommen bzw. ausgegeben werden, einen Sniffer mitlaufen lassen (PortMon). Dieser lieferte die standartisierte Öffnung der Kommunikation zum Eingabegerät. ABER aus irgenteinem Grund kam dauerhaft die Meldung "IOCTL_SERIAL_WAIT_ON_MASK" und danach "IOCTL_SERIAL_GET_COMMSTATUS" manchmal letzteres öfter als das andere aber Das ist irrelevant denke ich.
Nun kam auch nach Durchführung des Scans nur das im Sniffer vor.
Daraufhin hab ich ein Thread.Sleep(300/400) eingebaut, was dann auch geholfen hat. Ich bekam Daten. 😄
Nun hat er aber immernoch diese beiden Meldungen ("IOCTL_SERIAL_WAIT_ON_MASK" und danach "IOCTL_SERIAL_GET_COMMSTATUS") ausgeben und die Daten die haben wollte waren iwo dazwischen aber sie waren immerhin zu sehen.
Dann jedoch hat sich nach dem Scan und einigen weiteren der aufgeführten Meldungen des Geräts bzw. des Treibers oder was auch immer geweigert weitere Scans anzunehmen.
Wieviele Scans innerhalb dieser Zeit, wo es funktioniert hat, ausgeführt werden scheint egal zu sein. Da auch mehrere, wenn ich es schnell gemacht hab, ohne Probleme möglich waren.
Im Sniffer stand dann hinter den letzten beiden Meldungen also der Wait on Mask und Commstatus kein tolles SUCCESS mehr sondern garnichts.
Daraufhin stürzte mein Programm schließen und neu debuggen wollte ab und erzeugte eine geniale Prozessleiche die einmal mich daran hinderte mein Programm neu zu debuggen und zusätzlich den virtuellen ComPort besetzten und somit unzugänglich macht für jedes andere Programm.
Dann habe ich mal geschaut was die Original-TestSoftware des Herstellers macht und was der Sniffer bei ihr anzeigt.

Da waren dann einige sehr große Unterschiede zu sehen.
Zum einen kamen keine dauerhaften Meldungen von CommStatus bzw Wait on Mask abfragen.
Stattdessen nur eine Wait on Mask und ein Read und keine CommStatus abfrage.
Beides hatte kein SUCCESS sondern schien darauf zu warten bis ein Scan durchgeführt wurde.
Außerdem waren einige Eigenschaften des ComPorts anders.
Und zwar:

  • Mask: ERR statt Mask: RXCHAR RXFLAG CTS DSR RLSD BRK ERR RING
  • Timeouts: RI: 10 RM: 0 RC: 0 WM: 0 WC: 0 statt RI: -1 RM: 0 RC: 0 WM: 0 WC: 0
  • XonLimit: 512 XoffLimit: 512 statt 4096 und 2048

Somit war nur ein Neustart des Rechners die temporäre Lösung um vernünftig weiterarbeiten und Coden zu können. Nun bin ich immer fleißig am suchen gewesen und habe pro Tag den Rechner ca. 100-Mal neustarten müssen da keine Lösung meinerseits half. 😦 😦
Nun da ich schon seit mind. 2 Wochen alles möglich suche/ausprobiere und abändere und keine Ahnung mehr habe woran es liegen könnte.. Bitte ich hier um hilfe.
Ich bedanke mich schonma im vorraus 😄 Danke.
Ich hänge mal schon Klassen als Datei an diesen Post an, vielleicht könnte ihr da mal reinschaun.

Wenn ihr mehr Code oder weitere Infos haben wollt kann ich das posten, ich schau nun täglich mehr als oft hier rein^^. 😃

Hinweis von herbivore vor 10 Jahren

Anhang entfernt, siehe [Hinweis] Wie poste ich richtig? Punkt 4.1.

185 Beiträge seit 2005
vor 10 Jahren

schau doch mal hier:

SerialPort Template

C
Cronnok Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren

Habe das Template getestet.. Es treten EXAKT dieselben Probleme/Unterschiede zur Original-Software auf. O.o
Wieder diese Meldungen.. wieder der Absturz nach kurzer Zeit bzw. der Absturz tritt sogar auf sobald ich versuche zu scannen.
Wieder die unterschiedlichen Eigenschaften.
Die genannten Resultate traten beim Test des Templates auf, bei meiner Software ist alles wie gehabt und funktioniert auch nicht.

Ich hab den Code teilweise, da ich einige Stellen interessant bzw. eleganter fand, übernommen.

EDIT:
Aber trotzdem danke für den Post. Das hatte ich bisher iwie übersehen. Sieht sehr gut aus vllt benutze ich es bei dem nächsten Projekt als Vorlage.

C
224 Beiträge seit 2009
vor 10 Jahren

Hast Du denn alle seriellen Parameter richtig eingestellt?

  • Baud
  • Parity
  • Handshake
  • Stopbits
    (...)usw.(...)
C
Cronnok Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren

Also. Ich habe nun nochmal alle Handshakes( da meine Vermutung war, das hier die fehlerhafte Einstellung/Eigenschaft lag) durchprobiert.
Nun funktioniert, das Template sowie auch mein Programm.
Zumindest bist zum 4 oder 5ten Scan.
Den Fehler habe ich schon gefunden und zwar handelt es sich hier um den Buffer der vollgestopft wird mit den Scans bis nix mehr geht.
Genauer gesagt die Eigenschaft SerialPort.BytesToRead wird immer größer und die Anzahl der hinzukommenden Bytes stimmt mit den Eingelesenen überein und dadurch wird die Überprüfung (If(sp. BytesToRead == 82 || sp.BytesToRead == 102)) niemals wahr und es können keine Daten reinkommen. Bis dann iwann die Abfragen gestoppt werden und die Kommunikation zwischen Scanner-Treiber-Prog komplett eingestellt wird.
Nun weiß ich jedoch nicht wie ich den leere ( DiscardIn/OutBuffer hat nichts gebracht ) und sonst weiß ich iwie nicht weiter.. also ich möchte nicht umbedingt nach jedem 4ten Scan den kompletten Port löschen.
Weiß jemand was ich da machen könnte bzw was in meinem Code fehlt?


private void DeskoDataReceivedHandler(
                        object DEsender,
                        SerialDataReceivedEventArgs e)
        {
            
            if (Desko_dataBuffer == null && !Desko_continue /*&& first != true*/)
            {
                Thread.Sleep(300);
                int byteCount = ((SerialPort)DEsender).BytesToRead;
                if (byteCount == 82 || byteCount == 102)
                {
                    Desko_dataBuffer = new byte[byteCount];
                    Thread.Sleep(300);
                    ((SerialPort)DEsender).Read(Desko_dataBuffer, 0, byteCount);
                    Desko_encode((object)Desko_dataBuffer);
                    Desko_continue = true;

                    Desko_dataBuffer = null; 
                }
                else
                {
                }
            }
            //else
            //    first = false;
        }

 private void Desko_encode(object data)
        {
            byte[] b = (byte[])data;
            try
            {
                Thread.Sleep(200);
                string basicStr = Encoding.ASCII.GetString(b);
                Desko_inhalt = ScanSplit(basicStr);
            }
            catch
            {

                Desko_inhalt = null;
            }
        }

 private object[] ScanSplit(string basicStr)
        {
            int intZaehler = 0;
            empfaenger e;
            Ausweise ausw;
            string[] SplittedStr = basicStr.Split(new Char[] { '<' });
            for (int i = 0; i <= SplittedStr.Length; i++)
            {
                if (SplittedStr[i] == "")
                {
                    
                }
                else
                {
                    if (Desko_dataBuffer.Length == 82)
                    {
                        string str = SplittedStr[i][1].ToString();
                        if (str == "\r")
                        {
                            Zwischenablage = SplittedStr[i];
                            int gebID = i + 2;
                            GebDate = SplittedStr[gebID].Substring(0, 6);
                            int gueltID = gebID + 1;
                            GueltDate = SplittedStr[gueltID].Substring(0, 6);
                            break;
                        }
                    }
                    else if (Desko_dataBuffer.Length == 102)
                    {
                        string str = SplittedStr[i][z].ToString();
                        if (str == "\r" && intZaehler == 0)
                        {
                            GebDate = SplittedStr[i].Substring(2, 6);
                            int gueltID = i + 1;
                            GueltDate = SplittedStr[gueltID].Substring(0, 6);
                            intZaehler++;
                            z++;
                        }
                        else if (str == "\r" && intZaehler == 1)
                        {
                            Name = SplittedStr[i].Split(new Char[] { '\r' })[1];
                            int vnameID = i + 2;
                            Vorname = SplittedStr[vnameID];
                            intZaehler++;
                            break;
                        }
                    }
                }
            }
            
            if (Desko_dataBuffer.Length == 82)
            {
                string ID = Zwischenablage.Substring(2, 9);
                string WohnortID = Zwischenablage.Substring(2, 4);

                ausw = new Ausweise(ID, GueltDate);
                e = new empfaenger(SplittedStr[2], SplittedStr[4], GebDate, WohnortID);
                objArray = new object[] { ausw, e };
            }
            else if (Desko_dataBuffer.Length == 102)
            {
                intZaehler = 0;
                z = 1;
                string ID = SplittedStr[2];

                ausw = new Ausweise(ID, GueltDate);
                e = new empfaenger(Name, Vorname, GebDate, "");
                objArray = new object[] { ausw, e };
            }
            return objArray;
        }

EDIT Info:
Achja was mich an dem Problem noch mehr verwirrt hat das nach abbruch des aktuellen Debug- vorganges, wo die Eigenschaft(BytesToRead) bereits zB. 204 groß war, sich dies nicht nach einem weiteren Debug-Vorganges geändert hat.
Außerdem wurde auch das DataReceive-Event direkt nach dem zweite Start, mit genau demselben Wert(204), ausgeführt.

Daraus folgt meine Schlussfolgerung das der Buffer nicht richtig gecleared wird.

185 Beiträge seit 2005
vor 10 Jahren

es ist nie sichergestellt, das du genau die Anzahl Bytes in BytesToRead bekommst, die du erwartest.
Gibt es in dem Protokoll kein Anfang und End-Zeichen, auf das du Triggern kannst?

C
Cronnok Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren

Ich habe nun den Fehler des vollen Buffers gelöst.
Nun wird nach jedem erfolgreichen Scan der Buffer wie folgt geleert:


                    ((SerialPort)DEsender).Read(Desko_dataBuffer, 0, byteCount); // *1
                    if (Encoding.ASCII.GetString(Desko_dataBuffer).Contains("0IDD")) // *2
                    {
                        Desko_encode((object)Desko_dataBuffer); // *3
                        ((SerialPort)DEsender).DiscardInBuffer();  // Hier wird der Buffer geleert.
                    }
                    else
                        ((SerialPort)DEsender).DiscardInBuffer(); //*4


zu 1: Hier findet der normale Read-Befehlssatz ausgeführt um den Buffer mit Daten zu füttern.

zu 2: Hier habe ich mir deinen Rat zunutze gemacht MartinH und versuche die nützlichen Daten anhand des Anfangszeichens zu erkennen und nicht an der Bytes im Buffer.

  • Dies funktioniert auch einwandfrei.

zu 3: Hier wird der String zugeschnitten und der Inhalt in einen Zustand gesplittet der letztendlich als Eigenschaften der Empfänger genutzt werden kann.

zu 4: Hier soll der Buffer geleert werden wenn keine nützlichen Daten im Buffer sind. Was heißt das der unten beschriebene Fehler nur dann auftritt wenn falsche Daten reinkommen.

Mit Letzterem entsteht wieder das Problem das die Kommunikation zwischen Gerät-Treiber-Prog komplett zusammenbricht und keine Daten mehr empfangen werden können und das Prog abstürzt sobald ich es beende.

185 Beiträge seit 2005
vor 10 Jahren

Es kann durchaus passieren, dass du einen Datensatz nicht vollständig auf einmal bekommst.
Der Event wird vorher gefeuert, deshalb auch dein Thread.Sleep(300)

Ich speichere mir die Empfangenen Bytes in einem Buffer, und prüfe den Buffer auf die Daten.
Du erstellst immer einen neuen Buffer für die Empfangenen Daten, deshalb hast du nur einen Teil der Daten im Buffer.
Auserdem kann es die passieren, dass der nächste Event gefeuert wird, du aber noch die empfangenen Daten verarbeitest.

Mit den Start- und Endzeichen meinte ich eigendlich so was wie STX und ETX.

C
224 Beiträge seit 2009
vor 10 Jahren

Ergänzung zu MartinH:

Interessant hierzu ist Reading from the serial port in C#.

Kernaussage:


  void serialPort_DataReceived(object s, SerialDataReceivedEventArgs e)
  {
    byte[] data = new byte[serialPort.BytesToRead];
    serialPort.Read(data, 0, data.Length);

    //(...) Verarbeitung von data. Z.B. Anhängen von data in eine Queue, welche verarbeitet wird.
  }