Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse bits in a byte to enum

Tags:

c#

enums

binary

I'm working on a dll that parses binary data I get from a Home Automation module.

But I need some advice on some code I have.
So I get a message with some bytes, and each bit indicates a certain condition in this case.

enter image description here

In the code I have at the moment each condition is an enum, I put the enums in an array and check if the corresponding bit is set.

private void ParseZoneConditionFlag1(int Flag1)  // Flag1 = Hex represenation of byte
{
    Zone_Status_ZoneConditionFlagEnum[] FlagArray = new Zone_Status_ZoneConditionFlagEnum[8];
    FlagArray[0] = Zone_Status_ZoneConditionFlagEnum.Faulted;
    FlagArray[1] = Zone_Status_ZoneConditionFlagEnum.Tampered;
    FlagArray[2] = Zone_Status_ZoneConditionFlagEnum.Trouble;
    FlagArray[3] = Zone_Status_ZoneConditionFlagEnum.Bypassed;
    FlagArray[4] = Zone_Status_ZoneConditionFlagEnum.Inhibited;
    FlagArray[5] = Zone_Status_ZoneConditionFlagEnum.Low_Battery;
    FlagArray[6] = Zone_Status_ZoneConditionFlagEnum.Loss_Supervision;
    FlagArray[7] = Zone_Status_ZoneConditionFlagEnum.Reserved;

    base.CheckBitsSet(FlagArray, Flag1, ZoneConditionFlags_List);
 }

 private void ParseZoneConditionFlag2(int Flag2)
 {
    Zone_Status_ZoneConditionFlagEnum[] FlagArray = new Zone_Status_ZoneConditionFlagEnum[8];
    FlagArray[0] = Zone_Status_ZoneConditionFlagEnum.Alarm_Memory;
    FlagArray[1] = Zone_Status_ZoneConditionFlagEnum.Bypass_Memory;
    FlagArray[2] = Zone_Status_ZoneConditionFlagEnum.Reserved;
    FlagArray[3] = Zone_Status_ZoneConditionFlagEnum.Reserved;
    FlagArray[4] = Zone_Status_ZoneConditionFlagEnum.Reserved;
    FlagArray[5] = Zone_Status_ZoneConditionFlagEnum.Reserved;
    FlagArray[6] = Zone_Status_ZoneConditionFlagEnum.Reserved;
    FlagArray[7] = Zone_Status_ZoneConditionFlagEnum.Reserved;

    base.CheckBitsSet(FlagArray, Flag2, ZoneConditionFlags_List);
 }

And the method were I check the actual bits

 protected void CheckBitsSet<T>(T[] ConstantArray, int HexValue, List<T> DestinationList)
 {
     byte b = (byte) HexValue;

     for (int i = 0; i < Mask.Length; i++)
     {
        if(IsBitSet(b, i))
        {
           DestinationList.Add(ConstantArray[i]);
        }
     }
 }

 public bool IsBitSet(byte b, int pos)
 {
    return (b & (1 << pos)) != 0;
 }

This works, but I wonder if there is a cleaner way to do this.
With cleaner I mean without having to add the right enums to an array each time.

like image 283
Robby Smet Avatar asked Jun 20 '13 08:06

Robby Smet


2 Answers

How about just:

[Flags]
enum MyFlags : short
{
    None = 0,
    Faulted = 1 << 0,
    Tampered = 1 << 1,
    Trouble = 1 << 2,
    Bypassed = 1 << 3,
    Inhibited = 1 << 4,
    LowBattery = 1 << 5,
    LossOfSupervision = 1 << 6,
    AlarmMemory = 1 << 8,
    BypassMemory = 1 << 9
}
static bool IsSet(MyFlags value, MyFlags flag)
{
    return ((value & flag) == flag);
}

and read the value as a 2-byte value (short, being careful about endianness), and then cast to MyFlags.

To check for any flag, just:

MyFlags value = ...
bool isAlarmMemory = IsSet(value, MyFlags.AlarmMemory);

It gets tricker when you talk about composite flags, i.e.

bool memoryProblem = IsSet(value, MyFlags.AlarmMemory | MyFlags.BypassMemory);

as you need to figure out whether you mean "is any of these flags set?" vs "are all of these flags set?"

It comes down to the test;

return ((value & flag) == flag); // means "are all set"
return ((value & flag) != 0); // means "is any set"

For reading:

// this is just some garbage that I'm pretending is a message from
// your module; I'm assuming the byte numbers in the image are
// zero-based, so the two that we want are: \/\/\/ (the 6,3)
byte[] data = { 12, 63, 113, 0, 13, 123, 14, 6, 3, 14, 15 };

// and I'm assuming "byte 7" and "byte 8" (image) are zero-based;
// MyFlags uses byte 7 *first*, so it is little-endian; we can get that
// via:
short flagsRaw = (short)(data[7] | (data[8] << 8));
MyFlags flags = (MyFlags)flagsRaw;
// flags has value Tampered | Trouble | AlarmMemory | BypassMemory,
// which is what we expect for {6,3}
like image 171
Marc Gravell Avatar answered Nov 10 '22 11:11

Marc Gravell


Use this:

[Flags]
public enum MyEnum
{
    Value1 = 1,
    Value2 = 2,
    Value3 = 4,
    Value5 = 8
}

(...)

void Func(int flag)
{
    MyEnum @enum = (MyEnum)flag;

    // Testing, whether a flag is set

    if ((@enum & MyEnum.Value1) != 0) // sth
}
like image 44
Spook Avatar answered Nov 10 '22 12:11

Spook