1 /*
2 * ebusd - daemon for communication with eBUS heating systems.
3 * Copyright (C) 2014-2021 John Baier <ebusd@ebusd.eu>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include "lib/ebus/datatype.h"
24 #include <math.h>
25 #include <iostream>
26 #include <sstream>
27 #include <iomanip>
28 #include <vector>
29 #include <cstring>
30 #ifdef HAVE_CONTRIB
31 # include "lib/ebus/contrib/contrib.h"
32 #endif
33
34 namespace ebusd {
35
36 using std::dec;
37 using std::hex;
38 using std::fixed;
39 using std::setfill;
40 using std::setprecision;
41 using std::setw;
42 using std::endl;
43
44
dump(OutputFormat outputFormat,size_t length,bool appendDivisor,ostream * output) const45 bool DataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const {
46 if (outputFormat & OF_JSON) {
47 *output << "\"type\": \"" << m_id << "\", \"isbits\": "
48 << (getBitCount() < 8 ? "true" : "false");
49 if (outputFormat & OF_ALL_ATTRS) {
50 *output << ", \"isadjustable\": " << (isAdjustableLength() ? "true" : "false");
51 *output << ", \"isignored\": " << (isIgnored() ? "true" : "false");
52 }
53 *output << ", \"length\": ";
54 if (isAdjustableLength() && length == REMAIN_LEN) {
55 *output << "-1";
56 } else {
57 *output << static_cast<unsigned>(length);
58 }
59 } else {
60 *output << m_id;
61 if (isAdjustableLength()) {
62 *output << LENGTH_SEPARATOR;
63 if (length == REMAIN_LEN) {
64 *output << "*";
65 } else {
66 *output << static_cast<unsigned>(length);
67 }
68 }
69 if (appendDivisor) {
70 *output << FIELD_SEPARATOR;
71 }
72 }
73 return false;
74 }
75
76
dump(OutputFormat outputFormat,size_t length,bool appendDivisor,ostream * output) const77 bool StringDataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const {
78 DataType::dump(outputFormat, length, appendDivisor, output);
79 if ((outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) {
80 *output << ", \"result\": \"" << (isIgnored() ? "void" : "string") << "\"";
81 }
82 return false;
83 }
84
readRawValue(size_t,size_t,const SymbolString &,unsigned int *) const85 result_t StringDataType::readRawValue(size_t, size_t, const SymbolString&, unsigned int*) const {
86 return RESULT_EMPTY;
87 }
88
readSymbols(size_t offset,size_t length,const SymbolString & input,OutputFormat outputFormat,ostream * output) const89 result_t StringDataType::readSymbols(size_t offset, size_t length, const SymbolString& input,
90 OutputFormat outputFormat, ostream* output) const {
91 size_t start = 0, count = length;
92 int incr = 1;
93 symbol_t symbol;
94 bool terminated = false;
95 if (count == REMAIN_LEN && input.getDataSize() > offset) {
96 count = input.getDataSize() - offset;
97 } else if (offset + count > input.getDataSize()) {
98 return RESULT_ERR_INVALID_POS;
99 }
100 if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
101 start = length - 1;
102 incr = -1;
103 }
104
105 if (outputFormat & OF_JSON) {
106 *output << '"';
107 }
108 *output << setfill('0') << (m_isHex ? hex : dec);
109 for (size_t index = start, i = 0; i < count; index += incr, i++) {
110 symbol = input.dataAt(offset + index);
111 if (m_isHex) {
112 if (i > 0) {
113 *output << ' ';
114 }
115 *output << setw(2) << static_cast<unsigned>(symbol);
116 } else {
117 if (symbol == 0x00) {
118 terminated = true;
119 } else if (!terminated) {
120 if (symbol < 0x20) {
121 symbol = (symbol_t)m_replacement;
122 } else if (!isprint(symbol)) {
123 symbol = '?';
124 } else if (outputFormat & OF_JSON) {
125 if (symbol == '"' || symbol == '\\') {
126 *output << '\\'; // escape
127 }
128 }
129 *output << static_cast<char>(symbol);
130 }
131 }
132 }
133 if (outputFormat & OF_JSON) {
134 *output << '"';
135 }
136 return RESULT_OK;
137 }
138
writeSymbols(size_t offset,size_t length,istringstream * input,SymbolString * output,size_t * usedLength) const139 result_t StringDataType::writeSymbols(size_t offset, size_t length, istringstream* input,
140 SymbolString* output, size_t* usedLength) const {
141 size_t start = 0, count = length;
142 bool remainder = count == REMAIN_LEN && hasFlag(ADJ);
143 int incr = 1;
144 unsigned int value = 0;
145 string token;
146
147 if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
148 start = length - 1;
149 incr = -1;
150 }
151 if (isIgnored() && !hasFlag(REQ)) {
152 if (remainder) {
153 count = 1;
154 }
155 for (size_t index = start, i = 0; i < count; index += incr, i++) {
156 output->dataAt(offset + index) = (symbol_t)m_replacement; // fill up with replacement
157 }
158 if (usedLength != nullptr) {
159 *usedLength = count;
160 }
161 return RESULT_OK;
162 }
163 result_t result;
164 size_t i = 0, index;
165 for (index = start; i < count; index += incr, i++) {
166 if (m_isHex) {
167 while (!input->eof() && input->peek() == ' ') {
168 input->get();
169 }
170 if (input->eof()) { // no more digits
171 value = m_replacement; // fill up with replacement
172 } else {
173 token.clear();
174 token.push_back((symbol_t)input->get());
175 if (input->eof()) {
176 return RESULT_ERR_INVALID_NUM; // too short hex value
177 }
178 token.push_back((symbol_t)input->get());
179 if (input->eof()) {
180 return RESULT_ERR_INVALID_NUM; // too short hex value
181 }
182 value = parseInt(token.c_str(), 16, 0, 0xff, &result);
183 if (result != RESULT_OK) {
184 return result; // invalid hex value
185 }
186 }
187 } else {
188 if (input->eof()) {
189 value = m_replacement;
190 } else {
191 value = input->get();
192 if (input->eof() || value < 0x20) {
193 value = m_replacement;
194 }
195 }
196 }
197 if (remainder && input->eof() && i > 0) {
198 if (value == 0x00 && !m_isHex) {
199 output->dataAt(offset + index) = 0;
200 index += incr;
201 }
202 break;
203 }
204 if (value > 0xff) {
205 return RESULT_ERR_OUT_OF_RANGE; // value out of range
206 }
207 output->dataAt(offset + index) = (symbol_t)value;
208 }
209
210 if (!remainder && i < count) {
211 return RESULT_ERR_EOF; // input too short
212 }
213 if (usedLength != nullptr) {
214 *usedLength = (index-start)*incr;
215 }
216 return RESULT_OK;
217 }
218
219
dump(OutputFormat outputFormat,size_t length,bool appendDivisor,ostream * output) const220 bool DateTimeDataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const {
221 DataType::dump(outputFormat, length, appendDivisor, output);
222 if ((outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) {
223 *output << ", \"result\": \"" << (hasDate() ? hasTime() ? "datetime" : "date" : "time") << "\"";
224 }
225 return false;
226 }
227
readRawValue(size_t,size_t,const SymbolString &,unsigned int *) const228 result_t DateTimeDataType::readRawValue(size_t, size_t, const SymbolString&, unsigned int*) const {
229 return RESULT_EMPTY;
230 }
231
readSymbols(size_t offset,size_t length,const SymbolString & input,OutputFormat outputFormat,ostream * output) const232 result_t DateTimeDataType::readSymbols(size_t offset, size_t length, const SymbolString& input,
233 OutputFormat outputFormat, ostream* output) const {
234 size_t start = 0, count = length;
235 int incr = 1;
236 symbol_t symbol, last = 0, hour = 0;
237 unsigned long minutes = 0;
238 if (count == REMAIN_LEN && input.getDataSize() > offset) {
239 count = input.getDataSize() - offset;
240 } else if (offset + count > input.getDataSize()) {
241 return RESULT_ERR_INVALID_POS;
242 }
243 if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
244 start = length - 1;
245 incr = -1;
246 }
247
248 if (outputFormat & OF_JSON) {
249 *output << '"';
250 }
251 int type = (m_hasDate?2:0) | (m_hasTime?1:0);
252 for (size_t index = start, i = 0; i < count; index += incr, i++) {
253 if (length == 4 && i == 2 && m_hasDate && !m_hasTime) {
254 continue; // skip weekday in between
255 }
256 symbol = input.dataAt(offset + index);
257 if (hasFlag(BCD) && (hasFlag(REQ) || symbol != m_replacement)) {
258 if ((symbol & 0xf0) > 0x90 || (symbol & 0x0f) > 0x09) {
259 return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
260 }
261 symbol = (symbol_t)((symbol >> 4) * 10 + (symbol & 0x0f));
262 }
263 switch (type) {
264 case 2: // date only
265 if (!hasFlag(REQ) && symbol == m_replacement) {
266 if (i + 1 != length) {
267 *output << NULL_VALUE << ".";
268 break;
269 } else if (last == m_replacement) {
270 if (length == 2) { // number of days since 01.01.1900
271 *output << NULL_VALUE << ".";
272 }
273 *output << NULL_VALUE;
274 break;
275 }
276 }
277 if (length == 2) { // number of days since 01.01.1900
278 if (i == 0) {
279 break;
280 }
281 int mjd = last + symbol*256 + 15020; // 01.01.1900
282 int y = static_cast<int>((mjd-15078.2)/365.25);
283 int m = static_cast<int>((mjd-14956.1-static_cast<int>(y*365.25))/30.6001);
284 int d = mjd-14956-static_cast<int>(y*365.25)-static_cast<int>(m*30.6001);
285 m--;
286 if (m >= 13) {
287 y++;
288 m -= 12;
289 }
290 *output << dec << setfill('0') << setw(2) << static_cast<unsigned>(d) << "."
291 << setw(2) << static_cast<unsigned>(m) << "." << static_cast<unsigned>(y + 1900);
292 break;
293 }
294 if (i + 1 == length) {
295 *output << (2000 + symbol);
296 } else if (symbol < 1 || (i == 0 && symbol > 31) || (i == 1 && symbol > 12)) {
297 return RESULT_ERR_OUT_OF_RANGE; // invalid date
298 } else {
299 *output << setw(2) << dec << setfill('0') << static_cast<unsigned>(symbol) << ".";
300 }
301 break;
302
303 case 1: // time only
304 if (!hasFlag(REQ) && symbol == m_replacement) {
305 if (length == 1) { // truncated time
306 *output << NULL_VALUE << ":" << NULL_VALUE;
307 break;
308 }
309 if (i > 0) {
310 *output << ":";
311 }
312 *output << NULL_VALUE;
313 break;
314 }
315 if (hasFlag(SPE)) { // minutes since midnight
316 if (i == 0) {
317 last = symbol;
318 continue;
319 }
320 minutes = symbol*256 + last;
321 if (minutes > 24*60) {
322 return RESULT_ERR_OUT_OF_RANGE; // invalid value
323 }
324 unsigned int minutesHour = (unsigned int)(minutes / 60);
325 if (minutesHour > 24) {
326 return RESULT_ERR_OUT_OF_RANGE; // invalid hour
327 }
328 *output << setw(2) << dec << setfill('0') << minutesHour;
329 symbol = (symbol_t)(minutes % 60);
330 } else if (length == 1) { // truncated time
331 if (m_bitCount < 8) {
332 symbol = (symbol_t)(symbol & ((1 << m_bitCount) - 1));
333 }
334 if (i == 0) {
335 symbol = (symbol_t)(symbol/(60/m_resolution)); // convert to hours
336 index -= incr; // repeat for minutes
337 count++;
338 } else {
339 symbol = (symbol_t)((symbol % (60/m_resolution)) * m_resolution); // convert to minutes
340 }
341 }
342 if (i == 0) {
343 if (symbol > 24) {
344 return RESULT_ERR_OUT_OF_RANGE; // invalid hour
345 }
346 hour = symbol;
347 } else if (symbol > 59 || (hour == 24 && symbol > 0)) {
348 return RESULT_ERR_OUT_OF_RANGE; // invalid time
349 }
350 if (i > 0) {
351 *output << ":";
352 }
353 *output << setw(2) << dec << setfill('0') << static_cast<unsigned>(symbol);
354 break;
355
356 case 3: // date+time
357 if (length != 4) {
358 return RESULT_ERR_INVALID_POS;
359 }
360 // number of minutes since 01.01.2009
361 minutes |= symbol*(1<<(8*i));
362 if (i<3) {
363 break;
364 }
365 int mjd = static_cast<int>(minutes/(24*60)) + 54832; // 01.01.2009
366 int y = static_cast<int>((mjd-15078.2)/365.25);
367 int m = static_cast<int>((mjd-14956.1-static_cast<int>(y*365.25))/30.6001);
368 int d = mjd-14956-static_cast<int>(y*365.25)-static_cast<int>(m*30.6001);
369 m--;
370 if (m >= 13) {
371 y++;
372 m -= 12;
373 }
374 *output << dec << setfill('0') << setw(2) << static_cast<unsigned>(d) << "."
375 << setw(2) << static_cast<unsigned>(m) << "." << static_cast<unsigned>(y + 1900);
376 m = static_cast<int>(minutes%(24*60));
377 d = m/60;
378 *output << " " << setw(2) << dec << setfill('0') << static_cast<unsigned>(d);
379 m -= d*60;
380 *output << ":" << setw(2) << dec << setfill('0') << static_cast<unsigned>(m);
381 break;
382 }
383 last = symbol;
384 }
385 if (outputFormat & OF_JSON) {
386 *output << '"';
387 }
388 return RESULT_OK;
389 }
390
writeSymbols(size_t offset,size_t length,istringstream * input,SymbolString * output,size_t * usedLength) const391 result_t DateTimeDataType::writeSymbols(size_t offset, size_t length, istringstream* input,
392 SymbolString* output, size_t* usedLength) const {
393 size_t start = 0, count = length;
394 bool remainder = count == REMAIN_LEN && hasFlag(ADJ);
395 int incr = 1;
396 unsigned int value = 0, last = 0, lastLast = 0;
397 string token;
398
399 if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
400 start = length - 1;
401 incr = -1;
402 }
403 if (isIgnored() && !hasFlag(REQ)) {
404 if (remainder) {
405 count = 1;
406 }
407 for (size_t index = start, i = 0; i < count; index += incr, i++) {
408 output->dataAt(offset + index) = (symbol_t)m_replacement; // fill up with replacement
409 }
410 if (usedLength != nullptr) {
411 *usedLength = count;
412 }
413 return RESULT_OK;
414 }
415 result_t result;
416 size_t i = 0, index;
417 int type = m_hasDate ? 2 : (m_hasTime ? 1 : 0);
418 bool skip = false;
419 for (index = start; i < count; index += skip ? 0 : incr, i++) {
420 skip = false;
421 switch (type) {
422 case 2: // date only
423 if (length == 4 && i == 2 && !m_hasTime) {
424 continue; // skip weekday in between
425 }
426 if (input->eof() || !getline(*input, token, m_hasTime && i==2 ? ' ' : '.')) {
427 return RESULT_ERR_EOF; // incomplete
428 }
429 if (!hasFlag(REQ) && token == NULL_VALUE) {
430 value = m_replacement;
431 break;
432 }
433 value = parseInt(token.c_str(), 10, 0, 2099, &result);
434 if (result != RESULT_OK) {
435 return result; // invalid date part
436 }
437 if (length == 2) { // number of days since 01.01.1900
438 skip = true;
439 if (i == 0) {
440 count++;
441 } else if (i + 1 == count) {
442 int y = (value < 100 ? value + 2000 : value) - 1900;
443 int l = last <= 2 ? 1 : 0;
444 int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001);
445 value = mjd - 15020; // 01.01.1900
446 output->dataAt(offset + index) = (symbol_t)(value&0xff);
447 value >>= 8;
448 index += incr;
449 skip = false;
450 break;
451 }
452 }
453 if (i + 1 == (m_hasTime ? count-1 : count)) {
454 if (length == 4) {
455 int y = (value < 100 ? value + 2000 : value) - 1900;
456 int l = last <= 2 ? 1 : 0;
457 int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001);
458 if (m_hasTime) {
459 if (mjd < 54832) { // 01.01.2009
460 return RESULT_ERR_OUT_OF_RANGE; // invalid date
461 }
462 last = mjd - 54832;
463 index = start + incr;
464 i = 1;
465 type = 1;
466 skip = true; // switch to second pass for parsing the time
467 } else {
468 // calculate local week day
469 int daysSinceSunday = (mjd + 3) % 7; // Sun=0
470 if (hasFlag(SPE)) {
471 output->dataAt(offset + index - incr) = (symbol_t) ((6 + daysSinceSunday) % 7); // Sun=0x06
472 } else {
473 // Sun=0x07
474 output->dataAt(offset + index - incr) = (symbol_t) (daysSinceSunday == 0 ? 7 : daysSinceSunday);
475 }
476 }
477 }
478 if (value >= 2000) {
479 value -= 2000;
480 }
481 if (value > 99) {
482 return RESULT_ERR_OUT_OF_RANGE; // invalid year
483 }
484 } else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12)) {
485 return RESULT_ERR_OUT_OF_RANGE; // invalid date part
486 }
487 break;
488
489 case 1: // time only
490 if (input->eof() || !getline(*input, token, LENGTH_SEPARATOR)) {
491 return RESULT_ERR_EOF; // incomplete
492 }
493 if (!hasFlag(REQ) && token == NULL_VALUE) {
494 value = m_replacement;
495 if (length == 1) { // truncated time
496 if (i == 0) {
497 skip = true; // repeat for minutes
498 count++;
499 break;
500 }
501 if (last != m_replacement) {
502 return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes
503 }
504 }
505 break;
506 }
507 value = parseInt(token.c_str(), 10, 0, 59, &result);
508 if (result != RESULT_OK) {
509 return result; // invalid time part
510 }
511 if ((i == 0 && value > 24) || (i > 0 && (last == 24 && value > 0) )) {
512 return RESULT_ERR_OUT_OF_RANGE; // invalid time part
513 }
514 if (hasFlag(SPE)) { // minutes since midnight
515 if (i == 0) {
516 skip = true; // repeat for minutes
517 break;
518 }
519 value += last*60;
520 output->dataAt(offset + index) = (symbol_t)(value&0xff);
521 value >>= 8;
522 index += incr;
523 } else if (length == 1) { // truncated time
524 if (i == 0) {
525 skip = true; // repeat for minutes
526 count++;
527 break;
528 }
529 value = (last * 60 + value + m_resolution/2)/m_resolution;
530 if (value > 24 * 6) {
531 return RESULT_ERR_OUT_OF_RANGE; // invalid time
532 }
533 } else if (m_hasDate) {
534 if (i + 1 == count) {
535 last = (lastLast * 24 + last) * 60 + value;
536 value = last & 0xff;
537 last >>= 8;
538 index = start;
539 i = 0;
540 type = 3;
541 } else {
542 last = lastLast;
543 skip = true;
544 }
545 }
546 break;
547
548 case 3: // date and time in store phase
549 value = lastLast & 0xff;
550 last = lastLast >> 8;
551 break;
552 }
553 lastLast = last;
554 last = value;
555 if (!skip) {
556 if (hasFlag(BCD) && (hasFlag(REQ) || value != m_replacement)) {
557 if (value > 99) {
558 return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
559 }
560 value = ((value / 10) << 4) | (value % 10);
561 }
562 if (value > 0xff) {
563 return RESULT_ERR_OUT_OF_RANGE; // value out of range
564 }
565 output->dataAt(offset + index) = (symbol_t)value;
566 }
567 }
568
569 if (!remainder && i < count) {
570 return RESULT_ERR_EOF; // input too short
571 }
572 if (usedLength != nullptr) {
573 *usedLength = (index-start)*incr;
574 }
575 return RESULT_OK;
576 }
577
578
calcPrecision(int divisor)579 size_t NumberDataType::calcPrecision(int divisor) {
580 size_t precision = 0;
581 if (divisor > 1) {
582 for (unsigned int exp = 1; exp < MAX_DIVISOR; exp *= 10, precision++) {
583 if (exp >= (unsigned int)divisor) {
584 break;
585 }
586 }
587 }
588 return precision;
589 }
590
dump(OutputFormat outputFormat,size_t length,bool appendDivisor,ostream * output) const591 bool NumberDataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const {
592 if (m_bitCount < 8) {
593 DataType::dump(outputFormat, m_bitCount, appendDivisor, output);
594 } else {
595 DataType::dump(outputFormat, length, appendDivisor, output);
596 }
597 if ((outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) {
598 *output << ", \"result\": \"number\"";
599 }
600 if (!appendDivisor) {
601 return false;
602 }
603 bool ret = false;
604 if (m_baseType) {
605 if (m_baseType->m_divisor != m_divisor) {
606 if (outputFormat & OF_JSON) {
607 *output << ", \"divisor\": ";
608 }
609 *output << (m_divisor / m_baseType->m_divisor);
610 ret = true;
611 }
612 } else if (m_divisor != 1) {
613 if (outputFormat & OF_JSON) {
614 *output << ", \"divisor\": ";
615 }
616 *output << m_divisor;
617 ret = true;
618 }
619 if (ret && (outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) {
620 *output << ", \"precision\": " << static_cast<unsigned>(getPrecision());
621 }
622 return ret;
623 }
624
derive(int divisor,size_t bitCount,const NumberDataType ** derived) const625 result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataType** derived) const {
626 if (divisor == 0) {
627 divisor = 1;
628 }
629 if (m_divisor != 1) {
630 if (divisor == 1) {
631 divisor = m_divisor;
632 } else if (divisor < 0) {
633 if (m_divisor > 1) {
634 return RESULT_ERR_INVALID_ARG;
635 }
636 divisor *= -m_divisor;
637 } else if (m_divisor < 0) {
638 if (divisor > 1) {
639 return RESULT_ERR_INVALID_ARG;
640 }
641 divisor *= -m_divisor;
642 } else {
643 divisor *= m_divisor;
644 }
645 }
646 if (divisor == m_divisor && bitCount == m_bitCount) {
647 *derived = this;
648 return RESULT_OK;
649 }
650 if (-MAX_DIVISOR > divisor || divisor > MAX_DIVISOR) {
651 return RESULT_ERR_OUT_OF_RANGE;
652 }
653 if (bitCount <= 0 || bitCount == m_bitCount) {
654 bitCount = m_bitCount;
655 } else if (isAdjustableLength()) {
656 if (m_bitCount < 8) {
657 if (bitCount+m_firstBit > 8) {
658 return RESULT_ERR_OUT_OF_RANGE;
659 }
660 } else if ((bitCount%8) == 0) {
661 return RESULT_ERR_INVALID_ARG;
662 }
663 } else {
664 return RESULT_ERR_INVALID_ARG;
665 }
666 if (m_bitCount < 8) {
667 *derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement,
668 m_firstBit, divisor, m_baseType ? m_baseType : this);
669 } else {
670 *derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement,
671 m_minValue, m_maxValue, divisor, m_baseType ? m_baseType : this);
672 }
673 DataTypeList::getInstance()->addCleanup(*derived);
674 return RESULT_OK;
675 }
676
readRawValue(size_t offset,size_t length,const SymbolString & input,unsigned int * value) const677 result_t NumberDataType::readRawValue(size_t offset, size_t length, const SymbolString& input,
678 unsigned int* value) const {
679 size_t start = 0, count = length;
680 int incr = 1;
681 symbol_t symbol;
682
683 if (offset + length > input.getDataSize()) {
684 return RESULT_ERR_INVALID_POS; // not enough data available
685 }
686 if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
687 start = length - 1;
688 incr = -1;
689 }
690
691 *value = 0;
692 unsigned int exp = 1;
693 for (size_t index = start, i = 0; i < count; index += incr, i++) {
694 symbol = input.dataAt(offset + index);
695 if (hasFlag(BCD)) {
696 if (!hasFlag(REQ) && symbol == (m_replacement & 0xff)) {
697 *value = m_replacement;
698 return RESULT_OK;
699 }
700 if (!hasFlag(HCD)) {
701 if ((symbol & 0xf0) > 0x90 || (symbol & 0x0f) > 0x09) {
702 return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
703 }
704 symbol = (symbol_t)((symbol >> 4) * 10 + (symbol & 0x0f));
705 } else if (symbol > 0x63) {
706 return RESULT_ERR_OUT_OF_RANGE; // invalid HCD
707 }
708 *value += symbol * exp;
709 exp *= 100;
710 } else {
711 *value |= symbol * exp;
712 exp <<= 8;
713 }
714 }
715 if (m_firstBit > 0) {
716 *value >>= m_firstBit;
717 }
718 if (m_bitCount < 8) {
719 *value &= (1 << m_bitCount) - 1;
720 }
721
722 return RESULT_OK;
723 }
724
readSymbols(size_t offset,size_t length,const SymbolString & input,OutputFormat outputFormat,ostream * output) const725 result_t NumberDataType::readSymbols(size_t offset, size_t length, const SymbolString& input,
726 OutputFormat outputFormat, ostream* output) const {
727 unsigned int value = 0;
728 int signedValue;
729
730 result_t result = readRawValue(offset, length, input, &value);
731 if (result != RESULT_OK) {
732 return result;
733 }
734 *output << setw(0) << dec; // initialize output
735
736 if (!hasFlag(REQ) && value == m_replacement) {
737 if (outputFormat & OF_JSON) {
738 *output << "null";
739 } else {
740 *output << NULL_VALUE;
741 }
742 return RESULT_OK;
743 }
744
745 bool negative;
746 if (hasFlag(SIG)) { // signed value
747 negative = (value & (1 << (m_bitCount - 1))) != 0;
748 if (negative) { // negative signed value
749 if (value < m_minValue) {
750 return RESULT_ERR_OUT_OF_RANGE; // value out of range
751 }
752 } else if (value > m_maxValue) {
753 return RESULT_ERR_OUT_OF_RANGE; // value out of range
754 }
755 } else if (value < m_minValue || value > m_maxValue) {
756 return RESULT_ERR_OUT_OF_RANGE; // value out of range
757 } else {
758 negative = false;
759 }
760 if (m_bitCount == 32) {
761 if (hasFlag(EXP)) { // IEEE 754 binary32
762 float val;
763 #ifdef HAVE_DIRECT_FLOAT_FORMAT
764 # if HAVE_DIRECT_FLOAT_FORMAT == 2
765 value = __builtin_bswap32(value);
766 # endif
767 symbol_t* pval = reinterpret_cast<symbol_t*>(&value);
768 val = *reinterpret_cast<float*>(pval);
769 #else
770 int exp = (value >> 23) & 0xff; // 8 bits, signed
771 if (exp == 0) {
772 val = 0.0;
773 } else {
774 exp -= 127;
775 unsigned int sig = value & ((1 << 23) - 1);
776 val = (1.0f + static_cast<float>(sig / exp2(23))) * static_cast<float>(exp2(exp));
777 if (negative) {
778 val = -val;
779 }
780 }
781 #endif
782 if (val != val) { // !isnan(val)
783 if (outputFormat & OF_JSON) {
784 *output << "null";
785 } else {
786 *output << NULL_VALUE;
787 }
788 return RESULT_OK;
789 }
790 if (val != 0.0) {
791 if (m_divisor < 0) {
792 val *= static_cast<float>(-m_divisor);
793 } else if (m_divisor > 1) {
794 val /= static_cast<float>(m_divisor);
795 }
796 }
797 if (m_precision != 0) {
798 *output << fixed << setprecision(static_cast<int>(m_precision+6));
799 } else if (val == 0) {
800 *output << fixed << setprecision(1);
801 }
802 *output << static_cast<double>(val);
803 return RESULT_OK;
804 }
805 if (!negative) {
806 if (m_divisor < 0) {
807 *output << (static_cast<float>(value) * static_cast<float>(-m_divisor));
808 } else if (m_divisor <= 1) {
809 *output << value;
810 } else {
811 *output << setprecision(static_cast<int>(m_precision))
812 << fixed << (static_cast<float>(value) / static_cast<float>(m_divisor));
813 }
814 return RESULT_OK;
815 }
816 signedValue = static_cast<int>(value); // negative signed value
817 } else if (negative) { // negative signed value
818 signedValue = static_cast<int>(value) - (1 << m_bitCount);
819 } else {
820 signedValue = static_cast<int>(value);
821 }
822 if (m_divisor < 0) {
823 *output << fixed << setprecision(0)
824 << (static_cast<float>(signedValue) * static_cast<float>(-m_divisor));
825 } else if (m_divisor <= 1) {
826 if (hasFlag(FIX) && hasFlag(BCD)) {
827 if (outputFormat & OF_JSON) {
828 *output << '"' << setw(static_cast<int>(length * 2))
829 << setfill('0') << signedValue << setw(0) << '"';
830 return RESULT_OK;
831 }
832 *output << setw(static_cast<int>(length * 2)) << setfill('0');
833 }
834 *output << signedValue << setw(0);
835 } else {
836 *output << setprecision(static_cast<int>(m_precision))
837 << fixed << (static_cast<float>(signedValue) / static_cast<float>(m_divisor));
838 }
839 return RESULT_OK;
840 }
841
writeRawValue(unsigned int value,size_t offset,size_t length,SymbolString * output,size_t * usedLength) const842 result_t NumberDataType::writeRawValue(unsigned int value, size_t offset, size_t length,
843 SymbolString* output, size_t* usedLength) const {
844 size_t start = 0, count = length;
845 int incr = 1;
846 symbol_t symbol;
847
848 if (m_bitCount < 8 && (value & ~((1 << m_bitCount) - 1)) != 0) {
849 return RESULT_ERR_OUT_OF_RANGE;
850 }
851 if (m_firstBit > 0) {
852 value <<= m_firstBit;
853 }
854
855 if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
856 start = length - 1;
857 incr = -1;
858 }
859
860 for (size_t index = start, i = 0, exp = 1; i < count; index += incr, i++) {
861 if (hasFlag(BCD)) {
862 if (!hasFlag(REQ) && value == m_replacement) {
863 symbol = m_replacement & 0xff;
864 } else {
865 symbol = (symbol_t)((value / exp) % 100);
866 if (!hasFlag(HCD)) {
867 symbol = (symbol_t)(((symbol / 10) << 4) | (symbol % 10));
868 }
869 }
870 exp *= 100;
871 } else {
872 symbol = (value / exp) & 0xff;
873 exp <<= 8;
874 }
875 if (index == start && (m_bitCount % 8) != 0 && offset + index < output->getCalculatedDataSize()) {
876 output->dataAt(offset + index) |= symbol;
877 } else {
878 output->dataAt(offset + index) = symbol;
879 }
880 }
881 if (usedLength != nullptr) {
882 *usedLength = length;
883 }
884 return RESULT_OK;
885 }
886
writeSymbols(size_t offset,size_t length,istringstream * input,SymbolString * output,size_t * usedLength) const887 result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstream* input,
888 SymbolString* output, size_t* usedLength) const {
889 unsigned int value;
890
891 const string inputStr = input->str();
892 if (!hasFlag(REQ) && (isIgnored() || inputStr == NULL_VALUE)) {
893 value = m_replacement; // replacement value
894 } else if (inputStr.empty()) {
895 return RESULT_ERR_EOF; // input too short
896 } else if (hasFlag(EXP)) { // IEEE 754 binary32
897 const char* str = inputStr.c_str();
898 char* strEnd = nullptr;
899 double dvalue = strtod(str, &strEnd);
900 if (strEnd == nullptr || strEnd == str || *strEnd != 0) {
901 return RESULT_ERR_INVALID_NUM; // invalid value
902 }
903 if (m_divisor < 0) {
904 dvalue /= -m_divisor;
905 } else if (m_divisor > 1) {
906 dvalue *= m_divisor;
907 }
908 #ifdef HAVE_DIRECT_FLOAT_FORMAT
909 float val = static_cast<float>(dvalue);
910 symbol_t* pval = reinterpret_cast<symbol_t*>(&val);
911 value = *reinterpret_cast<int32_t*>(pval);
912 # if HAVE_DIRECT_FLOAT_FORMAT == 2
913 value = __builtin_bswap32(value);
914 # endif
915 #else
916 value = 0;
917 if (dvalue != 0) {
918 bool negative = dvalue < 0;
919 if (negative) {
920 dvalue = -dvalue;
921 }
922 int exp = ilogb(dvalue);
923 if (exp < -126 || exp > 127) {
924 return RESULT_ERR_INVALID_NUM; // invalid value
925 }
926 dvalue = scalbln(dvalue, -exp) - 1.0;
927 unsigned int sig = (unsigned int)(dvalue * exp2(23));
928 exp += 127;
929 value = (exp << 23) | sig;
930 if (negative) {
931 value |= 0x80000000;
932 }
933 }
934 #endif
935 } else {
936 const char* str = inputStr.c_str();
937 char* strEnd = nullptr;
938 if (m_divisor == 1) {
939 if (hasFlag(SIG)) {
940 long signedValue = strtol(str, &strEnd, 10);
941 if (signedValue < 0 && m_bitCount != 32) {
942 value = (unsigned int)(signedValue + (1 << m_bitCount));
943 } else {
944 value = (unsigned int)signedValue;
945 }
946 } else {
947 value = (unsigned int)strtoul(str, &strEnd, 10);
948 }
949 if (strEnd == nullptr || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
950 return RESULT_ERR_INVALID_NUM; // invalid value
951 }
952 } else {
953 double dvalue = strtod(str, &strEnd);
954 if (strEnd == nullptr || strEnd == str || *strEnd != 0) {
955 return RESULT_ERR_INVALID_NUM; // invalid value
956 }
957 if (m_divisor < 0) {
958 dvalue = round(dvalue / -m_divisor);
959 } else {
960 dvalue = round(dvalue * m_divisor);
961 }
962 if (hasFlag(SIG)) {
963 if (dvalue < -exp2((8 * static_cast<double>(length)) - 1)
964 || dvalue >= exp2((8 * static_cast<double>(length)) - 1)) {
965 return RESULT_ERR_OUT_OF_RANGE; // value out of range
966 }
967 if (dvalue < 0 && m_bitCount != 32) {
968 value = static_cast<int>(dvalue + (1 << m_bitCount));
969 } else {
970 value = static_cast<int>(dvalue);
971 }
972 } else {
973 if (dvalue < 0.0 || dvalue >= exp2(8 * static_cast<double>(length))) {
974 return RESULT_ERR_OUT_OF_RANGE; // value out of range
975 }
976 value = (unsigned int)dvalue;
977 }
978 }
979
980 if (hasFlag(SIG)) { // signed value
981 if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
982 if (value < m_minValue) {
983 return RESULT_ERR_OUT_OF_RANGE; // value out of range
984 }
985 } else if (value > m_maxValue) {
986 return RESULT_ERR_OUT_OF_RANGE; // value out of range
987 }
988 } else if (value < m_minValue || value > m_maxValue) {
989 return RESULT_ERR_OUT_OF_RANGE; // value out of range
990 }
991 }
992
993 return writeRawValue(value, offset, length, output, usedLength);
994 }
995
996
997 DataTypeList DataTypeList::s_instance;
998
999 #ifdef HAVE_CONTRIB
1000 bool DataTypeList::s_contrib_initialized = libebus_contrib_register();
1001 #endif
1002
1003
DataTypeList()1004 DataTypeList::DataTypeList() {
1005 add(new StringDataType("STR", MAX_LEN*8, ADJ, ' ')); // >= 1 byte character string filled up with space
1006 // unsigned decimal in BCD, 0000 - 9999 (fixed length)
1007 add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1));
1008 add(new NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254
1009 add(new StringDataType("IGN", MAX_LEN*8, IGN|ADJ, 0)); // >= 1 byte ignored data
1010 // >= 1 byte character string filled up with 0x00 (null terminated string)
1011 add(new StringDataType("NTS", MAX_LEN*8, ADJ, 0));
1012 // >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d
1013 add(new StringDataType("HEX", MAX_LEN*8, ADJ, 0, true));
1014 // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99,
1015 // WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff)
1016 add(new DateTimeDataType("BDA", 32, BCD, 0xff, true, false, 0));
1017 add(new DateTimeDataType("BDA:4", 32, BCD|DUP, 0xff, true, false, 0));
1018 // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99, replacement 0xff)
1019 add(new DateTimeDataType("BDA:3", 24, BCD, 0xff, true, false, 0));
1020 // date with zero-based weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WZ,0x00 - 0x31,0x12,WZ,0x99,
1021 // WZ is zero-based weekday Mon=0x00 - Sun=0x06, replacement 0xff)
1022 add(new DateTimeDataType("BDZ", 32, BCD|SPE, 0xff, true, false, 0));
1023 // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x1f,0x0c,WW,0x63,
1024 // WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff)
1025 add(new DateTimeDataType("HDA", 32, 0, 0xff, true, false, 0));
1026 add(new DateTimeDataType("HDA:4", 32, DUP, 0xff, true, false, 0));
1027 // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x1f,0x0c,0x63, replacement 0xff)
1028 add(new DateTimeDataType("HDA:3", 24, 0, 0xff, true, false, 0));
1029 // date, days since 01.01.1900, 01.01.1900 - 06.06.2079 (0x00,0x00 - 0xff,0xff)
1030 add(new DateTimeDataType("DAY", 16, 0, 0xff, true, false, 0));
1031 // date+time in minutes since 01.01.2009, 01.01.2009 - 31.12.2099 (0x00,0x00,0x00,0x00 - 0x02,0xda,0x4e,0x1f)
1032 add(new DateTimeDataType("DTM", 32, REQ, 0x100, true, true, 0));
1033 // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
1034 add(new DateTimeDataType("BTI", 24, BCD|REV, 0xff, false, true, 0));
1035 // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b)
1036 add(new DateTimeDataType("HTI", 24, 0, 0xff, false, true, 0));
1037 // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type]
1038 add(new DateTimeDataType("VTI", 24, REV, 0x63, false, true, 0));
1039 // time as hh:mm in BCD, 00:00 - 23:59 (0x00,0x00 - 0x59,0x23, replacement 0xff)
1040 add(new DateTimeDataType("BTM", 16, BCD|REV, 0xff, false, true, 0));
1041 // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
1042 add(new DateTimeDataType("HTM", 16, 0, 0xff, false, true, 0));
1043 // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x3b,0x17, replacement 0xff) [Vaillant type]
1044 add(new DateTimeDataType("VTM", 16, REV, 0xff, false, true, 0));
1045 // time, minutes since last midnight, 00:00 - 24:00 (minutes + hour * 60 as integer)
1046 add(new DateTimeDataType("MIN", 16, SPE, 0xff, false, true, 0));
1047 // truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer)
1048 add(new DateTimeDataType("TTM", 8, 0, 0x90, false, true, 10));
1049 // truncated time (only multiple of 30 minutes), 00:00 - 24:00 (minutes div 30 + hour * 2 as integer)
1050 add(new DateTimeDataType("TTH", 6, 0, 0, false, true, 30));
1051 // truncated time (only multiple of 15 minutes), 00:00 - 24:00 (minutes div 15 + hour * 4 as integer)
1052 add(new DateTimeDataType("TTQ", 7, 0, 0, false, true, 15));
1053 add(new NumberDataType("BDY", 8, DAY, 0x07, 0, 6, 1)); // weekday, "Mon" - "Sun" (0x00 - 0x06) [eBUS type]
1054 add(new NumberDataType("HDY", 8, DAY, 0x00, 1, 7, 1)); // weekday, "Mon" - "Sun" (0x01 - 0x07) [Vaillant type]
1055 add(new NumberDataType("BCD", 8, BCD, 0xff, 0, 99, 1)); // unsigned decimal in BCD, 0 - 99
1056 add(new NumberDataType("BCD:1", 8, BCD|DUP, 0xff, 0, 99, 1)); // unsigned decimal in BCD, 0 - 99
1057 add(new NumberDataType("BCD:2", 16, BCD, 0xffff, 0, 9999, 1)); // unsigned decimal in BCD, 0 - 9999
1058 add(new NumberDataType("BCD:3", 24, BCD, 0xffffff, 0, 999999, 1)); // unsigned decimal in BCD, 0 - 999999
1059 add(new NumberDataType("BCD:4", 32, BCD, 0xffffffff, 0, 99999999, 1)); // unsigned decimal in BCD, 0 - 99999999
1060 add(new NumberDataType("HCD", 32, HCD|BCD|REQ, 0, 0, 99999999, 1)); // unsigned decimal in HCD, 0 - 99999999
1061 add(new NumberDataType("HCD:4", 32, HCD|BCD|REQ|DUP, 0, 0, 99999999, 1)); // unsigned decimal in HCD, 0 - 99999999
1062 add(new NumberDataType("HCD:1", 8, HCD|BCD|REQ, 0, 0, 99, 1)); // unsigned decimal in HCD, 0 - 99
1063 add(new NumberDataType("HCD:2", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999
1064 add(new NumberDataType("HCD:3", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999
1065 add(new NumberDataType("SCH", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
1066 add(new NumberDataType("D1B", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
1067 // unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff)
1068 add(new NumberDataType("D1C", 8, 0, 0xff, 0x00, 0xc8, 2));
1069 // signed number (fraction 1/256), -127.99 - +127.99
1070 add(new NumberDataType("D2B", 16, SIG, 0x8000, 0x8001, 0x7fff, 256));
1071 // signed number (fraction 1/16), -2047.9 - +2047.9
1072 add(new NumberDataType("D2C", 16, SIG, 0x8000, 0x8001, 0x7fff, 16));
1073 // signed number (fraction 1/1000), -32.767 - +32.767, little endian
1074 add(new NumberDataType("FLT", 16, SIG, 0x8000, 0x8001, 0x7fff, 1000));
1075 // signed number (fraction 1/1000), -32.767 - +32.767, big endian
1076 add(new NumberDataType("FLR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1000));
1077 // signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), little endian
1078 add(new NumberDataType("EXP", 32, SIG|EXP, 0x7f800000, 0x00000000, 0xffffffff, 1));
1079 // signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), big endian
1080 add(new NumberDataType("EXR", 32, SIG|EXP|REV, 0x7f800000, 0x00000000, 0xffffffff, 1));
1081 // unsigned integer, 0 - 65534, little endian
1082 add(new NumberDataType("UIN", 16, 0, 0xffff, 0, 0xfffe, 1));
1083 // unsigned integer, 0 - 65534, big endian
1084 add(new NumberDataType("UIR", 16, REV, 0xffff, 0, 0xfffe, 1));
1085 // signed integer, -32767 - +32767, little endian
1086 add(new NumberDataType("SIN", 16, SIG, 0x8000, 0x8001, 0x7fff, 1));
1087 // signed integer, -32767 - +32767, big endian
1088 add(new NumberDataType("SIR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1));
1089 // unsigned 3 bytes int, 0 - 16777214, little endian
1090 add(new NumberDataType("U3N", 24, 0, 0xffffff, 0, 0xfffffe, 1));
1091 // unsigned 3 bytes int, 0 - 16777214, big endian
1092 add(new NumberDataType("U3R", 24, REV, 0xffffff, 0, 0xfffffe, 1));
1093 // signed 3 bytes int, -8388607 - +8388607, little endian
1094 add(new NumberDataType("S3N", 24, SIG, 0x800000, 0x800001, 0xffffff, 1));
1095 // signed 3 bytes int, -8388607 - +8388607, big endian
1096 add(new NumberDataType("S3R", 24, SIG|REV, 0x800000, 0x800001, 0xffffff, 1));
1097 // unsigned integer, 0 - 4294967294, little endian
1098 add(new NumberDataType("ULG", 32, 0, 0xffffffff, 0, 0xfffffffe, 1));
1099 // unsigned integer, 0 - 4294967294, big endian
1100 add(new NumberDataType("ULR", 32, REV, 0xffffffff, 0, 0xfffffffe, 1));
1101 // signed integer, -2147483647 - +2147483647, little endian
1102 add(new NumberDataType("SLG", 32, SIG, 0x80000000, 0x80000001, 0xffffffff, 1));
1103 // signed integer, -2147483647 - +2147483647, big endian
1104 add(new NumberDataType("SLR", 32, SIG|REV, 0x80000000, 0x80000001, 0xffffffff, 1));
1105 add(new NumberDataType("BI0", 7, ADJ|REQ, 0, 0, 1)); // bit 0 (up to 7 bits until bit 6)
1106 add(new NumberDataType("BI1", 7, ADJ|REQ, 0, 1, 1)); // bit 1 (up to 7 bits until bit 7)
1107 add(new NumberDataType("BI2", 6, ADJ|REQ, 0, 2, 1)); // bit 2 (up to 6 bits until bit 7)
1108 add(new NumberDataType("BI3", 5, ADJ|REQ, 0, 3, 1)); // bit 3 (up to 5 bits until bit 7)
1109 add(new NumberDataType("BI4", 4, ADJ|REQ, 0, 4, 1)); // bit 4 (up to 4 bits until bit 7)
1110 add(new NumberDataType("BI5", 3, ADJ|REQ, 0, 5, 1)); // bit 5 (up to 3 bits until bit 7)
1111 add(new NumberDataType("BI6", 2, ADJ|REQ, 0, 6, 1)); // bit 6 (up to 2 bits until bit 7)
1112 add(new NumberDataType("BI7", 1, REQ, 0, 7, 1)); // bit 7
1113 }
1114
getInstance()1115 DataTypeList* DataTypeList::getInstance() {
1116 return &s_instance;
1117 }
1118
dump(OutputFormat outputFormat,bool appendDivisor,ostream * output) const1119 void DataTypeList::dump(OutputFormat outputFormat, bool appendDivisor, ostream* output) const {
1120 bool json = outputFormat & OF_JSON;
1121 string sep = "\n";
1122 for (const auto &it: m_typesById) {
1123 const DataType *dataType = it.second;
1124 if (dataType->hasFlag(DUP)) {
1125 continue;
1126 }
1127 if (json) {
1128 *output << sep << " {";
1129 }
1130 if ((dataType->getBitCount() % 8) != 0) {
1131 dataType->dump(outputFormat, dataType->getBitCount(), appendDivisor, output);
1132 } else {
1133 dataType->dump(outputFormat, dataType->getBitCount() / 8, appendDivisor, output);
1134 }
1135 if (json) {
1136 *output << "}";
1137 sep = ",\n";
1138 } else {
1139 *output << "\n";
1140 }
1141 }
1142 }
1143
clear()1144 void DataTypeList::clear() {
1145 for (auto& it : m_cleanupTypes) {
1146 delete it;
1147 }
1148 m_cleanupTypes.clear();
1149 m_typesById.clear();
1150 }
1151
add(const DataType * dataType)1152 result_t DataTypeList::add(const DataType* dataType) {
1153 if (m_typesById.find(dataType->getId()) != m_typesById.end()) {
1154 return RESULT_ERR_DUPLICATE_NAME; // duplicate key
1155 }
1156 m_typesById[dataType->getId()] = dataType;
1157 m_cleanupTypes.push_back(dataType);
1158 return RESULT_OK;
1159 }
1160
get(const string & id,size_t length) const1161 const DataType* DataTypeList::get(const string& id, size_t length) const {
1162 if (length > 0) {
1163 ostringstream str;
1164 str << id << LENGTH_SEPARATOR << static_cast<unsigned>(length);
1165 auto it = m_typesById.find(str.str());
1166 if (it != m_typesById.end()) {
1167 return it->second;
1168 }
1169 }
1170 auto it = m_typesById.find(id);
1171 if (it == m_typesById.end()) {
1172 return nullptr;
1173 }
1174 if (length > 0 && !it->second->isAdjustableLength()) {
1175 return nullptr;
1176 }
1177 return it->second;
1178 }
1179
1180 } // namespace ebusd
1181