0

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,

EverActive
  • 15
  • 4
  • 1
    If you use a 4 `int` (or 2 `long`) `struct` with `[StructLayout(LayoutKind.Sequential)]`, then you'll have a 128-bit value type. Then you can create properties (read-only or read-write) that access the bits you need, in the format your consumers want. It will provide nice isolation and encapsulation – Flydog57 Sep 02 '22 at 03:01
  • Take a look at my answer to https://stackoverflow.com/questions/55499116/c-sharp-extract-bit-ranges-from-byte-array/55505757#55505757 – Flydog57 Sep 02 '22 at 03:06
  • 1
    Can you explain what you mean by your last paragraph in greater detail? It seems like you get the data as a 128 struct-ish thing, and you want to pull the green-highlighted data into an 85 bit array? What's the point of the array? By the way, if you do this as a `struct`, you could implement an _indexer_ (indexing on an int) that, combined with a dictionary, could make your struct act like a bool array (without actually having a bool array). If you explain more, I could probably give you some example code – Flydog57 Sep 02 '22 at 21:29
  • what do you mean by "mass bitshift"? If you read the packet as a whole then there's zero bitshift, unless you want to pack only 85 bits into an 11-byte struct – phuclv Sep 03 '22 at 01:40

3 Answers3

3

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;
Drunken Code Monkey
  • 1,796
  • 1
  • 14
  • 18
  • 1
    Going with `public bool W1_A => (_bytes[0] & (1 << 0)) != 0;` makes it look a little friendlier. – Enigmativity Sep 02 '22 at 03:28
  • If you do this with a `[StructLayout(LayoutKind.Sequential)]` struct, and either a bunch of named `byte`s, four named `uint`s or two named `long`s (it won't work with arrays), they you have a 128 bit structure that you can treat just like a native 128 bit C-style `struct`. It should make interop with your CAN driver much easier. – Flydog57 Sep 02 '22 at 21:25
1

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

BitArray bitArray = new(inputBytes);
bool set = bitArray.Get(bitIndex);
Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
0

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)

Flydog57
  • 6,851
  • 2
  • 17
  • 18