Forum: Mikrocontroller und Digitale Elektronik Endian Umwandlung einer unbekannten Struktur


von ChrisB (Gast)


Lesenswert?

Hallo an Alle,

ich möchte Datenstrukturen zwischen meinem PC (little endian) und einem 
Mikrocontroller (big endian) mittels eigenem Protokoll hin und her 
schicken. Grunsätzlich ist es ja nicht schwierig eine Umwandlung 
zwischen Little und Big Endian vorzunehmen, wenn beide 
Kommunikationsstellen wissen, um welche Struktur mit welchen 
Datenelementen und dessen Größe es sich handelt.

Gibt es auch eine Möglichkeit das ganze etwas flexibler zu gestallten?
Ich würde mir gerne eine Funktion schreiben, der ich nur noch eine 
Datenstruktur übergebe, diese auf dem Mikrocontroller automatisch ins 
Little Endian Format umgewandelt und dann zum PC übertragen wird.
Es wäre sehr aufwendig, wenn ich zu jeder Struktur angeben müsste, 
welche größe die einzelnen Elemente diese Struktur hat. Geht das auch 
irgendwie anders? Eventuell per Präprozessor oder mittels anderer 
Konstrukte?
Eine andere Möglichkeit, die ich sehe wäre die Kodierung der Größe der 
Datenelemente in die Struktur selbst...

Habt Ihr diesbezüglich irgendwelche Ideen oder Vorschläge?

Lieben Gruß,

ChrisB

von Karl H. (kbuchegg)


Lesenswert?

Die Größenangaben einzukodieren ist unpraktisch. Da verwezifelst du sehr 
schnell.
Was du brauchen würdest ist Reflection. Aber die gibt es in C nicht.

Allso wirst du wohl um Umwandlungsfunktionen nicht umhinkommen. Also ist 
entweder selberschreiben angesagt, oder du schreibst dir ein 
Hilfsprogramm, welches die entsprechenden Funktionen erzeugt. Mit einem 
kleinen Parser, welcher die structs im Source Code findet und 
entsprechend parst, ist das schon möglich. Ob es sich lohnt (ob du genug 
Strukturen hast) musst du wissen.

von holger (Gast)


Lesenswert?

Übergib dich, quatsch, übergib alle Werte als Bytes.

unsigned int wert;
unsigned char bytehigh;
unsigned char bytelow;

bytehigh = (unsigned char ) (wert>>8);
bytelow = (unsigned char )wert;

Sende dann bytehigh, bytelow.
Dann hast du keine Probleme mit Big/Littleendian.

von Reinhard Kern (Gast)


Lesenswert?

ChrisB schrieb:
> Eine andere Möglichkeit, die ich sehe wäre die Kodierung der Größe der
> Datenelemente in die Struktur selbst...

Das ist eigentlich nicht nötig, es müsste doch auch in C sowas wie 
SizeOf () geben.

Trotzdem musst du natürlich Element für Element einer Struktur 
umwandeln.

Gruss Reinhard

von Rolf Magnus (Gast)


Lesenswert?

Zur Not schreibt man sich einen kleinen Codegenerator, die die 
Strukturen aus dem Header liest und entsprechende Umwandlungsfunktionen 
automatisch erzeugt.

von ChrisB (Gast)


Lesenswert?

Danke für eure Antworten.
Ich denke die Variante, die Bytes einzeln in der Struktur abzuspeichern 
wäre momentan noch die schönste lösung. Für jede Struktur eine 
Umwandlungsfunktion zu haben ist doch sehr aufwendig, selbst wenn man 
einen Codegenerator dafür hat.
An eine sizeof-Möglichkeit habe ich auch gedacht, jedoch dürfte diese so 
nicht umsetzbar sein. Klar kann man sizeof benutzen, jedoch nur wenn ich 
an eine Funktion immer die gleiche Struktur übergebe. Wenn ich jedoch 
eine Funktion habe, die für das Senden aller Strukturen vorgesehen ist 
wird das nicht funktionieren, oder ist da jemand anderer Meinung? Ich 
wüsste jetzt nicht wie ich sowas ausprobieren könnte...

von Peter (Gast)


Lesenswert?

Ich würde immer die "Network Byte Order" für den Austausch von 
Integer-Werten zwischen verschidenen Systemen benutzen, dafür gibt es 
bei den meisten Compiler entsprechende Funktionen, natürlich auch für 
den GNU.

http://www.gnu.org/s/libc/manual/html_node/Byte-Order.html

Falls die Werte für das entsprechende System schon die richtige Byte 
Order haben, machen die Funktionen nix und müssten vom Optimizer 
wegoptimiert werden...

von Karl H. (kbuchegg)


Lesenswert?

ChrisB schrieb:
> Ich denke die Variante, die Bytes einzeln in der Struktur abzuspeichern
> wäre momentan noch die schönste lösung.

Und wie machst du das?
Du willst auch mit den Strukturen intern arbeiten, oder etwa nicht?
ALso doch wieder eine eigene Aufbereitungsfunktion für jede Struktur.

> Für jede Struktur eine
> Umwandlungsfunktion zu haben ist doch sehr aufwendig, selbst wenn man
> einen Codegenerator dafür hat.

Über wieviele hundert Strukturen reden wir eigentlich?

> Wenn ich jedoch
> eine Funktion habe, die für das Senden aller Strukturen vorgesehen ist
> wird das nicht funktionieren, oder ist da jemand anderer Meinung?

Funktionalität trennen!
Das Umwandeln einer Struktur in eine Abfolge von Bytes (mit einer 
bestimmten Order) ist eine Sache. Das Senden dieser Bytefolge ist eine 
andere Sache. Beides muss nichts miteinander zu tun haben, ausser das 
der Output von der einen Funktion Input für die andere Funktion ist.



Man kann natürlich auch einfach aus jeder Struktur eine textuelle 
Beschreibung generieren. Dann hat man die Probleme mit der Byteorder 
(und andere) erst gar nicht, erkauft sich das aber mit längerer 
Übertragungszeit.

von ChrisB (Gast)


Lesenswert?

Ich habe mir gerade nochmal Gedanken über eine Codierte Möglichkeit 
gemacht.
Dabei habe ich mir folgendes überlegt:
In jeder Struktur stehen am Anfang x+1 Bytes. Dabei entspricht x der 
Anzahl der eigentlichen Datenelementen in der Struktur, das letzte Byte 
hat immer den Wert 0 als Abschluss.
Wenn man dann per Define seinen unterschiedlichen Datentypen ID's gibt 
(oder direkt die Länge der einzelnen Datentypen definiert) und diese in 
gleicher Reihenfolge wie die Datenelemente in die ersten Bytes der 
Struktur einpflegt sollte man mit einer Funktion doch alle Strukturen in 
ein anderes Endian Format konvertieren und dann direkt übertragen 
können.

Ich denke diese Lösung ist eigentlich nicht schlecht und sollte den 
geringsten Aufwand aufweisen, da man ohne Probleme schnell neue 
Strukturen erstellen kann.

Was haltet ihr davon?

von ChrisB (Gast)


Lesenswert?

Ja, mit den Strukturen will ich intern auch arbeiten können, also fällt 
die Möglichkeit weg, die Daten direkt in die einzelnen Bytes 
aufzusplitten.
Momentan hanelt es sich nur um ein paar wenige (vielleicht 6 bis 8) 
Strukturen, jedoch möchte ich später sehr einfach auch weitere 
Strukturen definieren und mit diesen wie mit den anderen arbeiten 
können.

Ja die Funktionalität wird getrennt. Es handelt sich wie du auch sagst 
um zwei verschiedene Dinge, einmal die Konvertierung, dann die 
Generierung eines Paketes mit Checksumme und zu letzt die Übertragung.

von Karl H. (kbuchegg)


Lesenswert?

ChrisB schrieb:

> Was haltet ihr davon?

Das du jetzt endlich mal Nägel mit Köpfen machen solltest und etwas mehr 
Details rausrückst, worum es eigentlich geht und zb eine derartige 
Struktur zeigst.

So eine Struktur ist ja nicht einfach nur Selbstzweck. Mit der wird ja 
normalerweise auch programintern gearbeitet. Je mehr 
Spezialfunktionalität du dir jetzt einbaust, desto
* aufgeblähter werden deine Strukturen (Speicherverbrauch!)
* fehleranfälliger wird das in der Definitionsphase der Struktur
* komplizierter wird die restliche Handhabung im restlichen Program

von Karl H. (kbuchegg)


Lesenswert?

ChrisB schrieb:

> Dabei habe ich mir folgendes überlegt:
> In jeder Struktur stehen am Anfang x+1 Bytes. Dabei entspricht x der
> Anzahl der eigentlichen Datenelementen in der Struktur, das letzte Byte
> hat immer den Wert 0 als Abschluss.
> Wenn man dann per Define seinen unterschiedlichen Datentypen ID's gibt
> (oder direkt die Länge der einzelnen Datentypen definiert) und diese in
> gleicher Reihenfolge wie die Datenelemente in die ersten Bytes der
> Struktur einpflegt sollte man mit einer Funktion doch alle Strukturen in
> ein anderes Endian Format konvertieren und dann direkt übertragen
> können.

