sq epan/dissectors/pidl/rcg/rcg.cnf
[wireshark-sm.git] / tools / make-isobus.py
blob792f2b337e46eae397ef861efa1707d8ef66aed4
1 #!/usr/bin/env python3
3 # Wireshark - Network traffic analyzer
4 # By Gerald Combs <gerald@wireshark.org>
5 # Copyright 1998 Gerald Combs
7 # SPDX-License-Identifier: GPL-2.0-or-later
8 '''Update the "packet-isobus-parameters.h" file.
9 Make-isobus creates a file containing isobus parameters
10 from the databases at isobus.net.
11 '''
13 import csv
14 import io
15 import os
16 import sys
17 import urllib.request, urllib.error, urllib.parse
18 import zipfile
20 def exit_msg(msg=None, status=1):
21 if msg is not None:
22 sys.stderr.write(msg + '\n\n')
23 sys.stderr.write(__doc__ + '\n')
24 sys.exit(status)
26 def open_url_zipped(url):
27 '''Open a URL of a zipped file.
29 '''
31 url_path = '/'.join(url)
33 req_headers = { 'User-Agent': 'Wireshark make-isobus' }
34 try:
35 req = urllib.request.Request(url_path, headers=req_headers)
36 response = urllib.request.urlopen(req)
37 body = response.read()
38 except Exception:
39 exit_msg('Error opening ' + url_path)
41 return zipfile.ZipFile(io.BytesIO(body))
43 def main():
44 isobus_output_path = os.path.join('epan', 'dissectors', 'packet-isobus-parameters.h')
46 isobus_zip_url = [ "https://www.isobus.net/isobus/attachments/", "isoExport_csv.zip"]
48 isobus_files = {
49 'indust' : 'Industry Groups.csv',
50 'glblfcts' : 'Global NAME Functions.csv',
51 'igfcts' :'IG Specific NAME Function.csv',
52 'manuf' : 'Manufacturer IDs.csv',
53 'pgn_spns' : 'SPNs and PGNs.csv'
56 zipf = open_url_zipped(isobus_zip_url)
58 # Industries csv
59 min_total = 4 # typically 8
60 f = zipf.read(isobus_files['indust'])
61 lines = f.decode('UTF-8', 'replace').splitlines()
63 if len(lines) < min_total:
64 exit_msg("{}: Not enough entries ({})".format(isobus_files['indust'], len(lines)))
66 indust_csv = csv.reader(lines)
67 next(indust_csv)
69 # Global Name Functions csv
70 min_total = 50 # XXX as of 2023-10-18
71 f = zipf.read(isobus_files['glblfcts'])
72 lines = f.decode('UTF-8', 'replace').splitlines()
74 if len(lines) < min_total:
75 exit_msg("{}: Not enough entries ({})".format(isobus_files['glblfcts'], len(lines)))
77 glbl_name_functions_csv = csv.reader(lines)
78 next(glbl_name_functions_csv)
80 # Specific Name Functions csv
81 min_total = 200 # 295 as of 2023-10-18
82 f = zipf.read(isobus_files['igfcts'])
83 lines = f.decode('UTF-8', 'replace').splitlines()
85 if len(lines) < min_total:
86 exit_msg("{}: Not enough entries ({})".format(isobus_files['igfcts'], len(lines)))
88 vehicle_system_names = {}
89 specific_functions = {}
91 specific_functions_csv = csv.reader(lines)
92 next(specific_functions_csv)
93 for row in specific_functions_csv:
94 ig_id, vs_id, vs_name, f_id, f_name = row[:5]
95 new_id = int(ig_id) * 256 + int(vs_id)
96 if len(vs_name) > 50:
97 if new_id != 539: # 539: Weeders ...
98 print(f"shortening {new_id}: {vs_name} -> {vs_name[:36]}")
99 vs_name = vs_name[:36]
100 vehicle_system_names[new_id] = vs_name
102 #vehicle_system_names.setdefault(ig_id, {}).setdefault(vs_id, vs_name)
103 new_id2 = 256 * new_id + int(f_id)
104 specific_functions[new_id2] = f_name
106 # Manufacturers csv
107 min_total = 1000 # 1396 as of 2023-10-18
108 f = zipf.read(isobus_files['manuf'])
109 lines = f.decode('UTF-8', 'replace').splitlines()
111 if len(lines) < min_total:
112 exit_msg("{}: Not enough entries ({})".format(isobus_files['manuf'], len(lines)))
114 manuf_csv = csv.reader(lines)
115 next(manuf_csv)
117 # PGN SPN csv
118 min_total = 20000 # 23756 as of 2023-10-18
119 f = zipf.read(isobus_files['pgn_spns'])
120 lines = f.decode('UTF-8', 'replace').splitlines()
122 if len(lines) < min_total:
123 exit_msg("{}: Not enough entries ({})".format(isobus_files['pgn_spns'], len(lines)))
125 pgn_names = {}
127 pgn_spn_csv = csv.reader(lines)
128 next(pgn_spn_csv)
129 for row in pgn_spn_csv:
130 try:
131 pgn_id, pgn_name, = row[:2]
132 if not pgn_name.startswith("Proprietary B"):
133 pgn_names[int(pgn_id)] = pgn_name.replace("\"","'")
134 except Exception:
135 pass
137 # prepare output file
138 try:
139 output_fd = io.open(isobus_output_path, 'w', encoding='UTF-8')
140 except Exception:
141 exit_msg("Couldn't open ({}) ".format(isobus_output_path))
143 output_fd.write('''/*
144 * This file was generated by running ./tools/make-isobus.py.
146 * SPDX-License-Identifier: GPL-2.0-or-later
148 * The ISOBUS public listings available from:
149 * <https://www.isobus.net/isobus/attachments/isoExport_csv.zip>
153 #ifndef __PACKET_ISOBUS_PARAMETERS_H__
154 #define __PACKET_ISOBUS_PARAMETERS_H__
156 ''')
158 # Write Industries
159 output_fd.write("static const value_string _isobus_industry_groups[] = {\n")
161 for row in sorted(indust_csv, key=lambda x: int(x[0])):
162 output_fd.write(f" {{ {row[0]}, \"{row[1]}\" }},\n")
164 output_fd.write(" { 0, NULL }\n")
165 output_fd.write("};\n")
166 output_fd.write("static value_string_ext isobus_industry_groups_ext = VALUE_STRING_EXT_INIT(_isobus_industry_groups);\n\n")
168 # Write Vehicle System Names
169 output_fd.write("/* key: 256 * Industry-Group-ID + Vehicle-Group-ID */\n")
170 output_fd.write("static const value_string _isobus_vehicle_systems[] = {\n")
172 for key in sorted(vehicle_system_names):
173 output_fd.write(f" {{ {hex(key)}, \"{vehicle_system_names[key]}\" }},\n")
175 output_fd.write(" { 0, NULL }\n")
176 output_fd.write("};\n")
177 output_fd.write("static value_string_ext isobus_vehicle_systems_ext = VALUE_STRING_EXT_INIT(_isobus_vehicle_systems);\n\n")
179 # Write Global Name Functions
180 output_fd.write("static const value_string _isobus_global_name_functions[] = {\n")
182 for row in sorted(glbl_name_functions_csv, key=lambda x: int(x[0])):
183 output_fd.write(f" {{ {row[0]}, \"{row[1]}\" }},\n")
185 output_fd.write(" { 0, NULL }\n")
186 output_fd.write("};\n")
187 output_fd.write("static value_string_ext isobus_global_name_functions_ext = VALUE_STRING_EXT_INIT(_isobus_global_name_functions);\n\n")
189 # IG Specific Global Name Functions
190 output_fd.write("/* key: 65536 * Industry-Group-ID + 256 * Vehicle-System-ID + Function-ID */\n")
191 output_fd.write("static const value_string _isobus_ig_specific_name_functions[] = {\n")
193 for key in sorted(specific_functions):
194 output_fd.write(f" {{ {hex(key)}, \"{specific_functions[key]}\" }},\n")
196 output_fd.write(" { 0, NULL }\n")
197 output_fd.write("};\n")
198 output_fd.write("static value_string_ext isobus_ig_specific_name_functions_ext = VALUE_STRING_EXT_INIT(_isobus_ig_specific_name_functions);\n\n")
200 # Write Manufacturers
201 output_fd.write("static const value_string _isobus_manufacturers[] = {\n")
203 for row in sorted(manuf_csv, key=lambda x: int(x[0])):
204 output_fd.write(f" {{ {row[0]}, \"{row[1]}\" }},\n")
206 output_fd.write(" { 0, NULL }\n")
207 output_fd.write("};\n")
208 output_fd.write("static value_string_ext isobus_manufacturers_ext = VALUE_STRING_EXT_INIT(_isobus_manufacturers);\n\n")
210 # PGN Names
211 output_fd.write("static const value_string _isobus_pgn_names[] = {\n")
213 for key in sorted(pgn_names):
214 output_fd.write(f" {{ {key}, \"{pgn_names[key]}\" }},\n")
216 output_fd.write(" { 0, NULL }\n")
217 output_fd.write("};\n")
218 output_fd.write("static value_string_ext isobus_pgn_names_ext = VALUE_STRING_EXT_INIT(_isobus_pgn_names);\n\n")
220 output_fd.write("#endif /* __PACKET_ISOBUS_PARAMETERS_H__ */")
221 if __name__ == '__main__':
222 main()