예제 #1
0
        /// <summary>
        /// Update the VIN.
        /// </summary>
        private async void modifyVinButton_Click(object sender, EventArgs e)
        {
            try
            {
                Response <uint> osidResponse = await this.Vehicle.QueryOperatingSystemId(CancellationToken.None);

                if (osidResponse.Status != ResponseStatus.Success)
                {
                    this.AddUserMessage("Operating system query failed: " + osidResponse.Status);
                    return;
                }

                PcmInfo info = new PcmInfo(osidResponse.Value);

                var vinResponse = await this.Vehicle.QueryVin();

                if (vinResponse.Status != ResponseStatus.Success)
                {
                    this.AddUserMessage("VIN query failed: " + vinResponse.Status.ToString());
                    return;
                }

                DialogBoxes.VinForm vinForm = new DialogBoxes.VinForm();
                vinForm.Vin = vinResponse.Value;
                DialogResult dialogResult = vinForm.ShowDialog();

                if (dialogResult == DialogResult.OK)
                {
                    bool unlocked = await this.Vehicle.UnlockEcu(info.KeyAlgorithm);

                    if (!unlocked)
                    {
                        this.AddUserMessage("Unable to unlock PCM.");
                        return;
                    }

                    Response <bool> vinmodified = await this.Vehicle.UpdateVin(vinForm.Vin.Trim());

                    if (vinmodified.Value)
                    {
                        this.AddUserMessage("VIN successfully updated to " + vinForm.Vin);
                        MessageBox.Show("VIN updated to " + vinForm.Vin + " successfully.", "Good news.", MessageBoxButtons.OK);
                    }
                    else
                    {
                        MessageBox.Show("Unable to change the VIN to " + vinForm.Vin + ". Error: " + vinmodified.Status, "Bad news.", MessageBoxButtons.OK);
                    }
                }
            }
            catch (Exception exception)
            {
                this.AddUserMessage("VIN change failed: " + exception.ToString());
            }
        }
예제 #2
0
        /// <summary>
        /// Write the contents of the flash.
        /// </summary>
        private async void writeFullContentsButton_Click(object sender, EventArgs e)
        {
            if (this.vehicle == null)
            {
                // This shouldn't be possible - it would mean the buttons
                // were enabled when they shouldn't be.
                return;
            }

            Response <uint> osidResponse = await this.vehicle.QueryOperatingSystemId();

            if (osidResponse.Status != ResponseStatus.Success)
            {
                this.AddUserMessage("Operating system query failed: " + osidResponse.Status);
                return;
            }

            PcmInfo info = new PcmInfo(osidResponse.Value);

            bool unlocked = await this.vehicle.UnlockEcu(info.KeyAlgorithm);

            if (!unlocked)
            {
                this.AddUserMessage("Unlock was not successful.");
                return;
            }

            this.AddUserMessage("Unlock succeeded.");

            string path = this.ShowOpenDialog();

            if (path == null)
            {
                return;
            }

            this.AddUserMessage("Pretending to update PCM with content from " + path);

            try
            {
                using (Stream stream = File.OpenRead(path))
                {
                    await this.vehicle.WriteContents(stream);
                }
            }
            catch (IOException exception)
            {
                this.AddUserMessage(exception.ToString());
            }
        }
