Friday, September 04, 2009

Bit packing/upacking



Our TCT require to store and read information on a smartcard, each transaction, officer and engineer identification will use a smartcard. For example to store and read transaction information the card management use a value block, it's a 32 bit unsigned integer, some informations will be packed into this integer, for example with this informations:

MSB                                       LSB
5 bit | 6 bit | 4 bit | 6 bit | 8 bit | 3 bit   (32 bit integer)
info1 | info2 | info3 | info4 | info5 | info6


Given the value for 0xa082abc8 or 2692918216 in decimal, to unpack the informations we simply do bit shift and masking:

info1 = value >> 27 & 0x1f;
info2 = value >> 21 & 0x3f;
info3 = value >> 17 & 0xf;
info4 = value >> 11 & 0x3f;
info5 = value >> 3 & 0xff;
info6 = value & 0x7;


and for packing from the informations:

((info1 & 0x1f) << 27) | ((info2 & 0x3f) << 21) | ((info3 & 0xf) << 17) | ((info4 & 0x3f) << 11) | ((info5 & 0xff) << 3) | (info6 & 0x7)

another way is to create bitfield, as follow:

union {
    struct {
        unsigned int info6 : 3;
        unsigned int info5 : 8;
        unsigned int info4 : 6;
        unsigned int info3 : 4;
        unsigned int info2 : 6;
        unsigned int info1 : 5;
    } bit;
    unsigned int val
} data;


The bitfield already packed, so we only need to assign a value to val member and access bitfield info member as informations. To assign a bitfield member, it's like we do in a generic C structure. But be carefull with bitfield, different machine maybe has different a byte-order convention. Intel CPU follow litle-endian and other CPU like Motorola use big-endian convention, the above bitfield was intended to be use in a litle-endian system, if you want more portable code use bit shifting and masking, for bitfield, use compiler preprocessor directive such as __LITTLE_ENDIAN in GCC.

http://en.wikipedia.org/wiki/Bit_field
http://en.wikipedia.org/wiki/Endianness