Forum: Mikrocontroller und Digitale Elektronik Mikrocontroller: Probleme mit char Buffer


von zoe (Gast)


Lesenswert?

Guten Morgen,

auf einem Mikrocontroller soll ein Empfangspuffer vom Typ char in 
entsprechende Variablen kopiert werden.
1
uint8_t TestPuffer[256]
2
3
uint16_t Length;
4
uint32_t IpAddr;
5
uint8_t *Data;

In den ersten beiden char Elementen befindet sich die Länge in den 
nächsten 4 Elementen eine Ip Addresse. Die Daten befinden sich ab dem 
Element 6.

WIe kann man die Daten am Besten in die entsprechenden Variablen 
kopieren?

von Baendiger (Gast)


Lesenswert?

Es ist erstmal wichtig zu wissen, in welcher Form die ersten Daten 
vorliegen. Sind das einfach in 8Bit Stükchen zerteilte 16 bzw 32Bit 
Integer oder sind diese anders kodiert?

von zoe (Gast)


Lesenswert?

Es handelt sich hierbei um 8bit, 16bit und auch 32bit Stücke.

von zoe (Gast)


Lesenswert?

Mit memcpy könnte man sowas machen. Gibt es da eine bessere Alternative?

von Hmmhmm (Gast)


Lesenswert?

zoe schrieb:
> Mit memcpy könnte man sowas machen. Gibt es da eine bessere
> Alternative?

Was spricht gegen memcpy?

Alternativ könntest du dir natürlich eine Union aus einer Struktur mit 
den Daten drin und dem Buffer deklarieren. Bei den Unions bin ich mir 
nicht zu 100% sicher, ob jeder Compiler die Elemente des Struct im 
Buffer gleich anodnen muss.

Oder du machst das mit Pointern. Also immer auf den Typ casten und dann 
den offset addieren oder so.

Der Aufwand für den µC dürfte aber immer relativ gleich sein.

Ich persönlich würde die memcpy oder pointer Variante nehmen.

von Peter D. (peda)


Lesenswert?

zoe schrieb:
> uint8_t *Data;

Das ist nur ein Zeiger, da kannst Du nichts reinkopieren.
Es muß heißen:
1
uint8_t Data[250};

Wenn die Elemente zusammen hängen, mach ne Struct daraus.

von Walter S. (avatar)


Lesenswert?

zoe schrieb:
> uint8_t *Data;

da kannst du nicht die Daten selbst reinkopieren, das ist nur ein 
Zeiger.
Je nachdem was du willst brauchst du vielleicht
Data = &TestPuffer[6];

von W.S. (Gast)


Lesenswert?

zoe schrieb:
> In den ersten beiden char Elementen befindet sich die Länge in den
> nächsten 4 Elementen eine Ip Addresse. Die Daten befinden sich ab dem
> Element 6.
>
> WIe kann man die Daten am Besten in die entsprechenden Variablen
> kopieren?

Sowas regt mich auf. Wie - bittesehr - stehen Länge un IP-Adresse denn 
dort drin? Bigendian oder Littleendian? Du müßtest sowas schon 
dazusagen.

Ansonsten ist sowas doch kinderleicht - sofern ich dich wenigstens 
halbwegs verstanden habe:
long L;
 L = Testpuffer[0];
 L = (L << 8) | Testpuffer[1];
 Laenge = L;

Und sinngemäß dasselbe für die IP-Adr. Du solltest es aber für deine 
Endianess anpassen - gelle?

W.S.

von zoe (Gast)


Lesenswert?

Vielen Dank für die Hilfe.

Wie würde sowas mit union funktionieren?

von Jim M. (turboj)


Lesenswert?

zoe schrieb:
> Wie würde sowas mit union funktionieren

Vermutlich gar nicht.

von E-Techniker (Gast)


Lesenswert?

typedef struct {
   uint16_t Length;
   uint32_t IpAddr;
   uint8_t TestPuffer[256]
} __attribute__((packed)) uart_t;

uart_t uart;



Pointer auf das erste Element
uint8_t *buffer_ptr = (unsigned char*) &uart

von E-Techniker (Gast)


Lesenswert?

an den Pointer buffer_ptr werden die Daten dann linear reinkopiert.

