Files
nixie-clock/firmware/uniclock/lib/arduino-home-assistant/src/utils/HANumeric.cpp
T

214 lines
4.2 KiB
C++
Raw Normal View History

2026-10-25 21:37:25 +01:00
#include "HANumeric.h"
const uint8_t HANumeric::MaxDigitsNb = 19;
HANumeric HANumeric::fromStr(const uint8_t* buffer, const uint16_t length)
{
if (length == 0) {
return HANumeric();
}
const uint8_t* firstCh = &buffer[0];
int64_t out = 0;
bool isSigned = false;
if (*firstCh == '-') {
isSigned = true;
firstCh++;
}
uint8_t digitsNb = isSigned ? length - 1 : length;
if (digitsNb > MaxDigitsNb) {
return HANumeric();
}
uint64_t base = 1;
const uint8_t* ptr = &buffer[length - 1];
while (ptr >= firstCh) {
uint8_t digit = *ptr - '0';
if (digit > 9) {
return HANumeric();
}
out += digit * base;
ptr--;
base *= 10;
}
return HANumeric(isSigned ? out * -1 : out);
}
HANumeric::HANumeric():
_isSet(false),
_value(0),
_precision(0)
{
}
HANumeric::HANumeric(const float value, const uint8_t precision):
_isSet(true),
_precision(precision)
{
_value = value * static_cast<float>(getPrecisionBase());
}
HANumeric::HANumeric(const int8_t value, const uint8_t precision):
_isSet(true),
_precision(precision)
{
_value = value * static_cast<int32_t>(getPrecisionBase());
}
HANumeric::HANumeric(const int16_t value, const uint8_t precision):
_isSet(true),
_precision(precision)
{
_value = value * static_cast<int32_t>(getPrecisionBase());
}
HANumeric::HANumeric(const int32_t value, const uint8_t precision):
_isSet(true),
_precision(precision)
{
_value = value * static_cast<int32_t>(getPrecisionBase());
}
HANumeric::HANumeric(const uint8_t value, const uint8_t precision):
_isSet(true),
_precision(precision)
{
_value = value * getPrecisionBase();
}
HANumeric::HANumeric(const uint16_t value, const uint8_t precision):
_isSet(true),
_precision(precision)
{
_value = value * getPrecisionBase();
}
HANumeric::HANumeric(const uint32_t value, const uint8_t precision):
_isSet(true),
_precision(precision)
{
_value = value * getPrecisionBase();
}
#ifdef ARDUINOHA_INT_OVERLOAD
HANumeric::HANumeric(const int value, const uint8_t precision):
_isSet(true),
_precision(precision)
{
_value = value * static_cast<int>(getPrecisionBase());
}
#endif
HANumeric::HANumeric(const int64_t value):
_isSet(true),
_value(value),
_precision(0)
{
}
uint32_t HANumeric::getPrecisionBase() const
{
// using pow() increases the flash size by ~2KB
switch (_precision) {
case 1:
return 10;
case 2:
return 100;
case 3:
return 1000;
default:
return 1;
}
}
uint8_t HANumeric::calculateSize() const
{
if (!_isSet) {
return 0;
}
int64_t value = _value;
const bool isSigned = value < 0;
if (isSigned) {
value *= -1;
}
uint8_t digitsNb = 1;
while (value > 9) {
value /= 10;
digitsNb++;
}
if (isSigned) {
digitsNb++; // sign
}
if (_precision > 0) {
if (value == 0) {
return 1;
}
// one digit + dot + decimal digits (+ sign)
const uint8_t minValue = isSigned ? _precision + 3 : _precision + 2;
return digitsNb >= minValue ? digitsNb + 1 : minValue;
}
return digitsNb;
}
uint16_t HANumeric::toStr(char* dst) const
{
char* prefixCh = &dst[0];
if (!_isSet || _value == 0) {
*prefixCh = '0';
return 1;
}
int64_t value = _value;
const uint8_t numberLength = calculateSize();
if (value < 0) {
value *= -1;
*prefixCh = '-';
prefixCh++;
}
if (_precision > 0) {
uint8_t i = _precision;
char* dotPtr = prefixCh + 1;
do {
*prefixCh = '0';
prefixCh++;
} while(i-- > 0);
*dotPtr = '.';
}
char* ch = &dst[numberLength - 1];
char* lastCh = ch;
char* dotPos = _precision > 0 ? &dst[numberLength - 1 - _precision] : nullptr;
while (value != 0) {
if (ch == dotPos) {
*dotPos = '.';
ch--;
continue;
}
*ch = (value % 10) + '0';
value /= 10;
ch--;
}
return lastCh - &dst[0] + 1;
}