0

I had to write a c++ code for the following packet header:

Original image link, PNG version of the above JPEG.

Here is the struct code I wrote for the above Packet Format. I want to know if the uint8_t or the uint16_t bit fields are correct

    struct TelemetryTransferFramePrimaryHeader
    {
        //-- 6 Ocets Long --//

        //-- Master Channel ID (2 octets)--//
        uint16_t TransferFrameVersionNumber : 2;
        uint16_t SpacecraftID : 10;
        uint16_t VirtualChannelID : 3;
        uint16_t OCFFlag : 1;

        //-----------------//

        uint8_t MasterChannelFrameCount;
        uint8_t VirtualChannelFrameCount;

        //-- Transfer Frame Data Field Status (2 octets) --//

        uint16_t TransferFrameSecondaryHeaderFlag : 1;
        uint16_t SyncFlag : 1;
        uint16_t PacketOrderFlag : 1;
        uint16_t SegmentLengthID : 2;
        uint16_t FirstHeaderPointer : 11;

        //-----------------//

    };

How do I ensure that that the LSB -> MSB is preserved in the struct ?

I keep getting confused, and I've tried reading up but it ends up confusing me even more.

PS: I am using a 32bit processor.

unwind
  • 391,730
  • 64
  • 469
  • 606
rkrishnasanka
  • 166
  • 1
  • 9
  • I would store the data in the struct as normal ints. And create pack/unpack functions to convert the struct to a stream of bits when required. – Neil Kirk Jul 11 '14 at 12:54

3 Answers3

5

Exactly how bits are mapped when using bit fields is implementation-specific. So it's very hard to say for sure if you did it right, we'd need to know the exact CPU and compiler (and compiler version, of course).

In short; don't do this. Bit fields are not very usable for things like this.

Do it manually instead, by declaring the words as needed and setting the bits inside them.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • Would agree. You can use inline member functions to abstract away the grotesque masks & shifts. – Pete Jul 11 '14 at 12:55
  • And also be aware of processor endian-ness. – Pete Jul 11 '14 at 12:56
  • The bitfields will end up making masks and shifts anyway, so you dont lose anything by doing it manually, what you gain though is that it 1) works and 2) ports/continues to work. – old_timer Jul 14 '14 at 00:03
2

IMHO anyone trying to construct a struct in this way is in a state of sin.

The C99 Standard, for example, says:

An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.

Even if you could predict that your compiler would construct bit-fields in units of (say) uint32_t, and the fields were arranged first field LS bits... you still have endian-ness to deal with !

So... as unwind says... do it by hand !

1

I agree that you should not do this. However STMicroelectronics uses bitfields to access the bits of its Cortex-M3/M4 microcontroller registers. So any compiler vendor that wants its users to be able to use the STMicroelectronics Cortex-M3/M4 libraries needs to support the allocation of bitfields starting at the least significant bit. In my compiler this is the default, but it is also optional so I could reverse it if I wanted to.

user3717478
  • 863
  • 1
  • 8
  • 15