eferu / dbcparser Goto Github PK
View Code? Open in Web Editor NEW.NET CAN bus dbc file parser
License: MIT License
.NET CAN bus dbc file parser
License: MIT License
"BA_DEF_DEF_: Attribute default definition. Specifies the default value for the attribute if none is given."
This means that the CycleTime should be initialized with the DefaultCycleTime if there is no definition for the CycleTime of a specific message
After parsing a dbc, the user gets a list of messages. Each message contains i.a. the CycleTime, although there is no information as to whether the value of the CycleTime was set by the class initialization or by an entry in the dbc. The DefaultCycleTime is available as a CustomProperty. Information about the decision criterion as to whether the CycleTime must be overwritten with the DefaultCycleTime "...Specifies the default value for the attribute if none is given." is not present. If you do not allow the value 0 as a valid CycleTime, you can check the CycleTime for the value 0 to get this information, since the CycleTime is set to the value 0 via the class initialization. If it contains any other value, there must have been an entry for the CycleTime of that message in the dbc. But I would like to allow the value 0 as a valid CycleTime. Perhaps the parser could first initialize each message with the DefaultCycleTime. If there is still an entry for a specific CycleTime in the DBC, the CycleTime can be overwritten with it. This would of course be easier for the user of the DbcParserLib, but the question arises as to how much logic the parser should contain. Otherwise it would be great if the Message class would contain a flag indicating whether there was an entry for the CycleTime. Thanks in advance.
Best regards,
Sebastian
Multiline comments for signals are possible, currently not supported
A
Hi guys,
i get an int32-overflow exception in case if i want to parse an dbc-file containing an unsigned integer variable with max value = 4294967295
Maybe the parser does not consider the sign of a valiable in this mehtod: "SetCustomPropertyValue" (CustomProperty.cs)
Today we do silently swallow errors when parsing.
My idea is to provide an optional IParsingObserver
which will allow user to react (or at least know!) to errors.
Quick example
public interface IParseObserver
{
void DuplicateMessage(int messageId);
void DuplicateSignalInMessage(int messageId, string signalName);
void DuplicateValueTableKey(double key, string value);
// etc...
}
public class StrictParseObserver : IParseObserver
{
public void DuplicateMessage(int message)
{
// This implementation is just an example
// The idea is that the parsing here will stop and fail
throw new ParsingException($"More than one message in dbc is defined with ID {message}, which does not follow the official spec");
}
// Etc...
}
// We could also provide an implementation that does nothing, like today
public class SilentParseObserver : IParseObserver
{
public void DuplicateMessage(int message)
{
}
// Etc...
}
// But a user could inject something custom like this
public class StrictParseObserver : IParseObserver
{
public void DuplicateMessage(int message)
{
// I don't want to break, I just want to log the issue to create a report
Console.WriteLine($"More than one message in dbc is defined with ID {message}, which does not follow the official spec");
}
// Etc...
}
Hope you get the idea.
A
As the title
I use a2lparser to parse a2l files, but the library is written in java and cannot be called well in .net
I would like to have a ApplyLimit function in the Packer to limit the values send to TxPack or limit the values received from RxUnpack.
The problem is that it is a bit unclear how you would implement this.
If both limits are 0 the limiter is anactive but i dont realy want to check for that everytime. i would like one of the following options:
I would like to see the Messages property of the DBC class to be set as a Dictionary to improve lookup.
Another option would be to add a Get method that would use an internal dictionary.
Another suggestions is to add the ValueTable as a dictionary as a complement to the string. That would simplify mapping values to descriptions.
Hi @Adhara3 ,
Is there a reason why we made the Parser
class and methods static:
DbcParser/DbcParserLib/Parser.cs
Lines 7 to 9 in a47d31f
This will prevent for doing somethig like this:
Parser dbc = new Parser(); // user cannot do `new` on static classes
dbc.ParseFromPath(filePath);
instead the user needs to do:
Dbc dbc = Parser.ParseFromPath(filePath);
I am not sure if it has any impact on flexibility at the user side. Let me know what is your opinion.
Hello,
I wanted to bring to your attention an issue I recently discovered with the signal value table in some dbc files.
It appears that the contents of the dbc file are not parsing properly, and they seem somewhat weird.
The syntax of the dbc file does not necessarily consist of just one line, which seems to be causing problems with line-level parsing with Regex.
Here's an example:
VAL_ 134 TEST_BuckleSwitch 0 "Buckled " 1 " Unbuckle " 2 "Not Used" 3 "Not Used
Default value: 0x0";
I noticed that this dbc file is written over two lines, and it's actually being used. Unfortunately, this syntax is also parsed correctly in Vector CANdb++.
Could you please consider including improvements in this area in your plans? If not, should we provide guidance to writers on writing the dbc file accurately, line by line?
Your assistance in addressing this matter would be greatly appreciated.
Thank you for your time and attention.
Hi, I'm facing a problem when importing DBCs, hwere the minumum and Maximum values of a custom attributes are set to 0. I'm working with the Vector CANDB++ Editor. The Editor ignores the validation of min max values for custom properties, when both are set to 0, and accept all Default values.
When importing such DBCs the DBCParser library returns 0 in such cases. Would it be possible to also ignore min/max validation by a setting or default behavior?
Best regards and you do a fantastic job,
Julius
It seems that ValueTables can not be parsed for messages with extended id's.
Example:
`BO_ 2566896411 ACSmessage1_L: 8 ArticulationControl_L
SG_ CurrentLeft : 16|16@1+ (1,0) [0|4092] "" ArticulationControl_L
SG_ FeedbackLeft : 0|16@1+ (1,0) [0|4092] "" ArticulationControl_L
SG_ PropValveLeftError : 48|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ IgnitionRelayNode2Error : 49|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ Master_Slave : 56|2@1+ (1,0) [0|3] "" Vector__XXX
SG_ PropValveLeftShortCircuit : 50|1@1+ (1,0) [0|0] "" Vector__XXX
VAL_ 2566896411 PropValveLeftError 0 "False" 1 "True" 2 "Error" ;
VAL_ 2566896411 IgnitionRelayNode2Error 0 "False" 1 "True" ;
VAL_ 2566896411 Master_Slave 0 "Node2Slave" 1 "NotDefined" 2 "Node2Master" 3 "NotDefined" ;
VAL_ 2566896411 PropValveLeftShortCircuit 0 "False" 1 "True" ;`
I think the check for extendeded id is missing in the LinkTableValuesToSignal
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.
Similar to issue #7 the signal length also has a chance to be greater than 255. As you can see below we have values of 256 present in the .dbc file. To solve this issue Signal.Length should be changed from a byte to a ushort.
Currently in the target frameworks of the project the following are listed:
netstandard2.0;net461;net5.0;net6.0
i would consider changing it a bit for the following reasons:
net461 is out of support since beginning of 2022 therefor atleast use net462 which is still officialy supported.
net5.0 is out of support;
net6.0 runs out of support this year but is okay for now;
netstandard2.0 is kind of tricky but as its currently supported you would probably keep supporting it.
net framework support:
https://learn.microsoft.com/de-de/lifecycle/products/microsoft-net-framework
.net support:
https://dotnet.microsoft.com/en-us/platform/support/policy
.net standard infos:
https://learn.microsoft.com/en-us/dotnet/standard
https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-1-0#net-5-and-net-standard
I would like to change supported frameworks to:
netstandard2.0;net462;net6.0;net8.0
How do I enable the new regex parsing feature? Do I have to use the source code or is there a way to do it with v1.3.0 as compiled? Right now the SignalLineParser, at least, is not using the regex parsing by default. I've found that some DBC files will not parse properly. For example, if there is no space between the signal name and the ":" character then an exception is thrown. A quick test with an online regex tester shows that this issue won't happen with the regex parsing. Would be nice if Parser.ParseFromPath or similar methods had a parameter that allowed the caller to specify whether to parse using regex.
It is also possible for a multiplexor signal to be multiplexed!
The logic already implemented in the parser library doesn't allow that.
The following JSON shows how this information can be a part of a Multiplexor Signal.
{
"ID": 128,
"Name": "XCP1_Dummy_TX",
"CANNetwork": 3,
"CycleTime": 0,
"Signals": [
{
"ID": 128,
"Name": "XCP1_TX_Data",
"StartBit": 7,
"Length": 64,
"ByteOrder": 0,
"IsSigned": 1,
"InitialValue": 0.0,
"Factor": 1.0,
"IsInteger": true,
"Offset": 0.0,
"Minimum": 0.0,
"Maximum": 0.0,
"Unit": "",
"Receiver": [
"Vector__XXX"
],
"ValueTable": null,
"Comment": null,
"Multiplexor": false/true, <----- Is this signal a Multiplexor?
"Multiplexed":
{
"Multiplexor":"Multiplexor Signal Name", <-------- The name of the multiplexor signal
"Value": 0X0 <----- The Value of the Signal
}
}
]
}
Further information about Extended Multiplexing can be found here ->
When parsing the following line in a DBC file
VAL_ 1234 Signal_Name 0 "24h" 1 " 12h AM/PM" ;
an exception is thrown from the ExtensionsAndHelpers.ToDictionary.
The code
var valueTable = match.Groups[4].Value.TrimStart().Replace("" ", """ + Environment.NewLine);
in ValueTableLineParser.TryParse replaces space between 12h by the new line and it causes an exception.
Is there a chance we can look into being able to read multiple .dbc files and store them inside one Dbc object?
Currently Parser.cs doesn't have a function that achieves this https://github.com/EFeru/DbcParser/blob/main/DbcParserLib/Parser.cs
Below I've made a work around of sort but it's not optimal. If we could possibly look into this that would be great thanks!
string[] fileNames = Directory.GetFiles(DBC_FILES_PATH, "*.dbc");
File.WriteAllLines(DBC_PATH, fileNames.SelectMany(file => File.ReadLines(file)));
dbc = Parser.ParseFromPath(DBC_PATH);
Hello,
I wanted to parse dbc messages from a .dbc file in ASP.NET project using your dbc parser. I have a line in my dbc file like bellow:
BA_ "GenSigStartValue" SG_ 2364604659 PDU_Act_VehicleSoH 637.5;
According to: reference on http://mcu.so/Microcontroller/Automotive/dbc-file-format-documentation_compress.pdf
Meaning of that line:
'BA_' attribute_name 'SG_' message_id signal_name attribute_value ';' ;
According to documentation, attribute_value could be float.
attribute_value = unsigned_integer | signed_integer | double | char_string; (http://mcu.so/Microcontroller/Automotive/dbc-file-format-documentation_compress.pdf)
but I was unable to get the value of GenSigStartValue as 637.5.
Using release 1.3.3, I got an exception ("Input string was not in a correct format").
Using latest release 1.4.2, I got the value of GenSigStartValue as 0(which is not desirable).
Could you please suggest me how to overcome this problem?
Advance thank you.
#17 Is still not fixed both line 64 and 97 in SignalLineParser.cs need to be changed to ushort.Parse instead of byte.Parse
DbcParser
: move the Message and Signal class into Model folderCurrently the only values that can be pulled for the message class are the ID, ExtID, Name, DLC, Transmitter, Comment, Cycle time and the list of signals.
Though there is a chance a .dbc will have additional columns/values in the case of the j1939.dbc file below there is an additional column for the PGN value of the message titled PGN Decimal
I propose that an additional variable is added to the Message class so all values for a message can be read regardless of the .dbc file. In this case perhaps we can have a list of strings that contains each column of the message? This future proofs and allows us to extract all the data for each message regadless of the dbc file.
I ask for this change as PGNs are important in the decoding process of J1939 messages. I would propose a PGN variable for the Message class but as PGNs are specifically for the J1939 protocol and aren't present in standard CAN it would be unfeasible
So Packer.RxSignalUnpack can produce incorrect values for example I have the following byte array using this code snippet:
//bytearray = D1-00-00-FF-FF-1F-66-7E
var receivedBytes = BitConverter.ToUInt64(dataBytes, 0);
resolvedSpnValue = Packer.RxSignalUnpack(receivedBytes, signal);
I then have these decoding rules highlighted in blue:
So looking at the decoding rules we are looking at the 7th byte which is 66. So 66 hex equals 102 in decimal which is 102 x 0.4 when decoded which is 40.8 exactly. Which is not produced by Packer.RxSignalUnpack it acutally gives a value of 40.800000000000004 which is incorrect. I've only just found this bug but I will dig deeper
Hi,
I am not a huge regex fan, but I have to admit that this line parsing really looks like a regex playground.
Some reasons, not in priority order:
string.Split
does allocate arrays. Not a big deal, but....Substring
, .Join
.Trim
all create other strings, often just temporary\s
works for both " "
and "\t"
)There are scenarios where the string.Split
is a bit tricky, e.g.
SG_ DAS_steeringControlType : 23|2@0+ (1,0) [0|0] "" EPAS,TEST
supports multiple receivers, BUT in Vector CANdb++ this is also supported
SG_ DAS_steeringControlType : 23|2@0+ (1,0) [0|0] "" EPAS, TEST
with a spacing after the comma. This breaks current implementation.
I will try to add a benchmark project in the solution just to make sure performances do not dramatically drop.
I will provide a separate PR for this item so that you can evaluate other aspects like readability.
Moreover, for this kind of refactorings having unit tests is a must.
Cheers
A
While parsing a DBC file at my work using this parser library I realized that this library doesn't support parsing of "SendType" for both Signal and Message. For our particular project we are using this information from the DBC file. So, I modified this library a bit and added a "SendType Parser" that gives the assigned "SendType" information for each Message and Signal otherwise it will return default value as "Cyclic".
The available send types are defined in the DBC at:
BA_DEF_ BO_ "GenMsgSendType" ENUM "Cyclic","Event","NotUsed","NotUsed","NotUsed","NotUsed","NotUsed","IfActive","NoMsgSendType","NotUsed","NotUsed","NotUsed","vector_leerstring";
These can change from DBC to DBC for example the following is also possible:
"cyclic","triggered","cyclicIfActive","cyclicAndTriggered","cyclicIfActiveAndTriggered","none"
The Message "Send Type" can be found here:
BA_ "GenMsgSendType" BO_ 1424 7;
Where "BO_ 1424" is the id of the message and "7" is the Enum value
If a message has no definition of BA_ "GenMsgSendType" BO_ XXXX X we should use the default value which is defined here:
BA_DEF_DEF_ "GenMsgSendType" "Cyclic";
Also each signal can also have a "SendType" Information that can be found here:
BA_DEF_ SG_ "GenSigSendType" ENUM "Cyclic","OnWrite","OnWriteWithRepetition","OnChange","OnChangeWithRepetition","IfActive","IfActiveWithRepetition","NoSigSendType","OnChangeAndIfActive","OnChangeAndIfActiveWithRepetition","NotUsed","NotUsed","NotUsed";
BA_ "GenSigSendType" SG_ 1424 SeatControlCommand1 8;
SeatControlCommand1 is the Signal Name and "8" is the ENUM value.
If this entry is not present the default value shall be used:
BA_DEF_DEF_ "GenSigSendType" "Cyclic";
What good timing I'm facing an issue with signed signals while trying to unpack messages using the packer class.
Here's an extract of the .dbc I'm using: https://drive.google.com/file/d/1RJc9zE_VEt6jdlhrABVl-E-nyLOPOi5l/view?usp=share_link
The main things to keep note of are the Latitude, Longitude and Altitude signals (which are all signed). No matter what I feed to the
Packer.RxSignalUnpack
function the value returned is 0 for all 3 signals.
Maybe this is because the factor used for them is in scientific notation instead of a decimal? i.e for Latitude the Factor is 1e-16
@Adhara3 Hopefully the .dbc file extract helps you in solving this issue
Originally posted by @taylorjdlee in #3 (comment)
Line in dbc file:
BA_DEF_ BO_ "GenMsgSendType" ENUM "Cyclic","Event","CyclicIfActive","SpontanWithDelay","CyclicAndSpontan";
Propose fix in PropertiesDefinitionLineParser.cs:
Line 16:
Add:
private readonly char[] PropertySeparatorChar = { ' ' };
Line 92:
Replace:
var enumDefinition = match.Groups[10].Value.Replace("\"", "").Split(' ')[1];
By:
var enumDefinition = match.Groups[10].Value.Replace("\"", "").Split(PropertySeparatorChar, StringSplitOptions.RemoveEmptyEntries)[1];
On version 1.0.6, i noticed the initial value and maybe some other attributes like message cycle time is not parsed from the CAN db at all, all is 0.
On version 1.0.5 it still work for me.
I have a question, The INextLineProvider type is not used in ILineParser type ,so why TryParse function has a type of INextLineProvider parameter , is for what ?
Descriptions that contain space in value tables are not parsed proparly.
Example
VAL_ 2566843904 Temp5 10 "Description for 10";
This is can not be handled since the ValueTableLineParser splits the line by space.
Hi,
when parsing a signal the multiplexed info are lost, and this make impossible to eventually work with correct message layout.
Cheers
A
DbcParser/DbcParserLib/Extensions.cs
Line 64 in 59b4eb6
Due to using the any() method IsMultiplexed() can take sometime to run if there are a lot of signals present in the message. It would be great if we could have a simple boolean in the message that means we don't have to iterate across every signal to improve the runtime of this function.
But I also think it's down to the runtime of MultiplexingInfo
DbcParser/DbcParserLib/Extensions.cs
Line 45 in 59b4eb6
Pretty much I want IsMultiplexed() to be efficient as possible due to using this library to decode data at runtime. Maybe the message class can even have a boolean value stored that does this? Pretty much when we initialise a message when loading from the .dbc we run the IsMultiplexed() function once to generate this boolean value
Hi!
I have a DBC file with a message with a "large" dlc and with a signal that has startbit 256
BO_ 200 SENSOR_SONARS: 39 SENSOR
SG_ SENSOR_SONARS_no_filt_rear m1 : 256|6@1+ (0.1,0) [0|0] "" DBG
This can not be loaded by the library.
Any plans of supporting this?
I copied the relevant lines from a sample J1939 file:
BO_ 2364540158 EEC1: 8 Vector__XXX
SG_ EngineSpeed : 24|16@1+ (0.125,0) [0|8031.875] "rpm" Vector__XXX
BA_DEF_ BO_ "VFrameFormat" ENUM "StandardCAN","ExtendedCAN","reserved","J1939PG";
BA_DEF_DEF_ "VFrameFormat" "J1939PG";
BA_ "VFrameFormat" BO_ 2364540158 3;
It seems the enum value for the message is specified by an integer index into the enum definition.
The current implementation just assumes a string value and copies the index as value into the property.
I couldn't find any solid information how enum values are supposed to be specified, but this is the way CANdb++ writes the dbc file.
I will try to provide a PR to handle this correctly.
While trying to address issue #7 I decided to try building the library with netcoreapp3.1 and it does build successfully. This is as the project I'm using the library on uses the netcoreapp3.1 framework
Should be a simple addition to the framework section of the DbcParserLib.csproj
Hi,
as already mentioned, I would like to add this feature based on the SIG_VALTYPE_
tag.
I will take care of adding it once we are done with the refactoring.
I just wanted to share a related discussion here. Signal.IsSigned
as of today is of type byte
. This is strange, given that usually a property name starting with 'is' usually identifies a bool
. However, adding floating point values make the IsSigned
property obsolete, since it has no meaning for floating points.
My suggestion is to remove the IsSigned
property and replace it by a ValueType
property, defined as follows:
public class Signal
{
// ...
public DbcValueType ValueType { get; }
// ...
}
public enum DbcValueType
{
Signed, Unsigned, IEEEFloat, IEEEDouble
}
this follows what happens in Vector CANdb++ editor which I usually take as a reference given the fact Vector is DBC "father".
What do you think about it?
Cheers
A
Hi there,
there are dbc files which define global attributes or network attributes, e.g.
...
BA_DEF_ "Baudrate" INT 0 1000000;
...
BA_DEF_DEF_ "Baudrate" 500000;
...
When parsed, this attribute is added to all nodes' CustomProperties in Dbc.Nodes. However, each node may have unique Node attributes (defined with BA_DEF_ BU_
) themselves. Now each node has CustomProperties which may contain Network and Node attributes. If I didn't miss any property/method, there is no way to distinguish between those two.
One way to accomplish this would be a CustomProperties property on Dbc root level.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.