seriel-byte-stream parsen

OP #3786926
Lesenswert?

hi @all,

ich habe gerade einige probleme mit dem parsen von daten die ich
von der serielen schnittstelle auf einem mikrocontroller lese

irgendwie bekomme ich die daten nicht richtig auseinander, eventuell
kann mir hier ja jemand einen tip geben ;)

die datenstruktur schaut so aus
1
1byte | 1byte | 4byte | 110byte | 1byte
2
 117  |  105  |  idx  |  daten  |  chk

das problem ist, dass die daten im data-feld nicht
an byte sondern an bits ausgerichtet sind

die ersten    8bit = wert 1
die nächsten 15bit = wert 2
die nächsten  7bit = wert 3
usw...


also hab ich mir mal folgende structs gemacht
1
struct DataSetBinary {
2
    unsigned int dataset_length:8;
3
    unsigned int dataset_code:8;
4
    unsigned int dataset_index:32;
5
    unsigned int wert1:8;
6
    unsigned int wert2:15;
7
    unsigned int wert3:7;
8
    ...
9
    unsigned int checksumme:8;
10
}
11

12
struct DataSet {
13
    unsigned int dataset_length;
14
    unsigned int dataset_code;
15
    unsigned int dataset_index;
16
    signed int wert1;
17
    float wert2;
18
    signed int wert3;
19
    ...
20
    unsigned int checksumme;
21
}

parsen versuche ich aktuell so
1
unsigned int fillBuffer  = 0;
2
unsigned int bufCounter  = 0;
3
unsigned int arrayLength = 117;
4

5
int main() {
6
    unsigned char inBuffer[arrayLength];
7

8
    while( Serial3.available > 0 ) {
9
        unsigned char byte1 = Serial3.read();
10

11
           if(fillBuffer == 0 && byte1 == 117) {
12
               int byte2 = Serial3.read();
13
               if(byte2 == 105) {
14
                   fillBuffer = 1;
15
                   inBuffer[0] = byte1;
16
                   bufCounter = 1;
17
                   byte1 = byte2; // damit unten weiter richtig befüllt wird
18
               }
19
           }
20
           if(fillBuffer) {
21
               inBuffer[bufCounter++] = byte1;
22

23
               if(bufCounter == arrayLength) {
24
                   // checksum test
25
                   // summe über alle bytes (inkl. der Checksumme selbst) sollte 0 ergeben?!
26
                   unsigned char checksum = 0;
27
                   for(unsigned int i = 0; i < arrayLength; ++i) {
28
                       checksum += inBuffer[i];
29
                   }   
30
                   //checksumme passt nicht
31
                   if(checksum != 0) {
32
                       // weiter nach einem Anfang suchen
33
                       bool startfound = false;
34
                       for(unsigned int i = 2; i < arrayLength-2; ++i) {
35
                           // potentieller Anfang gefunden
36
                           if(inBuffer[i] == 117 && inBuffer[i+1] == 105) {
37
                               // inBuffer rest an den Anfang von inBuffer kopieren
38
                               // geht mglw. auch mit memcpy() oder ähnlichem
39
                               unsigned int k = 0;
40
                               for(; k < arrayLength-i; k++) {
41
                                   inBuffer[k] = inBuffer[i+k];
42
                               }   
43
                               bufCounter = k; // weiter von Serial3 lesen, bis Buffer wieder voll, dann wieder checksum, etc.
44
                               startfound = true;
45
                               break;
46
                           }
47
                       }
48
                       if(!startfound) {
49
                           bufCounter = 0;
50
                       }
51
                   } else {
52
                       struct DataSetBinary* data = (struct DataSetBinary*)inBuffer;
53

54
                       Serial.println("Index: %d\n", data->dataset_index);
55
                       Serial.println("\twert1: %d\n", data->wert1);
56
                       Serial.println("\twert2: %f\n", data->wert2*0.00413);
57

58
                       fillBuffer = false;
59
                       bufCounter = 0;
60
                   }
61
               }
62
           }
63
       }
64
}

leider sind die ausgegeben werte def. falsch ;(
Persönliche Seite #3786994
Lesenswert?

Ray M. schrieb:
> leider sind die ausgegeben werte def. falsch ;(

Prüfe mal die Größe Deiner Struktur "DataSetBinary".

Entspricht die genau der Menge der enthaltenen Bits (aufgerundet auf 
Bytegrenzen)?

Wenn nicht, ist Deine Struktur nicht "gepackt", d.h. zur 
Geschwindigkeitsoptimierung werden Lücken eingefügt.

Je nach Compiler wird das mit einem #pragma pack o.ä. eingestellt.
#3787485
Lesenswert?

Mein Tip: es ist nicht verboten, sich während der Entwiclungsphase im 
Code mittels eingestreuten printf einen Überblick zu verschaffen, was da 
eigentlich passiert und mit welchen Werten gearbeitet wird.
Wenn dir nicht klar ist, wie ein bestimmtes Endergebnis zustande kommt, 
dann musst du dir eben dieses Wissen verschaffen. Zum Beispiel, indem 
man im Code zusätzliche printf einfügt, die einem dieses Wissen 
verschaffen.

Zum Beispiel ist interessant, welche Werte über die Serielle 
Schnittstelle reinkommen. Also geb ich mir die Bytes, so wie sie 
reinkommen aus.
Zum Beispiel möchte ich gerne wissen, ob die Synchronisierung auf den 
Anfang der Nachricht geklappt hat. Auch das gebe ich mir mittels printf 
aus. Wenn es einen Checksum Error gegeben hat (was eigentlich nicht 
vorkommen sollte), dann möchte ich das wissen und ich gebe mir auch hier 
eine entsprechende Meldung aus, zusammen mit der Information wo im 
Buffer die Startsequenz erneut angetroffen wurde. Zudem wird es eine 
gute Idee sein, wenn ich mir am Anfang der Auswertung mal alle 
empfangenen und gesammelten Bytes in einem Rutsch ausgebe, damit ich sie 
mir aus dem Protokoll nicht mühsam zusammensuchen muss um sie mal 
händisch den Bits zuzuordnen.


> leider sind die ausgegeben werte def. falsch ;(
lass dir mal die sizeof(DataSetBinary ) ausgeben. Die sollte eigentlich 
deiner Array-Length entsprechen. Je nachdem, ob dein Compiler Padding 
bytes eingefügt hat oder nicht, kann die aber auch unterschiedlich sein.
OP #3789456
Lesenswert?

danke für eure gut gemeinten ratschläge, aber
das man printf reinschreiben kann und sich die größen der
daten anschauen kann, hab ich auch schon raus gefunden ;)

spaß bei seite, das problem ist eigentlich einfach, man(n)/frau muss
nur drauf kommen:

  padding ist das schlagwort ...

schreibt man(n)/frau

  #pragma pack(push,1)
  struct DataSetBinary {
    unsigned int dataset_length:8;
    unsigned int dataset_code:8;
    unsigned int dataset_index:32;
    unsigned int wert1:8;
    unsigned int wert2:15;
    unsigned int wert3:7;
    ...
    unsigned int checksumme:8;
  };
  #pragma pack(pop)

oder

  /* #pragma pack(1) */
  struct DataSetBinary {
    unsigned int dataset_length:8;
    unsigned int dataset_code:8;
    unsigned int dataset_index:32;
    unsigned int wert1:8;
    unsigned int wert2:15;
    unsigned int wert3:7;
    ...
    unsigned int checksumme:8;
  } _attribute_ ((packed));

macht der gcc auch genau das was man(n)/frau erwartet ...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren