DbcParser
DbcParser copied to clipboard
Unpack signal for CAN FD messages
If the dbc file contains CAN-FD messages that can be longer than 64 bit the unpack functions are not usable. Also i think most can implementations work by giving you a byte array for the received data anyway (peak, innodisk, esd to name a few).
Therefor i adjusted the unpack signals method like this:
/// <summary>
/// Get start bit Little Endian
/// </summary>
private static byte GetStartBitLE(Signal signal, int messageByteCount = 8)
{
var startByte = (byte)(signal.StartBit / 8);
return (byte)(8 * messageByteCount - (signal.Length + 8 * startByte + (8 * (startByte + 1) - (signal.StartBit + 1)) % 8));
}
And then adjust the code from before to
/// <summary>
/// Function to unpack a signal from a CAN data message
/// </summary>
/// <param name="receiveMessage">The message data</param>
/// <param name="signal">Signal containing dbc information</param>
/// <returns>Returns a double value representing the unpacked signal</returns>
private static double RxSignalUnpack(byte[] receiveMessage, Signal signal)
{
var bitMask = signal.BitMask();
var startBit = signal.StartBit;
if (!signal.Intel())
{
receiveMessage = receiveMessage.Reverse().ToArray();
startBit = GetStartBitLE(signal, receiveMessage.Length);
}
// Unpack signal
var receiveMessageBitArray = new BitArray(receiveMessage);
receiveMessageBitArray.RightShift(startBit);
receiveMessageBitArray.Length = 64; //Fill up to 64 if shorter or cut to length 64
receiveMessageBitArray.And(new BitArray(BitConverter.GetBytes(bitMask)));
var tempArray = new byte[8];
receiveMessageBitArray.CopyTo(tempArray, 0);
var iVal = BitConverter.ToInt64(tempArray, 0);
// Manage sign bit (if signed)
if (signal.ValueType == DbcValueType.Signed)
{
iVal -= ((iVal >> (signal.Length - 1)) != 0) ? (1L << signal.Length) : 0L;
}
else if (signal.ValueType == DbcValueType.IEEEFloat)
{
return (FloatConverter.AsFloatingPoint((int)iVal) * signal.Factor + signal.Offset);
}
else if (signal.ValueType == DbcValueType.IEEEDouble)
{
return (DoubleConverter.AsFloatingPoint(iVal) * signal.Factor + signal.Offset);
}
// Apply scaling
return ((double)(iVal * (decimal)signal.Factor + (decimal)signal.Offset));
}
this seems to work in a manual test. i tried to reuse most of the code. Probably is also not the fasted solution but should work.
~Problem with this is that the BitArray.ShiftRight() is not available in all targeted frameworks. For .net461 there is no solution for .netstandard2.0 you could upgrade the solution to .netstandard2.1.~