/// <summary> /// Unlock the PCM by requesting a 'seed' and then sending the corresponding 'key' value. /// </summary> public async Task<bool> UnlockEcu(int keyAlgorithm) { await this.device.SetTimeout(TimeoutScenario.ReadProperty); this.device.ClearMessageQueue(); this.logger.AddDebugMessage("Sending seed request."); Message seedRequest = this.messageFactory.CreateSeedRequest(); if (!await this.TrySendMessage(seedRequest, "seed request")) { this.logger.AddUserMessage("Unable to send seed request."); return false; } bool seedReceived = false; UInt16 seedValue = 0; for (int attempt = 1; attempt < MaxReceiveAttempts; attempt++) { Message seedResponse = await this.device.ReceiveMessage(); if (seedResponse == null) { this.logger.AddDebugMessage("No response to seed request."); return false; } if (this.messageParser.IsUnlocked(seedResponse.GetBytes())) { this.logger.AddUserMessage("PCM is already unlocked"); return true; } this.logger.AddDebugMessage("Parsing seed value."); Response<UInt16> seedValueResponse = this.messageParser.ParseSeed(seedResponse.GetBytes()); if (seedValueResponse.Status == ResponseStatus.Success) { seedValue = seedValueResponse.Value; seedReceived = true; break; } this.logger.AddDebugMessage("Unable to parse seed response. Attempt #" + attempt.ToString()); } if (!seedReceived) { this.logger.AddUserMessage("No seed reponse received, unable to unlock PCM."); return false; } if (seedValue == 0x0000) { this.logger.AddUserMessage("PCM Unlock not required"); return true; } UInt16 key = KeyAlgorithm.GetKey(keyAlgorithm, seedValue); this.logger.AddDebugMessage("Sending unlock request (" + seedValue.ToString("X4") + ", " + key.ToString("X4") + ")"); Message unlockRequest = this.messageFactory.CreateUnlockRequest(key); if (!await this.TrySendMessage(unlockRequest, "unlock request")) { this.logger.AddDebugMessage("Unable to send unlock request."); return false; } for (int attempt = 1; attempt < MaxReceiveAttempts; attempt++) { Message unlockResponse = await this.device.ReceiveMessage(); if (unlockResponse == null) { this.logger.AddDebugMessage("No response to unlock request. Attempt #" + attempt.ToString()); continue; } string errorMessage; Response<bool> result = this.messageParser.ParseUnlockResponse(unlockResponse.GetBytes(), out errorMessage); if (errorMessage == null) { return result.Value; } this.logger.AddUserMessage(errorMessage); } this.logger.AddUserMessage("Unable to process unlock response."); return false; }
/// <summary> /// Suppres chatter on the VPW bus. /// </summary> public async Task SuppressChatter() { this.logger.AddDebugMessage("Suppressing VPW chatter."); Message suppressChatter = this.messageFactory.CreateDisableNormalMessageTransmission(); await this.device.SendMessage(suppressChatter); }
/// <summary> /// Load the executable payload on the PCM at the supplied address, and execute it. /// </summary> public async Task<bool> PCMExecute(byte[] payload, int address, CancellationToken cancellationToken) { logger.AddUserMessage("Uploading kernel to PCM."); logger.AddDebugMessage("Sending upload request with payload size " + payload.Length + ", loadaddress " + address.ToString("X6")); Message request = messageFactory.CreateUploadRequest(payload.Length, address); if(!await TrySendMessage(request, "upload request")) { return false; } if (!await this.WaitForSuccess(this.messageParser.ParseUploadPermissionResponse)) { logger.AddUserMessage("Permission to upload kernel was denied."); return false; } if (cancellationToken.IsCancellationRequested) { return false; } logger.AddDebugMessage("Going to load a " + payload.Length + " byte payload to 0x" + address.ToString("X6")); await this.device.SetTimeout(TimeoutScenario.SendKernel); // Loop through the payload building and sending packets, highest first, execute on last int payloadSize = device.MaxSendSize - 12; // Headers use 10 bytes, sum uses 2 bytes. int chunkCount = payload.Length / payloadSize; int remainder = payload.Length % payloadSize; int offset = (chunkCount * payloadSize); int startAddress = address + offset; // First we send the 'remainder' payload, containing any bytes that won't fill up an entire upload packet. logger.AddDebugMessage( string.Format( "Sending remainder payload with offset 0x{0:X}, start address 0x{1:X}, length 0x{2:X}.", offset, startAddress, remainder)); Message remainderMessage = messageFactory.CreateBlockMessage( payload, offset, remainder, address + offset, remainder == payload.Length); Response<bool> uploadResponse = await WriteToRam(remainderMessage); if (uploadResponse.Status != ResponseStatus.Success) { logger.AddDebugMessage("Could not upload kernel to PCM, remainder payload not accepted."); return false; } // Now we send a series of full upload packets for (int chunkIndex = chunkCount; chunkIndex > 0; chunkIndex--) { if (cancellationToken.IsCancellationRequested) { return false; } offset = (chunkIndex - 1) * payloadSize; startAddress = address + offset; Message payloadMessage = messageFactory.CreateBlockMessage( payload, offset, payloadSize, startAddress, offset == 0); logger.AddDebugMessage( string.Format( "Sending payload with offset 0x{0:X}, start address 0x{1:X}, length 0x{2:X}.", offset, startAddress, payloadSize)); uploadResponse = await WriteToRam(payloadMessage); if (uploadResponse.Status != ResponseStatus.Success) { logger.AddDebugMessage("Could not upload kernel to PCM, payload not accepted."); return false; } int bytesSent = payload.Length - offset; int percentDone = bytesSent * 100 / payload.Length; this.logger.AddUserMessage( string.Format( "Kernel upload {0}% complete.", percentDone)); } return true; }
/// <summary> /// Does everything required to switch to VPW 4x /// </summary> public async Task<bool> VehicleSetVPW4x(VpwSpeed newSpeed) { if (!device.Supports4X) { if (newSpeed == VpwSpeed.FourX) { // where there is no support only report no switch to 4x logger.AddUserMessage("This interface does not support VPW 4x"); } return true; } // Configure the vehicle bus when switching to 4x if (newSpeed == VpwSpeed.FourX) { logger.AddUserMessage("Attempting switch to VPW 4x"); await device.SetTimeout(TimeoutScenario.ReadProperty); // The list of modules may not be useful after all, but // checking for an empty list indicates an uncooperative // module on the VPW bus. List<byte> modules = await this.RequestHighSpeedPermission(); if (modules == null) { // A device has refused the switch to high speed mode. return false; } Message broadcast = this.messageFactory.CreateBeginHighSpeed(DeviceId.Broadcast); await this.device.SendMessage(broadcast); // Check for any devices that refused to switch to 4X speed. // These responses usually get lost, so this code might be pointless. Message response = null; while ((response = await this.device.ReceiveMessage()) != null) { Response<bool> refused = this.messageParser.ParseHighSpeedRefusal(response); if (refused.Status != ResponseStatus.Success) { continue; } if (refused.Value == false) { // TODO: Add module number. this.logger.AddUserMessage("Module refused high-speed switch."); return false; } } } else { logger.AddUserMessage("Reverting to VPW 1x"); } // Request the device to change await device.SetVpwSpeed(newSpeed); TimeoutScenario scenario = newSpeed == VpwSpeed.Standard ? TimeoutScenario.ReadProperty : TimeoutScenario.ReadMemoryBlock; await device.SetTimeout(scenario); return true; }
private async Task<bool> TryReadBlock(byte[] image, int length, int startAddress) { this.logger.AddDebugMessage(string.Format("Reading from {0}, length {1}", startAddress, length)); for(int sendAttempt = 1; sendAttempt <= MaxSendAttempts; sendAttempt++) { Message message = this.messageFactory.CreateReadRequest(startAddress, length); //this.logger.AddDebugMessage("Sending " + message.GetBytes().ToHex()); if (!await this.device.SendMessage(message)) { this.logger.AddDebugMessage("Unable to send read request."); continue; } bool sendAgain = false; for (int receiveAttempt = 1; receiveAttempt <= MaxReceiveAttempts; receiveAttempt++) { Message response = await this.ReceiveMessage(); if (response == null) { this.logger.AddDebugMessage("Did not receive a response to the read request."); sendAgain = true; break; } this.logger.AddDebugMessage("Processing message"); Response<bool> readResponse = this.messageParser.ParseReadResponse(response); if (readResponse.Status != ResponseStatus.Success) { this.logger.AddDebugMessage("Not a read response."); continue; } if (!readResponse.Value) { this.logger.AddDebugMessage("Read request failed."); sendAgain = true; break; } // We got a successful read response, so now wait for the payload. sendAgain = false; break; } if (sendAgain) { continue; } this.logger.AddDebugMessage("Read request allowed, expecting for payload..."); for (int receiveAttempt = 1; receiveAttempt <= MaxReceiveAttempts; receiveAttempt++) { Message payloadMessage = await this.device.ReceiveMessage(); if (payloadMessage == null) { this.logger.AddDebugMessage("No payload following read request."); continue; } this.logger.AddDebugMessage("Processing message"); Response<byte[]> payloadResponse = this.messageParser.ParsePayload(payloadMessage, length, startAddress); if (payloadResponse.Status != ResponseStatus.Success) { this.logger.AddDebugMessage("Not a valid payload message or bad checksum"); continue; } byte[] payload = payloadResponse.Value; Buffer.BlockCopy(payload, 0, image, startAddress, length); int percentDone = (startAddress * 100) / image.Length; this.logger.AddUserMessage(string.Format("Recieved block starting at {0} / 0x{0:X}. {1}%", startAddress, percentDone)); return true; } } return false; }