-
Notifications
You must be signed in to change notification settings - Fork 85
Add extra DTCs for Volvo 850 & S/C/V70 as well as parser for generating them #99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
183ba11
425147a
3cefed9
78a73ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| #ifndef __SCANTOOL_850_CONFIG_H__ | ||
| #define __SCANTOOL_850_CONFIG_H__ | ||
|
|
||
|
|
||
| // There are three possible sources for DTC/ECU codes | ||
| // The default | ||
| #define DEFAULT_850_DTC | ||
| #define DEFAULT_850_ECU | ||
|
|
||
| // Sourced from Aleksi (author of the 850 OBD Android App) | ||
| // #define __SCANTOOL_850_DTC_XIAOTEC__ | ||
|
|
||
| // Sourced from Richard Jones (https://jonesrh.info/volvo850/index.html) | ||
| // #define __SCANTOOL_850_DTC_FROBBED__ | ||
|
|
||
| #endif // __SCANTOOL_850_CONFIG_H__ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
|
|
||
| #include "../diag.h" | ||
| #include "ecu.h" | ||
| #include "config.h" | ||
|
|
||
| const struct ecu_info *ecu_info_by_addr(uint8_t addr) { | ||
| const struct ecu_info *ecu_entry; | ||
|
|
@@ -28,6 +29,7 @@ const struct ecu_info *ecu_info_by_name(const char *name) { | |
| } | ||
|
|
||
|
|
||
| #ifdef DEFAULT_850_ECU | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to keep these at all ? |
||
|
|
||
| const struct ecu_info ecu_list[] = { | ||
| {0x01, "abs", "antilock brakes", "ABS"}, | ||
|
|
@@ -58,3 +60,4 @@ const struct ecu_info ecu_list[] = { | |
| {0, NULL, NULL, NULL} | ||
| }; | ||
|
|
||
| #endif | ||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,204 @@ | ||
| import sys | ||
| import re | ||
|
|
||
| # a class representing an OBD-II Diagnostic Trouble Code (DTC) | ||
| class dtc: | ||
| # constructor | ||
| def __init__(self, ecu, code, prefix, suffix, description): | ||
| self.code = code | ||
| self.description = description | ||
| self.ecu = ecu | ||
| self.prefix = prefix | ||
| self.suffix = suffix | ||
|
|
||
| # a class representing an ecu address and description | ||
| class ecu: | ||
| # constructor | ||
| def __init__(self, address, description, prefix): | ||
| self.address = address | ||
| self.description = description | ||
| self.prefix = prefix | ||
|
|
||
|
|
||
| # this loads dtcs from the xiaotec file export | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this function just applicable to the xiaotec import ? |
||
| def load_dtcs(file_path): | ||
| dtcs = [] | ||
| ecus = [] | ||
|
|
||
| with open(file_path, 'r') as file: | ||
| current_ecu = None | ||
| strings = {} | ||
| for line in file: | ||
| # regular expression to match 01 - description | ||
| match = re.match(r'([0-9A-F][0-9A-F]) - (.+)', line.strip()) | ||
| if match: | ||
| current_ecu = ecu(match.groups()[0], match.groups()[1], 'unknown') | ||
| ecus.append(current_ecu) | ||
| # print(current_ecu.address) | ||
|
|
||
| # regular expression to match dtc.contains("<code>") once | ||
| match = re.match(r'^if \(dtc.contains\("([0-9A-F]+)"\)\) ?// ?([^\-]+)\-?([0-9]+) ?\(?([a-z])?\)?', line.strip()) | ||
| if match: | ||
| string_key = match.groups()[2] | ||
| if match.groups()[3]: | ||
| string_key += match.groups()[3] | ||
| dtcs.append(dtc(current_ecu.address, match.groups()[0], match.groups()[1], match.groups()[2].strip(), string_key)) | ||
| current_ecu.prefix = match.groups()[1] | ||
|
|
||
| # regular expression to match dtc.contains("<code>") twice | ||
| match = re.match(r'^if \(dtc.contains\("([0-9A-F]+)"\) ?\|\| ?dtc.contains\("([0-9A-F]+)"\)\) ?// ?([^\-]+)\-?([0-9]+) ?\(?([a-z])?\)?', line.strip()) | ||
| if match: | ||
| string_key = match.groups()[2] | ||
| if match.groups()[3]: | ||
| string_key += match.groups()[3] | ||
| dtcs.append(dtc(current_ecu.address, match.groups()[0], match.groups()[2], match.groups()[3], string_key)) | ||
| dtcs.append(dtc(current_ecu.address, match.groups()[1], match.groups()[2], match.groups()[3], string_key)) | ||
|
|
||
| match = re.match(r'<string name="([0-9A-Za-z_]+)">(.+)</string>', line.strip()) | ||
| if match: | ||
| if not current_ecu.address in strings: | ||
| strings[current_ecu.address] = {} | ||
| strings[current_ecu.address][match.groups()[0]] = match.groups()[1] | ||
|
|
||
| for d in dtcs: | ||
| key = d.prefix + d.suffix | ||
| ecu_key = d.ecu | ||
| if ecu_key == '2E': | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wha'ts special about 2E / 2F here ?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2E is the left power seat and 2F is the right power seat. The DTCs are the same, only the address is different. (Except on model year '96, where they put them both on 2F, and the tester can't talk to them unless you unhook one or the other. Oops.) |
||
| ecu_key = '2F' | ||
| if ecu_key in strings: | ||
| string_list = strings[ecu_key] | ||
| if key in string_list: | ||
| d.description = string_list[key] | ||
| # Special case for motronic 4.4 | ||
| elif key + '_7A' in string_list: | ||
| d.description = string_list[key + '_7A'] | ||
| # Special case for EMS ECU | ||
| elif 'V_' + key in string_list: | ||
| d.description = string_list['V_' + key] | ||
| else: | ||
| print('No description found for ' + key) | ||
| else: | ||
| print('No ecu found for: "%s"' % ecu_key) | ||
|
|
||
| d.description = escape(d.description) | ||
|
|
||
| return (dtcs, ecus) | ||
|
|
||
|
|
||
| def escape(description): | ||
| result = description.replace('"', '\\"') | ||
| # Sadly some strings are already escaped :( so we need to unescape the double escape. | ||
| result = result.replace('\\\\"', '\\"') | ||
| # This is a weird typo in the original file :( | ||
| result = result.replace('\\A', '\\nA' | ||
| ) | ||
| return result | ||
|
|
||
| # write a function to parse the DTCs from a text file and return a list of DTCs | ||
| def parse_dtc_file(file_path): | ||
| dtcs = [] | ||
| ecus = {} | ||
| with open(file_path, 'r') as file: | ||
| for line in file: | ||
| match = re.match(r'([0-9]+) ([0-9A-F]+) ([A-Z]+)\-([0-9]+) (.+)', line.strip()) | ||
| if match: | ||
| # construct a dtc object from match and append it to the list | ||
| dtcs.append(dtc(match.groups()[0], match.groups()[1], match.groups()[2], match.groups()[3], escape(match.groups()[4]))) | ||
| current_ecu = ecu(match.groups()[0], match.groups()[2], match.groups()[2]) | ||
| ecus[current_ecu.address] = current_ecu | ||
| ecu_list = [] | ||
| for key in ecus: | ||
| ecu_list.append(ecus[key]) | ||
| return (dtcs, ecu_list) | ||
|
|
||
| # a function that takes a dtc object and a pointer to a mustach file and writes the dtc to the file | ||
| def write_dtc_to_mustache(dtc, template): | ||
| # substitute the fields of the dtc object into the template | ||
| template = template.replace('{{ecu}}', dtc.ecu) | ||
| template = template.replace('{{code}}', dtc.code) | ||
| template = template.replace('{{prefix}}', dtc.prefix) | ||
| template = template.replace('{{suffix}}', dtc.suffix) | ||
| template = template.replace('{{description}}', dtc.description) | ||
|
|
||
| return template | ||
|
|
||
| # a function that given a list of dtcs groups them into a map by ecu | ||
| def group_dtcs_by_ecu(dtcs): | ||
| ecu_map = {} | ||
| for dtc in dtcs: | ||
| if dtc.ecu not in ecu_map: | ||
| ecu_map[dtc.ecu] = [] | ||
| ecu_map[dtc.ecu].append(dtc) | ||
| return ecu_map | ||
|
|
||
|
|
||
| # write a main function to call the parse_dtc_file function with a file from the first argument | ||
| def main(): | ||
| if len(sys.argv) != 5: | ||
| print('Usage: python parser.py <format> <input-file> <template_directory> <header-name>') | ||
| sys.exit(1) | ||
| format = sys.argv[1] | ||
| if format == 'aleksi': | ||
| (raw_dtcs, ecus) = load_dtcs(sys.argv[2]) | ||
| elif format == 'richard': | ||
| (raw_dtcs, ecus) = parse_dtc_file(sys.argv[2]) | ||
| else: | ||
| print('Unknown format: ' + format) | ||
| sys.exit(1) | ||
|
|
||
| ecu_map = group_dtcs_by_ecu(raw_dtcs) | ||
|
|
||
| directory = sys.argv[3] | ||
| name = sys.argv[4] | ||
|
|
||
| with (open(directory + '/dtc.mustache', 'r') as dtc_template_file, | ||
| open(directory + '/dtc_list.mustache', 'r') as dtc_list_template_file, | ||
| open(directory + '/ecu_entry.mustache', 'r') as ecu_template_file, | ||
| open(directory + '/ecu_item.mustache', 'r') as ecu_item_template_file, | ||
| open(directory + '/ecu_list.mustache', 'r') as ecu_list_template_file, | ||
| open(directory + '/prefix.mustache', 'r') as prefix_template_file, | ||
| open(directory + '/suffix.mustache', 'r') as suffix_template_file): | ||
|
|
||
| prefix_template = prefix_template_file.read() | ||
| prefix_template = prefix_template.replace('{{name}}', name.upper()) | ||
| print(prefix_template) | ||
|
|
||
| template = dtc_template_file.read() | ||
| dtc_list_template = dtc_list_template_file.read() | ||
| ecu_template = ecu_template_file.read() | ||
|
|
||
| dtc_ecu_list = [] | ||
| for ecu in ecu_map.keys(): | ||
| out = ecu_template.replace('{{ecu}}', ecu) | ||
| out = out.replace('{{dtc_table}}', 'dtc_list_' + ecu.lower()) | ||
| dtc_ecu_list.append(out) | ||
|
|
||
| dtcs = ecu_map[ecu] | ||
| dtc_list = [] | ||
| for dtc in dtcs: | ||
| dtc_list.append(write_dtc_to_mustache(dtc, template)) | ||
| out = dtc_list_template.replace('{{dtc_list}}', '\n'.join(dtc_list)) | ||
| out = out.replace('{{dtc_list_name}}', 'dtc_list_' + ecu.lower()) | ||
| print(out) | ||
|
|
||
| ecu_list_template = ecu_list_template_file.read() | ||
| ecu_item_template = ecu_item_template_file.read() | ||
|
|
||
| ecu_list = [] | ||
| for ecu in ecus: | ||
| ecu_list.append(ecu_item_template | ||
| .replace('{{ecu_address}}', ecu.address) | ||
| .replace('{{ecu_description}}', ecu.description) | ||
| .replace('{{ecu_prefix}}', ecu.prefix)) | ||
| # ecu_list.append(' { .addr = 0x' + ecu.address + ', .desc = "' + ecu.description + '", .dtc_prefix = "' + ecu.prefix + '" },') | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dead code ? should be removed |
||
| print(ecu_list_template.replace('{{ecu_list}}', '\n'.join(ecu_list))) | ||
| print() | ||
|
|
||
| suffix_template = suffix_template_file.read() | ||
| suffix_template = suffix_template.replace('{{name}}', name.upper()) | ||
| suffix_template = suffix_template.replace('{{ecu_list}}', '\n'.join(dtc_ecu_list)) | ||
| print(suffix_template) | ||
|
|
||
| # Example call: python3 parser.py richard sources/export_2024-04-06_frobbed.txt templates/ frobbed > frobbed.c | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are nice !! Better put them near the top, not hidden way at the end |
||
| # Example call: python3 parser.py aleksi sources/DTC_List_850OBDII_D2.txt templates/ xiaotec > xiaotec.c | ||
| main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {0x{{code}}, {{suffix}}, "{{description}}", NULL}, |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| const struct dtc_table_entry {{dtc_list_name}}[] = { | ||
| {{dtc_list}} | ||
| {0, 0, NULL, NULL}, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {0x{{ecu}}, {{dtc_table}}}, |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| { .addr = 0x{{ecu_address}}, .desc = "{{ecu_description}}", .dtc_prefix = "{{ecu_prefix}}" }, | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I mentioned earlier, unless there's a really compelling reason to use designated initializers, I think |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| const struct ecu_info ecu_list[] = { | ||
| {{ecu_list}} | ||
| {0, NULL, NULL, NULL} | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| #include <stdlib.h> | ||
| #include "dtc.h" | ||
| #include "ecu.h" | ||
| #include "config.h" | ||
|
|
||
| #ifdef __SCANTOOL_850_DTC_{{name}}__ | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| const struct ecu_dtc_table_map_entry ecu_dtc_map[] = { | ||
| {{ecu_list}} | ||
| {0, NULL}, | ||
| }; | ||
|
|
||
| #endif // __SCANTOOL_850_DTC_{{name}}__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why
frobbed?