コード例 #1
0
        public DiagService(BinaryReader reader, CTFLanguage language, long baseAddress, int poolIndex, ECU parentEcu)
        {
            ParentECU   = parentEcu;
            PoolIndex   = poolIndex;
            BaseAddress = baseAddress;
            reader.BaseStream.Seek(baseAddress, SeekOrigin.Begin);

            ulong bitflags        = reader.ReadUInt32();
            ulong bitflagExtended = reader.ReadUInt32();

            Qualifier = CaesarReader.ReadBitflagStringWithReader(ref bitflags, reader, baseAddress);

            Name_CTF        = CaesarReader.ReadBitflagInt32(ref bitflags, reader, -1);
            Description_CTF = CaesarReader.ReadBitflagInt32(ref bitflags, reader, -1);

            DataClass_ServiceType        = CaesarReader.ReadBitflagUInt16(ref bitflags, reader);
            DataClass_ServiceTypeShifted = 1 << (DataClass_ServiceType - 1);

            IsExecutable        = CaesarReader.ReadBitflagUInt16(ref bitflags, reader);;
            ClientAccessLevel   = CaesarReader.ReadBitflagUInt16(ref bitflags, reader);;
            SecurityAccessLevel = CaesarReader.ReadBitflagUInt16(ref bitflags, reader);;

            T_ComParam_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            T_ComParam_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            Q_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            Q_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            R_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            R_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            InputRefNameMaybe = CaesarReader.ReadBitflagStringWithReader(ref bitflags, reader, baseAddress);

            U_prep_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            U_prep_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            // array of DWORDs, probably reference to elsewhere
            V_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            V_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            RequestBytes_Count  = CaesarReader.ReadBitflagInt16(ref bitflags, reader);
            RequestBytes_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            W_OutPres_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            W_OutPres_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            field50 = CaesarReader.ReadBitflagUInt16(ref bitflags, reader);

            NegativeResponseName = CaesarReader.ReadBitflagStringWithReader(ref bitflags, reader, baseAddress); // negative response name
            UnkStr3 = CaesarReader.ReadBitflagStringWithReader(ref bitflags, reader, baseAddress);
            UnkStr4 = CaesarReader.ReadBitflagStringWithReader(ref bitflags, reader, baseAddress);

            P_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            P_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            DiagServiceCodeCount  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            DiagServiceCodeOffset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            S_Count  = CaesarReader.ReadBitflagInt16(ref bitflags, reader);
            S_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            bitflags = bitflagExtended;

            X_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            X_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            Y_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            Y_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            Z_Count  = CaesarReader.ReadBitflagInt32(ref bitflags, reader);
            Z_Offset = CaesarReader.ReadBitflagInt32(ref bitflags, reader);

            if (RequestBytes_Count > 0)
            {
                reader.BaseStream.Seek(baseAddress + RequestBytes_Offset, SeekOrigin.Begin);
                RequestBytes = reader.ReadBytes(RequestBytes_Count);
            }
            else
            {
                RequestBytes = new byte[] { };
            }

            // u_table to u_entries
            InputPreparations = new List <DiagPreparation>();
            for (int prepIndex = 0; prepIndex < U_prep_Count; prepIndex++)
            {
                long presentationTableOffset = baseAddress + U_prep_Offset;
                reader.BaseStream.Seek(presentationTableOffset + (prepIndex * 10), SeekOrigin.Begin);

                // DIOpenDiagService (reads 4, 4, 2 then calls DiagServiceReadPresentation) to build a presentation
                int    prepEntryOffset = reader.ReadInt32();  // file: 0 (DW)
                int    prepEntryBitPos = reader.ReadInt32();  // file: 4 (DW)
                ushort prepEntryMode   = reader.ReadUInt16(); // file: 8 (W)

                DiagPreparation preparation = new DiagPreparation(reader, language, presentationTableOffset + prepEntryOffset, prepEntryBitPos, prepEntryMode, parentEcu, this);
                //preparation.PrintDebug();
                InputPreparations.Add(preparation);
            }


            OutputPreparations = new List <List <DiagPreparation> >();
            long outPresBaseAddress = BaseAddress + W_OutPres_Offset;

            for (int presIndex = 0; presIndex < W_OutPres_Count; presIndex++)
            {
                reader.BaseStream.Seek(outPresBaseAddress + (presIndex * 8), SeekOrigin.Begin);
                int resultPresentationCount  = reader.ReadInt32();
                int resultPresentationOffset = reader.ReadInt32();

                List <DiagPreparation> ResultPresentationSet = new List <DiagPreparation>();
                for (int presInnerIndex = 0; presInnerIndex < resultPresentationCount; presInnerIndex++)
                {
                    long presentationTableOffset = outPresBaseAddress + resultPresentationOffset;
                    reader.BaseStream.Seek(presentationTableOffset + (presIndex * 10), SeekOrigin.Begin);

                    int    prepEntryOffset = reader.ReadInt32();  // file: 0 (DW)
                    int    prepEntryBitPos = reader.ReadInt32();  // file: 4 (DW)
                    ushort prepEntryMode   = reader.ReadUInt16(); // file: 8 (W)

                    DiagPreparation preparation = new DiagPreparation(reader, language, presentationTableOffset + prepEntryOffset, prepEntryBitPos, prepEntryMode, parentEcu, this);
                    ResultPresentationSet.Add(preparation);
                }
                OutputPreparations.Add(ResultPresentationSet);
            }

            DiagComParameters = new List <ComParameter>();
            long comParamTableBaseAddress = BaseAddress + T_ComParam_Offset;

            for (int cpIndex = 0; cpIndex < T_ComParam_Count; cpIndex++)
            {
                reader.BaseStream.Seek(comParamTableBaseAddress + (cpIndex * 4), SeekOrigin.Begin);
                int          resultCpOffset     = reader.ReadInt32();
                long         cpEntryBaseAddress = comParamTableBaseAddress + resultCpOffset;
                ComParameter cp = new ComParameter(reader, cpEntryBaseAddress, parentEcu.ECUInterfaces);
                DiagComParameters.Add(cp);
            }

            // DJ_Zugriffsberechtigung_Abgleich
            // DJ_Zugriffsberechtigung
            // DT_Abgasklappe_kontinuierlich
            // FN_HardReset
            // WVC_Implizite_Variantenkodierung_Write

            // NR_Disable_Resp_required noexec
            // DT_Laufzeiten_Resetzaehler_nicht_implementiert exec

            /*
             * if (false && qualifierName.Contains("RVC_SCN_Variantencodierung_VGS_73_Lesen"))
             * {
             *
             *  Console.WriteLine($"{nameof(field50)} : {field50}");
             *  Console.WriteLine($"{nameof(IsExecutable)} : {IsExecutable} {IsExecutable != 0}");
             *  Console.WriteLine($"{nameof(AccessLevel)} : {AccessLevel}");
             *  Console.WriteLine($"{nameof(SecurityAccessLevel)} : {SecurityAccessLevel}");
             *  Console.WriteLine($"{nameof(DataClass)} : {DataClass}");
             *
             *
             *
             *  Console.WriteLine($"{qualifierName} - ReqBytes: {RequestBytes_Count}, P: {P_Count}, Q: {Q_Count}, R: {R_Count}, S: {S_Count}, T: {T_Count}, Preparation: {U_prep_Count}, V: {V_Count}, W: {W_Count}, X: {X_Count}, Y: {Y_Count}, Z: {Z_Count}, DSC {DiagServiceCodeCount}");
             *  Console.WriteLine($"at 0x{baseAddress:X}, W @ 0x{W_Offset:X}, DSC @ 0x{DiagServiceCodeOffset:X}");
             *  Console.WriteLine($"ReqBytes: {BitUtility.BytesToHex(RequestBytes)}");
             * }
             */
            //Console.WriteLine($"{qualifierName} - O: {RequestBytes_Count}, P: {P_Count}, Q: {Q_Count}, R: {R_Count}, S: {S_Count}, T: {T_Count}, U: {U_Count}, V: {V_Count}, W: {W_Count}, X: {X_Count}, Y: {Y_Count}, Z: {Z_Count}, DSC {DiagServiceCodeCount}");


            byte[] dscPool             = parentEcu.ParentContainer.CaesarCFFHeader.DSCPool;
            long   dscTableBaseAddress = BaseAddress + DiagServiceCodeOffset;

            using (BinaryReader dscPoolReader = new BinaryReader(new MemoryStream(dscPool)))
            {
                for (int dscIndex = 0; dscIndex < DiagServiceCodeCount; dscIndex++)
                {
                    reader.BaseStream.Seek(dscTableBaseAddress + (4 * dscIndex), SeekOrigin.Begin);
                    long dscEntryBaseAddress = reader.ReadInt32() + dscTableBaseAddress;
                    reader.BaseStream.Seek(dscEntryBaseAddress, SeekOrigin.Begin);

                    ulong  dscEntryBitflags = reader.ReadUInt16();
                    uint   idk1             = CaesarReader.ReadBitflagUInt8(ref dscEntryBitflags, reader);
                    uint   idk2             = CaesarReader.ReadBitflagUInt8(ref dscEntryBitflags, reader);
                    int    dscPoolOffset    = CaesarReader.ReadBitflagInt32(ref dscEntryBitflags, reader);
                    string dscQualifier     = CaesarReader.ReadBitflagStringWithReader(ref dscEntryBitflags, reader, dscEntryBaseAddress);

                    dscPoolReader.BaseStream.Seek(dscPoolOffset * 8, SeekOrigin.Begin);
                    long dscRecordOffset = dscPoolReader.ReadInt32() + parentEcu.ParentContainer.CaesarCFFHeader.DscBlockOffset;
                    int  dscRecordSize   = dscPoolReader.ReadInt32();

                    reader.BaseStream.Seek(dscRecordOffset, SeekOrigin.Begin);

                    // Console.WriteLine($"DSC {qualifierName} @ 0x{dscTableBaseAddress:X8} {idk1}/{idk2} pool @ 0x{dscPoolOffset:X}, name: {dscQualifier}");
                    byte[] dscBytes = reader.ReadBytes(dscRecordSize);
#if DEBUG
                    //string dscName = $"{parentEcu.Qualifier}_{Qualifier}_{dscIndex}.pal";
                    //Console.WriteLine($"Exporting DSC: {dscName}");
                    //File.WriteAllBytes(dscName, dscBytes);
#endif
                    // at this point, the DSC binary is available in dscBytes, intended for use in DSCContext (but is currently unimplemented)
                    // Console.WriteLine($"DSC actual at 0x{dscRecordOffset:X}, size=0x{dscRecordSize:X}\n");
                }
            }
        }
