Forum: PC-Programmierung seriel-byte-stream parsen


von Ray M. (ray_m)


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 ;(

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


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.

von Ray M. (ray_m)


Lesenswert?

nein, leider nicht

die struktur mit den daten wird nur hinten mit 0 aufgefüllt um auf 
110byte zu kommen, wenn werte nicht gesetzt sind werden die mit 0 
angegeben ...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Ray M. schrieb:
> die struktur mit den daten wird nur hinten mit 0 aufgefüllt um auf
> 110byte zu kommen

Ich glaube nicht, daß Du verstanden hast, was ich meine.

von Karl H. (kbuchegg)


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.

: Bearbeitet durch User
von Ray M. (ray_m)


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 ...

: Bearbeitet durch User
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.