From 5b819e1571e214464a74f5e342c1d42d3f597475 Mon Sep 17 00:00:00 2001 From: turboat <43698566+turboat@users.noreply.github.com> Date: Wed, 3 Oct 2018 19:53:18 +0100 Subject: [PATCH 1/9] Update README.md --- README.md | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0241e5d..0930ed5 100644 --- a/README.md +++ b/README.md @@ -1 +1,41 @@ -# eepromtool \ No newline at end of file +# 95040 Eepromtool + +95040 Eepromtool (previously called 95040tool) is a tool for easily displaying information in bosch m7.5 ecu eeproms and coresponding custer eeproms. This tool was written for VAG 1.8t engines using immo 3, it may also work with other engines and versions, but has limited testing. Eepromtool does not offer facility to read/write to an ecu, it is soley for viewing and modifying files that you have already. + +The most recent release can be found in https://github.com/turboat/eepromtool/releases/ + +## Usage +Eepromtool is a command line tool, either run using 'python eepromtool_04.py' or 'eepromtool_04.exe'. To simply display the info in a bin called INFILE, use: + +`eepromtool_04.exe INFILE` + +For example with an ecu eeprom: + +```$ eepromtool_04.exe ecu.bin +EEPROM Status: +- Type: ECU_eeprom +- Version: Immo3 +- VIN: WAULC68E52A221040 (Audi 2002 - A4 01-08, Ingolstadt, Germany) +- SKC: 01256 +- Immobiliser: On +- Checksum: OK +- Size: 512bytes +- Cluster Code: 98 8A 4E AB 77 D2 A2 +- P0601 DTC: not set +- Immo ID: AUZ6Z0C0185357 +- Softcoding ID: 16701 +- Tuner Tag: Not Set +- Flash Programming (successful): 0 +- Flash Programming (attempts): 1``` + +With a cluster eeprom: + +```$ eepromtool_04.exe cluster.bin +Read in 2048bytes +Detected 2kb bin, parsing as a cluster eeprom (prevent this guessing by using --force) +EEPROM Status: +- Type: Cluster +- VIN: WVWZZZ1JZ4W115023 (VW 2004 - Golf and Bora 4, Wolfsburg, Germany) +- SKC: 01629 +- Cluster Code: 2F 27 CE D8 89 6D 36 +- Immo ID: VWZ7Z0C852208``` From 9f67a837fb2c15291a99e4463207d6b796753528 Mon Sep 17 00:00:00 2001 From: turboat <43698566+turboat@users.noreply.github.com> Date: Wed, 3 Oct 2018 19:53:46 +0100 Subject: [PATCH 2/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0930ed5..354b564 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 95040 Eepromtool -95040 Eepromtool (previously called 95040tool) is a tool for easily displaying information in bosch m7.5 ecu eeproms and coresponding custer eeproms. This tool was written for VAG 1.8t engines using immo 3, it may also work with other engines and versions, but has limited testing. Eepromtool does not offer facility to read/write to an ecu, it is soley for viewing and modifying files that you have already. +95040 Eepromtool is a tool for easily displaying information in bosch m7.5 ecu eeproms and coresponding custer eeproms. This tool was written for VAG 1.8t engines using immo 3, it may also work with other engines and versions, but has limited testing. Eepromtool does not offer facility to read/write to an ecu, it is soley for viewing and modifying files that you have already. The most recent release can be found in https://github.com/turboat/eepromtool/releases/ From 893cc7b3969dc174265656aa899f5998a2c943eb Mon Sep 17 00:00:00 2001 From: matt Date: Thu, 14 Feb 2019 20:35:57 +0000 Subject: [PATCH 3/9] converted from python2 to python3 --- eepromtool_04.py | 211 ++++++++++++++++++++++++----------------------- 1 file changed, 106 insertions(+), 105 deletions(-) diff --git a/eepromtool_04.py b/eepromtool_04.py index 418c156..839f9fb 100644 --- a/eepromtool_04.py +++ b/eepromtool_04.py @@ -2,8 +2,9 @@ import argparse, sys #for handling command line params # Last major update: 9-9-2014 # Minor edit, 28-9-2018 +# Converted to Python3, 13-02-2019 -VERSION = 0.4 +VERSION = 0.4.1 WARN = False DEBUG = False @@ -65,7 +66,7 @@ class ecueeprom: def __init__(self,ndata): - if DEBUG: print "Parsing as ECU eeprom" + if DEBUG: print("Parsing as ECU eeprom") self.data = ndata self.parse() @@ -81,7 +82,7 @@ class ecueeprom: if self.immover == 3: if self.data[0x00][0x00] == 0x30: - print "Bin starts 30 30 30 30 30 - is this a 1024kb R32 bin?" + print("Bin starts 30 30 30 30 30 - is this a 1024kb R32 bin?") #R32 = True #set length @@ -91,13 +92,13 @@ class ecueeprom: #Parse R32 1kb bins if self.size == 1024 or R32 == True: - print "Found 1024b bin - parsing as a R32 bin - experimental" + print("Found 1024b bin - parsing as a R32 bin - experimental") for page in range(0x20,0x40): for bite in self.data[page]: if bite != 0xFF: R32=False if R32: - print "The last 512bytes are padded with 0xFF, this appears to be an R32 bin" + print("The last 512bytes are padded with 0xFF, this appears to be an R32 bin") self.R32 = True #add the padding bytes to nochecksumpages self.noCheckSumPages.append(0x1C) @@ -105,7 +106,7 @@ class ecueeprom: for page in range(0x20,0x40): self.noCheckSumPages.append(page) else: - print "ERROR: 1024byte file detected, but the last 512bytes are not all padded with 0xFF, this file is may be a corupt dump, a cluster dump or something other than an eeprom dump, open it with a hex editor - if this is a valid eeprom please post the file and vehicle info on the thread for this tool" + print("ERROR: 1024byte file detected, but the last 512bytes are not all padded with 0xFF, this file is may be a corupt dump, a cluster dump or something other than an eeprom dump, open it with a hex editor - if this is a valid eeprom please post the file and vehicle info on the thread for this tool") #get SKC @@ -144,7 +145,7 @@ class ecueeprom: try: self.vin = vinstring.decode('ascii') except: - print "WARNING: cannot decode VIN, try setting VIN to fix" + print("WARNING: cannot decode VIN, try setting VIN to fix") self.vindetail = parsevin(self.vin) #get softcoding @@ -159,7 +160,7 @@ class ecueeprom: try: self.immoid = immostring.decode('ascii') except: - print "WARNING: cannot decode ImmmoID" + print("WARNING: cannot decode ImmmoID") #get flasher tag try: @@ -177,14 +178,14 @@ class ecueeprom: def validateChecksum(self): try: - if DEBUG: print "Validating Checksum" + if DEBUG: print("Validating Checksum") minus = 1 self.csum = True #FFFF - (page number - 1) - sum(first 14 bytes) for pageno in range(0x00,len(self.data)): #skip pages without a checksum if pageno in self.noCheckSumPages: - if DEBUG: print "Skipping nochecksumpage: %0.2X" % pageno + if DEBUG: print("Skipping nochecksumpage: %0.2X" % pageno) continue #if this is a backup page, use the previous page's no to calculate the checksum if pageno in self.backupPage: @@ -199,18 +200,18 @@ class ecueeprom: savedsum = "%0.2X%0.2X" % (self.data[pageno][0x0F],self.data[pageno][0x0E]) if calcsum != int(savedsum,16): self.csum = False - if DEBUG: print "Checksum Error page: %0.2X" % pageno + if DEBUG: print("Checksum Error page: %0.2X" % pageno) else: - if DEBUG: print "Checksum OK page: %0.2X" % pageno + if DEBUG: print("Checksum OK page: %0.2X" % pageno) except: - print "WARNING: Cannot validate checksum, possible invalid input" + print("WARNING: Cannot validate checksum, possible invalid input") self.csum = False if DEBUG: if self.csum == True: - print "Checksum OK" + print("Checksum OK") else: - print "Checksum error or validation failure" + print("Checksum error or validation failure") def fixChecksum(self): """ @@ -219,16 +220,16 @@ class ecueeprom: #if the nfc flag is set (from the command line), return without doing checksum/backups if self.noFixCheckSum: - print "- Skipping page backup and checksum correction" + print("- Skipping page backup and checksum correction") return - print "- Setting backup pages" + print("- Setting backup pages") #do backups for pageno in range(0x00,len(self.data)): if pageno in self.backupPage: self.data[pageno] = self.data[pageno - 1] - print "- Correcting checksums" + print("- Correcting checksums") #do checksums minus = 1 self.csum = True @@ -260,53 +261,53 @@ class ecueeprom: try: self.fixChecksum() except: - print "Warning: Error correcting checksum, checksums in output file may be invalid" + print("Warning: Error correcting checksum, checksums in output file may be invalid") outputdata = bytearray() for row in self.data: for bite in row: outputdata.append(bite) - print "" - if DEBUG: print "Writing %dkb ECU eeprom bin to: %s" % (len(outputdata),outputfile) + print("") + if DEBUG: print("Writing %dkb ECU eeprom bin to: %s" % (len(outputdata),outputfile)) try: with open(outputfile,'wb') as fp: fp.write(outputdata) except: - print "Error: Could not open output file, exiting" + print("Error: Could not open output file, exiting") exit(1) - print "- Write Successful" + print("- Write Successful") def printStatus(self): - print "EEPROM Status:" - print "- Type: %s" % self.bin_type - print "- Version: Immo%d" % self.immover + print("EEPROM Status:") + print("- Type: %s" % self.bin_type) + print("- Version: Immo%d" % self.immover) if self.getVINDetail() is not "": - print "- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail()) + print("- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail())) else: - print "- VIN: %s" % (self.getVIN()) - print "- SKC: " + self.getSKC() - print "- Immobiliser: " + self.getImmo() - print "- Checksum: " + self.getChecksum() - print "- Size: " + self.getLength() - print "- Cluster Code: " + self.getClusterCode() - print "- P0601 DTC: " + self.getDTC() - print "- Immo ID: " + self.getImmoID() - print "- Softcoding ID: " + self.getSoftcoding() - print "- Tuner Tag: " + self.getTunerTag() - print "- Flash Programming (successful): %d" % self.flashsuccessfulcount - print "- Flash Programming (attempts): %d" % self.flashattemptcount - print "" + print("- VIN: %s" % (self.getVIN())) + print("- SKC: " + self.getSKC()) + print("- Immobiliser: " + self.getImmo()) + print("- Checksum: " + self.getChecksum()) + print("- Size: " + self.getLength()) + print("- Cluster Code: " + self.getClusterCode()) + print("- P0601 DTC: " + self.getDTC()) + print("- Immo ID: " + self.getImmoID()) + print("- Softcoding ID: " + self.getSoftcoding()) + print("- Tuner Tag: " + self.getTunerTag()) + print("- Flash Programming (successful): %d" % self.flashsuccessfulcount) + print("- Flash Programming (attempts): %d" % self.flashattemptcount) + print("") def getLength(self): if self.size == 512: return "%dbytes" % self.size elif self.size/1024 == 512: - print "Size: 512kb - is this a flash bin not an eeprom bin?" - print "Exiting" + print("Size: 512kb - is this a flash bin not an eeprom bin?") + print("Exiting") exit(1) elif self.size/1024 == 1024: - print "Size: 1024kb - is this a flash bin not an eeprom bin?" - print "Exiting" + print("Size: 1024kb - is this a flash bin not an eeprom bin?") + print("Exiting") exit(1) else: return "%dbytes - 512bytes expected, check this is a eeprom bin" % self.size @@ -354,24 +355,24 @@ class ecueeprom: Set the immo on or off """ if setting is True: - print "Setting Immobiliser: On" + print("Setting Immobiliser: On") if self.immo is True: - print "- Immobiliser already set On" + print("- Immobiliser already set On") return #Set immobiliser on self.data[0x1][0x2] = 0x01 self.data[0x2][0x2] = 0x01 - print "- Immobiliser On" + print("- Immobiliser On") else: - print "Setting Immobiliser: Off" + print("Setting Immobiliser: Off") if self.immo is False: - print "- Immobiliser already set Off" + print("- Immobiliser already set Off") return #Set immo off self.data[0x1][0x2] = 0x02 self.data[0x2][0x2] = 0x02 - print "- Immobiliser Off" + print("- Immobiliser Off") self.parse() self.write = True @@ -385,9 +386,9 @@ class ecueeprom: def setVIN(self,newvin): if len(newvin) is not 17: - print "ERROR: VIN number must be 17 characters" + print("ERROR: VIN number must be 17 characters") exit(1) - print "Setting VIN to %s" % newvin + print("Setting VIN to %s" % newvin) bavin = bytearray(newvin,'ascii') self.data[0xB][0x05:0xA] = bavin[0x00:0x05] @@ -396,7 +397,7 @@ class ecueeprom: try: a = 1 except: - print "ERROR: Could not set VIN" + print("ERROR: Could not set VIN") exit(1) self.parse() self.write = True @@ -421,7 +422,7 @@ class clustereeprom: def __init__(self,ndata): - if DEBUG: print "Parsing as cluster eeprom" + if DEBUG: print("Parsing as cluster eeprom") self.data = ndata self.parse() @@ -431,8 +432,8 @@ class clustereeprom: self.size = 0 for page in self.data: self.size += len(page) - if len(page) > 16: print "ERROR, long row: %d " % len(page) - elif len(page) < 16: print "ERROR, short row: %d " % len(page) + if len(page) > 16: print("ERROR, long row: %d " % len(page)) + elif len(page) < 16: print("ERROR, short row: %d " % len(page)) #get SKC hexskc = "%0.2x%0.2x" % (self.data[0xC][0xD],self.data[0xC][0xC]) @@ -445,11 +446,11 @@ class clustereeprom: cc3 = self.data[0x8][0x2:0x9] if cc1 != cc2: - print "WARNING: Cluster Code Block 1 and 2 do not match, this may indicate an error in the file, or a format not supported by this tool" + print("WARNING: Cluster Code Block 1 and 2 do not match, this may indicate an error in the file, or a format not supported by this tool") if cc1 != cc3: - print "WARNING: Cluster Code Block 1 and 3 do not match, this may indicate an error in the file, or a format not supported by this tool" + print("WARNING: Cluster Code Block 1 and 3 do not match, this may indicate an error in the file, or a format not supported by this tool") if cc2 != cc3: - print "WARNING: Cluster Code Block 2 and 3 do not match, this may indicate an error in the file, or a format not supported by this tool" + print("WARNING: Cluster Code Block 2 and 3 do not match, this may indicate an error in the file, or a format not supported by this tool") self.clustercode = "" @@ -465,7 +466,7 @@ class clustereeprom: try: self.vin = vinstring.decode('ascii') except: - print "WARNING: cannot decode VIN, try setting VIN to fix" + print("WARNING: cannot decode VIN, try setting VIN to fix") self.vindetail = parsevin(self.vin) @@ -477,7 +478,7 @@ class clustereeprom: try: self.immoid = immostring.decode('ascii') except: - print "WARNING: cannot decode ImmmoID" + print("WARNING: cannot decode ImmmoID") def writebin(self,outputfile): outputdata = bytearray() @@ -486,38 +487,38 @@ class clustereeprom: for bite in row: count += 1 outputdata.append(bite) - print "Writing %dkb cluster eeprom bin to: %s" % (len(outputdata),outputfile) + print("Writing %dkb cluster eeprom bin to: %s" % (len(outputdata),outputfile)) try: with open(outputfile,'wb') as fp: fp.write(outputdata) except: - print "Error: Could not open output file, exiting" + print("Error: Could not open output file, exiting") exit(1) - print "- Write Successful" - print "\nThis tool cannot set checksum for cluster bins, so you must force the cluster to reset the checksum by using VCDS to update the cluster softcoding (setting it to the same value will force the update)" + print("- Write Successful") + print("\nThis tool cannot set checksum for cluster bins, so you must force the cluster to reset the checksum by using VCDS to update the cluster softcoding (setting it to the same value will force the update)") def printStatus(self): - print "EEPROM Status:" - print "- Type: %s" % self.bin_type + print("EEPROM Status:") + print("- Type: %s" % self.bin_type) if self.getVINDetail() is not "": - print "- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail()) + print("- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail())) else: - print "- VIN: %s" % (self.getVIN()) - print "- SKC: " + self.getSKC() - print "- Cluster Code: " + self.getClusterCode() - print "- Immo ID: " + self.getImmoID() - print "" + print("- VIN: %s" % (self.getVIN())) + print("- SKC: " + self.getSKC()) + print("- Cluster Code: " + self.getClusterCode()) + print("- Immo ID: " + self.getImmoID()) + print("") def getLength(self): if self.size == 2048: return "%dbytes" % self.size elif self.size/1024 == 512: - print "Size: 512kb - is this a flash bin not an eeprom bin?" - print "Exiting" + print("Size: 512kb - is this a flash bin not an eeprom bin?") + print("Exiting") exit(1) elif self.size/1024 == 1024: - print "Size: 1024kb - is this a flash bin not an eeprom bin?" - print "Exiting" + print("Size: 1024kb - is this a flash bin not an eeprom bin?") + print("Exiting") exit(1) else: return "%dbytes - 2048bytes expected, check this is an ecu eeprom bin" % self.size @@ -528,15 +529,15 @@ class clustereeprom: def setSKC(self,skc): #sanity check if len(skc) > 5 or len(skc) < 4: - print "ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9" + print("ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9") exit(1) try: tmp = int(skc) except: - print "ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9" + print("ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9") exit(1) if len(skc) == 5 and skc[0] != "0": - print "ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9" + print("ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9") exit(1) if len(skc) == 5: @@ -544,7 +545,7 @@ class clustereeprom: else: tskc = "%0.4x" % int(skc) - print "Setting SKC to %s" % skc + print("Setting SKC to %s" % skc) self.data[0xC][0xC] = int(tskc[2:],16) self.data[0xC][0xD] = int(tskc[:2],16) self.data[0xC][0xE] = int(tskc[2:],16) @@ -580,35 +581,35 @@ class clustereeprom: return self.vindetail def setVIN(self,newvin): - if DEBUG: print "Trying to set vin to %s (%s)" % (newvin,parsevin(newvin)) + if DEBUG: print("Trying to set vin to %s (%s)" % (newvin,parsevin(newvin))) try: if len(newvin) is not 17: - print "ERROR: VIN number must be 17 characters" + print("ERROR: VIN number must be 17 characters") exit(1) - print "Setting VIN to %s" % newvin + print("Setting VIN to %s" % newvin) bavin = bytearray(newvin,'ascii') self.data[0xD][0x02:0x10] = bavin[0x00:0x0E] del bavin[0x0:0xE] self.data[0xE][0x00:0x03] = bavin except: - print "ERROR: Could not set VIN" + print("ERROR: Could not set VIN") exit(1) self.parse() self.write = True - if DEBUG: print "Set vin to %s" % self.getVIN() + if DEBUG: print("Set vin to %s" % self.getVIN()) def getImmoID(self): return self.immoid def setImmoID(self,immoid): - if DEBUG: print "Trying to set immo ID to %s" % immoid + if DEBUG: print("Trying to set immo ID to %s" % immoid) try: if len(immoid) is not 14: - print "ERROR: VIN number must be 14 characters" + print("ERROR: VIN number must be 14 characters") exit(1) - print "Setting Immo ID to %s" % immoid + print("Setting Immo ID to %s" % immoid) baii = bytearray(immoid,'ascii') self.data[0xA][0x02:0x10] = baii[0x00:0x0E] @@ -616,12 +617,12 @@ class clustereeprom: self.data[0xB][0xE:0x10] = baii[0x00:0x02] self.data[0xC][:0xC] = baii[0x02:0x0E] except: - print "ERROR: Could not set Immo ID" + print("ERROR: Could not set Immo ID") exit(1) self.parse() self.write = True - if DEBUG: print "Set immo ID to %s" % self.getImmoID() + if DEBUG: print("Set immo ID to %s" % self.getImmoID()) def pair(self,ecueepromfile): ecueeprombin = ecueeprom(readbin(ecueepromfile)) @@ -632,8 +633,8 @@ class clustereeprom: self.setClusterCode(ecueeprombin.getClusterCode()) self.setSKC(ecueeprombin.getSKC()) - print "" - print "Cluster updated to:" + print("") + print("Cluster updated to:") self.printStatus() self.write = True @@ -654,8 +655,8 @@ def readbin(filename): if onlyread512k: if len(data) == 32: readmore = False - if DEBUG: print "Read in %d 16 byte rows - %dbytes total" % (len(data),len(data)*16) - print "Read in %dbytes" % (len(data)*16) + if DEBUG: print("Read in %d 16 byte rows - %dbytes total" % (len(data),len(data)*16)) + print("Read in %dbytes" % (len(data)*16)) return data @@ -673,7 +674,7 @@ def parsevin(vinin): def main(): - if WARN: print "95040 Eeprom Tool - " + str(VERSION) + "- No warranty implied or given, manually verify all changes before saving eeprom to ECU, this tool could cause permenent damage to ECU and prevent vehicle running\n" + if WARN: print("95040 Eeprom Tool - " + str(VERSION) + "- No warranty implied or given, manually verify all changes before saving eeprom to ECU, this tool could cause permenent damage to ECU and prevent vehicle running\n") parser = argparse.ArgumentParser(description='95040 Eeprom Tool ' + str(VERSION) + ' View/Modify me7.5 eeprom files') parser.add_argument('--in',dest='infile',help='Input eeprom bin',required=True) parser.add_argument('--out',dest='outfile',help='File to save eeprom to (must be supplied if changing Immo/VIN)') @@ -690,7 +691,7 @@ def main(): parser.add_argument('--force',dest='force',action='store_const',const=True, help='Prevent the tool from guessing eeprom type') if DEBUG: - print "Debug mode active" + print("Debug mode active") #create namespace for args args = argparse.Namespace() @@ -713,17 +714,17 @@ def main(): try: data = readbin(args.infile) except: - print "ERROR: Could not open input file - %s" % args.infile + print("ERROR: Could not open input file - %s" % args.infile) sys.exit(1) else: - print "Error: No Input file" + print("Error: No Input file") sys.exit(1) #Attempt to autodetect if this is a cluster or ecu bin, based on size if not args.force: if not args.cluster: if (len(data) *16) == 2048: - print "Detected 2kb bin, parsing as a cluster eeprom (prevent this guessing by using --force)" + print("Detected 2kb bin, parsing as a cluster eeprom (prevent this guessing by using --force)") args.cluster = True #Load and parse eeprom @@ -742,7 +743,7 @@ def main(): if args.fixcs or args.immo or args.vin: if not args.outfile: - print "ERROR: Output file must be supplied when correcting checksum, setting immo or changing VIN" + print("ERROR: Output file must be supplied when correcting checksum, setting immo or changing VIN") sys.exit(1) if args.nofixcs: @@ -753,7 +754,7 @@ def main(): if args.immo: if args.cluster: - print "ERROR: No immo to set in cluster eeprom" + print("ERROR: No immo to set in cluster eeprom") exit(1) if args.immo.lower() == 'off': eeprombin.setImmo(False) @@ -765,17 +766,17 @@ def main(): if args.skc: if not args.cluster: - print "Not Yet Supported for ECU Bins" + print("Not Yet Supported for ECU Bins") eeprombin.setSKC(args.skc) if args.cc: if not args.cluster: - print "Not Yet Supported for ECU Bins" + print("Not Yet Supported for ECU Bins") eeprombin.setClusterCode(args.cc) if args.ii: if not args.cluster: - print "Not Yet Supported for ECU Bins" + print("Not Yet Supported for ECU Bins") eeprombin.setImmoID(args.ii) if args.pair: From 72eb953ae0dceae8440b6b1f82baba96cb415eab Mon Sep 17 00:00:00 2001 From: Matthew Hilton Date: Thu, 14 Feb 2019 21:14:33 +0000 Subject: [PATCH 4/9] Fix typo Revert version increase --- eepromtool_04.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eepromtool_04.py b/eepromtool_04.py index 839f9fb..39367ea 100644 --- a/eepromtool_04.py +++ b/eepromtool_04.py @@ -4,7 +4,7 @@ import argparse, sys #for handling command line params # Minor edit, 28-9-2018 # Converted to Python3, 13-02-2019 -VERSION = 0.4.1 +VERSION = 0.4 WARN = False DEBUG = False From 4dcf548d332ab257a65396d21bcee1b791c3d5fd Mon Sep 17 00:00:00 2001 From: matt Date: Thu, 14 Feb 2019 23:11:30 +0000 Subject: [PATCH 5/9] added gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..763624e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/* \ No newline at end of file From 8910cb2050be3526145f77540af6879eed1a6f0a Mon Sep 17 00:00:00 2001 From: matt Date: Thu, 14 Feb 2019 23:12:44 +0000 Subject: [PATCH 6/9] fixed typo --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 763624e..cfad139 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -__pycache__/* \ No newline at end of file +*/__pycache__/* \ No newline at end of file From 93ef3da8346de9bdbb760615ea13089de984e314 Mon Sep 17 00:00:00 2001 From: matt Date: Thu, 14 Feb 2019 23:14:15 +0000 Subject: [PATCH 7/9] split out into separate files. switched to logging module --- eepromtool/cluster.py | 236 ++++++++++++++ eepromtool/ecu.py | 371 ++++++++++++++++++++++ eepromtool/eepromtool.py | 34 ++ eepromtool_04.py | 668 ++------------------------------------- 4 files changed, 659 insertions(+), 650 deletions(-) create mode 100644 eepromtool/cluster.py create mode 100644 eepromtool/ecu.py create mode 100644 eepromtool/eepromtool.py diff --git a/eepromtool/cluster.py b/eepromtool/cluster.py new file mode 100644 index 0000000..4c6a81b --- /dev/null +++ b/eepromtool/cluster.py @@ -0,0 +1,236 @@ +import logging +from .eepromtool import eeprom + +class clustereeprom: + bin_type = "Cluster" + noCheckSumPages = [0x10000] + backupPage = [0x10000] + write = False #set to write out eeprom after modification + + size = 0 + data = [] + + vin = "" + vindetail = "" + immoid = "" + skc = "" + clustercode = "" #0x34-0x3A + + + def __init__(self,ndata): + logging.warn("Parsing as cluster eeprom") + self.data = ndata + self.parse() + + def parse(self): + + #set length + self.size = 0 + for page in self.data: + self.size += len(page) + if len(page) > 16: logging.error("ERROR, long row: %d " % len(page)) + elif len(page) < 16: logging.error("ERROR, short row: %d " % len(page)) + + #get SKC + hexskc = "%0.2x%0.2x" % (self.data[0xC][0xD],self.data[0xC][0xC]) + self.skc = "0%d" % int(hexskc,16) + + #get cluster code + cc1 = self.data[0x7][0x2:0x9] + cc2 = self.data[0x7][0xA:0x18] + cc2.append(self.data[0x8][0x0]) + cc3 = self.data[0x8][0x2:0x9] + + if cc1 != cc2: + logging.warn("WARNING: Cluster Code Block 1 and 2 do not match, this may indicate an error in the file, or a format not supported by this tool") + if cc1 != cc3: + logging.warn("WARNING: Cluster Code Block 1 and 3 do not match, this may indicate an error in the file, or a format not supported by this tool") + if cc2 != cc3: + logging.warn("WARNING: Cluster Code Block 2 and 3 do not match, this may indicate an error in the file, or a format not supported by this tool") + + + self.clustercode = "" + for i in range(0x2, 0x9): + self.clustercode += "%0.2X " % self.data[0x7][i] + + #get VIN + vinstring = bytearray() + for bite in range (0x02,0x10): + vinstring.append(self.data[0xD][bite]) + for bite in range (0x00,0x03): + vinstring.append(self.data[0xE][bite]) + try: + self.vin = vinstring.decode('ascii') + except: + logging.warn("WARNING: cannot decode VIN, try setting VIN to fix") + + self.vindetail = eeprom.parsevin(self.vin) + + + #get Immo ID + immostring = bytearray() + for bite in range (0x02,0x0F): + immostring.append(self.data[0xA][bite]) + try: + self.immoid = immostring.decode('ascii') + except: + logging.warn("WARNING: cannot decode ImmmoID") + + def writebin(self,outputfile): + outputdata = bytearray() + for row in self.data: + count = 0 + for bite in row: + count += 1 + outputdata.append(bite) + logging.info("Writing %dkb cluster eeprom bin to: %s" % (len(outputdata),outputfile)) + try: + with open(outputfile,'wb') as fp: + fp.write(outputdata) + except: + logging.error("Error: Could not open output file, exiting") + exit(1) + logging.info("- Write Successful") + logging.info("\nThis tool cannot set checksum for cluster bins, so you must force the cluster to reset the checksum by using VCDS to update the cluster softcoding (setting it to the same value will force the update)") + + def printStatus(self): + logging.info("EEPROM Status:") + logging.info("- Type: %s" % self.bin_type) + if self.getVINDetail() is not "": + logging.info("- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail())) + else: + logging.info("- VIN: %s" % (self.getVIN())) + logging.info("- SKC: " + self.getSKC()) + logging.info("- Cluster Code: " + self.getClusterCode()) + logging.info("- Immo ID: " + self.getImmoID()) + logging.info("") + + def getLength(self): + if self.size == 2048: + return "%dbytes" % self.size + elif self.size/1024 == 512: + logging.warn("Size: 512kb - is this a flash bin not an eeprom bin?") + logging.warn("Exiting") + exit(1) + elif self.size/1024 == 1024: + logging.warn("Size: 1024kb - is this a flash bin not an eeprom bin?") + logging.warn("Exiting") + exit(1) + else: + return "%dbytes - 2048bytes expected, check this is an ecu eeprom bin" % self.size + + def getSKC(self): + return self.skc + + def setSKC(self,skc): + #sanity check + if len(skc) > 5 or len(skc) < 4: + logging.error("ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9") + exit(1) + try: + tmp = int(skc) + except: + logging.error("ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9") + exit(1) + if len(skc) == 5 and skc[0] != "0": + logging.error("ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9") + exit(1) + + if len(skc) == 5: + tskc = "%0.4x" % int(skc[0:]) + else: + tskc = "%0.4x" % int(skc) + + logging.info("Setting SKC to %s" % skc) + self.data[0xC][0xC] = int(tskc[2:],16) + self.data[0xC][0xD] = int(tskc[:2],16) + self.data[0xC][0xE] = int(tskc[2:],16) + self.data[0xC][0xF] = int(tskc[:2],16) + self.data[0xD][0x0] = int(tskc[2:],16) + self.data[0xD][0x1] = int(tskc[:2],16) + + + self.parse() + self.write = True + + + def getClusterCode(self): + return self.clustercode + + def setClusterCode(self,clustercode): + + bacc = bytearray(clustercode.replace(" ","").decode("hex")) + self.data[0x7][2:9] = bacc + self.data[0x7][0xA:18] = bacc[0:6] + self.data[0x8][0x0] = bacc[6] + self.data[0x8][2:9] = bacc + + self.parse() + self.write = True + + + + def getVIN(self): + return self.vin + + def getVINDetail(self): + return self.vindetail + + def setVIN(self,newvin): + logging.debug("Trying to set vin to %s (%s)" % (newvin,parsevin(newvin))) + try: + if len(newvin) is not 17: + logging.error("ERROR: VIN number must be 17 characters") + exit(1) + logging.info("Setting VIN to %s" % newvin) + bavin = bytearray(newvin,'ascii') + + self.data[0xD][0x02:0x10] = bavin[0x00:0x0E] + del bavin[0x0:0xE] + self.data[0xE][0x00:0x03] = bavin + except: + logging.error("ERROR: Could not set VIN") + exit(1) + self.parse() + self.write = True + + logging.debug("Set vin to %s" % self.getVIN()) + + def getImmoID(self): + return self.immoid + + def setImmoID(self,immoid): + logging.debug("Trying to set immo ID to %s" % immoid) + try: + if len(immoid) is not 14: + logging.error("ERROR: VIN number must be 14 characters") + exit(1) + logging.info("Setting Immo ID to %s" % immoid) + baii = bytearray(immoid,'ascii') + + self.data[0xA][0x02:0x10] = baii[0x00:0x0E] + self.data[0xB][:0xE] = baii[0x00:0x0E] + self.data[0xB][0xE:0x10] = baii[0x00:0x02] + self.data[0xC][:0xC] = baii[0x02:0x0E] + except: + logging.error("ERROR: Could not set Immo ID") + exit(1) + self.parse() + self.write = True + + logging.debug("Set immo ID to %s" % self.getImmoID()) + + def pair(self,ecueepromfile): + ecueeprombin = ecueeprom(readbin(ecueepromfile)) + + #Set Vin, Immo ID, Cluster Code + self.setVIN(ecueeprombin.getVIN()) + self.setImmoID(ecueeprombin.getImmoID()) + self.setClusterCode(ecueeprombin.getClusterCode()) + self.setSKC(ecueeprombin.getSKC()) + + logging.info("") + logging.info("Cluster updated to:") + self.printStatus() + self.write = True + diff --git a/eepromtool/ecu.py b/eepromtool/ecu.py new file mode 100644 index 0000000..a5dca2f --- /dev/null +++ b/eepromtool/ecu.py @@ -0,0 +1,371 @@ +import logging +from .eepromtool import eeprom + +class ecueeprom: + bin_type = "ECU_eeprom" + noFixCheckSum = False + noCheckSumPages = [0x00,0x11,0x12,0x13,0x14] + backupPage = [0x8,0xA,0xC,0xE,0x10,0x1F] + write = False #set to write out eeprom after modification + + size = 0 + data = [] + + immover = 3 + vin = "" + vindetail = "" + immoid = "" + skc = "" + clustercode = "" #0x34-0x3A + softcoding = "" #0x7A 0x7B + immoval = [] + + tunertag = "" + flashattemptcount = 0 + flashsuccessfulcount = 0 + + dtc = None + immo = None #True indicates immo is on, False is off, None is error + csum = True #True indicates checksum is ok, false indicates checksum is wrong + R32 = False #True indiciates that this is a R32 bin 1024kb bin with FF padding + + + + def __init__(self,ndata): + logging.warn("Parsing as ECU eeprom") + self.data = ndata + self.parse() + + def parse(self): + R32 = False + + #try to work out of this is immo2, immo3 or immo3r32 + tmpval = self.data[0x00][0x00] + for bite in range(0x01,0x05): + if self.data[0x00][bite] != tmpval: + #first 5 bytes are not the same, assume immo2 (or some new immo 3) + self.immover = 2 + + if self.immover == 3: + if self.data[0x00][0x00] == 0x30: + logging.info("Bin starts 30 30 30 30 30 - is this a 1024kb R32 bin?") + #R32 = True + + #set length + self.size = 0 + for page in self.data: + self.size += len(page) + + #Parse R32 1kb bins + if self.size == 1024 or R32 == True: + logging.info("Found 1024b bin - parsing as a R32 bin - experimental") + for page in range(0x20,0x40): + for bite in self.data[page]: + if bite != 0xFF: + R32=False + if R32: + logging.info("The last 512bytes are padded with 0xFF, this appears to be an R32 bin") + self.R32 = True + #add the padding bytes to nochecksumpages + self.noCheckSumPages.append(0x1C) + self.noCheckSumPages.append(0x1D) + for page in range(0x20,0x40): + self.noCheckSumPages.append(page) + else: + logging.error("ERROR: 1024byte file detected, but the last 512bytes are not all padded with 0xFF, this file is may be a corupt dump, a cluster dump or something other than an eeprom dump, open it with a hex editor - if this is a valid eeprom please post the file and vehicle info on the thread for this tool") + + + #get SKC + hexskc = "%0.2x%0.2x" % (self.data[0x3][0x3],self.data[0x3][0x2]) + self.skc = "0%0.4d" % int(hexskc,16) + + #get death DTC + if self.data[0x1][0xC] + self.data[0x2][0xC] > 0: + self.dtc = "%0.2X %0.2X" % (self.data[0x1][0xC],self.data[0x2][0xC]) + + #get immo + immo1 = self.data[0x1][0x2] + immo2 = self.data[0x2][0x2] + if immo1 == immo2: + #if byte 12 and byte 22 are not set the same, leave self.immo None to indicate error + if immo1 == 0x01: + self.immo = True + elif immo1 == 0x02: + self.immo = False + + #if byte 12 and 22 are not set to 0x01 or 0x02, fall through to indicate error, set immoval to the actual value for display + self.immoval.append(immo1) + self.immoval.append(immo2) + + #get cluster code + self.clustercode = "" + for i in range(0x4, 0xB): + self.clustercode += "%0.2X " % self.data[0x3][i] + + #get VIN + vinstring = bytearray() + for bite in range (0x05,0xA): + vinstring.append(self.data[0xB][bite]) + for bite in range (0x00,0xC): + vinstring.append(self.data[0xD][bite]) + try: + self.vin = vinstring.decode('ascii') + except: + logging.warn("WARNING: cannot decode VIN, try setting VIN to fix") + + self.vindetail = eeprom.parsevin(self.vin) + #get softcoding + hexscing = "%0.2x%0.2x" % (self.data[0x7][0xB],self.data[0x7][0xA]) + self.softcoding = "%0.4d" % int(hexscing,16) + + #get Immo ID + immostring = bytearray() + immostring.append(self.data[0xD][0xC]) + for bite in range (0x00,0xD): + immostring.append(self.data[0xF][bite]) + try: + self.immoid = immostring.decode('ascii') + except: + logging.warn("WARNING: cannot decode ImmmoID") + + #get flasher tag + try: + self.tunertag = self.data[0x1E][0x2:0x8].decode('ascii') + except: + pass + + #get flash programming counts + self.flashsuccessfulcount = self.data[0x1E][0x9] + self.flashattemptcount = self.data[0x1E][0xA] + + + #validate checksum + self.validateChecksum() + + def validateChecksum(self): + try: + logging.debug("Validating Checksum") + minus = 1 + self.csum = True + #FFFF - (page number - 1) - sum(first 14 bytes) + for pageno in range(0x00,len(self.data)): + #skip pages without a checksum + if pageno in self.noCheckSumPages: + logging.debug("Skipping nochecksumpage: %0.2X" % pageno) + continue + #if this is a backup page, use the previous page's no to calculate the checksum + if pageno in self.backupPage: + minus = 2 + else: + minus = 1 + bytesum = 0x00 + for i in range (0, 14): + bytesum += self.data[pageno][i] + calcsum = 0xFFFF - (pageno - minus) - bytesum + #get checksum for this page from the bin + savedsum = "%0.2X%0.2X" % (self.data[pageno][0x0F],self.data[pageno][0x0E]) + if calcsum != int(savedsum,16): + self.csum = False + logging.debug("Checksum Error page: %0.2X" % pageno) + else: + logging.debug("Checksum OK page: %0.2X" % pageno) + except: + logging.warn("WARNING: Cannot validate checksum, possible invalid input") + self.csum = False + + if self.csum == True: + logging.debug("Checksum OK") + else: + logging.debug("Checksum error or validation failure") + + def fixChecksum(self): + """ + Fixes the checksum and sets the backup rows + """ + + #if the nfc flag is set (from the command line), return without doing checksum/backups + if self.noFixCheckSum: + logging.info("- Skipping page backup and checksum correction") + return + + logging.info("- Setting backup pages") + #do backups + for pageno in range(0x00,len(self.data)): + if pageno in self.backupPage: + self.data[pageno] = self.data[pageno - 1] + + logging.info("- Correcting checksums") + #do checksums + minus = 1 + self.csum = True + #FFFF - (page number - 1) - sum(first 14 bytes) + for pageno in range(0x00,len(self.data)): + + #skip pages without a checksum + if pageno in self.noCheckSumPages: + continue + #if this is a backup page, use the previous page's no to calculate the checksum + if pageno in self.backupPage: + minus = 2 + else: + minus = 1 + bytesum = 0x00 + for i in range (0, 14): + bytesum += self.data[pageno][i] + calcsum = 0xFFFF - (pageno - minus) - bytesum + self.data[pageno][0x0F] = (calcsum / 256) + self.data[pageno][0x0E] = (calcsum % 256) + + def getChecksum(self): + if self.csum: + return "OK" + else: + return "Invalid Checksum" + + def writebin(self,outputfile): + try: + self.fixChecksum() + except: + logging.warn("Warning: Error correcting checksum, checksums in output file may be invalid") + outputdata = bytearray() + for row in self.data: + for bite in row: + outputdata.append(bite) + + print("") + logging.debug("Writing %dkb ECU eeprom bin to: %s" % (len(outputdata),outputfile)) + try: + with open(outputfile,'wb') as fp: + fp.write(outputdata) + except: + logging.error("Error: Could not open output file, exiting") + exit(1) + logging.info("- Write Successful") + + def printStatus(self): + logging.info("EEPROM Status:") + logging.info("- Type: %s" % self.bin_type) + logging.info("- Version: Immo%d" % self.immover) + if self.getVINDetail() is not "": + logging.info("- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail())) + else: + logging.info("- VIN: %s" % (self.getVIN())) + logging.info("- SKC: " + self.getSKC()) + logging.info("- Immobiliser: " + self.getImmo()) + logging.info("- Checksum: " + self.getChecksum()) + logging.info("- Size: " + self.getLength()) + logging.info("- Cluster Code: " + self.getClusterCode()) + logging.info("- P0601 DTC: " + self.getDTC()) + logging.info("- Immo ID: " + self.getImmoID()) + logging.info("- Softcoding ID: " + self.getSoftcoding()) + logging.info("- Tuner Tag: " + self.getTunerTag()) + logging.info("- Flash Programming (successful): %d" % self.flashsuccessfulcount) + logging.info("- Flash Programming (attempts): %d" % self.flashattemptcount) + logging.info("") + + def getLength(self): + if self.size == 512: + return "%dbytes" % self.size + elif self.size/1024 == 512: + logging.warn("Size: 512kb - is this a flash bin not an eeprom bin?") + logging.warn("Exiting") + exit(1) + elif self.size/1024 == 1024: + logging.warn("Size: 1024kb - is this a flash bin not an eeprom bin?") + logging.warn("Exiting") + exit(1) + else: + return "%dbytes - 512bytes expected, check this is a eeprom bin" % self.size + + def getTunerTag(self): + if self.tunertag == "": + return "Not Set" + else: + return self.tunertag + + def getSoftcoding(self): + return self.softcoding + + def getSKC(self): + return self.skc + + def getClusterCode(self): + return self.clustercode + + def getDTC(self): + if self.dtc is not None: + return "set to " + self.dtc + else: + return "not set" + + def clearDTC(self): + self.data[0x1c] = 0x00 + self.data[0x2c] = 0x00 + self.parse() + self.write = True + + def getImmo(self): + """ + Get the current setting for the immobiliser, returns text string to indicate status + """ + if self.immo is True: + return "On" + elif self.immo is False: + return "Off" + else: + return "Error, set Immo - Current values: 0x12 = 0x%0.2X, 0x22 = 0x%0.2X" % (self.immoval[0],self.immoval[1]) + + def setImmo(self,setting): + """ + Set the immo on or off + """ + if setting is True: + logging.info("Setting Immobiliser: On") + if self.immo is True: + logging.info("- Immobiliser already set On") + return + #Set immobiliser on + self.data[0x1][0x2] = 0x01 + self.data[0x2][0x2] = 0x01 + logging.info("- Immobiliser On") + + else: + logging.info("Setting Immobiliser: Off") + if self.immo is False: + logging.info("- Immobiliser already set Off") + return + #Set immo off + self.data[0x1][0x2] = 0x02 + self.data[0x2][0x2] = 0x02 + logging.info("- Immobiliser Off") + + self.parse() + self.write = True + + def getVIN(self): + return self.vin + + def getVINDetail(self): + return self.vindetail + + + def setVIN(self,newvin): + if len(newvin) is not 17: + logging.error("ERROR: VIN number must be 17 characters") + exit(1) + logging.info("Setting VIN to %s" % newvin) + bavin = bytearray(newvin,'ascii') + + self.data[0xB][0x05:0xA] = bavin[0x00:0x05] + del bavin[0:5] + self.data[0xD][0x00:0xC] = bavin + try: + a = 1 + except: + logging.error("ERROR: Could not set VIN") + exit(1) + self.parse() + self.write = True + + def getImmoID(self): + return self.immoid diff --git a/eepromtool/eepromtool.py b/eepromtool/eepromtool.py new file mode 100644 index 0000000..86d2864 --- /dev/null +++ b/eepromtool/eepromtool.py @@ -0,0 +1,34 @@ +import logging + +class eeprom: + def readbin(filename): + logging.warn("Loading eeprom - %s" % filename) + data = [] + readmore = True + onlyread512k = False + with open(filename, "rb") as f: + while readmore: + page = f.read(16) + if page: + data.append(bytearray(page)) + else: + break + if onlyread512k: + if len(data) == 32: + readmore = False + logging.debug("Read in %d 16 byte rows - %dbytes total" % (len(data),len(data)*16)) + logging.info("Read in %dbytes" % (len(data)*16)) + return data + + def parsevin(vinin): + vinstring = "" + try: + #attempt to parse the vin + vinstring += WMI[vinin[0:3]] + vinstring += " " + YEAR[vinin[9]] + vinstring += " - " + MODEL[vinin[6:8]] + vinstring += ", " + ORIGIN[vinin[10]] + except: + pass + return vinstring + diff --git a/eepromtool_04.py b/eepromtool_04.py index 839f9fb..918539e 100644 --- a/eepromtool_04.py +++ b/eepromtool_04.py @@ -1,10 +1,11 @@ import argparse, sys #for handling command line params +import logging # Last major update: 9-9-2014 # Minor edit, 28-9-2018 # Converted to Python3, 13-02-2019 -VERSION = 0.4.1 +VERSION = 0.4 WARN = False DEBUG = False @@ -35,646 +36,14 @@ ORIGIN = {'A':"Ingolstadt, Germany",'B':"Brussels, Belgium",'D':"Bratislave, Slo 'K':"Osnabrueck, Germany",'M':"Mexico",'N':"Neckarsulm, Germany; Mlada Boleslav",'P':"Mosel, Germany",'R':"Martorell, Spain",'S':"Stuttgart, Germany", 'T':"Kvasiny, Czech",'V':"Palmela, Portugal",'W':"Wolfsburg, Germany",'X':"Posnan, Poland",'Y':"Pamplona, Spain",'Z':"Pacheco, Argentina",'1':"Gyor, Hungary",'8':"Dresden; Vrchlabi"} -class ecueeprom: - bin_type = "ECU_eeprom" - noFixCheckSum = False - noCheckSumPages = [0x00,0x11,0x12,0x13,0x14] - backupPage = [0x8,0xA,0xC,0xE,0x10,0x1F] - write = False #set to write out eeprom after modification - - size = 0 - data = [] - - immover = 3 - vin = "" - vindetail = "" - immoid = "" - skc = "" - clustercode = "" #0x34-0x3A - softcoding = "" #0x7A 0x7B - immoval = [] - - tunertag = "" - flashattemptcount = 0 - flashsuccessfulcount = 0 - - dtc = None - immo = None #True indicates immo is on, False is off, None is error - csum = True #True indicates checksum is ok, false indicates checksum is wrong - R32 = False #True indiciates that this is a R32 bin 1024kb bin with FF padding - - - - def __init__(self,ndata): - if DEBUG: print("Parsing as ECU eeprom") - self.data = ndata - self.parse() - - def parse(self): - R32 = False - - #try to work out of this is immo2, immo3 or immo3r32 - tmpval = self.data[0x00][0x00] - for bite in range(0x01,0x05): - if self.data[0x00][bite] != tmpval: - #first 5 bytes are not the same, assume immo2 (or some new immo 3) - self.immover = 2 - - if self.immover == 3: - if self.data[0x00][0x00] == 0x30: - print("Bin starts 30 30 30 30 30 - is this a 1024kb R32 bin?") - #R32 = True - - #set length - self.size = 0 - for page in self.data: - self.size += len(page) - - #Parse R32 1kb bins - if self.size == 1024 or R32 == True: - print("Found 1024b bin - parsing as a R32 bin - experimental") - for page in range(0x20,0x40): - for bite in self.data[page]: - if bite != 0xFF: - R32=False - if R32: - print("The last 512bytes are padded with 0xFF, this appears to be an R32 bin") - self.R32 = True - #add the padding bytes to nochecksumpages - self.noCheckSumPages.append(0x1C) - self.noCheckSumPages.append(0x1D) - for page in range(0x20,0x40): - self.noCheckSumPages.append(page) - else: - print("ERROR: 1024byte file detected, but the last 512bytes are not all padded with 0xFF, this file is may be a corupt dump, a cluster dump or something other than an eeprom dump, open it with a hex editor - if this is a valid eeprom please post the file and vehicle info on the thread for this tool") - - - #get SKC - hexskc = "%0.2x%0.2x" % (self.data[0x3][0x3],self.data[0x3][0x2]) - self.skc = "0%0.4d" % int(hexskc,16) - - #get death DTC - if self.data[0x1][0xC] + self.data[0x2][0xC] > 0: - self.dtc = "%0.2X %0.2X" % (self.data[0x1][0xC],self.data[0x2][0xC]) - - #get immo - immo1 = self.data[0x1][0x2] - immo2 = self.data[0x2][0x2] - if immo1 == immo2: - #if byte 12 and byte 22 are not set the same, leave self.immo None to indicate error - if immo1 == 0x01: - self.immo = True - elif immo1 == 0x02: - self.immo = False - - #if byte 12 and 22 are not set to 0x01 or 0x02, fall through to indicate error, set immoval to the actual value for display - self.immoval.append(immo1) - self.immoval.append(immo2) - - #get cluster code - self.clustercode = "" - for i in range(0x4, 0xB): - self.clustercode += "%0.2X " % self.data[0x3][i] - - #get VIN - vinstring = bytearray() - for bite in range (0x05,0xA): - vinstring.append(self.data[0xB][bite]) - for bite in range (0x00,0xC): - vinstring.append(self.data[0xD][bite]) - try: - self.vin = vinstring.decode('ascii') - except: - print("WARNING: cannot decode VIN, try setting VIN to fix") - - self.vindetail = parsevin(self.vin) - #get softcoding - hexscing = "%0.2x%0.2x" % (self.data[0x7][0xB],self.data[0x7][0xA]) - self.softcoding = "%0.4d" % int(hexscing,16) - - #get Immo ID - immostring = bytearray() - immostring.append(self.data[0xD][0xC]) - for bite in range (0x00,0xD): - immostring.append(self.data[0xF][bite]) - try: - self.immoid = immostring.decode('ascii') - except: - print("WARNING: cannot decode ImmmoID") - - #get flasher tag - try: - self.tunertag = self.data[0x1E][0x2:0x8].decode('ascii') - except: - pass - - #get flash programming counts - self.flashsuccessfulcount = self.data[0x1E][0x9] - self.flashattemptcount = self.data[0x1E][0xA] - - - #validate checksum - self.validateChecksum() - - def validateChecksum(self): - try: - if DEBUG: print("Validating Checksum") - minus = 1 - self.csum = True - #FFFF - (page number - 1) - sum(first 14 bytes) - for pageno in range(0x00,len(self.data)): - #skip pages without a checksum - if pageno in self.noCheckSumPages: - if DEBUG: print("Skipping nochecksumpage: %0.2X" % pageno) - continue - #if this is a backup page, use the previous page's no to calculate the checksum - if pageno in self.backupPage: - minus = 2 - else: - minus = 1 - bytesum = 0x00 - for i in range (0, 14): - bytesum += self.data[pageno][i] - calcsum = 0xFFFF - (pageno - minus) - bytesum - #get checksum for this page from the bin - savedsum = "%0.2X%0.2X" % (self.data[pageno][0x0F],self.data[pageno][0x0E]) - if calcsum != int(savedsum,16): - self.csum = False - if DEBUG: print("Checksum Error page: %0.2X" % pageno) - else: - if DEBUG: print("Checksum OK page: %0.2X" % pageno) - except: - print("WARNING: Cannot validate checksum, possible invalid input") - self.csum = False - - if DEBUG: - if self.csum == True: - print("Checksum OK") - else: - print("Checksum error or validation failure") - - def fixChecksum(self): - """ - Fixes the checksum and sets the backup rows - """ - - #if the nfc flag is set (from the command line), return without doing checksum/backups - if self.noFixCheckSum: - print("- Skipping page backup and checksum correction") - return - - print("- Setting backup pages") - #do backups - for pageno in range(0x00,len(self.data)): - if pageno in self.backupPage: - self.data[pageno] = self.data[pageno - 1] - - print("- Correcting checksums") - #do checksums - minus = 1 - self.csum = True - #FFFF - (page number - 1) - sum(first 14 bytes) - for pageno in range(0x00,len(self.data)): - - #skip pages without a checksum - if pageno in self.noCheckSumPages: - continue - #if this is a backup page, use the previous page's no to calculate the checksum - if pageno in self.backupPage: - minus = 2 - else: - minus = 1 - bytesum = 0x00 - for i in range (0, 14): - bytesum += self.data[pageno][i] - calcsum = 0xFFFF - (pageno - minus) - bytesum - self.data[pageno][0x0F] = (calcsum / 256) - self.data[pageno][0x0E] = (calcsum % 256) - - def getChecksum(self): - if self.csum: - return "OK" - else: - return "Invalid Checksum" - - def writebin(self,outputfile): - try: - self.fixChecksum() - except: - print("Warning: Error correcting checksum, checksums in output file may be invalid") - outputdata = bytearray() - for row in self.data: - for bite in row: - outputdata.append(bite) - - print("") - if DEBUG: print("Writing %dkb ECU eeprom bin to: %s" % (len(outputdata),outputfile)) - try: - with open(outputfile,'wb') as fp: - fp.write(outputdata) - except: - print("Error: Could not open output file, exiting") - exit(1) - print("- Write Successful") - - def printStatus(self): - print("EEPROM Status:") - print("- Type: %s" % self.bin_type) - print("- Version: Immo%d" % self.immover) - if self.getVINDetail() is not "": - print("- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail())) - else: - print("- VIN: %s" % (self.getVIN())) - print("- SKC: " + self.getSKC()) - print("- Immobiliser: " + self.getImmo()) - print("- Checksum: " + self.getChecksum()) - print("- Size: " + self.getLength()) - print("- Cluster Code: " + self.getClusterCode()) - print("- P0601 DTC: " + self.getDTC()) - print("- Immo ID: " + self.getImmoID()) - print("- Softcoding ID: " + self.getSoftcoding()) - print("- Tuner Tag: " + self.getTunerTag()) - print("- Flash Programming (successful): %d" % self.flashsuccessfulcount) - print("- Flash Programming (attempts): %d" % self.flashattemptcount) - print("") - - def getLength(self): - if self.size == 512: - return "%dbytes" % self.size - elif self.size/1024 == 512: - print("Size: 512kb - is this a flash bin not an eeprom bin?") - print("Exiting") - exit(1) - elif self.size/1024 == 1024: - print("Size: 1024kb - is this a flash bin not an eeprom bin?") - print("Exiting") - exit(1) - else: - return "%dbytes - 512bytes expected, check this is a eeprom bin" % self.size - - def getTunerTag(self): - if self.tunertag == "": - return "Not Set" - else: - return self.tunertag - - def getSoftcoding(self): - return self.softcoding - - def getSKC(self): - return self.skc - - def getClusterCode(self): - return self.clustercode - - def getDTC(self): - if self.dtc is not None: - return "set to " + self.dtc - else: - return "not set" - - def clearDTC(self): - self.data[0x1c] = 0x00 - self.data[0x2c] = 0x00 - self.parse() - self.write = True - - def getImmo(self): - """ - Get the current setting for the immobiliser, returns text string to indicate status - """ - if self.immo is True: - return "On" - elif self.immo is False: - return "Off" - else: - return "Error, set Immo - Current values: 0x12 = 0x%0.2X, 0x22 = 0x%0.2X" % (self.immoval[0],self.immoval[1]) - - def setImmo(self,setting): - """ - Set the immo on or off - """ - if setting is True: - print("Setting Immobiliser: On") - if self.immo is True: - print("- Immobiliser already set On") - return - #Set immobiliser on - self.data[0x1][0x2] = 0x01 - self.data[0x2][0x2] = 0x01 - print("- Immobiliser On") - - else: - print("Setting Immobiliser: Off") - if self.immo is False: - print("- Immobiliser already set Off") - return - #Set immo off - self.data[0x1][0x2] = 0x02 - self.data[0x2][0x2] = 0x02 - print("- Immobiliser Off") - - self.parse() - self.write = True - - def getVIN(self): - return self.vin - - def getVINDetail(self): - return self.vindetail - - - def setVIN(self,newvin): - if len(newvin) is not 17: - print("ERROR: VIN number must be 17 characters") - exit(1) - print("Setting VIN to %s" % newvin) - bavin = bytearray(newvin,'ascii') - - self.data[0xB][0x05:0xA] = bavin[0x00:0x05] - del bavin[0:5] - self.data[0xD][0x00:0xC] = bavin - try: - a = 1 - except: - print("ERROR: Could not set VIN") - exit(1) - self.parse() - self.write = True - - def getImmoID(self): - return self.immoid - -class clustereeprom: - bin_type = "Cluster" - noCheckSumPages = [0x10000] - backupPage = [0x10000] - write = False #set to write out eeprom after modification - - size = 0 - data = [] - - vin = "" - vindetail = "" - immoid = "" - skc = "" - clustercode = "" #0x34-0x3A - - - def __init__(self,ndata): - if DEBUG: print("Parsing as cluster eeprom") - self.data = ndata - self.parse() - - def parse(self): - - #set length - self.size = 0 - for page in self.data: - self.size += len(page) - if len(page) > 16: print("ERROR, long row: %d " % len(page)) - elif len(page) < 16: print("ERROR, short row: %d " % len(page)) - - #get SKC - hexskc = "%0.2x%0.2x" % (self.data[0xC][0xD],self.data[0xC][0xC]) - self.skc = "0%d" % int(hexskc,16) - - #get cluster code - cc1 = self.data[0x7][0x2:0x9] - cc2 = self.data[0x7][0xA:0x18] - cc2.append(self.data[0x8][0x0]) - cc3 = self.data[0x8][0x2:0x9] - - if cc1 != cc2: - print("WARNING: Cluster Code Block 1 and 2 do not match, this may indicate an error in the file, or a format not supported by this tool") - if cc1 != cc3: - print("WARNING: Cluster Code Block 1 and 3 do not match, this may indicate an error in the file, or a format not supported by this tool") - if cc2 != cc3: - print("WARNING: Cluster Code Block 2 and 3 do not match, this may indicate an error in the file, or a format not supported by this tool") - - - self.clustercode = "" - for i in range(0x2, 0x9): - self.clustercode += "%0.2X " % self.data[0x7][i] - - #get VIN - vinstring = bytearray() - for bite in range (0x02,0x10): - vinstring.append(self.data[0xD][bite]) - for bite in range (0x00,0x03): - vinstring.append(self.data[0xE][bite]) - try: - self.vin = vinstring.decode('ascii') - except: - print("WARNING: cannot decode VIN, try setting VIN to fix") - - self.vindetail = parsevin(self.vin) - - - #get Immo ID - immostring = bytearray() - for bite in range (0x02,0x0F): - immostring.append(self.data[0xA][bite]) - try: - self.immoid = immostring.decode('ascii') - except: - print("WARNING: cannot decode ImmmoID") - - def writebin(self,outputfile): - outputdata = bytearray() - for row in self.data: - count = 0 - for bite in row: - count += 1 - outputdata.append(bite) - print("Writing %dkb cluster eeprom bin to: %s" % (len(outputdata),outputfile)) - try: - with open(outputfile,'wb') as fp: - fp.write(outputdata) - except: - print("Error: Could not open output file, exiting") - exit(1) - print("- Write Successful") - print("\nThis tool cannot set checksum for cluster bins, so you must force the cluster to reset the checksum by using VCDS to update the cluster softcoding (setting it to the same value will force the update)") - - def printStatus(self): - print("EEPROM Status:") - print("- Type: %s" % self.bin_type) - if self.getVINDetail() is not "": - print("- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail())) - else: - print("- VIN: %s" % (self.getVIN())) - print("- SKC: " + self.getSKC()) - print("- Cluster Code: " + self.getClusterCode()) - print("- Immo ID: " + self.getImmoID()) - print("") - - def getLength(self): - if self.size == 2048: - return "%dbytes" % self.size - elif self.size/1024 == 512: - print("Size: 512kb - is this a flash bin not an eeprom bin?") - print("Exiting") - exit(1) - elif self.size/1024 == 1024: - print("Size: 1024kb - is this a flash bin not an eeprom bin?") - print("Exiting") - exit(1) - else: - return "%dbytes - 2048bytes expected, check this is an ecu eeprom bin" % self.size - - def getSKC(self): - return self.skc - - def setSKC(self,skc): - #sanity check - if len(skc) > 5 or len(skc) < 4: - print("ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9") - exit(1) - try: - tmp = int(skc) - except: - print("ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9") - exit(1) - if len(skc) == 5 and skc[0] != "0": - print("ERROR: SKC must be in format 0xxxx or xxxx, where x is in range 0-9") - exit(1) - - if len(skc) == 5: - tskc = "%0.4x" % int(skc[0:]) - else: - tskc = "%0.4x" % int(skc) - - print("Setting SKC to %s" % skc) - self.data[0xC][0xC] = int(tskc[2:],16) - self.data[0xC][0xD] = int(tskc[:2],16) - self.data[0xC][0xE] = int(tskc[2:],16) - self.data[0xC][0xF] = int(tskc[:2],16) - self.data[0xD][0x0] = int(tskc[2:],16) - self.data[0xD][0x1] = int(tskc[:2],16) - - - self.parse() - self.write = True - - - def getClusterCode(self): - return self.clustercode - - def setClusterCode(self,clustercode): - - bacc = bytearray(clustercode.replace(" ","").decode("hex")) - self.data[0x7][2:9] = bacc - self.data[0x7][0xA:18] = bacc[0:6] - self.data[0x8][0x0] = bacc[6] - self.data[0x8][2:9] = bacc - - self.parse() - self.write = True - - - - def getVIN(self): - return self.vin - - def getVINDetail(self): - return self.vindetail - - def setVIN(self,newvin): - if DEBUG: print("Trying to set vin to %s (%s)" % (newvin,parsevin(newvin))) - try: - if len(newvin) is not 17: - print("ERROR: VIN number must be 17 characters") - exit(1) - print("Setting VIN to %s" % newvin) - bavin = bytearray(newvin,'ascii') - - self.data[0xD][0x02:0x10] = bavin[0x00:0x0E] - del bavin[0x0:0xE] - self.data[0xE][0x00:0x03] = bavin - except: - print("ERROR: Could not set VIN") - exit(1) - self.parse() - self.write = True - - if DEBUG: print("Set vin to %s" % self.getVIN()) - - def getImmoID(self): - return self.immoid - - def setImmoID(self,immoid): - if DEBUG: print("Trying to set immo ID to %s" % immoid) - try: - if len(immoid) is not 14: - print("ERROR: VIN number must be 14 characters") - exit(1) - print("Setting Immo ID to %s" % immoid) - baii = bytearray(immoid,'ascii') - - self.data[0xA][0x02:0x10] = baii[0x00:0x0E] - self.data[0xB][:0xE] = baii[0x00:0x0E] - self.data[0xB][0xE:0x10] = baii[0x00:0x02] - self.data[0xC][:0xC] = baii[0x02:0x0E] - except: - print("ERROR: Could not set Immo ID") - exit(1) - self.parse() - self.write = True - - if DEBUG: print("Set immo ID to %s" % self.getImmoID()) - - def pair(self,ecueepromfile): - ecueeprombin = ecueeprom(readbin(ecueepromfile)) - - #Set Vin, Immo ID, Cluster Code - self.setVIN(ecueeprombin.getVIN()) - self.setImmoID(ecueeprombin.getImmoID()) - self.setClusterCode(ecueeprombin.getClusterCode()) - self.setSKC(ecueeprombin.getSKC()) - - print("") - print("Cluster updated to:") - self.printStatus() - self.write = True - - - - -def readbin(filename): - data = [] - readmore = True - onlyread512k = False - with open(filename, "rb") as f: - while readmore: - page = f.read(16) - if page: - data.append(bytearray(page)) - else: - break - if onlyread512k: - if len(data) == 32: - readmore = False - if DEBUG: print("Read in %d 16 byte rows - %dbytes total" % (len(data),len(data)*16)) - print("Read in %dbytes" % (len(data)*16)) - return data - - -def parsevin(vinin): - vinstring = "" - try: - #attempt to parse the vin - vinstring += WMI[vinin[0:3]] - vinstring += " " + YEAR[vinin[9]] - vinstring += " - " + MODEL[vinin[6:8]] - vinstring += ", " + ORIGIN[vinin[10]] - except: - pass - return vinstring - +# import ecu and cluster modules +from eepromtool.eepromtool import eeprom +from eepromtool.ecu import ecueeprom +from eepromtool.cluster import clustereeprom def main(): - if WARN: print("95040 Eeprom Tool - " + str(VERSION) + "- No warranty implied or given, manually verify all changes before saving eeprom to ECU, this tool could cause permenent damage to ECU and prevent vehicle running\n") + logging.basicConfig(level=logging.INFO) + logging.warn("95040 Eeprom Tool - " + str(VERSION) + "- No warranty implied or given, manually verify all changes before saving eeprom to ECU, this tool could cause permenent damage to ECU and prevent vehicle running\n") parser = argparse.ArgumentParser(description='95040 Eeprom Tool ' + str(VERSION) + ' View/Modify me7.5 eeprom files') parser.add_argument('--in',dest='infile',help='Input eeprom bin',required=True) parser.add_argument('--out',dest='outfile',help='File to save eeprom to (must be supplied if changing Immo/VIN)') @@ -690,8 +59,7 @@ def main(): parser.add_argument('--cluster',dest='cluster',action='store_const',const=True, help='Parse a cluster bin (default is ecu bin) - override eeprom type guessing') parser.add_argument('--force',dest='force',action='store_const',const=True, help='Prevent the tool from guessing eeprom type') - if DEBUG: - print("Debug mode active") + logging.debug("Debug mode active") #create namespace for args args = argparse.Namespace() @@ -712,19 +80,19 @@ def main(): if args.infile: try: - data = readbin(args.infile) + data = eeprom.readbin(args.infile) except: - print("ERROR: Could not open input file - %s" % args.infile) + logging.error("ERROR: Could not open input file - %s" % args.infile) sys.exit(1) else: - print("Error: No Input file") + logging.error("Error: No Input file") sys.exit(1) #Attempt to autodetect if this is a cluster or ecu bin, based on size if not args.force: if not args.cluster: if (len(data) *16) == 2048: - print("Detected 2kb bin, parsing as a cluster eeprom (prevent this guessing by using --force)") + logging.info("Detected 2kb bin, parsing as a cluster eeprom (prevent this guessing by using --force)") args.cluster = True #Load and parse eeprom @@ -743,7 +111,7 @@ def main(): if args.fixcs or args.immo or args.vin: if not args.outfile: - print("ERROR: Output file must be supplied when correcting checksum, setting immo or changing VIN") + logging.error("ERROR: Output file must be supplied when correcting checksum, setting immo or changing VIN") sys.exit(1) if args.nofixcs: @@ -754,7 +122,7 @@ def main(): if args.immo: if args.cluster: - print("ERROR: No immo to set in cluster eeprom") + logging.error("ERROR: No immo to set in cluster eeprom") exit(1) if args.immo.lower() == 'off': eeprombin.setImmo(False) @@ -766,17 +134,17 @@ def main(): if args.skc: if not args.cluster: - print("Not Yet Supported for ECU Bins") + logging.info("Not Yet Supported for ECU Bins") eeprombin.setSKC(args.skc) if args.cc: if not args.cluster: - print("Not Yet Supported for ECU Bins") + logging.info("Not Yet Supported for ECU Bins") eeprombin.setClusterCode(args.cc) if args.ii: if not args.cluster: - print("Not Yet Supported for ECU Bins") + logging.info("Not Yet Supported for ECU Bins") eeprombin.setImmoID(args.ii) if args.pair: From 1492d159d789a503b149cd682a74d8f81df08045 Mon Sep 17 00:00:00 2001 From: Oldperl Date: Tue, 6 May 2025 14:25:58 +0000 Subject: [PATCH 8/9] README.md aktualisiert --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 354b564..9bba6c3 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ 95040 Eepromtool is a tool for easily displaying information in bosch m7.5 ecu eeproms and coresponding custer eeproms. This tool was written for VAG 1.8t engines using immo 3, it may also work with other engines and versions, but has limited testing. Eepromtool does not offer facility to read/write to an ecu, it is soley for viewing and modifying files that you have already. -The most recent release can be found in https://github.com/turboat/eepromtool/releases/ - ## Usage Eepromtool is a command line tool, either run using 'python eepromtool_04.py' or 'eepromtool_04.exe'. To simply display the info in a bin called INFILE, use: From 8ef0c6d4099e654709e55bbe27e36ea949867d30 Mon Sep 17 00:00:00 2001 From: "o.pinke" Date: Tue, 6 May 2025 16:48:43 +0200 Subject: [PATCH 9/9] fixed py3 errors, increase version --- eepromtool/cluster.py | 6 +++--- eepromtool/ecu.py | 4 ++-- eepromtool_04.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/eepromtool/cluster.py b/eepromtool/cluster.py index 4c6a81b..53625cc 100644 --- a/eepromtool/cluster.py +++ b/eepromtool/cluster.py @@ -96,7 +96,7 @@ class clustereeprom: def printStatus(self): logging.info("EEPROM Status:") logging.info("- Type: %s" % self.bin_type) - if self.getVINDetail() is not "": + if self.getVINDetail() != "": logging.info("- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail())) else: logging.info("- VIN: %s" % (self.getVIN())) @@ -179,7 +179,7 @@ class clustereeprom: def setVIN(self,newvin): logging.debug("Trying to set vin to %s (%s)" % (newvin,parsevin(newvin))) try: - if len(newvin) is not 17: + if len(newvin) != 17: logging.error("ERROR: VIN number must be 17 characters") exit(1) logging.info("Setting VIN to %s" % newvin) @@ -202,7 +202,7 @@ class clustereeprom: def setImmoID(self,immoid): logging.debug("Trying to set immo ID to %s" % immoid) try: - if len(immoid) is not 14: + if len(immoid) != 14: logging.error("ERROR: VIN number must be 14 characters") exit(1) logging.info("Setting Immo ID to %s" % immoid) diff --git a/eepromtool/ecu.py b/eepromtool/ecu.py index a5dca2f..1d4e534 100644 --- a/eepromtool/ecu.py +++ b/eepromtool/ecu.py @@ -246,7 +246,7 @@ class ecueeprom: logging.info("EEPROM Status:") logging.info("- Type: %s" % self.bin_type) logging.info("- Version: Immo%d" % self.immover) - if self.getVINDetail() is not "": + if self.getVINDetail() != "": logging.info("- VIN: %s (%s)" % (self.getVIN(),self.getVINDetail())) else: logging.info("- VIN: %s" % (self.getVIN())) @@ -350,7 +350,7 @@ class ecueeprom: def setVIN(self,newvin): - if len(newvin) is not 17: + if len(newvin) != 17: logging.error("ERROR: VIN number must be 17 characters") exit(1) logging.info("Setting VIN to %s" % newvin) diff --git a/eepromtool_04.py b/eepromtool_04.py index 918539e..a22dd31 100644 --- a/eepromtool_04.py +++ b/eepromtool_04.py @@ -5,7 +5,7 @@ import logging # Minor edit, 28-9-2018 # Converted to Python3, 13-02-2019 -VERSION = 0.4 +VERSION = 0.5 WARN = False DEBUG = False @@ -43,7 +43,7 @@ from eepromtool.cluster import clustereeprom def main(): logging.basicConfig(level=logging.INFO) - logging.warn("95040 Eeprom Tool - " + str(VERSION) + "- No warranty implied or given, manually verify all changes before saving eeprom to ECU, this tool could cause permenent damage to ECU and prevent vehicle running\n") + logging.warning("95040 Eeprom Tool - " + str(VERSION) + "- No warranty implied or given, manually verify all changes before saving eeprom to ECU, this tool could cause permenent damage to ECU and prevent vehicle running\n") parser = argparse.ArgumentParser(description='95040 Eeprom Tool ' + str(VERSION) + ' View/Modify me7.5 eeprom files') parser.add_argument('--in',dest='infile',help='Input eeprom bin',required=True) parser.add_argument('--out',dest='outfile',help='File to save eeprom to (must be supplied if changing Immo/VIN)')