diff --git a/doc/reference/networking/lwm2m.rst b/doc/reference/networking/lwm2m.rst index 5b94c4e8713..e76c7930d5c 100644 --- a/doc/reference/networking/lwm2m.rst +++ b/doc/reference/networking/lwm2m.rst @@ -216,7 +216,7 @@ Example LwM2M object and resources: Device - R - Multiple - Optional - - ObjLink + - ObjLnk The server could query the ``Manufacturer`` resource for ``Device`` object instance 0 (the default and only instance) by sending a ``READ 3/0/0`` diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index b9f8a80fd57..d4846439115 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -341,6 +341,19 @@ typedef struct float64_value { int64_t val2; } float64_value_t; +/** + * @brief Maximum value for ObjLnk resource fields + */ +#define LWM2M_OBJLNK_MAX_ID USHRT_MAX + +/** + * @brief LWM2M ObjLnk resource type structure + */ +struct lwm2m_objlnk { + uint16_t obj_id; + uint16_t obj_inst; +}; + /** * @brief Create an LwM2M object instance. * @@ -485,6 +498,16 @@ int lwm2m_engine_set_float32(char *pathstr, float32_value_t *value); */ int lwm2m_engine_set_float64(char *pathstr, float64_value_t *value); +/** + * @brief Set resource (instance) value (ObjLnk) + * + * @param[in] pathstr LwM2M path string "obj/obj-inst/res(/res-inst)" + * @param[in] value pointer to the lwm2m_objlnk structure + * + * @return 0 for success or negative in case of error. + */ +int lwm2m_engine_set_objlnk(char *pathstr, struct lwm2m_objlnk *value); + /** * @brief Get resource (instance) value (opaque buffer) * @@ -617,6 +640,17 @@ int lwm2m_engine_get_float32(char *pathstr, float32_value_t *buf); */ int lwm2m_engine_get_float64(char *pathstr, float64_value_t *buf); +/** + * @brief Get resource (instance) value (ObjLnk) + * + * @param[in] pathstr LwM2M path string "obj/obj-inst/res(/res-inst)" + * @param[out] buf lwm2m_objlnk buffer to copy data into + * + * @return 0 for success or negative in case of error. + */ +int lwm2m_engine_get_objlnk(char *pathstr, struct lwm2m_objlnk *buf); + + /** * @brief Set resource (instance) read callback * diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 181606f5999..db5ac1af381 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -12,11 +12,6 @@ * Joel Hoglund */ -/* - * TODO: - * - Handle Resource ObjLink type - */ - #define LOG_MODULE_NAME net_lwm2m_engine #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL @@ -1501,6 +1496,11 @@ static int lwm2m_engine_set(char *pathstr, void *value, uint16_t len) ((float64_value_t *)value)->val2; break; + case LWM2M_RES_TYPE_OBJLNK: + *((struct lwm2m_objlnk *)data_ptr) = + *(struct lwm2m_objlnk *)value; + break; + default: LOG_ERR("unknown obj data_type %d", obj_field->data_type); return -EINVAL; @@ -1587,6 +1587,11 @@ int lwm2m_engine_set_float64(char *pathstr, float64_value_t *value) return lwm2m_engine_set(pathstr, value, sizeof(float64_value_t)); } +int lwm2m_engine_set_objlnk(char *pathstr, struct lwm2m_objlnk *value) +{ + return lwm2m_engine_set(pathstr, value, sizeof(struct lwm2m_objlnk)); +} + /* user data getter functions */ int lwm2m_engine_get_res_data(char *pathstr, void **data_ptr, uint16_t *data_len, @@ -1739,6 +1744,11 @@ static int lwm2m_engine_get(char *pathstr, void *buf, uint16_t buflen) ((float64_value_t *)data_ptr)->val2; break; + case LWM2M_RES_TYPE_OBJLNK: + *(struct lwm2m_objlnk *)buf = + *(struct lwm2m_objlnk *)data_ptr; + break; + default: LOG_ERR("unknown obj data_type %d", obj_field->data_type); @@ -1823,6 +1833,11 @@ int lwm2m_engine_get_float64(char *pathstr, float64_value_t *buf) return lwm2m_engine_get(pathstr, buf, sizeof(float64_value_t)); } +int lwm2m_engine_get_objlnk(char *pathstr, struct lwm2m_objlnk *buf) +{ + return lwm2m_engine_get(pathstr, buf, sizeof(struct lwm2m_objlnk)); +} + int lwm2m_engine_get_resource(char *pathstr, struct lwm2m_engine_res **res) { int ret; @@ -2159,6 +2174,11 @@ static int lwm2m_read_handler(struct lwm2m_engine_obj_inst *obj_inst, (float64_value_t *)data_ptr); break; + case LWM2M_RES_TYPE_OBJLNK: + engine_put_objlnk(&msg->out, &msg->path, + (struct lwm2m_objlnk *)data_ptr); + break; + default: LOG_ERR("unknown obj data_type %d", obj_field->data_type); @@ -2386,6 +2406,12 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, len = sizeof(float64_value_t); break; + case LWM2M_RES_TYPE_OBJLNK: + engine_get_objlnk(&msg->in, + (struct lwm2m_objlnk *)data_ptr); + len = sizeof(struct lwm2m_objlnk); + break; + default: LOG_ERR("unknown obj data_type %d", obj_field->data_type); diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index 9156ed2ff18..723f64ca0ab 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -124,6 +124,7 @@ #define LWM2M_RES_TYPE_TIME 12 #define LWM2M_RES_TYPE_FLOAT32 13 #define LWM2M_RES_TYPE_FLOAT64 14 +#define LWM2M_RES_TYPE_OBJLNK 15 /* remember that we have already output a value - can be between two block's */ #define WRITER_OUTPUT_VALUE 1 @@ -470,6 +471,9 @@ struct lwm2m_writer { size_t (*put_opaque)(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, char *buf, size_t buflen); + size_t (*put_objlnk)(struct lwm2m_output_context *out, + struct lwm2m_obj_path *path, + struct lwm2m_objlnk *value); }; struct lwm2m_reader { @@ -487,6 +491,8 @@ struct lwm2m_reader { bool *value); size_t (*get_opaque)(struct lwm2m_input_context *in, uint8_t *buf, size_t buflen, bool *last_block); + size_t (*get_objlnk)(struct lwm2m_input_context *in, + struct lwm2m_objlnk *value); }; /* output user_data management functions */ @@ -674,6 +680,13 @@ static inline size_t engine_put_opaque(struct lwm2m_output_context *out, return 0; } +static inline size_t engine_put_objlnk(struct lwm2m_output_context *out, + struct lwm2m_obj_path *path, + struct lwm2m_objlnk *value) +{ + return out->writer->put_objlnk(out, path, value); +} + static inline size_t engine_get_s32(struct lwm2m_input_context *in, int32_t *value) { @@ -721,4 +734,10 @@ static inline size_t engine_get_opaque(struct lwm2m_input_context *in, return 0; } +static inline size_t engine_get_objlnk(struct lwm2m_input_context *in, + struct lwm2m_objlnk *value) +{ + return in->reader->get_objlnk(in, value); +} + #endif /* LWM2M_OBJECT_H_ */ diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_json.c b/subsys/net/lib/lwm2m/lwm2m_rw_json.c index baaa1b8741e..5f788ec0698 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_json.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_json.c @@ -526,6 +526,20 @@ static size_t put_bool(struct lwm2m_output_context *out, return (size_t)len; } +static size_t put_objlnk(struct lwm2m_output_context *out, + struct lwm2m_obj_path *path, + struct lwm2m_objlnk *value) +{ + size_t len; + + len = put_json_prefix(out, path, "\"ov\""); + len += plain_text_put_format(out, "\"%u:%u\"", value->obj_id, + value->obj_inst); + len += put_json_postfix(out); + + return len; +} + static size_t read_number(struct lwm2m_input_context *in, int64_t *value1, int64_t *value2, bool accept_sign, bool accept_dot) @@ -676,6 +690,37 @@ static size_t get_opaque(struct lwm2m_input_context *in, return 0; } +static size_t get_objlnk(struct lwm2m_input_context *in, + struct lwm2m_objlnk *value) +{ + int64_t tmp; + size_t len; + uint16_t value_offset; + struct json_in_formatter_data *fd; + + fd = engine_get_in_user_data(in); + if (!fd) { + return 0; + } + + /* Store the original value offset. */ + value_offset = fd->value_offset; + + len = read_number(in, &tmp, NULL, false, false); + value->obj_id = (uint16_t)tmp; + + len++; /* +1 for ':' delimeter. */ + fd->value_offset += len; + + len += read_number(in, &tmp, NULL, false, false); + value->obj_inst = (uint16_t)tmp; + + /* Restore the original value offset. */ + fd->value_offset = value_offset; + + return len; +} + const struct lwm2m_writer json_writer = { .put_begin = put_begin, .put_end = put_end, @@ -689,6 +734,7 @@ const struct lwm2m_writer json_writer = { .put_float32fix = put_float32fix, .put_float64fix = put_float64fix, .put_bool = put_bool, + .put_objlnk = put_objlnk, }; const struct lwm2m_reader json_reader = { @@ -699,6 +745,7 @@ const struct lwm2m_reader json_reader = { .get_float64fix = get_float64fix, .get_bool = get_bool, .get_opaque = get_opaque, + .get_objlnk = get_objlnk, }; int do_read_op_json(struct lwm2m_message *msg, int content_format) diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c index a250d6d33a7..8525217bb71 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c @@ -566,6 +566,15 @@ static size_t put_opaque(struct lwm2m_output_context *out, return put_string(out, path, buf, buflen); } +static size_t 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 size_t get_number(struct lwm2m_input_context *in, int64_t *value, uint8_t max_len) { @@ -758,6 +767,20 @@ static size_t get_opaque(struct lwm2m_input_context *in, return lwm2m_engine_get_opaque_more(in, value, buflen, last_block); } +static size_t get_objlnk(struct lwm2m_input_context *in, + struct lwm2m_objlnk *value) +{ + int32_t value_s32; + size_t size; + + size = get_s32(in, &value_s32); + + value->obj_id = (value_s32 >> 16) & 0xFFFF; + value->obj_inst = value_s32 && 0xFFFF; + + return size; +} + const struct lwm2m_writer oma_tlv_writer = { .put_begin_oi = put_begin_oi, .put_end_oi = put_end_oi, @@ -772,6 +795,7 @@ const struct lwm2m_writer oma_tlv_writer = { .put_float64fix = put_float64fix, .put_bool = put_bool, .put_opaque = put_opaque, + .put_objlnk = put_objlnk, }; const struct lwm2m_reader oma_tlv_reader = { @@ -782,6 +806,7 @@ const struct lwm2m_reader oma_tlv_reader = { .get_float64fix = get_float64fix, .get_bool = get_bool, .get_opaque = get_opaque, + .get_objlnk = get_objlnk, }; int do_read_op_tlv(struct lwm2m_message *msg, int content_format) diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_plain_text.c b/subsys/net/lib/lwm2m/lwm2m_rw_plain_text.c index 0613ce3240a..d1c54461e01 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_plain_text.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_plain_text.c @@ -194,6 +194,14 @@ static size_t put_bool(struct lwm2m_output_context *out, } } +static size_t put_objlnk(struct lwm2m_output_context *out, + struct lwm2m_obj_path *path, + struct lwm2m_objlnk *value) +{ + return plain_text_put_format(out, "%u:%u", value->obj_id, + value->obj_inst); +} + static int get_length_left(struct lwm2m_input_context *in) { return in->in_cpkt->offset - in->offset; @@ -330,6 +338,26 @@ static size_t get_opaque(struct lwm2m_input_context *in, return lwm2m_engine_get_opaque_more(in, value, buflen, last_block); } + +static size_t get_objlnk(struct lwm2m_input_context *in, + struct lwm2m_objlnk *value) +{ + int64_t tmp; + size_t len; + + len = plain_text_read_number(in, &tmp, NULL, false, false); + value->obj_id = (uint16_t)tmp; + + /* Skip ':' delimeter. */ + in->offset++; + len++; + + len += plain_text_read_number(in, &tmp, NULL, false, false); + value->obj_inst = (uint16_t)tmp; + + return len; +} + const struct lwm2m_writer plain_text_writer = { .put_s8 = put_s8, .put_s16 = put_s16, @@ -339,6 +367,7 @@ const struct lwm2m_writer plain_text_writer = { .put_float32fix = plain_text_put_float32fix, .put_float64fix = plain_text_put_float64fix, .put_bool = put_bool, + .put_objlnk = put_objlnk, }; const struct lwm2m_reader plain_text_reader = { @@ -349,6 +378,7 @@ const struct lwm2m_reader plain_text_reader = { .get_float64fix = get_float64fix, .get_bool = get_bool, .get_opaque = get_opaque, + .get_objlnk = get_objlnk, }; int do_read_op_plain_text(struct lwm2m_message *msg, int content_format)