diff --git a/library.json b/library.json index 539abe709..dc2da52f4 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Firebase Arduino Client Library for ESP8266 and ESP32", - "version": "3.1.6", + "version": "3.1.7", "keywords": "communication, REST, esp32, esp8266, arduino", "description": "The library supports Firebase products e.g. Realtime database, Cloud Firestore database, Firebase Storage and Google Cloud Storage, Cloud Functions for Firebase and Cloud Messaging. The library also supported other Arduino devices using Clients interfaces e.g. WiFiClient, EthernetClient, and GSMClient.", "repository": { diff --git a/library.properties b/library.properties index 97356655c..e5fb959f6 100644 --- a/library.properties +++ b/library.properties @@ -1,6 +1,6 @@ name=Firebase Arduino Client Library for ESP8266 and ESP32 -version=3.1.6 +version=3.1.7 author=Mobizt diff --git a/src/Firebase_ESP_Client.h b/src/Firebase_ESP_Client.h index ae35d8d0c..f2a4f42a5 100644 --- a/src/Firebase_ESP_Client.h +++ b/src/Firebase_ESP_Client.h @@ -1,16 +1,19 @@ #ifndef FIREBASE_CLIENT_VERSION -#define FIREBASE_CLIENT_VERSION "3.1.6" +#define FIREBASE_CLIENT_VERSION "3.1.7" #endif /** - * Google's Firebase ESP Client Main class, Firebase_ESP_Client.h v3.1.6 + * Google's Firebase ESP Client Main class, Firebase_ESP_Client.h v3.1.7 * * This library supports Espressif ESP8266 and ESP32 MCUs * - * Created April 15, 2022 + * Created April 19, 2022 * * Updates: - * - Fixed ESP8266 core v2.x.x compilation error. + * - Fixed FirebaseJson double to string conversion issue. + * - Fixed FirebaseJson array's set by index issue. + * - Add support FirebaseJson non-object type data via setJsonData and setJsonArrayData functions. + * - Remove Nagle disable from TCP client. * * * This work is a part of Firebase ESP Client library diff --git a/src/json/FirebaseJson.cpp b/src/json/FirebaseJson.cpp index e494d6598..fd04269aa 100644 --- a/src/json/FirebaseJson.cpp +++ b/src/json/FirebaseJson.cpp @@ -1,14 +1,14 @@ /* - * FirebaseJson, version 2.6.15 + * FirebaseJson, version 2.6.17 * * The Easiest Arduino library to parse, create and edit JSON object using a relative path. * - * Created April 15, 2022 + * Created April 19, 2022 * * Features * - Using path to access node element in search style e.g. json.get(result,"a/b/c") - * - Serializing to writable objects e.g. String, C/C++ string, Client (WiFi and Ethernet), File and Hardware Serial. - * - Deserializing from const char, char array, string literal and stream e.g. Client (WiFi and Ethernet), File and + * - Serializing to writable objects e.g. String, C/C++ string, Clients (WiFi, Ethernet, and GSM), File and Hardware Serial. + * - Deserializing from const char, char array, string literal and stream e.g. Clients (WiFi, Ethernet, and GSM), File and * Hardware Serial. * - Use managed class, FirebaseJsonData to keep the deserialized result, which can be casted to any primitive data types. * @@ -77,7 +77,27 @@ void FirebaseJsonBase::mCopy(FirebaseJsonBase &other) bool FirebaseJsonBase::setRaw(const char *raw) { mClear(); - root = parse(raw); + + if (raw) + { + size_t i = 0; + while (i < strlen(raw) && raw[i] == ' ') + { + i++; + } + + if (raw[i] == '{' || raw[i] == '[') + { + this->root_type = (raw[i] == '{') ? Root_Type_JSON : Root_Type_JSONArray; + root = parse(raw); + } + else + { + this->root_type = Root_Type_Raw; + root = MB_JSON_CreateRaw(raw); + } + } + return root != NULL; } @@ -768,6 +788,13 @@ void FirebaseJsonBase::mSetElementType(FirebaseJsonData *result) strcpy(buf, (const char *)MBSTRING_FLASH_MCR("string")); result->typeNum = JSON_STRING; + + // try casting the string to numbers + if (result->stringValue.length() <= 32) + { + mSetResInt(result, result->stringValue.c_str()); + mSetResFloat(result, result->stringValue.c_str()); + } } else if (result->type_num == MB_JSON_NULL) { @@ -931,6 +958,11 @@ FirebaseJsonArray::FirebaseJsonArray(FirebaseJsonArray &other) FirebaseJsonArray &FirebaseJsonArray::nAdd(MB_JSON *value) { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + prepareRoot(); if (value == NULL) @@ -967,6 +999,13 @@ bool FirebaseJsonArray::mGetIdx(FirebaseJsonData *result, int index, bool pretti bool FirebaseJsonArray::mSetIdx(int index, MB_JSON *value) { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + + prepareRoot(); + int size = MB_JSON_GetArraySize(root); if (index < size) return MB_JSON_ReplaceItemInArray(root, index, value); diff --git a/src/json/FirebaseJson.h b/src/json/FirebaseJson.h index d4ed6f339..266fd3b46 100644 --- a/src/json/FirebaseJson.h +++ b/src/json/FirebaseJson.h @@ -1,14 +1,14 @@ /* - * FirebaseJson, version 2.6.15 + * FirebaseJson, version 2.6.17 * * The Easiest Arduino library to parse, create and edit JSON object using a relative path. * - * Created April 15, 2022 + * Created April 19, 2022 * * Features * - Using path to access node element in search style e.g. json.get(result,"a/b/c") - * - Serializing to writable objects e.g. String, C/C++ string, Client (WiFi and Ethernet), File and Hardware Serial. - * - Deserializing from const char, char array, string literal and stream e.g. Client (WiFi and Ethernet), File and + * - Serializing to writable objects e.g. String, C/C++ string, Clients (WiFi, Ethernet, and GSM), File and Hardware Serial. + * - Deserializing from const char, char array, string literal and stream e.g. Clients (WiFi, Ethernet, and GSM), File and * Hardware Serial. * - Use managed class, FirebaseJsonData to keep the deserialized result, which can be casted to any primitive data types. * @@ -613,6 +613,7 @@ class FirebaseJsonBase { Root_Type_JSON = 0, Root_Type_JSONArray = 1, + Root_Type_Raw = 2 }; FirebaseJsonBase(); @@ -653,6 +654,27 @@ class FirebaseJsonBase MB_JSON_Hooks *hooks = NULL; MB_String buf; + template + auto getStr(T val, uint32_t &addr) -> typename MB_ENABLE_IF::value || is_num_int::value || MB_IS_SAME::value || MB_IS_SAME::value || MB_IS_SAME::value, const char *>::type + { + MB_String t; + + if (is_bool::value) + t.appendNum(val, 0); + else if (is_num_int::value) + t.appendNum(val, -1); + else if (MB_IS_SAME::value) + t.appendNum(val, floatDigits); + else if (MB_IS_SAME::value || MB_IS_SAME::value) + t.appendNum(val, doubleDigits); + + char *out = (char *)newP(t.length() + 1); + strcpy(out, t.c_str()); + + addr = toAddr(*out); + return (const char *)out; + } + template auto getStr(const T &val, uint32_t &addr) -> typename MB_ENABLE_IF::value || is_arduino_string::value || is_mb_string::value || MB_IS_SAME::value, const char *>::type { @@ -2047,6 +2069,11 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + nAdd(MB_JSON_CreateBool(arg)); return *this; } @@ -2054,6 +2081,11 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + nAdd(MB_JSON_CreateRaw(num2Str(arg, -1))); return *this; } @@ -2061,13 +2093,23 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + nAdd(MB_JSON_CreateRaw(num2Str(arg, floatDigits))); return *this; } template - auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type + auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value || MB_IS_SAME::value, FirebaseJsonArray &>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + nAdd(MB_JSON_CreateRaw(num2Str(arg, doubleDigits))); return *this; } @@ -2075,6 +2117,11 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataAddHandler(T arg) -> typename MB_ENABLE_IF::value, FirebaseJsonArray &>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + uint32_t addr = 0; nAdd(MB_JSON_CreateString(getStr(arg, addr))); delAddr(addr); @@ -2085,13 +2132,18 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + uint32_t addr = 0; mSet(getStr(arg1, addr), MB_JSON_CreateNull()); delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF<(is_num_int::value || is_num_float::value || is_bool::value) && MB_IS_SAME::value>::type { mSetIdx(arg1, MB_JSON_CreateNull); } @@ -2100,13 +2152,18 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_bool::value>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + uint32_t addr = 0; mSet(getStr(arg1, addr), MB_JSON_CreateBool(arg2)); delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_bool::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF<(is_num_int::value || is_num_float::value || is_bool::value) && is_bool::value>::type { mSetIdx(arg1, MB_JSON_CreateBool(arg2)); } @@ -2114,13 +2171,18 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_num_int::value>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + uint32_t addr = 0; mSet(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, -1))); delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_num_int::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF<(is_num_int::value || is_num_float::value || is_bool::value) && is_num_int::value>::type { mSetIdx(arg1, MB_JSON_CreateRaw(num2Str(arg2, -1))); } @@ -2128,27 +2190,37 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + uint32_t addr = 0; mSet(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, floatDigits))); delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF<(is_num_int::value || is_num_float::value || is_bool::value) && MB_IS_SAME::value>::type { mSetIdx(arg1, MB_JSON_CreateRaw(num2Str(arg2, floatDigits))); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && (MB_IS_SAME::value || MB_IS_SAME::value)>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + uint32_t addr = 0; mSet(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, doubleDigits))); delAddr(addr); } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF<(is_num_int::value || is_num_float::value || is_bool::value) && (MB_IS_SAME::value || MB_IS_SAME::value)>::type { mSetIdx(arg1, MB_JSON_CreateRaw(num2Str(arg2, doubleDigits))); } @@ -2156,6 +2228,11 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_string::value>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + uint32_t addr1 = 0; uint32_t addr2 = 0; mSet(getStr(arg1, addr1), MB_JSON_CreateString(getStr(arg2, addr2))); @@ -2164,7 +2241,7 @@ class FirebaseJsonArray : public FirebaseJsonBase } template - auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF::value && is_string::value>::type + auto dataSetHandler(T1 arg1, T2 arg2) -> typename MB_ENABLE_IF<(is_num_int::value || is_num_float::value || is_bool::value) && is_string::value>::type { uint32_t addr = 0; mSetIdx(arg1, MB_JSON_CreateString(getStr(arg2, addr))); @@ -2174,6 +2251,11 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + MB_JSON *e = MB_JSON_Duplicate(arg2.root, true); uint32_t addr = 0; mSet(getStr(arg1, addr), e); @@ -2181,7 +2263,7 @@ class FirebaseJsonArray : public FirebaseJsonBase } template - auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type + auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF<(is_num_int::value || is_num_float::value || is_bool::value) && MB_IS_SAME::value>::type { MB_JSON *e = MB_JSON_Duplicate(arg2.root, true); mSetIdx(arg1, e); @@ -2190,6 +2272,11 @@ class FirebaseJsonArray : public FirebaseJsonBase template auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type { + if (root_type != Root_Type_JSONArray) + mClear(); + + root_type = Root_Type_JSONArray; + MB_JSON *e = MB_JSON_Duplicate(arg2.root, true); uint32_t addr = 0; mSet(getStr(arg1, addr), e); @@ -2197,7 +2284,7 @@ class FirebaseJsonArray : public FirebaseJsonBase } template - auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value>::type + auto dataSetHandler(T1 arg1, T2 &arg2) -> typename MB_ENABLE_IF<(is_num_int::value || is_num_float::value || is_bool::value) && MB_IS_SAME::value>::type { MB_JSON *e = MB_JSON_Duplicate(arg2.root, true); mSetIdx(arg1, e); @@ -2320,13 +2407,28 @@ class FirebaseJson : public FirebaseJsonBase * @return instance of an object. */ template - FirebaseJson &add(T1 key, T2 value) { return dataHandler(key, value, fb_json_func_type_add); } + FirebaseJson &add(T1 key, T2 value) + { + uint32_t addr = 0; + dataHandler(getStr(key, addr), value, fb_json_func_type_add); + return *this; + } template - FirebaseJson &add(T key, FirebaseJson &value) { return dataHandler(key, value, fb_json_func_type_add); } + FirebaseJson &add(T key, FirebaseJson &value) + { + uint32_t addr = 0; + dataHandler(getStr(key, addr), value, fb_json_func_type_add); + return *this; + } template - FirebaseJson &add(T key, FirebaseJsonArray &value) { return dataHandler(key, value, fb_json_func_type_add); } + FirebaseJson &add(T key, FirebaseJsonArray &value) + { + uint32_t addr = 0; + dataHandler(getStr(key, addr), value, fb_json_func_type_add); + return *this; + } /** * Get the FirebaseJson object serialized string. @@ -2464,13 +2566,31 @@ class FirebaseJson : public FirebaseJsonBase * boolean, FirebaseJson object and array. */ template - void set(T1 key, T2 value) { dataHandler(key, value, fb_json_func_type_set); } + FirebaseJson &set(T1 key, T2 value) + { + uint32_t addr = 0; + dataHandler(getStr(key, addr), value, fb_json_func_type_set); + delAddr(addr); + return *this; + } template - FirebaseJson &set(T key, FirebaseJson &value) { return dataHandler(key, value, fb_json_func_type_set); } + FirebaseJson &set(T key, FirebaseJson &value) + { + uint32_t addr = 0; + dataHandler(getStr(key, addr), value, fb_json_func_type_set); + delAddr(addr); + return *this; + } template - FirebaseJson &set(T key, FirebaseJsonArray &value) { return dataHandler(key, value, fb_json_func_type_set); } + FirebaseJson &set(T key, FirebaseJsonArray &value) + { + uint32_t addr = 0; + dataHandler(getStr(key, addr), value, fb_json_func_type_set); + delAddr(addr); + return *this; + } /** * Remove the specified node and its content. @@ -2530,6 +2650,11 @@ class FirebaseJson : public FirebaseJsonBase template auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && is_bool::value, FirebaseJson &>::type { + if (root_type != Root_Type_JSON) + mClear(); + + root_type = Root_Type_JSON; + uint32_t addr = 0; if (type == fb_json_func_type_add) nAdd(getStr(arg1, addr), MB_JSON_CreateBool(arg2)); @@ -2542,6 +2667,11 @@ class FirebaseJson : public FirebaseJsonBase template auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && is_num_int::value, FirebaseJson &>::type { + if (root_type != Root_Type_JSON) + mClear(); + + root_type = Root_Type_JSON; + uint32_t addr = 0; if (type == fb_json_func_type_add) nAdd(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, -1))); @@ -2554,6 +2684,11 @@ class FirebaseJson : public FirebaseJsonBase template auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value, FirebaseJson &>::type { + if (root_type != Root_Type_JSON) + mClear(); + + root_type = Root_Type_JSON; + uint32_t addr = 0; if (type == fb_json_func_type_add) nAdd(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, floatDigits))); @@ -2564,8 +2699,13 @@ class FirebaseJson : public FirebaseJsonBase } template - auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && MB_IS_SAME::value, FirebaseJson &>::type + auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && (MB_IS_SAME::value || MB_IS_SAME::value), FirebaseJson &>::type { + if (root_type != Root_Type_JSON) + mClear(); + + root_type = Root_Type_JSON; + uint32_t addr = 0; if (type == fb_json_func_type_add) nAdd(getStr(arg1, addr), MB_JSON_CreateRaw(num2Str(arg2, doubleDigits))); @@ -2578,6 +2718,11 @@ class FirebaseJson : public FirebaseJsonBase template auto dataHandler(T1 arg1, T2 arg2, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value && is_string::value, FirebaseJson &>::type { + if (root_type != Root_Type_JSON) + mClear(); + + root_type = Root_Type_JSON; + uint32_t addr1 = 0; uint32_t addr2 = 0; if (type == fb_json_func_type_add) @@ -2592,6 +2737,11 @@ class FirebaseJson : public FirebaseJsonBase template auto dataHandler(T arg, FirebaseJson &json, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value, FirebaseJson &>::type { + if (root_type != Root_Type_JSON) + mClear(); + + root_type = Root_Type_JSON; + MB_JSON *e = MB_JSON_Duplicate(json.root, true); uint32_t addr = 0; if (type == fb_json_func_type_add) @@ -2605,6 +2755,11 @@ class FirebaseJson : public FirebaseJsonBase template auto dataHandler(T arg, FirebaseJsonArray &arr, fb_json_func_type_t type) -> typename MB_ENABLE_IF::value, FirebaseJson &>::type { + if (root_type != Root_Type_JSON) + mClear(); + + root_type = Root_Type_JSON; + MB_JSON *e = MB_JSON_Duplicate(arr.root, true); uint32_t addr = 0; if (type == fb_json_func_type_add) diff --git a/src/json/MB_String.h b/src/json/MB_String.h index f462d4658..d2b68f52a 100644 --- a/src/json/MB_String.h +++ b/src/json/MB_String.h @@ -1,11 +1,14 @@ /** - * Mobizt's SRAM/PSRAM supported String, version 1.2.4 + * Mobizt's SRAM/PSRAM supported String, version 1.2.5 * - * Created February 28, 2022 + * Created April 19, 2022 * * Changes Log * + * v1.2.5 + * - Fixed double string issue and add support long double + * * v1.2.4 * - Check PSRAM availability before allocating the memory * @@ -71,7 +74,7 @@ #define MB_STRING_MAJOR 1 #define MB_STRING_MINOR 2 -#define MB_STRING_PATCH 4 +#define MB_STRING_PATCH 5 #if defined(ESP8266) && defined(MMU_EXTERNAL_HEAP) && defined(MB_STRING_USE_PSRAM) #include @@ -239,7 +242,7 @@ namespace mb_string template struct is_num_float { - static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value || MB_IS_SAME::value; }; template @@ -563,15 +566,45 @@ class MB_String { reserve(33); if (bufLen > 0) - dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); + { + char *v = toFloatStr(value, 0, decimalPlaces); + if (v) + { + strcpy(buf, v); + delP(&v); + } + } } MB_String(double value, unsigned char decimalPlaces = 3) { reserve(33); + + if (bufLen > 0) + { + char *v = toFloatStr(value, 1, decimalPlaces); + if (v) + { + strcpy(buf, v); + delP(&v); + } + } + } + + MB_String(long double value, unsigned char decimalPlaces = 3) + { + reserve(65); if (bufLen > 0) - dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); + { + char *v = toFloatStr(value, 2, decimalPlaces); + if (v) + { + strcpy(buf, v); + delP(&v); + } + } } + #if !defined(__AVR__) MB_String &operator=(const std::string &rhs) { @@ -832,7 +865,7 @@ class MB_String if (precision < 0) precision = 5; - char *s = floatStr(value, precision); + char *s = toFloatStr(value, 0, precision); if (s) { *this += s; @@ -846,7 +879,21 @@ class MB_String if (precision < 0) precision = 9; - char *s = doubleStr(value, precision); + char *s = toFloatStr(value, 1, precision); + if (s) + { + *this += s; + delP(&s); + } + return (*this); + } + + MB_String &appendNum(long double value, int precision = 9) + { + if (precision < 0) + precision = 9; + + char *s = toFloatStr(value, 2, precision); if (s) { *this += s; @@ -1370,136 +1417,6 @@ class MB_String static const size_t npos = -1; private: - /*** dtostrf function is taken from - * https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/avr/dtostrf.c - */ - - /*** - * dtostrf - Emulation for dtostrf function from avr-libc - * Copyright (c) 2013 Arduino. All rights reserved. - * Written by Cristian Maglie - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - char *dtostrf(double val, signed char width, unsigned char prec, char *sout) - { - // Commented code is the original version - /*** - char fmt[20]; - sprintf(fmt, "%%%d.%df", width, prec); - sprintf(sout, fmt, val); - return sout; - */ - - // Handle negative numbers - uint8_t negative = 0; - if (val < 0.0) - { - negative = 1; - val = -val; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for (int i = 0; i < prec; ++i) - { - rounding /= 10.0; - } - - val += rounding; - - // Extract the integer part of the number - unsigned long int_part = (unsigned long)val; - double remainder = val - (double)int_part; - - if (prec > 0) - { - // Extract digits from the remainder - unsigned long dec_part = 0; - double decade = 1.0; - for (int i = 0; i < prec; i++) - { - decade *= 10.0; - } - remainder *= decade; - dec_part = (int)remainder; - - if (negative) - { - sprintf(sout, (const char *)MBSTRING_FLASH_MCR("-%ld.%0*ld"), int_part, prec, dec_part); - } - else - { - sprintf(sout, (const char *)MBSTRING_FLASH_MCR("%ld.%0*ld"), int_part, prec, dec_part); - } - } - else - { - if (negative) - { - sprintf(sout, (const char *)MBSTRING_FLASH_MCR("-%ld"), int_part); - } - else - { - sprintf(sout, (const char *)MBSTRING_FLASH_MCR("%ld"), int_part); - } - } - // Handle minimum field width of the output string - // width is signed value, negative for left adjustment. - // Range -128,127 - - char *fmt = (char *)newP(129); - unsigned int w = width; - if (width < 0) - { - negative = 1; - w = -width; - } - else - { - negative = 0; - } - - if (strlen(sout) < w) - { - memset(fmt, ' ', 128); - fmt[w - strlen(sout)] = '\0'; - if (negative == 0) - { - char *tmp = (char *)newP(strlen(sout) + 1); - strcpy(tmp, sout); - strcpy(sout, fmt); - strcat(sout, tmp); - delP(&tmp); - } - else - { - // left adjustment - strcat(sout, fmt); - } - } - - delP(&fmt); - - return sout; - } - - char *intStr(int value) - { - char *t = (char *)newP(36); - sprintf(t, (const char *)MBSTRING_FLASH_MCR("%d"), value); - return t; - } #if defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) @@ -1540,19 +1457,23 @@ class MB_String return t; } - char *floatStr(float value, int precision) + char *toFloatStr(long double value, int type, int precision) { - char *t = (char *)newP(32); - dtostrf(value, (precision + 2), precision, t); - trim(t); - return t; - } + int width = type == 0 ? 32 : 64; + + char *t = (char *)newP(width); + + if (t) + { + MB_String fmt = MBSTRING_FLASH_MCR("%."); + fmt += precision; + if (type == 2) + fmt += MBSTRING_FLASH_MCR("L"); + fmt += MBSTRING_FLASH_MCR("f"); + sprintf(t, fmt.c_str(), value); + trim(t); + } - char *doubleStr(double value, int precision) - { - char *t = (char *)newP(64); - dtostrf(value, (precision + 2), precision, t); - trim(t); return t; }