Search code examples
c#bit-fields

How to emulate statically the C bitfields in c#?


I have to define a communication protocol and I want to use a bitfield to store some logic values.

I'm working on the both systems: the sender: a device and a .Net software as receiver.

On the firmware side, I defined as usually a bitfield struct like:

struct __attribute__((__packed__)) BitsField 
{
  // Logic values
  uint8_t vesselPresenceSw: 1;
  uint8_t drawerPresenceSw: 1;
  uint8_t pumpState: 1;
  uint8_t waterValveState: 1;
  uint8_t steamValveState: 1;
  uint8_t motorDriverState: 1;
    // Unused
  uint8_t unused_0: 1;
  uint8_t unused_1: 1;
};

How I can define a same structure on the software side that support a bytes deserialization to build the struct itself?


Solution

  • In the meantime, I had a similar idea @Dmitry. I found the following solution using FieldOffset attribute. Working well without additional code. I think it's acceptable.

    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct LiveDataBitField
    {
        // Where the values are effectively stored
        public byte WholeField { get; private set; }
    
        public bool VesselPresenceSw
        {
            get => (WholeField & 0x1) > 0;
            set
            {
                if (value)
                {
                    WholeField |= 1;
                }
                else
                {
                    WholeField &= 0xfE;
                }
            }
        }
    
        public bool DrawerPresenceSw
        {
            get => (WholeField & 0x2) >> 1 > 0;
            set
            {
                if (value)
                {
                    WholeField |= (1 << 1);
                }
                else
                {
                    WholeField &= 0xFD;
                }
            }
        }
        public bool PumpState
        {
            get => (WholeField & 0x4) >> 2 > 0;
            set
            {
                if (value)
                {
                    WholeField |= (1 << 2);
                }
                else
                {
                    WholeField &= 0xFB;
                }
            }
        }
        public bool WaterValveState
        {
            get => (WholeField & 0x8) >> 3 > 0;
            set
            {
                if (value)
                {
                    WholeField |= (1 << 3);
                }
                else
                {
                    WholeField &= 0xF7;
                }
            }
        }
        public bool SteamValveState
        {
            get => (WholeField & 0x10) >> 4 > 0;
            set
            {
                if (value)
                {
                    WholeField |= (1 << 4);
                }
                else
                {
                    WholeField &= 0xEF;
                }
            }
        }
        public bool MotorDriverState
        {
            get => (WholeField & 0x20) >> 5 > 0;
            set
            {
                if (value)
                {
                    WholeField |= (1 << 5);
                }
                else
                {
                    WholeField &= 0xDF;
                }
            }
        }
    }
    

    To deserialize a byte array to struct you can use:

        public static object ReadStruct(byte[] data, Type type)
        {
            var pinnedPacket = GCHandle.Alloc(data, GCHandleType.Pinned);
            var obj = Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), type); 
            pinnedPacket.Free();
            return obj;
        }