Forum: PC-Programmierung structur in C# empfangen


von Pier S. (bigpier)


Lesenswert?

Hallo ich bin absoluter beginer in C#!
drum möchte ich mich schon mal endschuldigen !!!

Also zu meiner Frage  ich habe einen Mikrokontroller der sendet eine 
structur Byte für Byte über die Uart raus indem ich der Sende Functio 
einfach start und stop Adresse übergebe ! Nun Möchte ich diese Daten auf 
der selben Art und weise wieder Empfangen und mit den Unterschiedlichen 
Daten im Programm Arbeiten ! Da ich aber nicht weis wie ich anfangen 
soll hoffe ich von Euch etwas hilfe zu bekommen !!


Danke schon mal

Gruß

Pier

von Ralf (Gast)


Lesenswert?

Hi Pier,

du brauchst dich nicht zu entschuldigen, dass du Anfänger bist. Besser 
wärs, sich dafür zu entschuldigen, dass du keine konkreten Informationen 
lieferst.

Wie sieht deine Struktur im µC aus? Das Prinzip ist allgemein gesehen 
einfach:

- im µC Daten aus Struktur lesen und senden
- in C# empfangen und an entsprechende Stelle in der Struktur schreiben.

Mit der Antwort kannst du wahrscheinlich soviel anfangen wie ich mit der 
Frage. Du musst schon sagen, wo genau es klemmt...

Ralf

von Pier S. (bigpier)


Lesenswert?

Also ich hab zum Beispiel eine solche Structur
struct
{
     unsigned char start;
  unsigned char adres ;
     unsigned char comando;
     int eine_nummer;
     unsigned char chksum;
    unsigned char ende;
} Comout;
Um diese zu senden übergeb ich meiner Sende Function den poiter auf den 
Anfang und Ende Dieser Daten !
Da es aber in C# anscheinend keine Poiter giebt weis ich nicht wie ich 
diese Daten wieder so empangen kann ???

Danke ich hoffe ich konnte mich jetzt klarer ausdrücken !!

Gruß
PIER

von Severino R. (severino)


Lesenswert?

Pier S. wrote:

> Da es aber in C# anscheinend keine Poiter giebt weis ich nicht wie ich
> diese Daten wieder so empangen kann ???

Nein, Poiter gibt's in C# keine!

Wenn's nicht anders geht, kannst Du ja byteweise empfangen und selber 
konvertieren. Dabei kannst Du, wenn nötig, auch Single-Byte Characters 
in Unicode konvertieren, resp. den int korrekt konvertieren (Grösse des 
Int, Endian).

von Pier S. (bigpier)


Lesenswert?

Giebt es keine besser lösung für meine structur ???
Irgend wie byte für byte weiterschieben oder so ????


Gruß
Pier

von mbc (Gast)


Lesenswert?

Es gibt in C# keine Pointer ?

http://msdn.microsoft.com/en-us/library/50sbeks5.aspx

Ich vermute mal ihr meint das mit "Poiter"


MFG
Marco

von Arc N. (arc)


Lesenswert?

Zwei Punkte:
1. Wenn es eine festgelegte Struktur ist, kann man mit Attributen die 
exakte Anordnung der Strukturinhalte festlegen
(von der ungünstigen Strukturgröße und der ungünstigen Anordnung mal 
abgesehen)
1
using System.Runtime.InteropServices;
2
3
[StructLayout(LayoutKind.Explicit,  Size = 9)]
4
struct ComOut1 {
5
    [FieldOffset(0)]
6
    byte start;
7
    [FieldOffset(1)]
8
    byte adres;
9
    [FieldOffset(2)]
10
    byte commando;
11
    [FieldOffset(3)]  
12
    int eine_nummer;
13
    [FieldOffset(7)]  // falls int ein 32-Bit Integer ist
14
    unsigned char chksum;
15
    [FieldOffset(8)]  
16
    unsigned char ende;
17
}
18
19
// oder 
20
21
[StructLayout(LayoutKind.Sequential, Pack = 1)]
22
struct ComOut2 {
23
    byte start;
24
    byte adres;
25
    byte commando;
26
    int eine_nummer;
27
    unsigned char chksum;
28
    unsigned char ende;
29
}

