Forum: Mikrocontroller und Digitale Elektronik Werte aus Array[] extrahieren / deserialisieren


von Timo (Gast)


Lesenswert?

Guten Morgen,

hab folgendes Problem. Ich hab ein  Array[] in das ich Hex Werte also 
Bytes empfange. Es ist wie folgt definiert.
1
unsigned char ARRAY[248]; //248bytes gross

In das Array bekomme ich, in die ersten zwei Bytes ein uint16_t mit der 
Wertigkeit 11 bzw. als Hex  "B" geschrieben und in die letzten zwei ein 
uint16_t mit der Wertigkeit 47 welches 2F als Hex entspricht.

ich wuerde nun gerne diese beiden Werte aus dem Array extrahieren bzw. 
deseriallsieren um zu vergleichen ob die Zahlen stimmen.... so als Check 
ob die Inhalte des Bytes vollstaendig sind.

so irgendwie waere:
1
//Eine Art parsing funktion so z.b.
2
uint16_t StartID = ByteToUINT16(ARRAY, 0) 
3
uint16_t EndeID = ByteToUINT16(ARRAY, 256)
4
5
//oder gibts ein weg das es so geht?
6
uint16_t StartID = ARRAY[0];
7
uint16_t EndeID = ARRAY[255];

In c# gabs eine tolle Funktion da konnte man direkt das gewuenschte aus 
einem Array rausparsen, gibt es sowas fuer embedded c? Oder vielleicht 
eine andere Moeglichkeit?

Spaeter muessen noch andere Werte aus dem ARRAY raus und zwar ein paar 
int32[] Arrays etc.
1
typedef struct
2
{
3
  uint16_t POSStartSign; // muss 11 sein  bzw in hex B
4
  uint16_t ID;
5
  uint16_t Schrauben;
6
7
        int32_t POS01[3]; 
8
        int32_t POS02[3];
9
        int32_t POS03[3];
10
  int32_t POS04[3];
11
  int32_t POS05[3];
12
  int32_t POS06[3];
13
  int32_t POS07[3];
14
  int32_t POS08[3];
15
  int32_t POS09[3];
16
  int32_t POS10[3];
17
  int32_t POS11[3];
18
        int32_t POS12[3];
19
        int32_t POS13[3];
20
  int32_t POS14[3];
21
  int32_t POS15[3];
22
  int32_t POS16[3];
23
  int32_t POS17[3];
24
  int32_t POS18[3];
25
  int32_t POS19[3];
26
  int32_t POS20[3];
27
        uint16_t POSEndSign; // hier muss 47 bzw hex 2F rein
28
29
} SCHR_POS; //TOTAL = 248byte

Ich hab dazu auch ein Strukt erstellt, in der Hoffnung, ich koennte 
meine empfangenen Bytes direkt in meine Struktur reinladen.

Hat jemand eine Idee?
Vielen Dank!

Timo

von Ersi (cell85)


Lesenswert?

Ich kenn das hier:

uint32 deserialize_uint32(unsigned char *buf)
{
    uint32 *x = (uint32*)buf;
    return *x;
}

unsigned char * deserialize_uint32B(unsigned char *buffer, uint32* 
value)
{
    *(uint32*)buffer = *value;
    return buffer;
}

Ich weis nicht ob es der optimalse Weg ist und ich hab leider keine 
Ahnung wie man das mit Arrays bewerkstelligt.

cya
Sven

PS.
jetzt gehts erstmal nach Malle ! :)

von Michael B. (planlessmichi)


Lesenswert?

Hallo Timo,

wenn Du nichts gegen Pointer hast, dann leg doch noch einen Pointer vom 
Typ SCH_POS an und initialisiere ihn mit der Adresse von ARRAY.

SCH_POS *pSchPos = &ARRAY;

Dann kannst Du mit z.B.

pSchPos-> POSStartSign

oder

pSchPos->POS01[0]

direkt auf die Werte zugreifen. Also quasi das 'ARRAY' für die Funktion 
benutzen, die das Teil  Byteweise befüllt und pSchPos für den Zugriff 
auf die 2- bzw. 4-Byte großen Datenzugriffe.

von Timo (Gast)


Lesenswert?

Danke Michael,

das ist ja praktisch wenn ich das so wie du beschreibst machen kann.
Muesste ich dann nicht im Strukt alle Elemente auch noch als Pointer 
schreiben? :
1
typedef struct
2
{
3
  uint16_t *POSStartSign;
4
  uint16_t *ID;
5
  uint16_t *Schrauben;
6
.
7
.
8
.
9
10
} SCHR_POS;

Gruss
Timo

von Timo (Gast)


Lesenswert?

Hi Michael,

ich hab das jetzt mal versucht und ich erhalte von Keil folgenden Fehler

..\main.c(323): error:  #31: expression must have integral type

