Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading / Decoding does not respect / account for signal multiplexing. #44

Open
tylerbucher opened this issue Jan 24, 2023 · 5 comments
Assignees
Labels
enhancement New feature or request

Comments

@tylerbucher
Copy link
Contributor

Is your feature request related to a problem? Please describe.
When attempting to decode a multiplexed signal (like OBDII) all signals are attempted to be decoded and returned.

Describe the solution you'd like
when decoding a multiplexed can frame the only signal(s) returned should be the multiplexed ones.
Example:

DBC FILE:
BO_ 2024 OBD2: 8 Vector__XXX
 SG_ S1_PID_00_VehicleSpeed m1 : 31|8@0+ (1,0) [0|255] "km/h" Vector__XXX
 <... 253 other pids>
 SG_ S1_PID_255_ThrottlePosition m255 : 31|8@0+ (0.39216,0) [0|100] "%" Vector__XXX

CAN FRAME:
7E8   03 41 FF 30 FF FF FF FF

when decoding the only signal(s) returned should be SG_ S1_PID_255_ThrottlePosition.

Describe alternatives you've considered
I was on the fence of not even using dbc decoding. however since i would also have to decode dbc files it makes sense to just contribute here and not re invent the wheel.

Additional context
Here is a very good explanation form csselectronics.com

Multiplexing is sometimes used in CAN bus communication, with perhaps the most known example being within OBD2 communication. Consider for example the below OBD2 response frames:

7E8   03 41 11 30 FF FF FF FF
7E8   03 41 0D 37 FF FF FF FF

Here, both response frames carry 1 byte of data in byte 3, yet despite the CAN ID being identical, the interpretation of the data differs between the two frames. This is because byte 2 serves as a multiplexer, specifying which OBD2 PID the data is coming from.

To handle this in a DBC file context, the below syntax can be applied:

BO_ 2024 OBD2: 8 Vector__XXX
 SG_ S1_PID_0D_VehicleSpeed m13 : 31|8@0+ (1,0) [0|255] "km/h" Vector__XXX
 SG_ S1_PID_11_ThrottlePosition m17 : 31|8@0+ (0.39216,0) [0|100] "%" Vector__XXX
 SG_ S1 m1M : 23|8@0+ (1,0) [0|255] "" Vector__XXX
 SG_ Service M : 11|4@0+ (1,0) [0|15] "" Vector__XXX
...
SG_MUL_VAL_ 2024 S1_PID_0D_VehicleSpeed S1 13-13;
SG_MUL_VAL_ 2024 S1_PID_11_ThrottlePosition S1 17-17;
SG_MUL_VAL_ 2024 S1 Service 1-1;

Here, the M in the Service signal serves as the 'multiplexor signal'. In this case, it toggles which OBD2 service mode is used (mode 01, 02, ...). The signal S1 is multiplexed by Service, which is evident from the SG_MUL_VAL_ field where the two are grouped.

As evident, the signal S1 has the value m1 after the signal name, which means that if the Service signal takes the value 1, the data reflects the OBD2 service mode 01.

The above is referred to as simple multiplexing. But CAN DBC files also support extended multiplexing, where a multiplexed signal (in this case S1) can also be a multiplexor and thus control the interpretation of other parts of the data payload. To see this, note that S1 takes the same role as Service in the syntax, adding an M after m1 and being grouped with the two OBD2 PIDs, speed and throttle position.

Extended multiplexing works as before: If S1 takes the value 13 (HEX 0D), it means that only signals that are A) part of the S1 group and B) have a multiplexer switch value of 13 should be taken into account. In this example, it means that byte 4 reflects data for vehicle speed. If byte 3 equals 17 (HEX 11), byte 4 reflects data for the throttle position instead.

@tylerbucher
Copy link
Contributor Author

@bit-dream I do not mind making a pr to fix this issue, however would love to hear your thoughts / feedback first.

@bit-dream
Copy link
Owner

@agent6262 Great writeup on the current multiplexing issue. It was always my intent to support both simple and extended multiplexing, I just have not gotten around to actually implementing it yet.

