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.

7
  • 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? Commented Jul 10, 2012 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? Commented Jul 10, 2012 at 18:33
  • I'm guessing that the default value is 0x2842C000. Is that right? Commented Jul 10, 2012 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 to solve your problem. Commented Jul 10, 2012 at 18:37
  • @Dancrumb: I make it 0x1842C000. Commented Jul 10, 2012 at 18:42

3 Answers 3

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);
Sign up to request clarification or add additional context in comments.

5 Comments

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?
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)
It's offset from the left, not from the right. Offset 2 gives you bits 25-29.
Awesome thanks! I'll use my code since I'm grabbing from the right side.
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.
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!

Comments

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.

2 Comments

You'd pull the values out bit-by-bit like that? Not in one chunk?
Yes this can be optimized. But I like to do it the clear way, at least until the tests have proved the decoding is correct.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.