diff options
Diffstat (limited to '')
-rw-r--r-- | tools/make-isobus.py | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/tools/make-isobus.py b/tools/make-isobus.py new file mode 100644 index 00000000..ce0259c7 --- /dev/null +++ b/tools/make-isobus.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# Copyright 1998 Gerald Combs +# +# SPDX-License-Identifier: GPL-2.0-or-later +'''Update the "packet-isobus-parameters.h" file. +Make-isobus creates a file containing isobus parameters +from the databases at isobus.net. +''' + +import csv +import io +import os +import sys +import urllib.request, urllib.error, urllib.parse +import zipfile + +def exit_msg(msg=None, status=1): + if msg is not None: + sys.stderr.write(msg + '\n\n') + sys.stderr.write(__doc__ + '\n') + sys.exit(status) + +def open_url_zipped(url): + '''Open a URL of a zipped file. + + ''' + + url_path = '/'.join(url) + + req_headers = { 'User-Agent': 'Wireshark make-isobus' } + try: + req = urllib.request.Request(url_path, headers=req_headers) + response = urllib.request.urlopen(req) + body = response.read() + except Exception: + exit_msg('Error opening ' + url_path) + + return zipfile.ZipFile(io.BytesIO(body)) + +def main(): + this_dir = os.path.dirname(__file__) + isobus_output_path = os.path.join('epan', 'dissectors', 'packet-isobus-parameters.h') + + isobus_zip_url = [ "https://www.isobus.net/isobus/attachments/", "isoExport_csv.zip"] + + isobus_files = { + 'indust' : 'Industry Groups.csv', + 'glblfcts' : 'Global NAME Functions.csv', + 'igfcts' :'IG Specific NAME Function.csv', + 'manuf' : 'Manufacturer IDs.csv', + 'pgn_spns' : 'SPNs and PGNs.csv' + } + + zipf = open_url_zipped(isobus_zip_url) + + # Industries csv + min_total = 4 # typically 8 + f = zipf.read(isobus_files['indust']) + lines = f.decode('UTF-8', 'replace').splitlines() + + if len(lines) < min_total: + exit_msg("{}: Not enough entries ({})".format(isobus_files['indust'], len(lines))) + + indust_csv = csv.reader(lines) + next(indust_csv) + + # Global Name Functions csv + min_total = 50 # XXX as of 2023-10-18 + f = zipf.read(isobus_files['glblfcts']) + lines = f.decode('UTF-8', 'replace').splitlines() + + if len(lines) < min_total: + exit_msg("{}: Not enough entries ({})".format(isobus_files['glblfcts'], len(lines))) + + glbl_name_functions_csv = csv.reader(lines) + next(glbl_name_functions_csv) + + # Specific Name Functions csv + min_total = 200 # 295 as of 2023-10-18 + f = zipf.read(isobus_files['igfcts']) + lines = f.decode('UTF-8', 'replace').splitlines() + + if len(lines) < min_total: + exit_msg("{}: Not enough entries ({})".format(isobus_files['igfcts'], len(lines))) + + vehicle_system_names = {} + specific_functions = {} + + specific_functions_csv = csv.reader(lines) + next(specific_functions_csv) + for row in specific_functions_csv: + ig_id, vs_id, vs_name, f_id, f_name = row[:5] + new_id = int(ig_id) * 256 + int(vs_id) + if len(vs_name) > 50: + if new_id != 539: # 539: Weeders ... + print(f"shortening {new_id}: {vs_name} -> {vs_name[:36]}") + vs_name = vs_name[:36] + vehicle_system_names[new_id] = vs_name + + #vehicle_system_names.setdefault(ig_id, {}).setdefault(vs_id, vs_name) + new_id2 = 256 * new_id + int(f_id) + specific_functions[new_id2] = f_name + + # Manufacturers csv + min_total = 1000 # 1396 as of 2023-10-18 + f = zipf.read(isobus_files['manuf']) + lines = f.decode('UTF-8', 'replace').splitlines() + + if len(lines) < min_total: + exit_msg("{}: Not enough entries ({})".format(isobus_files['manuf'], len(lines))) + + manuf_csv = csv.reader(lines) + next(manuf_csv) + + # PGN SPN csv + min_total = 20000 # 23756 as of 2023-10-18 + f = zipf.read(isobus_files['pgn_spns']) + lines = f.decode('UTF-8', 'replace').splitlines() + + if len(lines) < min_total: + exit_msg("{}: Not enough entries ({})".format(isobus_files['pgn_spns'], len(lines))) + + pgn_names = {} + + pgn_spn_csv = csv.reader(lines) + next(pgn_spn_csv) + for row in pgn_spn_csv: + try: + pgn_id, pgn_name, = row[:2] + if not pgn_name.startswith("Proprietary B"): + pgn_names[int(pgn_id)] = pgn_name.replace("\"","'") + except: + pass + + # prepare output file + try: + output_fd = io.open(isobus_output_path, 'w', encoding='UTF-8') + except Exception: + exit_msg("Couldn't open ({}) ".format(isobus_output_path)) + + output_fd.write('''/* + * This file was generated by running ./tools/make-isobus.py. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * The ISOBUS public listings available from: + * <https://www.isobus.net/isobus/attachments/isoExport_csv.zip> + * + */ + +#ifndef __PACKET_ISOBUS_PARAMETERS_H__ +#define __PACKET_ISOBUS_PARAMETERS_H__ + +''') + + # Write Industries + output_fd.write("static const value_string _isobus_industry_groups[] = {\n") + + for row in sorted(indust_csv, key=lambda x: int(x[0])): + output_fd.write(f" {{ {row[0]}, \"{row[1]}\" }},\n") + + output_fd.write(" { 0, NULL }\n") + output_fd.write("};\n") + output_fd.write("static value_string_ext isobus_industry_groups_ext = VALUE_STRING_EXT_INIT(_isobus_industry_groups);\n\n"); + + # Write Vehicle System Names + output_fd.write("/* key: 256 * Industry-Group-ID + Vehicle-Group-ID */\n") + output_fd.write("static const value_string _isobus_vehicle_systems[] = {\n") + + for key in sorted(vehicle_system_names): + output_fd.write(f" {{ {hex(key)}, \"{vehicle_system_names[key]}\" }},\n") + + output_fd.write(" { 0, NULL }\n") + output_fd.write("};\n") + output_fd.write("static value_string_ext isobus_vehicle_systems_ext = VALUE_STRING_EXT_INIT(_isobus_vehicle_systems);\n\n"); + + # Write Global Name Functions + output_fd.write("static const value_string _isobus_global_name_functions[] = {\n") + + for row in sorted(glbl_name_functions_csv, key=lambda x: int(x[0])): + output_fd.write(f" {{ {row[0]}, \"{row[1]}\" }},\n") + + output_fd.write(" { 0, NULL }\n") + output_fd.write("};\n") + output_fd.write("static value_string_ext isobus_global_name_functions_ext = VALUE_STRING_EXT_INIT(_isobus_global_name_functions);\n\n"); + + # IG Specific Global Name Functions + output_fd.write("/* key: 65536 * Industry-Group-ID + 256 * Vehicle-System-ID + Function-ID */\n") + output_fd.write("static const value_string _isobus_ig_specific_name_functions[] = {\n") + + for key in sorted(specific_functions): + output_fd.write(f" {{ {hex(key)}, \"{specific_functions[key]}\" }},\n") + + output_fd.write(" { 0, NULL }\n") + output_fd.write("};\n") + output_fd.write("static value_string_ext isobus_ig_specific_name_functions_ext = VALUE_STRING_EXT_INIT(_isobus_ig_specific_name_functions);\n\n"); + + # Write Manufacturers + output_fd.write("static const value_string _isobus_manufacturers[] = {\n") + + for row in sorted(manuf_csv, key=lambda x: int(x[0])): + output_fd.write(f" {{ {row[0]}, \"{row[1]}\" }},\n") + + output_fd.write(" { 0, NULL }\n") + output_fd.write("};\n") + output_fd.write("static value_string_ext isobus_manufacturers_ext = VALUE_STRING_EXT_INIT(_isobus_manufacturers);\n\n"); + + # PGN Names + output_fd.write("static const value_string _isobus_pgn_names[] = {\n") + + for key in sorted(pgn_names): + output_fd.write(f" {{ {key}, \"{pgn_names[key]}\" }},\n") + + output_fd.write(" { 0, NULL }\n") + output_fd.write("};\n") + output_fd.write("static value_string_ext isobus_pgn_names_ext = VALUE_STRING_EXT_INIT(_isobus_pgn_names);\n\n"); + + output_fd.write("#endif /* __PACKET_ISOBUS_PARAMETERS_H__ */") +if __name__ == '__main__': + main() |