Here's another reference to multiplexing written up by Vector themselves as an addition to the already good sources you posted:
https://cdn.vector.com/cms/content/know-how/_application-notes/AN-ION-1-0521_Extended_Signal_Multiplexing.pdf

In terms of making a PR to actually fix the issue, I'm more than happy to let you take on the challenge.

Some of my initial thoughts:

  1. Currently SG_MUL_VAL_ is not actually parsed from DBC files. Should be simple enough as the structure is well defined. What that will mean is modification of the grammar.peg file in the parser_generator folder. We'll need to add something like SigMulVal as an available 'choice' in that file (this will setup the Typescript type), then you can define the regex for how it will extract that information. TSPeg allows you to import functions to use as helpers, so there is a parserHelpers.ts file in the parser folder where helpful utility functions can be made for whatever your use case is.
  2. We'll need to extend the dbcParser.ts file to support the SG_MUL_VAL_ type. TSPeg will generate a parser.ts file in the parser folder, which is created from that .peg file. parser.ts will return type found (SigMulVal vs Message vs Signal, etc) and the parsed content based on that type. dbcParser takes that type and data and transforms/puts that data into the dbc data that the end user will use and reference.
  3. We may need to modify the existing Signal type (see below). Right now it only has the multiplex property, which is just the full multiplex string i.e. 'M', 'm122', etc. I haven't thought through how that looks (or if it even needs to change) to properly do multiplex decoding, but will need to be looked into.
