From d917d87aa4ed03c48ad69d05b14c8df783440946 Mon Sep 17 00:00:00 2001 From: Uight Date: Fri, 26 Jul 2024 21:52:53 +0200 Subject: [PATCH 01/14] First version of a fast Unpack function based on using byte array --- DbcParserLib/Packer.cs | 95 +++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 19 deletions(-) diff --git a/DbcParserLib/Packer.cs b/DbcParserLib/Packer.cs index bf79391..ec20812 100644 --- a/DbcParserLib/Packer.cs +++ b/DbcParserLib/Packer.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.InteropServices; using DbcParserLib.Model; +using System.Linq; namespace DbcParserLib { @@ -85,22 +86,7 @@ public static double RxSignalUnpack(uint64_T RxMsg64, Signal signal) else // Big endian (Motorola) iVal = (int64_T)((MirrorMsg(RxMsg64) >> GetStartBitLE(signal)) & bitMask); - // 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)); + return ApplySignAndScale(signal, iVal); } /// @@ -120,10 +106,56 @@ public static uint64_T RxStateUnpack(uint64_T RxMsg64, Signal signal) else // Big endian (Motorola) iVal = (MirrorMsg(RxMsg64) >> GetStartBitLE(signal)) & bitMask; - // Apply scaling return iVal; } + /// + /// Function to unpack a signal from a CAN data message + /// + /// The message data + /// Signal containing dbc information + /// Returns a double value representing the unpacked signal + public 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); + } + + var iVal = ExtractBits(receiveMessage, startBit, signal.Length); + + return ApplySignAndScale(signal, iVal); + } + + public static double ApplyLimit(double value, Signal signal) + { + return Math.Max(signal.Minimum, Math.Min(value, signal.Maximum)); + } + + private static double ApplySignAndScale(Signal signal, long iVal) + { + // 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)); + } + private static int64_T CLAMP(int64_T x, int64_T low, int64_T high) { return Math.Max(low, Math.Min(x, high)); @@ -163,10 +195,35 @@ private static uint64_T MirrorMsg(uint64_T msg) /// /// Get start bit Little Endian /// - private static uint8_T GetStartBitLE(Signal signal) + private static uint8_T GetStartBitLE(Signal signal, int messageByteCount = 8) { uint8_T startByte = (uint8_T)(signal.StartBit / 8); - return (uint8_T)(64 - (signal.Length + 8 * startByte + (8 * (startByte + 1) - (signal.StartBit + 1)) % 8)); + return (uint8_T)(8 * messageByteCount - (signal.Length + 8 * startByte + (8 * (startByte + 1) - (signal.StartBit + 1)) % 8)); + } + + private static long ExtractBits(byte[] data, int startBit, int length) + { + long result = 0; + int bitIndex = 0; + + for (int bitPos = startBit; bitPos < startBit + length; bitPos++) + { + int bytePos = bitPos / 8; + int bitInByte = bitPos % 8; + + if (bytePos >= data.Length) + break; + + bool bit = (data[bytePos] & (1 << bitInByte)) != 0; + if (bit) + { + result |= 1L << bitIndex; + } + + bitIndex++; + } + + return result; } } From d85870de0a574013dbc019766d2fcd7e67c4e462 Mon Sep 17 00:00:00 2001 From: Uight Date: Sat, 27 Jul 2024 19:57:12 +0200 Subject: [PATCH 02/14] Do all unpacking based on ulong --- DbcParserLib/Packer.cs | 52 ++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/DbcParserLib/Packer.cs b/DbcParserLib/Packer.cs index ec20812..c3c574e 100644 --- a/DbcParserLib/Packer.cs +++ b/DbcParserLib/Packer.cs @@ -77,14 +77,14 @@ public static uint64_T TxStatePack(uint64_T value, Signal signal) /// Returns a double value representing the unpacked signal public static double RxSignalUnpack(uint64_T RxMsg64, Signal signal) { - int64_T iVal; + uint64_T iVal; uint64_T bitMask = signal.BitMask(); // Unpack signal if (signal.Intel()) // Little endian (Intel) - iVal = (int64_T)((RxMsg64 >> signal.StartBit) & bitMask); + iVal = ((RxMsg64 >> signal.StartBit) & bitMask); else // Big endian (Motorola) - iVal = (int64_T)((MirrorMsg(RxMsg64) >> GetStartBitLE(signal)) & bitMask); + iVal = ((MirrorMsg(RxMsg64) >> GetStartBitLE(signal)) & bitMask); return ApplySignAndScale(signal, iVal); } @@ -136,24 +136,32 @@ public static double ApplyLimit(double value, Signal signal) return Math.Max(signal.Minimum, Math.Min(value, signal.Maximum)); } - private static double ApplySignAndScale(Signal signal, long iVal) + private static double ApplySignAndScale(Signal signal, ulong value) { - // 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) + switch (signal.ValueType) { - 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)); + case DbcValueType.Signed: + int64_T signedValue; + if (signal.Length == 64) + { + signedValue = unchecked((long)value); + } + else + { + signedValue = Convert.ToInt64(value); + if ((value >> (signal.Length - 1)) != 0) + { + signedValue -= (1L << signal.Length); + } + } + return (double)(signedValue * (decimal)signal.Factor + (decimal)signal.Offset); + case DbcValueType.IEEEFloat: + return FloatConverter.AsFloatingPoint((int)value) * signal.Factor + signal.Offset; + case DbcValueType.IEEEDouble: + return DoubleConverter.AsFloatingPoint(unchecked((long)value)) * signal.Factor + signal.Offset; + default: + return (double)(value * (decimal)signal.Factor + (decimal)signal.Offset); + } } private static int64_T CLAMP(int64_T x, int64_T low, int64_T high) @@ -201,9 +209,9 @@ private static uint8_T GetStartBitLE(Signal signal, int messageByteCount = 8) return (uint8_T)(8 * messageByteCount - (signal.Length + 8 * startByte + (8 * (startByte + 1) - (signal.StartBit + 1)) % 8)); } - private static long ExtractBits(byte[] data, int startBit, int length) + private static ulong ExtractBits(byte[] data, int startBit, int length) { - long result = 0; + ulong result = 0; int bitIndex = 0; for (int bitPos = startBit; bitPos < startBit + length; bitPos++) @@ -217,7 +225,7 @@ private static long ExtractBits(byte[] data, int startBit, int length) bool bit = (data[bytePos] & (1 << bitInByte)) != 0; if (bit) { - result |= 1L << bitIndex; + result |= 1UL << bitIndex; } bitIndex++; From 53befe77aa721324a827ccc838ca5f8c89a71dff Mon Sep 17 00:00:00 2001 From: Uight Date: Sun, 28 Jul 2024 14:27:32 +0200 Subject: [PATCH 03/14] Improve Speed of array copy and reverse --- DbcParserLib/Packer.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/DbcParserLib/Packer.cs b/DbcParserLib/Packer.cs index c3c574e..022164c 100644 --- a/DbcParserLib/Packer.cs +++ b/DbcParserLib/Packer.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.InteropServices; using DbcParserLib.Model; -using System.Linq; namespace DbcParserLib { @@ -117,16 +116,20 @@ public static uint64_T RxStateUnpack(uint64_T RxMsg64, Signal signal) /// Returns a double value representing the unpacked signal public static double RxSignalUnpack(byte[] receiveMessage, Signal signal) { - var bitMask = signal.BitMask(); var startBit = signal.StartBit; + var message = receiveMessage; if (!signal.Intel()) { - receiveMessage = receiveMessage.Reverse().ToArray(); - startBit = GetStartBitLE(signal, receiveMessage.Length); + var copyArray = new byte[message.Length]; + Array.Copy(message, copyArray, message.Length); + Array.Reverse(copyArray); + + message = copyArray; + startBit = GetStartBitLE(signal, message.Length); } - var iVal = ExtractBits(receiveMessage, startBit, signal.Length); + var iVal = ExtractBits(message, startBit, signal.Length); return ApplySignAndScale(signal, iVal); } From 07fa65299832f99ac30b9aa4145d3c09a4772ee6 Mon Sep 17 00:00:00 2001 From: Uight Date: Sun, 28 Jul 2024 14:43:01 +0200 Subject: [PATCH 04/14] Remove apply limit method because its unclear how to implement it --- DbcParserLib/Packer.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/DbcParserLib/Packer.cs b/DbcParserLib/Packer.cs index 022164c..08b8320 100644 --- a/DbcParserLib/Packer.cs +++ b/DbcParserLib/Packer.cs @@ -134,11 +134,6 @@ public static double RxSignalUnpack(byte[] receiveMessage, Signal signal) return ApplySignAndScale(signal, iVal); } - public static double ApplyLimit(double value, Signal signal) - { - return Math.Max(signal.Minimum, Math.Min(value, signal.Maximum)); - } - private static double ApplySignAndScale(Signal signal, ulong value) { switch (signal.ValueType) From 0491476df034ceb299bd5c29cf118e149bbdbe30 Mon Sep 17 00:00:00 2001 From: Uight Date: Sun, 28 Jul 2024 15:05:29 +0200 Subject: [PATCH 05/14] Prepare WriteBitsFunctions usable for Packing signals based on byte[] --- DbcParserLib/Packer.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/DbcParserLib/Packer.cs b/DbcParserLib/Packer.cs index 08b8320..7ea820d 100644 --- a/DbcParserLib/Packer.cs +++ b/DbcParserLib/Packer.cs @@ -207,6 +207,22 @@ private static uint8_T GetStartBitLE(Signal signal, int messageByteCount = 8) return (uint8_T)(8 * messageByteCount - (signal.Length + 8 * startByte + (8 * (startByte + 1) - (signal.StartBit + 1)) % 8)); } + private static void WriteBits(byte[] data, ulong value, int startBit, int length) + { + for (int bitIndex = 0; bitIndex < length; bitIndex++) + { + int bitPosition = startBit + bitIndex; + int byteIndex = bitPosition / 8; + int bitInBytePosition = bitPosition % 8; + + // Extract the bit from the signal value + ulong bitValue = (value >> bitIndex) & 1; + + // Set the bit in the message + data[byteIndex] |= (byte)(bitValue << bitInBytePosition); + } + } + private static ulong ExtractBits(byte[] data, int startBit, int length) { ulong result = 0; From 70eb9e6eb4db782aff7ef1db29933a1fd2b90cbe Mon Sep 17 00:00:00 2001 From: Uight Date: Sun, 28 Jul 2024 18:18:58 +0200 Subject: [PATCH 06/14] Use c# datatypes and first version for txPack based on byte array --- DbcParserLib/Packer.cs | 196 ++++++++++++++++++++++++----------------- 1 file changed, 115 insertions(+), 81 deletions(-) diff --git a/DbcParserLib/Packer.cs b/DbcParserLib/Packer.cs index 7ea820d..df0f826 100644 --- a/DbcParserLib/Packer.cs +++ b/DbcParserLib/Packer.cs @@ -1,6 +1,3 @@ -using uint8_T = System.Byte; -using int64_T = System.Int64; -using uint64_T = System.UInt64; using System; using System.Runtime.InteropServices; using DbcParserLib.Model; @@ -15,37 +12,45 @@ public static class Packer /// Value to be packed /// Signal containing dbc information /// Returns a 64 bit unsigned data message - public static uint64_T TxSignalPack(double value, Signal signal) + public static ulong TxSignalPack(double value, Signal signal) { - int64_T iVal; - uint64_T bitMask = signal.BitMask(); + long iVal = TxPackApplySignAndScale(value, signal); + ulong bitMask = signal.BitMask(); - // Apply scaling - var rawValue = (value - signal.Offset) / signal.Factor; - if (signal.ValueType == DbcValueType.IEEEFloat) - iVal = (long)FloatConverter.AsInteger((float)rawValue); - else if(signal.ValueType == DbcValueType.IEEEDouble) - iVal = DoubleConverter.AsInteger(rawValue); - else - iVal = (int64_T)Math.Round(rawValue); + // Pack signal + if (signal.Intel()) // Little endian (Intel) + return (((ulong)iVal & bitMask) << signal.StartBit); + else // Big endian (Motorola) + return MirrorMsg(((ulong)iVal & bitMask) << GetStartBitLE(signal)); + } - // Apply overflow protection - if (signal.ValueType == DbcValueType.Signed) - iVal = CLAMP(iVal, -(int64_T)(bitMask >> 1) - 1, (int64_T)(bitMask >> 1)); - else if(signal.ValueType == DbcValueType.Unsigned) - iVal = CLAMP(iVal, 0L, (int64_T)bitMask); + /// + /// Function to pack a signal into a CAN data message + /// + /// A ref to the byte array containing the message + /// Value to be packed + /// Signal containing dbc information + /// Due to needing to reverse the byte array when handling BigEndian(Motorola) format this method can not be called in parallel for multiple signals in one message. + /// To make this obvios the message is a ref and is actually reassigned after handling BigEndian format. + public static void TxSignalPack(ref byte[] message, double value, Signal signal) + { + long iVal = TxPackApplySignAndScale(value, signal); - // Manage sign bit (if signed) - if (signal.ValueType == DbcValueType.Signed && iVal < 0) + // Pack signal + if (!signal.Intel()) { - iVal += (int64_T)(1UL << signal.Length); - } + var tempArray = new byte[message.Length]; + Array.Copy(message, tempArray, message.Length); + Array.Reverse(tempArray); - // Pack signal - if (signal.Intel()) // Little endian (Intel) - return (((uint64_T)iVal & bitMask) << signal.StartBit); - else // Big endian (Motorola) - return MirrorMsg(((uint64_T)iVal & bitMask) << GetStartBitLE(signal)); + WriteBits(tempArray, unchecked((ulong)iVal), GetStartBitLE(signal, message.Length), signal.Length); + + Array.Reverse(tempArray); + + message = tempArray; + return; + } + WriteBits(message, unchecked((ulong)iVal), signal.StartBit, signal.Length); } /// @@ -54,9 +59,9 @@ public static uint64_T TxSignalPack(double value, Signal signal) /// Value to be packed /// Signal containing dbc information /// Returns a 64 bit unsigned data message - public static uint64_T TxStatePack(uint64_T value, Signal signal) + public static ulong TxStatePack(ulong value, Signal signal) { - uint64_T bitMask = signal.BitMask(); + ulong bitMask = signal.BitMask(); // Apply overflow protection value = CLAMP(value, 0UL, bitMask); @@ -74,10 +79,10 @@ public static uint64_T TxStatePack(uint64_T value, Signal signal) /// The 64 bit unsigned data message /// Signal containing dbc information /// Returns a double value representing the unpacked signal - public static double RxSignalUnpack(uint64_T RxMsg64, Signal signal) + public static double RxSignalUnpack(ulong RxMsg64, Signal signal) { - uint64_T iVal; - uint64_T bitMask = signal.BitMask(); + ulong iVal; + ulong bitMask = signal.BitMask(); // Unpack signal if (signal.Intel()) // Little endian (Intel) @@ -85,7 +90,33 @@ public static double RxSignalUnpack(uint64_T RxMsg64, Signal signal) else // Big endian (Motorola) iVal = ((MirrorMsg(RxMsg64) >> GetStartBitLE(signal)) & bitMask); - return ApplySignAndScale(signal, iVal); + return RxUnpackApplySignAndScale(signal, iVal); + } + + /// + /// Function to unpack a signal from a CAN data message + /// + /// The message data + /// Signal containing dbc information + /// Returns a double value representing the unpacked signal + public static double RxSignalUnpack(byte[] receiveMessage, Signal signal) + { + var startBit = signal.StartBit; + var message = receiveMessage; + + if (!signal.Intel()) + { + var tempArray = new byte[message.Length]; + Array.Copy(message, tempArray, message.Length); + Array.Reverse(tempArray); + + message = tempArray; + startBit = GetStartBitLE(signal, message.Length); + } + + var iVal = ExtractBits(message, startBit, signal.Length); + + return RxUnpackApplySignAndScale(signal, iVal); } /// @@ -94,10 +125,10 @@ public static double RxSignalUnpack(uint64_T RxMsg64, Signal signal) /// The 64 bit unsigned data message /// Signal containing dbc information /// Returns an unsigned integer representing the unpacked state - public static uint64_T RxStateUnpack(uint64_T RxMsg64, Signal signal) + public static ulong RxStateUnpack(ulong RxMsg64, Signal signal) { - uint64_T iVal; - uint64_T bitMask = signal.BitMask(); + ulong iVal; + ulong bitMask = signal.BitMask(); // Unpack signal if (signal.Intel()) // Little endian (Intel) @@ -108,38 +139,41 @@ public static uint64_T RxStateUnpack(uint64_T RxMsg64, Signal signal) return iVal; } - /// - /// Function to unpack a signal from a CAN data message - /// - /// The message data - /// Signal containing dbc information - /// Returns a double value representing the unpacked signal - public static double RxSignalUnpack(byte[] receiveMessage, Signal signal) + private static long TxPackApplySignAndScale(double value, Signal signal) { - var startBit = signal.StartBit; - var message = receiveMessage; + long iVal; + ulong bitMask = signal.BitMask(); - if (!signal.Intel()) - { - var copyArray = new byte[message.Length]; - Array.Copy(message, copyArray, message.Length); - Array.Reverse(copyArray); + // Apply scaling + var rawValue = (value - signal.Offset) / signal.Factor; + if (signal.ValueType == DbcValueType.IEEEFloat) + iVal = FloatConverter.AsInteger((float)rawValue); + else if (signal.ValueType == DbcValueType.IEEEDouble) + iVal = DoubleConverter.AsInteger(rawValue); + else + iVal = (long)Math.Round(rawValue); - message = copyArray; - startBit = GetStartBitLE(signal, message.Length); - } + // Apply overflow protection + if (signal.ValueType == DbcValueType.Signed) + iVal = CLAMP(iVal, -(long)(bitMask >> 1) - 1, (long)(bitMask >> 1)); + else if (signal.ValueType == DbcValueType.Unsigned) + iVal = CLAMP(iVal, 0L, (long)bitMask); - var iVal = ExtractBits(message, startBit, signal.Length); + // Manage sign bit (if signed) + if (signal.ValueType == DbcValueType.Signed && iVal < 0) + { + iVal += (long)(1UL << signal.Length); + } - return ApplySignAndScale(signal, iVal); + return iVal; } - private static double ApplySignAndScale(Signal signal, ulong value) + private static double RxUnpackApplySignAndScale(Signal signal, ulong value) { switch (signal.ValueType) { case DbcValueType.Signed: - int64_T signedValue; + long signedValue; if (signal.Length == 64) { signedValue = unchecked((long)value); @@ -162,12 +196,12 @@ private static double ApplySignAndScale(Signal signal, ulong value) } } - private static int64_T CLAMP(int64_T x, int64_T low, int64_T high) + private static long CLAMP(long x, long low, long high) { return Math.Max(low, Math.Min(x, high)); } - private static uint64_T CLAMP(uint64_T x, uint64_T low, uint64_T high) + private static ulong CLAMP(ulong x, ulong low, ulong high) { return Math.Max(low, Math.Min(x, high)); } @@ -175,36 +209,36 @@ private static uint64_T CLAMP(uint64_T x, uint64_T low, uint64_T high) /// /// Mirror data message. It is used to convert Big endian to Little endian and vice-versa /// - private static uint64_T MirrorMsg(uint64_T msg) + private static ulong MirrorMsg(ulong msg) { - uint8_T[] v = + byte[] v = { - (uint8_T)msg, - (uint8_T)(msg >> 8), - (uint8_T)(msg >> 16), - (uint8_T)(msg >> 24), - (uint8_T)(msg >> 32), - (uint8_T)(msg >> 40), - (uint8_T)(msg >> 48), - (uint8_T)(msg >> 56) + (byte)msg, + (byte)(msg >> 8), + (byte)(msg >> 16), + (byte)(msg >> 24), + (byte)(msg >> 32), + (byte)(msg >> 40), + (byte)(msg >> 48), + (byte)(msg >> 56) }; - return (((uint64_T)v[0] << 56) - | ((uint64_T)v[1] << 48) - | ((uint64_T)v[2] << 40) - | ((uint64_T)v[3] << 32) - | ((uint64_T)v[4] << 24) - | ((uint64_T)v[5] << 16) - | ((uint64_T)v[6] << 8) - | (uint64_T)v[7]); + return (((ulong)v[0] << 56) + | ((ulong)v[1] << 48) + | ((ulong)v[2] << 40) + | ((ulong)v[3] << 32) + | ((ulong)v[4] << 24) + | ((ulong)v[5] << 16) + | ((ulong)v[6] << 8) + | (ulong)v[7]); } /// /// Get start bit Little Endian /// - private static uint8_T GetStartBitLE(Signal signal, int messageByteCount = 8) + private static byte GetStartBitLE(Signal signal, int messageByteCount = 8) { - uint8_T startByte = (uint8_T)(signal.StartBit / 8); - return (uint8_T)(8 * messageByteCount - (signal.Length + 8 * startByte + (8 * (startByte + 1) - (signal.StartBit + 1)) % 8)); + byte startByte = (byte)(signal.StartBit / 8); + return (byte)(8 * messageByteCount - (signal.Length + 8 * startByte + (8 * (startByte + 1) - (signal.StartBit + 1)) % 8)); } private static void WriteBits(byte[] data, ulong value, int startBit, int length) From 24fb54c292b3bfed111aa6c99336e62720d46572 Mon Sep 17 00:00:00 2001 From: Uight Date: Fri, 9 Aug 2024 09:33:53 +0200 Subject: [PATCH 07/14] Ignore rider files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 96fb177..db050b2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.suo *.user *.sln.docstates +.idea .vs # Build results From 3bb40c76e90448a2d5760aa70f28a65804c5b5ea Mon Sep 17 00:00:00 2001 From: Uight Date: Fri, 9 Aug 2024 09:43:53 +0200 Subject: [PATCH 08/14] Use datatype compatible to c++ code; Fix StartbitLE being maxed at 255 --- DbcParserLib/Packer.cs | 124 +++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 60 deletions(-) diff --git a/DbcParserLib/Packer.cs b/DbcParserLib/Packer.cs index df0f826..7292032 100644 --- a/DbcParserLib/Packer.cs +++ b/DbcParserLib/Packer.cs @@ -1,3 +1,7 @@ +using uint8_T = System.Byte; +using uint16_T = System.UInt16; +using int64_T = System.Int64; +using uint64_T = System.UInt64; using System; using System.Runtime.InteropServices; using DbcParserLib.Model; @@ -12,16 +16,16 @@ public static class Packer /// Value to be packed /// Signal containing dbc information /// Returns a 64 bit unsigned data message - public static ulong TxSignalPack(double value, Signal signal) + public static uint64_T TxSignalPack(double value, Signal signal) { - long iVal = TxPackApplySignAndScale(value, signal); - ulong bitMask = signal.BitMask(); + int64_T iVal = TxPackApplySignAndScale(value, signal); + uint64_T bitMask = signal.BitMask(); // Pack signal if (signal.Intel()) // Little endian (Intel) - return (((ulong)iVal & bitMask) << signal.StartBit); + return (((uint64_T)iVal & bitMask) << signal.StartBit); else // Big endian (Motorola) - return MirrorMsg(((ulong)iVal & bitMask) << GetStartBitLE(signal)); + return MirrorMsg(((uint64_T)iVal & bitMask) << GetStartBitLE(signal)); } /// @@ -32,25 +36,25 @@ public static ulong TxSignalPack(double value, Signal signal) /// Signal containing dbc information /// Due to needing to reverse the byte array when handling BigEndian(Motorola) format this method can not be called in parallel for multiple signals in one message. /// To make this obvios the message is a ref and is actually reassigned after handling BigEndian format. - public static void TxSignalPack(ref byte[] message, double value, Signal signal) + public static void TxSignalPack(ref uint8_T[] message, double value, Signal signal) { - long iVal = TxPackApplySignAndScale(value, signal); + int64_T iVal = TxPackApplySignAndScale(value, signal); // Pack signal if (!signal.Intel()) { - var tempArray = new byte[message.Length]; + var tempArray = new uint8_T[message.Length]; Array.Copy(message, tempArray, message.Length); Array.Reverse(tempArray); - WriteBits(tempArray, unchecked((ulong)iVal), GetStartBitLE(signal, message.Length), signal.Length); + WriteBits(tempArray, unchecked((uint64_T)iVal), GetStartBitLE(signal, message.Length), signal.Length); Array.Reverse(tempArray); message = tempArray; return; } - WriteBits(message, unchecked((ulong)iVal), signal.StartBit, signal.Length); + WriteBits(message, unchecked((uint64_T)iVal), signal.StartBit, signal.Length); } /// @@ -59,9 +63,9 @@ public static void TxSignalPack(ref byte[] message, double value, Signal signal) /// Value to be packed /// Signal containing dbc information /// Returns a 64 bit unsigned data message - public static ulong TxStatePack(ulong value, Signal signal) + public static uint64_T TxStatePack(uint64_T value, Signal signal) { - ulong bitMask = signal.BitMask(); + uint64_T bitMask = signal.BitMask(); // Apply overflow protection value = CLAMP(value, 0UL, bitMask); @@ -79,10 +83,10 @@ public static ulong TxStatePack(ulong value, Signal signal) /// The 64 bit unsigned data message /// Signal containing dbc information /// Returns a double value representing the unpacked signal - public static double RxSignalUnpack(ulong RxMsg64, Signal signal) + public static double RxSignalUnpack(uint64_T RxMsg64, Signal signal) { - ulong iVal; - ulong bitMask = signal.BitMask(); + uint64_T iVal; + uint64_T bitMask = signal.BitMask(); // Unpack signal if (signal.Intel()) // Little endian (Intel) @@ -99,14 +103,14 @@ public static double RxSignalUnpack(ulong RxMsg64, Signal signal) /// The message data /// Signal containing dbc information /// Returns a double value representing the unpacked signal - public static double RxSignalUnpack(byte[] receiveMessage, Signal signal) + public static double RxSignalUnpack(uint8_T[] receiveMessage, Signal signal) { var startBit = signal.StartBit; var message = receiveMessage; if (!signal.Intel()) { - var tempArray = new byte[message.Length]; + var tempArray = new uint8_T[message.Length]; Array.Copy(message, tempArray, message.Length); Array.Reverse(tempArray); @@ -125,10 +129,10 @@ public static double RxSignalUnpack(byte[] receiveMessage, Signal signal) /// The 64 bit unsigned data message /// Signal containing dbc information /// Returns an unsigned integer representing the unpacked state - public static ulong RxStateUnpack(ulong RxMsg64, Signal signal) + public static uint64_T RxStateUnpack(uint64_T RxMsg64, Signal signal) { - ulong iVal; - ulong bitMask = signal.BitMask(); + uint64_T iVal; + uint64_T bitMask = signal.BitMask(); // Unpack signal if (signal.Intel()) // Little endian (Intel) @@ -139,10 +143,10 @@ public static ulong RxStateUnpack(ulong RxMsg64, Signal signal) return iVal; } - private static long TxPackApplySignAndScale(double value, Signal signal) + private static int64_T TxPackApplySignAndScale(double value, Signal signal) { - long iVal; - ulong bitMask = signal.BitMask(); + int64_T iVal; + uint64_T bitMask = signal.BitMask(); // Apply scaling var rawValue = (value - signal.Offset) / signal.Factor; @@ -151,18 +155,18 @@ private static long TxPackApplySignAndScale(double value, Signal signal) else if (signal.ValueType == DbcValueType.IEEEDouble) iVal = DoubleConverter.AsInteger(rawValue); else - iVal = (long)Math.Round(rawValue); + iVal = (int64_T)Math.Round(rawValue); // Apply overflow protection if (signal.ValueType == DbcValueType.Signed) - iVal = CLAMP(iVal, -(long)(bitMask >> 1) - 1, (long)(bitMask >> 1)); + iVal = CLAMP(iVal, -(int64_T)(bitMask >> 1) - 1, (int64_T)(bitMask >> 1)); else if (signal.ValueType == DbcValueType.Unsigned) - iVal = CLAMP(iVal, 0L, (long)bitMask); + iVal = CLAMP(iVal, 0L, (int64_T)bitMask); // Manage sign bit (if signed) if (signal.ValueType == DbcValueType.Signed && iVal < 0) { - iVal += (long)(1UL << signal.Length); + iVal += (int64_T)(1UL << signal.Length); } return iVal; @@ -173,10 +177,10 @@ private static double RxUnpackApplySignAndScale(Signal signal, ulong value) switch (signal.ValueType) { case DbcValueType.Signed: - long signedValue; + int64_T signedValue; if (signal.Length == 64) { - signedValue = unchecked((long)value); + signedValue = unchecked((int64_T)value); } else { @@ -190,18 +194,18 @@ private static double RxUnpackApplySignAndScale(Signal signal, ulong value) case DbcValueType.IEEEFloat: return FloatConverter.AsFloatingPoint((int)value) * signal.Factor + signal.Offset; case DbcValueType.IEEEDouble: - return DoubleConverter.AsFloatingPoint(unchecked((long)value)) * signal.Factor + signal.Offset; + return DoubleConverter.AsFloatingPoint(unchecked((int64_T)value)) * signal.Factor + signal.Offset; default: return (double)(value * (decimal)signal.Factor + (decimal)signal.Offset); } } - private static long CLAMP(long x, long low, long high) + private static int64_T CLAMP(int64_T x, int64_T low, int64_T high) { return Math.Max(low, Math.Min(x, high)); } - private static ulong CLAMP(ulong x, ulong low, ulong high) + private static uint64_T CLAMP(uint64_T x, uint64_T low, uint64_T high) { return Math.Max(low, Math.Min(x, high)); } @@ -209,39 +213,39 @@ private static ulong CLAMP(ulong x, ulong low, ulong high) /// /// Mirror data message. It is used to convert Big endian to Little endian and vice-versa /// - private static ulong MirrorMsg(ulong msg) + private static uint64_T MirrorMsg(uint64_T msg) { - byte[] v = + uint8_T[] v = { - (byte)msg, - (byte)(msg >> 8), - (byte)(msg >> 16), - (byte)(msg >> 24), - (byte)(msg >> 32), - (byte)(msg >> 40), - (byte)(msg >> 48), - (byte)(msg >> 56) + (uint8_T)msg, + (uint8_T)(msg >> 8), + (uint8_T)(msg >> 16), + (uint8_T)(msg >> 24), + (uint8_T)(msg >> 32), + (uint8_T)(msg >> 40), + (uint8_T)(msg >> 48), + (uint8_T)(msg >> 56) }; - return (((ulong)v[0] << 56) - | ((ulong)v[1] << 48) - | ((ulong)v[2] << 40) - | ((ulong)v[3] << 32) - | ((ulong)v[4] << 24) - | ((ulong)v[5] << 16) - | ((ulong)v[6] << 8) - | (ulong)v[7]); + return (((uint64_T)v[0] << 56) + | ((uint64_T)v[1] << 48) + | ((uint64_T)v[2] << 40) + | ((uint64_T)v[3] << 32) + | ((uint64_T)v[4] << 24) + | ((uint64_T)v[5] << 16) + | ((uint64_T)v[6] << 8) + | (uint64_T)v[7]); } /// /// Get start bit Little Endian /// - private static byte GetStartBitLE(Signal signal, int messageByteCount = 8) + private static uint16_T GetStartBitLE(Signal signal, int messageByteCount = 8) { - byte startByte = (byte)(signal.StartBit / 8); - return (byte)(8 * messageByteCount - (signal.Length + 8 * startByte + (8 * (startByte + 1) - (signal.StartBit + 1)) % 8)); + uint16_T startByte = (uint16_T)(signal.StartBit / 8); + return (uint16_T)(8 * messageByteCount - (signal.Length + 8 * startByte + (8 * (startByte + 1) - (signal.StartBit + 1)) % 8)); } - private static void WriteBits(byte[] data, ulong value, int startBit, int length) + private static void WriteBits(uint8_T[] data, uint64_T value, int startBit, int length) { for (int bitIndex = 0; bitIndex < length; bitIndex++) { @@ -250,16 +254,16 @@ private static void WriteBits(byte[] data, ulong value, int startBit, int length int bitInBytePosition = bitPosition % 8; // Extract the bit from the signal value - ulong bitValue = (value >> bitIndex) & 1; + uint64_T bitValue = (value >> bitIndex) & 1; // Set the bit in the message data[byteIndex] |= (byte)(bitValue << bitInBytePosition); } } - private static ulong ExtractBits(byte[] data, int startBit, int length) + private static uint64_T ExtractBits(uint8_T[] data, int startBit, int length) { - ulong result = 0; + uint64_T result = 0; int bitIndex = 0; for (int bitPos = startBit; bitPos < startBit + length; bitPos++) @@ -303,15 +307,15 @@ public static float AsFloatingPoint(int value) [StructLayout(LayoutKind.Explicit)] public class DoubleConverter { - [FieldOffset(0)] public long Integer; + [FieldOffset(0)] public int64_T Integer; [FieldOffset(0)] public double Float; - public static long AsInteger(double value) + public static int64_T AsInteger(double value) { return new DoubleConverter() { Float = value }.Integer; } - public static double AsFloatingPoint(long value) + public static double AsFloatingPoint(int64_T value) { return new DoubleConverter() { Integer = value }.Float; } From fff307343aa4e9955c0323085deecd285c46b4ba Mon Sep 17 00:00:00 2001 From: Uight Date: Fri, 9 Aug 2024 22:03:11 +0200 Subject: [PATCH 09/14] #67 Added a more complex unittest for big endian packing and added a basic benchmark setup for testing the packer --- .gitignore | 2 + DbcParser.sln | 12 ++- .../DbcParserLib.Benchmarks.csproj | 19 +++++ DbcParserLib.Benchmarks/PackerBenchmark.cs | 79 +++++++++++++++++++ DbcParserLib.Benchmarks/Program.cs | 21 +++++ DbcParserLib.Tests/PackerTests.cs | 61 ++++++++++++++ 6 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 DbcParserLib.Benchmarks/DbcParserLib.Benchmarks.csproj create mode 100644 DbcParserLib.Benchmarks/PackerBenchmark.cs create mode 100644 DbcParserLib.Benchmarks/Program.cs diff --git a/.gitignore b/.gitignore index db050b2..a5cc14e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ DbcParserLib/obj/ DbcParserLib/bin/ DbcParserLib.Tests/obj/ DbcParserLib.Tests/bin/ +DbcParserLib.Benchmarks/obj/ +DbcParserLib.Benchmarks/bin/ Demo/obj/ Demo/bin/ diff --git a/DbcParser.sln b/DbcParser.sln index 49dea36..a5e2920 100644 --- a/DbcParser.sln +++ b/DbcParser.sln @@ -1,13 +1,15 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31515.178 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34607.119 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbcParserLib", "DbcParserLib\DbcParserLib.csproj", "{82DD10F6-784A-4D87-B117-FB910E84D175}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo", "Demo\Demo.csproj", "{9CA98991-90EF-4E86-BCA6-372EF2AE471E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DbcParserLib.Tests", "DbcParserLib.Tests\DbcParserLib.Tests.csproj", "{0FE933E2-4870-49BD-9A9A-931F30730D82}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbcParserLib.Tests", "DbcParserLib.Tests\DbcParserLib.Tests.csproj", "{0FE933E2-4870-49BD-9A9A-931F30730D82}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DbcParserLib.Benchmarks", "DbcParserLib.Benchmarks\DbcParserLib.Benchmarks.csproj", "{0B3323E7-FEC3-4606-9012-C6166D941CCC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -27,6 +29,10 @@ Global {0FE933E2-4870-49BD-9A9A-931F30730D82}.Debug|Any CPU.Build.0 = Debug|Any CPU {0FE933E2-4870-49BD-9A9A-931F30730D82}.Release|Any CPU.ActiveCfg = Release|Any CPU {0FE933E2-4870-49BD-9A9A-931F30730D82}.Release|Any CPU.Build.0 = Release|Any CPU + {0B3323E7-FEC3-4606-9012-C6166D941CCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B3323E7-FEC3-4606-9012-C6166D941CCC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B3323E7-FEC3-4606-9012-C6166D941CCC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B3323E7-FEC3-4606-9012-C6166D941CCC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/DbcParserLib.Benchmarks/DbcParserLib.Benchmarks.csproj b/DbcParserLib.Benchmarks/DbcParserLib.Benchmarks.csproj new file mode 100644 index 0000000..b67e164 --- /dev/null +++ b/DbcParserLib.Benchmarks/DbcParserLib.Benchmarks.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + false + Exe + enable + enable + + + + + + + + + + + diff --git a/DbcParserLib.Benchmarks/PackerBenchmark.cs b/DbcParserLib.Benchmarks/PackerBenchmark.cs new file mode 100644 index 0000000..ce73632 --- /dev/null +++ b/DbcParserLib.Benchmarks/PackerBenchmark.cs @@ -0,0 +1,79 @@ +using DbcParserLib.Model; +using BenchmarkDotNet.Attributes; + +namespace DbcParserLib.Tests +{ + public class PackerBenchmark + { + private Signal EightByte_BigEndian_Signal1; + private Signal EightByte_BigEndian_Signal2; + private Signal EightByte_BigEndian_Signal3; + private Signal EightByte_BigEndian_Signal4; + + [GlobalSetup] + public void SetupSignals() + { + EightByte_BigEndian_Signal1 = new Signal + { + StartBit = 7, + Length = 10, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + EightByte_BigEndian_Signal2 = new Signal + { + StartBit = 13, + Length = 6, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + EightByte_BigEndian_Signal3 = new Signal + { + StartBit = 23, + Length = 32, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + EightByte_BigEndian_Signal4 = new Signal + { + StartBit = 55, + Length = 16, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + } + + [Benchmark] + public ulong Pack_8Byte_BigEndian_Uint64() + { + ulong TxMsg = 0; + TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal1); + TxMsg |= Packer.TxSignalPack(63, EightByte_BigEndian_Signal2); + TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal3); + TxMsg |= Packer.TxSignalPack(ushort.MaxValue, EightByte_BigEndian_Signal4); + return TxMsg; + } + + [Benchmark] + public ulong Pack_8Byte_BigEndian_ByteArray() + { + ulong TxMsg = 0; + TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal1); + TxMsg |= Packer.TxSignalPack(63, EightByte_BigEndian_Signal2); + TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal3); + TxMsg |= Packer.TxSignalPack(ushort.MaxValue, EightByte_BigEndian_Signal4); + return TxMsg; + } + } +} \ No newline at end of file diff --git a/DbcParserLib.Benchmarks/Program.cs b/DbcParserLib.Benchmarks/Program.cs new file mode 100644 index 0000000..62da277 --- /dev/null +++ b/DbcParserLib.Benchmarks/Program.cs @@ -0,0 +1,21 @@ +using BenchmarkDotNet.Running; +using DbcParserLib.Tests; + +var summary = BenchmarkRunner.Run(); + + +/* Summary + +BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3) +AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores +.NET SDK 8.0.200 + [Host] : .NET 6.0.32 (6.0.3224.31407), X64 RyuJIT AVX2 + DefaultJob : .NET 6.0.32 (6.0.3224.31407), X64 RyuJIT AVX2 + + +| Method | Mean | Error | StdDev | +|------------------------------- |---------:| --------:| --------:| +| Pack_8Byte_BigEndian_Uint64 | 40.24 ns | 0.555 ns | 0.519 ns | +| Pack_8Byte_BigEndian_ByteArray | 39.68 ns | 0.786 ns | 0.807 ns | + +*/ \ No newline at end of file diff --git a/DbcParserLib.Tests/PackerTests.cs b/DbcParserLib.Tests/PackerTests.cs index cebd5c2..5ef3fc7 100644 --- a/DbcParserLib.Tests/PackerTests.cs +++ b/DbcParserLib.Tests/PackerTests.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using DbcParserLib.Model; +using System; namespace DbcParserLib.Tests { @@ -138,6 +139,66 @@ public void SimplePackingTestNonSigned() Assert.AreEqual(800, val); } + [Test] + public void SimplePackingMultiPackBigEndian() + { + var sig1 = new Signal + { + StartBit = 7, + Length = 10, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + var sig2 = new Signal + { + StartBit = 13, + Length = 6, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + var sig3 = new Signal + { + StartBit = 23, + Length = 32, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + var sig4 = new Signal + { + StartBit = 55, + Length = 16, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + ulong TxMsg = 0; + TxMsg |= Packer.TxSignalPack(0, sig1); + TxMsg |= Packer.TxSignalPack(63, sig2); + TxMsg |= Packer.TxSignalPack(0, sig3); + TxMsg |= Packer.TxSignalPack(ushort.MaxValue, sig4); + + Assert.AreEqual(18446462598732857088, TxMsg); + + byte[] txMsg = new byte[8]; + Packer.TxSignalPack(ref txMsg, 0, sig1); + Packer.TxSignalPack(ref txMsg, 63, sig2); + Packer.TxSignalPack(ref txMsg, 0, sig3); + Packer.TxSignalPack(ref txMsg, ushort.MaxValue, sig4); + + Assert.AreEqual(18446462598732857088, BitConverter.ToUInt64(txMsg)); + } + [Test] public void PackingTest64Bit() { From 017645ed46416752d967061fd1dd0c040dc6a927 Mon Sep 17 00:00:00 2001 From: Uight Date: Sat, 10 Aug 2024 13:44:24 +0200 Subject: [PATCH 10/14] Quick safe for benchmarks --- DbcParserLib.Benchmarks/PackerBenchmark.cs | 112 ++++++++++++- DbcParserLib.Benchmarks/Program.cs | 21 ++- DbcParserLib.Benchmarks/UnpackBenchmark.cs | 181 +++++++++++++++++++++ 3 files changed, 301 insertions(+), 13 deletions(-) create mode 100644 DbcParserLib.Benchmarks/UnpackBenchmark.cs diff --git a/DbcParserLib.Benchmarks/PackerBenchmark.cs b/DbcParserLib.Benchmarks/PackerBenchmark.cs index ce73632..f60ccee 100644 --- a/DbcParserLib.Benchmarks/PackerBenchmark.cs +++ b/DbcParserLib.Benchmarks/PackerBenchmark.cs @@ -10,6 +10,13 @@ public class PackerBenchmark private Signal EightByte_BigEndian_Signal3; private Signal EightByte_BigEndian_Signal4; + private Signal EightByte_LittleEndian_Signal1; + private Signal EightByte_LittleEndian_Signal2; + private Signal EightByte_LittleEndian_Signal3; + private Signal EightByte_LittleEndian_Signal4; + + private Signal LittleEndian_Unsigned_NoScale; + [GlobalSetup] public void SetupSignals() { @@ -52,6 +59,56 @@ public void SetupSignals() Factor = 1, Offset = 0 }; + + EightByte_LittleEndian_Signal1 = new Signal + { + StartBit = 0, + Length = 10, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + EightByte_LittleEndian_Signal2 = new Signal + { + StartBit = 10, + Length = 6, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + EightByte_LittleEndian_Signal3 = new Signal + { + StartBit = 16, + Length = 32, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + EightByte_LittleEndian_Signal4 = new Signal + { + StartBit = 48, + Length = 16, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + LittleEndian_Unsigned_NoScale = new Signal + { + StartBit = 0, + Length = 32, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; } [Benchmark] @@ -66,14 +123,59 @@ public ulong Pack_8Byte_BigEndian_Uint64() } [Benchmark] - public ulong Pack_8Byte_BigEndian_ByteArray() + public byte[] Pack_8Byte_BigEndian_ByteArray() + { + byte[] TxMsg = new byte[8]; + Packer.TxSignalPack(ref TxMsg, 0, EightByte_BigEndian_Signal1); + Packer.TxSignalPack(ref TxMsg, 63, EightByte_BigEndian_Signal2); + Packer.TxSignalPack(ref TxMsg, 0, EightByte_BigEndian_Signal3); + Packer.TxSignalPack(ref TxMsg, ushort.MaxValue, EightByte_BigEndian_Signal4); + return TxMsg; + } + + [Benchmark] + public ulong Pack_8Byte_LittleEndian_Uint64() { ulong TxMsg = 0; - TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal1); - TxMsg |= Packer.TxSignalPack(63, EightByte_BigEndian_Signal2); - TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal3); - TxMsg |= Packer.TxSignalPack(ushort.MaxValue, EightByte_BigEndian_Signal4); + TxMsg |= Packer.TxSignalPack(0, EightByte_LittleEndian_Signal1); + TxMsg |= Packer.TxSignalPack(63, EightByte_LittleEndian_Signal2); + TxMsg |= Packer.TxSignalPack(0, EightByte_LittleEndian_Signal3); + TxMsg |= Packer.TxSignalPack(ushort.MaxValue, EightByte_LittleEndian_Signal4); + return TxMsg; + } + + [Benchmark] + public byte[] Pack_8Byte_LittleEndian_ByteArray() + { + byte[] TxMsg = new byte[8]; + Packer.TxSignalPack(ref TxMsg, 0, EightByte_LittleEndian_Signal1); + Packer.TxSignalPack(ref TxMsg, 63, EightByte_LittleEndian_Signal2); + Packer.TxSignalPack(ref TxMsg, 0, EightByte_LittleEndian_Signal3); + Packer.TxSignalPack(ref TxMsg, ushort.MaxValue, EightByte_LittleEndian_Signal4); return TxMsg; } + + [Benchmark] + public ulong Pack_1Signal_Unsigned_NoScale_StatePack() + { + ulong TxMsg = 0; + TxMsg |= Packer.TxStatePack(123, LittleEndian_Unsigned_NoScale); + return TxMsg; + } + + [Benchmark] + public ulong Pack_1Signal_Unsigned_NoScale_SignalPack() + { + ulong TxMsg = 0; + TxMsg |= Packer.TxSignalPack(123, LittleEndian_Unsigned_NoScale); + return TxMsg; + } + + [Benchmark] + public void Pack_1Signal_Unsigned_NoScale_SignalPackByteArray() + { + byte[] TxMsg = new byte[8]; + Packer.TxSignalPack(ref TxMsg, 123, LittleEndian_Unsigned_NoScale); + } } } \ No newline at end of file diff --git a/DbcParserLib.Benchmarks/Program.cs b/DbcParserLib.Benchmarks/Program.cs index 62da277..9e36227 100644 --- a/DbcParserLib.Benchmarks/Program.cs +++ b/DbcParserLib.Benchmarks/Program.cs @@ -1,10 +1,9 @@ using BenchmarkDotNet.Running; using DbcParserLib.Tests; -var summary = BenchmarkRunner.Run(); +var summaryPack = BenchmarkRunner.Run(); - -/* Summary +/* Summary => This is pc dependend. The relevant information is the time difference BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3) AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores @@ -13,9 +12,15 @@ .NET SDK 8.0.200 DefaultJob : .NET 6.0.32 (6.0.3224.31407), X64 RyuJIT AVX2 -| Method | Mean | Error | StdDev | -|------------------------------- |---------:| --------:| --------:| -| Pack_8Byte_BigEndian_Uint64 | 40.24 ns | 0.555 ns | 0.519 ns | -| Pack_8Byte_BigEndian_ByteArray | 39.68 ns | 0.786 ns | 0.807 ns | +| Method | Mean | Error | StdDev | +|-------------------------------------------------- |------------:| ----------:| ----------:| +| Pack_8Byte_BigEndian_Uint64 | 40.5778 ns | 0.3100 ns | 0.2420 ns | +| Pack_8Byte_BigEndian_ByteArray | 167.4555 ns | 2.3924 ns | 2.2379 ns | +| Pack_8Byte_LittleEndian_Uint64 | 12.1883 ns | 0.1173 ns | 0.0980 ns | +| Pack_8Byte_LittleEndian_ByteArray | 100.1948 ns | 0.6864 ns | 0.5359 ns | +| Pack_1Signal_Unsigned_NoScale_StatePack | 0.8825 ns | 0.0081 ns | 0.0068 ns | +| Pack_1Signal_Unsigned_NoScale_SignalPack | 3.0999 ns | 0.0711 ns | 0.0665 ns | +| Pack_1Signal_Unsigned_NoScale_SignalPackByteArray | 49.3012 ns | 0.8965 ns | 0.8386 ns | +*/ -*/ \ No newline at end of file +//var summaryUnpack = BenchmarkRunner.Run(); \ No newline at end of file diff --git a/DbcParserLib.Benchmarks/UnpackBenchmark.cs b/DbcParserLib.Benchmarks/UnpackBenchmark.cs new file mode 100644 index 0000000..982ff41 --- /dev/null +++ b/DbcParserLib.Benchmarks/UnpackBenchmark.cs @@ -0,0 +1,181 @@ +using DbcParserLib.Model; +using BenchmarkDotNet.Attributes; + +namespace DbcParserLib.Tests +{ + public class UnpackBenchmark + { + private Signal EightByte_BigEndian_Signal1; + private Signal EightByte_BigEndian_Signal2; + private Signal EightByte_BigEndian_Signal3; + private Signal EightByte_BigEndian_Signal4; + + private Signal EightByte_LittleEndian_Signal1; + private Signal EightByte_LittleEndian_Signal2; + private Signal EightByte_LittleEndian_Signal3; + private Signal EightByte_LittleEndian_Signal4; + + private Signal LittleEndian_Unsigned_NoScale; + + [GlobalSetup] + public void SetupSignals() + { + EightByte_BigEndian_Signal1 = new Signal + { + StartBit = 7, + Length = 10, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + EightByte_BigEndian_Signal2 = new Signal + { + StartBit = 13, + Length = 6, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + EightByte_BigEndian_Signal3 = new Signal + { + StartBit = 23, + Length = 32, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + EightByte_BigEndian_Signal4 = new Signal + { + StartBit = 55, + Length = 16, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + EightByte_LittleEndian_Signal1 = new Signal + { + StartBit = 0, + Length = 10, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + EightByte_LittleEndian_Signal2 = new Signal + { + StartBit = 10, + Length = 6, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + EightByte_LittleEndian_Signal3 = new Signal + { + StartBit = 16, + Length = 32, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + EightByte_LittleEndian_Signal4 = new Signal + { + StartBit = 48, + Length = 16, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + LittleEndian_Unsigned_NoScale = new Signal + { + StartBit = 0, + Length = 32, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + } + + [Benchmark] + public ulong Pack_8Byte_BigEndian_Uint64() + { + ulong TxMsg = 0; + TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal1); + TxMsg |= Packer.TxSignalPack(63, EightByte_BigEndian_Signal2); + TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal3); + TxMsg |= Packer.TxSignalPack(ushort.MaxValue, EightByte_BigEndian_Signal4); + return TxMsg; + } + + [Benchmark] + public byte[] Pack_8Byte_BigEndian_ByteArray() + { + byte[] TxMsg = new byte[8]; + Packer.TxSignalPack(ref TxMsg, 0, EightByte_BigEndian_Signal1); + Packer.TxSignalPack(ref TxMsg, 63, EightByte_BigEndian_Signal2); + Packer.TxSignalPack(ref TxMsg, 0, EightByte_BigEndian_Signal3); + Packer.TxSignalPack(ref TxMsg, ushort.MaxValue, EightByte_BigEndian_Signal4); + return TxMsg; + } + + [Benchmark] + public ulong Pack_8Byte_LittleEndian_Uint64() + { + ulong TxMsg = 0; + TxMsg |= Packer.TxSignalPack(0, EightByte_LittleEndian_Signal1); + TxMsg |= Packer.TxSignalPack(63, EightByte_LittleEndian_Signal2); + TxMsg |= Packer.TxSignalPack(0, EightByte_LittleEndian_Signal3); + TxMsg |= Packer.TxSignalPack(ushort.MaxValue, EightByte_LittleEndian_Signal4); + return TxMsg; + } + + [Benchmark] + public byte[] Pack_8Byte_LittleEndian_ByteArray() + { + byte[] TxMsg = new byte[8]; + Packer.TxSignalPack(ref TxMsg, 0, EightByte_LittleEndian_Signal1); + Packer.TxSignalPack(ref TxMsg, 63, EightByte_LittleEndian_Signal2); + Packer.TxSignalPack(ref TxMsg, 0, EightByte_LittleEndian_Signal3); + Packer.TxSignalPack(ref TxMsg, ushort.MaxValue, EightByte_LittleEndian_Signal4); + return TxMsg; + } + + [Benchmark] + public ulong Pack_1Signal_Unsigned_NoScale_StatePack() + { + ulong TxMsg = 0; + TxMsg |= Packer.TxStatePack(123, LittleEndian_Unsigned_NoScale); + return TxMsg; + } + + [Benchmark] + public ulong Pack_1Signal_Unsigned_NoScale_SignalPack() + { + ulong TxMsg = 0; + TxMsg |= Packer.TxSignalPack(123, LittleEndian_Unsigned_NoScale); + return TxMsg; + } + + [Benchmark] + public void Pack_1Signal_Unsigned_NoScale_SignalPackByteArray() + { + byte[] TxMsg = new byte[8]; + Packer.TxSignalPack(ref TxMsg, 123, LittleEndian_Unsigned_NoScale); + } + } +} \ No newline at end of file From 6fbddbb83f6833edf935c0a8bf9a8947a0c49ee7 Mon Sep 17 00:00:00 2001 From: Uight Date: Sat, 10 Aug 2024 14:20:49 +0200 Subject: [PATCH 11/14] Add unpack benchmarks --- DbcParserLib.Benchmarks/PackerBenchmark.cs | 3 +- DbcParserLib.Benchmarks/Program.cs | 22 ++++++- DbcParserLib.Benchmarks/UnpackBenchmark.cs | 68 +++++++++------------- 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/DbcParserLib.Benchmarks/PackerBenchmark.cs b/DbcParserLib.Benchmarks/PackerBenchmark.cs index f60ccee..3e24e5e 100644 --- a/DbcParserLib.Benchmarks/PackerBenchmark.cs +++ b/DbcParserLib.Benchmarks/PackerBenchmark.cs @@ -172,10 +172,11 @@ public ulong Pack_1Signal_Unsigned_NoScale_SignalPack() } [Benchmark] - public void Pack_1Signal_Unsigned_NoScale_SignalPackByteArray() + public byte[] Pack_1Signal_Unsigned_NoScale_SignalPackByteArray() { byte[] TxMsg = new byte[8]; Packer.TxSignalPack(ref TxMsg, 123, LittleEndian_Unsigned_NoScale); + return TxMsg; } } } \ No newline at end of file diff --git a/DbcParserLib.Benchmarks/Program.cs b/DbcParserLib.Benchmarks/Program.cs index 9e36227..ab768c3 100644 --- a/DbcParserLib.Benchmarks/Program.cs +++ b/DbcParserLib.Benchmarks/Program.cs @@ -23,4 +23,24 @@ .NET SDK 8.0.200 | Pack_1Signal_Unsigned_NoScale_SignalPackByteArray | 49.3012 ns | 0.8965 ns | 0.8386 ns | */ -//var summaryUnpack = BenchmarkRunner.Run(); \ No newline at end of file +var summaryUnpack = BenchmarkRunner.Run(); + +/* Summary => This is pc dependend. The relevant information is the time difference + +BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3) +AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores +.NET SDK 8.0.200 + [Host] : .NET 6.0.32 (6.0.3224.31407), X64 RyuJIT AVX2 + DefaultJob : .NET 6.0.32 (6.0.3224.31407), X64 RyuJIT AVX2 + + +| Method | Mean | Error | StdDev | +|------------------------------------------------ |-----------:| ----------:| ----------:| +| Unpack_8Byte_BigEndian_Uint64 | 107.287 ns | 2.1000 ns | 2.0625 ns | +| Unpack_8Byte_BigEndian_ByteArray | 201.915 ns | 4.0086 ns | 4.2892 ns | +| Unpack_8Byte_LittleEndian_Uint64 | 81.062 ns | 0.2072 ns | 0.1617 ns | +| Unpack_8Byte_LittleEndian_ByteArray | 171.328 ns | 3.2070 ns | 3.1497 ns | +| Unpack_1Signal_Unsigned_NoScale_State | 1.077 ns | 0.0037 ns | 0.0029 ns | +| Unpack_1Signal_Unsigned_NoScale_Signal | 20.269 ns | 0.1389 ns | 0.1232 ns | +| Unpack_1Signal_Unsigned_NoScale_SignalByteArray | 62.919 ns | 0.1156 ns | 0.0902 ns | +*/ \ No newline at end of file diff --git a/DbcParserLib.Benchmarks/UnpackBenchmark.cs b/DbcParserLib.Benchmarks/UnpackBenchmark.cs index 982ff41..13e72d5 100644 --- a/DbcParserLib.Benchmarks/UnpackBenchmark.cs +++ b/DbcParserLib.Benchmarks/UnpackBenchmark.cs @@ -17,6 +17,9 @@ public class UnpackBenchmark private Signal LittleEndian_Unsigned_NoScale; + private ulong RxMsg = ulong.MaxValue; + private byte[] RxBytes = new byte[] { byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue }; + [GlobalSetup] public void SetupSignals() { @@ -112,70 +115,57 @@ public void SetupSignals() } [Benchmark] - public ulong Pack_8Byte_BigEndian_Uint64() + public void Unpack_8Byte_BigEndian_Uint64() { - ulong TxMsg = 0; - TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal1); - TxMsg |= Packer.TxSignalPack(63, EightByte_BigEndian_Signal2); - TxMsg |= Packer.TxSignalPack(0, EightByte_BigEndian_Signal3); - TxMsg |= Packer.TxSignalPack(ushort.MaxValue, EightByte_BigEndian_Signal4); - return TxMsg; + var signal1 = Packer.RxSignalUnpack(RxMsg, EightByte_BigEndian_Signal1); + var signal2 = Packer.RxSignalUnpack(RxMsg, EightByte_BigEndian_Signal2); + var signal3 = Packer.RxSignalUnpack(RxMsg, EightByte_BigEndian_Signal3); + var signal4 = Packer.RxSignalUnpack(RxMsg, EightByte_BigEndian_Signal4); } [Benchmark] - public byte[] Pack_8Byte_BigEndian_ByteArray() + public void Unpack_8Byte_BigEndian_ByteArray() { - byte[] TxMsg = new byte[8]; - Packer.TxSignalPack(ref TxMsg, 0, EightByte_BigEndian_Signal1); - Packer.TxSignalPack(ref TxMsg, 63, EightByte_BigEndian_Signal2); - Packer.TxSignalPack(ref TxMsg, 0, EightByte_BigEndian_Signal3); - Packer.TxSignalPack(ref TxMsg, ushort.MaxValue, EightByte_BigEndian_Signal4); - return TxMsg; + var signal1 = Packer.RxSignalUnpack(RxBytes, EightByte_BigEndian_Signal1); + var signal2 = Packer.RxSignalUnpack(RxBytes, EightByte_BigEndian_Signal2); + var signal3 = Packer.RxSignalUnpack(RxBytes, EightByte_BigEndian_Signal3); + var signal4 = Packer.RxSignalUnpack(RxBytes, EightByte_BigEndian_Signal4); } [Benchmark] - public ulong Pack_8Byte_LittleEndian_Uint64() + public void Unpack_8Byte_LittleEndian_Uint64() { - ulong TxMsg = 0; - TxMsg |= Packer.TxSignalPack(0, EightByte_LittleEndian_Signal1); - TxMsg |= Packer.TxSignalPack(63, EightByte_LittleEndian_Signal2); - TxMsg |= Packer.TxSignalPack(0, EightByte_LittleEndian_Signal3); - TxMsg |= Packer.TxSignalPack(ushort.MaxValue, EightByte_LittleEndian_Signal4); - return TxMsg; + var signal1 = Packer.RxSignalUnpack(RxMsg, EightByte_LittleEndian_Signal1); + var signal2 = Packer.RxSignalUnpack(RxMsg, EightByte_LittleEndian_Signal2); + var signal3 = Packer.RxSignalUnpack(RxMsg, EightByte_LittleEndian_Signal3); + var signal4 = Packer.RxSignalUnpack(RxMsg, EightByte_LittleEndian_Signal4); } [Benchmark] - public byte[] Pack_8Byte_LittleEndian_ByteArray() + public void Unpack_8Byte_LittleEndian_ByteArray() { - byte[] TxMsg = new byte[8]; - Packer.TxSignalPack(ref TxMsg, 0, EightByte_LittleEndian_Signal1); - Packer.TxSignalPack(ref TxMsg, 63, EightByte_LittleEndian_Signal2); - Packer.TxSignalPack(ref TxMsg, 0, EightByte_LittleEndian_Signal3); - Packer.TxSignalPack(ref TxMsg, ushort.MaxValue, EightByte_LittleEndian_Signal4); - return TxMsg; + var signal1 = Packer.RxSignalUnpack(RxBytes, EightByte_LittleEndian_Signal1); + var signal2 = Packer.RxSignalUnpack(RxBytes, EightByte_LittleEndian_Signal2); + var signal3 = Packer.RxSignalUnpack(RxBytes, EightByte_LittleEndian_Signal3); + var signal4 = Packer.RxSignalUnpack(RxBytes, EightByte_LittleEndian_Signal4); } [Benchmark] - public ulong Pack_1Signal_Unsigned_NoScale_StatePack() + public ulong Unpack_1Signal_Unsigned_NoScale_State() { - ulong TxMsg = 0; - TxMsg |= Packer.TxStatePack(123, LittleEndian_Unsigned_NoScale); - return TxMsg; + return Packer.RxStateUnpack(RxMsg, LittleEndian_Unsigned_NoScale); } [Benchmark] - public ulong Pack_1Signal_Unsigned_NoScale_SignalPack() + public double Unpack_1Signal_Unsigned_NoScale_Signal() { - ulong TxMsg = 0; - TxMsg |= Packer.TxSignalPack(123, LittleEndian_Unsigned_NoScale); - return TxMsg; + return Packer.RxSignalUnpack(RxMsg, LittleEndian_Unsigned_NoScale); } [Benchmark] - public void Pack_1Signal_Unsigned_NoScale_SignalPackByteArray() + public double Unpack_1Signal_Unsigned_NoScale_SignalByteArray() { - byte[] TxMsg = new byte[8]; - Packer.TxSignalPack(ref TxMsg, 123, LittleEndian_Unsigned_NoScale); + return Packer.RxSignalUnpack(RxBytes, LittleEndian_Unsigned_NoScale); } } } \ No newline at end of file From 1b7bad8a937ecc12f2b8177dfe1412f5062ecee1 Mon Sep 17 00:00:00 2001 From: Uight Date: Sat, 10 Aug 2024 15:12:35 +0200 Subject: [PATCH 12/14] Remove ref when packing --- DbcParserLib.Benchmarks/PackerBenchmark.cs | 18 +++++++++--------- DbcParserLib.Benchmarks/Program.cs | 2 +- DbcParserLib.Tests/PackerTests.cs | 8 ++++---- DbcParserLib/Packer.cs | 16 ++++------------ 4 files changed, 18 insertions(+), 26 deletions(-) diff --git a/DbcParserLib.Benchmarks/PackerBenchmark.cs b/DbcParserLib.Benchmarks/PackerBenchmark.cs index 3e24e5e..549c083 100644 --- a/DbcParserLib.Benchmarks/PackerBenchmark.cs +++ b/DbcParserLib.Benchmarks/PackerBenchmark.cs @@ -126,10 +126,10 @@ public ulong Pack_8Byte_BigEndian_Uint64() public byte[] Pack_8Byte_BigEndian_ByteArray() { byte[] TxMsg = new byte[8]; - Packer.TxSignalPack(ref TxMsg, 0, EightByte_BigEndian_Signal1); - Packer.TxSignalPack(ref TxMsg, 63, EightByte_BigEndian_Signal2); - Packer.TxSignalPack(ref TxMsg, 0, EightByte_BigEndian_Signal3); - Packer.TxSignalPack(ref TxMsg, ushort.MaxValue, EightByte_BigEndian_Signal4); + Packer.TxSignalPack(TxMsg, 0, EightByte_BigEndian_Signal1); + Packer.TxSignalPack(TxMsg, 63, EightByte_BigEndian_Signal2); + Packer.TxSignalPack(TxMsg, 0, EightByte_BigEndian_Signal3); + Packer.TxSignalPack(TxMsg, ushort.MaxValue, EightByte_BigEndian_Signal4); return TxMsg; } @@ -148,10 +148,10 @@ public ulong Pack_8Byte_LittleEndian_Uint64() public byte[] Pack_8Byte_LittleEndian_ByteArray() { byte[] TxMsg = new byte[8]; - Packer.TxSignalPack(ref TxMsg, 0, EightByte_LittleEndian_Signal1); - Packer.TxSignalPack(ref TxMsg, 63, EightByte_LittleEndian_Signal2); - Packer.TxSignalPack(ref TxMsg, 0, EightByte_LittleEndian_Signal3); - Packer.TxSignalPack(ref TxMsg, ushort.MaxValue, EightByte_LittleEndian_Signal4); + Packer.TxSignalPack(TxMsg, 0, EightByte_LittleEndian_Signal1); + Packer.TxSignalPack(TxMsg, 63, EightByte_LittleEndian_Signal2); + Packer.TxSignalPack(TxMsg, 0, EightByte_LittleEndian_Signal3); + Packer.TxSignalPack(TxMsg, ushort.MaxValue, EightByte_LittleEndian_Signal4); return TxMsg; } @@ -175,7 +175,7 @@ public ulong Pack_1Signal_Unsigned_NoScale_SignalPack() public byte[] Pack_1Signal_Unsigned_NoScale_SignalPackByteArray() { byte[] TxMsg = new byte[8]; - Packer.TxSignalPack(ref TxMsg, 123, LittleEndian_Unsigned_NoScale); + Packer.TxSignalPack(TxMsg, 123, LittleEndian_Unsigned_NoScale); return TxMsg; } } diff --git a/DbcParserLib.Benchmarks/Program.cs b/DbcParserLib.Benchmarks/Program.cs index ab768c3..33f5cf2 100644 --- a/DbcParserLib.Benchmarks/Program.cs +++ b/DbcParserLib.Benchmarks/Program.cs @@ -15,7 +15,7 @@ .NET SDK 8.0.200 | Method | Mean | Error | StdDev | |-------------------------------------------------- |------------:| ----------:| ----------:| | Pack_8Byte_BigEndian_Uint64 | 40.5778 ns | 0.3100 ns | 0.2420 ns | -| Pack_8Byte_BigEndian_ByteArray | 167.4555 ns | 2.3924 ns | 2.2379 ns | +| Pack_8Byte_BigEndian_ByteArray | 126.9214 ns | 2.5612 ns | 2.3958 ns | | Pack_8Byte_LittleEndian_Uint64 | 12.1883 ns | 0.1173 ns | 0.0980 ns | | Pack_8Byte_LittleEndian_ByteArray | 100.1948 ns | 0.6864 ns | 0.5359 ns | | Pack_1Signal_Unsigned_NoScale_StatePack | 0.8825 ns | 0.0081 ns | 0.0068 ns | diff --git a/DbcParserLib.Tests/PackerTests.cs b/DbcParserLib.Tests/PackerTests.cs index 5ef3fc7..e2c9cc3 100644 --- a/DbcParserLib.Tests/PackerTests.cs +++ b/DbcParserLib.Tests/PackerTests.cs @@ -191,10 +191,10 @@ public void SimplePackingMultiPackBigEndian() Assert.AreEqual(18446462598732857088, TxMsg); byte[] txMsg = new byte[8]; - Packer.TxSignalPack(ref txMsg, 0, sig1); - Packer.TxSignalPack(ref txMsg, 63, sig2); - Packer.TxSignalPack(ref txMsg, 0, sig3); - Packer.TxSignalPack(ref txMsg, ushort.MaxValue, sig4); + Packer.TxSignalPack(txMsg, 0, sig1); + Packer.TxSignalPack(txMsg, 63, sig2); + Packer.TxSignalPack(txMsg, 0, sig3); + Packer.TxSignalPack(txMsg, ushort.MaxValue, sig4); Assert.AreEqual(18446462598732857088, BitConverter.ToUInt64(txMsg)); } diff --git a/DbcParserLib/Packer.cs b/DbcParserLib/Packer.cs index 7292032..54fa899 100644 --- a/DbcParserLib/Packer.cs +++ b/DbcParserLib/Packer.cs @@ -34,24 +34,16 @@ public static uint64_T TxSignalPack(double value, Signal signal) /// A ref to the byte array containing the message /// Value to be packed /// Signal containing dbc information - /// Due to needing to reverse the byte array when handling BigEndian(Motorola) format this method can not be called in parallel for multiple signals in one message. - /// To make this obvios the message is a ref and is actually reassigned after handling BigEndian format. - public static void TxSignalPack(ref uint8_T[] message, double value, Signal signal) + public static void TxSignalPack(uint8_T[] message, double value, Signal signal) { int64_T iVal = TxPackApplySignAndScale(value, signal); // Pack signal if (!signal.Intel()) { - var tempArray = new uint8_T[message.Length]; - Array.Copy(message, tempArray, message.Length); - Array.Reverse(tempArray); - - WriteBits(tempArray, unchecked((uint64_T)iVal), GetStartBitLE(signal, message.Length), signal.Length); - - Array.Reverse(tempArray); - - message = tempArray; + Array.Reverse(message); + WriteBits(message, unchecked((uint64_T)iVal), GetStartBitLE(signal, message.Length), signal.Length); + Array.Reverse(message); return; } WriteBits(message, unchecked((uint64_T)iVal), signal.StartBit, signal.Length); From 614a69af3ce1d4316571859fd1f41fe6ff4f7eeb Mon Sep 17 00:00:00 2001 From: Uight Date: Sat, 10 Aug 2024 16:50:17 +0200 Subject: [PATCH 13/14] add byte packing testcases to existing testcases --- DbcParserLib.Tests/PackerTests.cs | 85 ++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/DbcParserLib.Tests/PackerTests.cs b/DbcParserLib.Tests/PackerTests.cs index e2c9cc3..2589e6e 100644 --- a/DbcParserLib.Tests/PackerTests.cs +++ b/DbcParserLib.Tests/PackerTests.cs @@ -24,6 +24,14 @@ public void SimplePackingTestSigned() var val = Packer.RxSignalUnpack(txMsg, sig); Assert.AreEqual(-34.3, val, 1e-2); + + + var byteMsg = new byte[8]; + Packer.TxSignalPack(byteMsg, - 34.3, sig); + Assert.AreEqual(43816, BitConverter.ToUInt64(byteMsg)); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(-34.3, valbyte, 1e-2); } [TestCase((ushort)0, 3255382835ul)] @@ -48,6 +56,14 @@ public void FloatLittleEndianValuePackingTest(ushort start, ulong packet) var val = Packer.RxSignalUnpack(txMsg, sig); Assert.AreEqual(expected, val, 1e-2); + + + var byteMsg = new byte[8]; + Packer.TxSignalPack(byteMsg, expected, sig); + Assert.AreEqual(packet, BitConverter.ToUInt64(byteMsg)); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(expected, valbyte, 1e-2); } [TestCase((ushort)0, 439799153665ul)] @@ -72,6 +88,14 @@ public void FloatBigEndianValuePackingTest(ushort start, ulong packet) var val = Packer.RxSignalUnpack(txMsg, sig); Assert.AreEqual(value, val, 1e-2); + + + var byteMsg = new byte[8]; + Packer.TxSignalPack(byteMsg, value, sig); + Assert.AreEqual(packet, BitConverter.ToUInt64(byteMsg)); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(value, valbyte, 1e-2); } [Test] @@ -93,6 +117,14 @@ public void DoubleLittleEndianValuePackingTest() var val = Packer.RxSignalUnpack(txMsg, sig); Assert.AreEqual(expected, val, 1e-2); + + + var byteMsg = new byte[8]; + Packer.TxSignalPack(byteMsg, expected, sig); + Assert.AreEqual(13853404129830452697, BitConverter.ToUInt64(byteMsg)); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(expected, valbyte, 1e-2); } [Test] @@ -114,6 +146,14 @@ public void DoubleBigEndianValuePackingTest() var val = Packer.RxSignalUnpack(txMsg, sig); Assert.AreEqual(expected, val, 1e-2); + + + var byteMsg = new byte[8]; + Packer.TxSignalPack(byteMsg, expected, sig); + Assert.AreEqual(2419432028705210816, BitConverter.ToUInt64(byteMsg)); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(expected, valbyte, 1e-2); } [Test] @@ -190,6 +230,7 @@ public void SimplePackingMultiPackBigEndian() Assert.AreEqual(18446462598732857088, TxMsg); + byte[] txMsg = new byte[8]; Packer.TxSignalPack(txMsg, 0, sig1); Packer.TxSignalPack(txMsg, 63, sig2); @@ -217,6 +258,14 @@ public void PackingTest64Bit() var val = Packer.RxSignalUnpack(txMsg, sig); Assert.AreEqual(396.31676720860366, val); + + + var byteMsg = new byte[8]; + Packer.TxSignalPack(byteMsg, 396.31676720860366, sig); + Assert.AreEqual(3963167672086036480, BitConverter.ToUInt64(byteMsg)); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(396.31676720860366, valbyte); } //Although Pack has one output per value/signal. Unpack can produce the same result for two different RxMsg64 inputs @@ -241,6 +290,17 @@ public void UnPackingTestMultipleUnpacks() val = Packer.RxSignalUnpack(9655716608953581040, sig); Assert.AreEqual(8, val); + + + var byteMsg = new byte[8]; + Packer.TxSignalPack(byteMsg, 8, sig); + Assert.AreEqual(9583660007044415488, BitConverter.ToUInt64(byteMsg)); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(8, valbyte); + + valbyte = Packer.RxSignalUnpack(BitConverter.GetBytes(9655716608953581040), sig); + Assert.AreEqual(8, valbyte); } //A bit packing test with a length of 1 (to test signals with < 8 bits) @@ -265,11 +325,21 @@ public void BitPackingTest1() val = Packer.RxSignalUnpack(140737488617472, sig); Assert.AreEqual(1, val); + + + var byteMsg = new byte[8]; + Packer.TxSignalPack(byteMsg, 1, sig); + Assert.AreEqual(262144, BitConverter.ToUInt64(byteMsg)); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(1, valbyte); + + valbyte = Packer.RxSignalUnpack(BitConverter.GetBytes(140737488617472), sig); + Assert.AreEqual(1, valbyte); } - //A bit packing test with a length of 3 (to test signals with < 8 bits) [Test] - public void BitPackingTest2() + public void UnsignedPackingTest() { var sig = new Signal { @@ -289,6 +359,17 @@ public void BitPackingTest2() val = Packer.RxSignalUnpack(498806260540323729, sig); Assert.AreEqual(6, val); + + + var byteMsg = new byte[8]; + Packer.TxSignalPack(byteMsg, 6, sig); + Assert.AreEqual(384, BitConverter.ToUInt64(byteMsg)); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(6, valbyte); + + valbyte = Packer.RxSignalUnpack(BitConverter.GetBytes(498806260540323729), sig); + Assert.AreEqual(6, valbyte); } } } \ No newline at end of file From a0622892bdfce4e19f128e7501a172c4c6e72bed Mon Sep 17 00:00:00 2001 From: Uight Date: Sat, 10 Aug 2024 17:44:58 +0200 Subject: [PATCH 14/14] Add byte packing tests for lengths != 8 --- DbcParserLib.Tests/PackerTests.cs | 96 +++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/DbcParserLib.Tests/PackerTests.cs b/DbcParserLib.Tests/PackerTests.cs index 2589e6e..b12d6d5 100644 --- a/DbcParserLib.Tests/PackerTests.cs +++ b/DbcParserLib.Tests/PackerTests.cs @@ -371,5 +371,101 @@ public void UnsignedPackingTest() valbyte = Packer.RxSignalUnpack(BitConverter.GetBytes(498806260540323729), sig); Assert.AreEqual(6, valbyte); } + + [Test] + public void BytePackingBigEndianSmaller8Byte() + { + var messageLength = 5; + + var sig = new Signal + { + Length = 12, + StartBit = 13, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + var byteMsg = new byte[messageLength]; + + Packer.TxSignalPack(byteMsg, 4095, sig); + Assert.AreEqual(byteMsg, new byte[] { 0, 63, 252, 0, 0 }); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(4095, valbyte); + } + + [Test] + public void BytePackingLittleEndianSmaller8Byte() + { + var messageLength = 5; + + var sig = new Signal + { + Length = 12, + StartBit = 26, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + var byteMsg = new byte[messageLength]; + + Packer.TxSignalPack(byteMsg, 4095, sig); + Assert.AreEqual(byteMsg, new byte[] {0, 0, 0, 252, 63}); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(4095, valbyte); + } + + [Test] + public void BytePackingBigEndianBigger8Byte() + { + var messageLength = 24; + + var sig = new Signal + { + Length = 12, + StartBit = 138, + ValueType = DbcValueType.Unsigned, + ByteOrder = 0, + Factor = 1, + Offset = 0 + }; + + var byteMsg = new byte[messageLength]; + + Packer.TxSignalPack(byteMsg, 4095, sig); + Assert.AreEqual(byteMsg, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 255, 128, 0, 0, 0, 0 }); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(4095, valbyte); + } + + [Test] + public void BytePackingLittleEndianBigger8Byte() + { + var messageLength = 24; + + var sig = new Signal + { + Length = 12, + StartBit = 138, + ValueType = DbcValueType.Unsigned, + ByteOrder = 1, + Factor = 1, + Offset = 0 + }; + + var byteMsg = new byte[messageLength]; + + Packer.TxSignalPack(byteMsg, 4095, sig); + Assert.AreEqual(byteMsg, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 63, 0, 0, 0, 0, 0 }); + + var valbyte = Packer.RxSignalUnpack(byteMsg, sig); + Assert.AreEqual(4095, valbyte); + } } } \ No newline at end of file