1
static SCREW_POS *sharedPosData = NULL;
2
3
bool PosStartCheck() //pruefen ob StartID richtig
4
  {
5
  //hier die Positionsdaten reinladen, siehe header fuer mehr info!
6
  *sharedPosData &RXBUFF;
7
    
8
    bool status=false;// im normalfall true  = kein abbruch
9
    uint16_t ID = 47; //EndSign soll 47, 47 als HEX = 2F sein
10
    uint16_t RcvID = sharedPosData->POSStartSign;
11
    
12
      if (RcvID == ID)
13
       {
14
       printf("StartID korrekt\r\n");
15
       status=true;
16
       }
17
    printf("StartID NICHT korrekt: %i \r\n",RcvID);
18
  
19
  return status;
20
 }


Viele Gruesse
Timo

von Michael B. (planlessmichi)


Lesenswert?

Timo schrieb:
> *sharedPosData &RXBUFF;

Das muss so lauten:
sharedPosData  = &RXBUFF;

Also vorne den Stern weg und dann noch das = für die Zuweisung rein.

Die Struktur muss übrigens so bleiben; also keine zusätzlichen Pointer 
innerhalb der Struktur.
Der Grund: Deine "Füllfunktion" schreibt in die Struktur ja sicherlich 
die blanken Daten rein und nicht die Adressen, wo die Daten dann zu 
finden wären.

Was evtl. noch sein "könnte": Evtl. gibt es noch ein 
Big-/Little-Endian-Problem.... Kommt drauf an, wie Deine Plattform 16 
und 32 Byte Werte interpretiert...

von Michael B. (planlessmichi)


Lesenswert?

Michael B. schrieb:
> Was evtl. noch sein "könnte": Evtl. gibt es noch ein
> Big-/Little-Endian-Problem.... Kommt drauf an, wie Deine Plattform 16
> und 32 Byte Werte interpretiert...

Siehe hierzu auch: http://de.wikipedia.org/wiki/Byte-Reihenfolge

Viel Erfolg :-)

von Timo (Gast)


Lesenswert?

Hi Michael!

Danke für die Hilfe!

ja das big und little endian problem hatte ich. Ich hab das dann auf der 
Hostmaschine (win pc)  geändert um mir die arbeit am Pc zu sparen.

Viele Gruesse
Timo

von Timo (Gast)


Lesenswert?

Hi Michael,

der compiler sagt :

..\main.c(303): error:  #513: a value of type "unsigned char (*)[248]" 
cannot be assigned to an entity of type "SCREW_POS *"


Woran koennte das liegen?

Viele Gruesse
Timo

von Ersi (cell85)


Lesenswert?

Kann es sein das du eher sowas machen musst?
Also die Variablen so initialisieren bzw beladen ?


sharedPosData->POSStartSign = (uint16_t)RXBUFF[0];
sharedPosData->ID           = (uint16_t)RXBUFF[2];
sharedPosData->Schrauben    = (uint16_t)RXBUFF[4];
..
.
.

Bringts was?

von Ersi (cell85)


Lesenswert?

Funny hab das gleiche Problem wie Timo.
Ich arbeite ebenfalls gerade an einer deserializierung meiner daten die 
ich als byte erhalte.

unsigned char Buffer[48];  da sind meine Daten drin.

Mein XMEGA schickt dem STM32F103 per UART serialisierte Daten, 12x 
int16.

Ich will die jetzt ebenfalls aus dem byte array in meine int's parsen.
Aber wie?
Eine Struktur habe ich jetzt nicht erstellt, brauch ich auch nich.


MfG
Sven.

von Timo (Gast)


Lesenswert?

so

int32 mynumber1 = *((int32 *)&RXBUFFER[0]); // 4 bytes of rxbuffer 
parsed to int32 number1
int32 mynumber2 = *((int32 *)&RXBUFFER[4]);

oder so

int32 *array32 = (int32 *)RXBUFFER;

number1 = array32[0];
number2 = array32[1];

von Michael B. (planlessmichi)


Lesenswert?

Hallo Timo,

das hier:

Timo schrieb:
> ..\main.c(303): error:  #513: a value of type "unsigned char (*)[248]"
> cannot be assigned to an entity of type "SCREW_POS *"

bekommst Du mit einem cast weg:
sharedPosData = (SCREW_POS*)&RXBUFF;

Allerdings ist die struct etwas kritisch...
Es könnte sein, dass Dein Compiler das Teil etwas "optimiert", weil das 
Teil 2 Byte, 2 Byte, 2 Byte, dann lauter 4 Byte Variablen hat und am 
Ende wieder eine 2 Byte-Variable hat... Stichwort "struct Alignment"

Wenn Du eine Chance hast, Dir den Speicher anzuschauen, dann schau mal, 
wie das erste POS01 aussieht...

Am einfachsten füllst Du das Array vielleicht einfach mal mit einer 
einfachen for-Schleife wie z.B.

for (int i = 0; i < 248; i++)
{
  RXBUFF[i] = i;
}

