简体   繁体   中英

bit, nibbles and shifting in C

I'm trying to understand the bit operations, but after few hours of analysing - still nothing.

Here is the code: https://github.com/merbanan/rtl_433/blob/master/src/rtl_433.c

but the most interesting part is here:

static int prologue_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS]) {
    int rid;

    int16_t temp2;

    /* FIXME validate the received message better */
    if (((bb[1][0]&0xF0) == 0x90 && (bb[2][0]&0xF0) == 0x90 && (bb[3][0]&0xF0) == 0x90 && (bb[4][0]&0xF0) == 0x90 &&
        (bb[5][0]&0xF0) == 0x90 && (bb[6][0]&0xF0) == 0x90) ||
        ((bb[1][0]&0xF0) == 0x50 && (bb[2][0]&0xF0) == 0x50 && (bb[3][0]&0xF0) == 0x50 && (bb[4][0]&0xF0) == 0x50)) {

        /* Prologue sensor */
        temp2 = (int16_t)((uint16_t)(bb[1][2] << 8) | (bb[1][3]&0xF0));
        temp2 = temp2 >> 4;
        fprintf(stderr, "Sensor temperature event:\n");
        fprintf(stderr, "protocol      = Prologue\n");
        fprintf(stderr, "button        = %d\n",bb[1][1]&0x04?1:0);
        fprintf(stderr, "battery       = %s\n",bb[1][1]&0x08?"Ok":"Low");
        fprintf(stderr, "temp          = %s%d.%d\n",temp2<0?"-":"",abs((int16_t)temp2/10),abs((int16_t)temp2%10));
        fprintf(stderr, "humidity      = %d\n", ((bb[1][3]&0x0F)<<4)|(bb[1][4]>>4));
        fprintf(stderr, "channel       = %d\n",(bb[1][1]&0x03)+1);
        fprintf(stderr, "id            = %d\n",(bb[1][0]&0xF0)>>4);
        rid = ((bb[1][0]&0x0F)<<4)|(bb[1][1]&0xF0)>>4;
        fprintf(stderr, "rid           = %d\n", rid);
        fprintf(stderr, "hrid          = %02x\n", rid);

        fprintf(stderr, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[1][1],bb[1][2],bb[1][3],bb[1][4]);

        if (debug_output)
            debug_callback(bb);

        return 1;
    }
    return 0;

I don't understand what is bb[BITBUF_ROWS][BITBUF_COLS].

The algorithm gets the 9 nibbles, which are decoded into some variables, eg. temp, humidity etc.

The example taken from http://goughlui.com/2013/12/20/rtl-sdr-433-92mhz-askook-decoding-of-various-devices-with-rtl_433/

The input: 10010110 01000100 00010000 00010010 10111000

The result:

button: 1
battery: Low
temp: 25.7
humidity: 43
channel:1 
id: 9
rid :100
hrid: 64

Because I don't know if the input is negative or LSB reversed I prepared the table with all situations:

bin   dec   neg    neg  rev   rev   neg     neg
            bin    dec        dec   rev     rev dec
1001    9   0110    6   1001    9   0110    6
0110    6   1001    9   0110    6   1001    9
0100    4   1011    11  0010    2   1101    13
0100    4   1011    11  0010    2   1101    13
0001    1   1110    14  1000    8   0111    7
0000    0   1111    15  0000    0   1111    15
0001    1   1110    14  1000    8   0111    7
0010    2   1101    13  0100    4   1011    11
1011    11  0100    4   1101    13  0010    2
1000    8   0111    7   0001    1   1110    14

But I definetely don't understand how the temp is 25.7, while there's no 5 at all. the humidity id 43 but there's no 3 value.

What I'm doing wrong?

All values are in there. The input in hex is

96 44 10 12 B8

and writing it as nibbles, we get

A a | B b | C c | D d | E e
9 6 | 4 4 | 1 0 | 1 2 | B 8

With this notation, we can replace bb[1][0] with Aa , bb[1][1] with Bb and so forth. I will refer to individual nibbles as A , a , and so on, without the bit shifting and masking, which may make things a bit clearer. To get A , B , etc. take the byte, mask the 4 highest bits ( & 0xF0) and shift it right 4 bits ( >>4 ). To get a , b , etc. mask the lowest 4 bits of the original byte: & 0x0F .

Button is a simple bit flag: bit 2 of b : 0100 , so it is 1 . (Bits count right to left and start at 0.)

Battery is also a simple bit flag: bit 3 of b , so it is 0 , which indicates "Low" .

Temperature is ((Cc<<8)|D)>>4 : 10<<8 = 1000 + 10 = 1010 >> 4 , or 101 in hex, 257 in decimal. This appears to be in tenths of degrees, hence the division by 10: 25.7 (all that extra manipulation is to display a negative value correctly).

Humidity is (d<<4) | E (d<<4) | E , or 20 | B = 2B 20 | B = 2B , which is 43 .

Channel is bits 0-1 of b ( 00 ) plus 1, which equals 1 .

Id is the value in A : 9 .

RID , finally, is (a<<4) | B (a<<4) | B : 60 | 4 = 64 60 | 4 = 64 , 100 in decimals. hrid is the same value but written in hex.

The temperature bytes are bb[1][2] and bb[1][3] = 00010000 and 00010010 .

The code appends these, and then shifts right by 4: 0001 0000 0001

Converting from binary to decimal, this is 257 (hex is 0x101 ).

The code divides by ten to get the temperature: 25.7.

The data is packed into the array. For example humidity is extracted from the 4 ls bits of bb[1][3] and the 4 ms bits of bb[1][4] .

fprintf(stderr, "humidity      = %d\n", ((bb[1][3]&0x0F)<<4)|(bb[1][4]>>4));

So if bb[1][3] = xxxx0010 and bb[1][4] = 1011xxxx, humidity = 00101011 = 43

Temperature is similar but more complicated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM