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
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.
Ü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.
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
Zur Not schreibt man sich einen kleinen Codegenerator, die die Strukturen aus dem Header liest und entsprechende Umwandlungsfunktionen automatisch erzeugt.
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...
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...
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.
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?
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.
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
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'.
> 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.
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.
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.
>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.
> 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.
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.
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.
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.
Ja die Idee ist auf jeden Fall gut. Ich werde ein paar Anregungen von dort verwenden.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.