コード例 #2
0
        public string InterpretData(byte[] inBytes, DiagPreparation inPreparation)
        {
            // might be relevant: DMPrepareSingleDatum, DMPresentSingleDatum

            byte[] workingBytes = inBytes.Skip(inPreparation.BitPosition / 8).Take(TypeLength_1a).ToArray();
            if (workingBytes.Length != TypeLength_1a)
            {
                return($"InBytes [{BitUtility.BytesToHex(workingBytes)}] length mismatch (expecting {TypeLength_1a})");
            }

            // handle booleans first since they're the edge case where they can cross byte boundaries
            if (inPreparation.SizeInBits == 1)
            {
                int  bytesToSkip  = (int)(inPreparation.BitPosition / 8);
                int  bitsToSkip   = inPreparation.BitPosition % 8;
                byte selectedByte = inBytes[bytesToSkip];

                int selectedBit = (selectedByte >> bitsToSkip) & 1;

                return($"{DescriptionString}: {selectedBit} {DisplayedUnitString} (BitType)");
            }

            // everything else should be aligned to byte boundaries
            if (inPreparation.BitPosition % 8 != 0)
            {
                return("BitOffset was outside byte boundary (skipped)");
            }
            int    dataType          = GetDataType();
            string humanReadableType = $"UnhandledType:{dataType}";
            string parsedValue       = BitUtility.BytesToHex(workingBytes, true);

            if ((dataType == 6 || (dataType == 20)))
            {
                // parse as a regular int (BE)
                int result = 0;

                for (int i = 0; i < workingBytes.Length; i++)
                {
                    result <<= 8;
                    result  |= workingBytes[i];
                }

                humanReadableType = "IntegerType";

                parsedValue = result.ToString();
                if (dataType == 20)
                {
                    humanReadableType = "ScaledType";

                    double valueToScale = result;
                    foreach (Scale scale in Scales)
                    {
                        valueToScale *= scale.MultiplyFactor;
                        valueToScale += scale.AddConstOffset;
                    }

                    parsedValue = valueToScale.ToString("0.000000");
                }
            }
            else if (dataType == 18)
            {
                humanReadableType = "HexdumpType";
            }
            else if (dataType == 17)
            {
                humanReadableType = "StringType";
                parsedValue       = Encoding.UTF8.GetString(workingBytes);
            }

            return($"{DescriptionString}: {parsedValue} {DisplayedUnitString} ({humanReadableType})");
        }
