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
typedefstruct
2
{
3
U08format[5];//Kodierung der Elemente durch ihre Größe
4
5
U16rpm;
6
F32temperature;
7
F32curren;
8
F32voltage;
9
U32timestamp;
10
}STATE;
11
12
//Im Programm würde ich dann wie folgt ein Objekt erzeugen:
13
STATEs={{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.
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.
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.