private void UnlockControllerForEepromReadWrite(IKW1281Dialog kwp1281) { switch ((ControllerAddress)_controllerAddress) { case ControllerAddress.CCM: case ControllerAddress.CentralLocking: kwp1281.Login(code: 19283, workshopCode: 222); // This is what VDS-PRO uses break; case ControllerAddress.Cluster: // TODO:UnlockCluster() is only needed for EEPROM read, not memory read if (!VdoCluster.UnlockCluster(kwp1281)) { Logger.WriteLine("Unknown cluster software version. EEPROM access will likely fail."); } if (!ClusterRequiresSeedKey(kwp1281)) { Logger.WriteLine( "Cluster is unlocked for EEPROM access. Skipping Seed/Key login."); return; } ClusterSeedKeyAuthenticate(kwp1281); break; } }
private void ClarionVWPremium4SafeCode(IKW1281Dialog kwp1281) { if (_controllerAddress != (int)ControllerAddress.Radio) { Logger.WriteLine("Only supported for radio address 56"); return; } // Thanks to Mike Naberezny for this (https://github.com/mnaberez) const byte readWriteSafeCode = 0xF0; const byte read = 0x00; kwp1281.SendBlock(new List <byte> { readWriteSafeCode, read }); var block = kwp1281.ReceiveBlocks().FirstOrDefault(b => !b.IsAckNak); if (block == null) { Logger.WriteLine("No response received from radio."); } else if (block.Title != readWriteSafeCode) { Logger.WriteLine( $"Unexpected response received from radio. Block title: ${block.Title:X2}"); } else { var safeCode = block.Body[0] * 256 + block.Body[1]; Logger.WriteLine($"Safe code: {safeCode:X4}"); } }
private static void ClusterSeedKeyAuthenticate(IKW1281Dialog kwp1281) { // Perform Seed/Key authentication Logger.WriteLine("Sending Custom \"Seed request\" block"); var response = kwp1281.SendCustom(new List <byte> { 0x96, 0x01 }); var responseBlocks = response.Where(b => !b.IsAckNak).ToList(); if (responseBlocks.Count == 1 && responseBlocks[0] is CustomBlock customBlock) { Logger.WriteLine($"Block: {Utils.Dump(customBlock.Body)}"); var keyBytes = VdoKeyFinder.FindKey(customBlock.Body.ToArray()); Logger.WriteLine("Sending Custom \"Key response\" block"); var keyResponse = new List <byte> { 0x96, 0x02 }; keyResponse.AddRange(keyBytes); response = kwp1281.SendCustom(keyResponse); } }
// Begin top-level commands private static void ActuatorTest(IKW1281Dialog kwp1281) { using KW1281KeepAlive keepAlive = new(kwp1281); ConsoleKeyInfo keyInfo; do { var response = keepAlive.ActuatorTest(0x00); if (response == null || response.ActuatorName == "End") { Logger.WriteLine("End of test."); break; } Logger.WriteLine($"Actuator Test: {response.ActuatorName}"); // Press any key to advance to next test or press Q to exit Console.Write("Press 'N' to advance to next test or 'Q' to quit"); do { keyInfo = Console.ReadKey(intercept: true); } while (keyInfo.Key != ConsoleKey.N && keyInfo.Key != ConsoleKey.Q); Console.WriteLine(); } while (keyInfo.Key != ConsoleKey.Q); }
private void DumpClusterMem(IKW1281Dialog kwp1281, uint startAddress, uint length) { UnlockControllerForEepromReadWrite(kwp1281); const byte blockSize = 15; var dumpFileName = _filename ?? $"cluster_mem_${startAddress:X6}.bin"; Logger.WriteLine($"Saving memory dump to {dumpFileName}"); using (var fs = File.Create(dumpFileName, blockSize, FileOptions.WriteThrough)) { for (uint addr = startAddress; addr < startAddress + length; addr += blockSize) { var readLength = (byte)Math.Min(startAddress + length - addr, blockSize); var blockBytes = kwp1281.CustomReadMemory(addr, readLength); if (blockBytes.Count != readLength) { throw new InvalidOperationException( $"Expected {readLength} bytes from CustomReadMemory() but received {blockBytes.Count} bytes"); } fs.Write(blockBytes.ToArray(), 0, blockBytes.Count); fs.Flush(); } } Logger.WriteLine($"Saved memory dump to {dumpFileName}"); }
private static void DumpEeprom( IKW1281Dialog kwp1281, ushort startAddr, ushort length, byte maxReadLength, string fileName) { bool succeeded = true; using (var fs = File.Create(fileName, maxReadLength, FileOptions.WriteThrough)) { for (uint addr = startAddr; addr < (startAddr + length); addr += maxReadLength) { var readLength = (byte)Math.Min(startAddr + length - addr, maxReadLength); var blockBytes = kwp1281.ReadEeprom((ushort)addr, (byte)readLength); if (blockBytes == null) { blockBytes = Enumerable.Repeat((byte)0, readLength).ToList(); succeeded = false; } fs.Write(blockBytes.ToArray(), 0, blockBytes.Count); fs.Flush(); } } if (!succeeded) { Logger.WriteLine(); Logger.WriteLine("**********************************************************************"); Logger.WriteLine("*** Warning: Some bytes could not be read and were replaced with 0 ***"); Logger.WriteLine("**********************************************************************"); Logger.WriteLine(); } }
private static void ReadIdent(IKW1281Dialog kwp1281) { foreach (var identInfo in kwp1281.ReadIdent()) { Logger.WriteLine($"Ident: {identInfo}"); } }
private void WriteEeprom(IKW1281Dialog kwp1281, uint address, byte value) { UnlockControllerForEepromReadWrite(kwp1281); kwp1281.WriteEeprom((ushort)address, new List <byte> { value }); }
private void LoadEeprom(IKW1281Dialog kwp1281, uint address) { if (_controllerAddress != (int)ControllerAddress.Cluster) { Logger.WriteLine("Only supported for cluster"); return; } LoadClusterEeprom(kwp1281, (ushort)address, _filename); }
private void DumpMem(IKW1281Dialog kwp1281, uint address, uint length) { if (_controllerAddress != (int)ControllerAddress.Cluster) { Logger.WriteLine("Only supported for cluster"); return; } DumpClusterMem(kwp1281, address, length); }
private void DumpCcmEeprom(IKW1281Dialog kwp1281, ushort startAddress, ushort length) { UnlockControllerForEepromReadWrite(kwp1281); var dumpFileName = _filename ?? $"ccm_eeprom_${startAddress:X4}.bin"; Logger.WriteLine($"Saving EEPROM dump to {dumpFileName}"); DumpEeprom(kwp1281, startAddress, length, maxReadLength: 12, dumpFileName); Logger.WriteLine($"Saved EEPROM dump to {dumpFileName}"); }
private static void ReadFaultCodes(IKW1281Dialog kwp1281) { var faultCodes = kwp1281.ReadFaultCodes(); Logger.WriteLine("Fault codes:"); foreach (var faultCode in faultCodes) { Logger.WriteLine($" {faultCode}"); } }
private void Reset(IKW1281Dialog kwp1281) { if (_controllerAddress == (int)ControllerAddress.Cluster) { kwp1281.CustomReset(); } else { Logger.WriteLine("Only supported for cluster"); } }
private void DumpCcmRom(IKW1281Dialog kwp1281) { if (_controllerAddress != (int)ControllerAddress.CCM && _controllerAddress != (int)ControllerAddress.CentralLocking) { Logger.WriteLine("Only supported for CCM and Central Locking"); return; } kwp1281.Login(19283, 222); var dumpFileName = _filename ?? "ccm_rom_dump.bin"; const byte blockSize = 8; Logger.WriteLine($"Saving CCM ROM to {dumpFileName}"); bool succeeded = true; using (var fs = File.Create(dumpFileName, blockSize, FileOptions.WriteThrough)) { for (int seg = 0; seg < 16; seg++) { for (int msb = 0; msb < 16; msb++) { for (int lsb = 0; lsb < 256; lsb += blockSize) { var blockBytes = kwp1281.ReadCcmRom((byte)seg, (byte)msb, (byte)lsb, blockSize); if (blockBytes == null) { blockBytes = Enumerable.Repeat((byte)0, blockSize).ToList(); succeeded = false; } else if (blockBytes.Count < blockSize) { blockBytes.AddRange(Enumerable.Repeat((byte)0, blockSize - blockBytes.Count)); succeeded = false; } fs.Write(blockBytes.ToArray(), 0, blockBytes.Count); fs.Flush(); } } } } if (!succeeded) { Logger.WriteLine(); Logger.WriteLine("**********************************************************************"); Logger.WriteLine("*** Warning: Some bytes could not be read and were replaced with 0 ***"); Logger.WriteLine("**********************************************************************"); Logger.WriteLine(); } }
private void DumpClusterEeprom(IKW1281Dialog kwp1281, ushort startAddress, ushort length) { var identInfo = kwp1281.ReadIdent().First().ToString().Replace(' ', '_').Replace(":", ""); UnlockControllerForEepromReadWrite(kwp1281); var dumpFileName = _filename ?? $"{identInfo}_${startAddress:X4}_eeprom.bin"; Logger.WriteLine($"Saving EEPROM dump to {dumpFileName}"); DumpEeprom(kwp1281, startAddress, length, maxReadLength: 16, dumpFileName); Logger.WriteLine($"Saved EEPROM dump to {dumpFileName}"); }
private void ClearFaultCodes(IKW1281Dialog kwp1281) { var succeeded = kwp1281.ClearFaultCodes(_controllerAddress); if (succeeded) { Logger.WriteLine("Fault codes cleared."); } else { Logger.WriteLine("Failed to clear fault codes."); } }
private void SetSoftwareCoding( IKW1281Dialog kwp1281, int softwareCoding, int workshopCode) { var succeeded = kwp1281.SetSoftwareCoding(_controllerAddress, softwareCoding, workshopCode); if (succeeded) { Logger.WriteLine("Software coding set."); } else { Logger.WriteLine("Failed to set software coding."); } }
private string DumpClusterEeprom(IKW1281Dialog kwp1281, ushort startAddress, ushort length) { var identInfo = kwp1281.ReadIdent().First().ToString() .Split(Environment.NewLine).First() // Sometimes ReadIdent() can return multiple lines .Replace(' ', '_').Replace(":", ""); UnlockControllerForEepromReadWrite(kwp1281); var dumpFileName = _filename ?? $"{identInfo}_${startAddress:X4}_eeprom.bin"; Logger.WriteLine($"Saving EEPROM dump to {dumpFileName}"); DumpEeprom(kwp1281, startAddress, length, maxReadLength: 16, dumpFileName); Logger.WriteLine($"Saved EEPROM dump to {dumpFileName}"); return(dumpFileName); }
private void DumpClusterNecRom(IKW1281Dialog kwp1281) { if (_controllerAddress != (int)ControllerAddress.Cluster) { Logger.WriteLine("Only supported for cluster"); return; } var dumpFileName = _filename ?? "cluster_nec_rom_dump.bin"; const byte blockSize = 16; Logger.WriteLine($"Saving cluster NEC ROM to {dumpFileName}"); bool succeeded = true; using (var fs = File.Create(dumpFileName, blockSize, FileOptions.WriteThrough)) { { for (int address = 0; address < 65536; address += blockSize) { var blockBytes = kwp1281.CustomReadNecRom((ushort)address, blockSize); if (blockBytes == null) { blockBytes = Enumerable.Repeat((byte)0, blockSize).ToList(); succeeded = false; } else if (blockBytes.Count < blockSize) { blockBytes.AddRange(Enumerable.Repeat((byte)0, blockSize - blockBytes.Count)); succeeded = false; } fs.Write(blockBytes.ToArray(), 0, blockBytes.Count); fs.Flush(); } } } if (!succeeded) { Logger.WriteLine(); Logger.WriteLine("**********************************************************************"); Logger.WriteLine("*** Warning: Some bytes could not be read and were replaced with 0 ***"); Logger.WriteLine("**********************************************************************"); Logger.WriteLine(); } }
private void ReadEeprom(IKW1281Dialog kwp1281, uint address) { UnlockControllerForEepromReadWrite(kwp1281); var blockBytes = kwp1281.ReadEeprom((ushort)address, 1); if (blockBytes == null) { Logger.WriteLine("EEPROM read failed"); } else { var value = blockBytes[0]; Logger.WriteLine( $"Address {address} (${address:X4}): Value {value} (${value:X2})"); } }
private void LoadClusterEeprom(IKW1281Dialog kwp1281, ushort address, string filename) { _ = kwp1281.ReadIdent(); UnlockControllerForEepromReadWrite(kwp1281); if (!File.Exists(filename)) { Logger.WriteLine($"File {filename} does not exist."); return; } Logger.WriteLine($"Reading {filename}"); var bytes = File.ReadAllBytes(filename); Logger.WriteLine("Writing to cluster..."); WriteEeprom(kwp1281, address, bytes, 16); }
private void DumpEeprom(IKW1281Dialog kwp1281, uint address, uint length) { switch (_controllerAddress) { case (int)ControllerAddress.Cluster: DumpClusterEeprom(kwp1281, (ushort)address, (ushort)length); break; case (int)ControllerAddress.CCM: case (int)ControllerAddress.CentralLocking: DumpCcmEeprom(kwp1281, (ushort)address, (ushort)length); break; default: Logger.WriteLine("Only supported for cluster, CCM and Central Locking"); break; } }
private void MapEeprom(IKW1281Dialog kwp1281) { switch (_controllerAddress) { case (int)ControllerAddress.Cluster: MapClusterEeprom(kwp1281); break; case (int)ControllerAddress.CCM: case (int)ControllerAddress.CentralLocking: MapCcmEeprom(kwp1281); break; default: Logger.WriteLine("Only supported for cluster, CCM and Central Locking"); break; } }
private void DelcoVWPremium5SafeCode(IKW1281Dialog kwp1281) { if (_controllerAddress != (int)ControllerAddress.RadioManufacturing) { Logger.WriteLine("Only supported for radio manufacturing address 7C"); return; } // Thanks to Mike Naberezny for this (https://github.com/mnaberez) const string secret = "DELCO"; var code = (ushort)(secret[4] * 256 + secret[3]); var workshopCode = (ushort)(secret[1] * 256 + secret[0]); var unknown = (byte)secret[2]; kwp1281.Login(code, workshopCode, unknown); var bytes = kwp1281.ReadRomEeprom(0x0014, 2); Logger.WriteLine($"Safe code: {bytes[0]:X2}{bytes[1]:X2}"); }
private static bool ClusterRequiresSeedKey(IKW1281Dialog kwp1281) { Logger.WriteLine("Sending Custom \"Need Seed/Key?\" block"); var response = kwp1281.SendCustom(new List <byte> { 0x96, 0x04 }); var responseBlocks = response.Where(b => !b.IsAckNak).ToList(); if (responseBlocks.Count == 1 && responseBlocks[0] is CustomBlock) { // Custom 0x04 means need to do Seed/Key // Custom 0x07 means unlocked if (responseBlocks[0].Body.First() == 0x07) { return(false); } } return(true); }
private void MapCcmEeprom(IKW1281Dialog kwp1281) { kwp1281.Login(19283, 222); var bytes = new List <byte>(); const byte blockSize = 1; for (int addr = 0; addr <= 65535; addr += blockSize) { var blockBytes = kwp1281.ReadEeprom((ushort)addr, blockSize); blockBytes = Enumerable.Repeat( blockBytes == null ? (byte)0 : (byte)0xFF, blockSize).ToList(); bytes.AddRange(blockBytes); } var dumpFileName = _filename ?? "ccm_eeprom_map.bin"; Logger.WriteLine($"Saving EEPROM map to {dumpFileName}"); File.WriteAllBytes(dumpFileName, bytes.ToArray()); }
public static bool UnlockCluster(IKW1281Dialog kwp1281) { var versionBlocks = kwp1281.CustomReadSoftwareVersion(); // Now we need to send an unlock code that is unique to each ROM version Logger.WriteLine("Sending Custom \"Unlock partial EEPROM read\" block"); var softwareVersion = versionBlocks[0].Body; var unlockCodes = GetClusterUnlockCodes(softwareVersion); var unlocked = false; foreach (var unlockCode in unlockCodes) { var unlockCommand = new List <byte> { 0x9D }; unlockCommand.AddRange(unlockCode); var unlockResponse = kwp1281.SendCustom(unlockCommand); if (unlockResponse.Count != 1) { throw new InvalidOperationException( $"Received multiple responses from unlock request."); } if (unlockResponse[0].IsAck) { Logger.WriteLine( $"Unlock code for software version {KW1281Dialog.DumpMixedContent(softwareVersion)} is {Utils.Dump(unlockCode)}"); if (unlockCodes.Length > 1) { Logger.WriteLine("Please report this to the program maintainer."); } unlocked = true; break; } else if (!unlockResponse[0].IsNak) { throw new InvalidOperationException( $"Received non-ACK/NAK ${unlockResponse[0].Title:X2} from unlock request."); } } return(unlocked); }
private static void WriteEeprom( IKW1281Dialog kwp1281, ushort startAddr, byte[] bytes, uint maxWriteLength) { var succeeded = true; var length = bytes.Length; for (uint addr = startAddr; addr < (startAddr + length); addr += maxWriteLength) { var writeLength = (byte)Math.Min(startAddr + length - addr, maxWriteLength); if (!kwp1281.WriteEeprom( (ushort)addr, bytes.Skip((int)(addr - startAddr)).Take(writeLength).ToList())) { succeeded = false; } } if (!succeeded) { Logger.WriteLine("EEPROM write failed. You should probably try again."); } }
// End top-level commands private void MapClusterEeprom(IKW1281Dialog kwp1281) { // Unlock partial EEPROM read _ = kwp1281.SendCustom(new List <byte> { 0x9D, 0x39, 0x34, 0x34, 0x40 }); var bytes = new List <byte>(); const byte blockSize = 1; for (ushort addr = 0; addr < 2048; addr += blockSize) { var blockBytes = kwp1281.ReadEeprom(addr, blockSize); blockBytes = Enumerable.Repeat( blockBytes == null ? (byte)0 : (byte)0xFF, blockSize).ToList(); bytes.AddRange(blockBytes); } var dumpFileName = _filename ?? "eeprom_map.bin"; Logger.WriteLine($"Saving EEPROM map to {dumpFileName}"); File.WriteAllBytes(dumpFileName, bytes.ToArray()); }
private static void ReadSoftwareVersion(IKW1281Dialog kwp1281) { kwp1281.CustomReadSoftwareVersion(); }