C# Datenübertragen nicht vollständig (Comport)

-Rayz-

Lieutenant
Registriert
Okt. 2010
Beiträge
897
Hallo,

ich habe einen Scanner und dieser nimmt ein Bild auf sobald ich den entsprechenden Befehl hinschicke. Anschließend wird mein Event getriggert und ich lese die Daten:

Code:
if (sp.BytesToRead > 0)
                    {
                        byte[] buffer = new byte[sp.BytesToRead];
                        int cnt = sp.Read(buffer, 0, sp.BytesToRead);

                       Picture.spImage_Data(buffer);
                     
                    }

Problem ist, dass die Daten nur nach und nach kommen sprich dieser Code wird zweimal ausgeführt und dadurch werden Daten überschrieben, Arraylänge stimmt nicht mehr etc.

Dann hab ich es noch via Liste probiert.

Code:
byte[] data = new byte[sp.BytesToRead];
                    int len, pos = 0;
                    while ((len = sp.Read(data, pos, data.Length - pos)) > 0)
                    {
                        pos += len;
                    }
                    List<byte> result;
                    if (sp.BytesToRead == 0 && sp.IsOpen)
                    {                        
                        result = new List<byte>(data);
                    }
                    else
                    {
                        result = new List<byte>(pos);
                        for (int i = 0; i < pos; i++)
                        {
                            result.Add(data[i]);
                        }
                    }

                    byte[] buffer = result.ToArray();
                    Picture.Image_Received(buffer);

Hier aber auch genau das selbe Problem. Wird zweimal aufgerufen, Daten werden überschrieben.

Hier die Lösung des Problems:

Code:
   if (sp.BytesToRead > 0)
                    {
                        byte[] buffer = new byte[sp.BytesToRead];
                        int cnt = sp.Read(buffer, 0, sp.BytesToRead);

                        Picture.ImageReceived(buffer);
                     
                    }

Aber das möchte ich so nicht lösen. Das muss doch irgendwie anders gehen als mit einem Thread.Sleep.
Wer eine Idee?

MfG
 
Zuletzt bearbeitet:
Wenn man über DataReceived geht, sollte man einen Buffer erstellen der genauso groß ist wie BytesToRead, dann nur 1x alles rauslesen und die Prozedur beenden bis das nächste Event mit einer neuen Byteanzahl in BytesToRead kommt. Also quasi so wie dein erster Codeblock.

Du mußt eben in deiner Prozedur CapturePicture.spImage_DataReceived berücksichtigen dass die Bildinformationen häppchenweise kommen und einen übergebenen Buffer an alles was vorher kam anhängen. Der ReceiveBuffer des seriellen Ports wird niemals so groß sein können um ein größeres Bild aufzunehmen damit du es in einem Rutsch auslesen kannst.
 
Zuletzt bearbeitet:
"Häppchen" verarbeiten...
Meine Funktionen laufen aber nicht mit Häppchen, die wollen immer das Ganze :D
Ich überlege gerade, ob ich eine Schleife mache welche überprüft, ob ein Image vorhanden ist im buffer oder nicht. ein Image bzw. jpeg hat ja auch start/ende bytes.
Ergänzung ()

Hier noch ein paar weitere (erfolglose) Tests:

Code:
int startImage = 0;
                    int endImage = 0;

                    int i = 0;
                    byte temp;

                    if (sp.BytesToRead > 0)
                    {
                                      
                        int BytestoRead = sp.BytesToRead;                       
                        byte[] buffer = new byte[BytestoRead];                       
                        sp.Read(buffer, 0, BytestoRead);
                      
                }
                catch (Exception ex)
                {
                  
                }
            }

        }
        private static bool ToImage(byte[] byteArray)
        {
            try
            {       
                MemoryStream ms = new MemoryStream();
                ms.Write(byteArray, 0, byteArray.Length);
                ms.Position = 0;
                using (Image test = Image.FromStream(ms, false, false))
                {
                    test.Save(@"test2.jpg");
                }
            }
            catch (ArgumentException)
            {
                return false;
            }
            return true;           
        }


Also muss ich wohl noch den buffer nicht mit new neu erstellen sondern um die reinkommenden Daten erweitern...oder?
Sprich das was DocWindows gemeint hat ^^


PS: Sorry seh deinen letzten Post jetzt erst
Ergänzung ()

Und was nehme ich als Abbruchbedingung?
Ich bastel mir zwei bytes[]. Eines bekommt die Daten rein und hängt diese an das zweite byte[] woher weiß ich nun, wann alle Daten angekommen sind?
Durch diese häppchenweise Übertragung bringt eine Überprüfung auf 0 ja auch nichts.
 

Anhänge

  • scanbild.JPG
    scanbild.JPG
    179,6 KB · Aufrufe: 124
