6

For a specified communication standard RTCM SC104 3.1, I need to split data across bytes as a pair of 12 bit data segments. So for a given message I need to place the message type number on the first byte and half of the second byte. Then I need to start an ID integer on the half of second byte and continue to the third byte. This sort of pattern continues to the end of the message shaving down other integers in 20bit, 5bit, and other sizes essentially cutting of the 0's that would normally fill out the MSB end of the integer values.

I have not seen a clear definition but I assume it must go out in network byte order so before copying bits I would have to reverse my integers in memory. I am still quite new to cpp and am wondering how do I get to the individual bytes making up an integer in memory? If I can access the bytes then I could use bitwise or to split the bits from 2 bytes onto one for the message.

Here's the start of building a message before adding the data:

//build message 1002  gps 00111110 1010
    char buf1002[BUFFERSIZE];
    buf1002[0] = 0x3E; //00111110
    buf1002[1] = 0xA0; //10100000
//ref station id 12 bits of 16
//ex unsigned short m = 1100;
//m would be byte2 00000100 byte1 01001100
//buf1002[1] would be 10100100
//buf1002[2] would be 01001100
//reverse bit order for network after building? 

The reference station will be from an unsigned short, so a 2 byte integer. So how do I go about reading a single byte from it? Do I start with a memory location pointer? If so then what?

Any help would be greatly appreciated.

i_am_jorf
  • 53,608
  • 15
  • 131
  • 222
J Hinton
  • 147
  • 3
  • 13
  • Read the first answer here http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c – Tim Feb 22 '13 at 23:58
  • 4
    *"The reference station will be from an unsigned short, so a 2 byte integer."* A short isn't required to be two bytes (though that is by far the most common case), it is required to be at *least* 16 bits. You could use `uint16_t` to force the matter. – dmckee --- ex-moderator kitten Feb 22 '13 at 23:59

4 Answers4

4

You can use bit fields, like this - some caveats at the end:

typedef union packet {
    struct {
        unsigned int msgno  : 12; // creates a 12 bit wide integral field
        unsigned int msgtype  : 12;
        unsigned int somefield2  : 3;
        unsigned int somefield3  : 5;
    } fields;

    unsigned char asbytes[4];
} packet;

...

packet p;
// fill it, by using the field side of the union
p.fields.msgno = 16;
p.fields.msgtype = 12;
p.fields.somefield2 = 6;
// and retrieving them as regular bytes
unsigned char abyte = p.asbytes[0];
abyte = p.asbytes[1];
// and so on

For me the main advantage is readability: all operations behave like regular operations on albeit narrower integral type variables. There are limitations (eg portability) but if you don't have to target multiple architectures or compilers or different endians it can help make your program a lot easier to read.

fvu
  • 32,488
  • 6
  • 61
  • 79
  • I like your idea. Its a whole different approach to building the entire message in an array that I could send out the socket. It took me a while to figure out just what it was doing. – J Hinton Feb 23 '13 at 05:37
2

If you have your integer looking like 00001000 00000000 11000000 00110000 for example (i'm making spaces to difference each single bytes), contained in example in an int a:

int     a;
int     single_byte;

a = the_number;

You could do a function like

int     get_byte_in_integer(int byte_number, int integer);

So that:

single_byte = get_byte_in_integer(1, a); // That would give you the 11000000 byte

with

int    get_byte_in_integer(int byte_number, int integer)
{
      return (integer >> (byte_number << 3)) & 0xff);
}

Hope this helps, for the byte part.

SeedmanJ
  • 444
  • 2
  • 8
0

You can resort to punning it as bytes, for example:

const unsigned short s(1);
const char* const bytes(reinterpret_cast<const char*>(&s));

const char NaturalOrder[sizeof(s)] = {bytes[0],bytes[1]};
const char EndianFlipped[sizeof(s)] = {bytes[1],bytes[0]};

(But also see dmckee's comment regarding the natural size of builtins, and consider using fixed width types).

justin
  • 104,054
  • 14
  • 179
  • 226
0

Please check the getbitu function as implemented in libswiftnav repo (link reproduced below). Idea is to extract values packed across multiple bytes by extracting from the ms bit end and then moving towards the least significant bit end. The input which it needs is the buffer which holds the packed value(s), the byte offset of the value (relative to the start of the buffer) and the number of value's bits to extract. The functions can easily be templated to support returning packed integers other than uint32... Add some state to hold the current offset (which gets incremented across subsequent calls to getbitu) and you can easily unpack all data fields in a packed message by repeatedly issuing getbitu() as per a particular RTCM message schema. Portable, renders the value extraction code very readable and parsing a new message can be done in no time.

https://github.com/swift-nav/libswiftnav/blob/master/src/bits.c

Neelabh Mam
  • 300
  • 6
  • 10