Пример #1
0
        /// <summary>
        /// Write the calibration blocks.
        /// </summary>
        private async Task <bool> Write(CancellationToken cancellationToken, byte[] image, WriteType writeType)
        {
            await this.vehicle.SendToolPresentNotification();

            BlockType relevantBlocks;

            switch (writeType)
            {
            case WriteType.Compare:
                relevantBlocks = BlockType.All;
                break;

            case WriteType.TestWrite:
                relevantBlocks = BlockType.Calibration;
                break;

            case WriteType.Calibration:
                relevantBlocks = BlockType.Calibration;
                break;

            case WriteType.Parameters:
                relevantBlocks = BlockType.Parameter;
                break;

            case WriteType.OsAndCalibration:
                relevantBlocks = BlockType.Calibration | BlockType.OperatingSystem;
                break;

            case WriteType.Full:
                // Overwriting parameter blocks would break the EBCM pairing,
                // which is not what most users want. They just want a new OS
                // and the calibration to go along with it.
                //
                // The cast seems redundant, but C# converts the enum values
                // to ints when it does arithmetic.
                relevantBlocks = (BlockType)(BlockType.All - BlockType.Parameter);
                break;

            default:
                throw new InvalidDataException("Unsuppported operation type: " + writeType.ToString());
            }

            // Which flash chip?
            await this.vehicle.SendToolPresentNotification();

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

            Query <UInt32> chipIdQuery = this.vehicle.CreateQuery <UInt32>(
                this.protocol.CreateFlashMemoryTypeQuery,
                this.protocol.ParseFlashMemoryType,
                cancellationToken);
            Response <UInt32> chipIdResponse = await chipIdQuery.Execute();

            if (chipIdResponse.Status != ResponseStatus.Success)
            {
                logger.AddUserMessage("Unable to determine which flash chip is in this PCM");
                return(false);
            }

            // TODO: Move the device types lookup to a function in Misc/FlashChips.cs
            // known chips in the P01 and P59
            // http://ftp1.digi.com/support/documentation/jtag_v410_flashes.pdf
            string Amd     = "AMD";               // 0001
            string Intel   = "Intel";             // 0089
            string I4471   = "28F400B5-B 512Kb";  // 4471
            string A2258   = "Am29F800B 1Mbyte";  // 2258
            string I889D   = "28F800B5-B 1Mbyte"; // 889D
            string unknown = "unknown";           // default case

            logger.AddUserMessage("Flash memory ID code: " + chipIdResponse.Value.ToString("X8"));

            switch ((chipIdResponse.Value >> 16))
            {
            case 0x0001: logger.AddUserMessage("Flash memory manufactuer: " + Amd);
                break;

            case 0x0089: logger.AddUserMessage("Flash memory manufactuer: " + Intel);
                break;

            default: logger.AddUserMessage("Flash memory manufactuer: " + unknown);
                break;
            }

            switch (chipIdResponse.Value & 0xFFFF)
            {
            case 0x4471: logger.AddUserMessage("Flash memory type: " + I4471);
                break;

            case 0x2258: logger.AddUserMessage("Flash memory type: " + A2258);
                break;

            case 0x889D: logger.AddUserMessage("Flash memory type: " + I889D);
                break;

            default: logger.AddUserMessage("Flash memory type: " + unknown);
                break;
            }

            await this.vehicle.SendToolPresentNotification();

            IList <MemoryRange> ranges = FlashChips.GetMemoryRanges(chipIdResponse.Value, this.logger);

            if (ranges == null)
            {
                return(false);
            }

            CKernelVerifier verifier = new CKernelVerifier(
                image,
                ranges,
                this.vehicle,
                this.protocol,
                this.logger);

            bool allRangesMatch = false;
            bool writeAttempted = false;

            for (int attempt = 1; attempt <= 5; attempt++)
            {
                if (await verifier.CompareRanges(
                        ranges,
                        image,
                        relevantBlocks,
                        cancellationToken))
                {
                    allRangesMatch = true;

                    // Don't stop here if the user just wants to test their cable.
                    if (writeType == WriteType.TestWrite)
                    {
                        if (attempt == 1)
                        {
                            this.logger.AddUserMessage("Beginning test.");
                        }
                    }
                    else
                    {
                        this.logger.AddUserMessage("All ranges are identical.");
                        return(true);
                    }
                }

                if ((writeType == WriteType.TestWrite) && (attempt > 1))
                {
                    // TODO: the app should know if any errors were encountered. The user shouldn't need to check.
                    this.logger.AddUserMessage("Test complete. Were any errors logged above?");
                    return(true);
                }

                // Stop now if the user only requested a comparison.
                if (writeType == WriteType.Compare)
                {
                    this.logger.AddUserMessage("Note that mismatched Parameter blocks are to be expected.");
                    this.logger.AddUserMessage("Parameter data can change every time the PCM is used.");
                    return(true);
                }

                writeAttempted = true;

                // Erase and rewrite the required memory ranges.
                await this.vehicle.SetDeviceTimeout(TimeoutScenario.Maximum);

                foreach (MemoryRange range in ranges)
                {
                    // We'll send a tool-present message during the erase request.
                    if ((range.ActualCrc == range.DesiredCrc) && (writeType != WriteType.TestWrite))
                    {
                        continue;
                    }

                    if ((range.Type & relevantBlocks) == 0)
                    {
                        continue;
                    }

                    this.logger.AddUserMessage(
                        string.Format(
                            "Processing range {0:X6}-{1:X6}",
                            range.Address,
                            range.Address + (range.Size - 1)));

                    if (writeType == WriteType.TestWrite)
                    {
                        this.logger.AddUserMessage("Pretending to erase.");
                    }
                    else
                    {
                        if (!await this.EraseMemoryRange(range, cancellationToken))
                        {
                            return(false);
                        }
                    }

                    if (writeType == WriteType.TestWrite)
                    {
                        this.logger.AddUserMessage("Pretending to write...");
                    }
                    else
                    {
                        this.logger.AddUserMessage("Writing...");
                    }

                    await this.vehicle.SendToolPresentNotification();

                    await WriteMemoryRange(
                        range,
                        image,
                        writeType == WriteType.TestWrite,
                        cancellationToken);
                }
            }

            if (!writeAttempted)
            {
                this.logger.AddUserMessage("Assertion failed. WriteAttempted should be true.");
            }

            if (allRangesMatch)
            {
                this.logger.AddUserMessage("Flash successful!");
                return(true);
            }

            this.logger.AddUserMessage("===============================================");
            this.logger.AddUserMessage("THE CHANGES WERE -NOT- WRITTEN SUCCESSFULLY");
            this.logger.AddUserMessage("===============================================");

            if (writeType == WriteType.Calibration)
            {
                this.logger.AddUserMessage("Erasing Calibration to force recovery mode.");
                this.logger.AddUserMessage("");

                foreach (MemoryRange range in ranges)
                {
                    if (range.Type == BlockType.Calibration)
                    {
                        await this.EraseMemoryRange(range, cancellationToken);
                    }
                }
            }

            if (cancellationToken.IsCancellationRequested)
            {
                this.logger.AddUserMessage("");
                this.logger.AddUserMessage("The operation was cancelled.");
                this.logger.AddUserMessage("This PCM is probably not usable in its current state.");
                this.logger.AddUserMessage("");
            }
            else
            {
                this.logger.AddUserMessage("This may indicate a hardware problem on the PCM.");
                this.logger.AddUserMessage("We tried, and re-tried, and it still didn't work.");
                this.logger.AddUserMessage("");
                this.logger.AddUserMessage("Please start a new thread at pcmhacking.net, and");
                this.logger.AddUserMessage("include the contents of the debug tab.");
                this.RequestDebugLogs(cancellationToken);
            }

            return(false);
        }
