mirror of
https://github.com/xodio/xod.git
synced 2026-02-20 02:01:20 +01:00
refactor(xod-arduino, workspace): replace platform-dependent dtostrf with dtoa and move shared formatters.cpp into cpplib directory and rename it
This commit is contained in:
@@ -1,3 +1,14 @@
|
||||
/**
|
||||
* This file makes Catch2 show failed tests properly for the XString type.
|
||||
* E.G.
|
||||
* "some" == "something"
|
||||
* instead of
|
||||
* {?} == {?}
|
||||
*
|
||||
* Catch2 string conversion docs:
|
||||
* https://github.com/catchorg/Catch2/blob/master/docs/tostring.md
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
struct XodStringMaker {
|
||||
static std::string convert(T value) {
|
||||
161
packages/xod-arduino/platform/formatNumber.h
Normal file
161
packages/xod-arduino/platform/formatNumber.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Format Numbers
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
|
||||
/**
|
||||
* Provide `formatNumber` cross-platform number to string converter function.
|
||||
*
|
||||
* Taken from here:
|
||||
* https://github.com/client9/stringencoders/blob/master/src/modp_numtoa.c
|
||||
* Original function name: `modp_dtoa2`.
|
||||
*
|
||||
* Modified:
|
||||
* - `isnan` instead of tricky comparing and return "NaN"
|
||||
* - handle Infinity values and return "Inf" or "-Inf"
|
||||
* - return `OVF` and `-OVF` for numbers bigger than max possible, instead of using `sprintf`
|
||||
* - use `Number` instead of double
|
||||
* - if negative number rounds to zero, return just "0" instead of "-0"
|
||||
*
|
||||
* This is a replacement of `dtostrf`.
|
||||
*/
|
||||
|
||||
#ifndef XOD_FORMAT_NUMBER_H
|
||||
#define XOD_FORMAT_NUMBER_H
|
||||
|
||||
namespace xod {
|
||||
|
||||
/**
|
||||
* Powers of 10
|
||||
* 10^0 to 10^9
|
||||
*/
|
||||
static const Number powers_of_10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
|
||||
10000000, 100000000, 1000000000 };
|
||||
|
||||
static void strreverse(char* begin, char* end) {
|
||||
char aux;
|
||||
while (end > begin)
|
||||
aux = *end, *end-- = *begin, *begin++ = aux;
|
||||
};
|
||||
|
||||
size_t formatNumber(Number value, int prec, char* str) {
|
||||
if (isnan(value)) {
|
||||
strcpy(str, "NaN");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
if (isinf(value)) {
|
||||
bool isNegative = value < 0;
|
||||
strcpy(str, isNegative ? "-Inf" : "Inf");
|
||||
return (size_t)isNegative ? 4 : 3;
|
||||
}
|
||||
|
||||
/* if input is larger than thres_max return "OVF" */
|
||||
const Number thres_max = (Number)(0x7FFFFFFF);
|
||||
|
||||
Number diff = 0.0;
|
||||
char* wstr = str;
|
||||
|
||||
if (prec < 0) {
|
||||
prec = 0;
|
||||
} else if (prec > 9) {
|
||||
/* precision of >= 10 can lead to overflow errors */
|
||||
prec = 9;
|
||||
}
|
||||
|
||||
/* we'll work in positive values and deal with the
|
||||
negative sign issue later */
|
||||
int neg = 0;
|
||||
if (value < 0) {
|
||||
neg = 1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
Number tmp = (value - whole) * powers_of_10[prec];
|
||||
uint32_t frac = (uint32_t)(tmp);
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
/* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec > 0 && (frac & 1)) {
|
||||
/* if halfway, round up if odd, OR
|
||||
if last digit is 0. That last part is strange */
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec == 0 && (whole & 1)) {
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
|
||||
if (value > thres_max) {
|
||||
if (neg) {
|
||||
strcpy(str, "-OVF");
|
||||
return (size_t)4;
|
||||
}
|
||||
strcpy(str, "OVF");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
int has_decimal = 0;
|
||||
int count = prec;
|
||||
bool notzero = frac > 0;
|
||||
|
||||
/* Remove ending zeros */
|
||||
if (prec > 0) {
|
||||
while (count > 0 && ((frac % 10) == 0)) {
|
||||
count--;
|
||||
frac /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
while (count > 0) {
|
||||
--count;
|
||||
*wstr++ = (char)(48 + (frac % 10));
|
||||
frac /= 10;
|
||||
has_decimal = 1;
|
||||
}
|
||||
|
||||
if (frac > 0) {
|
||||
++whole;
|
||||
}
|
||||
|
||||
/* add decimal */
|
||||
if (has_decimal) {
|
||||
*wstr++ = '.';
|
||||
}
|
||||
|
||||
notzero = notzero || whole > 0;
|
||||
|
||||
/* do whole part
|
||||
* Take care of sign conversion
|
||||
* Number is reversed.
|
||||
*/
|
||||
do
|
||||
*wstr++ = (char)(48 + (whole % 10));
|
||||
while (whole /= 10);
|
||||
|
||||
if (neg && notzero) {
|
||||
*wstr++ = '-';
|
||||
}
|
||||
*wstr = '\0';
|
||||
strreverse(str, wstr - 1);
|
||||
return (size_t)(wstr - str);
|
||||
}
|
||||
|
||||
} // namespace xod
|
||||
#endif
|
||||
@@ -42,79 +42,7 @@
|
||||
# define pgm_read_ptr(addr) (*(const void **)(addr))
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Compatibilities
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if !defined(ARDUINO_ARCH_AVR) && !defined(__DTOSTRF_H_)
|
||||
/*
|
||||
* Provide dtostrf function for non-AVR platforms. Although many platforms
|
||||
* provide a stub many others do not. And the stub is based on `sprintf`
|
||||
* which doesn’t work with floating point formatters on some platforms
|
||||
* (e.g. Arduino M0).
|
||||
*
|
||||
* This is an implementation based on `fcvt` standard function. Taken here:
|
||||
* https://forum.arduino.cc/index.php?topic=368720.msg2542614#msg2542614
|
||||
*/
|
||||
char *dtostrf(double val, int width, unsigned int prec, char *sout) {
|
||||
int decpt, sign, reqd, pad;
|
||||
const char *s, *e;
|
||||
char *p;
|
||||
s = fcvt(val, prec, &decpt, &sign);
|
||||
if (prec == 0 && decpt == 0) {
|
||||
s = (*s < '5') ? "0" : "1";
|
||||
reqd = 1;
|
||||
} else {
|
||||
reqd = strlen(s);
|
||||
if (reqd > decpt) reqd++;
|
||||
if (decpt == 0) reqd++;
|
||||
}
|
||||
if (sign) reqd++;
|
||||
p = sout;
|
||||
e = p + reqd;
|
||||
pad = width - reqd;
|
||||
if (pad > 0) {
|
||||
e += pad;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
if (sign) *p++ = '-';
|
||||
if (decpt <= 0 && prec > 0) {
|
||||
*p++ = '0';
|
||||
*p++ = '.';
|
||||
e++;
|
||||
while ( decpt < 0 ) {
|
||||
decpt++;
|
||||
*p++ = '0';
|
||||
}
|
||||
}
|
||||
while (p < e) {
|
||||
*p++ = *s++;
|
||||
if (p == e) break;
|
||||
if (--decpt == 0) *p++ = '.';
|
||||
}
|
||||
if (width < 0) {
|
||||
pad = (reqd + width) * -1;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
*p = 0;
|
||||
return sout;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace xod {
|
||||
//----------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
//----------------------------------------------------------------------------
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Global variables
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
17
packages/xod-arduino/platform/types.h
Normal file
17
packages/xod-arduino/platform/types.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Basic XOD types
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
namespace xod {
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
} // namespace xod
|
||||
@@ -14,6 +14,8 @@ import programTpl from '../platform/program.tpl.cpp';
|
||||
import preambleH from '../platform/preamble.h';
|
||||
import listViewsH from '../platform/listViews.h';
|
||||
import listFuncsH from '../platform/listFuncs.h';
|
||||
import typesH from '../platform/types.h';
|
||||
import formatNumberH from '../platform/formatNumber.h';
|
||||
import uartH from '../platform/uart.h';
|
||||
import memoryH from '../platform/memory.h';
|
||||
import stlH from '../platform/stl.h';
|
||||
@@ -306,10 +308,12 @@ export const renderProject = def(
|
||||
preambleH,
|
||||
config,
|
||||
stlH,
|
||||
typesH,
|
||||
listViewsH,
|
||||
memoryH,
|
||||
uartH,
|
||||
omitLocalIncludes(listFuncsH),
|
||||
formatNumberH,
|
||||
runtimeCpp,
|
||||
impls,
|
||||
program,
|
||||
|
||||
60
packages/xod-arduino/test-cpp/formatNumber.cpp
Normal file
60
packages/xod-arduino/test-cpp/formatNumber.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "../platform/types.h"
|
||||
#include "../platform/listViews.h"
|
||||
#include "../platform/listFuncs.h"
|
||||
#include "../platform/formatNumber.h"
|
||||
#include <XStringFormat.inl>
|
||||
|
||||
xod::XStringCString convertAndTest(xod::Number val, unsigned int prec, char* sout) {
|
||||
xod::formatNumber(val, prec, sout);
|
||||
return xod::XStringCString(sout);
|
||||
}
|
||||
|
||||
TEST_CASE("Number to XString conversion", "[list]") {
|
||||
char str [16];
|
||||
|
||||
SECTION("Integer numbers") {
|
||||
REQUIRE(convertAndTest((xod::Number) 0, 0, str) == xod::XStringCString("0"));
|
||||
REQUIRE(convertAndTest((xod::Number) -1, 1, str) == xod::XStringCString("-1"));
|
||||
REQUIRE(convertAndTest((xod::Number) 42, 5, str) == xod::XStringCString("42"));
|
||||
REQUIRE(convertAndTest((xod::Number) -579, 1, str) == xod::XStringCString("-579"));
|
||||
REQUIRE(convertAndTest((xod::Number) 21474836, 0, str) == xod::XStringCString("21474836"));
|
||||
REQUIRE(convertAndTest((xod::Number) 21474836, 6, str) == xod::XStringCString("21474836"));
|
||||
}
|
||||
SECTION("Numbers with floating point") {
|
||||
REQUIRE(convertAndTest((xod::Number) 0.25, 0, str) == xod::XStringCString("0"));
|
||||
REQUIRE(convertAndTest((xod::Number) 0.51, 0, str) == xod::XStringCString("1"));
|
||||
REQUIRE(convertAndTest((xod::Number) 0.451, 1, str) == xod::XStringCString("0.5"));
|
||||
REQUIRE(convertAndTest((xod::Number) 0.451, 2, str) == xod::XStringCString("0.45"));
|
||||
REQUIRE(convertAndTest((xod::Number) 0.7385, 4, str) == xod::XStringCString("0.7385"));
|
||||
REQUIRE(convertAndTest((xod::Number) 0.73855, 4, str) == xod::XStringCString("0.7386"));
|
||||
REQUIRE(convertAndTest((xod::Number) 123.456, 0, str) == xod::XStringCString("123"));
|
||||
REQUIRE(convertAndTest((xod::Number) 123.456, 2, str) == xod::XStringCString("123.46"));
|
||||
|
||||
REQUIRE(convertAndTest((xod::Number) -0.25, 0, str) == xod::XStringCString("0"));
|
||||
REQUIRE(convertAndTest((xod::Number) -0.5, 0, str) == xod::XStringCString("0"));
|
||||
REQUIRE(convertAndTest((xod::Number) -0.451, 1, str) == xod::XStringCString("-0.5"));
|
||||
REQUIRE(convertAndTest((xod::Number) -0.6, 0, str) == xod::XStringCString("-1"));
|
||||
REQUIRE(convertAndTest((xod::Number) -0.7385, 4, str) == xod::XStringCString("-0.7385"));
|
||||
REQUIRE(convertAndTest((xod::Number) -0.73855, 4, str) == xod::XStringCString("-0.7386"));
|
||||
REQUIRE(convertAndTest((xod::Number) -123.456, 0, str) == xod::XStringCString("-123"));
|
||||
REQUIRE(convertAndTest((xod::Number) -123.456, 2, str) == xod::XStringCString("-123.46"));
|
||||
}
|
||||
SECTION("NaNs") {
|
||||
REQUIRE(convertAndTest((xod::Number) NAN, 0, str) == xod::XStringCString("NaN"));
|
||||
REQUIRE(convertAndTest((xod::Number) NAN, 2, str) == xod::XStringCString("NaN"));
|
||||
}
|
||||
SECTION("Infinities") {
|
||||
REQUIRE(convertAndTest((xod::Number) INFINITY, 0, str) == xod::XStringCString("Inf"));
|
||||
REQUIRE(convertAndTest((xod::Number) INFINITY, 5, str) == xod::XStringCString("Inf"));
|
||||
REQUIRE(convertAndTest((xod::Number) -INFINITY, 0, str) == xod::XStringCString("-Inf"));
|
||||
REQUIRE(convertAndTest((xod::Number) -INFINITY, 5, str) == xod::XStringCString("-Inf"));
|
||||
}
|
||||
SECTION("Overflowing numbers") {
|
||||
REQUIRE(convertAndTest((xod::Number) 99000000000, 0, str) == xod::XStringCString("OVF"));
|
||||
REQUIRE(convertAndTest((xod::Number) 99000000000, 2, str) == xod::XStringCString("OVF"));
|
||||
REQUIRE(convertAndTest((xod::Number) -99000000000, 0, str) == xod::XStringCString("-OVF"));
|
||||
REQUIRE(convertAndTest((xod::Number) -99000000000, 2, str) == xod::XStringCString("-OVF"));
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ AVR Memory Usage
|
||||
----------------
|
||||
Device: atmega328p
|
||||
|
||||
Program: 1684 bytes (5.1% Full)
|
||||
Program: 1626 bytes (5.0% Full)
|
||||
(.text + .data + .bootloader)
|
||||
|
||||
Data: 38 bytes (1.9% Full)
|
||||
|
||||
@@ -7,12 +7,14 @@ RUNNER=$DIR/run-tests
|
||||
|
||||
g++ \
|
||||
-I../../vendor/catch2 \
|
||||
-I../../cpplib/catch2utils \
|
||||
-std=c++11 \
|
||||
-g \
|
||||
-O0 \
|
||||
-o $RUNNER \
|
||||
$DIR/test.cpp \
|
||||
$DIR/list.cpp
|
||||
$DIR/list.cpp \
|
||||
$DIR/formatNumber.cpp
|
||||
|
||||
if [[ $* == *--leak-check* ]]; then
|
||||
valgrind --leak-check=yes $RUNNER
|
||||
|
||||
@@ -73,7 +73,8 @@
|
||||
"build:tabtestWorkspace": "cpx \"../xod-tabtest/workspace/**\" \"./bundle/tabtest-workspace\"",
|
||||
"build:tabtestSrc": "cpx \"../xod-tabtest/cpp/**\" \"./bundle/tabtest-cpp\"",
|
||||
"build:catch2": "cpx \"../../vendor/catch2/**\" \"./bundle/catch2\"",
|
||||
"build:bundle": "yarn run build:workspace && yarn run build:tabtestWorkspace && yarn run build:tabtestSrc && yarn run build:catch2",
|
||||
"build:catch2utils": "cpx \"../../cpplib/catch2utils/**\" \"./bundle/catch2utils\"",
|
||||
"build:bundle": "yarn run build:workspace && yarn run build:tabtestWorkspace && yarn run build:tabtestSrc && yarn run build:catch2 && yarn run build:catch2utils",
|
||||
"build:readme": "oclif-dev readme && sed -i -e 's/lib\\/commands\\//src\\/commands\\//g' README.md",
|
||||
"build:src": "babel src/ -d lib/ --source-maps",
|
||||
"build": "yarn run build:bundle && yarn run build:src",
|
||||
|
||||
@@ -17,6 +17,7 @@ import * as myFlags from '../flags';
|
||||
import { getListr } from '../listr';
|
||||
import {
|
||||
resolveBundledCatch2Path,
|
||||
resolveBundledCatch2UtilsPath,
|
||||
resolveBundledTabtestSrcPath,
|
||||
resolveBundledTabtestWorkspacePath,
|
||||
resolveBundledWorkspacePath,
|
||||
@@ -102,6 +103,7 @@ class TabtestCommand extends BaseCommand {
|
||||
allPromises,
|
||||
append(fs.copy(resolveBundledTabtestSrcPath(), ctx.outDir)),
|
||||
append(fs.copy(resolveBundledCatch2Path(), ctx.outDir)),
|
||||
append(fs.copy(resolveBundledCatch2UtilsPath(), ctx.outDir)),
|
||||
map(([filename, content]) =>
|
||||
fs.outputFile(path.join(ctx.outDir, filename), content)
|
||||
)
|
||||
|
||||
@@ -11,3 +11,6 @@ export const resolveBundledTabtestSrcPath = () =>
|
||||
|
||||
export const resolveBundledCatch2Path = () =>
|
||||
path.resolve(__dirname, '..', 'bundle', 'catch2');
|
||||
|
||||
export const resolveBundledCatch2UtilsPath = () =>
|
||||
path.resolve(__dirname, '..', 'bundle', 'catch2utils');
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
#ifndef ARDUINO_H
|
||||
#define ARDUINO_H
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint32_t, etc
|
||||
#include <string.h> // for strlen
|
||||
#include <stdlib.h> // for fcvt
|
||||
#include <algorithm> // for min/max
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint32_t, etc
|
||||
#include <string.h> // for strlen
|
||||
#include <stdlib.h> // to bring `abs` before its redefinition below
|
||||
#include <math.h>
|
||||
|
||||
void setup();
|
||||
@@ -13,6 +14,9 @@ void loop();
|
||||
|
||||
#define A0 14
|
||||
|
||||
using ::std::min;
|
||||
using ::std::max;
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
// because all platforms' Arduino.h do it
|
||||
#ifdef abs
|
||||
|
||||
@@ -254,7 +254,7 @@ module TestCase = {
|
||||
Cpp.(
|
||||
source([
|
||||
"#include \"catch.hpp\"",
|
||||
"#include \"formatters.cpp\"",
|
||||
"#include <XStringFormat.inl>",
|
||||
"",
|
||||
source(nodeAliases),
|
||||
"",
|
||||
|
||||
@@ -262,7 +262,7 @@ bool ESP8266::createTCP(const char* addr, uint32_t port) {
|
||||
writeCmd(COMMA_2);
|
||||
print(addr);
|
||||
writeCmd(COMMA_1);
|
||||
dtostrf(port, 0, 0, _port);
|
||||
formatNumber(port, 0, _port);
|
||||
println(_port);
|
||||
|
||||
bool ok = cmdOK(OK, ERROR, 5000);
|
||||
@@ -286,7 +286,7 @@ bool ESP8266::send(char* message) {
|
||||
|
||||
size_t len = sprintf(message, "%s", message);
|
||||
char reqLen[len];
|
||||
dtostrf(len, 0, 0, reqLen);
|
||||
formatNumber(len, 0, reqLen);
|
||||
println(reqLen);
|
||||
|
||||
bool prompt = cmdOK(PROMPT, LINK_IS_NOT);
|
||||
|
||||
@@ -12,6 +12,6 @@ struct State {
|
||||
void evaluate(Context ctx) {
|
||||
auto state = getState(ctx);
|
||||
auto num = getValue<input_IN>(ctx);
|
||||
dtostrf(num, 0, 2, state->str);
|
||||
formatNumber(num, 2, state->str);
|
||||
emitValue<output_OUT>(ctx, XString(&state->view));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ struct State {
|
||||
void evaluate(Context ctx) {
|
||||
auto state = getState(ctx);
|
||||
auto num = getValue<input_IN>(ctx);
|
||||
dtostrf(num, 0, 2, state->str);
|
||||
formatNumber(num, 2, state->str);
|
||||
emitValue<output_OUT>(ctx, XString(&state->view));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,6 @@ void evaluate(Context ctx) {
|
||||
auto state = getState(ctx);
|
||||
auto num = getValue<input_NUM>(ctx);
|
||||
auto dig = getValue<input_DIG>(ctx);
|
||||
dtostrf(num, 0, dig, state->str);
|
||||
formatNumber(num, dig, state->str);
|
||||
emitValue<output_STR>(ctx, XString(&state->view));
|
||||
}
|
||||
|
||||
256
workspace/blink/__fixtures__/arduino.cpp
generated
256
workspace/blink/__fixtures__/arduino.cpp
generated
@@ -56,6 +56,24 @@ typename remove_reference<T>::type&& move(T&& a) {
|
||||
} // namespace std
|
||||
} // namespace xod
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Basic XOD types
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
namespace xod {
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
} // namespace xod
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
@@ -573,10 +591,176 @@ template<typename T> bool equal(List<T> lhs, List<T> rhs) {
|
||||
return !lhsIt && !rhsIt;
|
||||
}
|
||||
|
||||
template<typename T> bool operator == (List<T> lhs, List<T> rhs) {
|
||||
return equal(lhs, rhs);
|
||||
}
|
||||
|
||||
} // namespace xod
|
||||
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Format Numbers
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
|
||||
/**
|
||||
* Provide `formatNumber` cross-platform number to string converter function.
|
||||
*
|
||||
* Taken from here:
|
||||
* https://github.com/client9/stringencoders/blob/master/src/modp_numtoa.c
|
||||
* Original function name: `modp_dtoa2`.
|
||||
*
|
||||
* Modified:
|
||||
* - `isnan` instead of tricky comparing and return "NaN"
|
||||
* - handle Infinity values and return "Inf" or "-Inf"
|
||||
* - return `OVF` and `-OVF` for numbers bigger than max possible, instead of using `sprintf`
|
||||
* - use `Number` instead of double
|
||||
* - if negative number rounds to zero, return just "0" instead of "-0"
|
||||
*
|
||||
* This is a replacement of `dtostrf`.
|
||||
*/
|
||||
|
||||
#ifndef XOD_FORMAT_NUMBER_H
|
||||
#define XOD_FORMAT_NUMBER_H
|
||||
|
||||
namespace xod {
|
||||
|
||||
/**
|
||||
* Powers of 10
|
||||
* 10^0 to 10^9
|
||||
*/
|
||||
static const Number powers_of_10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
|
||||
10000000, 100000000, 1000000000 };
|
||||
|
||||
static void strreverse(char* begin, char* end) {
|
||||
char aux;
|
||||
while (end > begin)
|
||||
aux = *end, *end-- = *begin, *begin++ = aux;
|
||||
};
|
||||
|
||||
size_t formatNumber(Number value, int prec, char* str) {
|
||||
if (isnan(value)) {
|
||||
strcpy(str, "NaN");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
if (isinf(value)) {
|
||||
bool isNegative = value < 0;
|
||||
strcpy(str, isNegative ? "-Inf" : "Inf");
|
||||
return (size_t)isNegative ? 4 : 3;
|
||||
}
|
||||
|
||||
/* if input is larger than thres_max return "OVF" */
|
||||
const Number thres_max = (Number)(0x7FFFFFFF);
|
||||
|
||||
Number diff = 0.0;
|
||||
char* wstr = str;
|
||||
|
||||
if (prec < 0) {
|
||||
prec = 0;
|
||||
} else if (prec > 9) {
|
||||
/* precision of >= 10 can lead to overflow errors */
|
||||
prec = 9;
|
||||
}
|
||||
|
||||
/* we'll work in positive values and deal with the
|
||||
negative sign issue later */
|
||||
int neg = 0;
|
||||
if (value < 0) {
|
||||
neg = 1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
Number tmp = (value - whole) * powers_of_10[prec];
|
||||
uint32_t frac = (uint32_t)(tmp);
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
/* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec > 0 && (frac & 1)) {
|
||||
/* if halfway, round up if odd, OR
|
||||
if last digit is 0. That last part is strange */
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec == 0 && (whole & 1)) {
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
|
||||
if (value > thres_max) {
|
||||
if (neg) {
|
||||
strcpy(str, "-OVF");
|
||||
return (size_t)4;
|
||||
}
|
||||
strcpy(str, "OVF");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
int has_decimal = 0;
|
||||
int count = prec;
|
||||
bool notzero = frac > 0;
|
||||
|
||||
/* Remove ending zeros */
|
||||
if (prec > 0) {
|
||||
while (count > 0 && ((frac % 10) == 0)) {
|
||||
count--;
|
||||
frac /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
while (count > 0) {
|
||||
--count;
|
||||
*wstr++ = (char)(48 + (frac % 10));
|
||||
frac /= 10;
|
||||
has_decimal = 1;
|
||||
}
|
||||
|
||||
if (frac > 0) {
|
||||
++whole;
|
||||
}
|
||||
|
||||
/* add decimal */
|
||||
if (has_decimal) {
|
||||
*wstr++ = '.';
|
||||
}
|
||||
|
||||
notzero = notzero || whole > 0;
|
||||
|
||||
/* do whole part
|
||||
* Take care of sign conversion
|
||||
* Number is reversed.
|
||||
*/
|
||||
do
|
||||
*wstr++ = (char)(48 + (whole % 10));
|
||||
while (whole /= 10);
|
||||
|
||||
if (neg && notzero) {
|
||||
*wstr++ = '-';
|
||||
}
|
||||
*wstr = '\0';
|
||||
strreverse(str, wstr - 1);
|
||||
return (size_t)(wstr - str);
|
||||
}
|
||||
|
||||
} // namespace xod
|
||||
#endif
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
@@ -621,79 +805,7 @@ template<typename T> bool equal(List<T> lhs, List<T> rhs) {
|
||||
# define pgm_read_ptr(addr) (*(const void **)(addr))
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Compatibilities
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if !defined(ARDUINO_ARCH_AVR) && !defined(__DTOSTRF_H_)
|
||||
/*
|
||||
* Provide dtostrf function for non-AVR platforms. Although many platforms
|
||||
* provide a stub many others do not. And the stub is based on `sprintf`
|
||||
* which doesn’t work with floating point formatters on some platforms
|
||||
* (e.g. Arduino M0).
|
||||
*
|
||||
* This is an implementation based on `fcvt` standard function. Taken here:
|
||||
* https://forum.arduino.cc/index.php?topic=368720.msg2542614#msg2542614
|
||||
*/
|
||||
char *dtostrf(double val, int width, unsigned int prec, char *sout) {
|
||||
int decpt, sign, reqd, pad;
|
||||
const char *s, *e;
|
||||
char *p;
|
||||
s = fcvt(val, prec, &decpt, &sign);
|
||||
if (prec == 0 && decpt == 0) {
|
||||
s = (*s < '5') ? "0" : "1";
|
||||
reqd = 1;
|
||||
} else {
|
||||
reqd = strlen(s);
|
||||
if (reqd > decpt) reqd++;
|
||||
if (decpt == 0) reqd++;
|
||||
}
|
||||
if (sign) reqd++;
|
||||
p = sout;
|
||||
e = p + reqd;
|
||||
pad = width - reqd;
|
||||
if (pad > 0) {
|
||||
e += pad;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
if (sign) *p++ = '-';
|
||||
if (decpt <= 0 && prec > 0) {
|
||||
*p++ = '0';
|
||||
*p++ = '.';
|
||||
e++;
|
||||
while ( decpt < 0 ) {
|
||||
decpt++;
|
||||
*p++ = '0';
|
||||
}
|
||||
}
|
||||
while (p < e) {
|
||||
*p++ = *s++;
|
||||
if (p == e) break;
|
||||
if (--decpt == 0) *p++ = '.';
|
||||
}
|
||||
if (width < 0) {
|
||||
pad = (reqd + width) * -1;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
*p = 0;
|
||||
return sout;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace xod {
|
||||
//----------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
//----------------------------------------------------------------------------
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Global variables
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Binary file not shown.
@@ -2,7 +2,7 @@
|
||||
:100010000C9479000C9479000C9479000C9479007C
|
||||
:100020000C9479000C9479000C9479000C9479006C
|
||||
:100030000C9479000C9479000C9479000C9479005C
|
||||
:100040000C9474020C9479000C9479000C9479004F
|
||||
:100040000C9460020C9479000C9479000C94790063
|
||||
:100050000C9479000C9479000C9479000C9479003C
|
||||
:100060000C9479000C947900000000002400270013
|
||||
:100070002A0000000000250028002B0004040404CE
|
||||
@@ -10,97 +10,95 @@
|
||||
:10009000010204081020408001020408102001021F
|
||||
:1000A00004081020000000080002010000030407FB
|
||||
:1000B000000000000000000011241FBECFEFD8E0B8
|
||||
:1000C000DEBFCDBF11E0A0E0B1E0EAE6F6E002C09D
|
||||
:1000C000DEBFCDBF11E0A0E0B1E0E2E4F6E002C0A7
|
||||
:1000D00005900D92A831B107D9F721E0A8E1B1E070
|
||||
:1000E00001C01D92A632B207E1F70E94BE020C9435
|
||||
:1000F00033030C9400003FB7F89480912201909153
|
||||
:1000E00001C01D92A632B207E1F70E94AA020C9449
|
||||
:1000F0001F030C9400003FB7F89480912201909167
|
||||
:100100002301A0912401B091250126B5A89B05C02B
|
||||
:100110002F3F19F00196A11DB11D3FBFBA2FA92F86
|
||||
:10012000982F8827820F911DA11DB11DBC01CD0103
|
||||
:1001300042E0660F771F881F991F4A95D1F70895EF
|
||||
:1001400080E090E0892B49F080E090E0892B29F055
|
||||
:100150000E94000081110C94000008950F931F93DA
|
||||
:100160002FB7F89480911E0190911F01A09120015A
|
||||
:10017000B09121012FBF8093180190931901A09392
|
||||
:100180001A01B0931B01409112015091130160912B
|
||||
:10019000140170911501411551056105710531F08A
|
||||
:1001A00021E0481759076A077B0708F020E0809193
|
||||
:1001B000170181FB992790F9292B20FB81F9809366
|
||||
:1001C000170140910B0150910C0160910D0170914C
|
||||
:1001D0000E01411551056105710571F031E0809105
|
||||
:1001E000180190911901A0911A01B0911B014817B3
|
||||
:1001F00059076A077B0708F030E08091100181FB06
|
||||
:10020000992790F9932B90FB81F980931001222379
|
||||
:10021000E9F081E08093160180911701816080935D
|
||||
:100220001701009118011091190120911A013091C4
|
||||
:100230001B010093120110931301209314013093BA
|
||||
:100240001501809106018460809306019923F1F1E4
|
||||
:10025000E0911C01009118011091190120911A01DF
|
||||
:1002600030911B01D901C80186509F4FAF4FBF4F3E
|
||||
:10027000411551056105710531F0401751076207BD
|
||||
:10028000730708F415C1EE23A1F0409107015091C6
|
||||
:1002900008016091090170910A0140175107620736
|
||||
:1002A000730708F4EBC084179507A607B70708F48F
|
||||
:1002B000E5C09091100191708091020181FB22278D
|
||||
:1002C00020F9922B90FB81F9809302018091020129
|
||||
:1002D00081FF20C0909101018091100180FF03C037
|
||||
:1002E00081E0892701C080E0891739F080930101FE
|
||||
:1002F00080910201816080930201909102019170CE
|
||||
:100300008091060182FB222720F9922B90FB82F933
|
||||
:10031000809306018091060182FF6CC0609101010B
|
||||
:100320008091170180FF66C04DE950E0FA01749199
|
||||
:1003300089E890E0FC012491222399F030E0220F1B
|
||||
:10034000331FF901E859FF4FA591B4912E583F4F43
|
||||
:10035000F901059114912FB7F8943C91732B7C937C
|
||||
:100360002FBFE1EBF0E02491FA014491FC0194915C
|
||||
:10037000992309F43CC0222339F1233091F038F459
|
||||
:100380002130A9F0223001F584B58F7D12C02730CD
|
||||
:1003900091F02830A1F02430B9F4809180008F7D55
|
||||
:1003A00003C0809180008F77809380000DC084B55A
|
||||
:1003B0008F7784BD09C08091B0008F7703C0809192
|
||||
:1003C000B0008F7D8093B000E92FF0E0EE0FFF1FAB
|
||||
:1003D000EE58FF4FA591B4918FB7F8949C9161119D
|
||||
:1003E00003C04095492301C0492B4C938FBF81E046
|
||||
:1003F00080930401109217011092100110920201D3
|
||||
:10040000109206018091120190911301A0911401A4
|
||||
:10041000B09115010097A105B10569F0409118014F
|
||||
:100420005091190160911A0170911B018417950771
|
||||
:10043000A607B707A0F180910B0190910C01A09144
|
||||
:100440000D01B0910E010097A105B10509F449C055
|
||||
:10045000409118015091190160911A0170911B018E
|
||||
:1004600084179507A607B707E0F510920B011092C5
|
||||
:100470000C0110920D0110920E0133C08093070100
|
||||
:1004800090930801A0930901B0930A0180930B0196
|
||||
:1004900090930C01A0930D01B0930E010ACF10921E
|
||||
:1004A0001201109213011092140110921501C3CF82
|
||||
:1004B00041E040930F0140911001416040931001D1
|
||||
:1004C0008093070190930801A0930901B0930A015A
|
||||
:1004D00080930B0190930C01A0930D01B0930E013A
|
||||
:1004E000D2CE1F910F9108951F920F920FB60F92C7
|
||||
:1004F00011242F933F938F939F93AF93BF9380913A
|
||||
:100500001E0190911F01A0912001B0912101309115
|
||||
:100510001D0123E0230F2D3720F40196A11DB11DED
|
||||
:1005200005C026E8230F0296A11DB11D20931D01D1
|
||||
:1005300080931E0190931F01A0932001B09321018D
|
||||
:100540008091220190912301A0912401B091250175
|
||||
:100550000196A11DB11D8093220190932301A093C8
|
||||
:100560002401B0932501BF91AF919F918F913F914D
|
||||
:100570002F910F900FBE0F901F901895789484B50F
|
||||
:10058000826084BD84B5816084BD85B5826085BD8F
|
||||
:1005900085B5816085BD80916E00816080936E001D
|
||||
:1005A000109281008091810082608093810080910F
|
||||
:1005B00081008160809381008091800081608093C0
|
||||
:1005C00080008091B10084608093B1008091B00080
|
||||
:1005D00081608093B00080917A00846080937A007B
|
||||
:1005E00080917A00826080937A0080917A008160A5
|
||||
:1005F00080937A0080917A00806880937A001092CC
|
||||
:10060000C1000E947B004B015C0184E6C82ED12C06
|
||||
:10061000E12CF12C0E947B00DC01CB0188199909A7
|
||||
:10062000AA09BB09883E9340A105B10558F021E015
|
||||
:10063000C21AD108E108F10888EE880E83E0981EFE
|
||||
:10064000A11CB11CC114D104E104F10419F781E02B
|
||||
:1006500080931C010E94AE0010921C010E94AE000B
|
||||
:0A0660000E94A000FBCFF894FFCF2A
|
||||
:10066A000000030000000400000000000000000079
|
||||
:08067A00020000000000000274
|
||||
:10016000FC01448155816681778141155105610506
|
||||
:10017000710571F081E00091180110911901209131
|
||||
:100180001A0130911B01401751076207730708F0ED
|
||||
:1001900080E01F910F9108958F929F92AF92BF922E
|
||||
:1001A000CF92DF92EF92FF92CF93DF938FB7F894C5
|
||||
:1001B00080901E0190901F01A0902001B09021011D
|
||||
:1001C0008FBF8092180190921901A0921A01B092EB
|
||||
:1001D0001B01409112015091130160911401709123
|
||||
:1001E0001501411551056105710531F081E0481592
|
||||
:1001F00059056A057B0508F080E0C0911701C1FB35
|
||||
:10020000DD27D0F9D82BD0FBC1F9C093170187E0C7
|
||||
:1002100091E00E94AE009091100191FB222720F9FD
|
||||
:10022000822B80FB91F990931001DD2399F091E0EE
|
||||
:1002300090931601C160C0931701809212019092B1
|
||||
:100240001301A0921401B0921501909106019460DF
|
||||
:1002500090930601882391F1C0911C0175016401FE
|
||||
:100260008AEFC80ED11CE11CF11C87E091E00E94CE
|
||||
:10027000AE008111E7C0CC23A1F0809107019091DD
|
||||
:100280000801A0910901B0910A0188159905AA05F4
|
||||
:10029000BB0508F4F0C0C816D906EA06FB0608F448
|
||||
:1002A000EAC08091020181FB222720F99091100180
|
||||
:1002B0009170922B90FB81F9809302018091020151
|
||||
:1002C00081FF20C0909101018091100180FF03C047
|
||||
:1002D00081E0892701C080E0981739F080930101FF
|
||||
:1002E000809102018160809302018091060182FB6E
|
||||
:1002F000222720F9909102019170922B90FB82F9B4
|
||||
:10030000809306018091060182FF6CC0609101011B
|
||||
:100310008091170180FF66C04DE950E0FA017491A9
|
||||
:1003200089E890E0FC012491222399F030E0220F2B
|
||||
:10033000331FF901E859FF4FA591B491F901EE5827
|
||||
:10034000FF4F259134913FB7F8942C91272B2C9394
|
||||
:100350003FBFE1EBF0E02491FA014491FC0194915C
|
||||
:10036000992309F43CC0222339F1233091F038F469
|
||||
:100370002130A9F0223001F584B58F7D12C02730DD
|
||||
:1003800091F02830A1F02430B9F4809180008F7D65
|
||||
:1003900003C0809180008F77809380000DC084B56A
|
||||
:1003A0008F7784BD09C08091B0008F7703C08091A2
|
||||
:1003B000B0008F7D8093B000E92FF0E0EE0FFF1FBB
|
||||
:1003C000EE58FF4FA591B4919FB7F8948C916111AD
|
||||
:1003D00003C04095482301C0482B4C939FBF81E048
|
||||
:1003E00080930401109217011092100110920201E3
|
||||
:1003F000109206018091120190911301A0911401B5
|
||||
:10040000B09115010097A105B10569F0409118015F
|
||||
:100410005091190160911A0170911B018417950781
|
||||
:10042000A607B707C8F187E091E00E94AE008823D5
|
||||
:10043000E1F110920B0110920C0110920D0110923B
|
||||
:100440000E0133C081E080930F0180911001816023
|
||||
:1004500080931001C0920701D0920801E092090137
|
||||
:10046000F0920A01C0920B01D0920C01E0920D01B2
|
||||
:10047000F0920E0100CFC0920701D0920801E092E5
|
||||
:100480000901F0920A01C0920B01D0920C01E09296
|
||||
:100490000D01F0920E0105CF10921201109213017E
|
||||
:1004A0001092140110921501BECFDF91CF91FF90F1
|
||||
:1004B000EF90DF90CF90BF90AF909F908F90089576
|
||||
:1004C0001F920F920FB60F9211242F933F938F9389
|
||||
:1004D0009F93AF93BF9380911E0190911F01A091B4
|
||||
:1004E0002001B091210130911D0123E0230F2D3710
|
||||
:1004F00020F40196A11DB11D05C026E8230F029628
|
||||
:10050000A11DB11D20931D0180931E0190931F0119
|
||||
:10051000A0932001B09321018091220190912301A9
|
||||
:10052000A0912401B09125010196A11DB11D8093D8
|
||||
:10053000220190932301A0932401B0932501BF9140
|
||||
:10054000AF919F918F913F912F910F900FBE0F9080
|
||||
:100550001F901895789484B5826084BD84B58160BD
|
||||
:1005600084BD85B5826085BD85B5816085BD80917E
|
||||
:100570006E00816080936E001092810080918100F6
|
||||
:1005800082608093810080918100816080938100EE
|
||||
:10059000809180008160809380008091B1008460B0
|
||||
:1005A0008093B1008091B00081608093B000809111
|
||||
:1005B0007A00846080937A0080917A0082608093D0
|
||||
:1005C0007A0080917A00816080937A0080917A002D
|
||||
:1005D000806880937A001092C1000E947B004B01DA
|
||||
:1005E0005C0184E6C82ED12CE12CF12C0E947B000A
|
||||
:1005F000DC01CB0188199909AA09BB09883E9340FF
|
||||
:10060000A105B10598F321E0C21AD108E108F1086B
|
||||
:1006100088EE880E83E0981EA11CB11CC114D10481
|
||||
:10062000E104F10419F781E080931C010E94CC00E1
|
||||
:1006300010921C010E94CC000E94A000FBCFF894F5
|
||||
:02064000FFCFEA
|
||||
:1006420000000300000004000000000000000000A1
|
||||
:0806520002000000000000029C
|
||||
:00000001FF
|
||||
|
||||
@@ -56,6 +56,24 @@ typename remove_reference<T>::type&& move(T&& a) {
|
||||
} // namespace std
|
||||
} // namespace xod
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Basic XOD types
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
namespace xod {
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
} // namespace xod
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
@@ -573,10 +591,176 @@ template<typename T> bool equal(List<T> lhs, List<T> rhs) {
|
||||
return !lhsIt && !rhsIt;
|
||||
}
|
||||
|
||||
template<typename T> bool operator == (List<T> lhs, List<T> rhs) {
|
||||
return equal(lhs, rhs);
|
||||
}
|
||||
|
||||
} // namespace xod
|
||||
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Format Numbers
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
|
||||
/**
|
||||
* Provide `formatNumber` cross-platform number to string converter function.
|
||||
*
|
||||
* Taken from here:
|
||||
* https://github.com/client9/stringencoders/blob/master/src/modp_numtoa.c
|
||||
* Original function name: `modp_dtoa2`.
|
||||
*
|
||||
* Modified:
|
||||
* - `isnan` instead of tricky comparing and return "NaN"
|
||||
* - handle Infinity values and return "Inf" or "-Inf"
|
||||
* - return `OVF` and `-OVF` for numbers bigger than max possible, instead of using `sprintf`
|
||||
* - use `Number` instead of double
|
||||
* - if negative number rounds to zero, return just "0" instead of "-0"
|
||||
*
|
||||
* This is a replacement of `dtostrf`.
|
||||
*/
|
||||
|
||||
#ifndef XOD_FORMAT_NUMBER_H
|
||||
#define XOD_FORMAT_NUMBER_H
|
||||
|
||||
namespace xod {
|
||||
|
||||
/**
|
||||
* Powers of 10
|
||||
* 10^0 to 10^9
|
||||
*/
|
||||
static const Number powers_of_10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
|
||||
10000000, 100000000, 1000000000 };
|
||||
|
||||
static void strreverse(char* begin, char* end) {
|
||||
char aux;
|
||||
while (end > begin)
|
||||
aux = *end, *end-- = *begin, *begin++ = aux;
|
||||
};
|
||||
|
||||
size_t formatNumber(Number value, int prec, char* str) {
|
||||
if (isnan(value)) {
|
||||
strcpy(str, "NaN");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
if (isinf(value)) {
|
||||
bool isNegative = value < 0;
|
||||
strcpy(str, isNegative ? "-Inf" : "Inf");
|
||||
return (size_t)isNegative ? 4 : 3;
|
||||
}
|
||||
|
||||
/* if input is larger than thres_max return "OVF" */
|
||||
const Number thres_max = (Number)(0x7FFFFFFF);
|
||||
|
||||
Number diff = 0.0;
|
||||
char* wstr = str;
|
||||
|
||||
if (prec < 0) {
|
||||
prec = 0;
|
||||
} else if (prec > 9) {
|
||||
/* precision of >= 10 can lead to overflow errors */
|
||||
prec = 9;
|
||||
}
|
||||
|
||||
/* we'll work in positive values and deal with the
|
||||
negative sign issue later */
|
||||
int neg = 0;
|
||||
if (value < 0) {
|
||||
neg = 1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
Number tmp = (value - whole) * powers_of_10[prec];
|
||||
uint32_t frac = (uint32_t)(tmp);
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
/* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec > 0 && (frac & 1)) {
|
||||
/* if halfway, round up if odd, OR
|
||||
if last digit is 0. That last part is strange */
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec == 0 && (whole & 1)) {
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
|
||||
if (value > thres_max) {
|
||||
if (neg) {
|
||||
strcpy(str, "-OVF");
|
||||
return (size_t)4;
|
||||
}
|
||||
strcpy(str, "OVF");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
int has_decimal = 0;
|
||||
int count = prec;
|
||||
bool notzero = frac > 0;
|
||||
|
||||
/* Remove ending zeros */
|
||||
if (prec > 0) {
|
||||
while (count > 0 && ((frac % 10) == 0)) {
|
||||
count--;
|
||||
frac /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
while (count > 0) {
|
||||
--count;
|
||||
*wstr++ = (char)(48 + (frac % 10));
|
||||
frac /= 10;
|
||||
has_decimal = 1;
|
||||
}
|
||||
|
||||
if (frac > 0) {
|
||||
++whole;
|
||||
}
|
||||
|
||||
/* add decimal */
|
||||
if (has_decimal) {
|
||||
*wstr++ = '.';
|
||||
}
|
||||
|
||||
notzero = notzero || whole > 0;
|
||||
|
||||
/* do whole part
|
||||
* Take care of sign conversion
|
||||
* Number is reversed.
|
||||
*/
|
||||
do
|
||||
*wstr++ = (char)(48 + (whole % 10));
|
||||
while (whole /= 10);
|
||||
|
||||
if (neg && notzero) {
|
||||
*wstr++ = '-';
|
||||
}
|
||||
*wstr = '\0';
|
||||
strreverse(str, wstr - 1);
|
||||
return (size_t)(wstr - str);
|
||||
}
|
||||
|
||||
} // namespace xod
|
||||
#endif
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
@@ -621,79 +805,7 @@ template<typename T> bool equal(List<T> lhs, List<T> rhs) {
|
||||
# define pgm_read_ptr(addr) (*(const void **)(addr))
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Compatibilities
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if !defined(ARDUINO_ARCH_AVR) && !defined(__DTOSTRF_H_)
|
||||
/*
|
||||
* Provide dtostrf function for non-AVR platforms. Although many platforms
|
||||
* provide a stub many others do not. And the stub is based on `sprintf`
|
||||
* which doesn’t work with floating point formatters on some platforms
|
||||
* (e.g. Arduino M0).
|
||||
*
|
||||
* This is an implementation based on `fcvt` standard function. Taken here:
|
||||
* https://forum.arduino.cc/index.php?topic=368720.msg2542614#msg2542614
|
||||
*/
|
||||
char *dtostrf(double val, int width, unsigned int prec, char *sout) {
|
||||
int decpt, sign, reqd, pad;
|
||||
const char *s, *e;
|
||||
char *p;
|
||||
s = fcvt(val, prec, &decpt, &sign);
|
||||
if (prec == 0 && decpt == 0) {
|
||||
s = (*s < '5') ? "0" : "1";
|
||||
reqd = 1;
|
||||
} else {
|
||||
reqd = strlen(s);
|
||||
if (reqd > decpt) reqd++;
|
||||
if (decpt == 0) reqd++;
|
||||
}
|
||||
if (sign) reqd++;
|
||||
p = sout;
|
||||
e = p + reqd;
|
||||
pad = width - reqd;
|
||||
if (pad > 0) {
|
||||
e += pad;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
if (sign) *p++ = '-';
|
||||
if (decpt <= 0 && prec > 0) {
|
||||
*p++ = '0';
|
||||
*p++ = '.';
|
||||
e++;
|
||||
while ( decpt < 0 ) {
|
||||
decpt++;
|
||||
*p++ = '0';
|
||||
}
|
||||
}
|
||||
while (p < e) {
|
||||
*p++ = *s++;
|
||||
if (p == e) break;
|
||||
if (--decpt == 0) *p++ = '.';
|
||||
}
|
||||
if (width < 0) {
|
||||
pad = (reqd + width) * -1;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
*p = 0;
|
||||
return sout;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace xod {
|
||||
//----------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
//----------------------------------------------------------------------------
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Global variables
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -1685,7 +1797,7 @@ State* getState(Context ctx) {
|
||||
void evaluate(Context ctx) {
|
||||
auto state = getState(ctx);
|
||||
auto num = getValue<input_IN>(ctx);
|
||||
dtostrf(num, 0, 2, state->str);
|
||||
formatNumber(num, 2, state->str);
|
||||
emitValue<output_OUT>(ctx, XString(&state->view));
|
||||
}
|
||||
|
||||
|
||||
258
workspace/lcd-time/__fixtures__/arduino.cpp
generated
258
workspace/lcd-time/__fixtures__/arduino.cpp
generated
@@ -56,6 +56,24 @@ typename remove_reference<T>::type&& move(T&& a) {
|
||||
} // namespace std
|
||||
} // namespace xod
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Basic XOD types
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
namespace xod {
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
} // namespace xod
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
@@ -573,10 +591,176 @@ template<typename T> bool equal(List<T> lhs, List<T> rhs) {
|
||||
return !lhsIt && !rhsIt;
|
||||
}
|
||||
|
||||
template<typename T> bool operator == (List<T> lhs, List<T> rhs) {
|
||||
return equal(lhs, rhs);
|
||||
}
|
||||
|
||||
} // namespace xod
|
||||
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Format Numbers
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
|
||||
/**
|
||||
* Provide `formatNumber` cross-platform number to string converter function.
|
||||
*
|
||||
* Taken from here:
|
||||
* https://github.com/client9/stringencoders/blob/master/src/modp_numtoa.c
|
||||
* Original function name: `modp_dtoa2`.
|
||||
*
|
||||
* Modified:
|
||||
* - `isnan` instead of tricky comparing and return "NaN"
|
||||
* - handle Infinity values and return "Inf" or "-Inf"
|
||||
* - return `OVF` and `-OVF` for numbers bigger than max possible, instead of using `sprintf`
|
||||
* - use `Number` instead of double
|
||||
* - if negative number rounds to zero, return just "0" instead of "-0"
|
||||
*
|
||||
* This is a replacement of `dtostrf`.
|
||||
*/
|
||||
|
||||
#ifndef XOD_FORMAT_NUMBER_H
|
||||
#define XOD_FORMAT_NUMBER_H
|
||||
|
||||
namespace xod {
|
||||
|
||||
/**
|
||||
* Powers of 10
|
||||
* 10^0 to 10^9
|
||||
*/
|
||||
static const Number powers_of_10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
|
||||
10000000, 100000000, 1000000000 };
|
||||
|
||||
static void strreverse(char* begin, char* end) {
|
||||
char aux;
|
||||
while (end > begin)
|
||||
aux = *end, *end-- = *begin, *begin++ = aux;
|
||||
};
|
||||
|
||||
size_t formatNumber(Number value, int prec, char* str) {
|
||||
if (isnan(value)) {
|
||||
strcpy(str, "NaN");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
if (isinf(value)) {
|
||||
bool isNegative = value < 0;
|
||||
strcpy(str, isNegative ? "-Inf" : "Inf");
|
||||
return (size_t)isNegative ? 4 : 3;
|
||||
}
|
||||
|
||||
/* if input is larger than thres_max return "OVF" */
|
||||
const Number thres_max = (Number)(0x7FFFFFFF);
|
||||
|
||||
Number diff = 0.0;
|
||||
char* wstr = str;
|
||||
|
||||
if (prec < 0) {
|
||||
prec = 0;
|
||||
} else if (prec > 9) {
|
||||
/* precision of >= 10 can lead to overflow errors */
|
||||
prec = 9;
|
||||
}
|
||||
|
||||
/* we'll work in positive values and deal with the
|
||||
negative sign issue later */
|
||||
int neg = 0;
|
||||
if (value < 0) {
|
||||
neg = 1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
Number tmp = (value - whole) * powers_of_10[prec];
|
||||
uint32_t frac = (uint32_t)(tmp);
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
/* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec > 0 && (frac & 1)) {
|
||||
/* if halfway, round up if odd, OR
|
||||
if last digit is 0. That last part is strange */
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec == 0 && (whole & 1)) {
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
|
||||
if (value > thres_max) {
|
||||
if (neg) {
|
||||
strcpy(str, "-OVF");
|
||||
return (size_t)4;
|
||||
}
|
||||
strcpy(str, "OVF");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
int has_decimal = 0;
|
||||
int count = prec;
|
||||
bool notzero = frac > 0;
|
||||
|
||||
/* Remove ending zeros */
|
||||
if (prec > 0) {
|
||||
while (count > 0 && ((frac % 10) == 0)) {
|
||||
count--;
|
||||
frac /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
while (count > 0) {
|
||||
--count;
|
||||
*wstr++ = (char)(48 + (frac % 10));
|
||||
frac /= 10;
|
||||
has_decimal = 1;
|
||||
}
|
||||
|
||||
if (frac > 0) {
|
||||
++whole;
|
||||
}
|
||||
|
||||
/* add decimal */
|
||||
if (has_decimal) {
|
||||
*wstr++ = '.';
|
||||
}
|
||||
|
||||
notzero = notzero || whole > 0;
|
||||
|
||||
/* do whole part
|
||||
* Take care of sign conversion
|
||||
* Number is reversed.
|
||||
*/
|
||||
do
|
||||
*wstr++ = (char)(48 + (whole % 10));
|
||||
while (whole /= 10);
|
||||
|
||||
if (neg && notzero) {
|
||||
*wstr++ = '-';
|
||||
}
|
||||
*wstr = '\0';
|
||||
strreverse(str, wstr - 1);
|
||||
return (size_t)(wstr - str);
|
||||
}
|
||||
|
||||
} // namespace xod
|
||||
#endif
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
@@ -621,79 +805,7 @@ template<typename T> bool equal(List<T> lhs, List<T> rhs) {
|
||||
# define pgm_read_ptr(addr) (*(const void **)(addr))
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Compatibilities
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if !defined(ARDUINO_ARCH_AVR) && !defined(__DTOSTRF_H_)
|
||||
/*
|
||||
* Provide dtostrf function for non-AVR platforms. Although many platforms
|
||||
* provide a stub many others do not. And the stub is based on `sprintf`
|
||||
* which doesn’t work with floating point formatters on some platforms
|
||||
* (e.g. Arduino M0).
|
||||
*
|
||||
* This is an implementation based on `fcvt` standard function. Taken here:
|
||||
* https://forum.arduino.cc/index.php?topic=368720.msg2542614#msg2542614
|
||||
*/
|
||||
char *dtostrf(double val, int width, unsigned int prec, char *sout) {
|
||||
int decpt, sign, reqd, pad;
|
||||
const char *s, *e;
|
||||
char *p;
|
||||
s = fcvt(val, prec, &decpt, &sign);
|
||||
if (prec == 0 && decpt == 0) {
|
||||
s = (*s < '5') ? "0" : "1";
|
||||
reqd = 1;
|
||||
} else {
|
||||
reqd = strlen(s);
|
||||
if (reqd > decpt) reqd++;
|
||||
if (decpt == 0) reqd++;
|
||||
}
|
||||
if (sign) reqd++;
|
||||
p = sout;
|
||||
e = p + reqd;
|
||||
pad = width - reqd;
|
||||
if (pad > 0) {
|
||||
e += pad;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
if (sign) *p++ = '-';
|
||||
if (decpt <= 0 && prec > 0) {
|
||||
*p++ = '0';
|
||||
*p++ = '.';
|
||||
e++;
|
||||
while ( decpt < 0 ) {
|
||||
decpt++;
|
||||
*p++ = '0';
|
||||
}
|
||||
}
|
||||
while (p < e) {
|
||||
*p++ = *s++;
|
||||
if (p == e) break;
|
||||
if (--decpt == 0) *p++ = '.';
|
||||
}
|
||||
if (width < 0) {
|
||||
pad = (reqd + width) * -1;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
*p = 0;
|
||||
return sout;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace xod {
|
||||
//----------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
//----------------------------------------------------------------------------
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Global variables
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -1065,7 +1177,7 @@ State* getState(Context ctx) {
|
||||
void evaluate(Context ctx) {
|
||||
auto state = getState(ctx);
|
||||
auto num = getValue<input_IN>(ctx);
|
||||
dtostrf(num, 0, 2, state->str);
|
||||
formatNumber(num, 2, state->str);
|
||||
emitValue<output_OUT>(ctx, XString(&state->view));
|
||||
}
|
||||
|
||||
|
||||
256
workspace/two-button-switch/__fixtures__/arduino.cpp
generated
256
workspace/two-button-switch/__fixtures__/arduino.cpp
generated
@@ -56,6 +56,24 @@ typename remove_reference<T>::type&& move(T&& a) {
|
||||
} // namespace std
|
||||
} // namespace xod
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Basic XOD types
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
namespace xod {
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
} // namespace xod
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
@@ -573,10 +591,176 @@ template<typename T> bool equal(List<T> lhs, List<T> rhs) {
|
||||
return !lhsIt && !rhsIt;
|
||||
}
|
||||
|
||||
template<typename T> bool operator == (List<T> lhs, List<T> rhs) {
|
||||
return equal(lhs, rhs);
|
||||
}
|
||||
|
||||
} // namespace xod
|
||||
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
*
|
||||
* Format Numbers
|
||||
*
|
||||
*
|
||||
=============================================================================*/
|
||||
|
||||
/**
|
||||
* Provide `formatNumber` cross-platform number to string converter function.
|
||||
*
|
||||
* Taken from here:
|
||||
* https://github.com/client9/stringencoders/blob/master/src/modp_numtoa.c
|
||||
* Original function name: `modp_dtoa2`.
|
||||
*
|
||||
* Modified:
|
||||
* - `isnan` instead of tricky comparing and return "NaN"
|
||||
* - handle Infinity values and return "Inf" or "-Inf"
|
||||
* - return `OVF` and `-OVF` for numbers bigger than max possible, instead of using `sprintf`
|
||||
* - use `Number` instead of double
|
||||
* - if negative number rounds to zero, return just "0" instead of "-0"
|
||||
*
|
||||
* This is a replacement of `dtostrf`.
|
||||
*/
|
||||
|
||||
#ifndef XOD_FORMAT_NUMBER_H
|
||||
#define XOD_FORMAT_NUMBER_H
|
||||
|
||||
namespace xod {
|
||||
|
||||
/**
|
||||
* Powers of 10
|
||||
* 10^0 to 10^9
|
||||
*/
|
||||
static const Number powers_of_10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
|
||||
10000000, 100000000, 1000000000 };
|
||||
|
||||
static void strreverse(char* begin, char* end) {
|
||||
char aux;
|
||||
while (end > begin)
|
||||
aux = *end, *end-- = *begin, *begin++ = aux;
|
||||
};
|
||||
|
||||
size_t formatNumber(Number value, int prec, char* str) {
|
||||
if (isnan(value)) {
|
||||
strcpy(str, "NaN");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
if (isinf(value)) {
|
||||
bool isNegative = value < 0;
|
||||
strcpy(str, isNegative ? "-Inf" : "Inf");
|
||||
return (size_t)isNegative ? 4 : 3;
|
||||
}
|
||||
|
||||
/* if input is larger than thres_max return "OVF" */
|
||||
const Number thres_max = (Number)(0x7FFFFFFF);
|
||||
|
||||
Number diff = 0.0;
|
||||
char* wstr = str;
|
||||
|
||||
if (prec < 0) {
|
||||
prec = 0;
|
||||
} else if (prec > 9) {
|
||||
/* precision of >= 10 can lead to overflow errors */
|
||||
prec = 9;
|
||||
}
|
||||
|
||||
/* we'll work in positive values and deal with the
|
||||
negative sign issue later */
|
||||
int neg = 0;
|
||||
if (value < 0) {
|
||||
neg = 1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
Number tmp = (value - whole) * powers_of_10[prec];
|
||||
uint32_t frac = (uint32_t)(tmp);
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
/* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec > 0 && (frac & 1)) {
|
||||
/* if halfway, round up if odd, OR
|
||||
if last digit is 0. That last part is strange */
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff == 0.5 && prec == 0 && (whole & 1)) {
|
||||
++frac;
|
||||
if (frac >= powers_of_10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
}
|
||||
|
||||
if (value > thres_max) {
|
||||
if (neg) {
|
||||
strcpy(str, "-OVF");
|
||||
return (size_t)4;
|
||||
}
|
||||
strcpy(str, "OVF");
|
||||
return (size_t)3;
|
||||
}
|
||||
|
||||
int has_decimal = 0;
|
||||
int count = prec;
|
||||
bool notzero = frac > 0;
|
||||
|
||||
/* Remove ending zeros */
|
||||
if (prec > 0) {
|
||||
while (count > 0 && ((frac % 10) == 0)) {
|
||||
count--;
|
||||
frac /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
while (count > 0) {
|
||||
--count;
|
||||
*wstr++ = (char)(48 + (frac % 10));
|
||||
frac /= 10;
|
||||
has_decimal = 1;
|
||||
}
|
||||
|
||||
if (frac > 0) {
|
||||
++whole;
|
||||
}
|
||||
|
||||
/* add decimal */
|
||||
if (has_decimal) {
|
||||
*wstr++ = '.';
|
||||
}
|
||||
|
||||
notzero = notzero || whole > 0;
|
||||
|
||||
/* do whole part
|
||||
* Take care of sign conversion
|
||||
* Number is reversed.
|
||||
*/
|
||||
do
|
||||
*wstr++ = (char)(48 + (whole % 10));
|
||||
while (whole /= 10);
|
||||
|
||||
if (neg && notzero) {
|
||||
*wstr++ = '-';
|
||||
}
|
||||
*wstr = '\0';
|
||||
strreverse(str, wstr - 1);
|
||||
return (size_t)(wstr - str);
|
||||
}
|
||||
|
||||
} // namespace xod
|
||||
#endif
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
*
|
||||
@@ -621,79 +805,7 @@ template<typename T> bool equal(List<T> lhs, List<T> rhs) {
|
||||
# define pgm_read_ptr(addr) (*(const void **)(addr))
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Compatibilities
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if !defined(ARDUINO_ARCH_AVR) && !defined(__DTOSTRF_H_)
|
||||
/*
|
||||
* Provide dtostrf function for non-AVR platforms. Although many platforms
|
||||
* provide a stub many others do not. And the stub is based on `sprintf`
|
||||
* which doesn’t work with floating point formatters on some platforms
|
||||
* (e.g. Arduino M0).
|
||||
*
|
||||
* This is an implementation based on `fcvt` standard function. Taken here:
|
||||
* https://forum.arduino.cc/index.php?topic=368720.msg2542614#msg2542614
|
||||
*/
|
||||
char *dtostrf(double val, int width, unsigned int prec, char *sout) {
|
||||
int decpt, sign, reqd, pad;
|
||||
const char *s, *e;
|
||||
char *p;
|
||||
s = fcvt(val, prec, &decpt, &sign);
|
||||
if (prec == 0 && decpt == 0) {
|
||||
s = (*s < '5') ? "0" : "1";
|
||||
reqd = 1;
|
||||
} else {
|
||||
reqd = strlen(s);
|
||||
if (reqd > decpt) reqd++;
|
||||
if (decpt == 0) reqd++;
|
||||
}
|
||||
if (sign) reqd++;
|
||||
p = sout;
|
||||
e = p + reqd;
|
||||
pad = width - reqd;
|
||||
if (pad > 0) {
|
||||
e += pad;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
if (sign) *p++ = '-';
|
||||
if (decpt <= 0 && prec > 0) {
|
||||
*p++ = '0';
|
||||
*p++ = '.';
|
||||
e++;
|
||||
while ( decpt < 0 ) {
|
||||
decpt++;
|
||||
*p++ = '0';
|
||||
}
|
||||
}
|
||||
while (p < e) {
|
||||
*p++ = *s++;
|
||||
if (p == e) break;
|
||||
if (--decpt == 0) *p++ = '.';
|
||||
}
|
||||
if (width < 0) {
|
||||
pad = (reqd + width) * -1;
|
||||
while (pad-- > 0) *p++ = ' ';
|
||||
}
|
||||
*p = 0;
|
||||
return sout;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace xod {
|
||||
//----------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
//----------------------------------------------------------------------------
|
||||
#if __SIZEOF_FLOAT__ == 4
|
||||
typedef float Number;
|
||||
#else
|
||||
typedef double Number;
|
||||
#endif
|
||||
typedef bool Logic;
|
||||
typedef unsigned long TimeMs;
|
||||
typedef uint8_t DirtyFlags;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Global variables
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user