mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Suche Lösung für Syntax Unterschiede zwischen Compiler


Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Ich habe ein MSP430 und ein PIC24 die ich über UART miteinander 
verbunden habe. Die Daten die ich senden will habe ich in Strukturen 
angelegt die ich in einem H-File definiert habe. Dieses H-File will ich 
in beiden Codes verwenden. Leider legen die beiden Compiler (IAR, C30) 
die Strukturen unterschiedlich im Speicher ab. Daher ist es nötig die 
Strukturen als "pack(1)" oder "packed" zu definieren. Und da fängt mein 
Problem an. Die Compiler habe unterschiedliche Syntax.

Beispiel PIC24 (C30):
//---------------------------------------------------------
//! Definition Telegramm
typedef struct __attribute__ ((__packed__)) COM_TEL_Test1_s
  {
  uint8_t geraeteTyp;
  uint8_t telTyp;
  uint8_t length;
  uint32_t id;
  uint8_t counter;
  uint16_t swVersion;
  } COM_TEL_Test1_t;     
//----------------------------------------------------------

Beispiel MSP430 (IAR)
//---------------------------------------------------------
//! Definition Telegramm
#pragma pack(1)
typedef struct COM_TEL_Test1_s
  {
  uint8_t geraeteTyp;
  uint8_t telTyp;
  uint8_t length;
  uint32_t id;
  uint8_t counter;
  uint16_t swVersion;
  } COM_TEL_Test1_t;
#pragma pack()
//----------------------------------------------------------

Meine Lösung "bis jetzt" ist ein Compiler Switch zu nutzen:
//---------------------------------------------------------
//! Definition Telegramm
#if defined(__ICC430__)
  #pragma pack(1)
  typedef struct COM_TEL_Test1_s
#elif defined(__C30__)
  typedef struct __attribute__ ((__packed__)) COM_TEL_Test1_s
#else
  #error 'Compiler ???'
#endif
  {
  uint8_t geraeteTyp;
  uint8_t telTyp;
  uint8_t length;
  uint32_t id;
  uint8_t counter;
  uint16_t swVersion;
  } COM_TEL_Test1_t;
#if defined(__ICC430__)
  #pragma pack()
#endif
//----------------------------------------------------------

Diese Lösung funktioniert aber sie ist mühsam weil der Compiler Switch 
bei jeder Strukturen eingefügt werden muss. Meine ursprüngliche Idee war 
ein Makro zu definieren habe aber Probleme mit den # in dem Makro.
// define PACK_S  #if defined(_ICC430_) #pragma pack(1) ...

Kennt jemand von euch eine bessere Lösung?

Gruss Manuel

Autor: Stephan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen,

schau dir mal die Lösungen von veröffentlichten Projekten wie "lwIp" 
usw. an.
die machen das ungefähr so:

// im config Headerfile
// (config der CPU und des Compilers)
// ka für was das Beispiel ist!!!
/* Compiler hints for packing structures */
#define PACK_STRUCT_FIELD(x) x __attribute__((packed))
#define PACK_STRUCT_STRUCT __attribute__((packed))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END

