Forum: Compiler & IDEs Suche Hilfe bei Bitakrobatik in C


von luggi (Gast)


Lesenswert?

Hallo Gemeinde!

Ich komme grad nicht recht weiter, ich habe hier ein Integerfeld der 
Länge 8, dass etwa folgendermaßen ausschaut:

xxxx 1101 0101 1001 | 1001 1111 0101 0010 | xxxx ....

soll heißen: die hochwertigsten vier Bits jedes zweiten Integers sind 
immer hinfällig, dann kommen 12 Nutzbits, dann der nächste Integer mit 
16 Nutzbits und dann wieder einer mit nur 12.

Alle Nutzbits hintereinander sind vom Typ

Label(4bits) | Daten (0-16bits) | Label(4bits) | Daten(0-16bits) ...

Die Länge und der Typ der Datenfelder ist durch das vorhergehende Label 
bestimmt. Ich hol mir also das Label, weiß dann was für Daten darauf 
folgen, hole mir diese und kann diese dann dekodieren. Hier komme ich 
ins Straucheln, da ja wie gesagt die Länge der Datenbereiche variiert. 
Natürlich könnte ich das ganze in einer ewigen if-else - Anweisung 
abarbeiten, aber es müsste doch auch eleganter gehen.

Ich hoffe es hat jemand einen Tipp für mich,
Danke und Gruss
luggi.

von Chris (Gast)


Lesenswert?

Eleganter, struct bzw typenumwandlung auf pointer struct mit 
anschließender Indizierung.

von luggi (Gast)


Lesenswert?

Danke,

in Richtung Struct hab ich auch schon nachgedacht, aber wie soll ich 
denn die Bits in den Struct packen?

Ich seh´s irgendwie noch nicht so recht...

von Stefan E. (sternst)


Lesenswert?

luggi wrote:

> Die Länge und der Typ der Datenfelder ist durch das vorhergehende Label
> bestimmt. Ich hol mir also das Label, weiß dann was für Daten darauf
> folgen, hole mir diese und kann diese dann dekodieren. Hier komme ich
> ins Straucheln, da ja wie gesagt die Länge der Datenbereiche variiert.

