DbcParser icon indicating copy to clipboard operation
DbcParser copied to clipboard

Unpack signal for CAN FD messages

Open Uight opened this issue 6 months ago • 21 comments

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.~

Uight avatar Jul 26 '24 07:07 Uight