hi @all, aktuell stehe ich vor der problem das ich int_*, uint_*, float usw. in einen buffer/struct packen muss ... typedef struct CAN_message_t { uint32_t id; // can identifier uint8_t ext; // identifier is extended uint8_t len; // length of data uint16_t timeout; // milliseconds, zero will disable waiting uint8_t buf[8]; } CAN_message_t; static CAN_message_t msg; in msg.buf muss jetzt ein z.b. ein float rein gibt es dafür eine standart-lib die man verwenden kann oder schreibt solche wirklich jeder neu auf diesem platenten, dass würde sich für mich ziemlich krank anhöhren ??? sowas wie int a = 123456; convert(msg.buf, a); CANbus.write(msg); ... float b = 1234.56; convert(msg.buf, b); CANbus.write(msg); danke für einen eventuellen hinweis oder tip ...
Ray M. schrieb: > gibt es dafür eine standart-lib die man verwenden einfach memcpy float b = 1234.56; memcpy(msg.buf, &b); bei int muss man aber die Byte-order beachten. Das kommt dann auf dein System an.
Peter II schrieb: > Ray M. schrieb: >> gibt es dafür eine standart-lib die man verwenden > > einfach memcpy so einfach ? uff ... da hätte ich drauf kommen sollen ... danke > float b = 1234.56; > memcpy(msg.buf, &b); und wie geht es wieder raus ? int a; convert(a, msg.buf); oder float a = convert(msg.buf); oder sowas in der art ... > bei int muss man aber die Byte-order beachten. Das kommt dann auf dein > System an. ps: danke fürs beantworten solcher anfängerfragen ;)
Peter II schrieb: > Ray M. schrieb: >> gibt es dafür eine standart-lib die man verwenden > > einfach memcpy > > float b = 1234.56; > memcpy(msg.buf, &b); ich hab jetzt memcpy(msg.buf, &data, sizeof(data)); das scheint zu passen ?
Ray M. schrieb: > und wie geht es wieder raus ? einfach die Parameter von memcpy tauschen
1 | //rein
|
2 | memcpy(msg.buf, &b, sizeof(float) ); |
3 | |
4 | //raus
|
5 | memcpy(&b, msg.buf, sizeof(float) ); |
Ray M. schrieb: > Peter II schrieb: >> einfach memcpy > > so einfach ? Wenn die Nachrichten zwischen gleichen Plattformen übertragen werden, dann ja. Ansonsten ist (De-)serialisierung komplizierten, z.B. unterschiedlicher Endianess oder sizeof int. memcpy hat zudem den Vorteil dass es standardkonform ist und i.d.R ohne Overhead compiliert wird.
Johann L. schrieb: > Wenn die Nachrichten zwischen gleichen Plattformen übertragen werden, > dann ja. Ansonsten ist (De-)serialisierung komplizierten, z.B. > unterschiedlicher Endianess oder sizeof int. habe ich ja geschrieben, float sollte aber überall passen.
Peter II schrieb: > Johann L. schrieb: >> Wenn die Nachrichten zwischen gleichen Plattformen übertragen werden, >> dann ja. Ansonsten ist (De-)serialisierung komplizierten, z.B. >> unterschiedlicher Endianess oder sizeof int. > > habe ich ja geschrieben, float sollte aber überall passen. joop, danke ... da war ich zu schnell ... es sind alles arm-cortex-m4 am canbus, da sollten keine probleme mit endianess auftreten danke nochmal für die super schnelle hilfe ...
Mit cast geht es auch
1 | float b; |
2 | |
3 | *(float*)msg.buf = b; |
4 | |
5 | b = *(float*)msg.buf; |
Wenn der Compiler optimiert, sollte kein Unterschied zum memcpy sein.
Dirk B. schrieb: > Mit cast geht es auch Wozu dieses Type-Punning und Verletzung der Aliasing-Regeln?
Dirk B. schrieb: > Mit cast geht es auch > float b; > > *(float*)msg.buf = b; > > b = *(float*)msg.buf; > Wenn der Compiler optimiert, sollte kein Unterschied zum memcpy sein. Wenn der Puffer nicht 4-Byte aligned ist, gibt das auf Cortex M4F einen Fault, die FPU möchte floats immer nur aligned lesen. Die memcpy() Version faultet aus eigener Erfahrung normalerweise nicht.
@Jim Meba (turboj) >Die memcpy() Version faultet aus eigener Erfahrung normalerweise nicht. Ich faulte Du faultest Er/Sie/Es faultet Wir faulten Ihr faultet Sie faulten OMG!!! (Hier ist die Abkürzung im Englischen wie Deutschen zufällig identisch) http://de.wikipedia.org/wiki/Denglisch
Falk Brunner schrieb: > Ich faulte > Du faultest > [...] Schon in der Bibel steht: "...Sie bewahrten es also bis zum Morgen auf, wie es Mose angeordnet hatte, und es faulte nicht, noch wurde es madig." 2. Mose 16,24 Scheint bugfrei gewesen zu sein. ;-)
scheiss auf moses, gibt es eigentlich auch so eine elegante möglichkeit das plattformunabhängig hinzubekommen, thema endianess, padding usw...
Ray M. schrieb: > scheiss auf moses, gibt es eigentlich auch so eine elegante > möglichkeit das plattformunabhängig hinzubekommen, thema > endianess, padding usw... Mal locker bleiben, ja? Endianess erledigt man mittels htonl() und Konsorten, vergleichbaren, zur Not selbst gemachten, Funktionen oder geschickt gewählten Shift-Operationen. Float/double packt man ohne genauere Untersuchung gar nicht direkt in Messages wenn es plattformunabhängig sein soll. Sondern man untersucht erst mal, ob man wirklich ein IEEE 754 Format hat, und ob man nicht von Little- nach Big-Endian wandeln muss/soll. htonf() und htond() sind selten in Bibliotheken zu finden, also implementiert man sich die selber. Padding vermeidet man, indem man die gesamte Message in einem uint8_t[] aufbaut, nicht in irgendwelchen structs, bei denen man dann dem jeweiligen Compiler gut zureden muss. Zugegriffen wird auf die einzelnen Komponenten einer Message mit Macros oder Funktionen.
1 | #define OFFSET_LEN (11)
|
2 | |
3 | #define SET_MSG_LEN(msg, len) do { msg[OFFSET_LEN] = (uint8_t)(len >> 8); msg[OFFSET_LEN + 1] = (uint8_t)(len & 0xFF) } while(1)
|
Ja, sieht hässlich aus, ist halt plattformunabhängig.
Jay schrieb: > Endianess erledigt man mittels htonl() und Konsorten, vergleichbaren, Bei GCC siehe auch __builtin_bswap32() http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005fbswap32-4076
Wer hat denn den Bus spezifiziert? Ist das ein eigenes (Hobby-) Projekt? Im Fahrzeug (da wo CAN ursprünglich eingesetzt wurde) sind die Signale genormt. Da ist genau spezifiziert welche Endianess welches Signal in welcher Botschaft hat. Dafür kann es aber auch passieren dass dein float nicht byte-aligned ist, du also dein memcpy nicht so ohne weiteres benutzen kannst. CAN überträgt eben 64 Bit, keine 8 Byte... In einem eigenen Projekt, noch dazu mit nur gleichen Architekturen am Bus sollte aber alles passen.
Johann L. schrieb: > Jay schrieb: >> Endianess erledigt man mittels htonl() und Konsorten, vergleichbaren, > > Bei GCC siehe auch __builtin_bswap32() > > http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005fbswap32-4076 Natürlich kann man auf allerhand verschiedene Arten Bytes "rumdrehen", wenn man denn weiß, wie rum. Und dazu muß man zuerst mal wissen, auf welcher Endianess man gerade rumoperiert. Der Witz bei htonl() und ntohl() (und ihrer Geschwister) ist aber gerade der, daß man es da nicht wissen muß (weil's die Library schon weiß und automatisch richtig macht, egal auf welcher Plattform man sitzt).
Markus F. schrieb: > Johann L. schrieb: >> Jay schrieb: >>> Endianess erledigt man mittels htonl() und Konsorten, vergleichbaren, >> >> Bei GCC siehe auch __builtin_bswap32() >> >> > http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005fbswap32-4076 > > Natürlich kann man auf allerhand verschiedene Arten Bytes "rumdrehen", > wenn man denn weiß, wie rum. Und dazu muß man zuerst mal wissen, auf > welcher Endianess man gerade rumoperiert. > > Der Witz bei htonl() und ntohl() (und ihrer Geschwister) ist aber gerade > der, daß man es da nicht wissen muß (weil's die Library schon weiß und > automatisch richtig macht, egal auf welcher Plattform man sitzt). dann scheint htonl() usw. die antwort auf die frage zu sein, danke für den hinweis, ich werde mir das mal ins gehirn tun ... es kann ja nicht sein das man das rad jedes mal neu erfinden muss
Ray M. schrieb: > dann scheint htonl() usw. die antwort auf die frage zu sein, Leider auch nicht in jedem Fall. htonx() und ntohx() sind (logischerweise) auf Big-Endian Systemen No-Ops (weil "network byte order" definitionsgemäß schon Big-Endian ist). Wenn Du dein Übertragungsformat als Little-Endian definierst (was ungeschickt wäre) und entsprechend auf einem Big-Endian System eine Wandlung nach Little-Endian und zurück brauchst, mußt Du sie erst wieder selber schreiben (oder besser: die Macros aus <endian.h> benutzen).
:
Bearbeitet durch User
Markus F. schrieb: > Ray M. schrieb: >> dann scheint htonl() usw. die antwort auf die frage zu sein, > > Leider auch nicht in jedem Fall. > > htonx() und ntohx() sind (logischerweise) auf Big-Endian Systemen No-Ops > (weil "network byte order" definitionsgemäß schon Big-Endian ist). > > Wenn Du dein Übertragungsformat als Little-Endian definierst (was > ungeschickt wäre) und entsprechend auf einem Big-Endian System eine > Wandlung nach Little-Endian und zurück brauchst, mußt Du sie erst wieder > selber schreiben (oder besser: die Macros aus <endian.h> benutzen). na ja, ich frage mich warum es auf so eine zentrale frage so viele verschiedene antworten gibt ... bei einem problem was seit anbegin der zeit existiert hätte ich gedacht das es einen standartweg gibt, in einer c-lib implementiert den man verwenden sollte ... das scheint nicht der fall zu sein ... für mich ehrlich gesagt unverständlich ...
Markus F. schrieb: > Wenn Du dein Übertragungsformat als Little-Endian definierst (was > ungeschickt wäre) ... Im Prinzip ist es egal, für welche Endianess man sich bei einem eigenen Protokoll entscheidet. Wenn man binäre Daten mit Werten größer 8 Bit übertragen will, dann muss man sich für eine Endianess entscheiden, was oft genug übersehen wird. Es bietet sich an, sich an bestehende Konventionen im Umfeld zu halten, z.B. bei TCP/IP gilt Network-Byte-Order, also Big-Endian. Da heutzutage TCP/IP überall ist, sind auch die ganzen Hilfsfunktionen/-makros für den Umgang mit Network-Byte-Order überall verfügbar. Ein Vorteil, den man nutzen kann.
Konrad S. schrieb: > Markus F. schrieb: >> Wenn Du dein Übertragungsformat als Little-Endian definierst (was >> ungeschickt wäre) ... > > Im Prinzip ist es egal, für welche Endianess man sich bei einem > eigenen Protokoll entscheidet. Wenn man binäre Daten mit Werten größer > 8 Bit übertragen will, dann muss man sich für eine Endianess > entscheiden, was oft genug übersehen wird. Es bietet sich an, sich an > bestehende Konventionen im Umfeld zu halten, z.B. bei TCP/IP gilt > Network-Byte-Order, also Big-Endian. Da heutzutage TCP/IP überall ist, > sind auch die ganzen Hilfsfunktionen/-makros für den Umgang mit > Network-Byte-Order überall verfügbar. Ein Vorteil, den man nutzen kann. ok, dass ist ein argument, also werde ich das so machen, klinkt sinnvoll danke ...
Ray M. schrieb: > ok, dass ist ein argument, also werde ich das so machen Hinterhältigerweise schiebe ich noch ein aber hinterher: PCs und 'ne Menge Mikrocontroller sind Little-Endian, verstehen sich also auch "ohne den ganzen Quatsch". Wichtig ist, um die Existenz des Problems zu wissen, eine Entscheidung zu treffen und zumindest das Ergebnis der Entscheidung im Projekt zu dokumentieren.
Konrad S. schrieb: > Ray M. schrieb: >> ok, dass ist ein argument, also werde ich das so machen > > Hinterhältigerweise schiebe ich noch ein aber hinterher: > PCs und 'ne Menge Mikrocontroller sind Little-Endian, verstehen sich > also auch "ohne den ganzen Quatsch". > > Wichtig ist, um die Existenz des Problems zu wissen, eine Entscheidung > zu treffen und zumindest das Ergebnis der Entscheidung im Projekt zu > dokumentieren. na ja, dass ist einfach, network-byte-order als standart definiert und in die docu geschrieben und alles wird gut ;)
Ray M. schrieb: > na ja, dass ist einfach, network-byte-order als standart definiert > und in die docu geschrieben und alles wird gut ;) Standar*d* bitte, ich kann da nicht mehr hinsehen. Danke.
Frank M. schrieb: > Ray M. schrieb: >> na ja, dass ist einfach, network-byte-order als standart definiert >> und in die docu geschrieben und alles wird gut ;) > > Standar*d* bitte, ich kann da nicht mehr hinsehen. Danke. jawohl chef ... bitte ;) ;) ;)
Frank M. schrieb: > Standar*d* bitte, ich kann da nicht mehr hinsehen. Danke. Ta musd tu turch, auch wänns we dud! ;-)
Ray M. schrieb: > Frank M. schrieb: >> Ray M. schrieb: >>> na ja, dass ist einfach, network-byte-order als standart definiert >>> und in die docu geschrieben und alles wird gut ;) >> >> Standar*d* bitte, ich kann da nicht mehr hinsehen. Danke. > > jawohl chef ... bitte ;) ;) ;) Und wenigstens ab und zu mal sinnvolle Verwendung der Shift-Taste angewöhnen. Nicht nur C-Compiler, sondern auch Menschen sind Case-sensitiv. Ray M. schrieb: >> Wichtig ist, um die Existenz des Problems zu wissen, eine Entscheidung >> zu treffen und zumindest das Ergebnis der Entscheidung im Projekt zu >> dokumentieren. > > na ja, dass ist einfach, network-byte-order als standart definiert > und in die docu geschrieben und alles wird gut ;) Meist wird die Entscheidung eher so getroffen, dass eben das genommen wird, was die aktuelle Zielplattform benutzt. Das muß auch nicht mal unbedingt unsinnig sein. Wenn ich eine Netzwerkverbindung habe, wo immer nur zwei PCs 50 MB/s an Daten hin und her schaufeln, brauch ich mir nicht unbedingt die Mühe machen, alles erst nach Big Endian und dann nachher wieder zurück zu wandeln, nur damit's halt in Network Byte Oder ist.
Ray M. schrieb: > na ja, ich frage mich warum es auf so eine zentrale frage so viele > verschiedene antworten gibt Beim Programmieren wird auch heutzutage noch ein bisschen Mitdenken erwartet. Es gibt nicht für jede Kleinigkeit gleich eine 3 MB große Bibliothek, wenn man etwas mit Bordmitteln in wenigen Zeilen erledigen kann. Obwohl ... siehe Unten. Protokolle implementieren ist sowieso Bitfummelei, da kann man die Endianes noch schnell nebenbei erledigen. > ... bei einem problem was seit anbegin > der zeit existiert Für die meisten existiert dieses Problem gar nicht, weil deren Programme nicht über die eigene CPU hinauskommen. Für das größte Netz der Welt ist es gelöst, siehe htonl() und Konsorten. Für andere Protokolle steht es in den entsprechenden Standards. > hätte ich gedacht das es einen standartweg gibt, Big-Endian für das größte Netz der Welt. Wer will kann es bei selbstgebastelten Protokollen diesem Netz gleich tun oder eben nicht. > in einer c-lib implementiert den man verwenden sollte ... htonl() und Konsorten für das größte Netz der Welt. Wer will kann die auch bei selbstgebastelten Protokollen verwenden oder macht halt was anderes. > das scheint nicht der fall zu sein ... für mich ehrlich gesagt > unverständlich ... Bit- und Byte-Order sind Tagesgeschäft wenn man Kommunikationsprotokolle programmiert. Aber, wenn du es dir ganz hart geben möchtest, es gibt so wunderbare Systeme wie ASN.1 zu der man noch eine Encoding Rule, z.B. DER, braucht. Ok, es ist ein bisschen doof, dass es keinen vollständigen ASN.1 Compiler gibt, und die existierenden Compiler auch schon mal 12 Durchläufe über den Quelltext brauchen um ein Ergebnis zu produzieren. Aber hey, für ein paar 1000 Euro bei kommerziellen Compilern kann man schon erwarten, dass der sich ein bisschen anstrengt.
Rolf Magnus schrieb: > [...] brauch ich mir > nicht unbedingt die Mühe machen, alles erst nach Big Endian und dann > nachher wieder zurück zu wandeln, nur damit's halt in Network Byte Oder > ist. Sehe ich genauso. Die Network Byte Order befindet sich auf einer anderen Ebene als die Anwendungs-Schicht des TCP/IP-Referenzmodells. Es gibt überhaupt keine Vorschrift für die Anordnung von Daten im Application-Layer. Am portabelsten wäre wohl die Konvertierung sämtlicher Werte per sprintf() in ASCII-Strings, die anschließende Übertragung und Zurückkonvertierung per sscanf() auf dem Zielsystem. Effizienz geht aber anders...
... und dann kommt wieder "strcmp() funktioniert nicht, kräh-kräh". ;-) Naja, irgendeinen Tod muss man sterben.
Frank M. schrieb: > Am portabelsten wäre wohl die Konvertierung sämtlicher Werte per > sprintf() in ASCII-Strings, die anschließende Übertragung und > Zurückkonvertierung per sscanf() auf dem Zielsystem. Effizienz geht aber > anders... Wird aber immer mehr so gemacht, vor allem über's Internet, das ja bekannt dafür ist, dass Bandbreite immer in Hülle und Fülle zur Verfügung steht. Damit es nicht immer noch zu effizient ist, nimmt man aber kein schnödes printf/scanf, sondern XML. Das mit möglichst tiefer Verschachtelung und möglichst langen Tag-Namen holt dann das Optimum and Overhead raus - sowohl bei der Bandbreite, als auch bei der Rechenzeit. Überraschenderweise macht das die Übertragung irgendwie langsam, also komprimiert man das ganze noch on the fly, um die Overheads besser gegeneinander auszubalancieren. Denn bekanntlich ist ja auch Strom auf Geräten wie z.B. Smartphones unbegrenzt verfügbar, und irgendwie muss man ja die viele Rechenpower verbraten.
Frank M. schrieb: > Rolf Magnus schrieb: >> [...] brauch ich mir >> nicht unbedingt die Mühe machen, alles erst nach Big Endian und dann >> nachher wieder zurück zu wandeln, nur damit's halt in Network Byte Oder >> ist. > > Sehe ich genauso. Die Network Byte Order befindet sich auf einer anderen > Ebene als die Anwendungs-Schicht des TCP/IP-Referenzmodells. Es gibt > überhaupt keine Vorschrift für die Anordnung von Daten im > Application-Layer. Doch, haufenweise, aber gerne für jede Protokollfamilie etwas anders. Beispiel: HTML, oder direkt die ganze XML-Familie. Da kommen die grundlegenden Vorschriften über das Charset-Encoding rein.
Frank M. schrieb: > Am portabelsten wäre wohl die Konvertierung sämtlicher Werte per > sprintf() in ASCII-Strings, die anschließende Übertragung und > Zurückkonvertierung per sscanf() auf dem Zielsystem. Effizienz geht aber > anders... Wie immer gibt es kein Schwarz oder Weiß. Bei einer Anmeldung an einem System (z.B. Server eines eigenen Online-Spiels) oder das Senden eines Kommandos alle heilige Zeit finde ich ASCII-Daten sehr praktisch. Und halte es auch bei meinem Kommandointerpreter selbst auf kleinen Mikrocontrollern so. Bei Videostreaming oder andere datenintensive Dienste oder wenn eine geringe Latenz gefordert ist sollte man vielleicht doch mit Rohdaten arbeiten...
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.