Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
ConfigRenderer.hxx
Go to the documentation of this file.
1
35#ifndef _OPENLCB_CONFIGRENDERER_HXX_
36#define _OPENLCB_CONFIGRENDERER_HXX_
37
38#include <climits>
39#include <string>
40#include <stdint.h>
41
45
46namespace openlcb
47{
48
51{
52 DECLARE_OPTIONALARG(Name, name, const char *, 0, nullptr);
53 DECLARE_OPTIONALARG(Description, description, const char *, 1, nullptr);
54 DECLARE_OPTIONALARG(MapValues, mapvalues, const char *, 2, nullptr);
55 DECLARE_OPTIONALARG(Hints, hints, const char *, 3, nullptr);
56 DECLARE_OPTIONALARG(SkipInit, skip_init, int, 15, 0);
57 DECLARE_OPTIONALARG(Offset, offset, int, 10, 0);
58 using Base = OptionalArg<AtomConfigDefs, Name, Description, MapValues,
59 Hints, SkipInit, Offset>;
60};
61
65{
66public:
68
70 DEFINE_OPTIONALARG(Name, name, const char *);
73 DEFINE_OPTIONALARG(Description, description, const char *);
75 DEFINE_OPTIONALARG(MapValues, mapvalues, const char *);
77 DEFINE_OPTIONALARG(Hints, hints, const char *);
80 DEFINE_OPTIONALARG(SkipInit, skip_init, int);
83 DEFINE_OPTIONALARG(Offset, offset, int);
84
85
86 void render_cdi(std::string *r) const
87 {
88 if (name())
89 {
90 *r += StringPrintf("<name>%s</name>\n", name());
91 }
92 if (description())
93 {
94 *r +=
95 StringPrintf("<description>%s</description>\n", description());
96 }
97 if (mapvalues())
98 {
99 *r += StringPrintf("<map>%s</map>\n", mapvalues());
100 }
101 if (hints())
102 {
103 *r += StringPrintf("<hints>%s</hints>\n", hints());
104 }
105 }
106};
107
110{
111public:
112 enum
113 {
114 SKIP_SIZE = 0xffffffff,
115 };
116
118
119 constexpr AtomConfigRenderer(const char *tag, unsigned size)
120 : tag_(tag)
121 , size_(size)
122 {
123 }
124
125 template <typename... Args> void render_cdi(string *s, Args... args) const
126 {
127 *s += StringPrintf("<%s", tag_);
128 if (size_ != SKIP_SIZE)
129 {
130 *s += StringPrintf(" size=\'%u\'", size_);
131 }
132 int ofs = AtomConfigOptions(args...).offset();
133 if (ofs != 0)
134 {
135 *s += StringPrintf(" offset=\'%d\'", ofs);
136 }
137 *s += ">\n";
138 AtomConfigOptions(args...).render_cdi(s);
139 *s += StringPrintf("</%s>\n", tag_);
140 }
141
142private:
144 const char *tag_;
146 unsigned size_;
147};
148
151{
152 // This is needed for inheriting declarations.
153 using AtomConfigDefs::check_arguments_are_valid;
154 DECLARE_OPTIONALARG(Min, minvalue, int, 6, INT_MAX);
155 DECLARE_OPTIONALARG(Max, maxvalue, int, 7, INT_MAX);
156 DECLARE_OPTIONALARG(Default, defaultvalue, int, 8, INT_MAX);
157 using Base = OptionalArg<NumericConfigDefs, Name, Description, MapValues,
158 Hints, Min, Max, Default, SkipInit, Offset>;
159};
160
163{
164public:
167
169 DEFINE_OPTIONALARG(Name, name, const char *);
172 DEFINE_OPTIONALARG(Description, description, const char *);
174 DEFINE_OPTIONALARG(MapValues, mapvalues, const char *);
176 DEFINE_OPTIONALARG(Hints, hints, const char *);
177 DEFINE_OPTIONALARG(Min, minvalue, int);
178 DEFINE_OPTIONALARG(Max, maxvalue, int);
179 DEFINE_OPTIONALARG(Default, defaultvalue, int);
180 DEFINE_OPTIONALARG(SkipInit, skip_init, int);
181 DEFINE_OPTIONALARG(Offset, offset, int);
182
183 void render_cdi(std::string *r) const
184 {
185 if (name())
186 {
187 *r += StringPrintf("<name>%s</name>\n", name());
188 }
189 if (description())
190 {
191 *r +=
192 StringPrintf("<description>%s</description>\n", description());
193 }
194 if (hints())
195 {
196 *r += StringPrintf("<hints>%s</hints>\n", hints());
197 }
198 if (minvalue() != INT_MAX)
199 {
200 *r += StringPrintf("<min>%d</min>\n", minvalue());
201 }
202 if (maxvalue() != INT_MAX)
203 {
204 *r += StringPrintf("<max>%d</max>\n", maxvalue());
205 }
206 if (defaultvalue() != INT_MAX)
207 {
208 *r += StringPrintf("<default>%d</default>\n", defaultvalue());
209 }
210 if (mapvalues())
211 {
212 *r += StringPrintf("<map>%s</map>\n", mapvalues());
213 }
214 }
215
216 int clip(int value) {
217 if (has_minvalue() && (value < minvalue())) {
218 value = minvalue();
219 }
220 if (has_maxvalue() && (value > maxvalue())) {
221 value = maxvalue();
222 }
223 return value;
224 }
225};
226
229{
230public:
231 enum
232 {
233 SKIP_SIZE = 0xffffffff,
234 };
235
237
238 constexpr NumericConfigRenderer(const char *tag, unsigned size)
239 : tag_(tag)
240 , size_(size)
241 {
242 }
243
244 template <typename... Args> void render_cdi(string *s, Args... args) const
245 {
246 *s += StringPrintf("<%s", tag_);
247 if (size_ != SKIP_SIZE)
248 {
249 *s += StringPrintf(" size=\'%u\'", size_);
250 }
251 int ofs = NumericConfigOptions(args...).offset();
252 if (ofs != 0)
253 {
254 *s += StringPrintf(" offset=\'%d\'", ofs);
255 }
256 *s += ">\n";
257 NumericConfigOptions(args...).render_cdi(s);
258 *s += StringPrintf("</%s>\n", tag_);
259 }
260
261private:
263 const char *tag_;
265 unsigned size_;
266};
267
272{
273 // This is needed for inheriting declarations.
274 using AtomConfigDefs::check_arguments_are_valid;
275 DECLARE_OPTIONALARG(Segment, segment, int, 11, -1);
276 DECLARE_OPTIONALARG(RepName, repname, const char*, 12, nullptr);
277 DECLARE_OPTIONALARG(FixedSize, fixed_size, unsigned, 13, 0);
278 DECLARE_OPTIONALARG(Hidden, hidden, int, 14, 0);
279 // 15 is used for SkipInit
280 DECLARE_OPTIONALARG(LinkRef, linkref, const char *, 16, nullptr);
281 DECLARE_OPTIONALARG(LinkText, linktext, const char *, 17, nullptr);
282 using Base = OptionalArg<GroupConfigDefs, Name, Description, Segment,
283 Hints, LinkRef, LinkText, Offset, RepName,
284 FixedSize, Hidden>;
285};
286
289{
290public:
292
293 DEFINE_OPTIONALARG(Name, name, const char *);
296 DEFINE_OPTIONALARG(Description, description, const char *);
297
300 DEFINE_OPTIONALARG(Offset, offset, int);
301
304 DEFINE_OPTIONALARG(Segment, segment, int);
305
308 DEFINE_OPTIONALARG(RepName, repname, const char*);
309
313 DEFINE_OPTIONALARG(FixedSize, fixed_size, int);
314
318 DEFINE_OPTIONALARG(Hidden, hidden, int);
319
321 DEFINE_OPTIONALARG(Hints, hints, const char *);
322
324 DEFINE_OPTIONALARG(LinkRef, linkref, const char *);
325
327 DEFINE_OPTIONALARG(LinkText, linktext, const char *);
328
332 /*struct MainCdi : public Segment
333 {
334 constexpr MainCdi()
335 : Segment(-2)
336 {
337 }
338 };*/
339
340 constexpr int skip_init() const
341 {
342 return 0;
343 }
344
350 constexpr bool is_cdi() const
351 {
352 return segment() == -2;
353 }
354
358 constexpr bool is_segment() const
359 {
360 return segment() >= 0;
361 }
362
367 constexpr unsigned get_segment_offset() const
368 {
369 return offset() == INT_MAX ? 0 : offset();
370 }
371
372 void render_cdi(std::string *r) const
373 {
374 if (name())
375 {
376 *r += StringPrintf("<name>%s</name>\n", name());
377 }
378 if (description())
379 {
380 *r +=
381 StringPrintf("<description>%s</description>\n", description());
382 }
383 if (hints())
384 {
385 *r += StringPrintf("<hints>%s</hints>\n", hints());
386 }
387 if (repname())
388 {
389 *r +=
390 StringPrintf("<repname>%s</repname>\n", repname());
391 }
392 if (linkref())
393 {
394 *r +=
395 StringPrintf("<link ref=\"%s\">%s</link>\n", linkref(),
396 has_linktext() ? linktext() : linkref());
397 }
398 }
399};
400
403{
404public:
405 enum
406 {
407 SKIP_SIZE = 0xffffffff,
408 };
409
411
412 constexpr EmptyGroupConfigRenderer(int size)
413 : size_(size)
414 {
415 }
416
417 template <typename... Args> void render_cdi(string *s, Args... args) const
418 {
419 *s += StringPrintf("<group offset='%d'/>\n", size_);
420 }
421
422private:
424 int size_;
425};
426
429template <class Body> class GroupConfigRenderer
430{
431
432public:
434
435 constexpr GroupConfigRenderer(unsigned replication, Body body)
436 : replication_(replication)
437 , body_(body)
438 {
439 }
440
441 template <typename... Args> void render_cdi(string *s, Args... args)
442 {
443 GroupConfigOptions opts(args..., Body::group_opts());
444 if (opts.hidden())
445 {
446 if (!opts.is_segment())
447 {
449 .render_cdi(s);
450 }
451 return;
452 }
453 const char *tag = nullptr;
454 *s += "<";
455 if (opts.is_cdi())
456 {
457 *s += "?xml version=\"1.0\" encoding=\"utf-8\"?>\n<";
458 tag = "cdi";
459 *s += tag;
460 *s += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
461 "xsi:noNamespaceSchemaLocation=\"http://openlcb.org/schema/"
462 "cdi/1/1/cdi.xsd\"";
463 HASSERT(replication_ == 1);
464 HASSERT(opts.name() == nullptr && opts.description() == nullptr);
465 }
466 else if (opts.segment() == -1)
467 {
468 // Regular group
469 tag = "group";
470 *s += tag;
471 if (replication_ != 1)
472 {
473 *s += StringPrintf(" replication='%u'", replication_);
474 }
475 int ofs = opts.offset();
476 if (ofs != 0)
477 {
478 *s += StringPrintf(" offset=\'%d\'", ofs);
479 }
480 }
481 else
482 {
483 // Segment inside CDI.
484 tag = "segment";
485 *s += tag;
486 *s += StringPrintf(" space='%d'", opts.segment());
487 if (opts.get_segment_offset() != 0)
488 {
489 *s += StringPrintf(" origin='%d'", opts.get_segment_offset());
490 }
491 HASSERT(replication_ == 1);
492 }
493 *s += ">\n";
494 opts.render_cdi(s);
495 body_.render_content_cdi(s);
496 if (opts.fixed_size() && (body_.end_buffer_length() > 0)) {
497 *s += StringPrintf(
498 "<group offset='%u'/>\n", body_.end_buffer_length());
499 }
500 *s += StringPrintf("</%s>\n", tag);
501 }
502
503private:
505 unsigned replication_;
508 Body body_;
509};
510
512
515{
516 DECLARE_OPTIONALARG(Manufacturer, manufacturer, const char *, 0, nullptr);
517 DECLARE_OPTIONALARG(Model, model, const char *, 1, nullptr);
518 DECLARE_OPTIONALARG(HwVersion, hardware_version, const char *, 2, nullptr);
519 DECLARE_OPTIONALARG(SwVersion, software_version, const char *, 3, nullptr);
520 // NOTE: the unique index for LinkRef and LinkText must match the values
521 // used in GroupConfigDefs otherwise complile_cdi will enter recursive loop
522 // and segfault.
523 DECLARE_OPTIONALARG(LinkRef, linkref, const char *, 16, nullptr);
524 DECLARE_OPTIONALARG(LinkText, linktext, const char *, 17, nullptr);
525 using Base = OptionalArg<IdentificationConfigDefs, Manufacturer, Model,
526 HwVersion, SwVersion, LinkRef, LinkText>;
527};
528
532{
533public:
536
537 DEFINE_OPTIONALARG(Manufacturer, manufacturer, const char *);
538 DEFINE_OPTIONALARG(Model, model, const char *);
539 DEFINE_OPTIONALARG(HwVersion, hardware_version, const char *);
540 DEFINE_OPTIONALARG(SwVersion, software_version, const char *);
541 DEFINE_OPTIONALARG(LinkRef, linkref, const char *);
542 DEFINE_OPTIONALARG(LinkText, linktext, const char *);
543
544 constexpr int skip_init() const
545 {
546 return 0;
547 }
548
549 constexpr int offset() const
550 {
551 return 0;
552 }
553};
554
557{
558public:
560
561 constexpr IdentificationRenderer()
562 {
563 }
564
565 static void render_tag(const char *tag, const char *value, string *s)
566 {
567 *s += StringPrintf("<%s>%s</%s>\n", tag, value, tag);
568 }
569
570 static const char *alt(const char *opt, const char *def)
571 {
572 if (opt)
573 return opt;
574 return def;
575 }
576
577 template <typename... Args> void render_cdi(string *s, Args... args) const
578 {
579 IdentificationConfigOptions opts(args...);
581 *s += "<identification>\n";
582 render_tag("manufacturer",
583 alt(opts.manufacturer(), SNIP_STATIC_DATA.manufacturer_name), s);
584 render_tag("model", alt(opts.model(), SNIP_STATIC_DATA.model_name), s);
585 render_tag("hardwareVersion",
586 alt(opts.hardware_version(), SNIP_STATIC_DATA.hardware_version), s);
587 render_tag("softwareVersion",
588 alt(opts.software_version(), SNIP_STATIC_DATA.software_version), s);
589 if (opts.linkref())
590 {
591 *s +=
592 StringPrintf("<link ref=\"%s\">%s</link>\n", opts.linkref(),
593 alt(opts.linktext(), opts.linkref()));
594 }
595 *s += "</identification>\n";
596 }
597};
598
601{
602public:
603 constexpr AcdiRenderer()
604 {
605 }
606
608
609 void render_cdi(string *s) const
610 {
611 s->append("<acdi/>\n");
612 }
613};
614
615} // namespace openlcb
616
617#endif // _OPENLCB_CONFIGRENDERER_HXX_
#define DEFINE_OPTIONALARG(SpecName, function_name, DataType)
Use this macro in the final optionalargs structure.
#define DECLARE_OPTIONALARG(SpecName, function_name, DataType, N, DEF)
Use this macro in the Defs structure of an optional args instance to add an optional argument.
Declares that a recursive class template is coming.
Helper class for rendering the "<acdi>" tag.
Configuration implementation class for CDI Atom elements (strings, events and numbers).
DEFINE_OPTIONALARG(Name, name, const char *)
Represent the value enclosed in the "<name>" tag of the data element.
DEFINE_OPTIONALARG(MapValues, mapvalues, const char *)
Represent the value enclosed in the "<map>" tag of the data element.
DEFINE_OPTIONALARG(SkipInit, skip_init, int)
When set to true, the event initializers will be skipped in this event or group.
DEFINE_OPTIONALARG(Hints, hints, const char *)
Represent the value enclosed in the "<hints>" tag of the data element.
DEFINE_OPTIONALARG(Offset, offset, int)
Represents the 'offset' attribute for groups and elements and the 'origin' attribute for segments.
DEFINE_OPTIONALARG(Description, description, const char *)
Represent the value enclosed in the "<description>" tag of the data element.
Helper class for rendering an atom data element into the cdi.xml.
const char * tag_
XML tag for this atom.
unsigned size_
The size attribute of the configuration atom.
Helper class for rendering an empty group of a given size into the cdi.xml.
int size_
The number of bytes this group has to skip.
Implementation class for the condifuration options of a CDI group element.
DEFINE_OPTIONALARG(Hidden, hidden, int)
If non-zero, the group contents will not be rendered in the CDI, effectively hiding hte settings from...
DEFINE_OPTIONALARG(Hints, hints, const char *)
Represent the value enclosed in the <hints> tag of the data element.
DEFINE_OPTIONALARG(LinkRef, linkref, const char *)
Represent the <link ref=..>> value.
constexpr bool is_segment() const
constexpr unsigned get_segment_offset() const
constexpr bool is_cdi() const
DEFINE_OPTIONALARG(Description, description, const char *)
Represent the value enclosed in the tag of the data element.
DEFINE_OPTIONALARG(LinkText, linktext, const char *)
Represent the value enclosed in the <link> tag of the data element.
DEFINE_OPTIONALARG(FixedSize, fixed_size, int)
Specifies that the size of this group should be fixed to this many bytes, even if the contents are sm...
DEFINE_OPTIONALARG(Offset, offset, int)
Represents the 'offset' attribute for groups and the 'origin' attribute for segments.
DEFINE_OPTIONALARG(RepName, repname, const char *)
Specifies for the UI what the repetitions of this group should be called.
DEFINE_OPTIONALARG(Segment, segment, int)
Declares that the group is a segment (and thus may be used in the toplevel CDI.
constexpr int skip_init() const
Declares that this group is a toplevel CDI.
Helper class for rendering the cdi.xml of groups, segments and the toplevel CDI node.
unsigned replication_
For regular groups, the count of replicas.
Body body_
Object representing the contents of this group.
Configuration implementation options for rendering CDI (identification) data elements.
Helper class for rendering the "<identification>" tag.
Definitions for the options for numeric CDI entries.
DEFINE_OPTIONALARG(Description, description, const char *)
Represent the value enclosed in the tag of the data element.
DEFINE_OPTIONALARG(Hints, hints, const char *)
Represent the value enclosed in the <hints> tag of the data element.
DEFINE_OPTIONALARG(MapValues, mapvalues, const char *)
Represent the value enclosed in the <map> tag of the data element.
DEFINE_OPTIONALARG(Name, name, const char *)
Represent the value enclosed in the "<name>" tag of the data element.
Helper class for rendering a numeric data element into the cdi.xml.
unsigned size_
The size attribute of the configuration atom.
const char * tag_
XML tag for this atom.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
#define INHERIT_CONSTEXPR_CONSTRUCTOR(CURRENT_CLASS, BASE_CLASS)
Adds a constexpr constructor to the current class that proxies every argument to the base constructor...
Definition macros.h:205
const SimpleNodeStaticValues SNIP_STATIC_DATA
This static data will be exported as the first block of SNIP.
Configuration options for rendering CDI (atom) data elements.
Configuration options for the CDI group element, as well as representing and distinguishing alternate...
Configuration options for rendering CDI (identification) data elements.
Declarations for the options for numeric CDI entries.
Structure representing the layout of the memory space for Simple Node Identification manufacturer-spe...