Пример #2
0
        /// <summary>
        /// This was used to test the kernel's CRC code.
        /// </summary>
        private async Task InvestigateCrc(CancellationToken cancellationToken)
        {
            IList <MemoryRange> ranges = FlashChips.GetMemoryRanges(0x00894471, this.logger);

            logger.AddUserMessage("Requesting CRCs from PCM...");
            foreach (MemoryRange range in ranges)
            {
                this.device.ClearMessageQueue();
                bool   success = false;
                UInt32 crc     = 0;
                await this.device.SetTimeout(TimeoutScenario.ReadCrc);

                // You might think that a shorter retry delay would speed things up,
                // but 1500ms delay gets CRC results in about 3.5 seconds.
                // A 1000ms delay resulted in 4+ second CRC responses, and a 750ms
                // delay resulted in 5 second CRC responses. The PCM needs to spend
                // its time caculating CRCs rather than responding to messages.
                int     retryDelay = 1500;
                Message query      = this.protocol.CreateCrcQuery(range.Address, range.Size);
                for (int attempts = 0; attempts < 100; attempts++)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    if (!await this.device.SendMessage(query))
                    {
                        await Task.Delay(retryDelay);

                        continue;
                    }

                    Message response = await this.device.ReceiveMessage();

                    if (response == null)
                    {
                        await Task.Delay(retryDelay);

                        continue;
                    }

                    Response <UInt32> crcResponse = this.protocol.ParseCrc(response, range.Address, range.Size);
                    if (crcResponse.Status != ResponseStatus.Success)
                    {
                        await Task.Delay(retryDelay);

                        continue;
                    }

                    success = true;
                    crc     = crcResponse.Value;
                    break;
                }

                this.device.ClearMessageQueue();

                if (!success)
                {
                    this.logger.AddUserMessage("Unable to get CRC for memory range " + range.Address.ToString("X8") + " / " + range.Size.ToString("X8"));
                    continue;
                }

                range.ActualCrc = crc;

                this.logger.AddUserMessage(
                    string.Format(
                        "Range {0:X6}-{1:X6} - Local: {2:X8} - PCM: {3:X8} - {4}",
                        range.Address,
                        range.Address + (range.Size - 1),
                        range.DesiredCrc,
                        range.ActualCrc,
                        range.Type));
            }
        }