From 8b0a86fda3418b1c9acc4d833326877e6c854840 Mon Sep 17 00:00:00 2001 From: Leandro Lanzieri Date: Wed, 25 Dec 2024 11:18:19 +0100 Subject: [PATCH 1/7] pkg/wakaama/objects: add IPSO on/off switch --- pkg/wakaama/contrib/objects/on_off_switch.c | 492 ++++++++++++++++++++ pkg/wakaama/include/objects/on_off_switch.h | 203 ++++++++ 2 files changed, 695 insertions(+) create mode 100644 pkg/wakaama/contrib/objects/on_off_switch.c create mode 100644 pkg/wakaama/include/objects/on_off_switch.h diff --git a/pkg/wakaama/contrib/objects/on_off_switch.c b/pkg/wakaama/contrib/objects/on_off_switch.c new file mode 100644 index 000000000000..c76b6fdc52bb --- /dev/null +++ b/pkg/wakaama/contrib/objects/on_off_switch.c @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2024 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @{ + * @ingroup lwm2m_objects_on_off_switch + * + * @file + * @brief On/off switch object implementation for LwM2M client using Wakaama + * + * @author Leandro Lanzieri + * @} + */ + +#include "mutex.h" +#include "inttypes.h" +#include "liblwm2m.h" +#include "lwm2m_client.h" +#include "objects/on_off_switch.h" +#include "ztimer.h" +#include "ztimer/stopwatch.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#define _USED_INSTANCES(_obj) (_obj.wakaama_object.instanceList) +#define _FREE_INSTANCES(_obj) (_obj.free_instances) + +/** + * @brief LwM2M On/off switch object instance + */ +typedef struct lwm2m_obj_on_off_switch_inst { + lwm2m_list_t list; /**< list handle */ + bool status; /**< digital input status */ + uint32_t counter; /**< counter for the digital input */ + ztimer_stopwatch_t stopwatch; /**< stopwatch for time periods */ + char app_type[CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE]; /**< application type */ +} lwm2m_obj_on_off_switch_inst_t; + +/** + * @brief 'Read' callback for the LwM2M On/off switch object implementation. + * + * @param[in] context LWM2M Context + * @param[in] instance_id ID of the instance to read resource from. + * @param[in] num_data Number of elements in @p data_array. + * @param[in, out] data_array IDs of resources to read. Array of data structures to place values. + * @param[in] object On/off switch object handle + * + * @return COAP_205_CONTENT on success + * @return COAP_404_NOT_FOUND if the instance was not found + * @return COAP_500_INTERNAL_SERVER_ERROR otherwise + */ +static uint8_t _read_cb(lwm2m_context_t * context, uint16_t instance_id, int * num_data, + lwm2m_data_t ** data_array, lwm2m_object_t * object); + +/** + * @brief 'Write' callback for the LwM2M On/off switch object implementation. + * + * @param[in] context LWM2M Context + * @param[in] instance_id ID of the instance to write resource to. + * @param[in] num_data Number of elements in @p data_array. + * @param[in] data_array IDs of resources to write and values. + * @param[in] object On/off switch object handle + * + * @return COAP_204_CHANGED on success + * @return COAP_404_NOT_FOUND if the instance was not found + * @return COAP_400_BAD_REQUEST if a value is not encoded correctly + * @return COAP_500_INTERNAL_SERVER_ERROR otherwise + */ +static uint8_t _write_cb(lwm2m_context_t * context, uint16_t instance_id, int num_data, + lwm2m_data_t * data_array, lwm2m_object_t * object, lwm2m_write_type_t write_type); + +/** + * @brief Gets the current value of a given @p instance. + * + * @param[in, out] data Initialized data structure. + * @param[in] instance Pointer to the instance to get the value from. + * + * @return COAP_205_CONTENT on success + * @return COAP_404_NOT_FOUND if the value is not found + */ +static uint8_t _get_value(lwm2m_data_t *data, lwm2m_obj_on_off_switch_inst_t *instance); + +/** + * @brief Mark a resource as changed on the LwM2M engine. + * + * @param[in] instance_id ID of the instance to mark the resource as changed. + * @param[in] resource_id ID of the resource to mark as changed. + */ +static void _mark_resource_changed(uint16_t instance_id, uint16_t resource_id); + +struct lwm2m_on_off_switch_object { + lwm2m_object_t wakaama_object; /**< Wakaama internal object */ + mutex_t lock; /**< mutex for the instances access */ + lwm2m_obj_on_off_switch_inst_t *free_instances; /**< list of free instances */ + lwm2m_obj_on_off_switch_inst_t instances[CONFIG_LWM2M_ON_OFF_SWITCH_INSTANCES_MAX]; /**< instances */ +}; + +struct lwm2m_on_off_switch_object _on_off_switch_object = { + .lock = MUTEX_INIT, + .wakaama_object = { + .objID = LWM2M_ON_OFF_SWITCH_OBJECT_ID, + .instanceList = NULL, + .readFunc = _read_cb, + .writeFunc = _write_cb, + .executeFunc = NULL, + .createFunc = NULL, + .deleteFunc = NULL, + .discoverFunc = NULL, + .userData = NULL + } +}; + +static uint8_t _get_value(lwm2m_data_t *data, lwm2m_obj_on_off_switch_inst_t *instance) +{ + assert(data); + assert(instance); + + switch (data->id) { + case LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID: + lwm2m_data_encode_bool(instance->status, data); + break; + + case LWM2M_ON_OFF_SWITCH_ON_TIME_ID: + if (instance->status) { + int64_t time = (int64_t) ztimer_stopwatch_measure(&instance->stopwatch); + lwm2m_data_encode_int(time, data); + } + else { + lwm2m_data_encode_int(0, data); + } + break; + + case LWM2M_ON_OFF_SWITCH_OFF_TIME_ID: + if (!instance->status) { + int64_t time = (int64_t) ztimer_stopwatch_measure(&instance->stopwatch); + lwm2m_data_encode_int(time, data); + } + else { + lwm2m_data_encode_int(0, data); + } + break; + + case LWM2M_ON_OFF_SWITCH_APP_TYPE_ID: + lwm2m_data_encode_string(instance->app_type, data); + break; + + default: + return COAP_404_NOT_FOUND; + } + return COAP_205_CONTENT; +} + +static uint8_t _read_cb(lwm2m_context_t * context, uint16_t instance_id, int * num_data, + lwm2m_data_t ** data_array, lwm2m_object_t * object) +{ + (void)context; + + lwm2m_obj_on_off_switch_inst_t *instance; + uint8_t result = COAP_404_NOT_FOUND; + int i = 0; + + mutex_lock(&_on_off_switch_object.lock); + + /* try to get the requested instance from the object list */ + instance = (lwm2m_obj_on_off_switch_inst_t *)lwm2m_list_find(object->instanceList, instance_id); + if (!instance) { + DEBUG("[lwm2m:on_off_switch:read]: can't find instance %" PRId16 "\n", instance_id); + result = COAP_404_NOT_FOUND; + goto free_out; + } + + /* if the number of resources is not specified, we need to read all resources */ + if (!*num_data) { + DEBUG("[lwm2m:on_off_switch:read]: reading all resources\n"); + + uint16_t res_list[] = { + LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID, + LWM2M_ON_OFF_SWITCH_ON_TIME_ID, + LWM2M_ON_OFF_SWITCH_OFF_TIME_ID, + LWM2M_ON_OFF_SWITCH_APP_TYPE_ID + }; + + /* allocate structures to return resources */ + int res_num = ARRAY_SIZE(res_list); + *data_array = lwm2m_data_new(res_num); + + if (NULL == *data_array) { + result = COAP_500_INTERNAL_SERVER_ERROR; + goto free_out; + } + + /* return the number of resources being read */ + *num_data = res_num; + + /* set the IDs of the resources in the data structures */ + for (i = 0; i < res_num; i++) { + (*data_array)[i].id = res_list[i]; + } + } + + /* now get the values */ + i = 0; + do { + DEBUG("[lwm2m:on_off_switch:read]: reading resource %" PRId16 "\n", (*data_array)[i].id); + result = _get_value(&(*data_array)[i], instance); + i++; + } while (i < *num_data && COAP_205_CONTENT == result); + +free_out: + mutex_unlock(&_on_off_switch_object.lock); + return result; +} + +static uint8_t _write_cb(lwm2m_context_t * context, uint16_t instance_id, int num_data, + lwm2m_data_t * data_array, lwm2m_object_t * object, lwm2m_write_type_t write_type) +{ + (void)context; + (void)write_type; + + lwm2m_obj_on_off_switch_inst_t *instance; + uint8_t result = COAP_204_CHANGED; + + mutex_lock(&_on_off_switch_object.lock); + + /* try to get the requested instance from the object list */ + instance = (lwm2m_obj_on_off_switch_inst_t *)lwm2m_list_find(object->instanceList, instance_id); + if (!instance) { + DEBUG("[lwm2m:on_off_switch:write]: can't find instance %" PRId16 "\n", instance_id); + result = COAP_404_NOT_FOUND; + goto free_out; + } + + for (int i = 0; i < num_data && result == COAP_204_CHANGED; i++) { + switch (data_array[i].id) { + case LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID: { + bool prev_status = instance->status; + + lwm2m_data_decode_bool(&data_array[i], &instance->status); + + /* reset timer on transitions */ + if (instance->status != prev_status) { + ztimer_stopwatch_reset(&instance->stopwatch); + + if (instance->status) { + instance->counter++; + } + } + + _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID); + break; + } + + case LWM2M_ON_OFF_SWITCH_ON_TIME_ID: + { + int64_t val; + lwm2m_data_decode_int(&data_array[i], &val); + if (val != 0) { + DEBUG("[lwm2m:on_off_switch:write]: invalid on_time value, only can write 0\n"); + result = COAP_400_BAD_REQUEST; + } else { + ztimer_stopwatch_reset(&instance->stopwatch); + _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_ON_TIME_ID); + } + break; + } + + case LWM2M_ON_OFF_SWITCH_OFF_TIME_ID: + { + int64_t val; + lwm2m_data_decode_int(&data_array[i], &val); + if (val != 0) { + DEBUG("[lwm2m:on_off_switch:write]: invalid off_time value, only can write 0\n"); + result = COAP_400_BAD_REQUEST; + } else { + ztimer_stopwatch_reset(&instance->stopwatch); + _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_OFF_TIME_ID); + } + break; + } + + case LWM2M_ON_OFF_SWITCH_APP_TYPE_ID: + if (data_array[i].type != LWM2M_TYPE_STRING && data_array[i].type != LWM2M_TYPE_OPAQUE) { + DEBUG("[lwm2m:on_off_switch:write]: invalid type for app_type" + "(%" PRId8 ")\n", (uint8_t)(data_array[i].type)); + result = COAP_400_BAD_REQUEST; + break; + } + + if (data_array[i].value.asBuffer.length > + CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE - 1) { + DEBUG("[lwm2m:on_off_switch:write]: value too big for app_type\n"); + result = COAP_500_INTERNAL_SERVER_ERROR; + break; + } + + memcpy(instance->app_type, data_array[i].value.asBuffer.buffer, + data_array[i].value.asBuffer.length); + instance->app_type[data_array[i].value.asBuffer.length] = '\0'; + _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_APP_TYPE_ID); + break; + } + } + +free_out: + mutex_unlock(&_on_off_switch_object.lock); + return result; +} + +static void _mark_resource_changed(uint16_t instance_id, uint16_t resource_id) +{ + lwm2m_uri_t uri; + LWM2M_URI_RESET(&uri); + uri.objectId = LWM2M_ON_OFF_SWITCH_OBJECT_ID; + uri.instanceId = instance_id; + uri.resourceId = resource_id; + + lwm2m_client_data_t *client_data; + client_data = (lwm2m_client_data_t *)_on_off_switch_object.wakaama_object.userData; + lwm2m_resource_value_changed(client_data->lwm2m_ctx, &uri); +} + + +lwm2m_object_t *lwm2m_object_on_off_switch_init(lwm2m_client_data_t *client_data) +{ + /* initialize the instances */ + for (unsigned i = 0; i < CONFIG_LWM2M_ON_OFF_SWITCH_INSTANCES_MAX; i++) { + _on_off_switch_object.instances[i].list.next = NULL; + _on_off_switch_object.instances[i].list.id = UINT16_MAX; + + _FREE_INSTANCES(_on_off_switch_object) = (lwm2m_obj_on_off_switch_inst_t *) LWM2M_LIST_ADD( + _FREE_INSTANCES(_on_off_switch_object), + &(_on_off_switch_object.instances[i]) + ); + } + + _on_off_switch_object.wakaama_object.userData = client_data; + + return &(_on_off_switch_object.wakaama_object); +} + +int lwm2m_object_on_off_switch_instance_create(const lwm2m_obj_on_off_switch_args_t *args, + int32_t instance_id) +{ + assert(args); + int result = -ENOMEM; + lwm2m_obj_on_off_switch_inst_t *instance = NULL; + uint16_t _instance_id; + + /* lock object */ + mutex_lock(&_on_off_switch_object.lock); + + /* determine ID for new instance */ + if (instance_id < 0) { + _instance_id = lwm2m_list_newId((lwm2m_list_t *) _USED_INSTANCES(_on_off_switch_object)); + } + else { + /* sanity check */ + if (instance_id >= (UINT16_MAX - 1)) { + DEBUG("[lwm2m:on_off_switch]: instance ID %" PRIi32 " is too big\n", instance_id); + result = -EINVAL; + goto free_out; + } + + _instance_id = (uint16_t)instance_id; + + /* check that the ID is free to use */ + if (LWM2M_LIST_FIND(_USED_INSTANCES(_on_off_switch_object), _instance_id ) != NULL) + { + DEBUG("[lwm2m:on_off_switch]: instance ID %" PRIi32 " already in use\n", instance_id); + goto free_out; + } + } + + /* try to allocate an instance, by popping a free node from the list */ + _FREE_INSTANCES(_on_off_switch_object) = (lwm2m_obj_on_off_switch_inst_t *) lwm2m_list_remove( + (lwm2m_list_t *) _FREE_INSTANCES(_on_off_switch_object), + UINT16_MAX, + (lwm2m_list_t **) &instance + ); + + if (!instance) { + DEBUG("[lwm2m:on_off_switch]: can't allocate new instance\n"); + goto free_out; + } + + memset(instance, 0, sizeof(lwm2m_obj_on_off_switch_inst_t)); + + instance->list.id = _instance_id; + instance->status = false; + + ztimer_stopwatch_init(ZTIMER_SEC, &instance->stopwatch); + ztimer_stopwatch_start(&instance->stopwatch); + + /* if app is specified, copy locally */ + if (args->app_type) { + if (args->app_type_len > CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE) { + DEBUG("[lwm2m:on_off_switch]: not enough space for app_type string\n"); + goto free_out; + } + memcpy(instance->app_type, args->app_type, args->app_type_len); + } + + DEBUG("[lwm2m:on_off_switch]: new instance with ID %" PRIu16 "\n", _instance_id); + + /* add the new instance to the list */ + _USED_INSTANCES(_on_off_switch_object) = LWM2M_LIST_ADD( + _USED_INSTANCES(_on_off_switch_object), + instance + ); + + result = 0; + +free_out: + mutex_unlock(&_on_off_switch_object.lock); + return result; +} + +int lwm2m_object_on_off_switch_update_status(uint16_t instance_id, bool status) +{ + int result = -EINVAL; + lwm2m_obj_on_off_switch_inst_t *instance; + + mutex_lock(&_on_off_switch_object.lock); + + instance = (lwm2m_obj_on_off_switch_inst_t *)LWM2M_LIST_FIND( + _USED_INSTANCES(_on_off_switch_object), + instance_id + ); + + if (!instance) { + DEBUG("[lwm2m:on_off_switch]: can't find instance %" PRId16 "\n", instance_id); + goto free_out; + } + + if (status != instance->status) { + if (status) { + instance->counter++; + } + + ztimer_stopwatch_start(&instance->stopwatch); + } + + instance->status = status; + _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID); + + result = 0; + +free_out: + mutex_unlock(&_on_off_switch_object.lock); + return result; +} + +int lwm2m_object_on_off_switch_update_app_type(uint16_t instance_id, const char *app_type, + size_t len) +{ + int result = -EINVAL; + lwm2m_obj_on_off_switch_inst_t *instance; + + mutex_lock(&_on_off_switch_object.lock); + + if (len > CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE - 1) { + DEBUG("[lwm2m:on_off_switch]: app_type string too long\n"); + result = -ENOBUFS; + goto free_out; + } + + instance = (lwm2m_obj_on_off_switch_inst_t *)LWM2M_LIST_FIND( + _USED_INSTANCES(_on_off_switch_object), + instance_id + ); + + if (!instance) { + DEBUG("[lwm2m:on_off_switch]: can't find instance %" PRId16 "\n", instance_id); + goto free_out; + } + + memcpy(instance->app_type, app_type, len); + instance->app_type[len] = '\0'; + + _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_APP_TYPE_ID); + + result = 0; + +free_out: + mutex_unlock(&_on_off_switch_object.lock); + return result; +} diff --git a/pkg/wakaama/include/objects/on_off_switch.h b/pkg/wakaama/include/objects/on_off_switch.h new file mode 100644 index 000000000000..94e86e92c760 --- /dev/null +++ b/pkg/wakaama/include/objects/on_off_switch.h @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2024 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup lwm2m_objects + * @defgroup lwm2m_objects_on_off-switch On/Off Switch + * @brief On/Off switch object implementation for LwM2M client using Wakaama + * + * @experimental This API is considered experimental and may change in future releases without + * deprecation process. + * + * This implements the LwM2M IPSO on/off switch object (ID 3342) as specified in the LwM2M registry. + * + * This IPSO object should be used with an On/Off switch to report the state of the switch. + * + * To use this object add `USEMODULE += wakaama_objects_on_off_switch` to the application Makefile. + * + * ## Resources + * + * For an XML description of the object see + * https://raw.githubusercontent.com/OpenMobileAlliance/lwm2m-registry/prod/3342.xml + * + * | Name | ID | Mandatory | Type | Range | Units | Implemented | + * |-----------------------|------|-----------|---------|-------|-------|-------------| + * | Digital Input State | 5500 | Yes | Boolean | - | - | Yes | + * | Digital Input Counter | 5501 | No | Integer | - | - | Yes | + * | On time | 5852 | No | Integer | - | s | Yes | + * | Off Time | 5854 | No | Integer | - | s | Yes | + * | Application Type | 5750 | No | String | - | - | Yes | + * + * ## Usage + * + * 1. Initialize the LwM2M client with @ref lwm2m_object_on_off_switch_init, by passing a pointer + * to the LwM2M client data. + * + * 2. Now you can create instances of the on/off switch object with + * @ref lwm2m_object_on_off_switch_instance_create. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * #define APP_TYPE "BTN 0" + * + * // ... /// + * + * lwm2m_object_t *on_off_switch; + * lwm2m_client_data_t client_data; + * + * lwm2m_client_init(&client_data); + * on_off_switch = lwm2m_object_on_off_switch_init(&client_data); + * + * lwm2m_obj_on_off_switch_args_t args = { + * .app_type = APP_TYPE, + * .app_type_len = sizeof(APP_TYPE) - 1 + * }; + * + * int result = lwm2m_object_on_off_switch_instance_create(&args, 0); + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 3. You can update the status and app_type of the on/off switch instance with + * @ref lwm2m_object_on_off_switch_update_status and + * @ref lwm2m_object_on_off_switch_update_app_type respectively. As this will make sure to send + * notifications to servers that may be observing these resources, avoid calling them from + * interrupt contexts. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * lwm2m_object_on_off_switch_update_app_type(0, true); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @{ + * + * @file + * + * @author Leandro Lanzieri + */ + +#ifndef OBJECTS_ON_OFF_SWITCH_H +#define OBJECTS_ON_OFF_SWITCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "liblwm2m.h" + +/** + * @defgroup lwm2m_objects_on_off_switch_config LwM2M On/Off switch object compile configurations + * @ingroup lwm2m_client_config + * @{ + */ +/** + * @brief Maximum number of instances of the object + */ +#ifndef CONFIG_LWM2M_ON_OFF_SWITCH_INSTANCES_MAX +#define CONFIG_LWM2M_ON_OFF_SWITCH_INSTANCES_MAX (3U) +#endif + +/** + * @brief Maximum size for the application type string + */ +#ifndef CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE +#define CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE (16U) +#endif +/** @} */ + +/** + * @brief On/Off switch object ID. + */ +#define LWM2M_ON_OFF_SWITCH_OBJECT_ID 3342 + +/** + * @name On/Off switch object resource's IDs. + * @{ + */ +/** + * @brief Digital input state esource ID. + */ +#define LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID 5500 +/** + * @brief Digital Input Counter resource ID. + */ +#define LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_COUNTER_ID 5501 +/** + * @brief On Time resource ID. + */ +#define LWM2M_ON_OFF_SWITCH_ON_TIME_ID 5852 +/** + * @brief Off Time resource ID. + */ +#define LWM2M_ON_OFF_SWITCH_OFF_TIME_ID 5854 +/** + * @brief Application type resource ID. + */ +#define LWM2M_ON_OFF_SWITCH_APP_TYPE_ID 5750 +/** @} */ + +/** + * @brief Arguments for the creation of an on/off switch object instance. + */ +typedef struct lwm2m_obj_on_off_switch_args { + const char *app_type; /**< Array of chars with the app type. May be NULL. */ + size_t app_type_len; /**< Length of app_type */ +} lwm2m_obj_on_off_switch_args_t; + +/** + * @brief Initialize the on/off switch object. + * + * @param[in] client_data LwM2M client data. + * + * @return Pointer to the On/Off switch object on success + */ +lwm2m_object_t *lwm2m_object_on_off_switch_init(lwm2m_client_data_t *client_data); + +/** + * @brief Create a new on/off switch instance and add it to the @p object list. + * + * @param[in] args Initialize structure with the parameter for the instance. May + * not be NULL. + * @param[in] instance_id ID for the new instance. It must be between 0 and + * (UINT16_MAX - 1), if -1 the next available ID will be used. + * + * @return 0 on success + * @return -EINVAL if an invalid @p instance_id is given + * @return -ENOMEM if no memory is available to create a new instance + */ +int lwm2m_object_on_off_switch_instance_create(const lwm2m_obj_on_off_switch_args_t *args, + int32_t instance_id); + +/** + * @brief Update the status of a on/off switch instance. + * + * @param[in] instance_id ID of the instance to update. + * @param[in] status New status of the switch. + * + * @return 0 on success + * @return -EINVAL if the instance does not exist + */ +int lwm2m_object_on_off_switch_update_status(uint16_t instance_id, bool status); + +/** + * @brief Update the application type of a on/off switch instance. + * + * @param[in] instance_id ID of the instance to update. + * @param[in] app_type New application type. + * @param[in] len Length of the app_type string. + * + * @return 0 on success + * @return -EINVAL if the instance does not exist + * @return -ENOBUFS if the app_type string is too long + */ +int lwm2m_object_on_off_switch_update_app_type(uint16_t instance_id, const char *app_type, + size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* OBJECTS_ON_OFF_SWITCH_H */ +/** @} */ From 2254a3527f31b1794e4b12b7ec123144f172ffe5 Mon Sep 17 00:00:00 2001 From: Leandro Lanzieri Date: Wed, 25 Dec 2024 11:38:59 +0100 Subject: [PATCH 2/7] examples/lwm2m: add on/off switch object --- examples/lwm2m/Makefile | 1 + examples/lwm2m/lwm2m_cli.c | 42 +++++++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/examples/lwm2m/Makefile b/examples/lwm2m/Makefile index efbecb6cd112..cc6324caacae 100644 --- a/examples/lwm2m/Makefile +++ b/examples/lwm2m/Makefile @@ -28,6 +28,7 @@ DEVELHELP ?= 1 # NOTE: Add the package for wakaama USEPKG += wakaama USEMODULE += wakaama_objects_light_control +USEMODULE += wakaama_objects_on_off_switch # add DTLS support USEMODULE += wakaama_client_dtls diff --git a/examples/lwm2m/lwm2m_cli.c b/examples/lwm2m/lwm2m_cli.c index 9b9d63a39ecb..147dd3c8f815 100644 --- a/examples/lwm2m/lwm2m_cli.c +++ b/examples/lwm2m/lwm2m_cli.c @@ -26,12 +26,13 @@ #include "objects/device.h" #include "objects/security.h" #include "objects/light_control.h" +#include "objects/on_off_switch.h" #include "credentials.h" #define LED_COLOR "FFFFFF" #define LED_APP_TYPE "LED 0" -# define OBJ_COUNT (4) +# define OBJ_COUNT (5) uint8_t connected = 0; lwm2m_object_t *obj_list[OBJ_COUNT]; @@ -67,6 +68,7 @@ void lwm2m_cli_init(void) obj_list[1] = lwm2m_client_get_server_object(&client_data, CONFIG_LWM2M_SERVER_SHORT_ID); obj_list[2] = lwm2m_object_device_init(&client_data); obj_list[3] = lwm2m_object_light_control_init(&client_data); + obj_list[4] = lwm2m_object_on_off_switch_init(&client_data); /* create light control object instance */ lwm2m_obj_light_control_args_t light_args = { @@ -83,6 +85,17 @@ void lwm2m_cli_init(void) puts("Error instantiating light control"); } + /* create on/off switch object instance */ + lwm2m_obj_on_off_switch_args_t switch_args = { + .app_type = "Switch 0", + .app_type_len = sizeof("Switch 0") - 1 + }; + + res = lwm2m_object_on_off_switch_instance_create(&switch_args, 0); + if (res < 0) { + puts("Error instantiating on/off switch"); + } + /* create security object instance */ lwm2m_obj_security_args_t security_args = { .server_id = CONFIG_LWM2M_SERVER_SHORT_ID, @@ -159,6 +172,25 @@ static int _parse_lwm2m_light_cmd(int argc, char **argv) return 0; } +static int _parse_lwm2m_switch_cmd(int argc, char **argv) +{ + if (argc < 3) { + printf("usage: %s switch \n", argv[0]); + return 1; + } + + if (!connected) { + puts("LwM2M client not connected"); + return 1; + } + + bool status = !strcmp(argv[2], "on"); + lwm2m_object_on_off_switch_update_status(0, status); + + return 0; +} + + int lwm2m_cli_cmd(int argc, char **argv) { if (argc == 1) { @@ -182,12 +214,16 @@ int lwm2m_cli_cmd(int argc, char **argv) return _parse_lwm2m_light_cmd(argc, argv); } + if (!strcmp(argv[1], "switch")) { + return _parse_lwm2m_switch_cmd(argc, argv); + } + help_error: if (IS_ACTIVE(DEVELHELP)) { - printf("usage: %s \n", argv[0]); + printf("usage: %s \n", argv[0]); } else { - printf("usage: %s \n", argv[0]); + printf("usage: %s \n", argv[0]); } return 1; From 9c15ffa4b8b9c778d45dee1d55b2fc3847a9be91 Mon Sep 17 00:00:00 2001 From: Leandro Lanzieri Date: Sat, 11 Jan 2025 14:35:51 +0100 Subject: [PATCH 3/7] fixup! pkg/wakaama/objects: add IPSO on/off switch --- pkg/wakaama/contrib/objects/on_off_switch.c | 270 ++++++++++++-------- pkg/wakaama/include/objects/on_off_switch.h | 9 +- 2 files changed, 170 insertions(+), 109 deletions(-) diff --git a/pkg/wakaama/contrib/objects/on_off_switch.c b/pkg/wakaama/contrib/objects/on_off_switch.c index c76b6fdc52bb..87e282ffdbaa 100644 --- a/pkg/wakaama/contrib/objects/on_off_switch.c +++ b/pkg/wakaama/contrib/objects/on_off_switch.c @@ -24,7 +24,7 @@ #include "ztimer.h" #include "ztimer/stopwatch.h" -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG 1 #include "debug.h" #define _USED_INSTANCES(_obj) (_obj.wakaama_object.instanceList) @@ -34,11 +34,11 @@ * @brief LwM2M On/off switch object instance */ typedef struct lwm2m_obj_on_off_switch_inst { - lwm2m_list_t list; /**< list handle */ - bool status; /**< digital input status */ - uint32_t counter; /**< counter for the digital input */ - ztimer_stopwatch_t stopwatch; /**< stopwatch for time periods */ - char app_type[CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE]; /**< application type */ + lwm2m_list_t list; /**< list handle */ + bool status; /**< digital input status (ON/OFF) */ + uint32_t counter; /**< ON-transitions counter of the digital input*/ + ztimer_stopwatch_t stopwatch; /**< stopwatch to count ON/OFF time periods */ + char app_type[CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE]; /**< application type */ } lwm2m_obj_on_off_switch_inst_t; /** @@ -75,9 +75,9 @@ static uint8_t _write_cb(lwm2m_context_t * context, uint16_t instance_id, int nu lwm2m_data_t * data_array, lwm2m_object_t * object, lwm2m_write_type_t write_type); /** - * @brief Gets the current value of a given @p instance. + * @brief Gets the current value of a resource from a given On/off switch object @p instance. * - * @param[in, out] data Initialized data structure. + * @param[in, out] data Initialized resource data structure. * @param[in] instance Pointer to the instance to get the value from. * * @return COAP_205_CONTENT on success @@ -85,6 +85,18 @@ static uint8_t _write_cb(lwm2m_context_t * context, uint16_t instance_id, int nu */ static uint8_t _get_value(lwm2m_data_t *data, lwm2m_obj_on_off_switch_inst_t *instance); +/** + * @brief Sets the value of a resource in a given On/off switch object @p instance. + * + * @param[in] data Data structure containing the new value. + * @param[in] instance Pointer to the instance to set the value. + * + * @return COAP_204_CHANGED on success + * @return COAP_400_BAD_REQUEST if the value is not encoded correctly + * @return COAP_404_NOT_FOUND if the value is not found + */ +static uint8_t _set_value(lwm2m_data_t *data, lwm2m_obj_on_off_switch_inst_t *instance); + /** * @brief Mark a resource as changed on the LwM2M engine. * @@ -125,6 +137,10 @@ static uint8_t _get_value(lwm2m_data_t *data, lwm2m_obj_on_off_switch_inst_t *in lwm2m_data_encode_bool(instance->status, data); break; + case LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_COUNTER_ID: + lwm2m_data_encode_int(instance->counter, data); + break; + case LWM2M_ON_OFF_SWITCH_ON_TIME_ID: if (instance->status) { int64_t time = (int64_t) ztimer_stopwatch_measure(&instance->stopwatch); @@ -156,13 +172,13 @@ static uint8_t _get_value(lwm2m_data_t *data, lwm2m_obj_on_off_switch_inst_t *in } static uint8_t _read_cb(lwm2m_context_t * context, uint16_t instance_id, int * num_data, - lwm2m_data_t ** data_array, lwm2m_object_t * object) + lwm2m_data_t ** p_data_array, lwm2m_object_t * object) { (void)context; lwm2m_obj_on_off_switch_inst_t *instance; + lwm2m_data_t * data_array = *p_data_array; uint8_t result = COAP_404_NOT_FOUND; - int i = 0; mutex_lock(&_on_off_switch_object.lock); @@ -180,6 +196,7 @@ static uint8_t _read_cb(lwm2m_context_t * context, uint16_t instance_id, int * n uint16_t res_list[] = { LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID, + LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_COUNTER_ID, LWM2M_ON_OFF_SWITCH_ON_TIME_ID, LWM2M_ON_OFF_SWITCH_OFF_TIME_ID, LWM2M_ON_OFF_SWITCH_APP_TYPE_ID @@ -187,9 +204,12 @@ static uint8_t _read_cb(lwm2m_context_t * context, uint16_t instance_id, int * n /* allocate structures to return resources */ int res_num = ARRAY_SIZE(res_list); - *data_array = lwm2m_data_new(res_num); + data_array = lwm2m_data_new(res_num); - if (NULL == *data_array) { + /* make sure to update the returned pointer */ + *p_data_array = data_array; + + if (NULL == data_array) { result = COAP_500_INTERNAL_SERVER_ERROR; goto free_out; } @@ -198,24 +218,117 @@ static uint8_t _read_cb(lwm2m_context_t * context, uint16_t instance_id, int * n *num_data = res_num; /* set the IDs of the resources in the data structures */ - for (i = 0; i < res_num; i++) { - (*data_array)[i].id = res_list[i]; + for (int i = 0; i < res_num; i++) { + data_array[i].id = res_list[i]; } } /* now get the values */ - i = 0; - do { - DEBUG("[lwm2m:on_off_switch:read]: reading resource %" PRId16 "\n", (*data_array)[i].id); - result = _get_value(&(*data_array)[i], instance); - i++; - } while (i < *num_data && COAP_205_CONTENT == result); + for (int i = 0; i < *num_data; i++) { + result = _get_value(&data_array[i], instance); + + if (COAP_205_CONTENT != result) { + break; + } + } free_out: mutex_unlock(&_on_off_switch_object.lock); return result; } +static uint8_t _set_value(lwm2m_data_t *data, lwm2m_obj_on_off_switch_inst_t *instance) +{ + assert(data); + assert(instance); + + switch (data->id) { + case LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID: { + bool previous_status = instance->status; + + int decode_result = lwm2m_data_decode_bool(data, &instance->status); + if (!decode_result) { + DEBUG("[lwm2m:on_off_switch:write]: invalid value for digital_input_state\n"); + return COAP_400_BAD_REQUEST; + } + + /* reset timer on transitions */ + if (instance->status != previous_status) { + ztimer_stopwatch_reset(&instance->stopwatch); + + if (instance->status) { + instance->counter++; + } + } + + _mark_resource_changed(instance->list.id, LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID); + return COAP_204_CHANGED; + } + + case LWM2M_ON_OFF_SWITCH_ON_TIME_ID: + { + int64_t value; + + int decode_result = lwm2m_data_decode_int(data, &value); + if (!decode_result) { + DEBUG("[lwm2m:on_off_switch:write]: invalid on_time value\n"); + return COAP_400_BAD_REQUEST; + } + + if (value != 0) { + DEBUG("[lwm2m:on_off_switch:write]: invalid on_time value, only can write 0\n"); + return COAP_400_BAD_REQUEST; + } + + ztimer_stopwatch_reset(&instance->stopwatch); + _mark_resource_changed(instance->list.id, LWM2M_ON_OFF_SWITCH_ON_TIME_ID); + return COAP_204_CHANGED; + } + + case LWM2M_ON_OFF_SWITCH_OFF_TIME_ID: + { + int64_t value; + int decode_result = lwm2m_data_decode_int(data, &value); + if (!decode_result) { + DEBUG("[lwm2m:on_off_switch:write]: invalid off_time value\n"); + return COAP_400_BAD_REQUEST; + } + + if (value != 0) { + DEBUG("[lwm2m:on_off_switch:write]: invalid off_time value, only can write 0\n"); + return COAP_400_BAD_REQUEST; + } + + ztimer_stopwatch_reset(&instance->stopwatch); + _mark_resource_changed(instance->list.id, LWM2M_ON_OFF_SWITCH_OFF_TIME_ID); + return COAP_204_CHANGED; + } + + case LWM2M_ON_OFF_SWITCH_APP_TYPE_ID: + if (data->type != LWM2M_TYPE_STRING && data->type != LWM2M_TYPE_OPAQUE) { + DEBUG("[lwm2m:on_off_switch:write]: invalid type for app_type" + "(%" PRId8 ")\n", (uint8_t)(data->type)); + return COAP_400_BAD_REQUEST; + } + + if (data->value.asBuffer.length > + CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE - 1) { + DEBUG("[lwm2m:on_off_switch:write]: value too big for app_type\n"); + return COAP_500_INTERNAL_SERVER_ERROR; + } + + memcpy(instance->app_type, data->value.asBuffer.buffer, + data->value.asBuffer.length); + instance->app_type[data->value.asBuffer.length] = '\0'; + _mark_resource_changed(instance->list.id, LWM2M_ON_OFF_SWITCH_APP_TYPE_ID); + return COAP_204_CHANGED; + + default: + return COAP_404_NOT_FOUND; + } + +} + static uint8_t _write_cb(lwm2m_context_t * context, uint16_t instance_id, int num_data, lwm2m_data_t * data_array, lwm2m_object_t * object, lwm2m_write_type_t write_type) { @@ -223,7 +336,7 @@ static uint8_t _write_cb(lwm2m_context_t * context, uint16_t instance_id, int nu (void)write_type; lwm2m_obj_on_off_switch_inst_t *instance; - uint8_t result = COAP_204_CHANGED; + uint8_t result = COAP_404_NOT_FOUND; mutex_lock(&_on_off_switch_object.lock); @@ -235,74 +348,13 @@ static uint8_t _write_cb(lwm2m_context_t * context, uint16_t instance_id, int nu goto free_out; } - for (int i = 0; i < num_data && result == COAP_204_CHANGED; i++) { - switch (data_array[i].id) { - case LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID: { - bool prev_status = instance->status; - - lwm2m_data_decode_bool(&data_array[i], &instance->status); - - /* reset timer on transitions */ - if (instance->status != prev_status) { - ztimer_stopwatch_reset(&instance->stopwatch); - - if (instance->status) { - instance->counter++; - } - } - - _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID); - break; - } - - case LWM2M_ON_OFF_SWITCH_ON_TIME_ID: - { - int64_t val; - lwm2m_data_decode_int(&data_array[i], &val); - if (val != 0) { - DEBUG("[lwm2m:on_off_switch:write]: invalid on_time value, only can write 0\n"); - result = COAP_400_BAD_REQUEST; - } else { - ztimer_stopwatch_reset(&instance->stopwatch); - _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_ON_TIME_ID); - } - break; - } - - case LWM2M_ON_OFF_SWITCH_OFF_TIME_ID: - { - int64_t val; - lwm2m_data_decode_int(&data_array[i], &val); - if (val != 0) { - DEBUG("[lwm2m:on_off_switch:write]: invalid off_time value, only can write 0\n"); - result = COAP_400_BAD_REQUEST; - } else { - ztimer_stopwatch_reset(&instance->stopwatch); - _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_OFF_TIME_ID); - } - break; - } + for (int i = 0; i < num_data; i++) { + result = _set_value(&data_array[i], instance); - case LWM2M_ON_OFF_SWITCH_APP_TYPE_ID: - if (data_array[i].type != LWM2M_TYPE_STRING && data_array[i].type != LWM2M_TYPE_OPAQUE) { - DEBUG("[lwm2m:on_off_switch:write]: invalid type for app_type" - "(%" PRId8 ")\n", (uint8_t)(data_array[i].type)); - result = COAP_400_BAD_REQUEST; - break; - } - - if (data_array[i].value.asBuffer.length > - CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE - 1) { - DEBUG("[lwm2m:on_off_switch:write]: value too big for app_type\n"); - result = COAP_500_INTERNAL_SERVER_ERROR; - break; - } - - memcpy(instance->app_type, data_array[i].value.asBuffer.buffer, - data_array[i].value.asBuffer.length); - instance->app_type[data_array[i].value.asBuffer.length] = '\0'; - _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_APP_TYPE_ID); - break; + if (result != COAP_204_CHANGED) { + DEBUG("[lwm2m:on_off_switch:write]: error writing resource %" PRId16 "\n", + data_array[i].id); + goto free_out; } } @@ -321,12 +373,15 @@ static void _mark_resource_changed(uint16_t instance_id, uint16_t resource_id) lwm2m_client_data_t *client_data; client_data = (lwm2m_client_data_t *)_on_off_switch_object.wakaama_object.userData; + assert(client_data); lwm2m_resource_value_changed(client_data->lwm2m_ctx, &uri); } lwm2m_object_t *lwm2m_object_on_off_switch_init(lwm2m_client_data_t *client_data) { + assert(client_data); + /* initialize the instances */ for (unsigned i = 0; i < CONFIG_LWM2M_ON_OFF_SWITCH_INSTANCES_MAX; i++) { _on_off_switch_object.instances[i].list.next = NULL; @@ -437,17 +492,18 @@ int lwm2m_object_on_off_switch_update_status(uint16_t instance_id, bool status) goto free_out; } - if (status != instance->status) { - if (status) { - instance->counter++; - } + lwm2m_data_t data = { + .type = LWM2M_TYPE_BOOLEAN, + .id = LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID, + .value.asBoolean = status + }; - ztimer_stopwatch_start(&instance->stopwatch); + int set_result = _set_value(&data, instance); + if (set_result != COAP_204_CHANGED) { + DEBUG("[lwm2m:on_off_switch]: error updating status\n"); + goto free_out; } - instance->status = status; - _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_DIGITAL_INPUT_STATE_ID); - result = 0; free_out: @@ -458,17 +514,13 @@ int lwm2m_object_on_off_switch_update_status(uint16_t instance_id, bool status) int lwm2m_object_on_off_switch_update_app_type(uint16_t instance_id, const char *app_type, size_t len) { + assert(app_type); + int result = -EINVAL; lwm2m_obj_on_off_switch_inst_t *instance; mutex_lock(&_on_off_switch_object.lock); - if (len > CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE - 1) { - DEBUG("[lwm2m:on_off_switch]: app_type string too long\n"); - result = -ENOBUFS; - goto free_out; - } - instance = (lwm2m_obj_on_off_switch_inst_t *)LWM2M_LIST_FIND( _USED_INSTANCES(_on_off_switch_object), instance_id @@ -479,10 +531,18 @@ int lwm2m_object_on_off_switch_update_app_type(uint16_t instance_id, const char goto free_out; } - memcpy(instance->app_type, app_type, len); - instance->app_type[len] = '\0'; + lwm2m_data_t data = { + .type = LWM2M_TYPE_STRING, + .id = LWM2M_ON_OFF_SWITCH_APP_TYPE_ID, + .value.asBuffer.buffer = (uint8_t *)app_type, + .value.asBuffer.length = len + }; - _mark_resource_changed(instance_id, LWM2M_ON_OFF_SWITCH_APP_TYPE_ID); + int set_result = _set_value(&data, instance); + if (set_result != COAP_204_CHANGED) { + DEBUG("[lwm2m:on_off_switch]: error updating app_type\n"); + goto free_out; + } result = 0; diff --git a/pkg/wakaama/include/objects/on_off_switch.h b/pkg/wakaama/include/objects/on_off_switch.h index 94e86e92c760..3b9114fc3bd9 100644 --- a/pkg/wakaama/include/objects/on_off_switch.h +++ b/pkg/wakaama/include/objects/on_off_switch.h @@ -158,7 +158,7 @@ lwm2m_object_t *lwm2m_object_on_off_switch_init(lwm2m_client_data_t *client_data /** * @brief Create a new on/off switch instance and add it to the @p object list. * - * @param[in] args Initialize structure with the parameter for the instance. May + * @param[in] args Initialize structure with the parameter for the instance. Must * not be NULL. * @param[in] instance_id ID for the new instance. It must be between 0 and * (UINT16_MAX - 1), if -1 the next available ID will be used. @@ -185,12 +185,13 @@ int lwm2m_object_on_off_switch_update_status(uint16_t instance_id, bool status); * @brief Update the application type of a on/off switch instance. * * @param[in] instance_id ID of the instance to update. - * @param[in] app_type New application type. - * @param[in] len Length of the app_type string. + * @param[in] app_type String representing new application type. Must be NULL terminated, must + * not be NULL. + * @param[in] len Length of the @p app_type string. * * @return 0 on success * @return -EINVAL if the instance does not exist - * @return -ENOBUFS if the app_type string is too long + * @return -ENOBUFS if the app_type string is too long (size > @ref CONFIG_LWM2M_ON_OFF_SWITCH_APP_TYPE_MAX_SIZE) */ int lwm2m_object_on_off_switch_update_app_type(uint16_t instance_id, const char *app_type, size_t len); From db3088d1901042205ade51258100b72065314930 Mon Sep 17 00:00:00 2001 From: Leandro Lanzieri Date: Sat, 11 Jan 2025 14:50:40 +0100 Subject: [PATCH 4/7] fixup! examples/lwm2m: add on/off switch object --- examples/lwm2m/lwm2m_cli.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/lwm2m/lwm2m_cli.c b/examples/lwm2m/lwm2m_cli.c index 147dd3c8f815..d46d0c2a9395 100644 --- a/examples/lwm2m/lwm2m_cli.c +++ b/examples/lwm2m/lwm2m_cli.c @@ -174,7 +174,7 @@ static int _parse_lwm2m_light_cmd(int argc, char **argv) static int _parse_lwm2m_switch_cmd(int argc, char **argv) { - if (argc < 3) { + if (argc != 3) { printf("usage: %s switch \n", argv[0]); return 1; } @@ -190,7 +190,6 @@ static int _parse_lwm2m_switch_cmd(int argc, char **argv) return 0; } - int lwm2m_cli_cmd(int argc, char **argv) { if (argc == 1) { From 77bac9c95f5b9905d43631cfa6de1e53752b4f07 Mon Sep 17 00:00:00 2001 From: Leandro Lanzieri Date: Wed, 29 Jan 2025 08:37:17 +0100 Subject: [PATCH 5/7] fixup! examples/lwm2m: add on/off switch object --- examples/lwm2m/lwm2m_cli.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/examples/lwm2m/lwm2m_cli.c b/examples/lwm2m/lwm2m_cli.c index d46d0c2a9395..fe9c3e40073f 100644 --- a/examples/lwm2m/lwm2m_cli.c +++ b/examples/lwm2m/lwm2m_cli.c @@ -144,10 +144,17 @@ void lwm2m_cli_init(void) } } +static void _print_usage_lwm2m_light_cmd(const char *cmd) +{ + assert(cmd); + printf("usage: %s light [color]\n", cmd); +} + static int _parse_lwm2m_light_cmd(int argc, char **argv) { - if (argc < 4) { - printf("usage: %s light [color]\n", argv[0]); + if (argc < 4 || argc > 5) { + printf("Error: invalid number of arguments\n"); + _print_usage_lwm2m_light_cmd(argv[0]); return 1; } @@ -156,7 +163,19 @@ static int _parse_lwm2m_light_cmd(int argc, char **argv) return 1; } - bool status = !strcmp(argv[2], "on"); + bool status; + if (!strcmp(argv[2], "on")) { + status = true; + } + else if (!strcmp(argv[2], "off")) { + status = false; + } + else { + printf("Error: light status can only be 'on' or 'off'\n"); + _print_usage_lwm2m_light_cmd(argv[0]); + return 1; + } + uint8_t dimmer = atoi(argv[3]); if (argc > 4) { From d3e83fc20586557f3b52efeab801915ee9b92ceb Mon Sep 17 00:00:00 2001 From: Leandro Lanzieri Date: Wed, 29 Jan 2025 08:38:20 +0100 Subject: [PATCH 6/7] fixup! pkg/wakaama/objects: add IPSO on/off switch --- pkg/wakaama/contrib/objects/on_off_switch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/wakaama/contrib/objects/on_off_switch.c b/pkg/wakaama/contrib/objects/on_off_switch.c index 87e282ffdbaa..8f56a43851e5 100644 --- a/pkg/wakaama/contrib/objects/on_off_switch.c +++ b/pkg/wakaama/contrib/objects/on_off_switch.c @@ -24,7 +24,7 @@ #include "ztimer.h" #include "ztimer/stopwatch.h" -#define ENABLE_DEBUG 1 +#define ENABLE_DEBUG 0 #include "debug.h" #define _USED_INSTANCES(_obj) (_obj.wakaama_object.instanceList) @@ -377,7 +377,6 @@ static void _mark_resource_changed(uint16_t instance_id, uint16_t resource_id) lwm2m_resource_value_changed(client_data->lwm2m_ctx, &uri); } - lwm2m_object_t *lwm2m_object_on_off_switch_init(lwm2m_client_data_t *client_data) { assert(client_data); From fb2eaad57528a501e114a015b47049d4350619e6 Mon Sep 17 00:00:00 2001 From: Leandro Lanzieri Date: Wed, 29 Jan 2025 10:56:02 +0100 Subject: [PATCH 7/7] fixup! fixup! examples/lwm2m: add on/off switch object --- examples/lwm2m/lwm2m_cli.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/lwm2m/lwm2m_cli.c b/examples/lwm2m/lwm2m_cli.c index fe9c3e40073f..b2ac463475ae 100644 --- a/examples/lwm2m/lwm2m_cli.c +++ b/examples/lwm2m/lwm2m_cli.c @@ -164,17 +164,17 @@ static int _parse_lwm2m_light_cmd(int argc, char **argv) } bool status; - if (!strcmp(argv[2], "on")) { + if (!strcmp(argv[2], "on")) { status = true; - } - else if (!strcmp(argv[2], "off")) { + } + else if (!strcmp(argv[2], "off")) { status = false; - } - else { + } + else { printf("Error: light status can only be 'on' or 'off'\n"); _print_usage_lwm2m_light_cmd(argv[0]); return 1; - } + } uint8_t dimmer = atoi(argv[3]);