und dann im allg. Programm Headerfile,
steht dann folgendes:
PACK_STRUCT_BEGIN
struct ip_hdr {
  /* version / header length / type of service */
  PACK_STRUCT_FIELD(u16_t _v_hl_tos);
  /* total length */
  PACK_STRUCT_FIELD(u16_t _len);
  /* identification */
  PACK_STRUCT_FIELD(u16_t _id);
  /* fragment offset field */
  PACK_STRUCT_FIELD(u16_t _offset);
  /* time to live */
  PACK_STRUCT_FIELD(u8_t _ttl);
  /* protocol*/
  PACK_STRUCT_FIELD(u8_t _proto);
  /* checksum */
  PACK_STRUCT_FIELD(u16_t _chksum);
  /* source and destination IP addresses */
  PACK_STRUCT_FIELD(ip_addr_p_t src);
  PACK_STRUCT_FIELD(ip_addr_p_t dest); 
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END

vielleicht gefällt dir das besser.

mfg
Stephan

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stephan schrieb:

> #define PACK_STRUCT_FIELD(x) x __attribute__((packed))
> #define PACK_STRUCT_STRUCT __attribute__((packed))

Nur scheint, dem obigen Text nach zu schliessen, der IAR MSP430 Compiler 
ebendiese GCC-spezifische Attributsyntax nicht zu goutieren. Und man 
kann, wie Manuel ebenfalls feststellen musste, in Präprozessormakros 
auch keine keine Präprozessoranweisungen verbuddeln.

Man erkennt hier, weshalb die GCC Autoren es vorziehen, für solche 
Konstrukte keine Präprozessor-Syntax zu nutzen - die dem 
ursprünglichen Konzept eines dem Compiler vorgeschalteten 
Text-Präprozessors ohnehin eklatant widerspricht.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde an anderer Stelle ansetzen:
Bei der Datenübertragung.
Die Übertragungsfunktion zerlegt die Struct in ihre Einzelteile und 
überträgt sie mit einem Protkoll, das beide Controller verstehen.
Fertig ist die Laube.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
STK500-Besitzer schrieb:

> Die Übertragungsfunktion zerlegt die Struct in ihre Einzelteile und
> überträgt sie mit einem Protkoll, das beide Controller verstehen.

Das sehe ich genauso. Wenn der nächste Controller dann auch noch einen 
anderen Endian hat, klappt da gar nichts mehr.

Die Schnittstellen müssen halt passen. Wie der einzelne Controller 
intern die Daten speichert, kann einem schnurzegal sein.

> Fertig ist die Laube.

Eben.

Gruß,

Frank

Autor: Stephan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

Manuel:
>Diese Lösung funktioniert aber sie ist mühsam weil der Compiler Switch
>bei jeder Strukturen eingefügt werden muss.
Es scheint doch zu funktionieren.
womit er Probleme hat war dies:

>// define PACK_S  #if defined(ICC430) #pragma pack(1) ...
und sowas hab ich noch nie gesehen!!!
Deshalb auch der Vorschlag, so wie es andere schon hinbekommen haben.

Frank M.:
>Die Schnittstellen müssen halt passen. Wie der einzelne Controller
>intern die Daten speichert, kann einem schnurzegal sein.

ok. dann braucht Manuel für den PIC und den MSP jeweils eine eigene
Sende- und Empfangsroutine!
Sollte bei einem gut organisierten Projekt auch kein Problem sein.

mfg
Stephan

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>ok. dann braucht Manuel für den PIC und den MSP jeweils eine eigene
>Sende- und Empfangsroutine!
>Sollte bei einem gut organisierten Projekt auch kein Problem sein.

Ich bezweifle, dass er für beide Controller exakt die gleichen Routinen 
verwendet. Es sind ja völlig verschiedene Controller.
Irgendwann ist die Portierbarkeit nicht mehr gegeben.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum sollte der Controller bei der Umsetzung der Datenformate eine 
entscheidende Rolle spielen? Die Datentypen in stdint.h sind klar 
definiert, die Arbeitsweise von C Funktionen auch.

Lediglich der exakte Transport über irgendwelche I/O-Register oder 
DMA-Puffer oder was auch immer ist verschieden. Aber das geschieht, wenn 
man das Software-Design richtig macht, einen Layer darunter. D.h. bei 
der Portierung wechselt man den I/O-Layer (quasi ein Device Driver) und 
behält den Rest.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> arum sollte der Controller bei der Umsetzung der Datenformate eine
> entscheidende Rolle spielen? Die Datentypen in stdint.h sind klar
> definiert, die Arbeitsweise von C Funktionen auch.

nein ist es nicht

http://de.wikipedia.org/wiki/Byte-Reihenfolge

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:

> nein ist es nicht
> http://de.wikipedia.org/wiki/Byte-Reihenfolge

Dieses Thema wurde oben bereits von Frank erwähnt. Auch das ist eine 
Frage des Designs. Man kann die Datenübertragungskonvention so 
definieren, dass sie von der Bytereihenfolge der real verwendeten 
Maschinen unabhängig ist. Für die reale Umsetzung stehen beispielsweise 
im TCP/IP-Umfeld Funktionen wie htons/ntohs zur Verfügung, die je nach 
Byteoder die Bytes umdrehen oder einfach nur durchreichen.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Warum sollte der Controller bei der Umsetzung der Datenformate eine
>entscheidende Rolle spielen? Die Datentypen in stdint.h sind klar
>definiert, die Arbeitsweise von C Funktionen auch.

Nur wirst du nicht einfach eine struct problemlos per fprintf o.dergl. 
zwischen zwei Controllern übertragen können. Edians sind da nur das eine 
Problem - wie der Compiler die struct zusammensetzt ein anderes.
Würde ich zumindest sagen.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Für die reale Umsetzung stehen beispielsweise
> im TCP/IP-Umfeld Funktionen wie htons/ntohs zur Verfügung, die je nach
> Byteoder die Bytes umdrehen oder einfach nur durchreichen.

und wie willst du die funktionen mit einen struct aufrufen? Es geht ja 
gerade darum das es keinen sinn macht einen struct als einheit zu 
übertragen. Sondern jedes element für sich und dabei kann man dann auch 
gleich die htons/ntohs funktionen aufrufen.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eben. Deshalb sollte nicht einfach den Speicherbereich einer struct so 
wie sie ist in den Tramnsportlayer schieben. Da bei befindet man sich 
auf recht glattem Eis und muss mit solchen compilerabhängigen Hacks wie 
gepackten Strukturen arbeiten. Wenn man, wie bereits vorgeschlagen, 
einen passenden Datenformatlayer einschiebt, dann ist Ruhe. Und der 
lässt sich, richtig gemacht, auch wiederum weitgehend portabel 
gestalten.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Deshalb sollte nicht einfach den Speicherbereich einer struct so
>wie sie ist in den Tramnsportlayer schieben.

Der eine macht es über eine Transportlayer, der ander über eine 
angepasste Tansportfunktion.
Dann sind wir uns ja einig.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.