예제 #3
0
        /// <summary>
        /// Write changes to the PCM's flash memory.
        /// </summary>
        private async void write_BackgroundThread(WriteType writeType)
        {
            using (new AwayMode())
            {
                try
                {
                    this.currentWriteType = writeType;

                    if (this.Vehicle == null)
                    {
                        // This shouldn't be possible - it would mean the buttons
                        // were enabled when they shouldn't be.
                        return;
                    }

                    this.cancellationTokenSource = new CancellationTokenSource();

                    string path = null;
                    this.Invoke((MethodInvoker) delegate()
                    {
                        this.DisableUserInput();
                        this.cancelButton.Enabled = true;

                        path = this.ShowOpenDialog();
                    });

                    if (path == null)
                    {
                        return;
                    }

                    this.AddUserMessage(path);

                    byte[] image;
                    using (Stream stream = File.OpenRead(path))
                    {
                        image = new byte[stream.Length];
                        int bytesRead = await stream.ReadAsync(image, 0, (int)stream.Length);

                        if (bytesRead != stream.Length)
                        {
                            // If this happens too much, we should try looping rather than reading the whole file in one shot.
                            this.AddUserMessage("Unable to load file.");
                            return;
                        }
                    }

                    // Sanity checks.
                    FileValidator validator = new FileValidator(image, this);
                    if (!validator.IsValid())
                    {
                        this.AddUserMessage("This file is corrupt. It would render your PCM unusable.");
                        return;
                    }

                    UInt32 kernelVersion = 0;
                    bool   needUnlock;
                    int    keyAlgorithm               = 1;
                    UInt32 pcmOperatingSystemId       = 0;
                    bool   needToCheckOperatingSystem = writeType != WriteType.Full;

                    this.AddUserMessage("Requesting operating system ID...");
                    Response <uint> osidResponse = await this.Vehicle.QueryOperatingSystemId(this.cancellationTokenSource.Token);

                    if (osidResponse.Status == ResponseStatus.Success)
                    {
                        pcmOperatingSystemId = osidResponse.Value;
                        PcmInfo info = new PcmInfo(pcmOperatingSystemId);
                        keyAlgorithm = info.KeyAlgorithm;
                        needUnlock   = true;

                        if (needToCheckOperatingSystem && !validator.IsSameOperatingSystem(pcmOperatingSystemId))
                        {
                            this.AddUserMessage("Flashing this file could render your PCM unusable.");
                            return;
                        }

                        needToCheckOperatingSystem = false;
                    }
                    else
                    {
                        if (this.cancellationTokenSource.Token.IsCancellationRequested)
                        {
                            return;
                        }

                        this.AddUserMessage("Operating system request failed, checking for a live kernel...");

                        kernelVersion = await this.Vehicle.GetKernelVersion();

                        if (kernelVersion == 0)
                        {
                            this.AddUserMessage("Checking for recovery mode...");
                            bool recoveryMode = await this.Vehicle.IsInRecoveryMode();

                            if (recoveryMode)
                            {
                                this.AddUserMessage("PCM is in recovery mode.");
                                needUnlock = true;
                            }
                            else
                            {
                                this.AddUserMessage("PCM is not responding to OSID, kernel version, or recovery mode checks.");
                                this.AddUserMessage("Unlock may not work, but we'll try...");
                                needUnlock = true;
                            }
                        }
                        else
                        {
                            needUnlock = false;

                            this.AddUserMessage("Kernel version: " + kernelVersion.ToString("X8"));

                            this.AddUserMessage("Asking kernel for the PCM's operating system ID...");
                            if (needToCheckOperatingSystem && !await this.Vehicle.IsSameOperatingSystemAccordingToKernel(validator, this.cancellationTokenSource.Token))
                            {
                                this.AddUserMessage("Flashing this file could render your PCM unusable.");
                                return;
                            }

                            needToCheckOperatingSystem = false;
                        }
                    }

                    await this.Vehicle.SuppressChatter();

                    if (needUnlock)
                    {
                        bool unlocked = await this.Vehicle.UnlockEcu(keyAlgorithm);

                        if (!unlocked)
                        {
                            this.AddUserMessage("Unlock was not successful.");
                            return;
                        }

                        this.AddUserMessage("Unlock succeeded.");
                    }

                    DateTime start = DateTime.Now;

                    CKernelWriter writer = new CKernelWriter(
                        this.Vehicle,
                        new Protocol(),
                        this);

                    await writer.Write(
                        image,
                        writeType,
                        kernelVersion,
                        validator,
                        needToCheckOperatingSystem,
                        this.cancellationTokenSource.Token);

                    this.AddUserMessage("Elapsed time " + DateTime.Now.Subtract(start));
                }
                catch (IOException exception)
                {
                    this.AddUserMessage(exception.ToString());
                }
                finally
                {
                    this.currentWriteType = WriteType.None;

                    this.Invoke((MethodInvoker) delegate()
                    {
                        this.EnableUserInput();
                        this.cancelButton.Enabled = false;
                    });

                    // The token / token-source can only be cancelled once, so we need to make sure they won't be re-used.
                    this.cancellationTokenSource = null;
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Read the entire contents of the flash.
        /// </summary>
        private async void readFullContents_BackgroundThread()
        {
            using (new AwayMode())
            {
                try
                {
                    this.Invoke((MethodInvoker) delegate()
                    {
                        this.DisableUserInput();
                        this.cancelButton.Enabled = true;
                    });

                    if (this.Vehicle == null)
                    {
                        // This shouldn't be possible - it would mean the buttons
                        // were enabled when they shouldn't be.
                        return;
                    }

                    // Get the path to save the image to.
                    string path = "";
                    this.Invoke((MethodInvoker) delegate() { path = this.ShowSaveAsDialog(); });
                    if (path == null)
                    {
                        this.AddUserMessage("Save canceled.");
                        return;
                    }

                    this.AddUserMessage("Will save to " + path);

                    this.cancellationTokenSource = new CancellationTokenSource();

                    this.AddUserMessage("Querying operating system of current PCM.");
                    Response <uint> osidResponse = await this.Vehicle.QueryOperatingSystemId(this.cancellationTokenSource.Token);

                    if (osidResponse.Status != ResponseStatus.Success)
                    {
                        this.AddUserMessage("Operating system query failed, will retry: " + osidResponse.Status);
                        await this.Vehicle.ExitKernel();

                        osidResponse = await this.Vehicle.QueryOperatingSystemId(this.cancellationTokenSource.Token);

                        if (osidResponse.Status != ResponseStatus.Success)
                        {
                            this.AddUserMessage("Operating system query failed: " + osidResponse.Status);
                        }
                    }

                    PcmInfo info;
                    if (osidResponse.Status == ResponseStatus.Success)
                    {
                        // Look up the information about this PCM, based on the OSID;
                        this.AddUserMessage("OSID: " + osidResponse.Value);
                        info = new PcmInfo(osidResponse.Value);
                    }
                    else
                    {
                        // TODO: prompt the user - 512kb or 1mb?
                        this.AddUserMessage("Will assume this is a 512kb PCM in recovery mode.");
                        info = new PcmInfo(0);
                    }

                    await this.Vehicle.SuppressChatter();

                    bool unlocked = await this.Vehicle.UnlockEcu(info.KeyAlgorithm);

                    if (!unlocked)
                    {
                        this.AddUserMessage("Unlock was not successful.");
                        return;
                    }

                    this.AddUserMessage("Unlock succeeded.");

                    if (cancellationTokenSource.Token.IsCancellationRequested)
                    {
                        return;
                    }

                    // Do the actual reading.
                    DateTime start = DateTime.Now;

                    CKernelReader reader = new CKernelReader(
                        this.Vehicle,
                        this);

                    Response <Stream> readResponse = await reader.ReadContents(
                        info,
                        cancellationTokenSource.Token);

                    this.AddUserMessage("Elapsed time " + DateTime.Now.Subtract(start));
                    if (readResponse.Status != ResponseStatus.Success)
                    {
                        this.AddUserMessage("Read failed, " + readResponse.Status.ToString());
                        return;
                    }

                    // Save the contents to the path that the user provided.
                    bool success = false;
                    do
                    {
                        try
                        {
                            this.AddUserMessage("Saving contents to " + path);

                            readResponse.Value.Position = 0;

                            using (Stream output = File.Open(path, FileMode.Create))
                            {
                                await readResponse.Value.CopyToAsync(output);
                            }

                            success = true;
                        }
                        catch (IOException exception)
                        {
                            this.AddUserMessage("Unable to save file: " + exception.Message);
                            this.AddDebugMessage(exception.ToString());

                            this.Invoke((MethodInvoker) delegate() { path = this.ShowSaveAsDialog(); });
                            if (path == null)
                            {
                                this.AddUserMessage("Save canceled.");
                                return;
                            }
                        }
                    } while (!success);
                }
                catch (Exception exception)
                {
                    this.AddUserMessage("Read failed: " + exception.ToString());
                }
                finally
                {
                    this.Invoke((MethodInvoker) delegate()
                    {
                        this.EnableUserInput();
                        this.cancelButton.Enabled = false;
                    });

                    // The token / token-source can only be cancelled once, so we need to make sure they won't be re-used.
                    this.cancellationTokenSource = null;
                }
            }
        }
예제 #5
0
        /// <summary>
        /// For testing prototype kernels.
        /// </summary>
        public async Task <bool> ExitKernel(bool kernelRunning, bool recoveryMode, CancellationToken cancellationToken, Stream unused)
        {
            try
            {
                this.device.ClearMessageQueue();

                Response <byte[]> response = await LoadKernelFromFile("test-kernel.bin");

                if (response.Status != ResponseStatus.Success)
                {
                    // The cleanup code in the finally block will exit the kernel.
                    return(true);
                }

                logger.AddUserMessage("Test kernel found.");

                UInt32          kernelVersion = 0;
                int             keyAlgorithm  = 1; // default, will work for most factory operating systems.
                Response <uint> osidResponse  = await this.QueryOperatingSystemId(cancellationToken);

                if (osidResponse.Status != ResponseStatus.Success)
                {
                    kernelVersion = await this.GetKernelVersion();

                    // TODO: Check for recovery mode.
                    // TODO: Load the tiny kernel, then use that to load the test kernel.
                    // Just to see whether we could potentially use that technique to assist
                    // a user whose flash is corrupted and regular flashing isn't working.
                }
                else
                {
                    PcmInfo info = new PcmInfo(osidResponse.Value);
                    keyAlgorithm = info.KeyAlgorithm;
                }

                this.logger.AddUserMessage("Unlocking PCM...");
                bool unlocked = await this.UnlockEcu(keyAlgorithm);

                if (!unlocked)
                {
                    this.logger.AddUserMessage("Unlock was not successful.");
                    return(false);
                }

                this.logger.AddUserMessage("Unlock succeeded.");

                if (cancellationToken.IsCancellationRequested)
                {
                    return(false);
                }

                if (!await PCMExecute(response.Value, 0xFF8000, cancellationToken))
                {
                    logger.AddUserMessage("Failed to upload kernel to PCM");

                    return(false);
                }

                logger.AddUserMessage("Kernel uploaded to PCM succesfully.");


                //await this.InvestigateDataCorruption(cancellationToken);
                //await this.InvestigateKernelVersionQueryTiming();
                //await this.InvestigateCrc(cancellationToken);
                //await this.InvestigateDataRelayCorruption(cancellationToken);
                await this.InvestigateFlashChipId();

                return(true);
            }
            catch (Exception exception)
            {
                this.logger.AddUserMessage("Something went wrong. " + exception.Message);
                this.logger.AddDebugMessage(exception.ToString());
                return(false);
            }
            finally
            {
                this.logger.AddUserMessage("Halting kernel.");
                await this.Cleanup();
            }
        }
예제 #6
0
        /// <summary>
        /// Read the full contents of the PCM.
        /// Assumes the PCM is unlocked an were ready to go
        /// </summary>
        public async Task <Response <Stream> > ReadContents(PcmInfo info, CancellationToken cancellationToken)
        {
            try
            {
                await this.vehicle.SendToolPresentNotification();

                this.vehicle.ClearDeviceMessageQueue();

                // switch to 4x, if possible. But continue either way.
                // if the vehicle bus switches but the device does not, the bus will need to time out to revert back to 1x, and the next steps will fail.
                if (!await this.vehicle.VehicleSetVPW4x(VpwSpeed.FourX))
                {
                    this.logger.AddUserMessage("Stopping here because we were unable to switch to 4X.");
                    return(Response.Create(ResponseStatus.Error, (Stream)null));
                }

                await this.vehicle.SendToolPresentNotification();

                // execute read kernel
                Response <byte[]> response = await vehicle.LoadKernelFromFile("read-kernel.bin");

                if (response.Status != ResponseStatus.Success)
                {
                    logger.AddUserMessage("Failed to load kernel from file.");
                    return(new Response <Stream>(response.Status, null));
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    return(Response.Create(ResponseStatus.Cancelled, (Stream)null));
                }

                await this.vehicle.SendToolPresentNotification();

                // TODO: instead of this hard-coded 0xFF9150, get the base address from the PcmInfo object.
                // TODO: choose kernel at run time? Because now it's FF8000...
                if (!await this.vehicle.PCMExecute(response.Value, 0xFF8000, cancellationToken))
                {
                    logger.AddUserMessage("Failed to upload kernel to PCM");

                    return(new Response <Stream>(
                               cancellationToken.IsCancellationRequested ? ResponseStatus.Cancelled : ResponseStatus.Error,
                               null));
                }

                logger.AddUserMessage("kernel uploaded to PCM succesfully. Requesting data...");

                await this.vehicle.SetDeviceTimeout(TimeoutScenario.ReadMemoryBlock);

                int startAddress   = info.ImageBaseAddress;
                int endAddress     = info.ImageBaseAddress + info.ImageSize;
                int bytesRemaining = info.ImageSize;
                int blockSize      = this.vehicle.DeviceMaxReceiveSize - 10 - 2; // allow space for the header and block checksum

                byte[] image = new byte[info.ImageSize];

                while (startAddress < endAddress)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        return(Response.Create(ResponseStatus.Cancelled, (Stream)null));
                    }

                    // The read kernel needs a short message here for reasons unknown. Without it, it will RX 2 messages then drop one.
                    await this.vehicle.ForceSendToolPresentNotification();

                    if (startAddress + blockSize > endAddress)
                    {
                        blockSize = endAddress - startAddress;
                    }

                    if (blockSize < 1)
                    {
                        this.logger.AddUserMessage("Image download complete");
                        break;
                    }

                    if (!await TryReadBlock(image, blockSize, startAddress, cancellationToken))
                    {
                        this.logger.AddUserMessage(
                            string.Format(
                                "Unable to read block from {0} to {1}",
                                startAddress,
                                (startAddress + blockSize) - 1));
                        return(new Response <Stream>(ResponseStatus.Error, null));
                    }

                    startAddress += blockSize;
                }

                await this.vehicle.Cleanup(); // Not sure why this does not get called in the finally block on successfull read?

                MemoryStream stream = new MemoryStream(image);
                return(new Response <Stream>(ResponseStatus.Success, stream));
            }
            catch (Exception exception)
            {
                this.logger.AddUserMessage("Something went wrong. " + exception.Message);
                this.logger.AddDebugMessage(exception.ToString());
                return(new Response <Stream>(ResponseStatus.Error, null));
            }
            finally
            {
                // Sending the exit command at both speeds and revert to 1x.
                await this.vehicle.Cleanup();
            }
        }
예제 #7
0
        /// <summary>
        /// Read the entire contents of the flash.
        /// </summary>
        private async void readFullContents_Routine()
        {
            try
            {
                this.Invoke((MethodInvoker) delegate()
                {
                    this.DisableUserInput();
                    this.cancelButton.Enabled = true;
                });

                this.cancellationTokenSource = new CancellationTokenSource();

                if (this.vehicle == null)
                {
                    // This shouldn't be possible - it would mean the buttons
                    // were enabled when they shouldn't be.
                    return;
                }

                DelayDialogBox dialogBox    = new DelayDialogBox();
                DialogResult   dialogResult = dialogBox.ShowDialog();
                if (dialogResult == DialogResult.Cancel)
                {
                    return;
                }

                this.AddUserMessage("Querying operating system of current PCM.");
                Response <uint> osidResponse = await this.vehicle.QueryOperatingSystemId();

                if (osidResponse.Status != ResponseStatus.Success)
                {
                    this.AddUserMessage("Operating system query failed, will retry: " + osidResponse.Status);
                    await this.vehicle.ExitKernel();

                    osidResponse = await this.vehicle.QueryOperatingSystemId();

                    if (osidResponse.Status != ResponseStatus.Success)
                    {
                        this.AddUserMessage("Operating system query failed, giving up: " + osidResponse.Status);
                        return;
                    }
                }

                // Look up the information about this PCM, based on the OSID;
                this.AddUserMessage("OSID: " + osidResponse.Value);
                PcmInfo info = new PcmInfo(osidResponse.Value);

                await this.vehicle.SuppressChatter();

                bool unlocked = await this.vehicle.UnlockEcu(info.KeyAlgorithm);

                if (!unlocked)
                {
                    this.AddUserMessage("Unlock was not successful.");
                    return;
                }

                this.AddUserMessage("Unlock succeeded.");

                if (this.cancellationTokenSource.Token.IsCancellationRequested)
                {
                    return;
                }

                // Do the actual reading.
                Response <Stream> readResponse = await this.vehicle.ReadContents(info, this.cancellationTokenSource.Token);

                if (readResponse.Status != ResponseStatus.Success)
                {
                    this.AddUserMessage("Read failed, " + readResponse.Status.ToString());
                    return;
                }

                // Get the path to save the image to.
                //
                // TODO: remember this value and offer to re-use it, in case
                // the read fails and the user has to try again.
                //
                string path = "";
                this.Invoke((MethodInvoker) delegate() { path = this.ShowSaveAsDialog(); });
                if (path == null)
                {
                    this.AddUserMessage("Save canceled.");
                    return;
                }

                this.AddUserMessage("Will save to " + path);

                // Save the contents to the path that the user provided.
                try
                {
                    this.AddUserMessage("Saving contents to " + path);

                    readResponse.Value.Position = 0;

                    using (Stream output = File.OpenWrite(path))
                    {
                        await readResponse.Value.CopyToAsync(output);
                    }
                }
                catch (IOException exception)
                {
                    this.AddUserMessage("Unable to save file: " + exception.Message);
                    this.AddDebugMessage(exception.ToString());
                }
            }
            catch (Exception exception)
            {
                this.AddUserMessage("Read failed: " + exception.ToString());
            }
            finally
            {
                this.Invoke((MethodInvoker) delegate()
                {
                    this.EnableUserInput();
                    this.cancelButton.Enabled = false;
                });

                // This should not get used again. If it does, that would
                // indicate a bug, so let's make sure that any attempt to
                // use it won't go un-noticed.
                this.cancellationTokenSource = null;
            }
        }