276fb25e61
- Adding reserved for incomplete dissections - more consistent formatting - adding sorting to make-isobus.py in case csv are not sorted in future - adding macros to packet-isobus-parameters.h
224 lines
7.5 KiB
Python
224 lines
7.5 KiB
Python
#!/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()
|