Open prj opened 2 years ago
Hi prj,
That looks right, and also explains why enums require EnumType_1E to be zero. Thank you for your time and effort in creating this issue to share this finding!
The little time and effort spent here is nothing compared to the task you have accomplished.
Another thing that might be useful to look at is how floats are encoded.
Considering that for example CR61 is available as both cbf and srmd (and because it's newer, most likely it contains some floats) it might be possible to dump data from both srmd (via dts APIS) and via your tool, and then look at the flags that are set if there is a float datatype. Unfortunately it is not possible to determine the source datatype via dts APIS for Caesar, as they throw an error - seems like the dts API was made with purely srmd in mind.
I'll update this if I get around to it.
P.S. Regarding front page questions: DT_STO_ID_Calibration_Verification_Number - this is a checksum calculated over the CAL area, can be CRC32 or ADD32, or even something more complex on newer ECU's. The algorithm is ECU specific. In some countries (e.g. Germany) it is checked during yearly inspections that the CAL ID and the CVN match an OEM supplied database to prevent chiptuning. However, when CRC or ADD algos are used it is possible to do a CVN fix by forcing collisions.
As far as I understand, floats and decimal values are expressed in Caesar as a SCALE type, which contain an additional multiply and add parameters. This was briefly discussed in https://github.com/jglim/CaesarSuite/discussions/1#discussioncomment-204708 , and it may be what you are looking for.
Thanks again for the extra knowledge on the CVN, especially with the details on collisions. Learning from folks like you makes working on this project worthwhile.
I think you misunderstood what I meant. Some ECU's use something the ASAM standards calls FLOAT32_IEEE as an internal representation. This means when you get 4 bytes back you can not interpret that as an int, because it is an IEEE754 single precision float.
In the ASAM MCD world there is the Coded Type and the Physical Type. The Coded Type is what comes from the ECU and the Physical Type is the type after conversion. Now, I wrote something like this, to infer the Coded Type:
private static int GetOdxType(int bitlen, bool signed) {
if (bitlen == 1) return ASAMProject.A_BOOLEAN;
int len = bitlen / 8;
if (len > 0 && bitlen % 8 != 0) {
throw new Exception("Non-boolean/byte with bad length");
}
switch (len) {
case 0:
case 1:
return signed ? ASAMProject.A_INT8 : ASAMProject.A_UINT8;
case 2:
return signed ? ASAMProject.A_INT16 : ASAMProject.A_UINT16;
case 3:
case 4:
return signed ? ASAMProject.A_INT32 : ASAMProject.A_UINT32;
default:
throw new Exception("Unknown length!");
}
}
Plus I assign A_ASCIISTRING or A_BYTEFIELD if it's ascii dump or hex dump type respectively. For the Physical type I always use Double for any type with a COMPU-SCALE just for simplicity reasons.
However, this approach does not leave room for floats as the coded type. For example in the MRD1 srm-d "Ams_Mp" is an IEEE Float. I will try to find an overlapping SRMD and CBF, and see if I can find what flags are set if it's a float type. CR43 so far did not yield any floats nor did CR61. It is of course possible that Caesar does not even support floats as input type, who knows.
P.S. Regarding the CVN, because the tester requests this from the ECU you can always just patch the code for the DID to always return a fixed number of your choosing. Meaning - read the original CVN, do your manipulations and then force return the original CVN by storing it in the flash and playing it back instead of returning the actually calculated value. In that case the algorithm is completely irrelevant...
I managed to find a float.
MED40.cbf, variant VC22_Star2_3 requestbytes: 22 66 B9 This is marked as a float in srm-d.
DescriptionString "IDENTICAL FLOAT DEC 4 Bytes 32 1" Unk1b shows 0x08 Unkd shows 0x03
In your code:
else if (Unk1b == 8)
{
result = 6; // integer
}
If I put a breakpoint here, the only time it ever triggers is when I hit a float. Unk1b probably should be labeled datatype, and 8 means IEE754 single precision float. Another mystery solved :)
Nice! I've added your contributions and there should now be experimental support for IEEE 32-bit floats.
The implementation assumes that the floats are in big-endian like the integer values. My MED40 files are a bit dated (last variant is VC15) and I don't have a compatible target, so I might to depend on community feedback if this works properly.
Also thanks for the other CVN fun fact, seems like the mechanism is fundamentally broken :^)
As far as I can see all ECUs are MSB first. Although ASAM-MCD has the facilities to support MSB Last data types. These are used for example on some VAG gearboxes. This setting is per ResponseParameter.
I did not find a way (yet?) to query this from the DTS MCD kernel, so for now I am just assuming that Daimler does not use this. But I'll go through the gearboxes and see if the data lines up.
ASAM-MCD has much more complicated data parsing. Caesar works differently, especially regarding byte and bit extraction. You can refer to 7.3.6.3 DATA EXTRACTION in ASAM MCD-2D specification if it interests you.
Another thing that came to my mind. You have it set that an EnumType must not have the signed bit set. But this is not a requirement. There is no reason why an EnumType (Texttable in MCD world or COMPU-VTAB in A2L) can not have negative variables and text assigned to those variables. Also, there is no reason that floats can not be scaled...
My approach was like this:
case 20:
case 6:
if (diagPresentation.Unk1b == 8) {
if (meas.bitLength != 32) {
throw new Exception("Float type, but invalid bit length!");
}
meas.odxType = ASAMProject.A_FLOAT32;
} else {
meas.odxType = GetOdxType(meas.bitLength, diagPresentation.EnumType_1E > 0);
}
// TextTable
if (diagPresentation.Scales.Count > 1) {
meas.compuCategory = 3;
meas.scaleTextTable = new List<ScaleTextTable>();
foreach (var scale in diagPresentation.Scales) {
ScaleTextTable table = new ScaleTextTable();
table.lowerLimit = scale.EnumLowBound.ToString();
table.upperLimit = scale.EnumUpBound.ToString();
table.data = diagPresentation.Language.GetString(scale.EnumDescription);
meas.scaleTextTable.Add(table);
}
meas.scaleTextTableDefault = meas.scaleTextTable[0].data;
// Normal scale
} else if (diagPresentation.Scales.Count == 1) {
meas.compuCategory = 1;
meas.scaleLinear = new ScaleLinear();
meas.scaleLinear.denominator = 1;
meas.scaleLinear.numerator1 = diagPresentation.Scales[0].AddConstOffset;
meas.scaleLinear.numerator2 = diagPresentation.Scales[0].MultiplyFactor;
// Identical
} else {
meas.compuCategory = 0;
}
break;
Maybe generalizing a little, but seems to work out fine for me so far.
Your approach looks good and is an improvement over the existing implementation. It might potentially fix some of the prior hacks that were used to adjust the data types too.
I might not be able to fix this up that quickly, so if at any time you would like to make a pull request, please let me know and I would be glad to work on merging your PR in.
I could make some changes to Caesar, but then I am worried it could break Diogenes and I have no idea how that works (nor am I too interested in the UI, I am mostly here for the data...)
Sure, changes to Caesar would be excellent. Don't worry about breaking Diogenes, I'll adjust your changes to fit :)
OK, will put aside some time and make some modifications to the presentation parsing. I don't want to be rude, but it's kinda spaghetti right now, most of the stuff needs a rewrite.
On another note, I tried sending you an e-mail on a domain that has something to do with lost mammals, but never received a reply. Is there some way I can contact you?
That's great to hear. Indeed it is extremely spaghetti right now, and I get excited whenever anyone manages to figure out their way around Caesar and suggest fixes.
Could you try this (normally unattended) email instead? That other address has been discontinued.
Unk1F if 1 means the data is LoHi. If not set, HiLo.
EnumType_1E is actually the sign bit.
In this example the EnumType_1E is in 2nd position:
Types cross-referenced from A2L are at end of row. I checked with a rather large sample set and it seems to agree.