export type Signal = {
  name: string;
  multiplex: string | null;
  startBit: number;
  length: number;
  endian: EndianType;
  signed: boolean;
  factor: number;
  offset: number;
  min: number;
  max: number;
  unit: string;
...
  1. Actual modifying the decode method to handle the multiplexing.

I'm not sure how much of this you want to tackle. You are more than welcome to take on the entire thing. If you are wanting some support, I can help out where needed (for instance if you are not comfortable with TSPeg and want me to handle that aspect of it I can).

In general, I'm pretty flexible when it comes to this project. Modify what you need to modify, change/rearrange what you need to, to get the feature working.

@bit-dream bit-dream added bug Something isn't working enhancement New feature or request and removed bug Something isn't working labels Jan 25, 2023
@bit-dream
Copy link
Owner

I went ahead and assigned you to this issue.

Additionally, I made a really quick and dirty .dbc file that does extended multiplexing that uses the simple example in that Vector link I posted above.

Feel free to use your own files for testing if you have better ones, but did want to just throw one out there in case you needed something to test against. (GitHub apparently doesn't allow .dbc extensions, so just posting the code below)

VERSION ""


NS_ : 
	NS_DESC_
	CM_
	BA_DEF_
	BA_
	VAL_
	CAT_DEF_
	CAT_
	FILTER
	BA_DEF_DEF_
	EV_DATA_
	ENVVAR_DATA_
	SGTYPE_
	SGTYPE_VAL_
	BA_DEF_SGTYPE_
	BA_SGTYPE_
	SIG_TYPE_REF_
	VAL_TABLE_
	SIG_GROUP_
	SIG_VALTYPE_
	SIGTYPE_VALTYPE_
	BO_TX_BU_
	BA_DEF_REL_
	BA_REL_
	BA_DEF_DEF_REL_
	BU_SG_REL_
	BU_EV_REL_
	BU_BO_REL_
	SG_MUL_VAL_

BS_:

BU_:


BO_ 2348875518 ExtendedMultiplexMessage: 8 Vector__XXX
 SG_ S6 m2 : 2|4@1+ (1,0) [0|0] "" Vector__XXX
 SG_ S5 m6 : 10|4@1+ (1,0) [0|0] "" Vector__XXX
 SG_ S4 m5 : 10|4@1+ (1,0) [0|0] "" Vector__XXX
 SG_ S3 m4 : 18|4@1+ (1,0) [0|0] "" Vector__XXX
 SG_ S2 m4 : 10|4@1+ (1,0) [0|0] "" Vector__XXX
 SG_ S1 m0M : 2|4@1+ (1,0) [0|0] "" Vector__XXX
 SG_ S0 M : 0|2@1+ (1,0) [0|0] "" Vector__XXX



BA_DEF_ BO_  "SingleFrame" INT 0 1;
BA_DEF_ SG_  "DDI" INT 0 65535;
BA_DEF_ SG_  "SigType" ENUM  "Default","Range","RangeSigned","ASCII","Discrete","Control","ReferencePGN","DTC","StringDelimiter","StringLength","StringLengthControl";
BA_DEF_ SG_  "GenSigEVName" STRING ;
BA_DEF_ SG_  "GenSigILSupport" ENUM  "No","Yes";
BA_DEF_ SG_  "GenSigSendType" ENUM  "Cyclic","OnWrite","OnWriteWithRepetition","OnChange","OnChangeWithRepetition","IfActive","IfActiveWithRepetition","NoSigSendType";
BA_DEF_ BO_  "GenMsgFastOnStart" INT 0 100000;
BA_DEF_ SG_  "GenSigInactiveValue" INT 0 0;
BA_DEF_ BO_  "GenMsgCycleTimeFast" INT 0 3600000;
BA_DEF_ BO_  "GenMsgNrOfRepetition" INT 0 1000000;
BA_DEF_ SG_  "GenSigStartValue" INT 0 10000;
BA_DEF_ BO_  "GenMsgDelayTime" INT 0 1000;
BA_DEF_ BO_  "GenMsgILSupport" ENUM  "No","Yes";
BA_DEF_ BO_  "GenMsgStartDelayTime" INT 0 100000;
BA_DEF_ BU_  "NodeLayerModules" STRING ;
BA_DEF_ BU_  "ECU" STRING ;
BA_DEF_ BU_  "NmJ1939SystemInstance" INT 0 15;
BA_DEF_ BU_  "NmJ1939System" INT 0 127;
BA_DEF_ BU_  "NmJ1939ManufacturerCode" INT 0 2047;
BA_DEF_ BU_  "NmJ1939IndustryGroup" INT 0 7;
BA_DEF_ BU_  "NmJ1939IdentityNumber" INT 0 2097151;
BA_DEF_ BU_  "NmJ1939FunctionInstance" INT 0 7;
BA_DEF_ BU_  "NmJ1939Function" INT 0 255;
BA_DEF_ BU_  "NmJ1939ECUInstance" INT 0 3;
BA_DEF_ BU_  "NmJ1939AAC" INT 0 1;
BA_DEF_ BU_  "NmStationAddress" INT 0 255;
BA_DEF_ BO_  "GenMsgSendType" ENUM  "cyclic","NotUsed","IfActive","NotUsed","NotUsed","NotUsed","NotUsed","NotUsed","noMsgSendType";
BA_DEF_ BO_  "GenMsgRequestable" INT 0 1;
BA_DEF_ BO_  "GenMsgCycleTime" INT 0 3600000;
BA_DEF_ SG_  "SPN" INT 0 524287;
BA_DEF_  "DBName" STRING ;
BA_DEF_  "BusType" STRING ;
BA_DEF_  "ProtocolType" STRING ;
BA_DEF_ BO_  "VFrameFormat" ENUM  "StandardCAN","ExtendedCAN","reserved","J1939PG";
BA_DEF_DEF_  "SingleFrame" 1;
BA_DEF_DEF_  "DDI" 0;
BA_DEF_DEF_  "SigType" "Default";
BA_DEF_DEF_  "GenSigEVName" "Env@Nodename_@Signame";
BA_DEF_DEF_  "GenSigILSupport" "Yes";
BA_DEF_DEF_  "GenSigSendType" "NoSigSendType";
BA_DEF_DEF_  "GenMsgFastOnStart" 0;
BA_DEF_DEF_  "GenSigInactiveValue" 0;
BA_DEF_DEF_  "GenMsgCycleTimeFast" 0;
BA_DEF_DEF_  "GenMsgNrOfRepetition" 0;
BA_DEF_DEF_  "GenSigStartValue" 0;
BA_DEF_DEF_  "GenMsgDelayTime" 0;
BA_DEF_DEF_  "GenMsgILSupport" "Yes";
BA_DEF_DEF_  "GenMsgStartDelayTime" 0;
BA_DEF_DEF_  "NodeLayerModules" "";
BA_DEF_DEF_  "ECU" "";
BA_DEF_DEF_  "NmJ1939SystemInstance" 0;
BA_DEF_DEF_  "NmJ1939System" 0;
BA_DEF_DEF_  "NmJ1939ManufacturerCode" 0;
BA_DEF_DEF_  "NmJ1939IndustryGroup" 0;
BA_DEF_DEF_  "NmJ1939IdentityNumber" 0;
BA_DEF_DEF_  "NmJ1939FunctionInstance" 0;
BA_DEF_DEF_  "NmJ1939Function" 0;
BA_DEF_DEF_  "NmJ1939ECUInstance" 0;
BA_DEF_DEF_  "NmJ1939AAC" 0;
BA_DEF_DEF_  "NmStationAddress" 254;
BA_DEF_DEF_  "GenMsgSendType" "noMsgSendType";
BA_DEF_DEF_  "GenMsgRequestable" 1;
BA_DEF_DEF_  "GenMsgCycleTime" 0;
BA_DEF_DEF_  "SPN" 0;
BA_DEF_DEF_  "DBName" "";
BA_DEF_DEF_  "BusType" "CAN";
BA_DEF_DEF_  "ProtocolType" "ISO11783";
BA_DEF_DEF_  "VFrameFormat" "J1939PG";
BA_ "DBName" "ExtendedMultiplexDbc";
BA_ "VFrameFormat" BO_ 2348875518 3;

SG_MUL_VAL_ 2348875518 S6 S0 2-2;
SG_MUL_VAL_ 2348875518 S5 S1 6-6;
SG_MUL_VAL_ 2348875518 S4 S1 5-5;
SG_MUL_VAL_ 2348875518 S3 S1 4-4;
SG_MUL_VAL_ 2348875518 S2 S1 4-4;
SG_MUL_VAL_ 2348875518 S1 S0 0-0, 1-1;

@bit-dream
Copy link
Owner

Providing some further context on SG_MUL_VAL_ from the Vector documentation:

Extended multiplexing allows defining more than one multiplexer switch within one message. Further it allows the usage of more than one multiplexer switch value for each multiplexed signal.
The extended multiplexing section contains multiplexed signals for which following conditions were fulfilled:
• The multiplexed signal is multiplexed by more than one multiplexer switch value
• The multiplexed signal belongs to a message which contains more than one multiplexor switch

extended multiplexing = {multiplexed signal} ;
multiplexed signal = SG_MUL_VAL_ message_id multiplexed_signal_name multiplexor_switch_name multiplexor_value_ranges ';' ;
message_id = unsigned_integer ;
multiplexed_signal_name = DBC_identifier ;
multiplexor_switch_name = DBC_identifier ; multiplexor_value_ranges = {multiplexor_value_range} ;
multiplexor_value_range = unsigned_integer '-' unsigned_integer ;

Sample:

BO_ 100 MuxMsg: 1 Vector__XXX
  SG_ Mux_4 m2 : 6|2@1+ (1,0) [0|0] "" Vector__XXX 
  SG_ Mux_3 m3M : 4|2@1+ (1,0) [0|0] "" Vector__XXX 
  SG_ Mux_2 m3M : 2|2@1+ (1,0) [0|0] "" Vector__XXX 
  SG_ Mux_1 M : 0|2@1+ (1,0) [0|0] "" Vector__XXX

SG_MUL_VAL_ 100 Mux_2 Mux_1 3-3, 5-10; 
SG_MUL_VAL_ 100 Mux_3 Mux_2 3-3; 
SG_MUL_VAL_ 100 Mux_4 Mux_3 2-2;

Note the line SG_MUL_VAL_ 100 Mux_2 Mux_1 3-3, 5-10; has multiple value ranges. I believe this would indicate that set of switch values that exist for Mux_1 would be [3,5,6,7,8,9,10]

@tylerbucher
Copy link
Contributor Author

Going to keep this open and submit one more pr fixing SG_MUL_VAL_ parsing. There needs to be more tests and I do believe there are edge cases not accounted for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants