mikrocontroller.net

Forum: PC-Programmierung C# Leidiges Thema Struct to byte array / byte array to Struct


Autor: otti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Forengemeinde,
Ich bin ein Anfänger in der C# Welt!
Ich habe hier im Forum die Suche  und auch Google bemüht eine Lösung für 
mein Problem zu kriegen, leider mit bescheidenem Erfolg.
Zu meinem Problem, ich möchte für eine Serielle Kommunikation zwischen 
Mikrocontroller und Pc eine Struktur verwenden. Auf der Mikrocontroller 
Seite ("C")kann ich einfach mittels Zeiger die Struktur byteweise 
versenden und auch wieder empfangen. Auf der Pc Seite ("C#") gestaltet 
sich das für einen Anfänger schwieriger! Ich habe mehrere Ansätze 
versucht folgende Struktur
public struct Protocol
        {
            public byte adress;
            public byte command;
            public byte len;
            public Int16[] recivebuffer;
            public uint Rtimeout;
            public Int16 rec_CRC;
        };
in ein byte Array zu  konvertieren.
hier der erste Ansatz:
public byte[] ByteArrayFromStruct(object obj)
        {
            int length = Marshal.SizeOf(obj);
            byte[] array = new byte[length];

            IntPtr ptr = Marshal.AllocHGlobal(length);
            Marshal.StructureToPtr(obj, ptr, true);
            Marshal.Copy(ptr, array, 0, length);
            Marshal.FreeHGlobal(ptr);

            return array;
        }
byte[] test = Serial.ByteArrayFromStruct(Proto);
aber sobald in der Struktur ein Array vorkommt funktioniert das Ganze 
nicht mehr
der zweite Ansatz
public Byte[] TestSerialization(object obj)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream stream = new MemoryStream();
            formatter.Serialize(stream, obj);
            Byte[] buffer = stream.ToArray();
            return buffer;
        }
byte[] test = Serial.TestSerialization(Proto);
bei diesem Ansatz wird das Array 188 byte lang
Was mach ich Falsch?
Wäre sehr dankbar für Eure Professionelle  Hilfe

Gruß
otti

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
man kann die Struktur auch mit dem BinaryWriter / Reader Elementweise 
zusammenbauen oder lesen.
Wenn man die Strukturen verwenden will muss man auf das Alignement 
achten, damit legt der Compiler die Variablen auf für den Prozessor 
'gerade' Adressen. Das sieht in C# aber nicht schöner aus als das 
Elementweise schreiben.
    private const int maxSpare = 16;

    [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi,Pack=1)] 
      public struct teleData
    {
      [MarshalAs(UnmanagedType.ByValArray, SizeConst=8)] public byte[] sampleString;

      public float aFloat;
      public byte aByte;

      [MarshalAs(UnmanagedType.ByValArray, SizeConst=maxSpare)] public float[] spare;
    };

    private teleData tele;
    private byte[] bArray = null;

    unsafe protected override void DoSomething()
    {
      if( bArray == null )
      {
        tele = new teleData();

        //  Header
        int n = Marshal.SizeOf(tele);
        bArray = new byte[n];

        tele.spare = new float[maxSpare];
      }


      //  In Byte Array übertragen
      fixed( byte* pArray = bArray )
        Marshal.StructureToPtr(tele, new IntPtr(pArray), false);

    }

Autor: otti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entschuldigt mich Bitte aber ich kann mit dem Oben genannten Beispiel 
nichts anfangen.

Wäre nett wenn es mir jemand erklären könnte!

Danke Gruß

Otti

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
in die Strukutrdeklaration müssen die Attribute
 [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi,Pack=1)]
rein damit beim Marshalling die Daten richtig aneinandergepackt werden. 
In meiner Struktur sind einige Typen als Beispiel drin, komplizierter 
sind Arrays in Strukturen weil die ja intern nicht als einfache 
Bytearrays abgelegt werden. Und das mit dem fixed Pointer war auch 
nötig, weiss grad nicht warum.
Aber wie gesagt, einfacher ist eigentlich die BinaryWriter Klasse zu 
verwenden. Du brauchst einen MemoryStream und kannst dann mit 
bw.Write(einByte) in den Stream schreiben.

Autor: otti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JojoS schrieb:
> komplizierter
> sind Arrays in Strukturen weil die ja intern nicht als einfache
> Bytearrays abgelegt werden.

Genau das ist mein Problem.
Leider brauche ich genau das.
Kann man einen Stream auch in ein byte Array umleiten??

Danke für Deine Hilfe

Gruß
Otti

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
um den Stream in ein ByteArray zu schreiben hast du ja schon die 
richtige Memberfunktion in deinem Beispiel drin:
Byte[] buffer = stream.ToArray();

Um den Stream zu füllen gibts nur die WriteByte() Methode, das ist für 
andere Datentypen als Bytes natürlich umständlich, deshalb braucht man 
noch den BinaryWriter als Helfer um beliebige andere Daten in den Stream 
zu schreiben.

Autor: otti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JojoS schrieb:
> Um den Stream zu füllen gibts nur die WriteByte() Methode, das ist für
> andere Datentypen als Bytes natürlich umständlich, deshalb braucht man
> noch den BinaryWriter als Helfer um beliebige andere Daten in den Stream
> zu schreiben.

kannst du mir bitte ein kleines Beispiel machen.

Möchte mich für Deine Hilfe schon mal herzlich bedanken!

Gruß