Anschließend kannst du mit
uart.Length
uart.IpAddr oder
uart.TestPuffer

auf die Daten zugreifen

von zoe (Gast)


Lesenswert?

Die eingehenden Daten liegen im TestPuffer. Der Puffer liegt somit nicht 
in der Struktur.

von zoe (Gast)


Lesenswert?

Wie mappt man nun die obige Struktur auf den TestPuffer?

von Dirk B. (dirkb2)


Lesenswert?

zoe schrieb:
> Wie mappt man nun die obige Struktur auf den TestPuffer?

Indem man der Leseroutine den Anfang der struct übergibt und somit 
gleich in die struct liest.

von Walter S. (avatar)


Lesenswert?

E-Techniker schrieb:
> an den Pointer buffer_ptr werden die Daten dann linear reinkopiert.
>
> Anschließend kannst du mit
> uart.Length
> uart.IpAddr oder
> uart.TestPuffer
>
> auf die Daten zugreifen

und die Endianess wird schon passen?

von ms (Gast)


Lesenswert?

Hallo,

müsste auch so gehen:
1
typedef struct {
2
   uint16_t Length;
3
   uint32_t IpAddr;
4
   uint8_t Data[250];
5
} message_t;
6
7
......
8
9
message_t *message = (message_t *) TestPuffer;
10
uint32_t ip = message->IpAddr;
11
12
......

ms

von PittyJ (Gast)


Lesenswert?

Sobald man portabel programmieren möchte holt man sich die Bytes einzeln 
raus, shiftet diese passend und odert sie zum Gesamtwert.
Alle diese Unions um Memcpys führen irgendwann zu Problemen.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

E-Techniker schrieb:
> __attribute__((packed))

Auf 8Bit AVRs vermutlich nicht mal notwendig, schaden tut es aber 
niemals! Vlt möchte man den Code irgendwann auf einen ARM portieren, 
dann hätte man da ein Problem ohne packed (padding)

von Rolf M. (rmagnus)


Lesenswert?

Mampf F. schrieb:
> E-Techniker schrieb:
>> __attribute__((packed))
>
> Auf 8Bit AVRs vermutlich nicht mal notwendig, schaden tut es aber
> niemals!

Doch.

> Vlt möchte man den Code irgendwann auf einen ARM portieren, dann hätte man
> da ein Problem ohne packed (padding)

Und ggf. mit auch, denn nicht jeder ARM unterstützt überhaupt Zugriffe 
mit falschem Alignment.

von Walter S. (avatar)


Lesenswert?

ms schrieb:
> müsste auch so gehen:
>
> typedef struct {
>    uint16_t Length;
>    uint32_t IpAddr;
>    uint8_t Data[250];
> } message_t;
>
> ......
>
> message_t *message = (message_t *) TestPuffer;
> uint32_t ip = message->IpAddr;

aber nur mit etwas Glück, bei Pechvögeln funktioniert das nicht

von ms (Gast)


Lesenswert?

Walter S. schrieb:
> aber nur mit etwas Glück, bei Pechvögeln funktioniert das nicht

ja muss ich dir recht geben. Sobald man das Gesamtsystem (Programm) 
nicht im griff hat ist der misserfolg vorprogrammiert.

ms

von W.S. (Gast)


Lesenswert?

PittyJ schrieb:
> Sobald man portabel programmieren möchte holt man sich die Bytes einzeln
> raus, shiftet diese passend und odert sie zum Gesamtwert.

Ja, eben! Damit hast du als so ziemlich einziger in dieser ganzen Runde 
den Nagel auf den Kopf getroffen - aber es hört dir keiner zu.

Stattdessen wird ganz gewiß ab hier noch ellenlang über weitere structs 
und unions schwadroniert werden.

W.S.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Doch.

Erklärung?

Wofür bräuchte ein 8Bit-Controller Padding in einem Struct?

Hmm ... Obwohl, wenn da ein 16Bit und 32Bit Wort noch im Struct ist, 
wäre die Adressierung vmtl einfacher, wenn gepaddet wird ...

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

ms schrieb:
> Walter S. schrieb:
>> aber nur mit etwas Glück, bei Pechvögeln funktioniert das nicht
>
> ja muss ich dir recht geben. Sobald man das Gesamtsystem (Programm)
> nicht im griff hat ist der misserfolg vorprogrammiert.