Schreibe als erstes mal eine Funktion, die aus dem Integerfeld die 
jeweils nächsten Bits extrahiert, und zwar abhängig von einem Parameter:
1
uint16_t GetBits ( uint8_t anzahl ) {

Dann kannst du erstmal 4 Bits "abholen", und dann jeweils entscheiden, 
wie viele du als nächstes brauchst.

von Stefan E. (sternst)


Lesenswert?

luggi wrote:

> in Richtung Struct hab ich auch schon nachgedacht, aber wie soll ich
> denn die Bits in den Struct packen?

Mit einer Struct geht das nicht wirklich gut, da ja die Datenfelder eine 
variable Länge haben.

von Karl H. (kbuchegg)


Lesenswert?

Stefan Ernst wrote:
> luggi wrote:
>
>> in Richtung Struct hab ich auch schon nachgedacht, aber wie soll ich
>> denn die Bits in den Struct packen?
>
> Mit einer Struct geht das nicht wirklich gut, da ja die Datenfelder eine
> variable Länge haben.

Ist zwar eigentlich nicht erlaubt, aber was solls.
So wie ich das verstanden habe, sind zwar die Datenfelder zwar variabel 
lang, aber nur in Bezug auf den Labeltyp.
Man könnte also für jeden Labeltyp eine eigene Struct definieren und die 
mit einem Cast über die Daten stülpen.

Je nach label, wird dann der Datenpointer zurechtgecastet und auf die 
Daten zugegriffen.



Bitfelder:

  struct a
  {
    unsigned int Dummy : 4;
    unsigned int Label : 4;
    unsigned int Data  : 12;
  }

Dummy belegt 4 Bits, Label ebenfalls und Data besteht aus 12 Bits.

Herausfinden musst du noch, ob dein Compiler bei der Bitnummerierung 
beim MSB oder beim LSB anfängt. Gegebenenfalls die Reihenfolge umdrehen 
und beten, dass sich das nie ändern wird.

von Chris (Gast)


Lesenswert?

Soweit ich verstanden habe, 32bit Integer
{ unsigned int label:4; unsigned int val12:12; unsigned int val16:16;}

das passt hervorragend in ein Struct.

von Stefan E. (sternst)


Lesenswert?

Nun, ich habe das etwas anders verstanden:
Die Rohdaten liegen in 28-Bit-Gruppen vor (in jeweils 4 Byte). Mehrere 
dieser Gruppen zusammen bilden die eigentlichen Nutzdaten. Und in diesen 
liegen dann mehrere dieser Label/Data-Paare direkt hintereinander. D.h. 
die genau Bitposition des zweiten Paares in den Nutzdaten hängt davon 
ab, wie lang das erste Paar war. Ich sehe nicht, wie das einfach mit 
Struct/Union zu handhaben wäre. Man müsste das ganze schon erst seriell 
"aufsplitten".

von luggi (Gast)


Lesenswert?

Danke schonmal für die Mühen!

Stefan hat recht,
es ist ein Feld aus 8 x 16bit Integer, zB.:

feld[0] = xxxx 0001 0010 0011 0111
feld[1] = 0101 0110 0111 1000 1001
feld[3] = xxxx 1010 1011 1100 1101
usw.

Bei den geraden Indizies sind die hochwertigsten 4bit Müll, bei den 
ungeraden nicht.

hier im Beispiel schauts also so aus:

Label_1 = 0001   -->  Data_1 ist 3bit lang:  001
Label_2 = 0 001  -->  Data_2 ist 3bit lang:  1 01
Label_3 = 11 01  -->  Data_3 ist 16bit lang: 01 0110 0111 1000 10
usw.

Ich denke ich werde mal anfangen, die insgesamt(max.) 112Nutzbits in ein 
7 x 16bit Feld zu schreiben und dabei den 4bit-Müll zu entsorgen.

von Stefan E. (sternst)


Lesenswert?

luggi wrote:

> Ich denke ich werde mal anfangen, die insgesamt(max.) 112Nutzbits in ein
> 7 x 16bit Feld zu schreiben und dabei den 4bit-Müll zu entsorgen.

Würde ich nicht machen. Schreibe die von mir oben genannte Funktion. Das 
wegwerfen der 4 Füllbits kannst du dort ganz einfach "nebenbei" machen.

von raki (Gast)


Lesenswert?

Ein Glück, andere kommen auch ins straucheln... die Beschreibung da oben
ist echt mies.

Was ist ein Integer der Länge 8? 8 Byte, oder was?

> Chris (Gast)
> Soweit ich verstanden habe, 32bit Integer
Das passt aber nicht zu "ich habe hier ein Integerfeld der Länge 8".
Außer er zählt in Oktetten.

> Ich komme grad nicht recht weiter, ich habe hier ein Integerfeld der
> Länge 8, dass etwa folgendermaßen ausschaut:
> xxxx 1101 0101 1001 | 1001 1111 0101 0010 | xxxx ....
>
> soll heißen: die hochwertigsten vier Bits jedes zweiten Integers sind
> immer hinfällig, dann kommen 12 Nutzbits, dann der nächste Integer mit
> 16 Nutzbits und dann wieder einer mit nur 12.
Bitmaske für die ersten zwei Bytes:
1111 1111  0000 1111


> Alle Nutzbits hintereinander sind vom Typ
Nutzbits waren bitte was? Das was nach den ersten zwei Bytes kommt?

> Label(4bits) | Daten (0-16bits) | Label(4bits) | Daten(0-16bits) ...
>
> Die Länge und der Typ der Datenfelder ist durch das vorhergehende Label
> bestimmt. Ich hol mir also das Label, weiß dann was für Daten darauf
> folgen, hole mir diese und kann diese dann dekodieren. Hier komme ich
> ins Straucheln, da ja wie gesagt die Länge der Datenbereiche variiert.
> Natürlich könnte ich das ganze in einer ewigen if-else - Anweisung
> abarbeiten, aber es müsste doch auch eleganter gehen.
Nach den obigen 16 Bit (oder 2 Byte) kommen also maximal 2 * 20 Bits?
Also 2,5 Bytes?

Am besten löst man sowas auf einem Blatt Papier...

von Karl H. (kbuchegg)


Lesenswert?

luggi wrote:
>
> feld[0] = xxxx 0001 0010 0011 0111
> feld[1] = 0101 0110 0111 1000 1001
> feld[3] = xxxx 1010 1011 1100 1101
> usw.
>
> hier im Beispiel schauts also so aus:
>
> Label_1 = 0001   -->  Data_1 ist 3bit lang:  001
> Label_2 = 0 001  -->  Data_2 ist 3bit lang:  1 01
> Label_3 = 11 01  -->  Data_3 ist 16bit lang: 01 0110 0111 1000 10
> usw.

Ah. OK also doch ein fortlaufender Bitstrom.
Ich dachte, dass bei den xxxx immer ein neuer Datensatz anfängt.

Stefan hat recht. Eine Funktion die die nächsten n Bits extrahiert 
(unter Berücksichtigung deiner Füllbits) ist die einfachste Variante.
Artet zwar in dieser Funktion in ein Bitgepfriemel und -geschiebe aus 
aber es wird sich nur in dieser Funktion konzentrieren. Darüberliegende 
Funktionen haben dann schon 'schöne' Daten, mit denen sie arbeiten.

von Stefan E. (sternst)


Lesenswert?

> Artet zwar in dieser Funktion in ein Bitgepfriemel und
> -geschiebe aus

Ach, so schlimm ist das gar nicht. ;-)

Die Funktion sieht etwa so aus (ungetestet!):
1
uint16_t GetBits ( uint8_t anzahl ) {
2
3
    static uint8_t  int_index = 0;
4
    static uint16_t bit_mask  = 0x0800;
5
6
    uint16_t bits = 0;
7
8
    while (anzahl--) {
9
10
        // Bit eintragen
11
        bits <<= 1;
12
        if (feld[int_index] & bit_mask)
13
            bits |= 1;
14
15
        // nächstes Bit
16
        bit_mask >>= 1;
17
18
        if (! bit_mask) {  // war letztes Bit, also nächster Int
19
            int_index++;
20
            if (int_index & 1)
21
                bit_mask = 0x8000;  // volles Int
22
            else
23
                bit_mask = 0x0800;  // 4 Bit wegschmeißen
24
        }
25
    }
26
27
    return bits;
28
}

von luggi (Gast)


Lesenswert?

> Artet zwar in dieser Funktion in ein Bitgepfriemel und -geschiebe aus
das war ja das wovor ich mich drücken wollte, aber naja, der Nachmittag 
dauert ja noch ein wenig... ;-)

Ok, ich mache eine Funktion, die mir in Abhängigkeit von meinem 
Parameter "Anzahl" Anzahl Bits extrahiert. Der Ablauf in der aufrufenden 
Funktion wäre dann der:
- hole 4 bit (Label)
- werte Label, zB. "Aha, das Label = 4, dann ist mein Datenblock 8 bit 
lang"
- hole 8 bit (Daten)
- werte die Daten aus
- hole 4 bit (das nächste Label)
usw.

Aber wie mache ich meiner Funktion dann klar, an welcher Stelle sie n 
bits auslesen soll. Ich dachte daran, die ausgelesen Bits zu löschen, 
bzw. noch nicht gelesene dann drüber-zu-shiften und immer von vorne zu 
lesen. Schön geht das zwar nicht, da ich ja über die Grenzen der 
einzelnen Variablen drüber schieben muss, aber was muss...

Danke für die Anstöße!

von Stefan E. (sternst)


Lesenswert?

PS:
Das Ganze wird ja wahrscheinlich mehrfach gebraucht, also ist auch noch 
eine Neuinitialisierung von int_index und bit_mask nötig. Könnte man in 
der Funktion machen, z.B. bei anzahl=0.

von luggi (Gast)


Lesenswert?

@ Stefan
Vielen Dank, das hast du jetzt also mal schnell hingezaubert, ok! Weiß 
jetzt zwar noch nicht obs im Detail so geht, aber die Idee mit dem 
static-Index kam mir Amateur mal wieder nicht, so sollte das 
Positionsproblem zu beheben sein - freufreu - danke.
Ja das mit der Neuinitialisierung ist klar, muss ich noch an geeigneter 
Stelle mit einbauen. Es kommt eh noch hinzu, das es nicht immer die 
vollen 112bits sind, bei bestimmten Labeln muss ich vorher abbrechen - 
aber das ist das kleinere Übel.

von Stefan E. (sternst)


Lesenswert?

luggi wrote:

> Ja das mit der Neuinitialisierung ist klar, muss ich noch an geeigneter
> Stelle mit einbauen.

Ergänze am Anfang der Funktion:
1
    if (! anzahl) {
2
        int_index = 0;
3
        bit_mask = 0x0800;
4
        return 0;
5
    }
Dann kannst du mit GetBits(0) die Neuinitialisierung machen.

von luggi (Gast)


Lesenswert?

Guten Morgen,

also Stefans Funktion - mit kleinen Änderungen - hab ich erfolgreich 
eingebaut, passt jetzt wunderbar!

Vielen Dank nochmal, wäre da alleine sicher noch ein gutes Stück 
drangehangen!

Schöne Grüße,
Luggi.

von Gast (Gast)


Lesenswert?

Ich würde für jeden Datensatztyp eine struct definieren
und diese structs mit einer union auf einen gemeinsamen
Speicherbereich legen. Die union kann dann auch noch
den Speicherplatz für die Eingangsdaten enthalten.
Beim ersten Zugriff auf die Union kann man die Daten-
satzart ermitteln und dann über die richtige struct
auf die Daten zugreifen.

von Stefan E. (sternst)


Lesenswert?

@ Gast:

Nein, geht nicht. Warum? Lies den ganzen Thread.

von luggi (Gast)


Lesenswert?

@Gast:
Danke für die Mühe aber das Problem ist schon erschlagen.
Aber trotzdem: Mit Union und Struct wäre es - glaub ich - nicht wirklich 
hübsch, da ich im Vorfeld nicht weiß, wie der Bitstrom ausschaut:
- er kann zwischen 28 und 4 x 28 = 112 bit lang sein
- es können zwischen 1 und 16 Label-Daten-Paare darin enthalten sein
- die Label-Daten-Paare können zwischen 4 und 20bit lang sein
das sind mir zuviele Unbekannte für feste Strukturen.

Ich denke die Lösung mit obiger Funktion triffts ganz gut.

Danke und Gruß,
Luggi.

von luggi (Gast)


Lesenswert?

Achja, vielleicht beschäftigt sich mal jemand anderes auch damit und 
dann sollte die Such-Funktion auch richtig anschlagen:

Das Ganze dient der Auswertung des

Optional Message Content, der in den
Free Format Bits der
RDS-TMC Multigroup - User - Messages

verpackt ist.


Schöne Grüße,
Luggi.

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.