Beispiel #1
0
        private void PresentRunDiagDialog(DiagService ds)
        {
            RunDiagForm runDiagForm = new RunDiagForm(ds);

            if (runDiagForm.ShowDialog() == DialogResult.OK)
            {
                Connection.ExecUserDiagJob(runDiagForm.Result, ds);
            }
        }
        /*
         *  test: med40
         *
         *  jg: dumping pres
         *  jg: q: SID_RQ pos byte: 0 size bytes: 1 modecfg:323 fieldtype: IntegerType dump: 2E 00 00 00
         *  jg: q: RecordDataIdentifier pos byte: 1 size bytes: 2 modecfg:324 fieldtype: IntegerType dump: 01 10 00 00
         *  jg: q: #0 pos byte: 33 size bytes: 16 modecfg:6430 fieldtype: BitDumpType dump:
         *  jg: q: #1 pos byte: 49 size bytes: 1 modecfg:6423 fieldtype: IntegerType dump:
         *  jg: q: #2 pos byte: 50 size bytes: 1 modecfg:6423 fieldtype: IntegerType dump:
         *  jg: q: #3 pos byte: 51 size bytes: 1 modecfg:6423 fieldtype: IntegerType dump:
         *  jg: q: #4 pos byte: 52 size bytes: 1 modecfg:6423 fieldtype: IntegerType dump:
         *  jg: q: #5 pos byte: 3 size bytes: 50 modecfg:6410 fieldtype: ExtendedBitDumpType dump:
         *  jg: done dumping pres
         *
         */


        public static void DoVariantCoding(ECUConnection connection, VCForm vcForm, bool writesEnabled)
        {
            Console.WriteLine($"Operator requesting for VC: {BitUtility.BytesToHex(vcForm.VCValue, true)}");

            RunDiagForm runDiagForm = new RunDiagForm(vcForm.WriteService);

            // construct a write command from presentations: fill up the VC value first, fill up all available dumps, then inherit the last values (fingerprints, scn) from the read command
            byte[] vcParameter      = vcForm.VCValue;
            byte[] writeCommand     = vcForm.WriteService.RequestBytes;
            byte[] priorReadCommand = vcForm.UnfilteredReadValue;


            // start with a list of all values that we will have to fill
            List <DiagPreparation> preparationsToProcess = new List <DiagPreparation>(vcForm.WriteService.InputPreparations);

            // fill up vc, which pretty much always uses the ExtendedBitDumpType type
            DiagPreparation vcPrep = preparationsToProcess.Find(x => x.FieldType == DiagPreparation.InferredDataType.ExtendedBitDumpType);

            if (vcPrep is null)
            {
                MessageBox.Show("VC: Could not find the VC ExtendedBitDump prep, stopping early to save your ECU.", "VC Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            int vcPrepSizeInBytes  = vcPrep.SizeInBits / 8;
            int vcPrepBytePosition = vcPrep.BitPosition / 8;

            if (vcPrepSizeInBytes < vcParameter.Length)
            {
                MessageBox.Show("VC: VC string is longer than the parameter can fit, stopping early to save your ECU.", "VC Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            // zero out the destination buffer for the param that we intend to write since there's a possibility that our param is shorter than the actual prep's size
            for (int i = vcPrepBytePosition; i < (vcPrepBytePosition + vcPrepSizeInBytes); i++)
            {
                writeCommand[i] = 0;
            }
            // copy the parameter in
            Array.ConstrainedCopy(vcParameter, 0, writeCommand, vcPrepBytePosition, vcParameter.Length);
            preparationsToProcess.Remove(vcPrep);
            // done with vc prep


            // merge prefilled constants such as the (SID_RQ, id..)
            List <DiagPreparation> prefilledValues = new List <DiagPreparation>();

            foreach (DiagPreparation prep in preparationsToProcess)
            {
                if (prep.Dump.Length > 0)
                {
                    prefilledValues.Add(prep);
                    if (prep.FieldType == DiagPreparation.InferredDataType.IntegerType)
                    {
                        byte[] fixedDump = prep.Dump.Take(prep.SizeInBits / 8).Reverse().ToArray();
                        Array.ConstrainedCopy(vcParameter, 0, writeCommand, vcPrepBytePosition, vcParameter.Length);
                    }
                    else
                    {
                        Console.WriteLine($"Skipping prefill for {prep.Qualifier} as the data type {prep.FieldType} is unsupported.");
                    }
                }
            }
            // "mark" the constants as done
            foreach (DiagPreparation prep in prefilledValues)
            {
                preparationsToProcess.Remove(prep);
            }

            // isolate the SCN if it exists
            foreach (DiagPreparation prep in preparationsToProcess)
            {
                int bytePosition = prep.BitPosition / 8;
                int byteLength   = prep.SizeInBits / 8;
                // SCN is always 16-bytes
                if (byteLength != 16)
                {
                    continue;
                }
                byte[] originalValue = new byte[byteLength];
                Array.ConstrainedCopy(priorReadCommand, bytePosition, originalValue, 0, byteLength);

                // SCN values are ASCII numerals (between 0x30 - 0x39)
                bool isValidSCN = true;
                foreach (byte b in originalValue)
                {
                    if ((b > 0x39) || (b < 0x30))
                    {
                        isValidSCN = false;
                        break;
                    }
                }
                if (!isValidSCN)
                {
                    continue;
                }

                Console.WriteLine($"Found SCN value: {Encoding.ASCII.GetString(originalValue)}");

                // check if operator is using vediamo-style variant-coding, where the SCN is set to 0000000000000000 when writing VC
                // otherwise, we can reuse the last value as read from the ECU
                bool useVediamoBehaviorZeroSCN = Preferences.GetValue(Preferences.PreferenceKey.EnableSCNZero) == "true";
                if (useVediamoBehaviorZeroSCN)
                {
                    for (int i = 0; i < originalValue.Length; i++)
                    {
                        originalValue[i] = 0x30;
                    }
                }

                Console.WriteLine($"Using {Encoding.ASCII.GetString(originalValue)} as new SCN value");

                // write-back the recognized (and optionally, modified) SCN
                Array.ConstrainedCopy(originalValue, 0, writeCommand, bytePosition, byteLength);
                preparationsToProcess.Remove(prep);
                break;
            }

            // isolate the fingerprint if it exists
            // normally fingerprint is appended at the tail of the VC command
            List <int> tailIndices = new List <int>()
            {
                writeCommand.Length - 1, writeCommand.Length - 2, writeCommand.Length - 3, writeCommand.Length - 4
            };
            List <DiagPreparation> possibleFingerprintFields = new List <DiagPreparation>();

            foreach (DiagPreparation prep in preparationsToProcess)
            {
                int bytePosition = prep.BitPosition / 8;
                int byteLength   = prep.SizeInBits / 8;

                if ((prep.FieldType == DiagPreparation.InferredDataType.IntegerType) && (byteLength == 1) && (tailIndices.Contains(bytePosition)))
                {
                    tailIndices.Remove(bytePosition);
                    possibleFingerprintFields.Add(prep);
                }
            }
            if (possibleFingerprintFields.Count == 4)
            {
                // copy in the fingerprint, and "mark" the constants as done
                byte[] fingerprint = priorReadCommand.Skip(priorReadCommand.Length - 4).ToArray();
                Console.WriteLine($"Found original fingerprint as {BitUtility.BytesToHex(fingerprint)}");

                // default behavior is to clone last fingerprint, else use stored fingerprint
                if (Preferences.GetValue(Preferences.PreferenceKey.EnableFingerprintClone) == "false")
                {
                    uint altFingerprintValue = uint.Parse(Preferences.GetValue(Preferences.PreferenceKey.FingerprintValue));
                    fingerprint[3]        = (byte)(altFingerprintValue & 0xFF);
                    altFingerprintValue >>= 8;
                    fingerprint[2]        = (byte)(altFingerprintValue & 0xFF);
                    altFingerprintValue >>= 8;
                    fingerprint[1]        = (byte)(altFingerprintValue & 0xFF);
                    altFingerprintValue >>= 8;
                    fingerprint[0]        = (byte)(altFingerprintValue & 0xFF);
                }

                Console.WriteLine($"Using {BitUtility.BytesToHex(fingerprint)} as new fingerprint value.");

                Array.ConstrainedCopy(fingerprint, 0, writeCommand, writeCommand.Length - 4, 4);

                foreach (DiagPreparation prep in possibleFingerprintFields)
                {
                    preparationsToProcess.Remove(prep);
                }
            }


            // at this point, whatever that's left in preparationsToProcess are stuff that are variable, but should be copied verbatim from the original read request (e.g. fingerprints, scn)
            // log the assumptions, show it the operator just in case
            StringBuilder assumptionsMade = new StringBuilder();

            if (preparationsToProcess.Count > 0)
            {
                if (writeCommand.Length != priorReadCommand.Length)
                {
                    MessageBox.Show("There are some preparations that do not have a default value. \r\n" +
                                    "The input and output values do not have matching lengths, which means that the automatic assumption may be wrong. \r\n" +
                                    "Please be very careful when proceeding.", "Warning");
                }

                foreach (DiagPreparation prep in preparationsToProcess)
                {
                    int bytePosition = prep.BitPosition / 8;
                    int byteLength   = prep.SizeInBits / 8;
                    Array.ConstrainedCopy(priorReadCommand, bytePosition, writeCommand, bytePosition, byteLength);
                    assumptionsMade.Append($"{prep.Qualifier} : {BitUtility.BytesToHex(priorReadCommand.Skip(bytePosition).Take(byteLength).ToArray(), true)}\r\n");
                }
            }

            /*
             * // lazy me dumping the values
             * for (int i = 0; i < vcForm.WriteService.InputPreparations.Count; i++)
             * {
             *  DiagPreparation prep = vcForm.WriteService.InputPreparations[i];
             *  Console.WriteLine($"debug: q: {prep.Qualifier} pos byte: {(prep.BitPosition / 8)} size bytes: {(prep.SizeInBits / 8)} modecfg:{prep.ModeConfig:X} fieldtype: {prep.FieldType} dump: {BitUtility.BytesToHex(prep.Dump, true)}");
             * }
             */

            // we are done preparing the command, if we are confident we can send the command straight to the ECU, else, let the user review
            if (assumptionsMade.Length > 0)
            {
                if (MessageBox.Show("Some assumptions were made when preparing the write parameters. \r\n\r\n" +
                                    "You may wish to review them by selecting Cancel, or select OK to execute the write command immediately.\r\n\r\n" + assumptionsMade.ToString(),
                                    "Review assumptions", MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
                {
                    ExecVCWrite(writeCommand, vcForm.WriteService, connection, writesEnabled);
                }
                else
                {
                    runDiagForm.Result = writeCommand;
                    if (runDiagForm.ShowDialog() == DialogResult.OK)
                    {
                        ExecVCWrite(runDiagForm.Result, vcForm.WriteService, connection, writesEnabled);
                    }
                }
            }
            else
            {
                // everything accounted for, immediately write
                ExecVCWrite(writeCommand, vcForm.WriteService, connection, writesEnabled);
            }
        }