otti

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
so könnte es aussehen:
        {
            MemoryStream ms = new MemoryStream(512);
            BinaryWriter bw = new BinaryWriter(ms);

            bw.Write((byte)0x11);   // address
            bw.Write((byte)0x22);   // command
            bw.Write((byte)40);     // length
            for(Int16 i=0; i<16; i++)
            {
                bw.Write(i);        // receivebuffer
            }
            bw.Write((uint)1000);   // Rtimeout
            bw.Write((Int16)1234);  // crc

            Byte [] ba = ms.ToArray();      // convert to Array

            SerialPort com = new SerialPort("COM1", 19200);     // open serial port
            com.Open();
            com.Write(ba, 0, ba.Length);                        // send data
            com.Close();
        }

Autor: otti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen herzlichen Dank für Dein Beispiel!

Ich muß mich erst mal durcharbeiten durch den Code (Anfänger)

Gruß
Otti

Autor: Johnny B. (johnnyb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein "Zauberwort" das Dir vielleicht noch hilft ist "Serialisieren".
Suche mal im Internet nach diesbezüglichen Beispielen, es gibt einige 
davon.

Autor: Sas K. (saku)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Community,

sorry, dass ich den alten Thread nochmal auskrame.
Wurde zum geposteten Problem mittlerweile eine Lösung gefunden?

Ich hab ein ähnliches Problem. Ich schicke über eine Tcp Verbindung 
double und Bytes und empfange diese in einem Array - Buffer.
Nun möchte ich aber auf die einzelnen Einträge des Arrays zugreifen um 
diese wieder in einen double oder byte - Wert dekodieren zu können.

Das müsste ich dann auch über einen Struct machen, oder?

Viele Grüße

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sas K. schrieb:
> Das müsste ich dann auch über einen Struct machen, oder?

nein, das sollte man nicht mit einer struct machen.

Empfange doch ersmal die byte du die brauchst und wandelst sie dann in 
deinen Datentype um.

Bei double z.b

BitConverter.ToDouble(byte[] value,int startIndex)
BitConverter.GetBytes(Double)


http://msdn.microsoft.com/de-de/library/system.bit...

Autor: saku (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, gut das hat mittlerweile schonmal geklappt.
Jetzt stehe ich vor dem nächsten Schritt, Daten von meinem C# Progamm 
über eine Tcp-Verbindung zu senden. Mache es derzeit über die Socket 
klasse mit socket.Send.

Problem dabei ist, dass ich nicht nur byte sondern auch double versenden 
will und diese vor dem Versenden ja zunächst umwandeln muss.
Hab es schon damit probiert:
System.Convert.ToByte(49.678) (also in diesem Beispiel soll die 
Doublezahl 49.678 versendet werden).

Auf meiner Empfangsseite kommen aber immer nur "50" an. Also ganze byte 
- Werte.


Wie könnte ich das denn eleganter lösen? Evtl erst eine Struct aufbauen 
und diese dann komplett in ein Bytearray wandeln?

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
saku schrieb:
> Wie könnte ich das denn eleganter lösen?

einfach mal den vorherigen Post lesen?

BitConverter.GetBytes(Double)

Autor: saku (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, das hatte ich irgendwie überlesen.

Leider gibt er mir da den Fehler aus, das "Eine implizite Konvertierung 
vom Typ "byte[]" in "byte" " nicht möglich ist.
  byte[] senden = new byte[c];
                        sbyte s1 = -126;
                        byte b1 = (byte)s1;
                        byte b2 = 120;
                        double d3 = 17.234;


                        senden[0] = b1;
                        senden[1] = b2;
                        senden[2] = BitConverter.GetBytes(d3);
                        
                  

                        socket.Send(senden);
                     

Autor: saku (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es funktioniert zwar gut, wenn ich mir einfach noch ein weiteres Array 
definiere und den Double dann über GetBytes in dieses Array schreibe. 
Aber das müsste sich doch auch noch anders lösen lassen, oder?
                     int c = 2;
                        int c1 = 8;
                        byte[] senden = new byte[c];
                        byte[] senden1 = new byte[c1];
                        sbyte s1 = -126;
                        byte b1 = (byte)s1;
                        byte b2 = 120;
                        double d3 = 17.234;

                        senden[0] = b1;
                        senden[1] = b2;
                        senden1 = BitConverter.GetBytes(d3);
                 
                        socket.Send(senden);
                        socket.Send(senden1);


Nochmals vielen Dank für eure zahlreichen und hilfreichen Antworten!

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
saku schrieb:
> Es funktioniert zwar gut, wenn ich mir einfach noch ein weiteres Array
> definiere und den Double dann über GetBytes in dieses Array schreibe.

GetBytes schreibt nichts in das Array senden1, sondern liefert ein neues 
Array zurück, das dann über senden1 "erreichbar" ist (siehe die GetBytes 
Typsignatur).

> Aber das müsste sich doch auch noch anders lösen lassen, oder?

s.o. Beitrag von JojoS mit MemoryStream + BinaryWriter

Autor: Sas K. (saku)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> GetBytes schreibt nichts in das Array senden1, sondern liefert ein neues
> Array zurück, das dann über senden1 "erreichbar" ist (siehe die GetBytes
> Typsignatur).
>

genau, so meinte ich das ja ;) hatte mich vielleicht ein wenig 
undeutlich ausgedrückt.

>
> s.o. Beitrag von JojoS mit MemoryStream + BinaryWriter

Ok was in diesem Fall doch um einiges umständlicher wäre, als einfach 
mehrere Arrays zu senden.


Vielen Dank :)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.