der "schwierigere" Teil:
Entweder man macht die gesamte Anwendung unsafe und castet/kopiert wie 
in C/C++ oder man benutzt die saubereren Möglichkeiten.
1. BinaryReader (dann braucht man das StructLayout nicht mehr)
1
SerialPort sp ...;
2
ComOut1 comout ...;
3
BinaryReader reader = new BinaryReader(sp.BaseStream);
4
comout.start = reader.ReadByte();
5
...
2. Marshal.StructureToPtr / Marshal.PtrToStructure
Das ganze mischt dann fröhlich managed und unmanaged Speicher, erfordert 
das manuelle freigeben/anfordern des Speichers (Marshal.AllocHGlobal ( 
Marshal.FreeHGlobal)
3. Will man das in 1. vorgeschlagene auch wartungsfreundlich gestalten, 
landet man bei Reflection/Emit.

von Arc N. (arc)


Lesenswert?

Kleiner Nachtrag:
Bei der dritten Variante kann man auch gleich die u.U. nötigen 
Byte-Order Umwandlungen eleganter miterledigen lassen.

von Pier S. (bigpier)


Lesenswert?

Arc Net Danke für deine Hilfe ,wenn ich auch sagen muß Bahnhof !!
Aber ich schau mir das alles mal an , hab jetzt ja Stichworte mit denen 
ich suchen kann !

Die ganze Sache ist wesentlich schwiriger als ich am Anfang gedacht habe 
!!

Beim Komunizieren zwischen zwei MC  ging meine Methode sehr gut da ich 
ganz gleich welchen Daten Typ ich auch versendet oder emfangen habe 
immer nur nach jedem Byte meinen Zeiger um Eins erhöhen musste !!


Sollte jemand ein Beispiel haben ( C#) wäre ich sehr dankbar!!

Gruß

Pier

von Ralf (Gast)


Lesenswert?

Warum legst du in C# nicht einfach ein Array an, in dem du die Daten 
ablegst. Wenn alle Daten da sind, machst du die entsprechende Zuweisung 
vom Array in deine Struktur.

Ralf

von JojoS (Gast)


Lesenswert?

weil sowas in C# nicht geht... C# ist eine Hochsprache und mag es nicht 
wenn man irgendwelche Annahmen macht wie die Daten im Speicher liegen.
Die Lösung mit dem BinaryReader ist sauber und einfach, man darf sich 
als hardwarenaher C oder Assembler Programmierer nur nicht Gedanken 
machen das alles doch irgendwie performanter gehen müsste.

von Johnny (Gast)


Lesenswert?

Wenn man weiss wie, kann man Dein Problem in C# ganz einfach lösen.
Wie schon beschrieben wurde, musst Du erst mal das Struct in C# 
ebenfalls mit einem Struct oder einer Klasse nachbilden.
Danach kannst Du mit sogenannten serializern, deserializern den 
Datenstrom ganz einfach einlesen oder ausgeben. Alles managed, ohne 
Pointer und Basteleien.
Such mal im Netz weitere Informationen zum Serialisieren und melde Dich 
wieder, falls Du nicht weiterkommst.

von Pier S. (bigpier)


Lesenswert?

Vielen Dank für Eure Hilfe !!!
Werd mich auf die suche machen !!!

Bin wol zu Hartwarebezogen eingestelt !!

Gruß Pier

von Daniel C. (cagara)


Lesenswert?

Also was man normalerweise und standardmässig in einem solchen Fall 
machen würde, ist das ganze Ding in ein Unsigned Char Array einzulesen 
und das ganze Array einfach zu einer Structur Casten.

Also sowas im Pseudocode:

unsigned char daten[sizeof(EinStruct)];
// ... daten füllen
EinStruct str = (EinStruct)daten;

von JojoS (Gast)


Angehängte Dateien:

Lesenswert?

Und in welcher Sprache soll der Pseudocode sein? In C# definitiv nicht, 
siehe mein Posting 3 Etagen höher. Und auch in C/C++ muss man den Umweg 
über Pointer gehen.
Ein Stück Code wie ich mal eine Kommunikation auf der C# Seite gebaut 
habe ist im Anhang. Dabei wird erst eine Message komplett mit STX, 
Daten, ETX und Blockcheck empfangen und die Daten in ein MemoryStream 
geschrieben. Danach wird ein Event ausgelöst das ein Paket da ist und 
ein anderer Eventhandler (könnte man auch direkt aufrufen) nimmt die 
Daten auseinander.

von Pier S. (bigpier)


Lesenswert?

Hallo Gemeinde,
ich komm nicht wirklich mit meinem Problem weiter !
Hab mir zwar ein fettes C# Buch gekauft aber ....?
Na ja !
Nun wollte ich fragen ob mir jemand einen kleinen Beispielcode mit 
Serialisieren geben kann ??
An dieser Stelle möchte ich mich für Eure Hilfe bedanken!!!

Guten Rutsch
Gruß

Pier

von Der Unbekannte #2 (Gast)


Lesenswert?

So vielleicht:
1
struct ComOut2
2
{
3
    byte start;
4
    byte adres;
5
    byte commando;
6
    int eine_nummer;
7
    byte chksum;
8
    byte ende;
9
};
10
11
SerialPort Port;
12
13
ComOut2 ReadMessage()
14
{
15
    ComOut2 Message = new Message();
16
    Message.start = Port.ReadByte();
17
    Message.adres = Port.ReadByte();
18
    Message.commando = Port.ReadByte();
19
    Message.eine_nummer = Port.ReadByte();
20
    Message.eine_nummer += Port.ReadByte() << 8;
21
    Message.chksum = Port.ReadByte();
22
    Message.ende = Port.ReadByte();
23
    return Message;
24
}

Da fehlt jetzt Berechnung und die Prüfung der Checksum. Mit 
fortschreitender Programmierung wirst Du auch feststellen, dass start 
und ende gar nicht Teil der Struktur sein müssen, weil sie eh bekannt 
sind. Beispielsweise:
1
struct ComOut3
2
{
3
    byte adres;
4
    byte commando;
5
    int eine_nummer;
6
    byte chksum;
7
};
8
9
const byte START = 0x02;
10
const byte ENDE = 0x03;
11
12
ComOut3 ReadMessage()
13
{
14
    ComOut3 Message = new Message();
15
    while (Port.ReadByte() != START)
16
        ;
17
    Message.adres = Port.ReadByte();
18
    Message.commando = Port.ReadByte();
19
    Message.eine_nummer = Port.ReadByte();
20
    Message.eine_nummer += Port.ReadByte() << 8;
21
    Message.chksum = Port.ReadByte();
22
    if (Port.ReadByte() != ENDE)
23
        throw new ApplicationException(whatever);
24
    return Message;
25
}

von Pier S. (bigpier)


Lesenswert?

Hallo & Danke erstmal,
ich hab eben den obigien Code probiert aber bekomme aber die 
Fehlermeldungen  nicht weg nämlich "Fehler  1  Eine implizite 
Konvertierung vom Typ "System.Windows.Forms.Message" in "ComOut2" ist 
nicht möglich. && Fehler  2  Der Zugriff auf "ComOut2.start" ist 
aufgrund der Sicherheitsebene nicht möglich.

ich stell mich irgend wie doff an !!!

währe sehr dankbar wenn mir jemand helfen könnte


Danke und Gruß

Pier

von Johnny (Gast)


Lesenswert?

Ich bleibe bei meiner Meinung, für Deine Aufgabe ist 
Serialisieren/Deserialisieren am besten geeignet.

Wichtig ist, Dein struct/klasse mit dem Attribut Serializable() zu 
versehen.
Also etwa so:

[Serializable]
struct ComOut2
{
    byte start;
    byte adres;
    byte commando;
    int eine_nummer;
    unsigned char chksum;
    unsigned char ende;
}

Dann musst Du einen "Stream" mit Deinen Daten machen und das ganze dann 
mit einem "BinaryFormatter" serialisieren/deserialisieren, wobei 
natürlich als Datentyp Dein struct angegeben werden muss.
Hier habe ich ein schönes Beispiel gefunden, welches zwar mit einer 
Datei arbeitet, aber es lässt sich auch einfach für Daten von einer 
seriellen Schnittstelle ändern. Aber zum üben ist es mit einer Datei 
vielleicht gar nicht so schlecht.
http://forum.codecall.net/csharp-tutorials/7918-tutorial-visual-studio-2008-c-serialization.html

von Pier S. (bigpier)


Lesenswert?

Danke für deine Hilfe ich schau mir das Beispiel gleich an!

Gruß Pier

von Arc N. (arc)


Lesenswert?

Pier S. wrote:
> Hallo & Danke erstmal,
> ich hab eben den obigien Code probiert aber bekomme aber die
> Fehlermeldungen  nicht weg nämlich "Fehler  1  Eine implizite
> Konvertierung vom Typ "System.Windows.Forms.Message" in "ComOut2" ist
> nicht möglich. && Fehler  2  Der Zugriff auf "ComOut2.start" ist
> aufgrund der Sicherheitsebene nicht möglich.
>
> ich stell mich irgend wie doff an !!!
>
> währe sehr dankbar wenn mir jemand helfen könnte
>
>
> Danke und Gruß
>
> Pier
1
    ComOut3 Message = new Message();
2
    // Message ist nicht vom Typ Message, sondern vom Typ ComOut3, also
3
    ComOut3 Message = new ComOut3();
4
    // oder 
5
    ComOut3 Message;
6
7
    // der zweite Fehler liegt daran, das die Member wie start private sind
8
    // (hätte eigentlich schon oben korrigiert werden müssen)
9
    struct ComOut3 {
10
        public byte adres;
11
        public byte commando;
12
        public int eine_nummer;
13
        public byte chksum;
14
    }

von Johnny (Gast)


Lesenswert?

> // der zweite Fehler liegt daran, das die Member wie start private sind
> // (hätte eigentlich schon oben korrigiert werden müssen)

Genau, hätte er eigentlich auch drauf kommen können, wenn er 
entsprechende Warnungen/Fehlermeldungen angeschaut hätte.

von Chris .. (dechavue)


Lesenswert?

@JoHnny:
>Ich bleibe bei meiner Meinung, für Deine Aufgabe ist
>Serialisieren/Deserialisieren am besten geeignet.


Die (De)Serialilisierung mit den integrierten BinaryFormatter wird nicht 
ganz klappen, da dieser, wenn auch binär, einen Header bzw. 
Metainformationen schreibt/benötigt und eben nicht die Daten einfach 
binär hinteinanderschreibt.
Führ mal folgendes Snipped aus und schau dir dir erstellte Datei in 
einem Hexeditor an:
1
            int i = 5;
2
            using (FileStream str = new FileStream("Test", FileMode.Create)){
3
                BinaryFormatter ser = new BinaryFormatter();
4
                ser.Serialize(str, i);
5
            }

greets

von ChrisB (Gast)


Lesenswert?

Weiss denn Jemand eine andere Lösung um in C# ein Byte-Array in eine 
Struktur zu wandeln?
Ich habe es mit folgender Funktion probiert:

T ByteArrayToStructure<T>(byte[] bytes)
{
  GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
  T structure = 
(T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),typeof(T));
  handle.Free();
  return structure;
}

Leider stimmen die Byte orders zwischen µC und PC nicht überein, so dass 
alle ints etc verdreht sind.
Kennt jemand eine einfache Lösung? Sollte doch irgendwie gehen...

von JG (Gast)


Lesenswert?

Beispiel:
Eine Structure ist definiert als:

Hinweis:
Die Struct ist als unsafe deklariert, da sie zwei char arrays fester 
Größe besitzen soll. (Eines ist public fixed byte JobID[28])

[StructLayout(LayoutKind.Explicit, Size = 184)]
        unsafe struct MetaData
        {
            [FieldOffset(0)]    //1 bytes
            public byte MetaDataVersion;
            [FieldOffset(1)]    //1 bytes
            public byte Channel_FFTLength;
            [FieldOffset(2)]    //2 bytes
            public Int16 Reserved1;
            [FieldOffset(4)]    //28 bytes
            public fixed byte JobID[28];
            [FieldOffset(32)]   //8 bytes
            public Int64 XOversampling;
            [FieldOffset(40)]   //8 bytes
            public Int64 YStart;
            [FieldOffset(48)]   //8 bytes
            public Int64 YDelta;
            [FieldOffset(56)]   //8 bytes
            public Int64 YRange;
            [FieldOffset(64)]   //8 bytes
            public Int64 ProcessingGain;
            [FieldOffset(72)]   //8 bytes
            public Int64 Reserved2;
            [FieldOffset(80)]   //1 bytes
            public byte Jop_Gap_ADCOverload;
            [FieldOffset(81)]   //1 bytes
            public byte DataVideofiltered;
            [FieldOffset(82)]   //2 bytes
            public Int16 Reserved3;
            [FieldOffset(84)]    //4 bytes
            public Int32 Antenna;
            [FieldOffset(88)]   //8 bytes
            public Int64 Centerfreq;
            [FieldOffset(96)]   //8 bytes
            public Int64 XDelta;
            [FieldOffset(104)]   //8 bytes
            public Int64 Duration;
            [FieldOffset(112)]   //8 bytes
            public Int64 Attenuation;
            [FieldOffset(120)]   //8 bytes
            public Int64 GainCorrection;
            [FieldOffset(128)]   //8 bytes
            public Int64 DetectorHfFrequency;
            [FieldOffset(136)]   //4 bytes
            public Int32 DetectorHfSignalValue;
            [FieldOffset(140)]   //4 bytes
            public Int32 DetectorHfSignalDelta;
            [FieldOffset(144)]   //40 bytes
            public fixed byte Reserved4[40];
        }

Mit folgender Funktion kann man sich die Structur aus einem Byte Array 
herausholen. Der Ansatz ist oben schon besprochen worden (Autor Arcnet 
1.12.2008 Lösungsnummer 2):

private static Header GetHeader( byte[] InBuffer)
        {

            Header Localheader = new Header();
            byte[] Buffer = new byte[Marshal.SizeOf(Localheader)];
            IntPtr pntHeader = 
Marshal.AllocHGlobal(Marshal.SizeOf(Localheader));
            try
            {
                BinaryReader reader = new BinaryReader(new 
MemoryStream(InBuffer));
                Buffer = reader.ReadBytes(Marshal.SizeOf(Localheader));
                Marshal.Copy(Buffer, 0, pntHeader, 
Marshal.SizeOf(Localheader));
                Localheader = (Header)Marshal.PtrToStructure(pntHeader, 
typeof(Header));
                DateTime dtTOA = new DateTime(1970, 01, 01, 0, 0, 0, 
DateTimeKind.Utc) + new TimeSpan(Localheader.TOA * 10);
                return Localheader;
            }
            catch
            {
                return Localheader;
            }
            finally
            {
                // Free the unmanaged memory.
                Marshal.FreeHGlobal(pntHeader);
            }
        }

Gruß JG

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.