supla-device
Loading...
Searching...
No Matches
inverter_parser.h
1// SPDX-FileCopyrightText: AC SOFTWARE SP. Z O.O.
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#ifndef SRC_SUPLA_PV_INVERTER_PARSER_H_
5#define SRC_SUPLA_PV_INVERTER_PARSER_H_
6
7#include <ctype.h>
8#include <errno.h>
9#include <float.h>
10#include <limits.h>
11#include <math.h>
12#include <stdint.h>
13#include <stdlib.h>
14
15namespace Supla {
16namespace PV {
17namespace detail {
18
19inline bool onlyWhitespace(const char *text) {
20 while (*text != '\0') {
21 if (!isspace(static_cast<unsigned char>(*text++))) {
22 return false;
23 }
24 }
25 return true;
26}
27
28template <typename Number = double, typename Measurement>
29bool parseInverterValue(const char *text,
30 uint32_t scale,
31 Measurement *measurement) {
32 if (text == nullptr) {
33 return false;
34 }
35 char *end = nullptr;
36 errno = 0;
37 double parsed = strtod(text, &end);
38 double maximum = sizeof(Number) == sizeof(float) ? FLT_MAX : DBL_MAX;
39 if (end == text || errno == ERANGE || !onlyWhitespace(end) ||
40 !isfinite(parsed) || parsed < -maximum || parsed > maximum) {
41 return false;
42 }
43 // Preserve the integration's arithmetic precision and scale, but check the
44 // destination's range before converting to an integer. An exclusive upper
45 // bound avoids rounding UINT64_MAX up to 2^64 when represented as double.
46 double scaled = static_cast<Number>(parsed) * static_cast<Number>(scale);
47 bool isSigned = static_cast<Measurement>(-1) < static_cast<Measurement>(1);
48 int digits = sizeof(Measurement) * CHAR_BIT - (isSigned ? 1 : 0);
49 double upper = ldexp(1.0, digits);
50 double lower = isSigned ? -upper : 0;
51 if (!isfinite(scaled) || scaled < lower || scaled >= upper) {
52 return false;
53 }
54 *measurement = static_cast<Measurement>(scaled);
55 return true;
56}
57
58} // namespace detail
59} // namespace PV
60} // namespace Supla
61
62#endif // SRC_SUPLA_PV_INVERTER_PARSER_H_