A modern, network-enabled music player platform built on Rockbox technology.
rockboxd.tsiry-sandratraina.com
rust
deno
navidrome
airplay
libadwaita
zig
mpris
snapcast
mpd
rockbox
audio
subsonic
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2012 by Amaury Pouly
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20#include "soc_desc_v1.hpp"
21#include <stdio.h>
22#include <stdlib.h>
23#include <map>
24#include <cstring>
25
26using namespace soc_desc_v1;
27
28template< typename T >
29bool build_map(const char *type, const std::vector< T >& vec,
30 std::map< std::string, size_t >& map)
31{
32 for(size_t i = 0; i < vec.size(); i++)
33 {
34 if(map.find(vec[i].name) != map.end())
35 {
36 printf("soc has duplicate %s '%s'\n", type, vec[i].name.c_str());
37 return false;
38 }
39 map[vec[i].name] = i;
40 }
41 return true;
42}
43
44template< typename T >
45bool build_map(const char *type, const std::vector< T >& a, const std::vector< T >& b,
46 std::vector< std::pair< size_t, size_t > >& m)
47{
48 std::map< std::string, size_t > ma, mb;
49 if(!build_map(type, a, ma) || !build_map(type, b, mb))
50 return false;
51 std::map< std::string, size_t >::iterator it;
52 for(it = ma.begin(); it != ma.end(); ++it)
53 {
54 if(mb.find(it->first) == mb.end())
55 {
56 printf("%s '%s' exists in only one file\n", type, it->first.c_str());
57 return false;
58 }
59 m.push_back(std::make_pair(it->second, mb[it->first]));
60 }
61 for(it = mb.begin(); it != mb.end(); ++it)
62 {
63 if(ma.find(it->first) == ma.end())
64 {
65 printf("%s '%s' exists in only one file\n", type, it->first.c_str());
66 return false;
67 }
68 }
69 return true;
70}
71
72bool compare_value(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& reg,
73 const soc_reg_field_t& field, const soc_reg_field_value_t& a, const soc_reg_field_value_t& b)
74{
75 if(a.value != b.value)
76 {
77 printf("register field value '%s.%s.%s.%s.%s' have different values\n", soc.name.c_str(),
78 dev.name.c_str(), reg.name.c_str(), field.name.c_str(), a.name.c_str());
79 return false;
80 }
81 if(a.desc != b.desc)
82 {
83 printf("register field value '%s.%s.%s.%s.%s' have different descriptions\n", soc.name.c_str(),
84 dev.name.c_str(), reg.name.c_str(), field.name.c_str(), a.name.c_str());
85 return false;
86 }
87 return true;
88}
89
90bool compare_field(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& reg,
91 const soc_reg_field_t& a, const soc_reg_field_t& b)
92{
93 if(a.first_bit != b.first_bit || a.last_bit != b.last_bit)
94 {
95 printf("register address '%s.%s.%s.%s' have different bit ranges\n", soc.name.c_str(),
96 dev.name.c_str(), reg.name.c_str(), a.name.c_str());
97 return false;
98 }
99 if(a.desc != b.desc)
100 {
101 printf("register address '%s.%s.%s.%s' have different descriptions\n", soc.name.c_str(),
102 dev.name.c_str(), reg.name.c_str(), a.name.c_str());
103 return false;
104 }
105 /* values */
106 std::vector< std::pair< size_t, size_t > > map;
107 if(!build_map("field value", a.value, b.value, map))
108 return false;
109 for(size_t i = 0; i < map.size(); i++)
110 if(!compare_value(soc, dev, reg, a, a.value[map[i].first], b.value[map[i].second]))
111 return false;
112 return true;
113}
114
115bool compare_reg_addr(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& reg,
116 const soc_reg_addr_t& a, const soc_reg_addr_t& b)
117{
118 if(a.addr != b.addr)
119 {
120 printf("register address '%s.%s.%s.%s' have different values\n", soc.name.c_str(),
121 dev.name.c_str(), reg.name.c_str(), a.name.c_str());
122 return false;
123 }
124 else
125 return true;
126}
127
128bool compare_reg(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& a,
129 const soc_reg_t& b)
130{
131 if(a.desc != b.desc)
132 {
133 printf("register '%s.%s.%s' have different descriptions\n", soc.name.c_str(),
134 dev.name.c_str(), a.name.c_str());
135 return false;
136 }
137 if(a.flags != b.flags)
138 {
139 printf("device '%s.%s.%s' have different flags\n", soc.name.c_str(),
140 dev.name.c_str(), a.name.c_str());
141 return false;
142 }
143 if(a.formula.type != b.formula.type)
144 {
145 printf("device '%s.%s.%s' have different formula types\n", soc.name.c_str(),
146 dev.name.c_str(), a.name.c_str());
147 return false;
148 }
149 if(a.formula.string != b.formula.string)
150 {
151 printf("device '%s.%s.%s' have different formula string\n", soc.name.c_str(),
152 dev.name.c_str(), a.name.c_str());
153 return false;
154 }
155 /* addresses */
156 std::vector< std::pair< size_t, size_t > > map;
157 if(!build_map("register address", a.addr, b.addr, map))
158 return false;
159 for(size_t i = 0; i < map.size(); i++)
160 if(!compare_reg_addr(soc, dev, a, a.addr[map[i].first], b.addr[map[i].second]))
161 return false;
162 /* field */
163 map.clear();
164 if(!build_map("field", a.field, b.field, map))
165 return false;
166 for(size_t i = 0; i < map.size(); i++)
167 if(!compare_field(soc, dev, a, a.field[map[i].first], b.field[map[i].second]))
168 return false;
169 return true;
170}
171
172bool compare_dev_addr(const soc_t& soc, const soc_dev_t& dev, const soc_dev_addr_t& a,
173 const soc_dev_addr_t& b)
174{
175 if(a.addr != b.addr)
176 {
177 printf("device address '%s.%s.%s' have different values\n", soc.name.c_str(),
178 dev.name.c_str(), a.name.c_str());
179 return false;
180 }
181 else
182 return true;
183}
184
185bool compare_dev(const soc_t& soc, const soc_dev_t& a, const soc_dev_t& b)
186{
187 if(a.long_name != b.long_name)
188 {
189 printf("device '%s.%s' have different long names\n", soc.name.c_str(),
190 a.name.c_str());
191 return false;
192 }
193 if(a.desc != b.desc)
194 {
195 printf("device '%s.%s' have different descriptions\n", soc.name.c_str(),
196 a.name.c_str());
197 return false;
198 }
199 if(a.version != b.version)
200 {
201 printf("device '%s.%s' have different versions\n", soc.name.c_str(),
202 a.name.c_str());
203 return false;
204 }
205 /* addresses */
206 std::vector< std::pair< size_t, size_t > > map;
207 if(!build_map("device address", a.addr, b.addr, map))
208 return false;
209 for(size_t i = 0; i < map.size(); i++)
210 if(!compare_dev_addr(soc, a, a.addr[map[i].first], b.addr[map[i].second]))
211 return false;
212 /* reg */
213 map.clear();
214 if(!build_map("register", a.reg, b.reg, map))
215 return false;
216 for(size_t i = 0; i < map.size(); i++)
217 if(!compare_reg(soc, a, a.reg[map[i].first], b.reg[map[i].second]))
218 return false;
219 return true;
220}
221
222bool compare_soc(const soc_t& a, const soc_t& b)
223{
224 if(a.name != b.name)
225 {
226 return printf("soc have different names\n");
227 return false;
228 }
229 if(a.desc != b.desc)
230 {
231 printf("soc '%s' have different descriptions\n", a.name.c_str());
232 return false;
233 }
234 std::vector< std::pair< size_t, size_t > > map;
235 if(!build_map("device", a.dev, b.dev, map))
236 return false;
237 for(size_t i = 0; i< map.size(); i++)
238 if(!compare_dev(a, a.dev[map[i].first], b.dev[map[i].second]))
239 return false;
240 return true;
241}
242
243int do_compare(int argc, char **argv)
244{
245 if(argc != 2)
246 return printf("compare mode expects two arguments\n");
247 soc_t soc[2];
248 if(!parse_xml(argv[0], soc[0]))
249 return printf("cannot read file '%s'\n", argv[0]);
250 if(!parse_xml(argv[1], soc[1]))
251 return printf("cannot read file '%s'\n", argv[1]);
252 if(compare_soc(soc[0], soc[1]))
253 printf("Files are identical.\n");
254 return 0;
255}
256
257int do_write(int argc, char **argv)
258{
259 if(argc != 2)
260 return printf("write mode expects two arguments\n");
261 soc_t soc;
262 if(!parse_xml(argv[0], soc))
263 return printf("cannot read file '%s'\n", argv[0]);
264 if(!produce_xml(argv[1], soc))
265 return printf("cannot write file '%s'\n", argv[1]);
266 return 0;
267}
268
269int do_check(int argc, char **argv)
270{
271 for(int i = 0; i < argc; i++)
272 {
273 soc_t soc;
274 if(!parse_xml(argv[i], soc))
275 {
276 printf("cannot read file '%s'\n", argv[i]);
277 continue;
278 }
279 printf("[%s]\n", argv[i]);
280 std::vector< soc_error_t > errs = soc.errors(true);
281 for(size_t i = 0; i < errs.size(); i++)
282 {
283 const soc_error_t& e = errs[i];
284 switch(e.level)
285 {
286 case SOC_ERROR_WARNING: printf("[WARN ] "); break;
287 case SOC_ERROR_FATAL: printf("[FATAL] "); break;
288 default: printf("[ UNK ] "); break;
289 }
290 printf("%s: %s\n", e.location.c_str(), e.message.c_str());
291 }
292 }
293 return 0;
294}
295
296int do_eval(int argc, char **argv)
297{
298 std::map< std::string, soc_word_t > map;
299 for(int i = 0; i < argc; i++)
300 {
301 std::string error;
302 std::string formula(argv[i]);
303 soc_word_t result;
304 if(strcmp(argv[i], "--var") == 0)
305 {
306 if(i + 1 >= argc)
307 break;
308 i++;
309 std::string str(argv[i]);
310 size_t pos = str.find('=');
311 if(pos == std::string::npos)
312 {
313 printf("invalid variable string '%s'\n", str.c_str());
314 continue;
315 }
316 std::string name = str.substr(0, pos);
317 std::string val = str.substr(pos + 1);
318 char *end;
319 soc_word_t v = strtoul(val.c_str(), &end, 0);
320 if(*end)
321 {
322 printf("invalid variable string '%s'\n", str.c_str());
323 continue;
324 }
325 printf("%s = %#lx\n", name.c_str(), (unsigned long)v);
326 map[name] = v;
327 continue;
328 }
329 if(!evaluate_formula(formula, map, result, error))
330 printf("error: %s\n", error.c_str());
331 else
332 printf("result: %lu (%#lx)\n", (unsigned long)result, (unsigned long)result);
333 }
334 return 0;
335}
336
337void usage()
338{
339 printf("usage: tester <mode> [options]\n");
340 printf("modes:\n");
341 printf(" compare <desc file> <desc file>\n");
342 printf(" write <read file> <write file>\n");
343 printf(" check <files...>\n");
344 printf(" eval [<formula>|--var <name>=<val>]...\n");
345 exit(1);
346}
347
348int main(int argc, char **argv)
349{
350 if(argc < 2)
351 usage();
352 std::string mode = argv[1];
353 if(mode == "compare")
354 return do_compare(argc - 2, argv + 2);
355 else if(mode == "write")
356 return do_write(argc - 2, argv + 2);
357 else if(mode == "check")
358 return do_check(argc - 2, argv + 2);
359 else if(mode == "eval")
360 return do_eval(argc - 2, argv + 2);
361 else
362 usage();
363 return 0;
364}