コード例 #3
0
        public string InterpretData(byte[] inBytes, DiagPreparation inPreparation, bool describe = true)
        {
            // might be relevant: DMPrepareSingleDatum, DMPresentSingleDatum

            bool isDebugBuild = false;

#if DEBUG
            isDebugBuild = true;
#endif

            string descriptionPrefix = describe ? $"{DescriptionString}: " : "";
            byte[] workingBytes      = inBytes.Skip(inPreparation.BitPosition / 8).Take(TypeLength_1A).ToArray();

            bool isEnumType = (EnumType_1E == 0) && ((Type_1C == 1) || (ScaleCountMaybe > 1));

            // hack: sometimes hybrid types (regularly parsed as an scaled value if within bounds) are misinterpreted as pure enums
            // this is a temporary fix for kilometerstand until there's a better way to ascertain its type
            // this also won't work on other similar cases without a unit string e.g. error instance counter (Häufigkeitszähler)
            if (DisplayedUnitString == "km")
            {
                isEnumType = false;
            }

            if (workingBytes.Length != TypeLength_1A)
            {
                return($"InBytes [{BitUtility.BytesToHex(workingBytes)}] length mismatch (expecting {TypeLength_1A})");
            }

            // handle booleans first since they're the edge case where they can cross byte boundaries
            if (inPreparation.SizeInBits == 1)
            {
                int  bytesToSkip  = (int)(inPreparation.BitPosition / 8);
                int  bitsToSkip   = inPreparation.BitPosition % 8;
                byte selectedByte = inBytes[bytesToSkip];

                int selectedBit = (selectedByte >> bitsToSkip) & 1;
                if (isEnumType && (Scales.Count > selectedBit))
                {
                    return($"{descriptionPrefix}{Language.GetString(Scales[selectedBit].EnumDescription)} {DisplayedUnitString}");
                }
                else
                {
                    return($"{descriptionPrefix}{selectedBit} {DisplayedUnitString}");
                }
            }

            // everything else should be aligned to byte boundaries
            if (inPreparation.BitPosition % 8 != 0)
            {
                return("BitOffset was outside byte boundary (skipped)");
            }
            int dataType             = GetDataType();
            int rawIntInterpretation = 0;

            string humanReadableType = $"UnhandledType:{dataType}";
            string parsedValue       = BitUtility.BytesToHex(workingBytes, true);
            if ((dataType == 6 || (dataType == 20)))
            {
                // parse as a regular int (BE)

                for (int i = 0; i < workingBytes.Length; i++)
                {
                    rawIntInterpretation <<= 8;
                    rawIntInterpretation  |= workingBytes[i];
                }

                humanReadableType = "IntegerType";

                parsedValue = rawIntInterpretation.ToString();
                if (dataType == 20)
                {
                    humanReadableType = "ScaledType";

                    double valueToScale = rawIntInterpretation;

                    // if there's only one scale, use it as-is
                    // if there's more than one, use the first scale as an interim solution;
                    // the results of stacking scales does not make sense
                    // there might be a better, non-hardcoded (0) solution to this, and perhaps with a sig-fig specifier

                    valueToScale *= Scales[0].MultiplyFactor;
                    valueToScale += Scales[0].AddConstOffset;

                    parsedValue = valueToScale.ToString("0.000000");
                }
            }
            else if (dataType == 18)
            {
                humanReadableType = "HexdumpType";
            }
            else if (dataType == 17)
            {
                humanReadableType = "StringType";
                parsedValue       = Encoding.UTF8.GetString(workingBytes);
            }

            if (isEnumType)
            {
                // discovered by @VladLupashevskyi in https://github.com/jglim/CaesarSuite/issues/27
                // if an enum is specified, the inclusive upper bound and lower bound will be defined in the scale object

                bool useNewInterpretation = false;
                foreach (Scale scale in Scales)
                {
                    if ((scale.EnumUpBound > 0) || (scale.EnumLowBound > 0))
                    {
                        useNewInterpretation = true;
                        break;
                    }
                }

                if (useNewInterpretation)
                {
                    foreach (Scale scale in Scales)
                    {
                        if ((rawIntInterpretation >= scale.EnumLowBound) && (rawIntInterpretation <= scale.EnumUpBound))
                        {
                            return($"{descriptionPrefix}{Language.GetString(scale.EnumDescription)} {DisplayedUnitString}");
                        }
                    }
                }
                else
                {
                    // original implementation, probably incorrect
                    if (rawIntInterpretation < Scales.Count)
                    {
                        return($"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}");
                    }
                }
                return($"{descriptionPrefix}(Enum not found) {DisplayedUnitString}");
                // this bit below for troubleshooting problematic presentations

                /*
                 * if (rawIntInterpretation < Scales.Count)
                 * {
                 *  return $"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}";
                 * }
                 * else
                 * {
                 *  // seems like an enum-like value broke
                 *  return $"{descriptionPrefix}{Language.GetString(Scales[0].EnumDescription)} {DisplayedUnitString} [!]";
                 * }
                 */
            }
            else
            {
                if (isDebugBuild)
                {
                    return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString} ({humanReadableType})");
                }
                else
                {
                    return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString}");
                }
            }
        }