Wenn schon, dann trenne die 'Datensatzbeschreibung' vom eigentlichen 
'Datensatz'.

von Hermann (Gast)


Lesenswert?

> Was haltet ihr davon?


Nix. Damit verlagerst du die Problemlösung vom Zeitpunkt des 
Programmierens hin zur Laufzeit des Programms. Das heißt, das Programm 
muss während es läuft, das machen, was du als Programmierer vorher nicht 
tun wolltest. Und das beeinflusst das Ergebnis negativ. Mehr 
Übertragungsvolumen, Speicherverbrauch und Programmlaufzeit.

von (prx) A. K. (prx)


Lesenswert?

Du kannst dir natürlich ein Programm schreiben, das auf Basis der 
Strukturdefinition die Konvertierungsfunktionen für den PC automatisch 
erstellt.

Sowas ähnliches hat Sun beim NFS verbrochen, siehe rpcgen und 
http://en.wikipedia.org/wiki/External_Data_Representation.

von Karl H. (kbuchegg)


Lesenswert?

Hermann schrieb:
>> Was haltet ihr davon?
>
>
> Nix. Damit verlagerst du die Problemlösung vom Zeitpunkt des
> Programmierens hin zur Laufzeit des Programms. Das heißt, das Programm
> muss während es läuft, das machen, was du als Programmierer vorher nicht
> tun wolltest. Und das beeinflusst das Ergebnis negativ. Mehr
> Übertragungsvolumen, Speicherverbrauch und Programmlaufzeit.

Nicht zu vergessen die 'schwierigere' Fehlersuche, falls mal etwas nicht 
funktioniert. Heute weiß man die Details noch, aber in einem halben Jahr 
sieht das anders aus.
Entweder man hat eine Vollautomatik (sprich Reflection) oder man muss 
selber Hand anlegen. Muss man selber Hand anlegen, sollte man Dinge 
nicht 'verstecken'. Das hat sich meistens immer noch als Bumerang 
erwiesen. Eine clevere Halbautomatik, die davon abhängig ist, dass der 
Programmierer schon die richtigen Codes in der richtigen Reihenfolge 
irgendwo einträgt, kann sich sehr schnell ins Gegenteil verkehren. Siehe 
zb. die ganzen Fehler in denen Leute die falschen printf Codes 
eingetragen haben.

von ChrisB (Gast)


Lesenswert?

>Das du jetzt endlich mal Nägel mit Köpfen machen solltest und etwas mehr
>Details rausrückst, worum es eigentlich geht und zb eine derartige
>Struktur zeigst.

Das ganze existiert momentan nur im Kopf. Ich denke es ist wichtig sich 
vor der Programmierung ein paar Gedanken dazu zu machen.
eine Struktur mit Kodierung könnte Beispielsweise so aussehen:
1
typedef struct
2
{
3
   U08 format[5]; //Kodierung der Elemente durch ihre Größe
4
 
5
   U16 rpm;
6
   F32 temperature;
7
   F32 curren;
8
   F32 voltage;
9
   U32 timestamp;
10
}STATE;
11
12
//Im Programm würde ich dann wie folgt ein Objekt erzeugen:
13
STATE s = {{2,4,4,4,4}};
14
//Und dann kann mit den einzelnen Elementen des Objektes gearbeitet werden
15
s.rpm = cur_rpm;
16
17
//und so weiter
18
//Zu guter letzt soll die Struktur konvertiert und gesendet werden
19
serializeStruct(&s, &buffer[0], &size);
20
transmittStruct(&buffer[0], size);

>Je mehr Spezialfunktionalität du dir jetzt einbaust, desto
>* aufgeblähter werden deine Strukturen (Speicherverbrauch!)
>* fehleranfälliger wird das in der Definitionsphase der Struktur
>* komplizierter wird die restliche Handhabung im restlichen Program

Ja, es wird etwas Aufgeblähter (was aber nicht weiter schlimm ist, da 
genügend Ram zur verfügung steht), jedoch erhöht sich dadurch auch der 
komfort. Anfangs mag es auch nicht ganz einfach sein, alles korrekt zu 
programmieren, jedoch funktioniert eine einzige Funktion für alle 
Strukturen und es passieren weniger Fehler, da einfach weniger 
Quellcode.
Ich denke die Handhabung im restlichen programm wird dadurch erheblich 
vereinfacht.

>
>Wenn schon, dann trenne die 'Datensatzbeschreibung' vom eigentlichen
>'Datensatz'.