Man kann solche Hinweise auch mal ernst nehmen...
(Aber eigentlich soll dem TO geholfen werden.)

Mir fallen dazu ein:
- Alignment nicht beachtet (zusätzliche Füllbytes, welche im char-Buffer 
nicht sind)
- Wenn message an einer ungünstigen Adresse liegt (weil ja ein 
char-Buffer das darf) geht bei verschiedenen Umgebungen der Zugriff auf 
32bit schief message->IpAddr

von Rolf Magnus (Gast)


Lesenswert?

Mampf F. schrieb:
> Rolf M. schrieb:
>> Doch.
>
> Erklärung?

Hab ich doch im Anschluss geschrieben.

> Wofür bräuchte ein 8Bit-Controller Padding in einem Struct?

Vielleicht hab ich dich missverstanden. Ich dachte mit "niemals" 
meintest du "auf keinem µC in keiner Situation". Wenn die Aussage aber 
auf den AVR beschränkt zu verstehen ist, dann ist das was anderes.

von ms (Gast)


Lesenswert?

Hallo Steffen,

Steffen R. schrieb:
> - Alignment nicht beachtet (zusätzliche Füllbytes, welche im char-Buffer
> nicht sind)
> - Wenn message an einer ungünstigen Adresse liegt (weil ja ein
> char-Buffer das darf) geht bei verschiedenen Umgebungen der Zugriff auf
> 32bit schief message->IpAddr

kannst Du mir da mal ein Beispiel geben.Ich würde das gerne mal bei mir 
im Labor Testen lassen an verschieden DEV-Systemen.

ms

von Einer K. (Gast)


Lesenswert?

ms schrieb:
> kannst Du mir da mal ein Beispiel geben.

Erzeuge lustige Strukturen.
Lasse dir mit sizeof() die jeweilige Größe zeigen.
Daraus solltest du auf die Anzahl Füllbytes schließen können.

von Steffen R. (steffen_rose)


Lesenswert?

ms schrieb:
> Hallo Steffen,
>
> Steffen R. schrieb:
>> - Alignment nicht beachtet (zusätzliche Füllbytes, welche im char-Buffer
>> nicht sind)
>> - Wenn message an einer ungünstigen Adresse liegt (weil ja ein
>> char-Buffer das darf) geht bei verschiedenen Umgebungen der Zugriff auf
>> 32bit schief message->IpAddr
>
> kannst Du mir da mal ein Beispiel geben.Ich würde das gerne mal bei mir
> im Labor Testen lassen an verschieden DEV-Systemen.

Der erste Punkt ist einfach. Man nehme ein System mit Alignment 4 oder 8 
(z.B. arm-gcc)

Es entsteht
1
typedef struct {
2
   uint16_t Length;
3
-- 2 Füllbytes --
4
   uint32_t IpAddr;
5
   uint8_t Data[250];
6
} message_t;

Für den zweiten Fall habe ich kein Beispiel zu Hand. Das char Array 
erfordert ein Alignment von 1 und kann somit z.B. auch an ungeraden 
Adressen anfangen. Häufig beginnen die Linker aber an eine ihrem max. 
Alignment passenden Stelle. Daher wird es in vielen Fällen nicht 
crashen, solange man die Struktur genau an den Anfang des Arrays legt.

Nur für die, die nicht kennen, dass man manche Zugriffe nicht auf 
beliebige Adressen durchführen darf:

Z.B. beim C166 würde ein modifiziertes Beispiel crashen:
1
message_t *message = (message_t *) &TestPuffer[1];
2
uint32_t ip = message->IpAddr

von Walter S. (avatar)


Lesenswert?

ms schrieb:
> Walter S. schrieb:
>> aber nur mit etwas Glück, bei Pechvögeln funktioniert das nicht
>
> ja muss ich dir recht geben. Sobald man das Gesamtsystem (Programm)
> nicht im griff hat ist der misserfolg vorprogrammiert.
>
> ms

ich meinte damit was anderes, nämlich dass das nur funktioniert wenn die 
Bytes des 16 bzw. 32-Bit Wortes in der passenden Reihenfolge abgelegt 
sind,
Stichwort: Endianess

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.