From 0dec79bf64b16540d71c21c84a98c162b66e624e Mon Sep 17 00:00:00 2001 From: tobozo Date: Sun, 16 Jun 2024 15:15:59 +0200 Subject: [PATCH] Migrated to ArduinoJSON 7.x, fixes #20 --- .../ReadWriteConfigFile.ino | 50 ++++++++++++++----- examples/deserializeYml/deserializeYml.ino | 16 ++++-- examples/test/include/README | 39 --------------- examples/test/lib/README | 46 ----------------- examples/test/src/test.cpp | 26 ++++++---- examples/test/test/README | 11 ---- src/ArduinoYaml.cpp | 33 ++++++++---- src/ArduinoYaml.hpp | 8 ++- 8 files changed, 95 insertions(+), 134 deletions(-) delete mode 100644 examples/test/include/README delete mode 100644 examples/test/lib/README delete mode 100644 examples/test/test/README diff --git a/examples/ReadWriteConfigFile/ReadWriteConfigFile.ino b/examples/ReadWriteConfigFile/ReadWriteConfigFile.ino index 30bd24b..216037d 100644 --- a/examples/ReadWriteConfigFile/ReadWriteConfigFile.ino +++ b/examples/ReadWriteConfigFile/ReadWriteConfigFile.ino @@ -1,6 +1,20 @@ #include #include -#include + +#if defined ARDUINO_M5Stack_Core_ESP32 + #include + #define FS_t fs::FS + #define File_t fs::File + #define delay_fn vTaskDelay +#elif defined CORE_TEENSY + #include + #include + #define FS_t FS + #define File_t File + #define delay_fn delay +#else + #error "please implement" +#endif const char* yaml_example_str = R"_YAML_STRING_( @@ -31,9 +45,9 @@ DynamicJsonDocument json_doc(2048); JsonObject myConfig; // json accessor -bool writeTestYaml( fs::FS &fs, const char* path ) +bool writeTestYaml( FS_t &fs, const char* path ) { - fs::File file = fs.open( path, FILE_WRITE ); + File_t file = fs.open( path, FILE_WRITE ); if( !file ) { Serial.println("Can't open file for writing"); return false; @@ -47,7 +61,7 @@ bool writeTestYaml( fs::FS &fs, const char* path ) bool loadYamlConfig() { - fs::File file = SD.open( config_file ); + File_t file = SD.open( config_file ); if( !file ) { Serial.println("Can't open test file for writing :-("); return false; @@ -68,7 +82,7 @@ bool loadYamlConfig() bool saveYamlConfig() { - fs::File file = SD.open( config_file, FILE_WRITE); + File_t file = SD.open( config_file, FILE_WRITE); if( !file ) { Serial.println("Can't open file for writing"); return false; @@ -93,14 +107,22 @@ bool toggleYamlProperty() void setup() { - M5.begin(); + #if defined ARDUINO_M5Stack_Core_ESP32 + M5.begin(); + if( M5.BtnA.isPressed() ) { + SD.remove( config_file ); + Serial.println("Deleted config file"); + while( M5.BtnA.isPressed() ) { M5.update(); } // wait for release + ESP.restart(); + } + #elif defined CORE_TEENSY + Serial.begin(115200); + SD.begin( BUILTIN_SDCARD ); + #else + #error "please implement" + #endif + - if( M5.BtnA.isPressed() ) { - SD.remove( config_file ); - Serial.println("Deleted config file"); - while( M5.BtnA.isPressed() ) { M5.update(); } // wait for release - ESP.restart(); - } _load_config: config_loaded = loadYamlConfig(); @@ -109,7 +131,7 @@ void setup() Serial.printf("Ceating config file %s\n", config_file ); if( !writeTestYaml( SD, config_file ) ) { Serial.println("Could not create config file, aborting"); - while(1) vTaskDelay(1); + while(1) delay_fn(1); } // write succeeded, reload config goto _load_config; @@ -122,6 +144,7 @@ void setup() void loop() { + #if defined ARDUINO_M5Stack_Core_ESP32 M5.update(); if( M5.BtnB.wasPressed() ) { @@ -129,5 +152,6 @@ void loop() Serial.println("Failed to save property"); } } + #endif } diff --git a/examples/deserializeYml/deserializeYml.ino b/examples/deserializeYml/deserializeYml.ino index 606af68..f3176fc 100644 --- a/examples/deserializeYml/deserializeYml.ino +++ b/examples/deserializeYml/deserializeYml.ino @@ -3,12 +3,18 @@ #include #include +#if ARDUINOJSON_VERSION_MAJOR<7 + #error "ArduinoJSON version is deprecated, please upgrade to 7.x" +#endif + const char* yaml_sample_str = R"_YAML_STRING_( first: true blah: nope: ["n","o","p","e"] integer: 12345 float: 12.3323 +qinteger: "12345" +qfloat: "12.3323" last: true )_YAML_STRING_"; @@ -20,6 +26,8 @@ const char* json_sample_str = R"_JSON_STRING_( "blah": { "nope": [ "n", "o", "p", "e" ] }, "integer": 12345, "float": 12.3323, + "qinteger": "12345" + "qfloat": "12.3323" "last": true } @@ -45,7 +53,7 @@ void test_deserializeYml_JsonObject_YamlStream() #if defined TEST_YAML_Stream_To_ArduinoJsonObject String yaml_str = String( yaml_sample_str ); StringStream yaml_stream( yaml_str ); - StaticJsonDocument<128> json_doc; + JsonDocument json_doc; JsonObject json_obj = json_doc.to(); auto err = deserializeYml( json_obj, yaml_stream ); // deserialize yaml stream to JsonObject if( err ) { @@ -60,7 +68,7 @@ void test_deserializeYml_JsonObject_YamlStream() void test_deserializeYml_JsonObject_YamlString() { #if defined TEST_YAML_String_To_ArduinoJsonObject - StaticJsonDocument<128> json_doc; + JsonDocument json_doc; JsonObject json_obj = json_doc.to(); auto err = deserializeYml( json_obj, yaml_sample_str ); // deserialize yaml string to JsonObject if( err ) { @@ -75,7 +83,7 @@ void test_deserializeYml_JsonObject_YamlString() void test_deserializeYml_JsonDocument_YamlStream() { #if defined TEST_YAML_Stream_To_ArduinoJsonDocument - StaticJsonDocument<128> json_doc; + JsonDocument json_doc; String yaml_str = String( yaml_sample_str ); StringStream yaml_stream( yaml_str ); auto err = deserializeYml( json_doc, yaml_stream ); // deserialize yaml stream to JsonDocument @@ -92,7 +100,7 @@ void test_deserializeYml_JsonDocument_YamlString() { #if defined TEST_YAML_String_To_ArduinoJsonDocument String yaml_str( yaml_sample_str ); - StaticJsonDocument<128> json_doc; + JsonDocument json_doc; auto err = deserializeYml( json_doc, yaml_str.c_str() ); // deserialize yaml string to JsonDocument if( err ) { Serial.printf("Unable to deserialize demo YAML to JsonObject: %s", err.c_str() ); diff --git a/examples/test/include/README b/examples/test/include/README deleted file mode 100644 index 194dcd4..0000000 --- a/examples/test/include/README +++ /dev/null @@ -1,39 +0,0 @@ - -This directory is intended for project header files. - -A header file is a file containing C declarations and macro definitions -to be shared between several project source files. You request the use of a -header file in your project source file (C, C++, etc) located in `src` folder -by including it, with the C preprocessing directive `#include'. - -```src/main.c - -#include "header.h" - -int main (void) -{ - ... -} -``` - -Including a header file produces the same results as copying the header file -into each source file that needs it. Such copying would be time-consuming -and error-prone. With a header file, the related declarations appear -in only one place. If they need to be changed, they can be changed in one -place, and programs that include the header file will automatically use the -new version when next recompiled. The header file eliminates the labor of -finding and changing all the copies as well as the risk that a failure to -find one copy will result in inconsistencies within a program. - -In C, the usual convention is to give header files names that end with `.h'. -It is most portable to use only letters, digits, dashes, and underscores in -header file names, and at most one dot. - -Read more about using header files in official GCC documentation: - -* Include Syntax -* Include Operation -* Once-Only Headers -* Computed Includes - -https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/examples/test/lib/README b/examples/test/lib/README deleted file mode 100644 index 6debab1..0000000 --- a/examples/test/lib/README +++ /dev/null @@ -1,46 +0,0 @@ - -This directory is intended for project specific (private) libraries. -PlatformIO will compile them to static libraries and link into executable file. - -The source code of each library should be placed in a an own separate directory -("lib/your_library_name/[here are source files]"). - -For example, see a structure of the following two libraries `Foo` and `Bar`: - -|--lib -| | -| |--Bar -| | |--docs -| | |--examples -| | |--src -| | |- Bar.c -| | |- Bar.h -| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html -| | -| |--Foo -| | |- Foo.c -| | |- Foo.h -| | -| |- README --> THIS FILE -| -|- platformio.ini -|--src - |- main.c - -and a contents of `src/main.c`: -``` -#include -#include - -int main (void) -{ - ... -} - -``` - -PlatformIO Library Dependency Finder will find automatically dependent -libraries scanning project source files. - -More information about PlatformIO Library Dependency Finder -- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/examples/test/src/test.cpp b/examples/test/src/test.cpp index 9a36ae4..e81cb79 100644 --- a/examples/test/src/test.cpp +++ b/examples/test/src/test.cpp @@ -1,6 +1,10 @@ #include +#if ARDUINOJSON_VERSION_MAJOR<7 + #error "ArduinoJSON version is deprecated, please upgrade to 7.x" +#endif + //#define YAML_DISABLE_CJSON // not needed here //#define YAML_DISABLE_ARDUINOJSON // not needed here @@ -45,9 +49,11 @@ fourth: false prop3: bar prop2: baz prop4: wat - integer: 12345 + integer: 1234567890 + quoted_integer: "1234567890" # this float value gives a memleak to cJSON float: 12.3323 + quoted_float: "12.3323" inline_json_for_the_haters: { "hello":"json", "nested":[3,2,"1","moon"] } whatever: nope: ["n","o","p","e"] @@ -78,8 +84,10 @@ const char* json_sample_str = R"_JSON_STRING_( "prop4": "wat" } ], - "integer": 12345, + "integer": 1234567890, + "quoted_integer": "1234567890", "float": 12.3323, + "quoted_float": "12.3323", "inline_json_for_the_haters": { "hello": "json", "nested": [ 3, 2, "1", "moon" ] } }, "whatever": { "nope": [ "n", "o", "p", "e" ] }, @@ -199,7 +207,7 @@ void test_Json_gettext_stream() { String yaml_str = String( yaml_sample_str ); StringStream yaml_stream( yaml_str ); - DynamicJsonDocument json_doc(2048); + JsonDocument json_doc; JsonObject json_obj = json_doc.to(); auto err = deserializeYml( json_obj, yaml_stream ); // deserialize yaml stream to JsonObject if( err ) { @@ -215,7 +223,7 @@ void test_Json_gettext_stream() void test_deserializeYml_JsonObject_YamlString() { - DynamicJsonDocument json_doc(2048); + JsonDocument json_doc; JsonObject json_obj = json_doc.to(); auto err = deserializeYml( json_obj, yaml_sample_str ); // deserialize yaml string to JsonObject if( err ) { @@ -230,7 +238,7 @@ void test_Json_gettext_stream() void test_deserializeYml_JsonDocument_YamlStream() { - DynamicJsonDocument json_doc(2048); + JsonDocument json_doc; String yaml_str = String( yaml_sample_str ); StringStream yaml_stream( yaml_str ); auto err = deserializeYml( json_doc, yaml_stream ); // deserialize yaml stream to JsonDocument @@ -248,7 +256,7 @@ void test_Json_gettext_stream() void test_deserializeYml_JsonDocument_YamlString() { String yaml_str( yaml_sample_str ); - DynamicJsonDocument json_doc(2048); + JsonDocument json_doc; auto err = deserializeYml( json_doc, yaml_str.c_str() ); // deserialize yaml string to JsonDocument if( err ) { YAML_LOG_n("Unable to deserialize demo YAML to JsonObject: %s", err.c_str() ); @@ -267,7 +275,7 @@ void test_Json_gettext_stream() String str_yaml_out = ""; // YAML output string String json_str = String( json_sample_str ); StringStream yaml_stream_out( str_yaml_out ); // Stream to str_yaml_out - DynamicJsonDocument doc(2048); // create and populate a JsonObject + JsonDocument doc; // create and populate a JsonObject auto err = deserializeJson( doc, json_str.c_str() ); if( err ) { YAML_LOG_n("Unable to deserialize demo JSON to JsonObject: %s", err.c_str() ); @@ -285,7 +293,7 @@ void test_Json_gettext_stream() // Convert JsonObject to yaml String str_yaml_out = ""; // YAML output string String json_str = String( json_sample_str ); - DynamicJsonDocument doc(2048); // create and populate a JsonObject + JsonDocument doc; // create and populate a JsonObject auto err = deserializeJson( doc, json_str.c_str() ); if( err ) { YAML_LOG_n("Unable to deserialize demo JSON to JsonObject: %s", err.c_str() ); @@ -417,7 +425,7 @@ void setup() test_fn( test_Yaml2JsonPretty, "serializeYml", "Yaml2JsonPretty", "serializeYml(yaml_document_t*, Stream&, OUTPUT_JSON_PRETTY)" ); test_fn( test_Yaml2Json, "serializeYml", "Yaml2Json", "serializeYml(yaml_document_t*, Stream&, OUTPUT_JSON)" ); - test_fn( test_Json2Yaml, "serializeYml", "Json2Yam", "serializeYml(yaml_document_t*, Stream&, OUTPUT_YAML)" ); + test_fn( test_Json2Yaml, "serializeYml", "Json2Yaml", "serializeYml(yaml_document_t*, Stream&, OUTPUT_YAML)" ); YAML_LOG_n("### YAMLParser libyaml tests complete\n"); diff --git a/examples/test/test/README b/examples/test/test/README deleted file mode 100644 index 9b1e87b..0000000 --- a/examples/test/test/README +++ /dev/null @@ -1,11 +0,0 @@ - -This directory is intended for PlatformIO Test Runner and project tests. - -Unit Testing is a software testing method by which individual units of -source code, sets of one or more MCU program modules together with associated -control data, usage procedures, and operating procedures, are tested to -determine whether they are fit for use. Unit testing finds problems early -in the development cycle. - -More information about PlatformIO Unit Testing: -- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html diff --git a/src/ArduinoYaml.cpp b/src/ArduinoYaml.cpp index 92d53f3..d510b90 100644 --- a/src/ArduinoYaml.cpp +++ b/src/ArduinoYaml.cpp @@ -1007,25 +1007,34 @@ namespace YAML char* end; scalar = SCALAR_s(yamlNode); number = strtod(scalar, &end); + bool is_double = false; bool is_bool = false; bool bool_value = false; bool is_string = (end == scalar || *end); if( is_string && yaml_node_is_bool( yamlNode, &bool_value ) ) { is_bool = true; } + if( SCALAR_Quoted(yamlNode) ) { + is_string = true; + } + if( !is_bool && !is_string ) { + is_double = String(scalar).indexOf(".") > 0; + } switch( nt ) { case YAMLNode::Type::Sequence: { JsonArray array = jsonNode[nodename]; if(is_bool) array.add( bool_value ); else if(is_string) array.add( scalar ); - else array.add( number ); + else if(is_double) array.add( number ); + else array.add( (int64_t)number ); } break; case YAMLNode::Type::Map: if(is_bool) jsonNode[nodename] = bool_value; else if(is_string) jsonNode[nodename] = scalar; - else jsonNode[nodename] = number; + else if(is_double) jsonNode[nodename] = number; + else jsonNode[nodename] = (int64_t)number; break; default: YAML_LOG_e("Error invalid nesting type"); break; } @@ -1033,19 +1042,23 @@ namespace YAML break; case YAML_SEQUENCE_NODE: { - JsonArray tmpArray = jsonNode.createNestedArray((char*)nodename); + jsonNode[(char*)nodename].to(); + JsonArray nodeArray = jsonNode[(char*)nodename];//.to(); + yaml_node_item_t * item_i; yaml_node_t *itemNode; String _nodeItemName; + JsonDocument copyDoc; JsonObject tmpObj; for (item_i = yamlNode->data.sequence.items.start; item_i < yamlNode->data.sequence.items.top; ++item_i) { itemNode = yaml_document_get_node(document, *item_i); if( itemNode->type == YAML_MAPPING_NODE ) { // array of anonymous objects - tmpObj = tmpArray.createNestedObject(); // insert empty nested object - _nodeItemName = ROOT_NODE + String( nodename ) + String( tmpArray.size() ); // generate a temporary nodename - tmpObj.createNestedObject((char*)_nodeItemName.c_str()); + tmpObj = nodeArray.add(); // insert empty nested object + _nodeItemName = ROOT_NODE + String( nodename ) + String( nodeArray.size() ); // generate a temporary nodename + tmpObj[(char*)_nodeItemName.c_str()].to(); deserializeYml_JsonObject( document, itemNode, tmpObj, YAMLNode::Type::Sequence, _nodeItemName.c_str(), depth+1 ); // go recursive using temporary node name - jsonNode[nodename][tmpArray.size()-1] = tmpObj[_nodeItemName.c_str()]; // remove temporary name and make object anonymous + copyDoc.set(tmpObj[_nodeItemName]); // make object anonymous, remove temporary nodename + nodeArray[nodeArray.size()-1].set(copyDoc); // replace array item by reparented node } else { // array of sequences or values _nodeItemName = "" + String( nodename ); deserializeYml_JsonObject( document, itemNode, jsonNode, YAMLNode::Type::Sequence, _nodeItemName.c_str(), depth+1 ); @@ -1055,7 +1068,7 @@ namespace YAML break; case YAML_MAPPING_NODE: { - JsonObject tmpNode = isRootNode ? jsonNode : jsonNode.createNestedObject((char*)nodename); + JsonObject tmpNode = isRootNode ? jsonNode : jsonNode[(char*)nodename].to(); yaml_node_pair_t* pair_i; yaml_node_t* key; yaml_node_t* value; @@ -1066,7 +1079,7 @@ namespace YAML YAML_LOG_e("Mapping key is not scalar (line %lu, val=%s).", key->start_mark.line, SCALAR_c(value) ); continue; } - tmpNode.createNestedObject( SCALAR_s(key) ); + tmpNode[SCALAR_s(key)].add(); deserializeYml_JsonObject( document, value, tmpNode, YAMLNode::Type::Map, SCALAR_c(key), depth+1 ); } } @@ -1266,7 +1279,7 @@ namespace YAML char * end; scalar = SCALAR_s(yamlNode); number = strtod(scalar, &end); - if( (end == scalar || *end) ) { // string or bool + if( (end == scalar || *end) || SCALAR_Quoted(yamlNode) ) { // string or bool bool bool_value; if( yaml_node_is_bool( yamlNode, &bool_value ) ) { object = cJSON_CreateBool( bool_value ); diff --git a/src/ArduinoYaml.hpp b/src/ArduinoYaml.hpp index f5ff705..86900de 100644 --- a/src/ArduinoYaml.hpp +++ b/src/ArduinoYaml.hpp @@ -85,6 +85,9 @@ extern "C" #if defined HAS_ARDUINOJSON #include + #if ARDUINOJSON_VERSION_MAJOR<7 + #error "ArduinoJSON version is deprecated, please upgrade to 7.x" + #endif #endif #if defined HAS_CJSON @@ -121,6 +124,7 @@ namespace YAML // shorthand to libyaml scalar values #define SCALAR_c(x) (const char*)x->data.scalar.value #define SCALAR_s(x) (char*)x->data.scalar.value + #define SCALAR_Quoted(n) n->data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE || n->data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE void setYAMLIndent( int spaces_per_indent=2 ); // min=2, max=16 void setJSONIndent( const char* spaces_or_tabs=JSON_SCALAR_TAB, int folding_depth=JSON_FOLDING_DEPTH ); @@ -290,13 +294,13 @@ namespace YAML public: YAMLToArduinoJson() {}; ~YAMLToArduinoJson() { if( _doc) delete _doc; } - void setJsonDocument( const size_t capacity ) { _doc = new DynamicJsonDocument(capacity); _root = _doc->to(); } + void setJsonDocument( const size_t capacity ) { _doc = new JsonDocument; _root = _doc->to(); } JsonObject& getJsonObject() { return _root; } static DeserializationError toJsonObject( Stream &src, JsonObject& output ); static DeserializationError toJsonObject( const char* src, JsonObject& output ); private: - DynamicJsonDocument *_doc = nullptr; + JsonDocument *_doc = nullptr; JsonObject _root; };