├── README.md └── odis2vcp.py /README.md: -------------------------------------------------------------------------------- 1 | # odis2vcp 2 | Converter for ODIS XML Datasets to VCP XML format. 3 | 4 | ## Requirements 5 | * Python 6 | * If there are any issues regarding missing modules, install them using pip 7 | 8 | ## Usage 9 | `python odis2vcp.py [-h] -i IN [-f FMT] -d DESC` 10 | 11 | ## Arguments 12 | ``` 13 | -h, --help show this help message and exit 14 | -i IN, --in IN Input file path 15 | -f FMT, --fmt FMT Output format: vcp (default) or raw. 16 | -d DESC, --desc DESC Output file description. E.g. "Seat Leon 2016" 17 | ``` 18 | 19 | ## Example 20 | `python odis2vcp.py -i ODIS_dataset.xml -d "Seat Leon 2016"` 21 | 22 | Result: 23 | ```Module: 19 24 | Start_Address: 0x000A80 25 | ZDC Name: V1234567ZJ 26 | ZDC version: 0001 27 | Login: 20103 28 | Extracting VCP data to "19 VCP 0x000A80 V1234567ZJ 0001 - Seat Leon 2016.xml" 29 | 30 | Module: 19 31 | Start_Address: 0x0002388 32 | ZDC Name: V1234567ZJ 33 | ZDC version: 0001 34 | Login: 20103 35 | Extracting VCP data to "19 VCP 0x0002388 V1234567ZJ 0001 - Seat Leon 2016.xml" 36 | 37 | Module: 19 38 | Start_Address: 0x1B80 39 | ZDC Name: V1234567ZJ 40 | ZDC version: 0001 41 | Login: 20103 42 | Extracting VCP data to "19 VCP 0x1B80 V1234567ZJ 0001 - Seat Leon 2016.xml" 43 | -------------------------------------------------------------------------------- /odis2vcp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # ODIS2VCP 3 | # Dataset extractor 4 | # Converts datasets from ODIS XML format to VCP XML format 5 | # by Jille 6 | 7 | from xml.dom.minidom import * 8 | import binascii, argparse, sys 9 | import xml.etree.cElementTree as ET 10 | 11 | # variables 12 | dataset_counter = 0 13 | extracted_dataset_counter = 0 14 | version = "1.0" 15 | 16 | # parse arguments 17 | ap = argparse.ArgumentParser(description="ODIS2VCP Dataset extractor v%s" % version) 18 | ap.add_argument("-i", "--in", required=True, help="Input file path") 19 | ap.add_argument("-f", "--fmt", required=False, help="Output format: vcp (default) or raw.") 20 | ap.add_argument("-d", "--desc", required=True, help="Output file description. E.g. \"Seat Leon 2016\" ") 21 | 22 | args = vars(ap.parse_args()) 23 | file_output_format = args['fmt'] 24 | file_prefix = args['desc'] 25 | input_file = args['in'] 26 | 27 | 28 | # extract dataset to a raw export of the dataset 29 | def extract_to_raw(dataset, filename, diagnostic_address): 30 | global extracted_dataset_counter 31 | extracted_dataset_counter=extracted_dataset_counter+1 32 | 33 | filename = diagnostic_address + " " + filename + ".bin" 34 | print (" Extracting raw data to \"%s\"" % filename) 35 | print ("") 36 | output_file = open(filename,"wb") 37 | binary_data = binascii.unhexlify(dataset) 38 | output_file.write(binary_data) 39 | 40 | output_file.close() 41 | 42 | # extract dataset to VCP dataset XML format 43 | def convert_to_vcp(dataset_data, diagnostic_address, start_address, zdc_name, zdc_version, login, filename): 44 | global extracted_dataset_counter 45 | extracted_dataset_counter=extracted_dataset_counter+1 46 | 47 | doc = Document(); 48 | root = doc.createElement("SW-CNT") 49 | doc.appendChild(root) 50 | 51 | ident = doc.createElement("IDENT") 52 | root.appendChild(ident) 53 | 54 | login_data = doc.createElement("LOGIN") 55 | dateiid = doc.createElement("DATEIID") 56 | version_inhalt = doc.createElement("VERSION-INHALT") 57 | ident.appendChild(login_data) 58 | ident.appendChild(dateiid) 59 | ident.appendChild(version_inhalt) 60 | 61 | login_data.appendChild (doc.createTextNode(login)) 62 | dateiid.appendChild (doc.createTextNode(zdc_name)) 63 | version_inhalt.appendChild (doc.createTextNode(zdc_version)) 64 | 65 | 66 | datasets = doc.createElement("DATENBEREICHE") 67 | root.appendChild(datasets) 68 | 69 | dataset = doc.createElement("DATENBEREICH") 70 | datasets.appendChild (dataset) 71 | 72 | dataname = zdc_name + " address - " + start_address 73 | dataset_name = doc.createElement("DATEN-NAME") 74 | dataset.appendChild (dataset_name) 75 | dataset_name.appendChild(doc.createTextNode(zdc_name)) 76 | 77 | dataset_format = doc.createElement("DATEN-FORMAT-NAME") 78 | dataset.appendChild (dataset_format) 79 | dataset_format.appendChild(doc.createTextNode("DFN_HEX")) 80 | 81 | dataset_start = doc.createElement("START-ADR") 82 | dataset.appendChild (dataset_start) 83 | dataset_start.appendChild(doc.createTextNode(start_address)) 84 | 85 | dataset_raw = dataset_data.replace("0x","") 86 | dataset_raw = dataset_raw.replace(",","") 87 | 88 | #some quick and dirty calculations to determine the right size and string format for file size 89 | dataset_size_calc = len(dataset_raw.encode('utf-8')) 90 | dataset_size_calc = hex(int(dataset_size_calc/2)) 91 | dataset_size_calc = str(dataset_size_calc) 92 | 93 | dataset_size = doc.createElement("GROESSE-DEKOMPRIMIERT") 94 | dataset.appendChild (dataset_size) 95 | dataset_size.appendChild(doc.createTextNode(dataset_size_calc)) 96 | 97 | data_data = doc.createElement("DATEN") 98 | dataset.appendChild (data_data) 99 | data_data.appendChild(doc.createTextNode(dataset_data)) 100 | 101 | # write xml data 102 | filename = diagnostic_address + " VCP " + filename + ".xml" 103 | 104 | print (" Extracting VCP data to \"%s\"" % filename) 105 | print ("") 106 | 107 | doc.writexml( open(filename, 'w'), 108 | indent=" ", 109 | addindent=" ", 110 | newl='\n') 111 | 112 | 113 | # Parse single OE XML file 114 | # Print detail of each dataset in small OE XML file 115 | def parse_small_oe_file(): 116 | global dataset_counter 117 | 118 | # Open XML document using minidom parser 119 | DOMTree = xml.dom.minidom.parse(input_file) #todo: use file input argument 120 | collection = DOMTree.documentElement 121 | 122 | #get data from XML 123 | parameter_datas = collection.getElementsByTagName("PARAMETER_DATA") 124 | for parameter_data in parameter_datas: 125 | if parameter_data.hasAttribute("DIAGNOSTIC_ADDRESS"): 126 | diagnostic_address = parameter_data.getAttribute("DIAGNOSTIC_ADDRESS") 127 | diagnostic_address = diagnostic_address.replace ("0x00","") 128 | print (" Module: %s" % diagnostic_address) 129 | if parameter_data.hasAttribute("START_ADDRESS"): 130 | start_address = parameter_data.getAttribute("START_ADDRESS") 131 | print (" Start_Address: %s" % start_address) 132 | if parameter_data.hasAttribute("ZDC_NAME"): 133 | zdc_name = parameter_data.getAttribute("ZDC_NAME") 134 | print (" ZDC Name: %s" % zdc_name) 135 | if parameter_data.hasAttribute("ZDC_VERSION"): 136 | zdc_version = parameter_data.getAttribute("ZDC_VERSION") 137 | print (" ZDC version: %s" % zdc_version) 138 | if parameter_data.hasAttribute("LOGIN"): 139 | login = parameter_data.getAttribute("LOGIN") 140 | print (" Login: %s" % login) 141 | #set filename, e.g. 19 ZL12345 - Seat Leon 2016 142 | filename = start_address + " " + zdc_name + " - " + file_prefix 143 | 144 | dataset_counter=dataset_counter+1 145 | dataset = parameter_data.childNodes[0].data 146 | 147 | #clean the data from all the 0x and commas 148 | if file_output_format == "raw": 149 | dataset = dataset.replace('0x','') 150 | dataset = dataset.replace(",","") 151 | extract_to_raw(dataset,filename,diagnostic_address) 152 | 153 | else: 154 | convert_to_vcp(dataset, diagnostic_address, start_address, zdc_name, zdc_version, login, filename) 155 | 156 | # run the parser. 157 | parse_small_oe_file() 158 | 159 | print ("") 160 | 161 | if file_output_format == "raw": 162 | print (" %s of %s datasets extracted to %s format" % (extracted_dataset_counter, dataset_counter, file_output_format) ) 163 | else: 164 | print (" %s of %s datasets extracted to VCP format" % (extracted_dataset_counter, dataset_counter) ) 165 | --------------------------------------------------------------------------------