Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scantool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ set (CLI_SRCS scantool_cli.c scantool_diag.c scantool_set.c
set (SCANTOOL_SRCS scantool.c
scantool_test.c scantool_vag.c scantool_850.c scantool_dyno.c
scantool_850/dtc.c scantool_850/ecu.c
scantool_850/frobbed.c scantool_850/xiaotec.c
scantool_obd.c ${FREEDIAG_RC})


Expand Down
16 changes: 16 additions & 0 deletions scantool/scantool_850/config.h
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__
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why frobbed ?


#endif // __SCANTOOL_850_CONFIG_H__
4 changes: 3 additions & 1 deletion scantool/scantool_850/dtc.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include "dtc.h"
#include "config.h"

const struct dtc_table_entry *dtctable_by_addr(uint8_t addr) {
const struct ecu_dtc_table_map_entry *ecu_dtc_entry;
Expand All @@ -11,6 +12,7 @@ const struct dtc_table_entry *dtctable_by_addr(uint8_t addr) {
return NULL;
}

#ifdef DEFAULT_850_DTC
static const struct dtc_table_entry aw50_dtc[] = {
{0x13, 332, "Torque converter lock-up solenoid open circuit", NULL},
{0, 0, NULL, NULL},
Expand All @@ -32,4 +34,4 @@ const struct ecu_dtc_table_map_entry ecu_dtc_map[] = {
{0x7a, m44_dtc},
{0, NULL},
};

#endif
1 change: 0 additions & 1 deletion scantool/scantool_850/dtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@ extern const struct ecu_dtc_table_map_entry ecu_dtc_map[];
/** find DTC table by ECU address. NULL if not found */
const struct dtc_table_entry *dtctable_by_addr(uint8_t addr);


#endif // __SCANTOOL_850_DTC_H__

3 changes: 3 additions & 0 deletions scantool/scantool_850/ecu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,6 +29,7 @@ const struct ecu_info *ecu_info_by_name(const char *name) {
}


#ifdef DEFAULT_850_ECU
Copy link
Owner

Choose a reason for hiding this comment

The 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"},
Expand Down Expand Up @@ -58,3 +60,4 @@ const struct ecu_info ecu_list[] = {
{0, NULL, NULL, NULL}
};

#endif
214 changes: 214 additions & 0 deletions scantool/scantool_850/frobbed.c

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions scantool/scantool_850/parser.py
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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this function just applicable to the xiaotec import ?
Then naming should be made more uniform in comments, function names, and filenames; currently I see inconsistent use of "Aleksi", "richard", "xiaotec", and "frobbed"

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':
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wha'ts special about 2E / 2F here ?

Copy link
Contributor

Choose a reason for hiding this comment

The 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 + '" },')
Copy link
Owner

Choose a reason for hiding this comment

The 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
Copy link
Owner

Choose a reason for hiding this comment

The 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()
1 change: 1 addition & 0 deletions scantool/scantool_850/templates/dtc.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{0x{{code}}, {{suffix}}, "{{description}}", NULL},
4 changes: 4 additions & 0 deletions scantool/scantool_850/templates/dtc_list.mustache
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},
};
Empty file.
1 change: 1 addition & 0 deletions scantool/scantool_850/templates/ecu_entry.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{0x{{ecu}}, {{dtc_table}}},
1 change: 1 addition & 0 deletions scantool/scantool_850/templates/ecu_item.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ .addr = 0x{{ecu_address}}, .desc = "{{ecu_description}}", .dtc_prefix = "{{ecu_prefix}}" },
Copy link
Owner

Choose a reason for hiding this comment

The 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 {0x{{ecu_address}}, "{{ecu_description}}", "{{ecu_prefix}}" }, will be unambiguously clear ?

4 changes: 4 additions & 0 deletions scantool/scantool_850/templates/ecu_list.mustache
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}
};
7 changes: 7 additions & 0 deletions scantool/scantool_850/templates/prefix.mustache
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}}__

6 changes: 6 additions & 0 deletions scantool/scantool_850/templates/suffix.mustache
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}}__
Loading