Ja das ist eine gute Idee, denn so reicht eine einzige 
Datenstatzbeschreibung für alle Objekte der Struktur und man muss beim 
erstellen eines Objektes das format-Array nicht ständig initialisieren.

@Hermann:
Deinen Einwand verstehe ich nicht ganz. Das Problem wird doch nicht vom 
Programmieren zum Ausführzeitpunkt verlagert. Es handelt sich lediglich 
um eine Abstaktion, so dass viele Strukturen von einer Routine behandelt 
werdne können und man nicht für jede Struktur eine andere Routine hat.
Die Datensatzbeschreibung an sich wird doch nur auf meinem 
Mikrocontroller zur Konvertierung verwendet und nicht zum PC übertragen, 
also bleibt das Übertragungsvolumen gleich.
Die Laufzeit wird sich etwas erhöhen, jedoch kann man das im Verhältnis 
zur Flexibilität in Kauf nehmen.

>Nicht zu vergessen die 'schwierigere' Fehlersuche, falls mal etwas nicht
>funktioniert. Heute weiß man die Details noch, aber in einem halben Jahr
>sieht das anders aus.

Ja die Fehlersuche wird anfangs nicht ganz einfach, jedoch ist die 
Aufgabe auch nicht so komplex, dass es da großartig Schwierigkeiten 
geben sollte.
Reflection ist ne schöne sache, aber das ist dann doch zu Oversized für 
meine Anwendung. Man bräuchte Unmengen an Speicher und Rechenzeit. Das 
sollte einem PC überlassen bleiben, nicht einem Mikrocontroller.

Durch eine Datensatzbeschreibung in der die Elementtypen einer Struktur 
bzw. deren Größe beschrieben wird kann man doch eine vollautomatische 
Konvertierung erreichen, die auf jede Struktur passt. Diese 
Konvertierung wird von der Laufzweit her auch nicht so viel Zeit in 
Anspruch nehmen, da wie bei jeder anderen Lösung Element für Element 
durchgegangen und konvertiert wird.

von Hermann (Gast)


Lesenswert?

> Die Datensatzbeschreibung an sich wird doch nur auf meinem
> Mikrocontroller zur Konvertierung verwendet und nicht zum PC übertragen

ok, das hatte ich anders verstanden. Dann scheint mir deine Idee auf den 
ersten Blick doch nicht so schlecht.

von ChrisB (Gast)


Lesenswert?

Ich habe mir gerade mal das XDR ein bisschen angeschaut. Das sieht im 
Moment garnicht so ungeeinet aus. Mal sehen ob das für mich das passende 
ist.

von ChrisB (Gast)


Lesenswert?

Naja doch nicht ganz das was ich brauche. Die wandeln dort nur fest 
definierte Datentypen um,leider keine Strukturen etc.
Ich denke ich werde mal eine schöne Routine schrieben, mit der das 
möglich ist.

von (prx) A. K. (prx)


Lesenswert?

Klar, war ja auch für Prozeduraufrufe gedacht. Wenn man sich eine 
Prozedur als Struktur der Parameter denkt, dann nähert sich das einander 
an. Ich meinte das XDR auch nicht direkt, sondern als Idee.

Beispielsweise könnte man eine einfache Sprache für die 
Strukturdefinitionen erstellen, aus der sowohl in die C "struct" Typen 
als auch die Konvertierungsfunktionen automatisch erstellt werden. In 
ein paar Zeilen Perl ist das erledigt.

von ChrisB (Gast)


Lesenswert?

Ja die Idee ist auf jeden Fall gut. Ich werde ein paar Anregungen von 
dort verwenden.

von Stephan V. (orca)


Lesenswert?

Also bei 6 bis 8 Strukturen würd ich mir für jede Struct eine eigene 
structtoBytes Funktion schreiben und dann zur Sicherheit noch mit 
sizeof() einen Plausibilitätscheck machen, damit du nicht aus versehen 
die Struktur erweiterst ohne die Funktion an zu passen.
1
int myStructtoBytes(MyStruct *data, char buf[], int *bufLen)
2
{
3
  if ( sizeof(MyStruct) != 42 )  // oder wie groß die struct halt ist
4
  {
5
    // Strukturgröße paßt nicht!
6
    return 1;
7
  }
8
9
  &bufLen = sizeof(MyStruct);
10
11
  buf[0] = data->ch;
12
  ...
13
14
  return 0;
15
}
Eine Überprüfung ob der Buffer wirklich groß genug ist, könnte natürlich 
auch nicht schaden.


by(e)
Stephan

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.