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 uint
s because you only show 64 bits, not 128. To access 128 bits, I'd use two ulong
s 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 byte
s 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)