コード例 #4
0
        public string InterpretData(byte[] inBytes, DiagPreparation inPreparation, bool describe = true)
        {
            // might be relevant: DMPrepareSingleDatum, DMPresentSingleDatum

            bool isDebugBuild = false;

#if DEBUG
            isDebugBuild = true;
#endif

            string descriptionPrefix = describe ? $"{DescriptionString}: " : "";
            byte[] workingBytes      = inBytes.Skip(inPreparation.BitPosition / 8).Take(TypeLength_1A).ToArray();

            bool isEnumType = (EnumType_1E == 0) && ((Type_1C == 1) || (ScaleCountMaybe > 1));

            if (workingBytes.Length != TypeLength_1A)
            {
                return($"InBytes [{BitUtility.BytesToHex(workingBytes)}] length mismatch (expecting {TypeLength_1A})");
            }

            // handle booleans first since they're the edge case where they can cross byte boundaries
            if (inPreparation.SizeInBits == 1)
            {
                int  bytesToSkip  = (int)(inPreparation.BitPosition / 8);
                int  bitsToSkip   = inPreparation.BitPosition % 8;
                byte selectedByte = inBytes[bytesToSkip];

                int selectedBit = (selectedByte >> bitsToSkip) & 1;
                if (isEnumType && (Scales.Count > selectedBit))
                {
                    return($"{descriptionPrefix}{Language.GetString(Scales[selectedBit].EnumDescription)} {DisplayedUnitString}");
                }
                else
                {
                    return($"{descriptionPrefix}{selectedBit} {DisplayedUnitString}");
                }
            }

            // everything else should be aligned to byte boundaries
            if (inPreparation.BitPosition % 8 != 0)
            {
                return("BitOffset was outside byte boundary (skipped)");
            }
            int dataType             = GetDataType();
            int rawIntInterpretation = 0;

            string humanReadableType = $"UnhandledType:{dataType}";
            string parsedValue       = BitUtility.BytesToHex(workingBytes, true);
            if ((dataType == 6 || (dataType == 20)))
            {
                // parse as a regular int (BE)

                for (int i = 0; i < workingBytes.Length; i++)
                {
                    rawIntInterpretation <<= 8;
                    rawIntInterpretation  |= workingBytes[i];
                }

                humanReadableType = "IntegerType";

                parsedValue = rawIntInterpretation.ToString();
                if (dataType == 20)
                {
                    humanReadableType = "ScaledType";

                    double valueToScale = rawIntInterpretation;

                    // if there's only one scale, use it as-is
                    // if there's more than one, use the first scale as an interim solution;
                    // the results of stacking scales does not make sense
                    // there might be a better, non-hardcoded (0) solution to this, and perhaps with a sig-fig specifier

                    valueToScale *= Scales[0].MultiplyFactor;
                    valueToScale += Scales[0].AddConstOffset;

                    parsedValue = valueToScale.ToString("0.000000");
                }
            }
            else if (dataType == 18)
            {
                humanReadableType = "HexdumpType";
            }
            else if (dataType == 17)
            {
                humanReadableType = "StringType";
                parsedValue       = Encoding.UTF8.GetString(workingBytes);
            }

            if (isEnumType && (rawIntInterpretation < Scales.Count))
            {
                return($"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}");
                // this bit below for troubleshooting problematic presentations

                /*
                 * if (rawIntInterpretation < Scales.Count)
                 * {
                 *  return $"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}";
                 * }
                 * else
                 * {
                 *  // seems like an enum-like value broke
                 *  return $"{descriptionPrefix}{Language.GetString(Scales[0].EnumDescription)} {DisplayedUnitString} [!]";
                 * }
                 */
            }
            else
            {
                if (isDebugBuild)
                {
                    return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString} ({humanReadableType})");
                }
                else
                {
                    return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString}");
                }
            }
        }