diff --git a/subsys/net/lib/lwm2m/CMakeLists.txt b/subsys/net/lib/lwm2m/CMakeLists.txt index 54d7964f41f..3ef2077d22c 100644 --- a/subsys/net/lib/lwm2m/CMakeLists.txt +++ b/subsys/net/lib/lwm2m/CMakeLists.txt @@ -59,6 +59,12 @@ zephyr_library_sources_ifdef(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT zephyr_library_sources_ifdef(CONFIG_LWM2M_RW_CBOR_SUPPORT lwm2m_rw_cbor.c ) +# SENML CBOR support +zephyr_library_sources_ifdef(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT + lwm2m_rw_senml_cbor.c + lwm2m_senml_cbor_decode.c + lwm2m_senml_cbor_encode.c + ) # IPSO Objects zephyr_library_sources_ifdef(CONFIG_LWM2M_IPSO_TEMP_SENSOR diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index f2a4901390b..6651902fb67 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -447,6 +447,21 @@ config LWM2M_RW_CBOR_SUPPORT help Include support for writing CBOR data +config LWM2M_RW_SENML_CBOR_SUPPORT + bool "support for SenML CBOR writer" + depends on ZCBOR + depends on ZCBOR_CANONICAL + help + Include support for writing SenML CBOR data + +config LWM2M_RW_SENML_CBOR_RECORDS + int "Maximum # of SenML records packed into a CBOR binary" + depends on LWM2M_RW_SENML_CBOR_SUPPORT + default 30 + help + The CBOR library requires you to set an upper limit for the records when encoder + and decoder do get generated. + config LWM2M_DEVICE_PWRSRC_MAX int "Maximum # of device power source records" default 5 diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 4b29072ba52..a5a9e1ee1bf 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -54,6 +54,9 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #ifdef CONFIG_LWM2M_RW_CBOR_SUPPORT #include "lwm2m_rw_cbor.h" #endif +#ifdef CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT +#include "lwm2m_rw_senml_cbor.h" +#endif #ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT #include "lwm2m_rd_client.h" #endif @@ -1685,6 +1688,12 @@ static int select_writer(struct lwm2m_output_context *out, uint16_t accept) break; #endif +#ifdef CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT + case LWM2M_FORMAT_APP_SENML_CBOR: + out->writer = &senml_cbor_writer; + break; +#endif + default: LOG_WRN("Unknown content type %u", accept); return -ENOMSG; @@ -1730,6 +1739,13 @@ static int select_reader(struct lwm2m_input_context *in, uint16_t format) break; #endif +#ifdef CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT + case LWM2M_FORMAT_APP_SENML_CBOR: + in->reader = &senml_cbor_reader; + break; +#endif + + default: LOG_WRN("Unknown content type %u", format); return -ENOMSG; @@ -3799,6 +3815,11 @@ static int do_read_op(struct lwm2m_message *msg, uint16_t content_format) return do_read_op_cbor(msg); #endif +#if defined(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT) + case LWM2M_FORMAT_APP_SENML_CBOR: + return do_read_op_senml_cbor(msg); +#endif + default: LOG_ERR("Unsupported content-format: %u", content_format); return -ENOMSG; @@ -3815,6 +3836,11 @@ static int do_composite_read_op(struct lwm2m_message *msg, uint16_t content_form return do_composite_read_op_senml_json(msg); #endif +#if defined(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT) + case LWM2M_FORMAT_APP_SENML_CBOR: + return do_composite_read_op_senml_cbor(msg); +#endif + default: LOG_ERR("Unsupported content-format: %u", content_format); return -ENOMSG; @@ -3833,6 +3859,12 @@ static int do_composite_observe_read_path_op(struct lwm2m_message *msg, uint16_t lwm2m_path_free_list); #endif +#if defined(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT) + case LWM2M_FORMAT_APP_SENML_CBOR: + return do_composite_observe_parse_path_senml_cbor(msg, lwm2m_path_list, + lwm2m_path_free_list); +#endif + default: LOG_ERR("Unsupported content-format: %u", content_format); return -ENOMSG; @@ -4350,6 +4382,11 @@ static int do_write_op(struct lwm2m_message *msg, return do_write_op_cbor(msg); #endif +#ifdef CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT + case LWM2M_FORMAT_APP_SENML_CBOR: + return do_write_op_senml_cbor(msg); +#endif + default: LOG_ERR("Unsupported format: %u", format); return -ENOMSG; @@ -4366,6 +4403,11 @@ static int do_composite_write_op(struct lwm2m_message *msg, return do_write_op_senml_json(msg); #endif +#if defined(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT) + case LWM2M_FORMAT_APP_SENML_CBOR: + return do_write_op_senml_cbor(msg); +#endif + default: LOG_ERR("Unsupported format: %u", format); return -ENOMSG; @@ -4523,7 +4565,10 @@ static int lwm2m_engine_default_content_format(uint16_t *accept_format) { if (IS_ENABLED(CONFIG_LWM2M_VERSION_1_1)) { /* Select content format use SenML CBOR when it possible */ - if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT)) { + if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT)) { + LOG_DBG("No accept option given. Assume SenML CBOR."); + *accept_format = LWM2M_FORMAT_APP_SENML_CBOR; + } else if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT)) { LOG_DBG("No accept option given. Assume SenML Json."); *accept_format = LWM2M_FORMAT_APP_SEML_JSON; } else if (IS_ENABLED(CONFIG_LWM2M_RW_CBOR_SUPPORT)) { @@ -6341,6 +6386,11 @@ static int do_send_op(struct lwm2m_message *msg, uint16_t content_format, return do_send_op_senml_json(msg, lwm2m_path_list); #endif +#if defined(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT) + case LWM2M_FORMAT_APP_SENML_CBOR: + return do_send_op_senml_cbor(msg, lwm2m_path_list); +#endif + default: LOG_ERR("Unsupported content-format for /dp: %u", content_format); return -ENOMSG; @@ -6404,8 +6454,9 @@ int lwm2m_engine_send(struct lwm2m_ctx *ctx, char const *path_list[], uint8_t pa return -E2BIG; } - /* Select content format use CBOR when it possible */ - if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT)) { + if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT)) { + content_format = LWM2M_FORMAT_APP_SENML_CBOR; + } else if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT)) { content_format = LWM2M_FORMAT_APP_SEML_JSON; } else { LOG_WRN("SenML CBOR or JSON is not supported"); diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index d5d54666189..b7b0ff1fb5e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -29,6 +29,7 @@ #define LWM2M_FORMAT_APP_JSON 50 #define LWM2M_FORMAT_APP_CBOR 60 #define LWM2M_FORMAT_APP_SEML_JSON 110 +#define LWM2M_FORMAT_APP_SENML_CBOR 112 #define LWM2M_FORMAT_OMA_PLAIN_TEXT 1541 #define LWM2M_FORMAT_OMA_OLD_TLV 1542 #define LWM2M_FORMAT_OMA_OLD_JSON 1543 diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index abdf14bc195..df625a2aa9e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -428,7 +428,9 @@ struct lwm2m_senml_json_context senml_json_ctx; uint8_t token[8]; uint8_t tkl; bool last_block : 1; + uint8_t level; /* 3/4 (4 = resource instance) */ uint16_t res_id; + uint16_t res_inst_id; }; struct lwm2m_output_context { diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.c b/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.c new file mode 100644 index 00000000000..54436e48370 --- /dev/null +++ b/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.c @@ -0,0 +1,898 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_MODULE_NAME net_lwm2m_senml_cbor +#define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "lwm2m_engine.h" +#include "lwm2m_object.h" +#include "lwm2m_rw_senml_cbor.h" +#include "lwm2m_senml_cbor_decode.h" +#include "lwm2m_senml_cbor_encode.h" +#include "lwm2m_senml_cbor_types.h" +#include "lwm2m_util.h" + +struct cbor_out_fmt_data { + /* Data */ + struct lwm2m_senml input; + + /* Storage for basenames and names ~ sizeof("/65535/999/") */ + struct { + char names[CONFIG_LWM2M_RW_SENML_CBOR_RECORDS][sizeof("/65535/999/")]; + size_t name_sz; /* Name buff size */ + uint8_t name_cnt; + }; +}; + +struct cbor_in_fmt_data { + /* Decoded data */ + struct lwm2m_senml dcd; /* Decoded data */ + struct record *current; + char basename[sizeof("/65535/999/")]; /* Null terminated basename */ +}; + +#define GET_CBOR_FD_NAME(fd) ((fd)->names[(fd)->name_cnt]) +/* Get the current record */ +#define GET_CBOR_FD_REC(fd) \ + &((fd)->input._lwm2m_senml__record[(fd)->input._lwm2m_senml__record_count]) +/* Get a record */ +#define GET_IN_FD_REC_I(fd, i) &((fd)->dcd._lwm2m_senml__record[i]) +/* Consume the current record */ +#define CONSUME_CBOR_FD_REC(fd) \ + &((fd)->input._lwm2m_senml__record[(fd)->input._lwm2m_senml__record_count++]) +/* Get CBOR output formatter data */ +#define LWM2M_OFD_CBOR(octx) ((struct cbor_out_fmt_data *)engine_get_out_user_data(octx)) + +static struct cbor_out_fmt_data *setup_out_fmt_data(struct lwm2m_message *msg) +{ + struct cbor_out_fmt_data *fd = malloc(sizeof(*fd)); + + if (!fd) { + return NULL; + } + + (void)memset(fd, 0, sizeof(*fd)); + engine_set_out_user_data(&msg->out, fd); + fd->name_sz = sizeof("/65535/999/"); + + return fd; +} + +static void clear_out_fmt_data(struct lwm2m_message *msg, struct cbor_out_fmt_data *fd) +{ + free(fd); + fd = NULL; + + engine_clear_out_user_data(&msg->out); +} + +static struct cbor_in_fmt_data *setup_in_fmt_data(struct lwm2m_message *msg) +{ + struct cbor_in_fmt_data *fd = malloc(sizeof(*fd)); + + if (!fd) { + return NULL; + } + + (void)memset(fd, 0, sizeof(*fd)); + engine_set_in_user_data(&msg->in, fd); + + return fd; +} + +static void clear_in_fmt_data(struct lwm2m_message *msg, struct cbor_in_fmt_data *fd) +{ + free(fd); + fd = NULL; + + engine_clear_in_user_data(&msg->in); +} + +static int put_basename(struct lwm2m_output_context *out, struct lwm2m_obj_path *path) +{ + struct cbor_out_fmt_data *fd = LWM2M_OFD_CBOR(out); + int len; + + if (fd->name_cnt >= CONFIG_LWM2M_RW_SENML_CBOR_RECORDS) { + LOG_ERR("CONFIG_LWM2M_RW_SENML_CBOR_RECORDS too small"); + return -ENOMEM; + } + + char *basename = GET_CBOR_FD_NAME(fd); + + len = lwm2m_path_to_string(basename, fd->name_sz, path, LWM2M_PATH_LEVEL_OBJECT_INST); + + if (len < 0) { + return len; + } + + /* Tell CBOR encoder where to find the name */ + struct record *record = GET_CBOR_FD_REC(fd); + + record->_record_bn._record_bn.value = basename; + record->_record_bn._record_bn.len = len; + record->_record_bn_present = 1; + + if ((len < sizeof("0/0") - 1) || (len >= sizeof("65535/999"))) { + __ASSERT_NO_MSG(false); + return -EINVAL; + } + + fd->name_cnt++; + + return 0; +} + +static int put_end(struct lwm2m_output_context *out, struct lwm2m_obj_path *path) +{ + size_t len; + + uint_fast8_t ret = + cbor_encode_lwm2m_senml(CPKT_BUF_W_REGION(out->out_cpkt), + (struct lwm2m_senml *)&(LWM2M_OFD_CBOR(out)->input), &len); + + if (ret != ZCBOR_SUCCESS) { + LOG_ERR("unable to encode senml cbor msg"); + + return -E2BIG; + } + + out->out_cpkt->offset += len; + + return len; +} + +static int put_begin_oi(struct lwm2m_output_context *out, struct lwm2m_obj_path *path) +{ + int ret; + uint8_t tmp = path->level; + + /* In case path level is set to 'none' or 'object' and we have only default oi */ + path->level = LWM2M_PATH_LEVEL_OBJECT_INST; + + ret = put_basename(out, path); + path->level = tmp; + + return ret; +} + +static int put_begin_r(struct lwm2m_output_context *out, struct lwm2m_obj_path *path) +{ + struct cbor_out_fmt_data *fd = LWM2M_OFD_CBOR(out); + int len; + + if (fd->name_cnt >= CONFIG_LWM2M_RW_SENML_CBOR_RECORDS) { + LOG_ERR("CONFIG_LWM2M_RW_SENML_CBOR_RECORDS too small"); + return -ENOMEM; + } + + char *name = GET_CBOR_FD_NAME(fd); + + /* Write resource name */ + len = snprintk(name, sizeof("65535"), "%" PRIu16 "", path->res_id); + + if (len < sizeof("0") - 1) { + __ASSERT_NO_MSG(false); + return -EINVAL; + } + + /* Check if we could use an already existing name + * -> latest name slot is used as a scratchpad + */ + for (int idx = 0; idx < fd->name_cnt; idx++) { + if (strncmp(name, fd->names[idx], len) == 0) { + name = fd->names[idx]; + break; + } + } + + /* Tell CBOR encoder where to find the name */ + struct record *record = GET_CBOR_FD_REC(fd); + + record->_record_n._record_n.value = name; + record->_record_n._record_n.len = len; + record->_record_n_present = 1; + + /* Makes possible to use same slot for storing r/ri name combination. + * No need to increase the name count if an existing name has been used + */ + if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST && name == GET_CBOR_FD_NAME(fd)) { + fd->name_cnt++; + } + + return 0; +} + +static int put_begin_ri(struct lwm2m_output_context *out, struct lwm2m_obj_path *path) +{ + struct cbor_out_fmt_data *fd = LWM2M_OFD_CBOR(out); + char *name = GET_CBOR_FD_NAME(fd); + struct record *record = GET_CBOR_FD_REC(fd); + + if (fd->name_cnt >= CONFIG_LWM2M_RW_SENML_CBOR_RECORDS) { + LOG_ERR("CONFIG_LWM2M_RW_SENML_CBOR_RECORDS too small"); + return -ENOMEM; + } + + /* Forms name from resource id and resource instance id */ + int len = snprintk(name, sizeof("65535/999"), + "%" PRIu16 "/%" PRIu16 "", + path->res_id, path->res_inst_id); + + if (len < sizeof("0/0") - 1) { + __ASSERT_NO_MSG(false); + return -EINVAL; + } + + /* Check if we could use an already existing name + * -> latest name slot is used as a scratchpad + */ + for (int idx = 0; idx < fd->name_cnt; idx++) { + if (strncmp(name, fd->names[idx], len) == 0) { + name = fd->names[idx]; + break; + } + } + + /* Tell CBOR encoder where to find the name */ + record->_record_n._record_n.value = name; + record->_record_n._record_n.len = len; + record->_record_n_present = 1; + + /* No need to increase the name count if an existing name has been used */ + if (name == GET_CBOR_FD_NAME(fd)) { + fd->name_cnt++; + } + + return 0; +} + +static int put_name_nth_ri(struct lwm2m_output_context *out, struct lwm2m_obj_path *path) +{ + int ret = 0; + + /* With the first ri the resource name (and ri name) are already in place */ + if (path->res_inst_id > 0) { + ret = put_begin_ri(out, path); + } + + return ret; +} + +static int put_value(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int64_t value) +{ + int ret = put_name_nth_ri(out, path); + + if (ret < 0) { + return ret; + } + + struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); + + /* Write the value */ + record->_record_union._record_union_choice = _union_v; + record->_record_union._union_v._numeric_choice = _numeric_int; + record->_record_union._union_v._numeric_int = value; + record->_record_union_present = 1; + + return 0; +} + +static int put_s8(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int8_t value) +{ + return put_value(out, path, value); +} + +static int put_s16(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int16_t value) +{ + return put_value(out, path, value); +} + +static int put_s32(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int32_t value) +{ + return put_value(out, path, value); +} + +static int put_s64(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int64_t value) +{ + return put_value(out, path, value); +} + +static int put_time(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int64_t value) +{ + int ret = put_name_nth_ri(out, path); + + if (ret < 0) { + return ret; + } + + struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); + + /* Write the value */ + record->_record_union._record_union_choice = _union_v; + record->_record_union._union_v._numeric_choice = _numeric_int; + record->_record_union._union_v._numeric_int = value; + record->_record_union_present = 1; + + return 0; +} + +static int put_float(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, double *value) +{ + int ret = put_name_nth_ri(out, path); + + if (ret < 0) { + return ret; + } + + struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); + + /* Write the value */ + record->_record_union._record_union_choice = _union_v; + record->_record_union._union_v._numeric_choice = _numeric_float; + record->_record_union._union_v._numeric_float = *value; + record->_record_union_present = 1; + + return 0; +} + +static int put_string(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, char *buf, + size_t buflen) +{ + int ret = put_name_nth_ri(out, path); + + if (ret < 0) { + return ret; + } + + struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); + + /* Write the value */ + record->_record_union._record_union_choice = _union_vs; + record->_record_union._union_vs.value = buf; + record->_record_union._union_vs.len = buflen; + record->_record_union_present = 1; + + return 0; +} + +static int put_bool(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, bool value) +{ + int ret = put_name_nth_ri(out, path); + + if (ret < 0) { + return ret; + } + + struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); + + /* Write the value */ + record->_record_union._record_union_choice = _union_vb; + record->_record_union._union_vb = value; + record->_record_union_present = 1; + + return 0; +} + +static int put_opaque(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, char *buf, + size_t buflen) +{ + int ret = put_name_nth_ri(out, path); + + if (ret < 0) { + return ret; + } + + struct record *record = CONSUME_CBOR_FD_REC(LWM2M_OFD_CBOR(out)); + + /* Write the value */ + record->_record_union._record_union_choice = _union_vd; + record->_record_union._union_vd.value = buf; + record->_record_union._union_vd.len = buflen; + record->_record_union_present = 1; + + return 0; +} + +static int put_objlnk(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, + struct lwm2m_objlnk *value) +{ + int32_t value_s32 = (value->obj_id << 16) | value->obj_inst; + + return put_s32(out, path, value_s32); +} + +static int get_opaque(struct lwm2m_input_context *in, + uint8_t *value, size_t buflen, + struct lwm2m_opaque_context *opaque, + bool *last_block) +{ + struct cbor_in_fmt_data *fd; + + /* Get the CBOR header only on first read. */ + if (opaque->remaining == 0) { + + fd = engine_get_in_user_data(in); + if (!fd || !fd->current) { + return -EINVAL; + } + + /* TODO: get the opaque data and it's length - + * now plain zero + */ + + opaque->len = fd->current->_record_union._union_vd.len; + opaque->remaining = fd->current->_record_union._union_vd.len; + + fd->current = NULL; + goto not_supported; + } + + return lwm2m_engine_get_opaque_more(in, value, buflen, + opaque, last_block); +not_supported: + return -ENOTSUP; +} + +static int get_s32(struct lwm2m_input_context *in, int32_t *value) +{ + struct cbor_in_fmt_data *fd; + + fd = engine_get_in_user_data(in); + if (!fd || !fd->current) { + return -EINVAL; + } + + *value = fd->current->_record_union._union_v._numeric_int; + fd->current = NULL; + + return 0; +} + +static int get_s64(struct lwm2m_input_context *in, int64_t *value) +{ + struct cbor_in_fmt_data *fd; + + fd = engine_get_in_user_data(in); + if (!fd || !fd->current) { + return -EINVAL; + } + + *value = fd->current->_record_union._union_v._numeric_int; + fd->current = NULL; + + return 0; +} + +static int get_float(struct lwm2m_input_context *in, double *value) +{ + struct cbor_in_fmt_data *fd; + + fd = engine_get_in_user_data(in); + if (!fd || !fd->current) { + return -EINVAL; + } + + *value = fd->current->_record_union._union_v._numeric_float; + fd->current = NULL; + + return 0; +} + +static int get_string(struct lwm2m_input_context *in, uint8_t *buf, size_t buflen) +{ + struct cbor_in_fmt_data *fd; + int len; + + fd = engine_get_in_user_data(in); + if (!fd || !fd->current) { + return -EINVAL; + } + + len = MIN(buflen-1, fd->current->_record_union._union_vs.len); + + memcpy(buf, fd->current->_record_union._union_vs.value, len); + buf[len] = '\0'; + + fd->current = NULL; + + return 0; +} + +static int get_objlnk(struct lwm2m_input_context *in, + struct lwm2m_objlnk *value) +{ + char objlnk[sizeof("65535:65535")] = {0}; + unsigned long id; + int ret; + + ret = get_string(in, objlnk, sizeof(objlnk)); + if (ret < 0) { + return ret; + } + + value->obj_id = LWM2M_OBJLNK_MAX_ID; + value->obj_inst = LWM2M_OBJLNK_MAX_ID; + + char *end; + char *idp = objlnk; + + for (int idx = 0; idx < 2; idx++) { + + errno = 0; + id = strtoul(idp, &end, 10); + + idp = end; + + if ((id == 0 && errno == ERANGE) || id > 65535) { + LOG_WRN("decoded id %lu out of range[0..65535]", id); + return -EBADMSG; + } + + switch (idx) { + case 0: + value->obj_id = id; + continue; + case 1: + value->obj_inst = id; + continue; + } + } + + if (value->obj_inst != LWM2M_OBJLNK_MAX_ID && (value->obj_id == LWM2M_OBJLNK_MAX_ID)) { + LOG_WRN("decoded obj inst id without obj id"); + return -EBADMSG; + } + + return ret; +} + +static int get_bool(struct lwm2m_input_context *in, bool *value) +{ + struct cbor_in_fmt_data *fd; + + fd = engine_get_in_user_data(in); + if (!fd || !fd->current) { + return -EINVAL; + } + + *value = fd->current->_record_union._union_vb; + fd->current = NULL; + + return 0; +} + +static int do_write_op_item(struct lwm2m_message *msg, struct record *rec) +{ + struct lwm2m_engine_obj_inst *obj_inst = NULL; + struct lwm2m_engine_obj_field *obj_field; + struct lwm2m_engine_res *res = NULL; + struct lwm2m_engine_res_inst *res_inst = NULL; + int ret; + uint8_t created = 0U; + struct cbor_in_fmt_data *fd; + + fd = engine_get_in_user_data(&msg->in); + if (!fd) { + return -EINVAL; + } + + /* Composite op - name with basename */ + if (rec->_record_n_present) { + char name[sizeof("65535/999")]; /* Null terminated name */ + int len = MIN(sizeof(name) - 1, rec->_record_n._record_n.len); + char fqn[MAX_RESOURCE_LEN + 1] = {0}; + + snprintk(name, len + 1, "%s", rec->_record_n._record_n.value); + + /* Form fully qualified path name */ + snprintk(fqn, sizeof(fqn), "%s%s", fd->basename, name); + + /* Set path on record basis */ + ret = lwm2m_string_to_path(fqn, &msg->path, '/'); + if (ret < 0) { + __ASSERT_NO_MSG(false); + return ret; + } + } + + fd->current = rec; + + ret = lwm2m_get_or_create_engine_obj(msg, &obj_inst, &created); + if (ret < 0) { + return ret; + } + + ret = lwm2m_engine_validate_write_access(msg, obj_inst, &obj_field); + if (ret < 0) { + return ret; + } + + ret = lwm2m_engine_get_create_res_inst(&msg->path, &res, &res_inst); + if (ret < 0) { + return -ENOENT; + } + + return lwm2m_write_handler(obj_inst, res, res_inst, obj_field, msg); +} + +const struct lwm2m_writer senml_cbor_writer = { + .put_end = put_end, + .put_begin_oi = put_begin_oi, + .put_begin_r = put_begin_r, + .put_begin_ri = put_begin_ri, + .put_s8 = put_s8, + .put_s16 = put_s16, + .put_s32 = put_s32, + .put_s64 = put_s64, + .put_time = put_time, + .put_string = put_string, + .put_float = put_float, + .put_bool = put_bool, + .put_opaque = put_opaque, + .put_objlnk = put_objlnk, +}; + +const struct lwm2m_reader senml_cbor_reader = { + .get_s32 = get_s32, + .get_s64 = get_s64, + .get_time = get_s64, + .get_string = get_string, + .get_float = get_float, + .get_bool = get_bool, + .get_opaque = get_opaque, + .get_objlnk = get_objlnk, +}; + +int do_read_op_senml_cbor(struct lwm2m_message *msg) +{ + int ret; + struct cbor_out_fmt_data *fd = setup_out_fmt_data(msg); + + if (!fd) { + return -ENOMEM; + } + + ret = lwm2m_perform_read_op(msg, LWM2M_FORMAT_APP_SENML_CBOR); + + clear_out_fmt_data(msg, fd); + + return ret; +} + +static uint8_t parse_composite_read_paths(struct lwm2m_message *msg, + sys_slist_t *lwm2m_path_list, + sys_slist_t *lwm2m_path_free_list) +{ + char basename[MAX_RESOURCE_LEN + 1] = {0}; /* to include terminating null */ + char name[MAX_RESOURCE_LEN + 1] = {0}; /* to include terminating null */ + char fqn[MAX_RESOURCE_LEN + 1] = {0}; + struct lwm2m_obj_path path; + struct cbor_in_fmt_data *fd; + uint8_t paths = 0; + uint32_t isize; + uint_fast8_t dret; + int len; + int ret; + + fd = setup_in_fmt_data(msg); + if (!fd) { + LOG_ERR("unable to decode composite read paths, out of memory"); + return -ENOMEM; + } + + dret = cbor_decode_lwm2m_senml(ICTX_BUF_R_REGION(&msg->in), &fd->dcd, &isize); + + if (dret != ZCBOR_SUCCESS) { + __ASSERT_NO_MSG(false); + goto out; + } + + msg->in.offset += isize; + + for (int idx = 0; idx < fd->dcd._lwm2m_senml__record_count; idx++) { + + /* Where to find the basenames and names */ + struct record *record = GET_IN_FD_REC_I(fd, idx); + + /* Set null terminated effective basename */ + if (record->_record_bn_present) { + len = MIN(sizeof(basename)-1, record->_record_bn._record_bn.len); + snprintk(basename, len + 1, "%s", record->_record_bn._record_bn.value); + basename[len] = '\0'; + } + + /* Best effort with read, skip if no proper name is available */ + if (!record->_record_n_present) { + if (strcmp(basename, "") == 0) { + continue; + } + } + + /* Set null terminated name */ + if (record->_record_n_present) { + len = MIN(sizeof(name)-1, record->_record_n._record_n.len); + snprintk(name, len + 1, "%s", record->_record_n._record_n.value); + name[len] = '\0'; + } + + /* Form fully qualified path name */ + snprintk(fqn, sizeof(fqn), "%s%s", basename, name); + + ret = lwm2m_string_to_path(fqn, &path, '/'); + + /* invalid path is forgiven with read */ + if (ret < 0) { + continue; + } + + ret = lwm2m_engine_add_path_to_list(lwm2m_path_list, lwm2m_path_free_list, &path); + + if (ret < 0) { + continue; + } + + paths++; + } + +out: + clear_in_fmt_data(msg, fd); + + return paths; +} + + +int do_composite_read_op_senml_cbor(struct lwm2m_message *msg) +{ + int ret; + struct cbor_out_fmt_data *fd; + struct lwm2m_obj_path_list lwm2m_path_list_buf[CONFIG_LWM2M_COMPOSITE_PATH_LIST_SIZE]; + sys_slist_t lwm_path_list; + sys_slist_t lwm_path_free_list; + uint8_t len; + + lwm2m_engine_path_list_init(&lwm_path_list, + &lwm_path_free_list, + lwm2m_path_list_buf, + CONFIG_LWM2M_COMPOSITE_PATH_LIST_SIZE); + + /* Parse paths */ + len = parse_composite_read_paths(msg, &lwm_path_list, &lwm_path_free_list); + if (len == 0) { + LOG_ERR("No Valid URL at msg"); + return -ESRCH; + } + + lwm2m_engine_clear_duplicate_path(&lwm_path_list, &lwm_path_free_list); + + fd = setup_out_fmt_data(msg); + if (!fd) { + LOG_ERR("unable to encode composite read msg, out of memory"); + return -ENOMEM; + } + + ret = lwm2m_perform_composite_read_op(msg, LWM2M_FORMAT_APP_SENML_CBOR, &lwm_path_list); + + clear_out_fmt_data(msg, fd); + + return ret; +} + + +int do_write_op_senml_cbor(struct lwm2m_message *msg) +{ + uint_fast8_t dret; + int ret = 0; + uint32_t decoded_sz; + struct cbor_in_fmt_data *fd; + + /* With block-wise transfer consecutive blocks will not carry the content header - + * go directly to the message processing + */ + if (msg->in.block_ctx != NULL && msg->in.block_ctx->ctx.current > 0) { + msg->path.res_id = msg->in.block_ctx->res_id; + msg->path.level = msg->in.block_ctx->level; + + if (msg->path.level == LWM2M_PATH_LEVEL_RESOURCE_INST) { + msg->path.res_inst_id = msg->in.block_ctx->res_inst_id; + } + + return do_write_op_item(msg, NULL); + } + + fd = setup_in_fmt_data(msg); + if (!fd) { + LOG_ERR("unable to decode msg, out of memory"); + return -ENOMEM; + } + + dret = cbor_decode_lwm2m_senml(ICTX_BUF_R_PTR(&msg->in), ICTX_BUF_R_LEFT_SZ(&msg->in), + &fd->dcd, &decoded_sz); + + if (dret == ZCBOR_SUCCESS) { + msg->in.offset += decoded_sz; + + for (int idx = 0; idx < fd->dcd._lwm2m_senml__record_count; idx++) { + + struct record *rec = &fd->dcd._lwm2m_senml__record[idx]; + + /* Basename applies for current and succeeding records */ + if (rec->_record_bn_present) { + int len = MIN(sizeof(fd->basename) - 1, + rec->_record_bn._record_bn.len); + + snprintk(fd->basename, len + 1, "%s", + rec->_record_bn._record_bn.value); + } + + ret = do_write_op_item(msg, rec); + + /* Write isn't supposed to fail */ + if (ret < 0) { + break; + } + } + } else { + ret = -EBADMSG; + } + + clear_in_fmt_data(msg, fd); + + return ret < 0 ? ret : decoded_sz; +} + +int do_composite_observe_parse_path_senml_cbor(struct lwm2m_message *msg, + sys_slist_t *lwm2m_path_list, + sys_slist_t *lwm2m_path_free_list) +{ + uint16_t original_offset; + uint8_t len; + + original_offset = msg->in.offset; + + /* Parse paths */ + len = parse_composite_read_paths(msg, lwm2m_path_list, lwm2m_path_free_list); + + if (len == 0) { + LOG_ERR("No Valid URL at msg"); + return -ESRCH; + } + + msg->in.offset = original_offset; + return 0; +} + +int do_send_op_senml_cbor(struct lwm2m_message *msg, sys_slist_t *lwm2m_path_list) +{ + int ret; + struct cbor_out_fmt_data *fd = setup_out_fmt_data(msg); + + if (!fd) { + LOG_ERR("Unable to complete SEND op, out of memory"); + return -ENOMEM; + } + + ret = lwm2m_perform_composite_read_op(msg, LWM2M_FORMAT_APP_SENML_CBOR, lwm2m_path_list); + + clear_out_fmt_data(msg, fd); + + return ret; +} diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.h b/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.h new file mode 100644 index 00000000000..fff42bceba5 --- /dev/null +++ b/subsys/net/lib/lwm2m/lwm2m_rw_senml_cbor.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LWM2M_RW_SENML_CBOR_H_ +#define LWM2M_RW_SENML_CBOR_H_ + +#include "lwm2m_object.h" + +extern const struct lwm2m_writer senml_cbor_writer; +extern const struct lwm2m_reader senml_cbor_reader; + +int do_read_op_senml_cbor(struct lwm2m_message *msg); +int do_composite_read_op_senml_cbor(struct lwm2m_message *msg); +int do_write_op_senml_cbor(struct lwm2m_message *msg); + +int do_composite_observe_parse_path_senml_cbor(struct lwm2m_message *msg, + sys_slist_t *lwm2m_path_list, + sys_slist_t *lwm2m_path_free_list); + +int do_send_op_senml_cbor(struct lwm2m_message *msg, sys_slist_t *lwm2m_path_list); + +#endif /* LWM2M_RW_SENML_CBOR_H_ */ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c new file mode 100644 index 00000000000..5eed8a473d0 --- /dev/null +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c @@ -0,0 +1,207 @@ +/* + * Generated using zcbor version 0.3.99 + * https://github.com/zephyrproject-rtos/zcbor + * Generated with a --default-max-qty of 99 + */ + +#include +#include +#include +#include +#include "zcbor_decode.h" +#include "lwm2m_senml_cbor_decode.h" + +#if DEFAULT_MAX_QTY != 99 +#error "The type file was generated with a different default_max_qty than this file" +#endif + +static bool decode_repeated_record_bn(zcbor_state_t *state, struct record_bn *result) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = ((((zcbor_int32_expect(state, (-2)))) && + (zcbor_tstr_decode(state, (&(*result)._record_bn))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool decode_repeated_record_n(zcbor_state_t *state, struct record_n *result) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = ((((zcbor_uint32_expect(state, (0)))) && + (zcbor_tstr_decode(state, (&(*result)._record_n))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool decode_numeric(zcbor_state_t *state, struct numeric_ *result) +{ + zcbor_print("%s\r\n", __func__); + bool int_res; + + bool tmp_result = + (((zcbor_union_start_code(state) && + (int_res = ((((zcbor_int64_decode(state, (&(*result)._numeric_int))) && + ((((*result)._numeric_int >= -9223372036854775807LL) && + ((*result)._numeric_int <= 9223372036854775807LL)) || + (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))) && + (((*result)._numeric_choice = _numeric_int) || 1)) || + (((zcbor_float_decode(state, (&(*result)._numeric_float)))) && + (((*result)._numeric_choice = _numeric_float) || 1))), + zcbor_union_end_code(state), int_res)))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool decode_repeated_record_union(zcbor_state_t *state, struct record_union_ *result) +{ + zcbor_print("%s\r\n", __func__); + bool int_res; + + bool tmp_result = (((zcbor_union_start_code(state) && + (int_res = (((((zcbor_uint32_expect_union(state, (2)))) && + (decode_numeric(state, (&(*result)._union_v)))) && + (((*result)._record_union_choice = _union_v) || 1)) || + ((((zcbor_uint32_expect_union(state, (3)))) && + (zcbor_tstr_decode(state, (&(*result)._union_vs)))) && + (((*result)._record_union_choice = _union_vs) || 1)) || + ((((zcbor_uint32_expect_union(state, (4)))) && + (zcbor_bool_decode(state, (&(*result)._union_vb)))) && + (((*result)._record_union_choice = _union_vb) || 1)) || + ((((zcbor_uint32_expect_union(state, (8)))) && + (zcbor_bstr_decode(state, (&(*result)._union_vd)))) && + (((*result)._record_union_choice = _union_vd) || 1))), + zcbor_union_end_code(state), int_res)))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool decode_value(zcbor_state_t *state, struct value_ *result) +{ + zcbor_print("%s\r\n", __func__); + bool int_res; + + bool tmp_result = + (((zcbor_union_start_code(state) && + (int_res = ((((zcbor_tstr_decode(state, (&(*result)._value_tstr)))) && + (((*result)._value_choice = _value_tstr) || 1)) || + (((zcbor_bstr_decode(state, (&(*result)._value_bstr)))) && + (((*result)._value_choice = _value_bstr) || 1)) || + (zcbor_union_elem_code(state) && + (((decode_numeric(state, (&(*result)._value__numeric)))) && + (((*result)._value_choice = _value__numeric) || 1))) || + (zcbor_union_elem_code(state) && + (((zcbor_bool_decode(state, (&(*result)._value_bool)))) && + (((*result)._value_choice = _value_bool) || 1)))), + zcbor_union_end_code(state), int_res)))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool decode_key_value_pair(zcbor_state_t *state, struct key_value_pair *result) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = ((((zcbor_int32_decode(state, (&(*result)._key_value_pair_key)))) && + (decode_value(state, (&(*result)._key_value_pair))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool decode_repeated_record__key_value_pair(zcbor_state_t *state, + struct record__key_value_pair *result) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = (((decode_key_value_pair(state, (&(*result)._record__key_value_pair))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool decode_record(zcbor_state_t *state, struct record *result) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = + (((zcbor_map_start_decode(state) && + ((zcbor_present_decode(&((*result)._record_bn_present), + (zcbor_decoder_t *)decode_repeated_record_bn, state, + (&(*result)._record_bn)) && + zcbor_present_decode(&((*result)._record_n_present), + (zcbor_decoder_t *)decode_repeated_record_n, state, + (&(*result)._record_n)) && + zcbor_present_decode(&((*result)._record_union_present), + (zcbor_decoder_t *)decode_repeated_record_union, state, + (&(*result)._record_union)) && + zcbor_multi_decode(0, 3, &(*result)._record__key_value_pair_count, + (zcbor_decoder_t *)decode_repeated_record__key_value_pair, + state, (&(*result)._record__key_value_pair), + sizeof(struct record__key_value_pair))) || + (zcbor_list_map_end_force_decode(state), false)) && + zcbor_map_end_decode(state)))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool decode_lwm2m_senml(zcbor_state_t *state, struct lwm2m_senml *result) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = (( + (zcbor_list_start_decode(state) && + ((zcbor_multi_decode(1, 99, &(*result)._lwm2m_senml__record_count, + (zcbor_decoder_t *)decode_record, state, + (&(*result)._lwm2m_senml__record), sizeof(struct record))) || + (zcbor_list_map_end_force_decode(state), false)) && + zcbor_list_end_decode(state)))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +uint_fast8_t cbor_decode_lwm2m_senml(const uint8_t *payload, size_t payload_len, + struct lwm2m_senml *result, size_t *payload_len_out) +{ + zcbor_state_t states[6]; + + zcbor_new_state(states, sizeof(states) / sizeof(zcbor_state_t), payload, payload_len, 1); + + bool ret = decode_lwm2m_senml(states, result); + + if (ret && (payload_len_out != NULL)) { + *payload_len_out = MIN(payload_len, (size_t)states[0].payload - (size_t)payload); + } + + if (!ret) { + uint_fast8_t ret = zcbor_pop_error(states); + return (ret == ZCBOR_SUCCESS) ? ZCBOR_ERR_UNKNOWN : ret; + } + return ZCBOR_SUCCESS; +} diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h new file mode 100644 index 00000000000..b4d575b728c --- /dev/null +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h @@ -0,0 +1,24 @@ +/* + * Generated using zcbor version 0.3.99 + * https://github.com/zephyrproject-rtos/zcbor + * Generated with a --default-max-qty of 99 + */ + +#ifndef LWM2M_SENML_CBOR_DECODE_H__ +#define LWM2M_SENML_CBOR_DECODE_H__ + +#include +#include +#include +#include +#include "zcbor_decode.h" +#include "lwm2m_senml_cbor_decode_types.h" + +#if DEFAULT_MAX_QTY != 99 +#error "The type file was generated with a different default_max_qty than this file" +#endif + +uint_fast8_t cbor_decode_lwm2m_senml(const uint8_t *payload, size_t payload_len, + struct lwm2m_senml *result, size_t *payload_len_out); + +#endif /* LWM2M_SENML_CBOR_DECODE_H__ */ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c new file mode 100644 index 00000000000..974715ed1eb --- /dev/null +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c @@ -0,0 +1,203 @@ +/* + * Generated using zcbor version 0.3.99 + * https://github.com/zephyrproject-rtos/zcbor + * Generated with a --default-max-qty of 99 + */ + +#include +#include +#include +#include +#include "zcbor_encode.h" +#include "lwm2m_senml_cbor_encode.h" + +#if DEFAULT_MAX_QTY != 99 +#error "The type file was generated with a different default_max_qty than this file" +#endif + +static bool encode_repeated_record_bn(zcbor_state_t *state, const struct record_bn *input) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = ((((zcbor_int32_put(state, (-2)))) && + (zcbor_tstr_encode(state, (&(*input)._record_bn))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool encode_repeated_record_n(zcbor_state_t *state, const struct record_n *input) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = ((((zcbor_uint32_put(state, (0)))) && + (zcbor_tstr_encode(state, (&(*input)._record_n))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool encode_numeric(zcbor_state_t *state, const struct numeric_ *input) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = + (((((*input)._numeric_choice == _numeric_int) ? + (((((*input)._numeric_int >= -9223372036854775807LL) && + ((*input)._numeric_int <= 9223372036854775807LL)) || + (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false)) && + (zcbor_int64_encode(state, (&(*input)._numeric_int)))) : + (((*input)._numeric_choice == _numeric_float) ? + ((zcbor_float64_encode(state, (&(*input)._numeric_float)))) : + false)))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool encode_repeated_record_union(zcbor_state_t *state, const struct record_union_ *input) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = + (((((*input)._record_union_choice == _union_v) ? + (((zcbor_uint32_put(state, (2)))) && + (encode_numeric(state, (&(*input)._union_v)))) : + (((*input)._record_union_choice == _union_vs) ? + (((zcbor_uint32_put(state, (3)))) && + (zcbor_tstr_encode(state, (&(*input)._union_vs)))) : + (((*input)._record_union_choice == _union_vb) ? + (((zcbor_uint32_put(state, (4)))) && + (zcbor_bool_encode(state, (&(*input)._union_vb)))) : + (((*input)._record_union_choice == _union_vd) ? + (((zcbor_uint32_put(state, (8)))) && + (zcbor_bstr_encode(state, + (&(*input)._union_vd)))) : + false)))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool encode_value(zcbor_state_t *state, const struct value_ *input) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = (( + (((*input)._value_choice == _value_tstr) ? + ((zcbor_tstr_encode(state, (&(*input)._value_tstr)))) : + (((*input)._value_choice == _value_bstr) ? + ((zcbor_bstr_encode(state, (&(*input)._value_bstr)))) : + (((*input)._value_choice == _value__numeric) ? + ((encode_numeric(state, (&(*input)._value__numeric)))) : + (((*input)._value_choice == _value_bool) ? + ((zcbor_bool_encode(state, + (&(*input)._value_bool)))) : + false)))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool encode_key_value_pair(zcbor_state_t *state, const struct key_value_pair *input) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = ((((zcbor_int32_encode(state, (&(*input)._key_value_pair_key)))) && + (encode_value(state, (&(*input)._key_value_pair))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool encode_repeated_record__key_value_pair(zcbor_state_t *state, + const struct record__key_value_pair *input) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = (((encode_key_value_pair(state, (&(*input)._record__key_value_pair))))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool encode_record(zcbor_state_t *state, const struct record *input) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = (((zcbor_map_start_encode(state, 6) && + ((zcbor_present_encode(&((*input)._record_bn_present), + (zcbor_encoder_t *)encode_repeated_record_bn, + state, (&(*input)._record_bn)) && + zcbor_present_encode(&((*input)._record_n_present), + (zcbor_encoder_t *)encode_repeated_record_n, + state, (&(*input)._record_n)) && + zcbor_present_encode(&((*input)._record_union_present), + (zcbor_encoder_t *)encode_repeated_record_union, + state, (&(*input)._record_union)) && + zcbor_multi_encode_minmax( + 0, 3, &(*input)._record__key_value_pair_count, + (zcbor_encoder_t *)encode_repeated_record__key_value_pair, + state, (&(*input)._record__key_value_pair), + sizeof(struct record__key_value_pair))) || + (zcbor_list_map_end_force_encode(state), false)) && + zcbor_map_end_encode(state, 6)))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +static bool encode_lwm2m_senml(zcbor_state_t *state, const struct lwm2m_senml *input) +{ + zcbor_print("%s\r\n", __func__); + + bool tmp_result = + (((zcbor_list_start_encode(state, 99) && + ((zcbor_multi_encode_minmax(1, 99, &(*input)._lwm2m_senml__record_count, + (zcbor_encoder_t *)encode_record, state, + (&(*input)._lwm2m_senml__record), + sizeof(struct record))) || + (zcbor_list_map_end_force_encode(state), false)) && + zcbor_list_end_encode(state, 99)))); + + if (!tmp_result) + zcbor_trace(); + + return tmp_result; +} + +uint_fast8_t cbor_encode_lwm2m_senml(uint8_t *payload, size_t payload_len, + const struct lwm2m_senml *input, size_t *payload_len_out) +{ + zcbor_state_t states[6]; + + zcbor_new_state(states, sizeof(states) / sizeof(zcbor_state_t), payload, payload_len, 1); + + bool ret = encode_lwm2m_senml(states, input); + + if (ret && (payload_len_out != NULL)) { + *payload_len_out = MIN(payload_len, (size_t)states[0].payload - (size_t)payload); + } + + if (!ret) { + uint_fast8_t ret = zcbor_pop_error(states); + return (ret == ZCBOR_SUCCESS) ? ZCBOR_ERR_UNKNOWN : ret; + } + return ZCBOR_SUCCESS; +} diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h new file mode 100644 index 00000000000..485180f95f2 --- /dev/null +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h @@ -0,0 +1,24 @@ +/* + * Generated using zcbor version 0.3.99 + * https://github.com/zephyrproject-rtos/zcbor + * Generated with a --default-max-qty of 99 + */ + +#ifndef LWM2M_SENML_CBOR_ENCODE_H__ +#define LWM2M_SENML_CBOR_ENCODE_H__ + +#include +#include +#include +#include +#include "zcbor_encode.h" +#include "lwm2m_senml_cbor_encode_types.h" + +#if DEFAULT_MAX_QTY != 99 +#error "The type file was generated with a different default_max_qty than this file" +#endif + +uint_fast8_t cbor_encode_lwm2m_senml(uint8_t *payload, size_t payload_len, + const struct lwm2m_senml *input, size_t *payload_len_out); + +#endif /* LWM2M_SENML_CBOR_ENCODE_H__ */ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h new file mode 100644 index 00000000000..c3cb70356d8 --- /dev/null +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h @@ -0,0 +1,104 @@ +/* + * Generated using zcbor version 0.3.99 + * https://github.com/zephyrproject-rtos/zcbor + * Generated with a --default-max-qty of 99 + */ + +#ifndef LWM2M_SENML_CBOR_DECODE_TYPES_H__ +#define LWM2M_SENML_CBOR_DECODE_TYPES_H__ + +#include +#include +#include +#include +#include "zcbor_decode.h" + +/** Which value for --default-max-qty this file was created with. + * + * The define is used in the other generated file to do a build-time + * compatibility check. + * + * See `zcbor --help` for more information about --default-max-qty + */ +#define DEFAULT_MAX_QTY 99 + +struct record_bn { + struct zcbor_string _record_bn; +}; + +struct record_n { + struct zcbor_string _record_n; +}; + +struct numeric_ { + union { + int64_t _numeric_int; + double _numeric_float; + }; + enum { _numeric_int, + _numeric_float, + } _numeric_choice; +}; + +struct record_union_ { + union { + struct { + struct numeric_ _union_v; + }; + struct { + struct zcbor_string _union_vs; + }; + struct { + bool _union_vb; + }; + struct { + struct zcbor_string _union_vd; + }; + }; + enum { _union_v, + _union_vs, + _union_vb, + _union_vd, + } _record_union_choice; +}; + +struct value_ { + union { + struct zcbor_string _value_tstr; + struct zcbor_string _value_bstr; + struct numeric_ _value__numeric; + bool _value_bool; + }; + enum { _value_tstr, + _value_bstr, + _value__numeric, + _value_bool, + } _value_choice; +}; + +struct key_value_pair { + int32_t _key_value_pair_key; + struct value_ _key_value_pair; +}; + +struct record__key_value_pair { + struct key_value_pair _record__key_value_pair; +}; + +struct record { + struct record_bn _record_bn; + uint_fast32_t _record_bn_present; + struct record_n _record_n; + uint_fast32_t _record_n_present; + struct record_union_ _record_union; + uint_fast32_t _record_union_present; + struct record__key_value_pair _record__key_value_pair[3]; + uint_fast32_t _record__key_value_pair_count; +}; + +struct lwm2m_senml { + struct record _lwm2m_senml__record[99]; + uint_fast32_t _lwm2m_senml__record_count; +}; + +#endif /* LWM2M_SENML_CBOR_DECODE_TYPES_H__ */