Dann sollte Dein POS01[0] den Wert 0x09080706 haben (bzw. 0x06070809 --> 
Little-Big-Endian; vielleicht sagst Du auch einfach mal, welche 
Plattform Du benutzt, dann ist es etwas einfacher :-))

Sollte POS01[0] allerdings sowas wie 0x0B0A0908 sein, dann hat Dir der 
Compiler aus Performance-Gründen noch ein paar Bytes dazu geschustert, 
damit die POSXX-Teile auf "besseren" Speicheradressen liegen...
Bei 32-Bit Maschinen wird sowas z.B. oft gemacht, wenn die entsprechende 
Optimierung zuschlägt...

Es gibt auch irgendeine Möglichkeit, so ein umsoriteren auszuschalten, 
aber da weiß ich gerade nicht, wie das geht...
Schau mal, ob das bei Dir überhaupt der Fall ist, dann kann ich mal 
googlen...

von Timo (Gast)


Lesenswert?

Es handelt sich um einen STM32 .. ich glaub die haben big endian.


mit dem :
int32 mynumber1 = *((int32 *)&RXBUFFER[0]);


hab ich das Problem das einfach nur das erste byte in das int32 mynumber 
kopiert wird nicht aber alle 4 bytes, weil ja das int32 auf 4 bytes 
besteht.

... also doch keine lösung.


nehmen wir an
2F 00 AA BB  ist RXBUFFER[0] bis [3]
unnd daraus müsste das int32 geparsed/convertiert werden.

Aber so eine Funktion gibts so nicht ... also ByteToInt32 oder 
ByteToUInt32

Das Endian Problem kann ich aber auch mit meiner Funktion ArrayReverse() 
beseitigen der macht mir dann aus einem big endian ein little endian.
Im momentan passt es mit der Endianness.

Ich will nur aus dem Byte-Stream mein int raus holen und dann das 
nächste.. :(

Mist, in C# geht das so einfach!

von Michael B. (planlessmichi)


Lesenswert?

O.k., für STM müsste vielleicht noch ein anderer helfen... Da kenne ich 
den Compiler nicht... Aber der sollte sicherlich auch eine Möglichkeit 
haben, das Alignmemt zu deaktivieren.

Aber wenn Du das mit dem cast nicht magst (was aber völlig o.k. und 
üblich ist), dann kannst Du ja auch eine eigene Funktion dafür schreiben 
(z.B. FillStruct()) und darin dann jede Variable einzeln mit Shifterei 
füllen... Etwas viel Aufwand, wenn es doch sonst in einer Zeile geht, 
aber durchaus möglich.... Oder Du schreibst zwei Funktionen für die 
Konvertieretei (eine für int16, eine für int32) und gibst als Parameter 
den Offset an. Den kannst Du ja auch als define anlegen und grob so 
nennen, wie die entsprechende Variable im struct. Also z.B.

#define OFFSET_POSStartSign 0
...
#define OFFSET_POS01_0 6
#define OFFSET_POS01_1 10
...

Gibt viele Wege... Wo liegt den jetzt genau Dein Problem?

von Timo (Gast)


Lesenswert?

Hi Michael,

also ich probiere das gleich mal mit dem Cast in das Struct erneut.
Das wäre ja der optimalste Weg.

Ansonsten muss ich jede einzelene Variable durch das verschieben der 
Bytes aus dem Array erzeugen. - Das wäre der zweite Weg , welchen du ja 
jetzt auch beschrieben hast (mit den offset's etc.)
(Übrigens hier mal der Bitconverter den ich sonst am PC nutze ... 
einfacher gehts nicht 
http://msdn.microsoft.com/de-de/library/bb384066.aspx)

Übrigens ich benutze den Keil Compiler und soeben habe ich 
herausgefunden, das man das byte alignment abschalten kann in dem man 
scheinbar die optimierungsstufe von -3 auf 0 setzt. (gut zu wissen!)

Ich hab gerade noch was interessantes gefunden:
1
template <typename IntegerType>
2
IntegerType bitsToInt( IntegerType& result, const unsigned char* bits, bool little_endian = true )
3
  {
4
  result = 0;
5
  if (little_endian)
6
    for (int n = sizeof( result ); n >= 0; n--)
7
      result = (result << 8) +bits[ n ];
8
  else
9
    for (unsigned n = 0; n < sizeof( result ); n++)
10
      result = (result << 8) +bits[ n ];
11
  return result;
12
  }

Quelle: http://www.cplusplus.com/forum/beginner/3076/

von Timo (Gast)


Lesenswert?

Michael es hat geklappt, in dem ich was geaendert habe !

1. unsinged char array zu einem uint8_t array

dann die funktion abgeandert

uint32_t* mynumber1 = (uint32_t *)&RXBUFFER[0];

uint32_t* mynumber2 = (uint32_t *)&RXBUFFER[4];

So gehts super! Ist aber halt BigEndian.
Ich schau mal ob es jetzt auch mit dem Strukt geht.

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.