Zuletzt bearbeitet:
Kann man in dem Gerät was die Daten schickt nicht Präfixe und/oder Suffixe festlegen? Dann kannst du Start und Ende der Datenübertragung erkennen.

Beim Start machst du z.B. einen MemoryStream auf und jedes Mal wenn Daten kommen, liest du die in ein Bytearray und schreibst sie anschließend in den Memorystream. Wenn das Ende-Zeichen kommt und das letzte Häppchen in den Stream geschrieben wurde, hast du im MemoryStream das komplette Bild und kannst es wie auch immer weiterverarbeiten.
 
Auch wenn ich Prä und Suffixe festlege wird mir das doch nicht weiterhelfen wenn das Paket in Einzelteilen geschickt wird oder?
 
Warum nicht? Erst kommt START, dann vielleicht 5 Pakete und im 5. ist ENDE drin.

Ich stell mir das so ungefähr vor:

START010111001 010100101 010101010 010101001 0101001ENDE

Halt 5 Pakete mit Start und Ende-Markierung.

Bisher habe ich diesbezüglich zwar nur mit Waagen und Barcodescannern gearbeitet, bei denen ein Gewicht, bzw. ein einfacher Barcode zurückgegeben wurde, aber ohne Start-, und Ende-Zeichen bin ich zumindest bei der Waage nicht ausgekommen. Die hat im Gegensatz zum Barcodescanner ununterbrochen Werte geliefert die man mit Start- und Stopzeichen auseinanderfummeln musste. Beim Barcode wars einfacher. Der hat ein CRLF am Ende gehabt und bestand nur aus Zahlen, weswegen ich die ReadLine-Funktion verwenden konnte.
 
Ich denke es würde eher sowas dann kommen:

START0101110010101001ENDE START010100101ENDE START010101010ENDE etc.
Ergänzung ()

Hab den Fehler wohl gefunden:

Code:
if (buffer[buffer.Length - 1] != 33 && buffer[buffer.Length - 2] != 6)
                        {                            
                           
                            CapturePicture._imgFileWriter.Write(buffer, 0, buffer.Length);
}

Dort wird das Ende überprüft. Sobald das Ende aber erreicht ist, springe ich ja gar nicht mehr in den Writer und schreibe die letzten Daten in den Stream!! :freak:

Lösung:

Code:
                  ...                         
                           
                            CapturePicture._imgFileWriter.Write(buffer, 0, buffer.Length);
                        
                        }
                        else
                        {
                            CapturePicture._imgFileWriter.Write(buffer, 0, buffer.Length);
                           
                            byte[] binaryData = new byte[CapturePicture._imgFileWriter.BaseStream.Length];
                            
                            binaryData = CapturePicture.ms.ToArray();
                       
                            if (byteArrayToImage(binaryData) != null)
                            {
                                CapturePicture.spImage_DataReceived(binaryData);
                            }
                        }

Bis jetzt geht es

... evtl. klappt es ja so:

Code:
                    Scan:
                    if (sp.BytesToRead > 0)
                    {
                  ...
                        else
                        {
                            CapturePicture._imgFileWriter.Write(buffer, 0, buffer.Length);
                            if (buffer[buffer.Length - 1] != 33675 && buffer[buffer.Length - 2] != 6675)
                            {                                
                                goto Scan;
                            }
                            else
                            {
                
                                byte[] binaryData = new byte[CapturePicture._imgFileWriter.BaseStream.Length];
                                check = "";
                                checki = 0;
                                binaryData = CapturePicture.ms.ToArray();

                                if (byteArrayToImage(binaryData) != null)
                                {
                                    Capture.Image_eceived(binaryData);
                                }
                            }
                        }
 
Zuletzt bearbeitet:
Kannst du nicht vorher wissen wie viele Daten übertragen werden müssen bzw. wie groß das Bild sein wird?
 
Nein kann ich nicht. Ist jedesmal anders da gibt es keine festen Werte.
Also bis jetzt geht es ja auch aber ich bin auch noch nicht wieder in die "goto" Anweisung gekommen.
 
@-Rayz-: Serielle Datenübertragung ist halt ziemlich low-level. Da muß man viel selber machen und viel Kram abfangen. Da möchte ich gleich noch zu Bedenken geben dass wenn das Endezeichen aus mehreren Bytes besteht, es auch vorkommen kann dass dieses Zeichen aufgrund von Übertragungspufferbegrenzungen aufgesplittet werden könnte und in zwei verschiedenen Read-Zyklen übertragen wird. So etwa:

START010100101
01011010101010
010101001010EN
DE

(Die Zeilenumbrüche symbolisieren die in einem Schwung übertragen Bytepakete)
 
Zurück
Oben