1

I receive a datapacket containing a byte array and I have to get some integer values from it. Here is a part of the documentation. Can someone help me please?

This comes in a 4-byte array.

Year from 1990 to 2052 (6 bit), Month from 1 to 12 (4 bit), Day from 1 to 31 (5 bit), Hour from 0 to 23 (5 bit), Minute from 0 to 59 (6 bit), Second from 0 to 59 (6 bit) Default value: 1 January 2000, 12:00:00

The format of the message is in little endian.

Tiago Farias
  • 3,397
  • 1
  • 27
  • 30
B. TIger
  • 459
  • 3
  • 10
  • 27
  • Does it include a table showing which bits represents which fields? Or is there any sample data showing the encoding of some date to some value? – Dancrumb Jul 10 '12 at 18:31
  • The layout is important. For example, is the 6 bit year in the 0th byte of the array? Are those 6 bits the most significant or least significant bits of the byte? – hatchet - done with SOverflow Jul 10 '12 at 18:33
  • I'm guessing that the default value is `0x2842C000`. Is that right? – Dancrumb Jul 10 '12 at 18:33
  • If you split your byte array into the right chunks for each field, you should be able to use the info in [this other question](http://stackoverflow.com/questions/5399798/byte-array-and-int-conversion-in-java) to solve your problem. – Windle Jul 10 '12 at 18:37
  • @Dancrumb: I make it `0x1842C000`. – MRAB Jul 10 '12 at 18:42
  • @MRAB: I get: `[10, 1, 1, 12, 0, 0]`, which is `[0b001010, 0b0001, 0b00001, 0b01100, 0b000000, 0b000000]`, which is `0b00101000010000101100000000000000` or `0x2842C000` – Dancrumb Jul 10 '12 at 18:48
  • @Dancrumb: I see where I went wrong. :-( – MRAB Jul 10 '12 at 18:55

3 Answers3

3

What you need is some bitwise operations. First, construct an int out of the bytes:

int n = b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);

Then, chop up the int into components. Now, your question does not specify which way do the fields go, right-to-left or left-to-right. That question is related to endianness, but not identical. So let's assume that the fields go from left to right.

Good sense suggests left-to-right. This way the integer representations of time values can be compared - the significance of year bits is more than month bits etc, so when you compare integers that correspond to two moments in time, you get a chronologically correct result.

Here's a mental image for you. This is an integer variable, composed of bits:

f e d c b a 9 8 7 6 5 4 3 2 1 0
            -----
              offset is 6, length is 3

Let's define a function that takes a arbitrary chunk from an int at a given offset (in bits), with a given length (in bits).

int bits(int n, int offset, int length)
{
    //shift the bits rightward, so that the desired chunk is at the right end
    n = n >> (31 - offset - length); 

    //prepare a mask where only the rightmost `length`  bits are 1's
    int mask = ~(-1 << length);

    //zero out all bits but the right chunk
    return n & mask;
}

Could've been a one-liner, but I wanted to make it somewhat instructive. Folks in the answers below effectively inline this function, by specifying the shift factor and the mask by hand for each chunk.

Now let's decompose. Assuming n comes from the topmost snippet:

int year  = bits(n, 0,  6),
    month = bits(n, 6,  4),
    day   = bits(n, 10, 5),
    hour  = bits(n, 15, 5),
    min   = bits(n, 20, 6),
    sec   = bits(n, 26, 6);

We get the values of the offset by combining the total lengths of the previous fields together. This is under the assumption that the fields go left to right; if they go the other way around, the offset values would be different.

Did that make sense?

EDIT: if the bit chunks go right to leftt, then here's how it'd go:

int sec   = bits(n, 0,  6),
    min   = bits(n, 6,  6),
    hour  = bits(n, 12, 5),
    day   = bits(n, 17, 5),
    month = bits(n, 22, 4),
    year  = bits(n, 26, 6);
Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • yes it made sense i tryed it here with the chunk of data that i recieved but the values dont seem to add up how should i treat the off set if their order is diferent? – B. TIger Jul 13 '12 at 19:26
  • I'm not sure that the algorithm is correct (or I'm using it wrong). If n = 421, offset = 2, and length = 4, the result is 0. Since we are dealing with java, the highest-order bit is on the far left; so `421 = 0b110100101`. I expect the result `0b1001` when specifying the offset of 2 and length of 4. I am using `n >> offset` for the correct result. (Your mask is good) – Nicholas Miller Mar 30 '14 at 20:30
  • 1
    It's offset from the left, not from the right. Offset 2 gives you bits 25-29. – Seva Alekseyev Mar 30 '14 at 20:47
  • Awesome thanks! I'll use my code since I'm grabbing from the right side. – Nicholas Miller Mar 30 '14 at 21:03
  • For grabbing from right side, the shift line would go: `n = n << offset;` assuming the offset means - the number of bits to be shifted out. The general idea still holds though. Shift the wanted bits into the rightmost position, mask away the rest. – Seva Alekseyev Mar 31 '14 at 02:43
2

First, I'd convert this to an integer:

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

int timestamp = ByteBuffer.wrap(byte_array).order(ByteOrder.LITTLE_ENDIAN).getInt();

Next, I'd take it apart:

int yearCode  = (timestamp >> 26) & 0b111111;
int monthCode = (timestamp >> 22) & 0b1111;
int dayCode   = (timestamp >> 17) & 0b11111;
int hourCode  = (timestamp >> 12) & 0b11111;
int minCode   = (timestamp >> 6)  & 0b111111;
int secCode   = (timestamp >> 0)  & 0b111111;

The masking in the first line and shifting in the last line are not strictly necessary, but are left in for clarity.

The final step is to add 1900 to the yearCode and you're done!

Dancrumb
  • 26,597
  • 10
  • 74
  • 130
0

Assuming you have java 7, you should be able to read the year as

    int year = 1990
    + ((b[0] & 0b1000_0000) << 5)
    + ((b[0] & 0b0100_0000) << 4)
    + ((b[0] & 0b0010_0000) << 3)
    + ((b[0] & 0b0001_0000) << 2)
    + ((b[0] & 0b0000_1000) << 1)
    + ((b[0] & 0b0000_0100));

and the month as

    int month = 1 
    + ((b[0] & 0b1000_0010) << 3)
    + ((b[0] & 0b0100_0001) << 2)
    + ((b[1] & 0b1000_0000) << 1)
    + ((b[1] & 0b0100_0000));

I let you do the others ints in the same way.

I don't have java7 and can't test now, I hope I'm not wrong. It's also possible that the order of the bytes is the reverse one.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758