diff --git a/include/thingset.h b/include/thingset.h index f6eae95..c77e272 100644 --- a/include/thingset.h +++ b/include/thingset.h @@ -1822,6 +1822,25 @@ struct thingset_data_object *thingset_iterate_subsets(struct thingset_context *t int thingset_import_data(struct thingset_context *ts, const uint8_t *data, size_t len, uint8_t auth_flags, enum thingset_data_format format); +/** + * Import report into data objects. + * + * This function allows importing data objects from a received report. + * + * Unknown data items are silently ignored. + * + * @param ts Pointer to ThingSet context. + * @param data Buffer containing ID/value map that should be written to the data objects + * @param len Length of the data in the buffer + * @param auth_flags Authentication flags to be used in this function (to override auth_flags) + * @param format Protocol data format to be used (text, binary with IDs or binary with names) + * @param subset The subset associated with the published report + * + * @returns 0 for success or negative ThingSet response code in case of error + */ +int thingset_import_report(struct thingset_context *ts, const uint8_t *data, size_t len, + uint8_t auth_flags, enum thingset_data_format format, uint16_t subset); + /** * EXPERIMENTAL * diff --git a/src/thingset.c b/src/thingset.c index 726fae1..508b8cf 100644 --- a/src/thingset.c +++ b/src/thingset.c @@ -349,6 +349,41 @@ int thingset_import_data(struct thingset_context *ts, const uint8_t *data, size_ return err; } +int thingset_import_report(struct thingset_context *ts, const uint8_t *data, size_t len, + uint8_t auth_flags, enum thingset_data_format format, uint16_t subset) +{ + int err; + + if (k_sem_take(&ts->lock, K_MSEC(THINGSET_CONTEXT_LOCK_TIMEOUT_MS)) != 0) { + LOG_ERR("ThingSet context lock timed out"); + return -THINGSET_ERR_INTERNAL_SERVER_ERR; + } + + ts->msg = data; + ts->msg_len = len; + ts->msg_pos = 0; + ts->rsp = NULL; + ts->rsp_size = 0; + ts->rsp_pos = 0; + + switch (format) { + case THINGSET_BIN_IDS_VALUES: + ts->endpoint.use_ids = true; + thingset_bin_setup(ts, 0); + ts->decoder->elem_count = 2; + ts->msg_payload = data; + err = thingset_bin_import_report(ts, auth_flags, subset); + break; + default: + err = -THINGSET_ERR_NOT_IMPLEMENTED; + break; + } + + k_sem_give(&ts->lock); + + return err; +} + static int deserialize_value_callback(struct thingset_context *ts, const struct thingset_data_object *item_offset) { diff --git a/src/thingset_bin.c b/src/thingset_bin.c index 94077e8..0a8c401 100644 --- a/src/thingset_bin.c +++ b/src/thingset_bin.c @@ -931,6 +931,22 @@ int thingset_bin_import_data(struct thingset_context *ts, uint8_t auth_flags, return ts->api->deserialize_finish(ts); } +int thingset_bin_import_report(struct thingset_context *ts, uint8_t auth_flags, uint16_t subset) +{ + uint32_t id = 0; + + if (ts->msg_payload[0] != THINGSET_BIN_REPORT) { + return -THINGSET_ERR_UNSUPPORTED_FORMAT; + } + + zcbor_uint32_decode(ts->decoder, &id); + if (id != subset) { + return -THINGSET_ERR_NOT_FOUND; + } + + return thingset_bin_import_data(ts, auth_flags, subset); +} + int thingset_bin_process(struct thingset_context *ts) { int ret; diff --git a/src/thingset_internal.h b/src/thingset_internal.h index 9e9aede..f9e000c 100644 --- a/src/thingset_internal.h +++ b/src/thingset_internal.h @@ -377,6 +377,8 @@ void thingset_bin_setup(struct thingset_context *ts, size_t buf_offset); int thingset_bin_import_data(struct thingset_context *ts, uint8_t auth_flags, enum thingset_data_format format); +int thingset_bin_import_report(struct thingset_context *ts, uint8_t auth_flags, uint16_t subset); + int thingset_bin_import_data_progressively(struct thingset_context *ts, uint8_t auth_flags, size_t size, uint32_t *last_id, size_t *consumed); diff --git a/tests/common/data.c b/tests/common/data.c index 745c083..54d9f0d 100644 --- a/tests/common/data.c +++ b/tests/common/data.c @@ -423,3 +423,23 @@ struct thingset_data_object data_objects[] = { }; size_t data_objects_size = ARRAY_SIZE(data_objects); + +/* + * Test case for importing reports with initial zero values. + */ +uint32_t report_timestamp = 0; +bool report_b = false; +int32_t report_nested_beginning = 0; +float report_nested_obj2_item2 = 0.0; + +struct thingset_data_object report_data_objects[] = { + THINGSET_ITEM_UINT32(THINGSET_ID_ROOT, 0x10, "t_s", &report_timestamp, THINGSET_ANY_RW, + SUBSET_LIVE), + THINGSET_ITEM_BOOL(0x200, 0x201, "wBool", &report_b, THINGSET_ANY_RW, SUBSET_LIVE), + THINGSET_ITEM_INT32(0x700, 0x701, "rBeginning", &report_nested_beginning, THINGSET_ANY_RW, + SUBSET_LIVE), + THINGSET_ITEM_FLOAT(0x706, 0x708, "rItem2_V", &report_nested_obj2_item2, 1, THINGSET_ANY_RW, + SUBSET_LIVE), +}; + +size_t report_data_objects_size = ARRAY_SIZE(report_data_objects); diff --git a/tests/protocol/src/bin.c b/tests/protocol/src/bin.c index 55a50ae..3f51e8d 100644 --- a/tests/protocol/src/bin.c +++ b/tests/protocol/src/bin.c @@ -13,6 +13,13 @@ #include "data.h" #include "test_utils.h" +extern struct thingset_data_object report_data_objects[]; +extern size_t report_data_objects_size; +extern uint32_t report_timestamp; +extern bool report_b; +extern int32_t report_nested_beginning; +extern float report_nested_obj2_item2; + static struct thingset_context ts; ZTEST(thingset_bin, test_get_root_ids) @@ -985,6 +992,63 @@ ZTEST(thingset_bin, test_import_data) b = true; } +ZTEST(thingset_bin, test_import_report) +{ + uint8_t data[THINGSET_TEST_BUF_SIZE]; + + const char rpt_exp_hex[] = + "1F 19 08 00 A5 " + "10 19 03 E8 " /* t_s */ + "19 02 01 F5 " /* Types/wBool */ + "19 06 00 02 " /* Records: 2 */ + "19 07 01 01 " /* Nested/rBeginning */ + "19 07 08 FA 40 0C CC CD"; /* Nested/Obj2/rItem2_V */ + + struct thingset_context ts_local; + thingset_init(&ts_local, report_data_objects, report_data_objects_size); + + int data_len = hex2bin_spaced(rpt_exp_hex, data, sizeof(data)); + + int status = thingset_import_report(&ts_local, data, data_len, THINGSET_WRITE_MASK, + THINGSET_BIN_IDS_VALUES, 0x800); + + zassert_equal(status, 0); + zassert_equal(report_timestamp, 1000); + zassert_equal(report_b, true); + zassert_equal(report_nested_beginning, 1); + zassert_equal(report_nested_obj2_item2, 2.2F); +} + +ZTEST(thingset_bin, test_import_report_error) +{ + uint8_t data[THINGSET_TEST_BUF_SIZE]; + + const char rpt_exp_hex[] = + "1F 19 08 00 A5 " + "10 19 03 E8 " /* t_s */ + "19 02 01 F5 " /* Types/wBool */ + "19 06 00 02 " /* Records: 2 */ + "19 07 01 01 " /* Nested/rBeginning */ + "19 07 08 FA 40 0C CC CD"; /* Nested/Obj2/rItem2_V */ + + struct thingset_context ts_local; + thingset_init(&ts_local, report_data_objects, report_data_objects_size); + + int data_len = hex2bin_spaced(rpt_exp_hex, data, sizeof(data)); + + /* no report */ + data[0] = 0x00; + int status = thingset_import_report(&ts_local, data, data_len, THINGSET_WRITE_MASK, + THINGSET_BIN_IDS_VALUES, 0x800); + zassert_equal(status, -THINGSET_ERR_UNSUPPORTED_FORMAT); + + /* wrong subset */ + data[0] = 0x1f; + status = thingset_import_report(&ts_local, data, data_len, THINGSET_WRITE_MASK, + THINGSET_BIN_IDS_VALUES, 0x0); + zassert_equal(status, -THINGSET_ERR_NOT_FOUND); +} + ZTEST(thingset_bin, test_import_record) { struct thingset_endpoint endpoint;