EverActive
EverActive

Reputation: 15

How to do mass Bit shift calculation in C#

I have 2 eight Byte of Data, received as the RX CAN message, so in total 128 bit, but not all the bit carries message. Each byte gives boolean value in specified bit like in the picture. enter image description here NOTE: This is the structure of first 8 byte, and bit Var Names are not as clean as in the picture.

At the moment I receive 85 bit of message excluding the Reserved bit. Reserved are for the future usage if a message is need to be added.

I have to check the boolean value of the specified bit, and store the boolean value in an Array. I am having difficulty in checking each of 85 bit and storing them in array, is there any more efficient way like using a function to check the bool status, and store the value in array using iteration? or any other,

Upvotes: 0

Views: 385

Answers (3)

Drunken Code Monkey
Drunken Code Monkey

Reputation: 1836

You could just create a class to store your 8 bytes, and create read only properties to get the different flags, through left shift and bitwise AND. Each flag can return something like this (for example, this is W1_A, bit 0 of first byte):

return (bytes[0] & (1 << 0)) != 0;

So something like this:

public class CanMessage
{
    private byte[] _bytes = new byte[8];
    
    public CanMessage(byte[] bytes)
    {
        if (bytes == null || bytes.Length != 8)
        {
            throw new ArgumentException(nameof(bytes));
        }
        
        _bytes = bytes;
    }
    
    public bool W1_A => (_bytes[0] & (1 << 0)) != 0;
    // ...
}

Which you can then use like this:

var msg = new CanMessage(new byte[] { 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA });
var w1a = msg.W1_A;

Upvotes: 3

Flydog57
Flydog57

Reputation: 7111

This is what I'm talking about. It's a struct, so it should be immutable. If you need mutability, you probably want a class, but with a way to work with a [StructLayout(LayoutKind.Sequential)] struct to do interop with your CAN driver (and initialize instances of your class.

I'm doing this with two uints because you only show 64 bits, not 128. To access 128 bits, I'd use two ulongs and adjust my magic numbers.

Here's the basic struct. We'll be adding members to this:

[StructLayout(LayoutKind.Sequential)]
public struct CanBuffer
{
    private uint First;
    private uint Second;
}

We need a way to read a bit from that struct. I'm using two bytes here to index into the struct. The first one will tell you which byte you are interested in, the second which bit. So, to get the value of W3_C, it would be whichByte == 2, bitNum == 3:

private bool ReadBit(byte whichByte, byte bitNum)
{
    uint whichItem = whichByte switch
    {
        (>= 0 and <= 3) => First,
        (>= 4 and <= 8) => Second,
        _ => throw new ArgumentOutOfRangeException(nameof(whichByte), "WhichByte is out of range")
    };
    if (bitNum > 31)
    {
        throw new ArgumentOutOfRangeException(nameof(bitNum), "BitNum is out of range");
    }

    var shiftBy = whichByte * 8 + bitNum;
    return ((whichItem & (1 << shiftBy)) != 0);
}

With that in place, I can write a ton of properties that look like this:

public bool W1A => ReadBit(0, 0);
//skip a bunch
public bool W3D => ReadBit(2, 4);
//etc.

Now what I need is a way to map an array index to a (byte whichByte, byte bitNum) tuple that I can use with ReadBit:

private static Dictionary<int, (byte whichByte, byte bitNum)> addresses = new()
{
    {1, (0, 0) },
    {2, (0, 1) },
    {3, (0, 3) },       //notice that (0, 2) is skipped
    {4, (0, 5) },
    {5, (1, 0) },
    {6, (1, 1) },
    //and so on
};

Note that the syntax (byte whichByte, byte bitNum) indicates a two-byte tuple.

With that in place, writing an indexer is easy:

public bool this[int index]
{
    get
    {
        if (index < 0 || index > 84)
        {
            throw new IndexOutOfRangeException("Index is out of range");
        }
        var (whichByte, bitNum) = addresses[index];
        return ReadBit(whichByte, bitNum);
    }
}

With that all in place, you can populated a CanBuffer from a call to your CAN driver (treating it as a 64 or 128 bit buffer).

CanBuffer myBuffer;
InteropCallToCanDriverToPopulateBuffer(myBuffer);  // this is up to you

Then to get the bit corresponding to W3_B (which, skipping the holes, is index 10), you'd do something like this:

bool w3_B = myBuffer[10];

Note that you are not creating an array, copying into an array, or doing anything else with an array. What you are doing is pretending to be an array by implementing an int-based indexer.

Also note, I haven't really tested this code (testing would be a lot of work - I figure you can figure it out)

Upvotes: 0

Kirill Polishchuk
Kirill Polishchuk

Reputation: 56212

Have a look at BitArray, I think it does exactly what you need.

BitArray bitArray = new(inputBytes);
bool set = bitArray.Get(bitIndex);

Upvotes: 1

Related Questions