1

I am recieving data from a ublox GPS module in 24 bit long bitfields (3 bytes of a 4 byte message), and I need to convert these 24 bit data fields to signed decimal values, but I can't find the description of how to do this in the specification. Also I know certain values from another program that came with the module.

For positive values, it seems that it just simply converts the 24 bit binary number to dec and that's it, e.g. 0x000C19 = 3097 and 0x000BD0 = 3024 , but for negative numbers I'm in trouble. 2's complement doesn't seem to work. Here are some known values: 0xFFFFC8 = -57, 0xFCB9FE = -214528, 0xFF2C3B = -54215 and 0xFFFA48 = -1462. Using 2's complement, the conversion is a few numbers off every time ( -56, -214530, -54213, -1464, respectively). (Hex numbers are used to avoid having to write 24 digits every time.)

Thanks for your help in advance!

  • Are you sure the program that came with the hardware computes correct negative results? – John Bollinger Jul 06 '16 at 13:21
  • 1
    @MoralesBatovski, the question is not "why isn't this code working?", it is "what is this black box program doing?". – John Bollinger Jul 06 '16 at 13:24
  • 3
    the "know values" look very odd, where did you get them from? i doubt it's a conversion problem, sometimes they're less than 2-complent, sometimes higher – Tommylee2k Jul 06 '16 at 13:24
  • 2
    The correspondences you give are not jointly consistent with any single integer format in which the sign bit and each value bit has a consistent place value. I am therefore inclined to guess that the program performing the conversions is losing precision for some reason. – John Bollinger Jul 06 '16 at 13:43
  • what mode is the code setting the ubox to? Is the communication protocol set to the: NEMA. UBX, time pulse, just what? What baud rate is your software set to use? You really need to post your code, so we can have any realistic chance to answer your question. – user3629249 Jul 07 '16 at 02:10
  • Well my program is 3800 lines, so I don't want to post it. I'm not sure if the other program is giving the correct results, and yeah, I noticed that it is not consistent with any integer format as I have been trying to understand it for 2 days now. – prohi the magnificent Jul 07 '16 at 08:21
  • It is set to UBX protocol, and I'm polling ESF messages to get the gyro and accelero data, but it gives me the data in bitfield format for some reason I don't completely understand. – prohi the magnificent Jul 07 '16 at 08:30

3 Answers3

1

First things first the "known" values you have there are not what you think they are:

#include <stdio.h>

static void p24(int x)
{
    printf("%8d = 0x%06X\n", x, (0x00ffffff & (unsigned)x));
}

int main(int argc, char *argv[])
{
    p24(-57);
    p24(-214528);
    p24(-54215);
    p24(-1462);
    return 0;
}

Compiling and running on a 2s complement machine prints

     -57 = 0xFFFFC7
 -214528 = 0xFCBA00
  -54215 = 0xFF2C39
   -1462 = 0xFFFA4A

When converting to 2s complement you'll have of course to pad to the full length of the target datatype you're working with, so that the sign is properly carried over. Then you divide the signed data type down to the designed number of bits.

Ex:

#include <stdio.h>
#include <stdint.h>

/* 24 bits big endian */
static char const m57[]     = {0xFF, 0xFF, 0xC7};
static char const m214528[] = {0xFC, 0xBA, 0x00};
static char const m54215[]  = {0xFF, 0x2C, 0x39};
static char const m1462[]   = {0xFF, 0xFA, 0x4A};

static
int32_t i_from_24b(char const *b)
{
    return (int32_t)(
        (((uint32_t)b[0] << 24) & 0xFF000000)
      | (((uint32_t)b[1] << 16) & 0x00FF0000)
      | (((uint32_t)b[2] <<  8) & 0x0000FF00)
    ) / 256;
}

int main(int argc, char *argv[])
{
    printf("%d\n", i_from_24b(m57) );
    printf("%d\n", i_from_24b(m214528) );
    printf("%d\n", i_from_24b(m54215) );
    printf("%d\n", i_from_24b(m1462) );
    return 0;
}

Will print

-57
-214528
-54215
-1462
datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • 4
    But how does this answer OPs question? – Support Ukraine Jul 06 '16 at 13:48
  • @2501: Actually CHAR_BIT >= 8, because of the post-shift masks applied. Maybe let the function return a int32_t as well. – datenwolf Jul 06 '16 at 13:48
  • 1
    Division by 256 is well-defined, but the cast to `int32_t` has implementation-defined behavior if the value being converted is not representable as an `int32_t`. You are relying on a particular choice of that implementation-defined behavior. – John Bollinger Jul 06 '16 at 13:49
  • @datenwolf Hmm, I think you're right. – 2501 Jul 06 '16 at 13:50
  • @JohnBollinger: Yes, there's always some implementation defined behaviour involved if you want to avoid a conditional `if( (unsigned)x > 0x7fffff)` and the whole thing relies completely on the machine to be 2s complement and that being passed through by the compiler. – datenwolf Jul 06 '16 at 13:53
  • 1
    Also the data being converted by this program are not the data the OP presents. – John Bollinger Jul 06 '16 at 13:53
  • @JohnBollinger: Yes, OPs initial "known" values don't match up with 2s complement in the first place. Hence the whole first section converting the decimal representation of the assumed values to cross check. – datenwolf Jul 06 '16 at 13:54
  • if you are ok with implementation defined, then why not left shift 8 then right shift 8? – user3528438 Jul 06 '16 at 13:55
  • 1
    @datenwolf, the OP already acknowledges that the known values don't match up with 2s complement. That seems to be the whole point of the question. – John Bollinger Jul 06 '16 at 14:03
0

OP's information is inconsistent and likely @John Bollinger comment applies: " ... program performing the conversions is losing precision ..."

OP needs to review and post more information/code.

OP's        OP's    2's comp.   Diff
Hex         Dec     
0xFFFFC8    -57     -56        -1
0xFCB9FE    -214528 -214530     2
0xFF2C3B    -54215  -54213     -2
0xFFFA48    -1462   -1464       2

Due to complexity of this comment, posted as an answer

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

Thanks everyone for trying to help, but I just realised that I'm retarded and even more retarded! The program I got the "known values" from shows the scaled values of the measured data and it seems that +-1 +-2 deviation is in the range of the same 0.001 precision shown value after the conversion, so it indeed uses 2s complement.

Sorry for your lost time everyone! (SO is awesome tho)