blob: de78d05cabe23247b8a46c914077dd7d6a39c81e [file] [log] [blame]
Amaury Pouly44bb2852016-11-11 15:40:56 +01001#!/usr/bin/python3
2import glob
3import os
4import re
5import subprocess
Igor Skochinsky03dd4b92017-04-03 15:13:46 +02006import hashlib
Amaury Pouly44bb2852016-11-11 15:40:56 +01007
8# parse models.txt
9g_models = []
10with open('models.txt') as fp:
11 for line in fp:
12 # we unpack and repack 1) to make the format obvious 2) to catch errors
13 mid,name = line.rstrip().split(",")
14 g_models.append({'mid': int(mid, 0), 'name': name})
15# parse series.txt
16g_series = []
Amaury Pouly90284b62017-01-09 21:48:43 +010017g_series_codename = set()
Amaury Pouly44bb2852016-11-11 15:40:56 +010018with open('series.txt') as fp:
19 for line in fp:
20 # we unpack and repack 1) to make the format obvious 2) to catch errors
21 arr = line.rstrip().split(",")
22 codename = arr[0]
23 name = arr[1]
24 models = arr[2:]
25 # handle empty list
26 if len(models) == 1 and models[0] == "":
27 models = []
28 models = [int(mid,0) for mid in models]
29 g_series.append({'codename': codename, 'name': name, 'models': models})
Amaury Pouly90284b62017-01-09 21:48:43 +010030 g_series_codename.add(codename)
Amaury Pouly44bb2852016-11-11 15:40:56 +010031# parse all maps in nvp/
32# since most nvps are the same, what we actually do is to compute the md5sum hash
33# of all files, to identify groups and then each entry in the name is in fact the
34# hash, and we only parse one file per hash group
35g_hash_nvp = dict() # hash -> nvp
36g_nvp_hash = dict() # codename -> hash
37HASH_SIZE=6
38map_files = glob.glob('nvp/nw*.txt')
Igor Skochinsky03dd4b92017-04-03 15:13:46 +020039for f in map_files:
40 h = hashlib.md5()
41 h.update(open(f, "rb").read())
42 hash = h.hexdigest()
43 codename = re.search('(nw.*)\.txt', f).group(1)
Amaury Pouly90284b62017-01-09 21:48:43 +010044 # sanity check
45 if not (codename in g_series_codename):
Igor Skochinsky03dd4b92017-04-03 15:13:46 +020046 print("Warning: file %s does not have a match series in series.txt" % f)
Amaury Pouly44bb2852016-11-11 15:40:56 +010047 hash = hash[:HASH_SIZE]
48 # only keep one file
49 if not (hash in g_hash_nvp):
50 g_hash_nvp[hash] = set()
51 g_hash_nvp[hash].add(codename);
52 g_nvp_hash[codename] = hash
53# we have some file nodes (nodes-*) but not necessarily for all series
54# so for each hash group, try to find at least one
55for hash in g_hash_nvp:
56 # look at all codename and see if we can find one with a node file
57 node_codename = ""
58 for codename in g_hash_nvp[hash]:
59 if os.path.isfile("nvp/nodes-%s.txt" % codename):
60 node_codename = codename
61 break
62 # if we didn't find one, we just keep the first one
63 # otherwise keep the one we found
64 if node_codename == "":
65 node_codename = g_hash_nvp[hash].pop()
66 g_hash_nvp[hash] = node_codename
67# for each entry in g_hash_nvp, replace the file name by the actual table
68# that we parse, and compute all nvp names at the same time
69g_nvp_names = set() # set of all nvp names
70g_nvp_desc = dict() # name -> set of all description of a node
71g_nvp_size = dict() # name -> set of all possible sizes of a node
72for hash in g_hash_nvp:
73 codename = g_hash_nvp[hash]
74 # extract codename from file
75 # parse file
76 map = dict()
77 with open("nvp/%s.txt" % codename) as fp:
78 for line in fp:
79 # we unpack and repack 1) to make the format obvious 2) to catch errors
80 name,index = line.rstrip().split(",")
81 # convert node to integer but be careful of leading 0 (ie 010 is actually
82 # 10 in decimal, it is not in octal)
83 index = int(index, 10)
84 map[index] = name
85 g_nvp_names.add(name)
86 # parse node map if any
87 node_map = dict()
88 if os.path.isfile("nvp/nodes-%s.txt" % codename):
89 with open("nvp/nodes-%s.txt" % codename) as fp:
90 for line in fp:
91 # we unpack and repack 1) to make the format obvious 2) to catch errors
92 index,size,desc = line.rstrip().split(",")
93 # convert node to integer but be careful of leading 0 (ie 010 is actually
94 # 10 in decimal, it is not in octal)
95 index = int(index, 10)
96 desc = desc.rstrip()
97 node_map[index] = {'size': size, 'desc': desc}
98 # compute final nvp
99 nvp = dict()
100 for index in map:
101 size = 0
102 desc = ""
103 name = map[index]
104 if index in node_map:
105 size = node_map[index]["size"]
106 desc = node_map[index]["desc"]
107 nvp[name] = index
108 if not (name in g_nvp_desc):
109 g_nvp_desc[name] = set()
110 if len(desc) != 0:
111 g_nvp_desc[name].add(desc)
112 if not (name in g_nvp_size):
113 g_nvp_size[name] = set()
114 if size != 0:
115 g_nvp_size[name].add(size)
116 g_hash_nvp[hash] = nvp
117
118#
119# generate header
120#
121header_begin = \
122"""\
123/***************************************************************************
124 * __________ __ ___.
125 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
126 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
127 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
128 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \\
129 * \/ \/ \/ \/ \/
130 *
131 * Copyright (C) 2016 Amaury Pouly
132 *
133 * This program is free software; you can redistribute it and/or
134 * modify it under the terms of the GNU General Public License
135 * as published by the Free Software Foundation; either version 2
136 * of the License, or (at your option) any later version.
137 *
138 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
139 * KIND, either express or implied.
140 *
141 ****************************************************************************/
142#ifndef __NWZ_DB_H__
143#define __NWZ_DB_H__
144
145/** /!\ This file was automatically generated, DO NOT MODIFY IT DIRECTLY /!\ */
146
147/* List of all known NVP nodes */
148enum nwz_nvp_node_t
149{
150"""
151
152header_end = \
153"""\
154 NWZ_NVP_COUNT /* Number of nvp nodes */
155};
156
157/* Invalid NVP index */
158#define NWZ_NVP_INVALID -1 /* Non-existent entry */
159/* Number of models */
160#define NWZ_MODEL_COUNT %s
161/* Number of series */
162#define NWZ_SERIES_COUNT %s
163
164/* NVP node info */
165struct nwz_nvp_info_t
166{
167 const char *name; /* Sony's name: "bti" */
168 unsigned long size; /* Size in bytes */
169 const char *desc; /* Description: "bootloader image" */
170};
171
172/* NVP index map (nwz_nvp_node_t -> index) */
173typedef int nwz_nvp_index_t[NWZ_NVP_COUNT];
174
175/* Model info */
176struct nwz_model_info_t
177{
178 unsigned long mid; /* Model ID: first 4 bytes of the NVP mid entry */
179 const char *name; /* Human name: "NWZ-E463" */
180};
181
182/* Series info */
183struct nwz_series_info_t
184{
185 const char *codename; /* Rockbox codename: nwz-e460 */
186 const char *name; /* Human name: "NWZ-E460 Series" */
187 int mid_count; /* number of entries in mid_list */
188 unsigned long *mid; /* List of model IDs */
189 /* Pointer to a name -> index map, nonexistent entries map to NWZ_NVP_INVALID */
190 nwz_nvp_index_t *nvp_index;
191};
192
193/* List of all NVP entries, indexed by nwz_nvp_node_t */
194extern struct nwz_nvp_info_t nwz_nvp[NWZ_NVP_COUNT];
195/* List of all models, sorted by increasing values of model ID */
196extern struct nwz_model_info_t nwz_model[NWZ_MODEL_COUNT];
197/* List of all series */
198extern struct nwz_series_info_t nwz_series[NWZ_SERIES_COUNT];
199
200#endif /* __NWZ_DB_H__ */
201"""
202
203with open("nwz_db.h", "w") as fp:
204 fp.write(header_begin)
205 # generate list of all nvp nodes
206 for name in sorted(g_nvp_names):
207 # create comment to explain the meaning, gather several meaning together
Amaury Pouly3c3e1332017-01-04 16:26:07 +0100208 # if there are more than one (sorted to keep a stable order when we update)
Amaury Pouly44bb2852016-11-11 15:40:56 +0100209 explain = ""
Amaury Poulybe68b6a2017-01-07 17:32:47 +0100210 if name in g_nvp_desc:
211 explain = " | ".join(sorted(list(g_nvp_desc[name])))
Amaury Pouly44bb2852016-11-11 15:40:56 +0100212 # overwrite desc set with a single string for later
213 g_nvp_desc[name] = explain
214 fp.write(" NWZ_NVP_%s, /* %s */\n" % (name.upper(), explain))
215 fp.write(header_end % (len(g_models), len(g_series)))
216
217#
218# generate tables
219#
220impl_begin = \
221"""\
222/***************************************************************************
223 * __________ __ ___.
224 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
225 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
226 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
227 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \\
228 * \/ \/ \/ \/ \/
229 *
230 * Copyright (C) 2016 Amaury Pouly
231 *
232 * This program is free software; you can redistribute it and/or
233 * modify it under the terms of the GNU General Public License
234 * as published by the Free Software Foundation; either version 2
235 * of the License, or (at your option) any later version.
236 *
237 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
238 * KIND, either express or implied.
239 *
240 ****************************************************************************/
241
242/** /!\ This file was automatically generated, DO NOT MODIFY IT DIRECTLY /!\ */
243
244#include "nwz_db.h"
245
246struct nwz_model_info_t nwz_model[NWZ_MODEL_COUNT] =
247{
248"""
249
250def by_mid(model):
251 return model["mid"]
252
253def by_name(nvp_entry):
254 return nvp_entry["name"]
255
256def codename_to_c(codename):
257 return re.sub('[^a-zA-Z0-9]', '_', codename, 0)
258
259with open("nwz_db.c", "w") as fp:
260 fp.write(impl_begin)
261 # generate model list (sort by mid)
262 for model in sorted(g_models, key = by_mid):
263 fp.write(" { %s, \"%s\" },\n" % (hex(model["mid"]), model["name"]))
264 fp.write("};\n")
265 # generate nvps
Amaury Pouly3c3e1332017-01-04 16:26:07 +0100266 for hash in sorted(g_hash_nvp):
Amaury Pouly44bb2852016-11-11 15:40:56 +0100267 nvp = g_hash_nvp[hash]
268 fp.write("\nstatic int nvp_index_%s[NWZ_NVP_COUNT] =\n" % hash)
269 fp.write("{\n")
270 for name in sorted(g_nvp_names):
271 index = "NWZ_NVP_INVALID"
272 if name in nvp:
273 index = nvp[name]
274 fp.write(" [NWZ_NVP_%s] = %s,\n" % (name.upper(), index))
275 fp.write("};\n")
276 # generate nvp info
277 fp.write("\nstruct nwz_nvp_info_t nwz_nvp[NWZ_NVP_COUNT] =\n")
278 fp.write("{\n")
279 for name in sorted(g_nvp_names):
280 size = 0
281 if name in g_nvp_size:
282 size_set = g_nvp_size[name]
283 if len(size_set) == 0:
284 size = 0
285 elif len(size_set) == 1:
286 size = next(iter(size_set))
287 else:
288 print("Warning: nvp node \"%s\" has several possible sizes: %s"
289 % (name, size_set))
290 size = 0
291 desc = ""
292 if name in g_nvp_desc:
293 desc = g_nvp_desc[name]
294 fp.write(" [NWZ_NVP_%s] = { \"%s\", %s, \"%s\" },\n" % (name.upper(),
295 name, size, desc))
296 fp.write("};\n")
297 # generate list of models for each series
298 for series in g_series:
299 c_codename = codename_to_c(series["codename"])
300 list = [hex(mid) for mid in series["models"]]
301 limit = 3
302 c_list = ""
303 while len(list) != 0:
304 if len(list) <= limit:
305 c_list = c_list + ", ".join(list)
306 list = []
307 else:
308 c_list = c_list + ", ".join(list[:limit]) + ",\n "
309 list = list[limit:]
310 limit = 6
311 fp.write("\nstatic unsigned long models_%s[] = { %s };\n" % (c_codename, c_list))
312 # generate series list
313 fp.write("\nstruct nwz_series_info_t nwz_series[NWZ_SERIES_COUNT] =\n{\n")
314 for series in g_series:
315 name = series["name"]
316 codename = series["codename"]
317 c_codename = codename_to_c(codename)
318 nvp = "0"
319 if codename in g_nvp_hash:
320 nvp = "&nvp_index_%s" % g_nvp_hash[codename]
321 fp.write(" { \"%s\", \"%s\", %s, models_%s, %s },\n" % (codename,
322 name, len(series["models"]), c_codename, nvp))
323 fp.write("};\n")