From 01932afa007009b02a358d08055ddec573ccbfac Mon Sep 17 00:00:00 2001 From: Nicolas Veloz Savino Date: Wed, 21 Dec 2022 12:17:58 +0100 Subject: [PATCH 1/7] Add support for publishing individual records --- src/thingset_txt.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/thingset_txt.c b/src/thingset_txt.c index e38c97e..a6b8a14 100644 --- a/src/thingset_txt.c +++ b/src/thingset_txt.c @@ -1060,7 +1060,15 @@ static int ts_serialize_statement(struct ts_context *ts, char *buf, size_t buf_s buf[len] = '\0'; } else { - return 0; + int len_value = ts_json_serialize_value(ts, &buf[len], buf_size - len, object); + if (len_value <= 0) { + return 0; + } + len+=len_value; + if (len >= buf_size - 1) { + return 0; + } + buf[--len] = '\0'; // overwrite comma } return len; From 113ec9280d860e1b16705c5b601630222f19fcf2 Mon Sep 17 00:00:00 2001 From: Nicolas Veloz Savino Date: Sat, 24 Dec 2022 00:21:51 +0100 Subject: [PATCH 2/7] Adding support for bool and some tests --- src/thingset_txt.c | 10 +++----- test/main.cpp | 1 + test/test.h | 2 ++ test/test_data.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ test/test_txt.c | 34 ++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 6 deletions(-) diff --git a/src/thingset_txt.c b/src/thingset_txt.c index a6b8a14..ce8f9aa 100644 --- a/src/thingset_txt.c +++ b/src/thingset_txt.c @@ -118,6 +118,8 @@ static int json_serialize_simple_value(char *buf, size_t size, void *data, int t return snprintf(buf, size, "%" PRIu8 ",", *((uint8_t *)data)); case TS_T_INT8: return snprintf(buf, size, "%" PRIi8 ",", *((int8_t *)data)); + case TS_T_BOOL: + return snprintf(buf,size, *((bool *)data)?"true":"false"); case TS_T_FLOAT32: { float value = *((float *)data); if (isnan(value) || isinf(value)) { @@ -1060,15 +1062,11 @@ static int ts_serialize_statement(struct ts_context *ts, char *buf, size_t buf_s buf[len] = '\0'; } else { - int len_value = ts_json_serialize_value(ts, &buf[len], buf_size - len, object); - if (len_value <= 0) { - return 0; - } - len+=len_value; + len += ts_json_serialize_value(ts, &buf[len], buf_size - len, object); if (len >= buf_size - 1) { return 0; } - buf[--len] = '\0'; // overwrite comma + buf[--len] = '\0'; // overwrite comma } return len; diff --git a/test/main.cpp b/test/main.cpp index 85b8904..b976f0d 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -71,6 +71,7 @@ void tests_text_mode() RUN_TEST(test_txt_statement_subset); RUN_TEST(test_txt_statement_group); RUN_TEST(test_txt_statement_record); + RUN_TEST(test_txt_statement_item); RUN_TEST(test_txt_pub_list_channels); RUN_TEST(test_txt_pub_enable); RUN_TEST(test_txt_pub_delete_append_object); diff --git a/test/test.h b/test/test.h index f89f108..0acdec2 100644 --- a/test/test.h +++ b/test/test.h @@ -34,6 +34,7 @@ extern "C" { #define ID_DFU 0x0D // device firmware upgrade #define ID_RPC 0x0E // remote procedure calls #define ID_PUB 0x0F // publication setup +#define ID_TXT 0x10 // txt statement test #define SUBSET_REPORT (1U << 0) // report subset of data items for publication #define SUBSET_CAN (1U << 1) // data nodes used for CAN bus publication messages @@ -163,6 +164,7 @@ void test_txt_fn_int32(void); void test_txt_statement_subset(void); void test_txt_statement_group(void); void test_txt_statement_record(void); +void test_txt_statement_item(void); void test_txt_pub_list_channels(void); void test_txt_pub_enable(void); void test_txt_pub_delete_append_object(void); diff --git a/test/test_data.c b/test/test_data.c index ff3cbc5..e69619e 100644 --- a/test/test_data.c +++ b/test/test_data.c @@ -38,6 +38,21 @@ bool pub_report_enable = false; uint16_t pub_report_interval = 1000; bool pub_info_enable = true; +// txt_statement +static float txt_st_float_pos = 12.53; +static float txt_st_float_neg = -2.3; +static int8_t txt_st_int8_pos = 120; +static int8_t txt_st_int8_neg = -123; +static int16_t txt_st_int16_pos = 32760; +static int16_t txt_st_int16_neg = -32750; +static int32_t txt_st_int32_pos = 2147483568; +static int32_t txt_st_int32_neg = -2147483450; +static uint8_t txt_st_uint8 = 254; +static uint16_t txt_st_uint16 = 64050; +static uint32_t txt_st_uint32 = 3399612978; +static bool txt_st_bool_true = true; +static bool txt_st_bool_false = false; + // exec void reset_function(void); void auth_function(void); @@ -240,6 +255,52 @@ struct ts_data_object data_objects[] = { TS_ITEM_BOOL(0xF6, "wOnChange", &pub_info_enable, 0xF5, TS_ANY_RW, 0), + + // TXT STATEMTENT DATA /////////////////////////////////////////////////////// + + TS_GROUP(ID_TXT,"TXT",TS_NO_CALLBACK,ID_ROOT), + + TS_ITEM_FLOAT(0x101, "rFloatPos", &txt_st_float_pos, 2, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_FLOAT(0x102, "rFloatNeg", &txt_st_float_neg, 2, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_INT8(0x103, "rInt8Pos", &txt_st_int8_pos, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_INT8(0x104, "rInt8Neg", &txt_st_int8_neg, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_INT16(0x105, "rInt16Pos", &txt_st_int16_pos, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_INT16(0x106, "rInt16Neg", &txt_st_int16_neg, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_INT32(0x107, "rInt32Pos", &txt_st_int32_pos, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_INT32(0x108, "rInt32Neg", &txt_st_int32_neg, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_UINT8(0x109, "rUint8", &txt_st_uint8, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_UINT16(0x10A, "rUint16", &txt_st_uint16, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_UINT32(0x10B, "rUint32", &txt_st_uint32, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_BOOL(0x10C, "rBoolTrue", &txt_st_bool_true, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + TS_ITEM_BOOL(0x10D, "rBoolFalse", &txt_st_bool_false, + ID_TXT, TS_ANY_R, SUBSET_REPORT), + + + // UNIT TEST DATA ///////////////////////////////////////////////////////// // using IDs >= 0x1000 diff --git a/test/test_txt.c b/test/test_txt.c index 7388d27..7cbccc7 100644 --- a/test/test_txt.c +++ b/test/test_txt.c @@ -237,6 +237,40 @@ void test_txt_statement_record(void) TEST_ASSERT_TXT_RESP(resp_len, expected); } + + +void test_txt_statement_item(void) +{ + + const struct { + const char* path; + const char* value; + } tests[] ={ + {"TXT/rFloatPos","12.53"}, + {"TXT/rFloatNeg","-2.30"}, + {"TXT/rInt8Pos","120"}, + {"TXT/rInt8Neg","-123"}, + {"TXT/rInt16Pos","32760"}, + {"TXT/rInt16Pos","-32750"}, + {"TXT/rInt32Pos","2147483568"}, + {"TXT/rInt32Pos","-2147483450"}, + {"TXT/rUint8","254"}, + {"TXT/rUint16","64050"}, + {"TXT/rUint32","3399612978"}, + {"TXT/rBoolTrue","true"}, + {"TXT/rBoolFalse","false"}, + }; + + for (size_t i=0;i Date: Thu, 12 Jan 2023 00:05:09 +0100 Subject: [PATCH 3/7] Adding test for txt_statement --- zephyr/tests/src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zephyr/tests/src/main.c b/zephyr/tests/src/main.c index 306a079..c71aeb1 100644 --- a/zephyr/tests/src/main.c +++ b/zephyr/tests/src/main.c @@ -61,6 +61,7 @@ void test_main(void) ztest_unit_test_setup_teardown(test_txt_statement_subset, setup, teardown), ztest_unit_test_setup_teardown(test_txt_statement_group, setup, teardown), ztest_unit_test_setup_teardown(test_txt_statement_record, setup, teardown), + ztest_unit_test_setup_teardown(test_txt_statement_item, setup, teardown), ztest_unit_test_setup_teardown(test_txt_pub_list_channels, setup, teardown), ztest_unit_test_setup_teardown(test_txt_pub_enable, setup, teardown), ztest_unit_test_setup_teardown(test_txt_pub_delete_append_object, setup, teardown), From 93f062a923cfc481b30e7346fd33bb86a56a6627 Mon Sep 17 00:00:00 2001 From: Nicolas Veloz Savino Date: Thu, 12 Jan 2023 09:49:48 +0100 Subject: [PATCH 4/7] Fixing duplicated TS_T_BOOL case on thingset_txt.c --- src/thingset_txt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/thingset_txt.c b/src/thingset_txt.c index ce8f9aa..7055eac 100644 --- a/src/thingset_txt.c +++ b/src/thingset_txt.c @@ -118,8 +118,6 @@ static int json_serialize_simple_value(char *buf, size_t size, void *data, int t return snprintf(buf, size, "%" PRIu8 ",", *((uint8_t *)data)); case TS_T_INT8: return snprintf(buf, size, "%" PRIi8 ",", *((int8_t *)data)); - case TS_T_BOOL: - return snprintf(buf,size, *((bool *)data)?"true":"false"); case TS_T_FLOAT32: { float value = *((float *)data); if (isnan(value) || isinf(value)) { From a0a5f7861bd0a53904a257e5f29e9a2c2df13a04 Mon Sep 17 00:00:00 2001 From: Nicolas Veloz Savino Date: Thu, 19 Jan 2023 18:47:01 +0100 Subject: [PATCH 5/7] Fixing get path for nested objects --- src/thingset.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/thingset.c b/src/thingset.c index 06b3b8c..a608e4d 100644 --- a/src/thingset.c +++ b/src/thingset.c @@ -179,24 +179,37 @@ struct ts_data_object *ts_get_object_by_path(struct ts_context *ts, const char * int ts_get_path(struct ts_context *ts, char *buf, size_t size, const struct ts_data_object *obj) { + int pos = 0; - if (obj->parent == 0) { + if (obj->parent == 0) + { + pos = snprintf(buf, size, "%s", obj->name); } - else { + else + { + struct ts_data_object *parent_obj = ts_get_object_by_id(ts, obj->parent); - if (parent_obj != NULL) { - pos = snprintf(buf, size, "%s/%s", parent_obj->name, obj->name); + if (parent_obj != NULL) + { + pos = ts_get_path(ts, buf, size, parent_obj); } - else { + else + { + return 0; + } + if (pos >= size) + { return 0; } + pos += snprintf(&buf[pos], size - pos, "/%s", obj->name); } - - if (pos < size) { + if (pos < size) + { return pos; } - else { + else + { // path did not fit into the buffer return 0; } From 0e93f34fe9927184439a3794cb8bd48f1532b830 Mon Sep 17 00:00:00 2001 From: Nicolas Veloz Savino Date: Thu, 19 Jan 2023 23:39:41 +0100 Subject: [PATCH 6/7] Fixing format --- src/thingset.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/thingset.c b/src/thingset.c index a608e4d..add8900 100644 --- a/src/thingset.c +++ b/src/thingset.c @@ -179,37 +179,27 @@ struct ts_data_object *ts_get_object_by_path(struct ts_context *ts, const char * int ts_get_path(struct ts_context *ts, char *buf, size_t size, const struct ts_data_object *obj) { - int pos = 0; - if (obj->parent == 0) - { - + if (obj->parent == 0) { pos = snprintf(buf, size, "%s", obj->name); } - else - { - + else { struct ts_data_object *parent_obj = ts_get_object_by_id(ts, obj->parent); - if (parent_obj != NULL) - { + if (parent_obj != NULL) { pos = ts_get_path(ts, buf, size, parent_obj); } - else - { + else { return 0; } - if (pos >= size) - { + if (pos >= size) { return 0; } pos += snprintf(&buf[pos], size - pos, "/%s", obj->name); } - if (pos < size) - { + if (pos < size) { return pos; } - else - { + else { // path did not fit into the buffer return 0; } From 5f7fd1e384b1753e444b63f91a1fb1de8093a387 Mon Sep 17 00:00:00 2001 From: Nicolas Veloz Savino Date: Thu, 19 Jan 2023 23:49:00 +0100 Subject: [PATCH 7/7] Adding .clang-format from LibreSolar to help formating --- .clang-format | 33 +++++++++++++++++++++++++++++++++ src/thingset.c | 23 ++++++++++++----------- 2 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..1430b10 --- /dev/null +++ b/.clang-format @@ -0,0 +1,33 @@ +# Format definition for Libre Solar firmware +# +# Use Clang-Format plugin in VS Code and add "editor.formatOnSave": true to settings + +# Generic format +BasedOnStyle: LLVM +UseTab: Never +IndentWidth: 4 +TabWidth: 4 +ColumnLimit: 100 +AccessModifierOffset: -4 + +# Indentation and alignment +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AlignConsecutiveAssignments: false +AlignConsecutiveMacros: true +AlignEscapedNewlines: DontAlign +BreakBeforeBinaryOperators: NonAssignment +IndentCaseLabels: true + +# Braces +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: true + AfterControlStatement: MultiLine + AfterEnum: true + AfterStruct: true + AfterFunction: true + BeforeElse: true + SplitEmptyFunction: false +Cpp11BracedListStyle: false diff --git a/src/thingset.c b/src/thingset.c index add8900..2eefea8 100644 --- a/src/thingset.c +++ b/src/thingset.c @@ -59,8 +59,8 @@ int ts_init_global(struct ts_context *ts) #endif -int ts_process(struct ts_context *ts, const uint8_t *request, size_t request_len, - uint8_t *response, size_t response_size) +int ts_process(struct ts_context *ts, const uint8_t *request, size_t request_len, uint8_t *response, + size_t response_size) { // check if proper request was set before asking for a response if (request == NULL || request_len < 1) { @@ -77,8 +77,9 @@ int ts_process(struct ts_context *ts, const uint8_t *request, size_t request_len // binary mode request return ts_bin_process(ts); } - else if (ts->req[0] == '?' || ts->req[0] == '=' || ts->req[0] == '+' - || ts->req[0] == '-' || ts->req[0] == '!') { + else if (ts->req[0] == '?' || ts->req[0] == '=' || ts->req[0] == '+' || ts->req[0] == '-' + || ts->req[0] == '!') + { // text mode request return ts_txt_process(ts); } @@ -100,16 +101,16 @@ void ts_set_update_callback(struct ts_context *ts, const uint16_t subsets, void ts->update_cb = update_cb; } -struct ts_data_object *ts_get_object_by_name(struct ts_context *ts, const char *name, - size_t len, int32_t parent) +struct ts_data_object *ts_get_object_by_name(struct ts_context *ts, const char *name, size_t len, + int32_t parent) { for (unsigned int i = 0; i < ts->num_objects; i++) { if (parent != -1 && ts->data_objects[i].parent != parent) { continue; } else if (strncmp(ts->data_objects[i].name, name, len) == 0 - // without length check foo and fooBar would be recognized as equal - && strlen(ts->data_objects[i].name) == len) + // without length check foo and fooBar would be recognized as equal + && strlen(ts->data_objects[i].name) == len) { return &(ts->data_objects[i]); } @@ -128,7 +129,7 @@ struct ts_data_object *ts_get_object_by_id(struct ts_context *ts, ts_object_id_t } struct ts_data_object *ts_get_endpoint_by_path(struct ts_context *ts, const char *path, size_t len, - int *index) + int *index) { struct ts_data_object *object = NULL; const char *start = path; @@ -140,8 +141,8 @@ struct ts_data_object *ts_get_endpoint_by_path(struct ts_context *ts, const char end = strchr(start, '/'); if (end == NULL || end >= path + len) { // we are at the end of the path - if (object != NULL && object->type == TS_T_RECORDS && - start[0] >= '0' && start[0] <= '9') + if (object != NULL && object->type == TS_T_RECORDS && start[0] >= '0' + && start[0] <= '9') { // numeric ID, only valid to select index in an array of records if (index != NULL) {