From d744e8306af916b22d389f82a9f972df77e2f56b Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Tue, 13 Mar 2018 09:34:11 +0100 Subject: [PATCH 01/12] Added Queue Mode implementation in LwM2M --- examples/ipso-objects/zoul/module-macros.h | 34 +++ examples/lwm2m-ipso-objects/Makefile | 3 + examples/lwm2m-ipso-objects/project-conf.h | 10 +- os/net/app-layer/coap/coap-observe.c | 14 + os/net/app-layer/coap/coap-observe.h | 2 + os/services/lwm2m/lwm2m-engine.c | 146 ++++++++- os/services/lwm2m/lwm2m-engine.h | 10 + os/services/lwm2m/lwm2m-notification-queue.c | 239 +++++++++++++++ os/services/lwm2m/lwm2m-notification-queue.h | 67 +++++ os/services/lwm2m/lwm2m-qmode-conf.h | 85 ++++++ os/services/lwm2m/lwm2m-qmode-object.c | 301 +++++++++++++++++++ os/services/lwm2m/lwm2m-qmode-object.h | 65 ++++ os/services/lwm2m/lwm2m-rd-client.c | 131 +++++++- os/services/lwm2m/lwm2m-rd-client.h | 9 + tests/01-compile-base/Makefile | 2 + tests/02-compile-arm-ports-01/Makefile | 2 + tests/03-compile-arm-ports-02/Makefile | 2 + 17 files changed, 1115 insertions(+), 7 deletions(-) create mode 100644 examples/ipso-objects/zoul/module-macros.h create mode 100644 os/services/lwm2m/lwm2m-notification-queue.c create mode 100644 os/services/lwm2m/lwm2m-notification-queue.h create mode 100644 os/services/lwm2m/lwm2m-qmode-conf.h create mode 100644 os/services/lwm2m/lwm2m-qmode-object.c create mode 100644 os/services/lwm2m/lwm2m-qmode-object.h diff --git a/examples/ipso-objects/zoul/module-macros.h b/examples/ipso-objects/zoul/module-macros.h new file mode 100644 index 000000000..5091ff08b --- /dev/null +++ b/examples/ipso-objects/zoul/module-macros.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, RISE SICS AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*---------------------------------------------------------------------------*/ +/* Only sleep mode 1 on Zoul to enable full 32 KiB RAM */ +#define LPM_CONF_MAX_PM 1 +/*---------------------------------------------------------------------------*/ diff --git a/examples/lwm2m-ipso-objects/Makefile b/examples/lwm2m-ipso-objects/Makefile index 7fa79d1ee..c2cef2cfd 100644 --- a/examples/lwm2m-ipso-objects/Makefile +++ b/examples/lwm2m-ipso-objects/Makefile @@ -11,4 +11,7 @@ MODULES += os/services/lwm2m MODULES += os/services/ipso-objects CONTIKI=../.. +include $(CONTIKI)/Makefile.identify-target +MODULES_REL += $(TARGET) + include $(CONTIKI)/Makefile.include diff --git a/examples/lwm2m-ipso-objects/project-conf.h b/examples/lwm2m-ipso-objects/project-conf.h index a7ad8b3ea..affe626b0 100644 --- a/examples/lwm2m-ipso-objects/project-conf.h +++ b/examples/lwm2m-ipso-objects/project-conf.h @@ -30,9 +30,6 @@ #ifndef PROJECT_CONF_H_ #define PROJECT_CONF_H_ -/* No sleep on CC2538 to enable full 32 KiB RAM */ -#define LPM_CONF_ENABLE 0 - #ifdef BOARD_STRING #define LWM2M_DEVICE_MODEL_NUMBER BOARD_STRING #elif defined(CONTIKI_TARGET_WISMOTE) @@ -62,4 +59,11 @@ /* Enable client-side support for COAP observe */ #define COAP_OBSERVE_CLIENT 1 +/* Definitions to enable Queue Mode, include the dynamic adaptation and change the default parameters */ +/* #define LWM2M_Q_MODE_CONF_ENABLED 1 + #define LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION 1 + #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME 2000 + #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME 10000 + #define LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 1 */ + #endif /* PROJECT_CONF_H_ */ diff --git a/os/net/app-layer/coap/coap-observe.c b/os/net/app-layer/coap/coap-observe.c index 83f5edf4a..d6ef3887e 100644 --- a/os/net/app-layer/coap/coap-observe.c +++ b/os/net/app-layer/coap/coap-observe.c @@ -353,4 +353,18 @@ coap_observe_handler(coap_resource_t *resource, coap_message_t *coap_req, } } /*---------------------------------------------------------------------------*/ +uint8_t +coap_has_observers(char *path) +{ + coap_observer_t *obs = NULL; + + for(obs = (coap_observer_t *)list_head(observers_list); obs; + obs = obs->next) { + if((strncmp(obs->url, path, strlen(path))) == 0) { + return 1; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/net/app-layer/coap/coap-observe.h b/os/net/app-layer/coap/coap-observe.h index c276522c5..93898f954 100644 --- a/os/net/app-layer/coap/coap-observe.h +++ b/os/net/app-layer/coap/coap-observe.h @@ -80,5 +80,7 @@ void coap_notify_observers_sub(coap_resource_t *resource, const char *subpath); void coap_observe_handler(coap_resource_t *resource, coap_message_t *request, coap_message_t *response); +uint8_t coap_has_observers(char *path); + #endif /* COAP_OBSERVE_H_ */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 6f2aeefd8..3c038deec 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -39,6 +39,7 @@ * \author * Joakim Eriksson * Niclas Finne + * Carlos Gonzalo Peces */ #include "lwm2m-engine.h" @@ -56,7 +57,6 @@ #include #include #include - #ifndef LWM2M_ENGINE_CLIENT_ENDPOINT_NAME #include "net/ipv6/uip-ds6.h" #endif /* LWM2M_ENGINE_CLIENT_ENDPOINT_NAME */ @@ -80,10 +80,24 @@ #define USE_RD_CLIENT 1 #endif /* LWM2M_ENGINE_CONF_USE_RD_CLIENT */ + +#if LWM2M_Q_MODE_ENABLED + /* Queue Mode is handled using the RD Client and the Q-Mode object */ +#define USE_RD_CLIENT 1 +/* Queue Mode dynamic adaptation masks */ +#define FIRST_REQUEST_MASK 0x01 +#define HANDLER_FROM_NOTIFICATION_MASK 0x02 +#endif + #if USE_RD_CLIENT #include "lwm2m-rd-client.h" #endif +#if LWM2M_Q_MODE_ENABLED +#include "lwm2m-qmode-object.h" +#include "lwm2m-notification-queue.h" +#endif + /* MACRO for getting out resource ID from resource array ID + flags */ #define RSC_ID(x) ((uint16_t)(x & 0xffff)) #define RSC_READABLE(x) ((x & LWM2M_RESOURCE_READ) > 0) @@ -129,6 +143,18 @@ static struct { /* in the future also a timeout */ } created; +#if LWM2M_Q_MODE_ENABLED +static uint8_t waked_up_by_notification; +/* For the dynamic adaptation of the awake time */ +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +static uint8_t dynamic_adaptation_params = 0x00; /* bit0: first_request, bit1: handler from notification */ +static uint64_t previous_request_time; +static inline void clear_first_request(); +static inline uint8_t is_first_request(); +static inline void clear_handler_from_notification(); +static inline uint8_t get_handler_from_notification(); +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_Q_MODE_ENABLED */ COAP_HANDLER(lwm2m_handler, lwm2m_handler_callback); LIST(object_list); @@ -554,6 +580,10 @@ lwm2m_engine_init(void) #if USE_RD_CLIENT lwm2m_rd_client_init(endpoint); #endif + +#if LWM2M_Q_MODE_ENABLED + lwm2m_q_object_init(); +#endif } /*---------------------------------------------------------------------------*/ /* @@ -1373,6 +1403,31 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, context.inbuf->size = coap_get_payload(request, (const uint8_t **)&context.inbuf->buffer); context.inbuf->pos = 0; + /*If Queue Mode, restart the client awake timer */ +#if LWM2M_Q_MODE_ENABLED + if(lwm2m_rd_client_is_client_awake()) { + lwm2m_rd_client_restart_client_awake_timer(); + } + +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { + if(is_first_request()) { + previous_request_time = coap_timer_uptime(); + clear_first_request(); + }else{ + if(coap_timer_uptime()-previous_request_time >= 0) { + lwm2m_q_object_add_time_object(coap_timer_uptime()-previous_request_time); + + } + previous_request_time = coap_timer_uptime(); + } + } + if(get_handler_from_notification()) { + clear_handler_from_notification(); + } +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_Q_MODE_ENABLED */ + /* Maybe this should be part of CoAP itself - this seems not to be working with the leshan server */ #define LWM2M_CONF_ENTITY_TOO_LARGE_BLOCK1 0 @@ -1632,14 +1687,99 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, return COAP_HANDLER_STATUS_PROCESSED; } /*---------------------------------------------------------------------------*/ -void lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, +static void +lwm2m_send_notification(char* path) +{ +#if LWM2M_Q_MODE_ENABLED && LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag()){ + lwm2m_engine_set_handler_from_notification(); + } +#endif + coap_notify_observers_sub(NULL, path); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, uint16_t resource) { char path[20]; /* 60000/60000/60000 */ if(obj != NULL) { snprintf(path, 20, "%d/%d/%d", obj->object_id, obj->instance_id, resource); - coap_notify_observers_sub(NULL, path); } + +#if LWM2M_Q_MODE_ENABLED + + if(coap_has_observers(path)) { + /* Client is sleeping -> add the notification to the list */ + if(!lwm2m_rd_client_is_client_awake()) { + lwm2m_notification_queue_add_notification_path(path); + + /* if it is the first notification -> wake up and send update */ + if(!waked_up_by_notification) { + waked_up_by_notification = 1; + lwm2m_rd_client_fsm_execute_q_mode_update(); + } + /* Client is awake -> send the notification */ + } else { + lwm2m_send_notification(path); + } + } +#else + lwm2m_send_notification(path); +#endif } /*---------------------------------------------------------------------------*/ +/* Queue Mode Support and dynamic adaptation of the client awake time */ +#if LWM2M_Q_MODE_ENABLED +uint8_t +lwm2m_engine_is_waked_up_by_notification() +{ + return waked_up_by_notification; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_engine_clear_waked_up_by_notification() +{ + waked_up_by_notification = 0; +} +/*---------------------------------------------------------------------------*/ +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +void +lwm2m_engine_set_first_request() +{ + dynamic_adaptation_params |= FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_engine_set_handler_from_notification() +{ + dynamic_adaptation_params |= HANDLER_FROM_NOTIFICATION_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline uint8_t +is_first_request() +{ + return dynamic_adaptation_params & FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline uint8_t +get_handler_from_notification() +{ + return (dynamic_adaptation_params & HANDLER_FROM_NOTIFICATION_MASK) != 0; +} +/*---------------------------------------------------------------------------*/ +static inline void +clear_first_request() +{ + dynamic_adaptation_params &= ~FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline void +clear_handler_from_notification() +{ + dynamic_adaptation_params &= ~HANDLER_FROM_NOTIFICATION_MASK; +} +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_Q_MODE_ENABLED */ +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-engine.h b/os/services/lwm2m/lwm2m-engine.h index 62a667e99..61d0353af 100644 --- a/os/services/lwm2m/lwm2m-engine.h +++ b/os/services/lwm2m/lwm2m-engine.h @@ -39,12 +39,14 @@ * \author * Joakim Eriksson * Niclas Finne + * Carlos Gonzalo Peces */ #ifndef LWM2M_ENGINE_H #define LWM2M_ENGINE_H #include "lwm2m-object.h" +#include "lwm2m-qmode-conf.h" #define LWM2M_FLOAT32_BITS 10 #define LWM2M_FLOAT32_FRAC (1L << LWM2M_FLOAT32_BITS) @@ -114,6 +116,14 @@ void lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, void lwm2m_engine_set_opaque_callback(lwm2m_context_t *ctx, lwm2m_write_opaque_callback cb); +#if LWM2M_Q_MODE_ENABLED +uint8_t lwm2m_engine_is_waked_up_by_notification(); +void lwm2m_engine_clear_waked_up_by_notification(); +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +void lwm2m_engine_set_first_request(); +void lwm2m_engine_set_handler_from_notification(); +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_Q_MODE_ENABLED */ #endif /* LWM2M_ENGINE_H */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c new file mode 100644 index 000000000..c3150a879 --- /dev/null +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2017, RISE SICS AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Implementation of functions to manage the queue of notifications + * \author + * Carlos Gonzalo Peces + */ +/*---------------------------------------------------------------------------*/ +#include "lwm2m-notification-queue.h" + +#if LWM2M_Q_MODE_ENABLED + +#include "lwm2m-qmode-object.h" +#include "lwm2m-engine.h" +#include "coap-engine.h" +#include "lib/memb.h" +#include "lib/list.h" +#include +#include +#include +#include + +/* Log configuration */ +#include "coap-log.h" +#define LOG_MODULE "lwm2m-notification-queue" +#define LOG_LEVEL LOG_LEVEL_LWM2M + +#ifdef LWM2M_NOTIFICATION_QUEUE_CONF_LENGTH +#define LWM2M_NOTIFICATION_QUEUE_LENGTH LWM2M_NOTIFICATION_QUEUE_CONF_LENGTH +#else +#define LWM2M_NOTIFICATION_QUEUE_LENGTH 3 +#endif + +/*---------------------------------------------------------------------------*/ +/* Queue to store the notifications in the period when the client has woken up, sent the update and it's waiting for the server response*/ +MEMB(notification_memb, notification_path_t, LWM2M_NOTIFICATION_QUEUE_LENGTH + 1); /* Length + 1 to allocate the new path to add */ +LIST(notification_paths_queue); +/*---------------------------------------------------------------------------*/ +void +lwm2m_notification_queue_init(void) +{ + list_init(notification_paths_queue); +} +/*---------------------------------------------------------------------------*/ +static void +reduce_path(notification_path_t *path_object, char *path) +{ + char *cut = strtok(path, "/"); + int i; + for(i = 0; i < 3; i++) { + if(cut != NULL) { + path_object->reduced_path[i] = (uint16_t)atoi(cut); + cut = strtok(NULL, "/"); + } else { + break; + } + } + path_object->level = i; +} +/*---------------------------------------------------------------------------*/ +static void +extend_path(notification_path_t *path_object, char *path) +{ + switch(path_object->level) { + case 1: + snprintf(path, sizeof(path) - 1, "%u", path_object->reduced_path[0]); + break; + case 2: + snprintf(path, sizeof(path) - 1, "%u/%u", path_object->reduced_path[0], path_object->reduced_path[1]); + break; + case 3: + snprintf(path, sizeof(path) - 1, "%u/%u/%u", path_object->reduced_path[0], path_object->reduced_path[1], path_object->reduced_path[2]); + break; + } +} +/*---------------------------------------------------------------------------*/ +static void +add_notification_path_object_ordered(notification_path_t *path) +{ + notification_path_t *iteration_path = (notification_path_t *)list_head(notification_paths_queue); + if(list_length(notification_paths_queue) == 0) { + list_add(notification_paths_queue, path); + } else if(path->level < iteration_path->level) { + list_push(notification_paths_queue, path); + } else if(memcmp((path->reduced_path), (iteration_path->reduced_path), (path->level) * sizeof(uint16_t)) <= 0) { + list_push(notification_paths_queue, path); + } else { + notification_path_t *previous_path = iteration_path; + while(iteration_path != NULL) { + if(path->level < iteration_path->level) { + path->next = iteration_path; + previous_path->next = path; + return; + } + if(memcmp((path->reduced_path), (iteration_path->reduced_path), (path->level) * sizeof(uint16_t)) <= 0) { + path->next = iteration_path; + previous_path->next = path; + return; + } + previous_path = iteration_path; + iteration_path = iteration_path->next; + } + list_add(notification_paths_queue, path); + } +} +/*---------------------------------------------------------------------------*/ +static void +remove_notification_path(notification_path_t *path) +{ + list_remove(notification_paths_queue, path); + memb_free(¬ification_memb, path); +} +/*---------------------------------------------------------------------------*/ +static void +notification_queue_remove_policy(uint16_t *reduced_path, uint8_t level) +{ + uint8_t path_removed_flag = 0; + + notification_path_t *path_object = NULL; + notification_path_t *iteration_path = NULL; + notification_path_t *previous = NULL; + notification_path_t *next_next = NULL; + notification_path_t *path_to_remove = NULL; + + for(iteration_path = (notification_path_t *)list_head(notification_paths_queue); iteration_path != NULL; + iteration_path = iteration_path->next) { + /* 1. check if there is one event of the same path -> remove it and add the new one */ + if((level == iteration_path->level) && memcmp(iteration_path->reduced_path, reduced_path, level * sizeof(uint16_t)) == 0) { + remove_notification_path(iteration_path); + path_object = memb_alloc(¬ification_memb); + memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); + path_object->level = level; + add_notification_path_object_ordered(path_object); + return; + } + /* 2. If there is no event of the same type, look for repeated events of the same resource and remove the oldest one */ + if(iteration_path->next != NULL && (iteration_path->level == iteration_path->next->level) + && (memcmp(iteration_path->reduced_path, (iteration_path->next)->reduced_path, iteration_path->level * sizeof(uint16_t)) == 0)) { + path_removed_flag = 1; + next_next = iteration_path->next->next; + path_to_remove = iteration_path->next; + previous = iteration_path; + } + } + /* 3. If there are no events for the same path, we remove a the oldest repeated event of another resource */ + if(path_removed_flag) { + memb_free(¬ification_memb, path_to_remove); + previous->next = next_next; + path_object = memb_alloc(¬ification_memb); + memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); + path_object->level = level; + add_notification_path_object_ordered(path_object); + } else { + /* 4. If all the events are from different resources, remove the last one */ + list_chop(notification_paths_queue); + path_object = memb_alloc(¬ification_memb); + memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); + path_object->level = level; + add_notification_path_object_ordered(path_object); + } + return; +} +/*---------------------------------------------------------------------------*/ +/* For adding objects to the list in an ordered way, depending on the path*/ +void +lwm2m_notification_queue_add_notification_path(char *path) +{ + notification_path_t *path_object = memb_alloc(¬ification_memb); + if(path_object == NULL) { + LOG_DBG("Could not allocate new notification in the queue\n"); + return; + } + reduce_path(path_object, path); + if(list_length(notification_paths_queue) >= LWM2M_NOTIFICATION_QUEUE_LENGTH) { + /* The queue is full, apply policy to remove */ + notification_queue_remove_policy(path_object->reduced_path, path_object->level); + } else { + add_notification_path_object_ordered(path_object); + } + LOG_DBG("Notification path added to the list: %s\n", path); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_notification_queue_send_notifications() +{ + char path[20]; + notification_path_t *iteration_path = (notification_path_t *)list_head(notification_paths_queue); + notification_path_t *aux = iteration_path; + + while(iteration_path != NULL) { + extend_path(iteration_path, path); +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag()) { + lwm2m_engine_set_handler_from_notification(); + } +#endif + LOG_DBG("Sending stored notification with path: %s\n", path); + coap_notify_observers_sub(NULL, path); + aux = iteration_path; + iteration_path = iteration_path->next; + remove_notification_path(aux); + } +} +#endif /* LWM2M_Q_MODE_ENABLED */ +/** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-notification-queue.h b/os/services/lwm2m/lwm2m-notification-queue.h new file mode 100644 index 000000000..3364d3a77 --- /dev/null +++ b/os/services/lwm2m/lwm2m-notification-queue.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017, RISE SICS AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Header file for functions to manage the queue of notifications + * \author + * Carlos Gonzalo Peces + */ + +#ifndef LWM2M_NOTIFICATION_QUEUE_H +#define LWM2M_NOTIFICATION_QUEUE_H + +#include "contiki.h" +#include "lwm2m-qmode-conf.h" + +#if LWM2M_Q_MODE_ENABLED +#include + +typedef struct notification_path { + struct notification_path *next; + uint16_t reduced_path[3]; + uint8_t level; /* The depth level of the path: 1. object, 2. object/instance, 3. object/instance/resource */ +} notification_path_t; + +void lwm2m_notification_queue_init(void); + +/* For adding objects to the list in an ordered way, depending on the path*/ +void lwm2m_notification_queue_add_notification_path(char *path); + +void lwm2m_notification_queue_send_notifications(); + +#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_NOTIFICATION_QUEUE_H */ +/** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-qmode-conf.h b/os/services/lwm2m/lwm2m-qmode-conf.h new file mode 100644 index 000000000..1220d0584 --- /dev/null +++ b/os/services/lwm2m/lwm2m-qmode-conf.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017, RISE SICS AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Queue Mode Configuration Parameters + * \author + * Carlos Gonzalo Peces + */ + +#ifndef LWM2M_QMODE_CONF_H +#define LWM2M_QMODE_CONF_H + +/* Enable the Queue Mode */ +#ifdef LWM2M_Q_MODE_CONF_ENABLED +#define LWM2M_Q_MODE_ENABLED LWM2M_Q_MODE_CONF_ENABLED +#else +#define LWM2M_Q_MODE_ENABLED 0 +#endif /* LWM2M_Q_MODE_CONF_ENABLED */ + +/* Default Sleeping Time */ +#ifdef LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME +#define LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME +#else +#define LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME 10000 /* msec */ +#endif /* LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEPING_TIME */ + +/* Default Awake Time */ +#ifdef LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME +#define LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME +#else +#define LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME 5000 /* msec */ +#endif /* LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME */ + +/* Include the possibility to do the dynamic adaptation of the client awake time */ +#ifdef LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION +#define LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION +#else +#define LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION 0 /* not included */ +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ + +/* Default value for the dynamic adaptation flag */ +#ifdef LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG +#define LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG +#else +#define LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 /* disabled */ +#endif /* LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG */ + +/* Length of the list of times for the dynamic adaptation */ +#define LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH 10 + +#endif /* LWM2M_QMODE_CONF_H */ +/** @} */ diff --git a/os/services/lwm2m/lwm2m-qmode-object.c b/os/services/lwm2m/lwm2m-qmode-object.c new file mode 100644 index 000000000..77a12e460 --- /dev/null +++ b/os/services/lwm2m/lwm2m-qmode-object.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2017, RISE SICS AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Implementation of the Contiki OMA LWM2M Queue Object for managing the queue mode + * \author + * Carlos Gonzalo Peces + */ + +#include "lwm2m-qmode-object.h" + +#if LWM2M_Q_MODE_ENABLED + +#include "lwm2m-object.h" +#include "lwm2m-engine.h" +#include "lwm2m-rd-client.h" +#include "lib/memb.h" +#include "lib/list.h" +#include + +/* Log configuration */ +#include "coap-log.h" +#define LOG_MODULE "lwm2m-qmode-object" +#define LOG_LEVEL LOG_LEVEL_LWM2M + +#define LWM2M_Q_OBJECT_ID 6000 +#define LWM2M_AWAKE_TIME_ID 3000 +#define LWM2M_SLEEP_TIME_ID 3001 + +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +#define LWM2M_DYNAMIC_ADAPTATION_FLAG_ID 3002 +#define UPDATE_WITH_MEAN 0 /* 1-mean time 0-maximum time */ +#endif + +static const lwm2m_resource_id_t resources[] = +{ RW(LWM2M_AWAKE_TIME_ID), + RW(LWM2M_SLEEP_TIME_ID), +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + RW(LWM2M_DYNAMIC_ADAPTATION_FLAG_ID), +#endif +}; + +static uint16_t q_mode_awake_time = LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME; +static uint32_t q_mode_sleep_time = LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME; +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +static uint8_t q_mode_dynamic_adaptation_flag = LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; + +typedef struct time_object { + struct times_object *next; + uint64_t time; +} time_object_t; + +/* Window to save the times and do the dynamic adaptation of the awake time*/ +MEMB(times_memb, time_object_t, LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH); +LIST(time_object_list); + +#endif +/*---------------------------------------------------------------------------*/ +uint16_t +lwm2m_q_object_get_awake_time() +{ + LOG_DBG("Client Awake Time: %d ms\n", (int)q_mode_awake_time); + return q_mode_awake_time; +} +/*---------------------------------------------------------------------------*/ +static void +lwm2m_q_object_set_awake_time(uint16_t time) +{ + q_mode_awake_time = time; +} +/*---------------------------------------------------------------------------*/ +uint32_t +lwm2m_q_object_get_sleep_time() +{ + LOG_DBG("Client Sleep Time: %d ms\n", (int)q_mode_sleep_time); + return q_mode_sleep_time; +} +/*---------------------------------------------------------------------------*/ +static void +lwm2m_q_object_set_sleep_time(uint32_t time) +{ + q_mode_sleep_time = time; +} +/*---------------------------------------------------------------------------*/ +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +uint8_t +lwm2m_q_object_get_dynamic_adaptation_flag() +{ + LOG_DBG("Dynamic Adaptation Flag: %d ms\n", (int)q_mode_dynamic_adaptation_flag); + return q_mode_dynamic_adaptation_flag; +} +/*---------------------------------------------------------------------------*/ +static void +lwm2m_q_object_set_dynamic_adaptation_flag(uint8_t flag) +{ + q_mode_dynamic_adaptation_flag = flag; +} +/*---------------------------------------------------------------------------*/ +#if !UPDATE_WITH_MEAN +static uint64_t +get_maximum_time() +{ + uint64_t max_time = 0; + time_object_t *iteration_time = NULL; + for(iteration_time = (time_object_t *)list_head(time_object_list); iteration_time; + iteration_time = (time_object_t *)iteration_time->next) { + + if(iteration_time->time > max_time) { + max_time = iteration_time->time; + } + } + return max_time; +} +#endif +/*---------------------------------------------------------------------------*/ +#if UPDATE_WITH_MEAN +static uint64_t +get_mean_time() +{ + uint64_t mean_time = 0; + time_object_t *iteration_time = NULL; + for(iteration_time = (time_object_t *)list_head(time_object_list); iteration_time; + (time_object_t *)iteration_time = iteration_time->next) { + + if(mean_time == 0) { + mean_time = iteration_time->time; + } else { + mean_time = (mean_time + iteration_time->time) / 2; + } + } + return mean_time; +} +#endif +/*---------------------------------------------------------------------------*/ +static void +update_awake_time() +{ +#if UPDATE_WITH_MEAN + uint64_t mean_time = get_mean_time(); + LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)mean_time); + lwm2m_q_object_set_awake_time(mean_time + (mean_time >> 1)); /* 50% margin */ + return; +#else + uint64_t max_time = get_maximum_time(); + LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)max_time); + lwm2m_q_object_set_awake_time(max_time + (max_time >> 1)); /* 50% margin */ + return; +#endif +} +/*---------------------------------------------------------------------------*/ +static void +remove_time_object(time_object_t *time_object) +{ + memb_free(×_memb, time_object); + list_remove(time_object_list, time_object); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_q_object_add_time_object(uint64_t time) +{ + time_object_t *time_object; + time_object = memb_alloc(×_memb); + if(time_object != NULL) { + time_object->time = time; + list_add(time_object_list, time_object); + } else { + remove_time_object((time_object_t *)list_head(time_object_list)); + time_object = memb_alloc(×_memb); + time_object->time = time; + list_add(time_object_list, time_object); + } + update_awake_time(); +} +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +/*---------------------------------------------------------------------------*/ +static lwm2m_status_t +lwm2m_callback(lwm2m_object_instance_t *object, lwm2m_context_t *ctx) +{ + if(ctx->operation == LWM2M_OP_READ) { + switch(ctx->resource_id) { + case LWM2M_AWAKE_TIME_ID: + lwm2m_object_write_int(ctx, (int32_t)q_mode_awake_time); + return LWM2M_STATUS_OK; + case LWM2M_SLEEP_TIME_ID: + lwm2m_object_write_int(ctx, (int32_t)q_mode_sleep_time); + return LWM2M_STATUS_OK; +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: + lwm2m_object_write_int(ctx, (int32_t)q_mode_dynamic_adaptation_flag); + return LWM2M_STATUS_OK; +#endif + } + } else if(ctx->operation == LWM2M_OP_WRITE) { + switch(ctx->resource_id) { + int32_t value_read; + size_t len; + + case LWM2M_AWAKE_TIME_ID: + + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Client Awake Time write request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write awake time\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_q_object_set_awake_time(value_read); + return LWM2M_STATUS_OK; + } + + case LWM2M_SLEEP_TIME_ID: + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Client Sleep Time write request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write sleep time\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_q_object_set_sleep_time(value_read); + return LWM2M_STATUS_OK; + } +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Dynamic Adaptation Flag request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write dynamic flag\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_q_object_set_dynamic_adaptation_flag(value_read); + return LWM2M_STATUS_OK; + } +#endif + } + } + + return LWM2M_STATUS_OPERATION_NOT_ALLOWED; +} +/*---------------------------------------------------------------------------*/ +static lwm2m_object_instance_t queue_object = { + .object_id = LWM2M_Q_OBJECT_ID, + .instance_id = 0, + .resource_ids = resources, + .resource_count = sizeof(resources) / sizeof(lwm2m_resource_id_t), + .resource_dim_callback = NULL, + .callback = lwm2m_callback, +}; +/*---------------------------------------------------------------------------*/ +void +lwm2m_q_object_init(void) +{ + lwm2m_engine_add_object(&queue_object); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_q_object_send_notifications() +{ + lwm2m_notify_object_observers(&queue_object, LWM2M_AWAKE_TIME_ID); + lwm2m_notify_object_observers(&queue_object, LWM2M_SLEEP_TIME_ID); +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + lwm2m_notify_object_observers(&queue_object, LWM2M_DYNAMIC_ADAPTATION_FLAG_ID); +#endif +} +/*---------------------------------------------------------------------------*/ +#endif /* LWM2M_Q_MODE_ENABLED */ +/** @} */ + diff --git a/os/services/lwm2m/lwm2m-qmode-object.h b/os/services/lwm2m/lwm2m-qmode-object.h new file mode 100644 index 000000000..68427a59c --- /dev/null +++ b/os/services/lwm2m/lwm2m-qmode-object.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017, RISE SICS AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup oma-lwm2m + * @{ + */ + +/** + * \file + * Header file for the Contiki OMA LWM2M Queue Object for managing the queue mode + * \author + * Carlos Gonzalo Peces + */ + +#ifndef LWM2M_Q_OBJECT_H_ +#define LWM2M_Q_OBJECT_H_ + +#include "contiki.h" +#include "lwm2m-qmode-conf.h" + +#if LWM2M_Q_MODE_ENABLED +#include + +uint16_t lwm2m_q_object_get_awake_time(); +uint32_t lwm2m_q_object_get_sleep_time(); +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +uint8_t lwm2m_q_object_get_dynamic_adaptation_flag(); +void lwm2m_q_object_add_time_object(uint64_t time); +#endif + +void lwm2m_q_object_send_notifications(); + +void lwm2m_q_object_init(void); + +#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_Q_OBJECT_H_ */ +/** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index 03d21e33e..61273797a 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -41,6 +41,7 @@ * Joakim Eriksson * Niclas Finne * Joel Hoglund + * Carlos Gonzalo Peces */ #include "lwm2m-engine.h" @@ -57,6 +58,10 @@ #include #include #include +#if LWM2M_Q_MODE_ENABLED +#include "lwm2m-qmode-object.h" +#include "lwm2m-notification-queue.h" +#endif #if UIP_CONF_IPV6_RPL #include "rpl.h" @@ -100,6 +105,10 @@ static coap_message_t request[1]; /* This way the message can be treated as #define DEREGISTER_SENT 11 #define DEREGISTER_FAILED 12 #define DEREGISTERED 13 +#if LWM2M_Q_MODE_ENABLED +#define Q_MODE_AWAKE 14 +#define Q_MODE_SEND_UPDATE 15 +#endif #define FLAG_RD_DATA_DIRTY 0x01 #define FLAG_RD_DATA_UPDATE_TRIGGERED 0x02 @@ -121,6 +130,13 @@ static void (*rd_callback)(coap_request_state_t *state); static coap_timer_t block1_timer; +#if LWM2M_Q_MODE_ENABLED +static coap_timer_t q_mode_client_awake_timer; /* Timer to control the client awake time */ +static uint8_t q_mode_client_awake; /* 1 - client is awake, 0 - client is sleeping */ +static uint16_t q_mode_client_awake_time; /* The time to be awake */ +static void q_mode_awake_timer_callback(coap_timer_t *timer); /* Callback for the client awake timer */ +#endif + static void check_periodic_observations(); static void update_callback(coap_request_state_t *state); @@ -147,7 +163,8 @@ set_rd_data(coap_message_t *request) } /*---------------------------------------------------------------------------*/ static void -prepare_update(coap_message_t *request, int triggered) { +prepare_update(coap_message_t *request, int triggered) +{ coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0); coap_set_header_uri_path(request, session_info.assigned_ep); @@ -423,7 +440,16 @@ registration_callback(coap_request_state_t *state) state->response->location_path_len); session_info.assigned_ep[state->response->location_path_len] = 0; /* if we decide to not pass the lt-argument on registration, we should force an initial "update" to register lifetime with server */ +#if LWM2M_Q_MODE_ENABLED +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag()) { + lwm2m_engine_set_first_request(); + } +#endif + lwm2m_rd_client_fsm_execute_q_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ +#else rd_state = REGISTRATION_DONE; +#endif /* remember the last reg time */ last_update = coap_timer_uptime(); LOG_DBG_("Done (assigned EP='%s')!\n", session_info.assigned_ep); @@ -468,8 +494,23 @@ update_callback(coap_request_state_t *state) LOG_DBG_("Done!\n"); /* remember the last reg time */ last_update = coap_timer_uptime(); +#if LWM2M_Q_MODE_ENABLED + /* If it has been waked up by a notification, send the stored notifications in queue */ + if(lwm2m_engine_is_waked_up_by_notification()) { + + lwm2m_engine_clear_waked_up_by_notification(); + lwm2m_notification_queue_send_notifications(); + } +#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_q_object_get_dynamic_adaptation_flag()) { + lwm2m_engine_set_first_request(); + } +#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ + lwm2m_rd_client_fsm_execute_q_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ +#else rd_state = REGISTRATION_DONE; rd_flags &= ~FLAG_RD_DATA_UPDATE_TRIGGERED; +#endif /* LWM2M_Q_MODE_ENABLED */ } else { /* Possible error response codes are 4.00 Bad request & 4.04 Not Found */ LOG_DBG_("Failed with code %d. Retrying registration\n", @@ -516,7 +557,15 @@ periodic_process(coap_timer_t *timer) uint64_t now; /* reschedule the CoAP timer */ +#if LWM2M_Q_MODE_ENABLED + /* In Queue Mode, the machine is not executed periodically, but with the awake/sleeping times */ + if(!((rd_state & 0xF) == 0xE)) { + coap_timer_reset(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); + } +#else coap_timer_reset(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); +#endif + now = coap_timer_uptime(); LOG_DBG("RD Client - state: %d, ms: %lu\n", rd_state, @@ -685,6 +734,24 @@ periodic_process(coap_timer_t *timer) rd_state = UPDATE_SENT; } break; +#if LWM2M_Q_MODE_ENABLED + case Q_MODE_AWAKE: + LOG_DBG("Queue Mode: Client is AWAKE at %lu\n", (unsigned long)coap_timer_uptime()); + q_mode_client_awake = 1; + q_mode_client_awake_time = lwm2m_q_object_get_awake_time(); + coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); + break; + case Q_MODE_SEND_UPDATE: +#if !STANDALONE + NETSTACK_MAC.on(); +#endif + prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED); + coap_send_request(&rd_request_state, &session_info.server_ep, request, + update_callback); + last_rd_progress = coap_timer_uptime(); + rd_state = UPDATE_SENT; + break; +#endif case UPDATE_SENT: /* just wait until the callback kicks us to the next state... */ @@ -718,15 +785,26 @@ lwm2m_rd_client_init(const char *ep) { session_info.ep = ep; /* default binding U = UDP, UQ = UDP Q-mode*/ +#if LWM2M_Q_MODE_ENABLED + session_info.binding = "UQ"; + session_info.lifetime = (LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; /* Enough margin to ensure that the client is not unregistered (we + * do not know the time it can stay awake) + */ +#else session_info.binding = "U"; if(session_info.lifetime == 0) { session_info.lifetime = LWM2M_DEFAULT_CLIENT_LIFETIME; } +#endif + rd_state = INIT; /* call the RD client periodically */ coap_timer_set_callback(&rd_timer, periodic_process); coap_timer_set(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); +#if LWM2M_Q_MODE_ENABLED + coap_timer_set_callback(&q_mode_client_awake_timer, q_mode_awake_timer_callback); +#endif } /*---------------------------------------------------------------------------*/ static void @@ -735,4 +813,55 @@ check_periodic_observations(void) /* TODO */ } /*---------------------------------------------------------------------------*/ +/* + *Queue Mode Support + */ +#if LWM2M_Q_MODE_ENABLED +/*---------------------------------------------------------------------------*/ +void +lwm2m_rd_client_restart_client_awake_timer(void) +{ + coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); +} +/*---------------------------------------------------------------------------*/ +uint8_t +lwm2m_rd_client_is_client_awake(void) +{ + return q_mode_client_awake; +} +/*---------------------------------------------------------------------------*/ +static void +q_mode_awake_timer_callback(coap_timer_t *timer) +{ + /* Timer has expired, no requests has been received, client can go to sleep */ + LOG_DBG("Queue Mode: Client is SLEEPING at %lu\n", (unsigned long)coap_timer_uptime()); + q_mode_client_awake = 0; +#if !STANDALONE + /* Turn off the radio and start sleeping timer. LPM will be entered since the radio + and the peripherals are off, and there is a sleep timer started for waking up */ + NETSTACK_MAC.off(); + rtimer_arch_schedule(RTIMER_NOW() + ((lwm2m_q_object_get_sleep_time() / 1000) * RTIMER_SECOND)); +#endif + rd_state = Q_MODE_SEND_UPDATE; + coap_timer_set(&rd_timer, lwm2m_q_object_get_sleep_time()); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_rd_client_fsm_execute_q_mode_awake() +{ + coap_timer_stop(&rd_timer); + rd_state = Q_MODE_AWAKE; + periodic_process(&rd_timer); +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_rd_client_fsm_execute_q_mode_update() +{ + coap_timer_stop(&rd_timer); + rd_state = Q_MODE_SEND_UPDATE; + periodic_process(&rd_timer); +} +/*---------------------------------------------------------------------------*/ +#endif +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.h b/os/services/lwm2m/lwm2m-rd-client.h index 7fba7e0ae..85946235d 100644 --- a/os/services/lwm2m/lwm2m-rd-client.h +++ b/os/services/lwm2m/lwm2m-rd-client.h @@ -40,6 +40,7 @@ * \author * Joakim Eriksson * Niclas Finne + * Carlos Gonzalo Peces */ #ifndef LWM2M_RD_CLIENT_H_ @@ -52,6 +53,7 @@ #define LWM2M_RD_CLIENT_DISCONNECTED 5 #include "lwm2m-object.h" +#include "lwm2m-qmode-conf.h" struct lwm2m_session_info; typedef void (*session_callback_t)(struct lwm2m_session_info *session, int status); @@ -75,6 +77,13 @@ void lwm2m_rd_client_init(const char *ep); void lwm2m_rd_client_set_session_callback(session_callback_t cb); +#if LWM2M_Q_MODE_ENABLED +uint8_t lwm2m_rd_client_is_client_awake(void); +void lwm2m_rd_client_restart_client_awake_timer(void); +void lwm2m_rd_client_fsm_execute_q_mode_awake(); +void lwm2m_rd_client_fsm_execute_q_mode_update(); +#endif + #ifndef LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN #define LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN 15 #endif /* LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN */ diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index eae930138..d9ef0ba58 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -15,6 +15,8 @@ libs/data-structures/sky \ libs/stack-check/sky \ lwm2m-ipso-objects/native \ lwm2m-ipso-objects/native:MAKE_WITH_DTLS=1 \ +lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1 \ +lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1\ rpl-udp/sky \ rpl-border-router/native \ rpl-border-router/native:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 5e73c4ecb..4bb1e9269 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -43,6 +43,8 @@ coap/coap-example-client/cc2538dk \ coap/coap-example-server/cc2538dk \ slip-radio/cc2538dk \ lwm2m-ipso-objects/cc2538dk \ +lwm2m-ipso-objects/cc2538dk:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1 \ +lwm2m-ipso-objects/native:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1\ multicast/cc2538dk \ dev/gpio-hal/cc2538dk \ dev/leds/cc2538dk \ diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index defd10a96..62120eba3 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -17,6 +17,8 @@ coap/coap-example-server/zoul \ multicast/zoul \ lwm2m-ipso-objects/zoul \ lwm2m-ipso-objects/zoul:MAKE_WITH_DTLS=1 \ +lwm2m-ipso-objects/zoul:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1 \ +lwm2m-ipso-objects/zoul:DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1\ hello-world/zoul \ sensniff/zoul \ sensniff/zoul:ZOUL_CONF_SUB_GHZ_SNIFFER=1 \ From 1f8754766a751c3f9c548340ca361577acd43269 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Fri, 6 Apr 2018 15:16:42 +0200 Subject: [PATCH 02/12] Added macros for defining wake up/sleep behaviour depending on the platform --- examples/ipso-objects/zoul/module-macros.h | 16 ++++++- os/services/lwm2m/lwm2m-rd-client.c | 52 +++++++++++++--------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/examples/ipso-objects/zoul/module-macros.h b/examples/ipso-objects/zoul/module-macros.h index 5091ff08b..4db4e82fe 100644 --- a/examples/ipso-objects/zoul/module-macros.h +++ b/examples/ipso-objects/zoul/module-macros.h @@ -27,8 +27,22 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ - /*---------------------------------------------------------------------------*/ /* Only sleep mode 1 on Zoul to enable full 32 KiB RAM */ #define LPM_CONF_MAX_PM 1 /*---------------------------------------------------------------------------*/ +/* Macros to enter sleep mode and wake up in the Zoul module. Sleep consists + * on turn off the radio and start a RTIMER to wake up, and wake up consists on + * turn on the radio again + */ +#define LWM2M_Q_MODE_WAKE_UP() do { \ + NETSTACK_MAC.on(); \ +} while(0) + +#define LWM2M_Q_MODE_SLEEP_MS(TIME_MS) do { \ + uint64_t aux = TIME_MS * RTIMER_SECOND; \ + NETSTACK_MAC.off(); \ + rtimer_arch_schedule(RTIMER_NOW() + (rtimer_clock_t)(aux / 1000)); \ +} while(0) + + diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index 61273797a..cf7c5deb3 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -43,7 +43,6 @@ * Joel Hoglund * Carlos Gonzalo Peces */ - #include "lwm2m-engine.h" #include "lwm2m-object.h" #include "lwm2m-device.h" @@ -58,15 +57,16 @@ #include #include #include -#if LWM2M_Q_MODE_ENABLED -#include "lwm2m-qmode-object.h" -#include "lwm2m-notification-queue.h" -#endif #if UIP_CONF_IPV6_RPL #include "rpl.h" #endif /* UIP_CONF_IPV6_RPL */ +#if LWM2M_Q_MODE_ENABLED +#include "lwm2m-qmode-object.h" +#include "lwm2m-notification-queue.h" +#endif /* LWM2M_Q_MODE_ENABLED */ + /* Log configuration */ #include "coap-log.h" #define LOG_MODULE "lwm2m-rd" @@ -131,10 +131,15 @@ static void (*rd_callback)(coap_request_state_t *state); static coap_timer_t block1_timer; #if LWM2M_Q_MODE_ENABLED -static coap_timer_t q_mode_client_awake_timer; /* Timer to control the client awake time */ -static uint8_t q_mode_client_awake; /* 1 - client is awake, 0 - client is sleeping */ +static coap_timer_t q_mode_client_awake_timer; /* Timer to control the client's + * awake time + */ +static uint8_t q_mode_client_awake; /* 1 - client is awake, + * 0 - client is sleeping + */ static uint16_t q_mode_client_awake_time; /* The time to be awake */ -static void q_mode_awake_timer_callback(coap_timer_t *timer); /* Callback for the client awake timer */ +/* Callback for the client awake timer */ +static void q_mode_awake_timer_callback(coap_timer_t *timer); #endif static void check_periodic_observations(); @@ -742,16 +747,19 @@ periodic_process(coap_timer_t *timer) coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); break; case Q_MODE_SEND_UPDATE: -#if !STANDALONE - NETSTACK_MAC.on(); -#endif +/* Define this macro to make the necessary actions for waking up, + * depending on the platform + */ +#ifdef LWM2M_Q_MODE_WAKE_UP + LWM2M_Q_MODE_WAKE_UP(); +#endif /* LWM2M_Q_MODE_WAKE_UP */ prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED); coap_send_request(&rd_request_state, &session_info.server_ep, request, update_callback); last_rd_progress = coap_timer_uptime(); rd_state = UPDATE_SENT; break; -#endif +#endif /* LWM2M_Q_MODE_ENABLED */ case UPDATE_SENT: /* just wait until the callback kicks us to the next state... */ @@ -787,9 +795,10 @@ lwm2m_rd_client_init(const char *ep) /* default binding U = UDP, UQ = UDP Q-mode*/ #if LWM2M_Q_MODE_ENABLED session_info.binding = "UQ"; - session_info.lifetime = (LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; /* Enough margin to ensure that the client is not unregistered (we - * do not know the time it can stay awake) - */ + /* Enough margin to ensure that the client is not unregistered (we + * do not know the time it can stay awake) + */ + session_info.lifetime = (LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; #else session_info.binding = "U"; if(session_info.lifetime == 0) { @@ -836,12 +845,11 @@ q_mode_awake_timer_callback(coap_timer_t *timer) /* Timer has expired, no requests has been received, client can go to sleep */ LOG_DBG("Queue Mode: Client is SLEEPING at %lu\n", (unsigned long)coap_timer_uptime()); q_mode_client_awake = 0; -#if !STANDALONE - /* Turn off the radio and start sleeping timer. LPM will be entered since the radio - and the peripherals are off, and there is a sleep timer started for waking up */ - NETSTACK_MAC.off(); - rtimer_arch_schedule(RTIMER_NOW() + ((lwm2m_q_object_get_sleep_time() / 1000) * RTIMER_SECOND)); -#endif + +/* Define this macro to enter sleep mode depending on the platform */ +#ifdef LWM2M_Q_MODE_SLEEP_MS + LWM2M_Q_MODE_SLEEP_MS(lwm2m_q_object_get_sleep_time()); +#endif /* LWM2M_Q_MODE_SLEEP_MS */ rd_state = Q_MODE_SEND_UPDATE; coap_timer_set(&rd_timer, lwm2m_q_object_get_sleep_time()); } @@ -862,6 +870,6 @@ lwm2m_rd_client_fsm_execute_q_mode_update() periodic_process(&rd_timer); } /*---------------------------------------------------------------------------*/ -#endif +#endif /* LWM2M_Q_MODE_ENABLED */ /*---------------------------------------------------------------------------*/ /** @} */ From 1dfa62fc88d58ef136b897e6bfe56cdf54cbf093 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Mon, 9 Apr 2018 14:16:26 +0200 Subject: [PATCH 03/12] Added Q-Mode regression tests working with Leshan Server --- .../zoul/module-macros.h | 0 .../18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh | 69 +++++++++++++++++++ .../09-lwm2m-qmode-standalone-test.sh | 68 ++++++++++++++++++ .../18-coap-lwm2m/pytests/test-qmode-awake.py | 20 ++++++ .../18-coap-lwm2m/pytests/test-qmode-sleep.py | 19 +++++ 5 files changed, 176 insertions(+) rename examples/{ipso-objects => lwm2m-ipso-objects}/zoul/module-macros.h (100%) create mode 100755 tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh create mode 100755 tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh create mode 100644 tests/18-coap-lwm2m/pytests/test-qmode-awake.py create mode 100644 tests/18-coap-lwm2m/pytests/test-qmode-sleep.py diff --git a/examples/ipso-objects/zoul/module-macros.h b/examples/lwm2m-ipso-objects/zoul/module-macros.h similarity index 100% rename from examples/ipso-objects/zoul/module-macros.h rename to examples/lwm2m-ipso-objects/zoul/module-macros.h diff --git a/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh new file mode 100755 index 000000000..142fb253d --- /dev/null +++ b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Contiki directory +CONTIKI=$1 +# Test basename +BASENAME=08-lwm2m-qmode-ipso-test + +IPADDR=fd00::302:304:506:708 + +# Starting Contiki-NG native node +echo "Starting native node - lwm2m/ipso objects with Q-Mode" +make -C $CONTIKI/examples/lwm2m-ipso-objects clean >/dev/null +make -C $CONTIKI/examples/lwm2m-ipso-objects DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1 > make.log 2> make.err +sudo $CONTIKI/examples/lwm2m-ipso-objects/example-ipso-objects.native > node.log 2> node.err & +CPID=$! +sleep 10 + +echo "Downloading leshan with Q-Mode support" +wget -nc https://carlosgp143.github.io/resources/leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar +echo "Starting leshan server with Q-Mode enabled" +java -jar leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar >leshan.log 2>leshan.err & +LESHID=$! + +COUNTER=10 +while [ $COUNTER -gt 0 ]; do + sleep 5 + aux=$(grep -c 'OK' leshan.err) + if [ $aux -eq 2 ] ; then + break + fi + let COUNTER-=1 +done + +echo "Closing native node" +sleep 1 +pgrep ipso | sudo xargs kill -9 + +echo "Closing leshan" +sleep 1 +pgrep java | sudo xargs kill -9 + +#Two OKs needed: awake and sleeping +aux=$(grep -c 'OK' leshan.err) +if [ $aux -eq 2 ] +then + cp leshan.err $BASENAME.testlog; + printf "%-32s TEST OK\n" "$BASENAME" | tee $BASENAME.testlog; +else + echo "==== make.log ====" ; cat make.log; + echo "==== make.err ====" ; cat make.err; + echo "==== node.log ====" ; cat node.log; + echo "==== node.err ====" ; cat node.err; + echo "==== leshan.log ====" ; cat leshan.log; + echo "==== leshan.err ====" ; cat leshan.err; + echo "==== $BASENAME.log ====" ; cat $BASENAME.log; + + printf "%-32s TEST FAIL\n" "$BASENAME" | tee $BASENAME.testlog; +fi + +rm make.log +rm make.err +rm node.log +rm node.err +rm leshan.log +rm leshan.err + +# We do not want Make to stop -> Return 0 +# The Makefile will check if a log contains FAIL at the end +exit 0 diff --git a/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh new file mode 100755 index 000000000..f22b20bef --- /dev/null +++ b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +# Contiki directory +CONTIKI=$1 +# Test basename +BASENAME=09-lwm2m-qmode-standalone-test + +# Building standalone posix example +echo "Compiling standalone posix example" +make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m clean >/dev/null +make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1 >make.log 2>make.err + +echo "Downloading leshan with Q-Mode support" +wget -nc https://carlosgp143.github.io/resources/leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar +echo "Starting leshan server with Q-Mode enabled" +java -jar leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar -lp 5686 -slp 5687 >leshan.log 2>leshan.err & +LESHID=$! + +echo "Starting lwm2m standalone example" +example-lwm2m-standalone/lwm2m/lwm2m-example coap://127.0.0.1:5686 > node.log 2> node.err & + +CPID=$! + +COUNTER=10 +while [ $COUNTER -gt 0 ]; do + sleep 5 + aux=$(grep -c 'OK' leshan.err) + if [ $aux -eq 2 ] ; then + break + fi + let COUNTER-=1 +done + +echo "Closing standalone example" +sleep 1 +pgrep lwm2m-example | sudo xargs kill -9 + +echo "Closing leshan" +sleep 1 +pgrep java | sudo xargs kill -9 + +aux=$(grep -c 'OK' leshan.err) +if [ $aux -eq 2 ] +then + cp leshan.err $BASENAME.testlog; + printf "%-32s TEST OK\n" "$BASENAME" | tee $BASENAME.testlog; +else + echo "==== make.log ====" ; cat make.log; + echo "==== make.err ====" ; cat make.err; + echo "==== node.log ====" ; cat node.log; + echo "==== node.err ====" ; cat node.err; + echo "==== leshan.log ====" ; cat leshan.log; + echo "==== leshan.err ====" ; cat leshan.err; + echo "==== $BASENAME.log ====" ; cat $BASENAME.log; + + printf "%-32s TEST FAIL\n" "$BASENAME" | tee $BASENAME.testlog; +fi + +rm make.log +rm make.err +rm node.log +rm node.err +rm leshan.log +rm leshan.err + +# We do not want Make to stop -> Return 0 +# The Makefile will check if a log contains FAIL at the end +exit 0 diff --git a/tests/18-coap-lwm2m/pytests/test-qmode-awake.py b/tests/18-coap-lwm2m/pytests/test-qmode-awake.py new file mode 100644 index 000000000..775e1cff0 --- /dev/null +++ b/tests/18-coap-lwm2m/pytests/test-qmode-awake.py @@ -0,0 +1,20 @@ +import unittest, array, time + +class TestQueueModeAwake(unittest.TestCase): + global respAwakeTime + global respSleepTime + + def test_read_awake_time(self): + self.assertEqual(respAwakeTime.getCode().getName(), "CONTENT") + + def test_read_sleep_time(self): + self.assertEqual(respSleepTime.getCode().getName(), "CONTENT") + + +print "----------------------------------------" +print "LWM2M Queue Mode Awake State Tester" +print "----------------------------------------" + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestQueueModeAwake) +unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py b/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py new file mode 100644 index 000000000..da9a2ffe8 --- /dev/null +++ b/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py @@ -0,0 +1,19 @@ +from __future__ import with_statement +import unittest, array, time + +class TestQueueModeSleep(unittest.TestCase): + global client + + def test_read_awake_time(self): + self.assertIsNone(client.read("6000/0/3000")) + + def test_read_sleep_time(self): + self.assertIsNone(client.read("6000/0/3001")) + + +print "----------------------------------------" +print "LWM2M Queue Mode Sleep State Tester - name of client: ", client.endpoint +print "----------------------------------------" + +suite = unittest.TestLoader().loadTestsFromTestCase(TestQueueModeSleep) +unittest.TextTestRunner(verbosity=2).run(suite) From 18714f2cad672fb73fee92e59843343cfa36d6b4 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Fri, 27 Apr 2018 16:31:22 +0200 Subject: [PATCH 04/12] Simplified awake time adaptation with array and other small fixes --- examples/lwm2m-ipso-objects/project-conf.h | 2 +- os/services/lwm2m/lwm2m-engine.c | 10 +-- os/services/lwm2m/lwm2m-notification-queue.c | 10 +-- os/services/lwm2m/lwm2m-qmode-object.c | 66 +++++++------------- os/services/lwm2m/lwm2m-qmode-object.h | 2 +- 5 files changed, 36 insertions(+), 54 deletions(-) diff --git a/examples/lwm2m-ipso-objects/project-conf.h b/examples/lwm2m-ipso-objects/project-conf.h index affe626b0..53d149617 100644 --- a/examples/lwm2m-ipso-objects/project-conf.h +++ b/examples/lwm2m-ipso-objects/project-conf.h @@ -64,6 +64,6 @@ #define LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION 1 #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME 2000 #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME 10000 - #define LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 1 */ + #define LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 */ #endif /* PROJECT_CONF_H_ */ diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 3c038deec..b80e6f5a4 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -1414,10 +1414,12 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, if(is_first_request()) { previous_request_time = coap_timer_uptime(); clear_first_request(); - }else{ + } else { if(coap_timer_uptime()-previous_request_time >= 0) { - lwm2m_q_object_add_time_object(coap_timer_uptime()-previous_request_time); - + if(coap_timer_uptime()-previous_request_time > 0xffff) { + lwm2m_q_object_add_time_to_window(0xffff); + } + lwm2m_q_object_add_time_to_window(coap_timer_uptime()-previous_request_time); } previous_request_time = coap_timer_uptime(); } @@ -1691,7 +1693,7 @@ static void lwm2m_send_notification(char* path) { #if LWM2M_Q_MODE_ENABLED && LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()){ + if(lwm2m_q_object_get_dynamic_adaptation_flag()) { lwm2m_engine_set_handler_from_notification(); } #endif diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c index c3150a879..dab243ec1 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.c +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -93,17 +93,17 @@ reduce_path(notification_path_t *path_object, char *path) } /*---------------------------------------------------------------------------*/ static void -extend_path(notification_path_t *path_object, char *path) +extend_path(notification_path_t *path_object, char *path, int path_size) { switch(path_object->level) { case 1: - snprintf(path, sizeof(path) - 1, "%u", path_object->reduced_path[0]); + snprintf(path, path_size, "%u", path_object->reduced_path[0]); break; case 2: - snprintf(path, sizeof(path) - 1, "%u/%u", path_object->reduced_path[0], path_object->reduced_path[1]); + snprintf(path, path_size, "%u/%u", path_object->reduced_path[0], path_object->reduced_path[1]); break; case 3: - snprintf(path, sizeof(path) - 1, "%u/%u/%u", path_object->reduced_path[0], path_object->reduced_path[1], path_object->reduced_path[2]); + snprintf(path, path_size, "%u/%u/%u", path_object->reduced_path[0], path_object->reduced_path[1], path_object->reduced_path[2]); break; } } @@ -222,7 +222,7 @@ lwm2m_notification_queue_send_notifications() notification_path_t *aux = iteration_path; while(iteration_path != NULL) { - extend_path(iteration_path, path); + extend_path(iteration_path, path, sizeof(path)); #if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_q_object_get_dynamic_adaptation_flag()) { lwm2m_engine_set_handler_from_notification(); diff --git a/os/services/lwm2m/lwm2m-qmode-object.c b/os/services/lwm2m/lwm2m-qmode-object.c index 77a12e460..be5bc7674 100644 --- a/os/services/lwm2m/lwm2m-qmode-object.c +++ b/os/services/lwm2m/lwm2m-qmode-object.c @@ -78,14 +78,9 @@ static uint32_t q_mode_sleep_time = LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME; #if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION static uint8_t q_mode_dynamic_adaptation_flag = LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; -typedef struct time_object { - struct times_object *next; - uint64_t time; -} time_object_t; - /* Window to save the times and do the dynamic adaptation of the awake time*/ -MEMB(times_memb, time_object_t, LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH); -LIST(time_object_list); +uint16_t times_window[LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH] = { 0 }; +uint8_t times_window_index = 0; #endif /*---------------------------------------------------------------------------*/ @@ -130,16 +125,14 @@ lwm2m_q_object_set_dynamic_adaptation_flag(uint8_t flag) } /*---------------------------------------------------------------------------*/ #if !UPDATE_WITH_MEAN -static uint64_t +static uint16_t get_maximum_time() { - uint64_t max_time = 0; - time_object_t *iteration_time = NULL; - for(iteration_time = (time_object_t *)list_head(time_object_list); iteration_time; - iteration_time = (time_object_t *)iteration_time->next) { - - if(iteration_time->time > max_time) { - max_time = iteration_time->time; + uint16_t max_time = 0; + uint8_t i; + for(i = 0; i < LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { + if(times_window[i] > max_time) { + max_time = times_window[i]; } } return max_time; @@ -147,18 +140,18 @@ get_maximum_time() #endif /*---------------------------------------------------------------------------*/ #if UPDATE_WITH_MEAN -static uint64_t +static uint16_t get_mean_time() { - uint64_t mean_time = 0; - time_object_t *iteration_time = NULL; - for(iteration_time = (time_object_t *)list_head(time_object_list); iteration_time; - (time_object_t *)iteration_time = iteration_time->next) { - + uint16_t mean_time = 0; + uint8_t i; + for(i = 0; i < LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { if(mean_time == 0) { - mean_time = iteration_time->time; + mean_time = times_window[i]; } else { - mean_time = (mean_time + iteration_time->time) / 2; + if(times_window[i] != 0) { + mean_time = (mean_time + times_window[i]) / 2; + } } } return mean_time; @@ -169,39 +162,26 @@ static void update_awake_time() { #if UPDATE_WITH_MEAN - uint64_t mean_time = get_mean_time(); + uint16_t mean_time = get_mean_time(); LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)mean_time); lwm2m_q_object_set_awake_time(mean_time + (mean_time >> 1)); /* 50% margin */ return; #else - uint64_t max_time = get_maximum_time(); + uint16_t max_time = get_maximum_time(); LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)max_time); lwm2m_q_object_set_awake_time(max_time + (max_time >> 1)); /* 50% margin */ return; #endif } /*---------------------------------------------------------------------------*/ -static void -remove_time_object(time_object_t *time_object) -{ - memb_free(×_memb, time_object); - list_remove(time_object_list, time_object); -} -/*---------------------------------------------------------------------------*/ void -lwm2m_q_object_add_time_object(uint64_t time) +lwm2m_q_object_add_time_to_window(uint16_t time) { - time_object_t *time_object; - time_object = memb_alloc(×_memb); - if(time_object != NULL) { - time_object->time = time; - list_add(time_object_list, time_object); - } else { - remove_time_object((time_object_t *)list_head(time_object_list)); - time_object = memb_alloc(×_memb); - time_object->time = time; - list_add(time_object_list, time_object); + if(times_window_index == LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH) { + times_window_index = 0; } + times_window[times_window_index] = time; + times_window_index++; update_awake_time(); } #endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ diff --git a/os/services/lwm2m/lwm2m-qmode-object.h b/os/services/lwm2m/lwm2m-qmode-object.h index 68427a59c..61ac35ff3 100644 --- a/os/services/lwm2m/lwm2m-qmode-object.h +++ b/os/services/lwm2m/lwm2m-qmode-object.h @@ -53,7 +53,7 @@ uint16_t lwm2m_q_object_get_awake_time(); uint32_t lwm2m_q_object_get_sleep_time(); #if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION uint8_t lwm2m_q_object_get_dynamic_adaptation_flag(); -void lwm2m_q_object_add_time_object(uint64_t time); +void lwm2m_q_object_add_time_to_window(uint16_t time); #endif void lwm2m_q_object_send_notifications(); From 5f0dd15f1ed1431d3678ccacccabea11e3db21b2 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Wed, 25 Apr 2018 14:22:23 +0200 Subject: [PATCH 05/12] node killed at the end of 08-native-runs tests pgrep pattern shoud be smaller than 15 characters --- tests/08-native-runs/01-test-data-structures.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/08-native-runs/01-test-data-structures.sh b/tests/08-native-runs/01-test-data-structures.sh index 790235638..4885a4c8f 100755 --- a/tests/08-native-runs/01-test-data-structures.sh +++ b/tests/08-native-runs/01-test-data-structures.sh @@ -16,7 +16,7 @@ sleep 2 echo "Closing native node" sleep 2 -pgrep $CODE | xargs kill -9 +pgrep ${CODE:0:15} | xargs kill -9 if grep -q "=check-me= FAILED" $CODE.log ; then echo "==== make.log ====" ; cat make.log; From 083c37802ab7335cd8d7f87f4c2601f98953a069 Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Fri, 18 May 2018 02:38:31 +0200 Subject: [PATCH 06/12] node killed with a simple "kill -9" only sudo commands need the "pgrep ... | sudo xargs kill -9" trick --- tests/08-native-runs/01-test-data-structures.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/08-native-runs/01-test-data-structures.sh b/tests/08-native-runs/01-test-data-structures.sh index 4885a4c8f..6ea908869 100755 --- a/tests/08-native-runs/01-test-data-structures.sh +++ b/tests/08-native-runs/01-test-data-structures.sh @@ -16,7 +16,7 @@ sleep 2 echo "Closing native node" sleep 2 -pgrep ${CODE:0:15} | xargs kill -9 +kill -9 ${CPID} if grep -q "=check-me= FAILED" $CODE.log ; then echo "==== make.log ====" ; cat make.log; From 08c28f251349ea460f93d1eb2f477f4364facfbb Mon Sep 17 00:00:00 2001 From: Rehan MALAK Date: Sat, 19 May 2018 17:50:10 +0200 Subject: [PATCH 07/12] homogenize the way we kill background processes kill_bg : -takes the PID of the process to kill -differentiates the sudo case from the non-sudo case --- .../08-native-runs/01-test-data-structures.sh | 3 ++- .../04-border-router-traceroute.sh | 5 +++-- tests/17-tun-rpl-br/05-native-ping.sh | 3 ++- tests/17-tun-rpl-br/06-native-coap.sh | 3 ++- tests/17-tun-rpl-br/test-border-router.sh | 5 +++-- .../test-native-border-router.sh | 5 +++-- tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh | 5 +++-- .../18-coap-lwm2m/07-lwm2m-standalone-test.sh | 5 +++-- tests/utils.sh | 20 +++++++++++++++++++ 9 files changed, 41 insertions(+), 13 deletions(-) create mode 100755 tests/utils.sh diff --git a/tests/08-native-runs/01-test-data-structures.sh b/tests/08-native-runs/01-test-data-structures.sh index 6ea908869..2343756fe 100755 --- a/tests/08-native-runs/01-test-data-structures.sh +++ b/tests/08-native-runs/01-test-data-structures.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -16,7 +17,7 @@ sleep 2 echo "Closing native node" sleep 2 -kill -9 ${CPID} +kill_bg $CPID if grep -q "=check-me= FAILED" $CODE.log ; then echo "==== make.log ====" ; cat make.log; diff --git a/tests/17-tun-rpl-br/04-border-router-traceroute.sh b/tests/17-tun-rpl-br/04-border-router-traceroute.sh index e1e9d6cdd..fe1333aab 100755 --- a/tests/17-tun-rpl-br/04-border-router-traceroute.sh +++ b/tests/17-tun-rpl-br/04-border-router-traceroute.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -38,8 +39,8 @@ HOPS=`wc $BASENAME.scriptlog -l | cut -f 1 -d ' '` echo "Closing simulation and tunslip6" sleep 1 -kill -9 $JPID -kill -9 $MPID +kill_bg $JPID +kill_bg $MPID sleep 1 rm COOJA.testlog rm COOJA.log diff --git a/tests/17-tun-rpl-br/05-native-ping.sh b/tests/17-tun-rpl-br/05-native-ping.sh index 9e677c16e..ea416aac4 100755 --- a/tests/17-tun-rpl-br/05-native-ping.sh +++ b/tests/17-tun-rpl-br/05-native-ping.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -22,7 +23,7 @@ STATUS=${PIPESTATUS[0]} echo "Closing native node" sleep 2 -pgrep hello-world | sudo xargs kill -9 +kill_bg $CPID if [ $STATUS -eq 0 ] ; then cp $BASENAME.log $BASENAME.testlog diff --git a/tests/17-tun-rpl-br/06-native-coap.sh b/tests/17-tun-rpl-br/06-native-coap.sh index 88627ec19..216d104f4 100755 --- a/tests/17-tun-rpl-br/06-native-coap.sh +++ b/tests/17-tun-rpl-br/06-native-coap.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -38,7 +39,7 @@ done echo "Closing native node" sleep 2 -pgrep coap-example | sudo xargs kill -9 +kill_bg $CPID if [ $TESTCOUNT -eq $OKCOUNT ] ; then printf "%-32s TEST OK %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" | tee $BASENAME.testlog; diff --git a/tests/17-tun-rpl-br/test-border-router.sh b/tests/17-tun-rpl-br/test-border-router.sh index f98ca81f4..c5653d480 100755 --- a/tests/17-tun-rpl-br/test-border-router.sh +++ b/tests/17-tun-rpl-br/test-border-router.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -44,8 +45,8 @@ REPLIES=`grep -c 'icmp_seq=' $BASENAME.scriptlog` echo "Closing simulation and tunslip6" sleep 1 -kill -9 $JPID -kill -9 $MPID +kill_bg $JPID +kill_bg $MPID sleep 1 rm COOJA.testlog rm COOJA.log diff --git a/tests/17-tun-rpl-br/test-native-border-router.sh b/tests/17-tun-rpl-br/test-native-border-router.sh index 636b6b973..50ea18179 100644 --- a/tests/17-tun-rpl-br/test-native-border-router.sh +++ b/tests/17-tun-rpl-br/test-native-border-router.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -43,8 +44,8 @@ REPLIES=`grep -c 'icmp_seq=' $BASENAME.scriptlog` echo "Closing simulation and nbr" sleep 1 -kill -9 $JPID -kill -9 $MPID +kill_bg $JPID +kill_bg $MPID sleep 1 rm COOJA.testlog rm COOJA.log diff --git a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh index 9aacc2976..ec7502a21 100755 --- a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh +++ b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -32,11 +33,11 @@ done echo "Closing native node" sleep 1 -pgrep ipso | sudo xargs kill -9 +kill_bg $CPID echo "Closing leshan" sleep 1 -pgrep java | sudo xargs kill -9 +kill_bg $LESHID if grep -q 'OK' leshan.err ; then diff --git a/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh b/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh index b13352447..a1257f36e 100755 --- a/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh +++ b/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../utils.sh # Contiki directory CONTIKI=$1 @@ -33,11 +34,11 @@ done echo "Closing standalone example" sleep 1 -pgrep lwm2m-example | sudo xargs kill -9 +kill_bg $CPID echo "Closing leshan" sleep 1 -pgrep java | sudo xargs kill -9 +kill_bg $LESHID if grep -q 'OK' leshan.err ; then diff --git a/tests/utils.sh b/tests/utils.sh new file mode 100755 index 000000000..bd00ca539 --- /dev/null +++ b/tests/utils.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +function echo_run( ) +{ + echo $@ + $@ +} + +function kill_bg( ) +{ + PID=$1 + CMD=$(ps -p $PID -o cmd=) + SUDO= + TOKILL=$PID + if [[ ${CMD:0:5} == "sudo " ]] ; then + SUDO="sudo " + TOKILL=$(ps --ppid $PID -o pid=) + fi + echo_run ${SUDO}kill -9 $TOKILL +} From 2e84d2abbec1742e217182f8664c3cefed8240a2 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Fri, 18 May 2018 18:22:14 +0200 Subject: [PATCH 08/12] Separated Queue Mode implementation and Queue Mode object. Changes in the naming --- os/services/lwm2m/lwm2m-engine.c | 54 ++-- os/services/lwm2m/lwm2m-engine.h | 10 +- os/services/lwm2m/lwm2m-notification-queue.c | 10 +- os/services/lwm2m/lwm2m-notification-queue.h | 4 +- os/services/lwm2m/lwm2m-qmode-object.c | 281 ------------------ ...m-qmode-conf.h => lwm2m-queue-mode-conf.h} | 59 ++-- os/services/lwm2m/lwm2m-queue-mode-object.c | 152 ++++++++++ ...ode-object.h => lwm2m-queue-mode-object.h} | 27 +- os/services/lwm2m/lwm2m-queue-mode.c | 173 +++++++++++ os/services/lwm2m/lwm2m-queue-mode.h | 61 ++++ os/services/lwm2m/lwm2m-rd-client.c | 102 +++---- os/services/lwm2m/lwm2m-rd-client.h | 8 +- .../18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh | 2 +- .../09-lwm2m-qmode-standalone-test.sh | 2 +- .../18-coap-lwm2m/pytests/test-qmode-sleep.py | 4 +- 15 files changed, 527 insertions(+), 422 deletions(-) delete mode 100644 os/services/lwm2m/lwm2m-qmode-object.c rename os/services/lwm2m/{lwm2m-qmode-conf.h => lwm2m-queue-mode-conf.h} (53%) create mode 100644 os/services/lwm2m/lwm2m-queue-mode-object.c rename os/services/lwm2m/{lwm2m-qmode-object.h => lwm2m-queue-mode-object.h} (74%) create mode 100644 os/services/lwm2m/lwm2m-queue-mode.c create mode 100644 os/services/lwm2m/lwm2m-queue-mode.h diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index b80e6f5a4..36f6fae44 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -81,7 +81,7 @@ #endif /* LWM2M_ENGINE_CONF_USE_RD_CLIENT */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED /* Queue Mode is handled using the RD Client and the Q-Mode object */ #define USE_RD_CLIENT 1 /* Queue Mode dynamic adaptation masks */ @@ -93,10 +93,13 @@ #include "lwm2m-rd-client.h" #endif -#if LWM2M_Q_MODE_ENABLED -#include "lwm2m-qmode-object.h" +#if LWM2M_QUEUE_MODE_ENABLED +#include "lwm2m-queue-mode.h" #include "lwm2m-notification-queue.h" -#endif +#if LWM2M_QUEUE_MODE_OBJECT_ENABLED +#include "lwm2m-queue-mode-object.h" +#endif /* LWM2M_QUEUE_MODE_OBJECT_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /* MACRO for getting out resource ID from resource array ID + flags */ #define RSC_ID(x) ((uint16_t)(x & 0xffff)) @@ -143,18 +146,18 @@ static struct { /* in the future also a timeout */ } created; -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED static uint8_t waked_up_by_notification; /* For the dynamic adaptation of the awake time */ -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION static uint8_t dynamic_adaptation_params = 0x00; /* bit0: first_request, bit1: handler from notification */ static uint64_t previous_request_time; static inline void clear_first_request(); static inline uint8_t is_first_request(); static inline void clear_handler_from_notification(); static inline uint8_t get_handler_from_notification(); -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ COAP_HANDLER(lwm2m_handler, lwm2m_handler_callback); LIST(object_list); @@ -581,8 +584,8 @@ lwm2m_engine_init(void) lwm2m_rd_client_init(endpoint); #endif -#if LWM2M_Q_MODE_ENABLED - lwm2m_q_object_init(); +#if LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_OBJECT_ENABLED + lwm2m_queue_mode_object_init(); #endif } /*---------------------------------------------------------------------------*/ @@ -1404,22 +1407,23 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, context.inbuf->pos = 0; /*If Queue Mode, restart the client awake timer */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED if(lwm2m_rd_client_is_client_awake()) { lwm2m_rd_client_restart_client_awake_timer(); } -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { if(is_first_request()) { previous_request_time = coap_timer_uptime(); clear_first_request(); } else { if(coap_timer_uptime()-previous_request_time >= 0) { if(coap_timer_uptime()-previous_request_time > 0xffff) { - lwm2m_q_object_add_time_to_window(0xffff); + lwm2m_queue_mode_add_time_to_window(0xffff); + } else { + lwm2m_queue_mode_add_time_to_window(coap_timer_uptime()-previous_request_time); } - lwm2m_q_object_add_time_to_window(coap_timer_uptime()-previous_request_time); } previous_request_time = coap_timer_uptime(); } @@ -1427,8 +1431,8 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, if(get_handler_from_notification()) { clear_handler_from_notification(); } -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /* Maybe this should be part of CoAP itself - this seems not to be working with the leshan server */ @@ -1692,8 +1696,8 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, static void lwm2m_send_notification(char* path) { -#if LWM2M_Q_MODE_ENABLED && LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()) { +#if LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { lwm2m_engine_set_handler_from_notification(); } #endif @@ -1709,7 +1713,7 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, snprintf(path, 20, "%d/%d/%d", obj->object_id, obj->instance_id, resource); } -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED if(coap_has_observers(path)) { /* Client is sleeping -> add the notification to the list */ @@ -1719,7 +1723,7 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, /* if it is the first notification -> wake up and send update */ if(!waked_up_by_notification) { waked_up_by_notification = 1; - lwm2m_rd_client_fsm_execute_q_mode_update(); + lwm2m_rd_client_fsm_execute_queue_mode_update(); } /* Client is awake -> send the notification */ } else { @@ -1732,7 +1736,7 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, } /*---------------------------------------------------------------------------*/ /* Queue Mode Support and dynamic adaptation of the client awake time */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED uint8_t lwm2m_engine_is_waked_up_by_notification() { @@ -1745,7 +1749,7 @@ lwm2m_engine_clear_waked_up_by_notification() waked_up_by_notification = 0; } /*---------------------------------------------------------------------------*/ -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION void lwm2m_engine_set_first_request() { @@ -1781,7 +1785,7 @@ clear_handler_from_notification() { dynamic_adaptation_params &= ~HANDLER_FROM_NOTIFICATION_MASK; } -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-engine.h b/os/services/lwm2m/lwm2m-engine.h index 61d0353af..0f6d35734 100644 --- a/os/services/lwm2m/lwm2m-engine.h +++ b/os/services/lwm2m/lwm2m-engine.h @@ -46,7 +46,7 @@ #define LWM2M_ENGINE_H #include "lwm2m-object.h" -#include "lwm2m-qmode-conf.h" +#include "lwm2m-queue-mode-conf.h" #define LWM2M_FLOAT32_BITS 10 #define LWM2M_FLOAT32_FRAC (1L << LWM2M_FLOAT32_BITS) @@ -116,14 +116,14 @@ void lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, void lwm2m_engine_set_opaque_callback(lwm2m_context_t *ctx, lwm2m_write_opaque_callback cb); -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED uint8_t lwm2m_engine_is_waked_up_by_notification(); void lwm2m_engine_clear_waked_up_by_notification(); -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION void lwm2m_engine_set_first_request(); void lwm2m_engine_set_handler_from_notification(); -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ #endif /* LWM2M_ENGINE_H */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c index dab243ec1..e7c57a03c 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.c +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -42,9 +42,9 @@ /*---------------------------------------------------------------------------*/ #include "lwm2m-notification-queue.h" -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED -#include "lwm2m-qmode-object.h" +#include "lwm2m-queue-mode.h" #include "lwm2m-engine.h" #include "coap-engine.h" #include "lib/memb.h" @@ -223,8 +223,8 @@ lwm2m_notification_queue_send_notifications() while(iteration_path != NULL) { extend_path(iteration_path, path, sizeof(path)); -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()) { +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { lwm2m_engine_set_handler_from_notification(); } #endif @@ -235,5 +235,5 @@ lwm2m_notification_queue_send_notifications() remove_notification_path(aux); } } -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-notification-queue.h b/os/services/lwm2m/lwm2m-notification-queue.h index 3364d3a77..805002cc2 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.h +++ b/os/services/lwm2m/lwm2m-notification-queue.h @@ -44,9 +44,8 @@ #define LWM2M_NOTIFICATION_QUEUE_H #include "contiki.h" -#include "lwm2m-qmode-conf.h" +#include "lwm2m-queue-mode-conf.h" -#if LWM2M_Q_MODE_ENABLED #include typedef struct notification_path { @@ -62,6 +61,5 @@ void lwm2m_notification_queue_add_notification_path(char *path); void lwm2m_notification_queue_send_notifications(); -#endif /* LWM2M_Q_MODE_ENABLED */ #endif /* LWM2M_NOTIFICATION_QUEUE_H */ /** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-qmode-object.c b/os/services/lwm2m/lwm2m-qmode-object.c deleted file mode 100644 index be5bc7674..000000000 --- a/os/services/lwm2m/lwm2m-qmode-object.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c) 2017, RISE SICS AB. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \addtogroup lwm2m - * @{ - */ - -/** - * \file - * Implementation of the Contiki OMA LWM2M Queue Object for managing the queue mode - * \author - * Carlos Gonzalo Peces - */ - -#include "lwm2m-qmode-object.h" - -#if LWM2M_Q_MODE_ENABLED - -#include "lwm2m-object.h" -#include "lwm2m-engine.h" -#include "lwm2m-rd-client.h" -#include "lib/memb.h" -#include "lib/list.h" -#include - -/* Log configuration */ -#include "coap-log.h" -#define LOG_MODULE "lwm2m-qmode-object" -#define LOG_LEVEL LOG_LEVEL_LWM2M - -#define LWM2M_Q_OBJECT_ID 6000 -#define LWM2M_AWAKE_TIME_ID 3000 -#define LWM2M_SLEEP_TIME_ID 3001 - -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION -#define LWM2M_DYNAMIC_ADAPTATION_FLAG_ID 3002 -#define UPDATE_WITH_MEAN 0 /* 1-mean time 0-maximum time */ -#endif - -static const lwm2m_resource_id_t resources[] = -{ RW(LWM2M_AWAKE_TIME_ID), - RW(LWM2M_SLEEP_TIME_ID), -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - RW(LWM2M_DYNAMIC_ADAPTATION_FLAG_ID), -#endif -}; - -static uint16_t q_mode_awake_time = LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME; -static uint32_t q_mode_sleep_time = LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME; -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION -static uint8_t q_mode_dynamic_adaptation_flag = LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; - -/* Window to save the times and do the dynamic adaptation of the awake time*/ -uint16_t times_window[LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH] = { 0 }; -uint8_t times_window_index = 0; - -#endif -/*---------------------------------------------------------------------------*/ -uint16_t -lwm2m_q_object_get_awake_time() -{ - LOG_DBG("Client Awake Time: %d ms\n", (int)q_mode_awake_time); - return q_mode_awake_time; -} -/*---------------------------------------------------------------------------*/ -static void -lwm2m_q_object_set_awake_time(uint16_t time) -{ - q_mode_awake_time = time; -} -/*---------------------------------------------------------------------------*/ -uint32_t -lwm2m_q_object_get_sleep_time() -{ - LOG_DBG("Client Sleep Time: %d ms\n", (int)q_mode_sleep_time); - return q_mode_sleep_time; -} -/*---------------------------------------------------------------------------*/ -static void -lwm2m_q_object_set_sleep_time(uint32_t time) -{ - q_mode_sleep_time = time; -} -/*---------------------------------------------------------------------------*/ -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION -uint8_t -lwm2m_q_object_get_dynamic_adaptation_flag() -{ - LOG_DBG("Dynamic Adaptation Flag: %d ms\n", (int)q_mode_dynamic_adaptation_flag); - return q_mode_dynamic_adaptation_flag; -} -/*---------------------------------------------------------------------------*/ -static void -lwm2m_q_object_set_dynamic_adaptation_flag(uint8_t flag) -{ - q_mode_dynamic_adaptation_flag = flag; -} -/*---------------------------------------------------------------------------*/ -#if !UPDATE_WITH_MEAN -static uint16_t -get_maximum_time() -{ - uint16_t max_time = 0; - uint8_t i; - for(i = 0; i < LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { - if(times_window[i] > max_time) { - max_time = times_window[i]; - } - } - return max_time; -} -#endif -/*---------------------------------------------------------------------------*/ -#if UPDATE_WITH_MEAN -static uint16_t -get_mean_time() -{ - uint16_t mean_time = 0; - uint8_t i; - for(i = 0; i < LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { - if(mean_time == 0) { - mean_time = times_window[i]; - } else { - if(times_window[i] != 0) { - mean_time = (mean_time + times_window[i]) / 2; - } - } - } - return mean_time; -} -#endif -/*---------------------------------------------------------------------------*/ -static void -update_awake_time() -{ -#if UPDATE_WITH_MEAN - uint16_t mean_time = get_mean_time(); - LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)mean_time); - lwm2m_q_object_set_awake_time(mean_time + (mean_time >> 1)); /* 50% margin */ - return; -#else - uint16_t max_time = get_maximum_time(); - LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)max_time); - lwm2m_q_object_set_awake_time(max_time + (max_time >> 1)); /* 50% margin */ - return; -#endif -} -/*---------------------------------------------------------------------------*/ -void -lwm2m_q_object_add_time_to_window(uint16_t time) -{ - if(times_window_index == LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH) { - times_window_index = 0; - } - times_window[times_window_index] = time; - times_window_index++; - update_awake_time(); -} -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -/*---------------------------------------------------------------------------*/ -static lwm2m_status_t -lwm2m_callback(lwm2m_object_instance_t *object, lwm2m_context_t *ctx) -{ - if(ctx->operation == LWM2M_OP_READ) { - switch(ctx->resource_id) { - case LWM2M_AWAKE_TIME_ID: - lwm2m_object_write_int(ctx, (int32_t)q_mode_awake_time); - return LWM2M_STATUS_OK; - case LWM2M_SLEEP_TIME_ID: - lwm2m_object_write_int(ctx, (int32_t)q_mode_sleep_time); - return LWM2M_STATUS_OK; -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: - lwm2m_object_write_int(ctx, (int32_t)q_mode_dynamic_adaptation_flag); - return LWM2M_STATUS_OK; -#endif - } - } else if(ctx->operation == LWM2M_OP_WRITE) { - switch(ctx->resource_id) { - int32_t value_read; - size_t len; - - case LWM2M_AWAKE_TIME_ID: - - len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, - &value_read); - LOG_DBG("Client Awake Time write request value: %d\n", (int)value_read); - if(len == 0) { - LOG_WARN("FAIL: could not write awake time\n"); - return LWM2M_STATUS_WRITE_ERROR; - } else { - lwm2m_q_object_set_awake_time(value_read); - return LWM2M_STATUS_OK; - } - - case LWM2M_SLEEP_TIME_ID: - len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, - &value_read); - LOG_DBG("Client Sleep Time write request value: %d\n", (int)value_read); - if(len == 0) { - LOG_WARN("FAIL: could not write sleep time\n"); - return LWM2M_STATUS_WRITE_ERROR; - } else { - lwm2m_q_object_set_sleep_time(value_read); - return LWM2M_STATUS_OK; - } -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: - len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, - &value_read); - LOG_DBG("Dynamic Adaptation Flag request value: %d\n", (int)value_read); - if(len == 0) { - LOG_WARN("FAIL: could not write dynamic flag\n"); - return LWM2M_STATUS_WRITE_ERROR; - } else { - lwm2m_q_object_set_dynamic_adaptation_flag(value_read); - return LWM2M_STATUS_OK; - } -#endif - } - } - - return LWM2M_STATUS_OPERATION_NOT_ALLOWED; -} -/*---------------------------------------------------------------------------*/ -static lwm2m_object_instance_t queue_object = { - .object_id = LWM2M_Q_OBJECT_ID, - .instance_id = 0, - .resource_ids = resources, - .resource_count = sizeof(resources) / sizeof(lwm2m_resource_id_t), - .resource_dim_callback = NULL, - .callback = lwm2m_callback, -}; -/*---------------------------------------------------------------------------*/ -void -lwm2m_q_object_init(void) -{ - lwm2m_engine_add_object(&queue_object); -} -/*---------------------------------------------------------------------------*/ -void -lwm2m_q_object_send_notifications() -{ - lwm2m_notify_object_observers(&queue_object, LWM2M_AWAKE_TIME_ID); - lwm2m_notify_object_observers(&queue_object, LWM2M_SLEEP_TIME_ID); -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - lwm2m_notify_object_observers(&queue_object, LWM2M_DYNAMIC_ADAPTATION_FLAG_ID); -#endif -} -/*---------------------------------------------------------------------------*/ -#endif /* LWM2M_Q_MODE_ENABLED */ -/** @} */ - diff --git a/os/services/lwm2m/lwm2m-qmode-conf.h b/os/services/lwm2m/lwm2m-queue-mode-conf.h similarity index 53% rename from os/services/lwm2m/lwm2m-qmode-conf.h rename to os/services/lwm2m/lwm2m-queue-mode-conf.h index 1220d0584..3432c112a 100644 --- a/os/services/lwm2m/lwm2m-qmode-conf.h +++ b/os/services/lwm2m/lwm2m-queue-mode-conf.h @@ -40,46 +40,57 @@ * Carlos Gonzalo Peces */ -#ifndef LWM2M_QMODE_CONF_H -#define LWM2M_QMODE_CONF_H +#ifndef LWM2M_QUEUE_MODE_CONF_H +#define LWM2M_QUEUE_MODE_CONF_H + +#include "contiki.h" /* Enable the Queue Mode */ -#ifdef LWM2M_Q_MODE_CONF_ENABLED -#define LWM2M_Q_MODE_ENABLED LWM2M_Q_MODE_CONF_ENABLED +#ifdef LWM2M_QUEUE_MODE_CONF_ENABLED +#define LWM2M_QUEUE_MODE_ENABLED LWM2M_QUEUE_MODE_CONF_ENABLED #else -#define LWM2M_Q_MODE_ENABLED 0 -#endif /* LWM2M_Q_MODE_CONF_ENABLED */ +#define LWM2M_QUEUE_MODE_ENABLED 0 +#endif /* LWM2M_QUEUE_MODE_CONF_ENABLED */ /* Default Sleeping Time */ -#ifdef LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME -#define LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME +#ifdef LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME +#define LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME #else -#define LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME 10000 /* msec */ -#endif /* LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEPING_TIME */ +#define LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME 10000 /* msec */ +#endif /* LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEPING_TIME */ /* Default Awake Time */ -#ifdef LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME -#define LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME +#ifdef LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME +#define LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME #else -#define LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME 5000 /* msec */ -#endif /* LWM2M_Q_MODE_DEFAULT_CLIENT_AWAKE_TIME */ +#define LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME 5000 /* msec */ +#endif /* LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME */ /* Include the possibility to do the dynamic adaptation of the client awake time */ -#ifdef LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION -#define LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION +#ifdef LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION +#define LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION #else -#define LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION 0 /* not included */ -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#define LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION 0 /* not included */ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ /* Default value for the dynamic adaptation flag */ -#ifdef LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG -#define LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG +#ifdef LWM2M_QUEUE_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG +#define LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG LWM2M_QUEUE_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG #else -#define LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 /* disabled */ -#endif /* LWM2M_Q_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG */ +#define LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 /* disabled */ +#endif /* LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG */ /* Length of the list of times for the dynamic adaptation */ -#define LWM2M_Q_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH 10 +#define LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH 10 -#endif /* LWM2M_QMODE_CONF_H */ +/* Enable and disable the Queue Mode Object */ +#ifdef LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED +#define LWM2M_QUEUE_MODE_OBJECT_ENABLED LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED +#else +#define LWM2M_QUEUE_MODE_OBJECT_ENABLED 0 /* not included */ +#endif /* LWM2M_QUEUE_MODE_OBJECT_ENABLED */ + + + +#endif /* LWM2M_QUEUE_MODE_CONF_H */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-queue-mode-object.c b/os/services/lwm2m/lwm2m-queue-mode-object.c new file mode 100644 index 000000000..a3c000d69 --- /dev/null +++ b/os/services/lwm2m/lwm2m-queue-mode-object.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2017, RISE SICS AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Implementation of the Contiki OMA LWM2M Queue Mode object + to manage the parameters from the server side + * \author + * Carlos Gonzalo Peces + */ + +#include "lwm2m-object.h" +#include "lwm2m-queue-mode.h" + +/* Log configuration */ +#include "coap-log.h" +#define LOG_MODULE "lwm2m-qmode-object" +#define LOG_LEVEL LOG_LEVEL_LWM2M + +#if LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_OBJECT_ENABLED + +#define LWM2M_QUEUE_MODE_OBJECT_ID 30000 +#define LWM2M_AWAKE_TIME_ID 30000 +#define LWM2M_SLEEP_TIME_ID 30001 + +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +#define LWM2M_DYNAMIC_ADAPTATION_FLAG_ID 30002 +#define UPDATE_WITH_MEAN 0 /* 1-mean time 0-maximum time */ +#endif + +static const lwm2m_resource_id_t resources[] = +{ RW(LWM2M_AWAKE_TIME_ID), + RW(LWM2M_SLEEP_TIME_ID), +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + RW(LWM2M_DYNAMIC_ADAPTATION_FLAG_ID), +#endif +}; + +/*---------------------------------------------------------------------------*/ +static lwm2m_status_t +lwm2m_callback(lwm2m_object_instance_t *object, lwm2m_context_t *ctx) +{ + if(ctx->operation == LWM2M_OP_READ) { + switch(ctx->resource_id) { + case LWM2M_AWAKE_TIME_ID: + lwm2m_object_write_int(ctx, (int32_t)lwm2m_queue_mode_get_awake_time()); + return LWM2M_STATUS_OK; + case LWM2M_SLEEP_TIME_ID: + lwm2m_object_write_int(ctx, (int32_t)lwm2m_queue_mode_get_sleep_time()); + return LWM2M_STATUS_OK; +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: + lwm2m_object_write_int(ctx, (int32_t)lwm2m_queue_mode_get_dynamic_adaptation_flag()); + return LWM2M_STATUS_OK; +#endif + } + } else if(ctx->operation == LWM2M_OP_WRITE) { + switch(ctx->resource_id) { + int32_t value_read; + size_t len; + + case LWM2M_AWAKE_TIME_ID: + + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Client Awake Time write request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write awake time\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_queue_mode_set_awake_time(value_read); + return LWM2M_STATUS_OK; + } + + case LWM2M_SLEEP_TIME_ID: + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Client Sleep Time write request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write sleep time\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_queue_mode_set_sleep_time(value_read); + return LWM2M_STATUS_OK; + } +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + case LWM2M_DYNAMIC_ADAPTATION_FLAG_ID: + len = lwm2m_object_read_int(ctx, ctx->inbuf->buffer, ctx->inbuf->size, + &value_read); + LOG_DBG("Dynamic Adaptation Flag request value: %d\n", (int)value_read); + if(len == 0) { + LOG_WARN("FAIL: could not write dynamic flag\n"); + return LWM2M_STATUS_WRITE_ERROR; + } else { + lwm2m_queue_mode_set_dynamic_adaptation_flag(value_read); + return LWM2M_STATUS_OK; + } +#endif + } + } + + return LWM2M_STATUS_OPERATION_NOT_ALLOWED; +} +/*---------------------------------------------------------------------------*/ +static lwm2m_object_instance_t queue_object = { + .object_id = LWM2M_QUEUE_MODE_OBJECT_ID, + .instance_id = 0, + .resource_ids = resources, + .resource_count = sizeof(resources) / sizeof(lwm2m_resource_id_t), + .resource_dim_callback = NULL, + .callback = lwm2m_callback, +}; +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_object_init(void) +{ + lwm2m_engine_add_object(&queue_object); +} +#endif /* LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_OBJECT_ENABLED */ +/** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-qmode-object.h b/os/services/lwm2m/lwm2m-queue-mode-object.h similarity index 74% rename from os/services/lwm2m/lwm2m-qmode-object.h rename to os/services/lwm2m/lwm2m-queue-mode-object.h index 61ac35ff3..017b797fc 100644 --- a/os/services/lwm2m/lwm2m-qmode-object.h +++ b/os/services/lwm2m/lwm2m-queue-mode-object.h @@ -35,31 +35,18 @@ /** * \file - * Header file for the Contiki OMA LWM2M Queue Object for managing the queue mode + * Header file for the Contiki OMA LWM2M Queue Mode object + to manage the parameters from the server side * \author * Carlos Gonzalo Peces */ -#ifndef LWM2M_Q_OBJECT_H_ -#define LWM2M_Q_OBJECT_H_ +#ifndef LWM2M_QUEUE_MODE_OBJECT_H_ +#define LWM2M_QUEUE_MODE_OBJECT_H_ -#include "contiki.h" -#include "lwm2m-qmode-conf.h" +#include "lwm2m-queue-mode-conf.h" -#if LWM2M_Q_MODE_ENABLED -#include +void lwm2m_queue_mode_object_init(void); -uint16_t lwm2m_q_object_get_awake_time(); -uint32_t lwm2m_q_object_get_sleep_time(); -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION -uint8_t lwm2m_q_object_get_dynamic_adaptation_flag(); -void lwm2m_q_object_add_time_to_window(uint16_t time); -#endif - -void lwm2m_q_object_send_notifications(); - -void lwm2m_q_object_init(void); - -#endif /* LWM2M_Q_MODE_ENABLED */ #endif /* LWM2M_Q_OBJECT_H_ */ -/** @} */ +/** @} */ \ No newline at end of file diff --git a/os/services/lwm2m/lwm2m-queue-mode.c b/os/services/lwm2m/lwm2m-queue-mode.c new file mode 100644 index 000000000..30c8dd6cc --- /dev/null +++ b/os/services/lwm2m/lwm2m-queue-mode.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2017, RISE SICS AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup lwm2m + * @{ + */ + +/** + * \file + * Implementation of the Contiki OMA LWM2M Queue Mode for managing the parameters + * \author + * Carlos Gonzalo Peces + */ + +#include "lwm2m-queue-mode.h" + +#if LWM2M_QUEUE_MODE_ENABLED + +#include "lwm2m-engine.h" +#include "lwm2m-rd-client.h" +#include "lib/memb.h" +#include "lib/list.h" +#include + +/* Log configuration */ +#include "coap-log.h" +#define LOG_MODULE "lwm2m-queue-mode" +#define LOG_LEVEL LOG_LEVEL_LWM2M + + +static uint16_t queue_mode_awake_time = LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME; +static uint32_t queue_mode_sleep_time = LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME; +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +static uint8_t queue_mode_dynamic_adaptation_flag = LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; + +/* Window to save the times and do the dynamic adaptation of the awake time*/ +uint16_t times_window[LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH] = { 0 }; +uint8_t times_window_index = 0; + +#endif +/*---------------------------------------------------------------------------*/ +uint16_t +lwm2m_queue_mode_get_awake_time() +{ + LOG_DBG("Client Awake Time: %d ms\n", (int)queue_mode_awake_time); + return queue_mode_awake_time; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_awake_time(uint16_t time) +{ + queue_mode_awake_time = time; +} +/*---------------------------------------------------------------------------*/ +uint32_t +lwm2m_queue_mode_get_sleep_time() +{ + LOG_DBG("Client Sleep Time: %d ms\n", (int)queue_mode_sleep_time); + return queue_mode_sleep_time; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_sleep_time(uint32_t time) +{ + queue_mode_sleep_time = time; +} +/*---------------------------------------------------------------------------*/ +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +uint8_t +lwm2m_queue_mode_get_dynamic_adaptation_flag() +{ + LOG_DBG("Dynamic Adaptation Flag: %d ms\n", (int)queue_mode_dynamic_adaptation_flag); + return queue_mode_dynamic_adaptation_flag; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_dynamic_adaptation_flag(uint8_t flag) +{ + queue_mode_dynamic_adaptation_flag = flag; +} +/*---------------------------------------------------------------------------*/ +#if !UPDATE_WITH_MEAN +static uint16_t +get_maximum_time() +{ + uint16_t max_time = 0; + uint8_t i; + for(i = 0; i < LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { + if(times_window[i] > max_time) { + max_time = times_window[i]; + } + } + return max_time; +} +#endif +/*---------------------------------------------------------------------------*/ +#if UPDATE_WITH_MEAN +static uint16_t +get_mean_time() +{ + uint16_t mean_time = 0; + uint8_t i; + for(i = 0; i < LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH; i++) { + if(mean_time == 0) { + mean_time = times_window[i]; + } else { + if(times_window[i] != 0) { + mean_time = (mean_time + times_window[i]) / 2; + } + } + } + return mean_time; +} +#endif +/*---------------------------------------------------------------------------*/ +static void +update_awake_time() +{ +#if UPDATE_WITH_MEAN + uint16_t mean_time = get_mean_time(); + LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)mean_time); + lwm2m_queue_mode_set_awake_time(mean_time + (mean_time >> 1)); /* 50% margin */ + return; +#else + uint16_t max_time = get_maximum_time(); + LOG_DBG("Dynamic Adaptation: updated awake time: %d ms\n", (int)max_time); + lwm2m_queue_mode_set_awake_time(max_time + (max_time >> 1)); /* 50% margin */ + return; +#endif +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_add_time_to_window(uint16_t time) +{ + if(times_window_index == LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH) { + times_window_index = 0; + } + times_window[times_window_index] = time; + times_window_index++; + update_awake_time(); +} +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ +/** @} */ + diff --git a/os/services/lwm2m/lwm2m-queue-mode.h b/os/services/lwm2m/lwm2m-queue-mode.h new file mode 100644 index 000000000..cc3bd3290 --- /dev/null +++ b/os/services/lwm2m/lwm2m-queue-mode.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017, RISE SICS AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup oma-lwm2m + * @{ + */ + +/** + * \file + * Header file for the Contiki OMA LWM2M Queue Mode implementation + to manage the parameters + * \author + * Carlos Gonzalo Peces + */ + +#ifndef LWM2M_QUEUE_MODE_H_ +#define LWM2M_QUEUE_MODE_H_ + +#include "lwm2m-queue-mode-conf.h" +#include + +uint16_t lwm2m_queue_mode_get_awake_time(); +void lwm2m_queue_mode_set_awake_time(uint16_t time); +uint32_t lwm2m_queue_mode_get_sleep_time(); +void lwm2m_queue_mode_set_sleep_time(uint32_t time); +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +uint8_t lwm2m_queue_mode_get_dynamic_adaptation_flag(); +void lwm2m_queue_mode_set_dynamic_adaptation_flag(uint8_t flag); +void lwm2m_queue_mode_add_time_to_window(uint16_t time); +#endif + +#endif /* LWM2M_QUEUE_MODE_H_ */ +/** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index cf7c5deb3..da8d276d0 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -62,10 +62,10 @@ #include "rpl.h" #endif /* UIP_CONF_IPV6_RPL */ -#if LWM2M_Q_MODE_ENABLED -#include "lwm2m-qmode-object.h" +#if LWM2M_QUEUE_MODE_ENABLED +#include "lwm2m-queue-mode.h" #include "lwm2m-notification-queue.h" -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /* Log configuration */ #include "coap-log.h" @@ -105,9 +105,9 @@ static coap_message_t request[1]; /* This way the message can be treated as #define DEREGISTER_SENT 11 #define DEREGISTER_FAILED 12 #define DEREGISTERED 13 -#if LWM2M_Q_MODE_ENABLED -#define Q_MODE_AWAKE 14 -#define Q_MODE_SEND_UPDATE 15 +#if LWM2M_QUEUE_MODE_ENABLED +#define QUEUE_MODE_AWAKE 14 +#define QUEUE_MODE_SEND_UPDATE 15 #endif #define FLAG_RD_DATA_DIRTY 0x01 @@ -130,16 +130,16 @@ static void (*rd_callback)(coap_request_state_t *state); static coap_timer_t block1_timer; -#if LWM2M_Q_MODE_ENABLED -static coap_timer_t q_mode_client_awake_timer; /* Timer to control the client's +#if LWM2M_QUEUE_MODE_ENABLED +static coap_timer_t queue_mode_client_awake_timer; /* Timer to control the client's * awake time */ -static uint8_t q_mode_client_awake; /* 1 - client is awake, +static uint8_t queue_mode_client_awake; /* 1 - client is awake, * 0 - client is sleeping */ -static uint16_t q_mode_client_awake_time; /* The time to be awake */ +static uint16_t queue_mode_client_awake_time; /* The time to be awake */ /* Callback for the client awake timer */ -static void q_mode_awake_timer_callback(coap_timer_t *timer); +static void queue_mode_awake_timer_callback(coap_timer_t *timer); #endif static void check_periodic_observations(); @@ -445,13 +445,13 @@ registration_callback(coap_request_state_t *state) state->response->location_path_len); session_info.assigned_ep[state->response->location_path_len] = 0; /* if we decide to not pass the lt-argument on registration, we should force an initial "update" to register lifetime with server */ -#if LWM2M_Q_MODE_ENABLED -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()) { +#if LWM2M_QUEUE_MODE_ENABLED +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { lwm2m_engine_set_first_request(); } #endif - lwm2m_rd_client_fsm_execute_q_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ + lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ #else rd_state = REGISTRATION_DONE; #endif @@ -499,23 +499,23 @@ update_callback(coap_request_state_t *state) LOG_DBG_("Done!\n"); /* remember the last reg time */ last_update = coap_timer_uptime(); -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED /* If it has been waked up by a notification, send the stored notifications in queue */ if(lwm2m_engine_is_waked_up_by_notification()) { lwm2m_engine_clear_waked_up_by_notification(); lwm2m_notification_queue_send_notifications(); } -#if LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_q_object_get_dynamic_adaptation_flag()) { +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { lwm2m_engine_set_first_request(); } -#endif /* LWM2M_Q_MODE_INCLUDE_DYNAMIC_ADAPTATION */ - lwm2m_rd_client_fsm_execute_q_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ + lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ #else rd_state = REGISTRATION_DONE; rd_flags &= ~FLAG_RD_DATA_UPDATE_TRIGGERED; -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ } else { /* Possible error response codes are 4.00 Bad request & 4.04 Not Found */ LOG_DBG_("Failed with code %d. Retrying registration\n", @@ -562,7 +562,7 @@ periodic_process(coap_timer_t *timer) uint64_t now; /* reschedule the CoAP timer */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED /* In Queue Mode, the machine is not executed periodically, but with the awake/sleeping times */ if(!((rd_state & 0xF) == 0xE)) { coap_timer_reset(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); @@ -739,27 +739,27 @@ periodic_process(coap_timer_t *timer) rd_state = UPDATE_SENT; } break; -#if LWM2M_Q_MODE_ENABLED - case Q_MODE_AWAKE: +#if LWM2M_QUEUE_MODE_ENABLED + case QUEUE_MODE_AWAKE: LOG_DBG("Queue Mode: Client is AWAKE at %lu\n", (unsigned long)coap_timer_uptime()); - q_mode_client_awake = 1; - q_mode_client_awake_time = lwm2m_q_object_get_awake_time(); - coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); + queue_mode_client_awake = 1; + queue_mode_client_awake_time = lwm2m_queue_mode_get_awake_time(); + coap_timer_set(&queue_mode_client_awake_timer, queue_mode_client_awake_time); break; - case Q_MODE_SEND_UPDATE: + case QUEUE_MODE_SEND_UPDATE: /* Define this macro to make the necessary actions for waking up, * depending on the platform */ -#ifdef LWM2M_Q_MODE_WAKE_UP - LWM2M_Q_MODE_WAKE_UP(); -#endif /* LWM2M_Q_MODE_WAKE_UP */ +#ifdef LWM2M_QUEUE_MODE_WAKE_UP + LWM2M_QUEUE_MODE_WAKE_UP(); +#endif /* LWM2M_QUEUE_MODE_WAKE_UP */ prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED); coap_send_request(&rd_request_state, &session_info.server_ep, request, update_callback); last_rd_progress = coap_timer_uptime(); rd_state = UPDATE_SENT; break; -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ case UPDATE_SENT: /* just wait until the callback kicks us to the next state... */ @@ -793,12 +793,12 @@ lwm2m_rd_client_init(const char *ep) { session_info.ep = ep; /* default binding U = UDP, UQ = UDP Q-mode*/ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED session_info.binding = "UQ"; /* Enough margin to ensure that the client is not unregistered (we * do not know the time it can stay awake) */ - session_info.lifetime = (LWM2M_Q_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; + session_info.lifetime = (LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2; #else session_info.binding = "U"; if(session_info.lifetime == 0) { @@ -811,8 +811,8 @@ lwm2m_rd_client_init(const char *ep) /* call the RD client periodically */ coap_timer_set_callback(&rd_timer, periodic_process); coap_timer_set(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); -#if LWM2M_Q_MODE_ENABLED - coap_timer_set_callback(&q_mode_client_awake_timer, q_mode_awake_timer_callback); +#if LWM2M_QUEUE_MODE_ENABLED + coap_timer_set_callback(&queue_mode_client_awake_timer, queue_mode_awake_timer_callback); #endif } /*---------------------------------------------------------------------------*/ @@ -825,51 +825,51 @@ check_periodic_observations(void) /* *Queue Mode Support */ -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED /*---------------------------------------------------------------------------*/ void lwm2m_rd_client_restart_client_awake_timer(void) { - coap_timer_set(&q_mode_client_awake_timer, q_mode_client_awake_time); + coap_timer_set(&queue_mode_client_awake_timer, queue_mode_client_awake_time); } /*---------------------------------------------------------------------------*/ uint8_t lwm2m_rd_client_is_client_awake(void) { - return q_mode_client_awake; + return queue_mode_client_awake; } /*---------------------------------------------------------------------------*/ static void -q_mode_awake_timer_callback(coap_timer_t *timer) +queue_mode_awake_timer_callback(coap_timer_t *timer) { /* Timer has expired, no requests has been received, client can go to sleep */ LOG_DBG("Queue Mode: Client is SLEEPING at %lu\n", (unsigned long)coap_timer_uptime()); - q_mode_client_awake = 0; + queue_mode_client_awake = 0; /* Define this macro to enter sleep mode depending on the platform */ -#ifdef LWM2M_Q_MODE_SLEEP_MS - LWM2M_Q_MODE_SLEEP_MS(lwm2m_q_object_get_sleep_time()); -#endif /* LWM2M_Q_MODE_SLEEP_MS */ - rd_state = Q_MODE_SEND_UPDATE; - coap_timer_set(&rd_timer, lwm2m_q_object_get_sleep_time()); +#ifdef LWM2M_QUEUE_MODE_SLEEP_MS + LWM2M_QUEUE_MODE_SLEEP_MS(lwm2m_queue_mode_get_sleep_time()); +#endif /* LWM2M_QUEUE_MODE_SLEEP_MS */ + rd_state = QUEUE_MODE_SEND_UPDATE; + coap_timer_set(&rd_timer, lwm2m_queue_mode_get_sleep_time()); } /*---------------------------------------------------------------------------*/ void -lwm2m_rd_client_fsm_execute_q_mode_awake() +lwm2m_rd_client_fsm_execute_queue_mode_awake() { coap_timer_stop(&rd_timer); - rd_state = Q_MODE_AWAKE; + rd_state = QUEUE_MODE_AWAKE; periodic_process(&rd_timer); } /*---------------------------------------------------------------------------*/ void -lwm2m_rd_client_fsm_execute_q_mode_update() +lwm2m_rd_client_fsm_execute_queue_mode_update() { coap_timer_stop(&rd_timer); - rd_state = Q_MODE_SEND_UPDATE; + rd_state = QUEUE_MODE_SEND_UPDATE; periodic_process(&rd_timer); } /*---------------------------------------------------------------------------*/ -#endif /* LWM2M_Q_MODE_ENABLED */ +#endif /* LWM2M_QUEUE_MODE_ENABLED */ /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.h b/os/services/lwm2m/lwm2m-rd-client.h index 85946235d..cfc5c549d 100644 --- a/os/services/lwm2m/lwm2m-rd-client.h +++ b/os/services/lwm2m/lwm2m-rd-client.h @@ -53,7 +53,7 @@ #define LWM2M_RD_CLIENT_DISCONNECTED 5 #include "lwm2m-object.h" -#include "lwm2m-qmode-conf.h" +#include "lwm2m-queue-mode-conf.h" struct lwm2m_session_info; typedef void (*session_callback_t)(struct lwm2m_session_info *session, int status); @@ -77,11 +77,11 @@ void lwm2m_rd_client_init(const char *ep); void lwm2m_rd_client_set_session_callback(session_callback_t cb); -#if LWM2M_Q_MODE_ENABLED +#if LWM2M_QUEUE_MODE_ENABLED uint8_t lwm2m_rd_client_is_client_awake(void); void lwm2m_rd_client_restart_client_awake_timer(void); -void lwm2m_rd_client_fsm_execute_q_mode_awake(); -void lwm2m_rd_client_fsm_execute_q_mode_update(); +void lwm2m_rd_client_fsm_execute_queue_mode_awake(); +void lwm2m_rd_client_fsm_execute_queue_mode_update(); #endif #ifndef LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN diff --git a/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh index 142fb253d..2b3d52c3e 100755 --- a/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh +++ b/tests/18-coap-lwm2m/08-lwm2m-qmode-ipso-test.sh @@ -10,7 +10,7 @@ IPADDR=fd00::302:304:506:708 # Starting Contiki-NG native node echo "Starting native node - lwm2m/ipso objects with Q-Mode" make -C $CONTIKI/examples/lwm2m-ipso-objects clean >/dev/null -make -C $CONTIKI/examples/lwm2m-ipso-objects DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1 > make.log 2> make.err +make -C $CONTIKI/examples/lwm2m-ipso-objects DEFINES=LWM2M_QUEUE_MODE_CONF_ENABLED=1,LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1,LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED=1 > make.log 2> make.err sudo $CONTIKI/examples/lwm2m-ipso-objects/example-ipso-objects.native > node.log 2> node.err & CPID=$! sleep 10 diff --git a/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh index f22b20bef..57f0e3f71 100755 --- a/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh +++ b/tests/18-coap-lwm2m/09-lwm2m-qmode-standalone-test.sh @@ -8,7 +8,7 @@ BASENAME=09-lwm2m-qmode-standalone-test # Building standalone posix example echo "Compiling standalone posix example" make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m clean >/dev/null -make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m DEFINES=LWM2M_Q_MODE_CONF_ENABLED=1,LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1 >make.log 2>make.err +make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m DEFINES=LWM2M_QUEUE_MODE_CONF_ENABLED=1,LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION=1,LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED=1 >make.log 2>make.err echo "Downloading leshan with Q-Mode support" wget -nc https://carlosgp143.github.io/resources/leshan-server-demo-qmode-support1.0.0-SNAPSHOT-jar-with-dependencies.jar diff --git a/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py b/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py index da9a2ffe8..66dc061ff 100644 --- a/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py +++ b/tests/18-coap-lwm2m/pytests/test-qmode-sleep.py @@ -5,10 +5,10 @@ class TestQueueModeSleep(unittest.TestCase): global client def test_read_awake_time(self): - self.assertIsNone(client.read("6000/0/3000")) + self.assertIsNone(client.read("30000/0/30000")) def test_read_sleep_time(self): - self.assertIsNone(client.read("6000/0/3001")) + self.assertIsNone(client.read("30000/0/30001")) print "----------------------------------------" From eba756e340e4f64fd12e98d428dc06b5e0c8acac Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Mon, 21 May 2018 16:13:29 +0200 Subject: [PATCH 09/12] Code of notification queue simplified --- os/services/lwm2m/lwm2m-engine.c | 2 +- os/services/lwm2m/lwm2m-notification-queue.c | 130 ++++--------------- os/services/lwm2m/lwm2m-notification-queue.h | 6 +- 3 files changed, 29 insertions(+), 109 deletions(-) diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 36f6fae44..015e1cea9 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -1718,7 +1718,7 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, if(coap_has_observers(path)) { /* Client is sleeping -> add the notification to the list */ if(!lwm2m_rd_client_is_client_awake()) { - lwm2m_notification_queue_add_notification_path(path); + lwm2m_notification_queue_add_notification_path(obj->object_id, obj->instance_id, resource); /* if it is the first notification -> wake up and send update */ if(!waked_up_by_notification) { diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c index e7c57a03c..4bbb860c1 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.c +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -35,7 +35,8 @@ /** * \file - * Implementation of functions to manage the queue of notifications + * Implementation of functions to manage the queue to store notifications + when waiting for the response to the update message in Queue Mode. * \author * Carlos Gonzalo Peces */ @@ -62,12 +63,12 @@ #ifdef LWM2M_NOTIFICATION_QUEUE_CONF_LENGTH #define LWM2M_NOTIFICATION_QUEUE_LENGTH LWM2M_NOTIFICATION_QUEUE_CONF_LENGTH #else -#define LWM2M_NOTIFICATION_QUEUE_LENGTH 3 +#define LWM2M_NOTIFICATION_QUEUE_LENGTH COAP_MAX_OBSERVERS #endif /*---------------------------------------------------------------------------*/ /* Queue to store the notifications in the period when the client has woken up, sent the update and it's waiting for the server response*/ -MEMB(notification_memb, notification_path_t, LWM2M_NOTIFICATION_QUEUE_LENGTH + 1); /* Length + 1 to allocate the new path to add */ +MEMB(notification_memb, notification_path_t, LWM2M_NOTIFICATION_QUEUE_LENGTH); /* Length + 1 to allocate the new path to add */ LIST(notification_paths_queue); /*---------------------------------------------------------------------------*/ void @@ -77,22 +78,6 @@ lwm2m_notification_queue_init(void) } /*---------------------------------------------------------------------------*/ static void -reduce_path(notification_path_t *path_object, char *path) -{ - char *cut = strtok(path, "/"); - int i; - for(i = 0; i < 3; i++) { - if(cut != NULL) { - path_object->reduced_path[i] = (uint16_t)atoi(cut); - cut = strtok(NULL, "/"); - } else { - break; - } - } - path_object->level = i; -} -/*---------------------------------------------------------------------------*/ -static void extend_path(notification_path_t *path_object, char *path, int path_size) { switch(path_object->level) { @@ -108,34 +93,18 @@ extend_path(notification_path_t *path_object, char *path, int path_size) } } /*---------------------------------------------------------------------------*/ -static void -add_notification_path_object_ordered(notification_path_t *path) +static int +is_notification_path_present(uint16_t object_id, uint16_t instance_id, uint16_t resource_id) { notification_path_t *iteration_path = (notification_path_t *)list_head(notification_paths_queue); - if(list_length(notification_paths_queue) == 0) { - list_add(notification_paths_queue, path); - } else if(path->level < iteration_path->level) { - list_push(notification_paths_queue, path); - } else if(memcmp((path->reduced_path), (iteration_path->reduced_path), (path->level) * sizeof(uint16_t)) <= 0) { - list_push(notification_paths_queue, path); - } else { - notification_path_t *previous_path = iteration_path; - while(iteration_path != NULL) { - if(path->level < iteration_path->level) { - path->next = iteration_path; - previous_path->next = path; - return; - } - if(memcmp((path->reduced_path), (iteration_path->reduced_path), (path->level) * sizeof(uint16_t)) <= 0) { - path->next = iteration_path; - previous_path->next = path; - return; - } - previous_path = iteration_path; - iteration_path = iteration_path->next; + while(iteration_path != NULL) { + if(iteration_path->reduced_path[0] == object_id && iteration_path->reduced_path[1] == instance_id + && iteration_path->reduced_path[2] == resource_id) { + return 1; } - list_add(notification_paths_queue, path); + iteration_path = iteration_path->next; } + return 0; } /*---------------------------------------------------------------------------*/ static void @@ -145,73 +114,24 @@ remove_notification_path(notification_path_t *path) memb_free(¬ification_memb, path); } /*---------------------------------------------------------------------------*/ -static void -notification_queue_remove_policy(uint16_t *reduced_path, uint8_t level) -{ - uint8_t path_removed_flag = 0; - - notification_path_t *path_object = NULL; - notification_path_t *iteration_path = NULL; - notification_path_t *previous = NULL; - notification_path_t *next_next = NULL; - notification_path_t *path_to_remove = NULL; - - for(iteration_path = (notification_path_t *)list_head(notification_paths_queue); iteration_path != NULL; - iteration_path = iteration_path->next) { - /* 1. check if there is one event of the same path -> remove it and add the new one */ - if((level == iteration_path->level) && memcmp(iteration_path->reduced_path, reduced_path, level * sizeof(uint16_t)) == 0) { - remove_notification_path(iteration_path); - path_object = memb_alloc(¬ification_memb); - memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); - path_object->level = level; - add_notification_path_object_ordered(path_object); - return; - } - /* 2. If there is no event of the same type, look for repeated events of the same resource and remove the oldest one */ - if(iteration_path->next != NULL && (iteration_path->level == iteration_path->next->level) - && (memcmp(iteration_path->reduced_path, (iteration_path->next)->reduced_path, iteration_path->level * sizeof(uint16_t)) == 0)) { - path_removed_flag = 1; - next_next = iteration_path->next->next; - path_to_remove = iteration_path->next; - previous = iteration_path; - } - } - /* 3. If there are no events for the same path, we remove a the oldest repeated event of another resource */ - if(path_removed_flag) { - memb_free(¬ification_memb, path_to_remove); - previous->next = next_next; - path_object = memb_alloc(¬ification_memb); - memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); - path_object->level = level; - add_notification_path_object_ordered(path_object); - } else { - /* 4. If all the events are from different resources, remove the last one */ - list_chop(notification_paths_queue); - path_object = memb_alloc(¬ification_memb); - memcpy(path_object->reduced_path, reduced_path, level * sizeof(uint16_t)); - path_object->level = level; - add_notification_path_object_ordered(path_object); - } - return; -} -/*---------------------------------------------------------------------------*/ -/* For adding objects to the list in an ordered way, depending on the path*/ void -lwm2m_notification_queue_add_notification_path(char *path) +lwm2m_notification_queue_add_notification_path(uint16_t object_id, uint16_t instance_id, uint16_t resource_id) { - notification_path_t *path_object = memb_alloc(¬ification_memb); - if(path_object == NULL) { - LOG_DBG("Could not allocate new notification in the queue\n"); + if(is_notification_path_present(object_id, instance_id, resource_id)) { + LOG_DBG("Notification path already present, not queueing it\n"); return; } - reduce_path(path_object, path); - if(list_length(notification_paths_queue) >= LWM2M_NOTIFICATION_QUEUE_LENGTH) { - /* The queue is full, apply policy to remove */ - notification_queue_remove_policy(path_object->reduced_path, path_object->level); - } else { - add_notification_path_object_ordered(path_object); + notification_path_t *path_object = memb_alloc(¬ification_memb); + if(path_object == NULL) { + LOG_DBG("Queue is full, could not allocate new notification\n"); + return; } - LOG_DBG("Notification path added to the list: %s\n", path); + path_object->reduced_path[0] = object_id; + path_object->reduced_path[1] = instance_id; + path_object->reduced_path[2] = resource_id; + path_object->level = 3; + list_add(notification_paths_queue, path_object); + LOG_DBG("Notification path added to the list: %u/%u/%u\n", object_id, instance_id, resource_id); } /*---------------------------------------------------------------------------*/ void diff --git a/os/services/lwm2m/lwm2m-notification-queue.h b/os/services/lwm2m/lwm2m-notification-queue.h index 805002cc2..e3f4719ac 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.h +++ b/os/services/lwm2m/lwm2m-notification-queue.h @@ -35,7 +35,8 @@ /** * \file - * Header file for functions to manage the queue of notifications + * Header file for functions to manage the queue to store notifications + when waiting for the response to the update message in Queue Mode. * \author * Carlos Gonzalo Peces */ @@ -56,8 +57,7 @@ typedef struct notification_path { void lwm2m_notification_queue_init(void); -/* For adding objects to the list in an ordered way, depending on the path*/ -void lwm2m_notification_queue_add_notification_path(char *path); +void lwm2m_notification_queue_add_notification_path(uint16_t object_id, uint16_t instance_id, uint16_t resource_id); void lwm2m_notification_queue_send_notifications(); From ec8fe6eb22a5e48a4358a2d30c5dc8b765689ca6 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Tue, 22 May 2018 15:34:30 +0200 Subject: [PATCH 10/12] Code moved frome lwm2m-engine to lwm2m-queue-mode to have a clearer separation --- examples/lwm2m-ipso-objects/project-conf.h | 11 +- os/services/lwm2m/lwm2m-engine.c | 101 +------------------ os/services/lwm2m/lwm2m-engine.h | 9 -- os/services/lwm2m/lwm2m-notification-queue.c | 2 +- os/services/lwm2m/lwm2m-queue-mode.c | 101 ++++++++++++++++++- os/services/lwm2m/lwm2m-queue-mode.h | 12 ++- os/services/lwm2m/lwm2m-rd-client.c | 8 +- 7 files changed, 125 insertions(+), 119 deletions(-) diff --git a/examples/lwm2m-ipso-objects/project-conf.h b/examples/lwm2m-ipso-objects/project-conf.h index 53d149617..01f919866 100644 --- a/examples/lwm2m-ipso-objects/project-conf.h +++ b/examples/lwm2m-ipso-objects/project-conf.h @@ -60,10 +60,11 @@ #define COAP_OBSERVE_CLIENT 1 /* Definitions to enable Queue Mode, include the dynamic adaptation and change the default parameters */ -/* #define LWM2M_Q_MODE_CONF_ENABLED 1 - #define LWM2M_Q_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION 1 - #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME 2000 - #define LWM2M_Q_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME 10000 - #define LWM2M_Q_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 0 */ +/* #define LWM2M_QUEUE_MODE_CONF_ENABLED 1 + #define LWM2M_QUEUE_MODE_CONF_INCLUDE_DYNAMIC_ADAPTATION 1 + #define LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_AWAKE_TIME 2000 + #define LWM2M_QUEUE_MODE_CONF_DEFAULT_CLIENT_SLEEP_TIME 10000 + #define LWM2M_QUEUE_MODE_CONF_DEFAULT_DYNAMIC_ADAPTATION_FLAG 1 + #define LWM2M_QUEUE_MODE_OBJECT_CONF_ENABLED 0 */ #endif /* PROJECT_CONF_H_ */ diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index 015e1cea9..0c4d9f5fd 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -84,9 +84,6 @@ #if LWM2M_QUEUE_MODE_ENABLED /* Queue Mode is handled using the RD Client and the Q-Mode object */ #define USE_RD_CLIENT 1 -/* Queue Mode dynamic adaptation masks */ -#define FIRST_REQUEST_MASK 0x01 -#define HANDLER_FROM_NOTIFICATION_MASK 0x02 #endif #if USE_RD_CLIENT @@ -146,19 +143,6 @@ static struct { /* in the future also a timeout */ } created; -#if LWM2M_QUEUE_MODE_ENABLED -static uint8_t waked_up_by_notification; -/* For the dynamic adaptation of the awake time */ -#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION -static uint8_t dynamic_adaptation_params = 0x00; /* bit0: first_request, bit1: handler from notification */ -static uint64_t previous_request_time; -static inline void clear_first_request(); -static inline uint8_t is_first_request(); -static inline void clear_handler_from_notification(); -static inline uint8_t get_handler_from_notification(); -#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_QUEUE_MODE_ENABLED */ - COAP_HANDLER(lwm2m_handler, lwm2m_handler_callback); LIST(object_list); LIST(generic_object_list); @@ -1406,32 +1390,8 @@ lwm2m_handler_callback(coap_message_t *request, coap_message_t *response, context.inbuf->size = coap_get_payload(request, (const uint8_t **)&context.inbuf->buffer); context.inbuf->pos = 0; - /*If Queue Mode, restart the client awake timer */ #if LWM2M_QUEUE_MODE_ENABLED - if(lwm2m_rd_client_is_client_awake()) { - lwm2m_rd_client_restart_client_awake_timer(); - } - -#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION - if(lwm2m_queue_mode_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { - if(is_first_request()) { - previous_request_time = coap_timer_uptime(); - clear_first_request(); - } else { - if(coap_timer_uptime()-previous_request_time >= 0) { - if(coap_timer_uptime()-previous_request_time > 0xffff) { - lwm2m_queue_mode_add_time_to_window(0xffff); - } else { - lwm2m_queue_mode_add_time_to_window(coap_timer_uptime()-previous_request_time); - } - } - previous_request_time = coap_timer_uptime(); - } - } - if(get_handler_from_notification()) { - clear_handler_from_notification(); - } -#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +lwm2m_queue_mode_request_received(); #endif /* LWM2M_QUEUE_MODE_ENABLED */ /* Maybe this should be part of CoAP itself - this seems not to be working @@ -1698,7 +1658,7 @@ lwm2m_send_notification(char* path) { #if LWM2M_QUEUE_MODE_ENABLED && LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { - lwm2m_engine_set_handler_from_notification(); + lwm2m_queue_mode_set_handler_from_notification(); } #endif coap_notify_observers_sub(NULL, path); @@ -1721,8 +1681,8 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, lwm2m_notification_queue_add_notification_path(obj->object_id, obj->instance_id, resource); /* if it is the first notification -> wake up and send update */ - if(!waked_up_by_notification) { - waked_up_by_notification = 1; + if(!lwm2m_queue_mode_is_waked_up_by_notification()) { + lwm2m_queue_mode_set_waked_up_by_notification(); lwm2m_rd_client_fsm_execute_queue_mode_update(); } /* Client is awake -> send the notification */ @@ -1735,57 +1695,4 @@ lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, #endif } /*---------------------------------------------------------------------------*/ -/* Queue Mode Support and dynamic adaptation of the client awake time */ -#if LWM2M_QUEUE_MODE_ENABLED -uint8_t -lwm2m_engine_is_waked_up_by_notification() -{ - return waked_up_by_notification; -} -/*---------------------------------------------------------------------------*/ -void -lwm2m_engine_clear_waked_up_by_notification() -{ - waked_up_by_notification = 0; -} -/*---------------------------------------------------------------------------*/ -#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION -void -lwm2m_engine_set_first_request() -{ - dynamic_adaptation_params |= FIRST_REQUEST_MASK; -} -/*---------------------------------------------------------------------------*/ -void -lwm2m_engine_set_handler_from_notification() -{ - dynamic_adaptation_params |= HANDLER_FROM_NOTIFICATION_MASK; -} -/*---------------------------------------------------------------------------*/ -static inline uint8_t -is_first_request() -{ - return dynamic_adaptation_params & FIRST_REQUEST_MASK; -} -/*---------------------------------------------------------------------------*/ -static inline uint8_t -get_handler_from_notification() -{ - return (dynamic_adaptation_params & HANDLER_FROM_NOTIFICATION_MASK) != 0; -} -/*---------------------------------------------------------------------------*/ -static inline void -clear_first_request() -{ - dynamic_adaptation_params &= ~FIRST_REQUEST_MASK; -} -/*---------------------------------------------------------------------------*/ -static inline void -clear_handler_from_notification() -{ - dynamic_adaptation_params &= ~HANDLER_FROM_NOTIFICATION_MASK; -} -#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_QUEUE_MODE_ENABLED */ -/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/services/lwm2m/lwm2m-engine.h b/os/services/lwm2m/lwm2m-engine.h index 0f6d35734..0ca24fb90 100644 --- a/os/services/lwm2m/lwm2m-engine.h +++ b/os/services/lwm2m/lwm2m-engine.h @@ -116,14 +116,5 @@ void lwm2m_notify_object_observers(lwm2m_object_instance_t *obj, void lwm2m_engine_set_opaque_callback(lwm2m_context_t *ctx, lwm2m_write_opaque_callback cb); -#if LWM2M_QUEUE_MODE_ENABLED -uint8_t lwm2m_engine_is_waked_up_by_notification(); -void lwm2m_engine_clear_waked_up_by_notification(); -#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION -void lwm2m_engine_set_first_request(); -void lwm2m_engine_set_handler_from_notification(); -#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ -#endif /* LWM2M_QUEUE_MODE_ENABLED */ - #endif /* LWM2M_ENGINE_H */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-notification-queue.c b/os/services/lwm2m/lwm2m-notification-queue.c index 4bbb860c1..c901bef82 100644 --- a/os/services/lwm2m/lwm2m-notification-queue.c +++ b/os/services/lwm2m/lwm2m-notification-queue.c @@ -145,7 +145,7 @@ lwm2m_notification_queue_send_notifications() extend_path(iteration_path, path, sizeof(path)); #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { - lwm2m_engine_set_handler_from_notification(); + lwm2m_queue_mode_set_handler_from_notification(); } #endif LOG_DBG("Sending stored notification with path: %s\n", path); diff --git a/os/services/lwm2m/lwm2m-queue-mode.c b/os/services/lwm2m/lwm2m-queue-mode.c index 30c8dd6cc..aad80ce3e 100644 --- a/os/services/lwm2m/lwm2m-queue-mode.c +++ b/os/services/lwm2m/lwm2m-queue-mode.c @@ -55,17 +55,30 @@ #define LOG_MODULE "lwm2m-queue-mode" #define LOG_LEVEL LOG_LEVEL_LWM2M +/* Queue Mode dynamic adaptation masks */ +#define FIRST_REQUEST_MASK 0x01 +#define HANDLER_FROM_NOTIFICATION_MASK 0x02 static uint16_t queue_mode_awake_time = LWM2M_QUEUE_MODE_DEFAULT_CLIENT_AWAKE_TIME; static uint32_t queue_mode_sleep_time = LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME; + +/* Flag for notifications */ +static uint8_t waked_up_by_notification; + +/* For the dynamic adaptation of the awake time */ #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION static uint8_t queue_mode_dynamic_adaptation_flag = LWM2M_QUEUE_MODE_DEFAULT_DYNAMIC_ADAPTATION_FLAG; /* Window to save the times and do the dynamic adaptation of the awake time*/ uint16_t times_window[LWM2M_QUEUE_MODE_DYNAMIC_ADAPTATION_WINDOW_LENGTH] = { 0 }; uint8_t times_window_index = 0; - -#endif +static uint8_t dynamic_adaptation_params = 0x00; /* bit0: first_request, bit1: handler from notification */ +static uint64_t previous_request_time; +static inline void clear_first_request(); +static inline uint8_t is_first_request(); +static inline void clear_handler_from_notification(); +static inline uint8_t get_handler_from_notification(); +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ /*---------------------------------------------------------------------------*/ uint16_t lwm2m_queue_mode_get_awake_time() @@ -106,6 +119,7 @@ lwm2m_queue_mode_set_dynamic_adaptation_flag(uint8_t flag) { queue_mode_dynamic_adaptation_flag = flag; } +#endif /*---------------------------------------------------------------------------*/ #if !UPDATE_WITH_MEAN static uint16_t @@ -167,6 +181,89 @@ lwm2m_queue_mode_add_time_to_window(uint16_t time) times_window_index++; update_awake_time(); } +/*---------------------------------------------------------------------------*/ +uint8_t +lwm2m_queue_mode_is_waked_up_by_notification() +{ + return waked_up_by_notification; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_clear_waked_up_by_notification() +{ + waked_up_by_notification = 0; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_waked_up_by_notification() +{ + waked_up_by_notification = 1; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_request_received() +{ + if(lwm2m_rd_client_is_client_awake()) { + lwm2m_rd_client_restart_client_awake_timer(); + } +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION + if(lwm2m_queue_mode_get_dynamic_adaptation_flag() && !get_handler_from_notification()) { + if(is_first_request()) { + previous_request_time = coap_timer_uptime(); + clear_first_request(); + } else { + if(coap_timer_uptime() - previous_request_time >= 0) { + if(coap_timer_uptime() - previous_request_time > 0xffff) { + lwm2m_queue_mode_add_time_to_window(0xffff); + } else { + lwm2m_queue_mode_add_time_to_window(coap_timer_uptime() - previous_request_time); + } + } + previous_request_time = coap_timer_uptime(); + } + } + if(get_handler_from_notification()) { + clear_handler_from_notification(); + } +#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ +} +/*---------------------------------------------------------------------------*/ +#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION +void +lwm2m_queue_mode_set_first_request() +{ + dynamic_adaptation_params |= FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +void +lwm2m_queue_mode_set_handler_from_notification() +{ + dynamic_adaptation_params |= HANDLER_FROM_NOTIFICATION_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline uint8_t +is_first_request() +{ + return dynamic_adaptation_params & FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline uint8_t +get_handler_from_notification() +{ + return (dynamic_adaptation_params & HANDLER_FROM_NOTIFICATION_MASK) != 0; +} +/*---------------------------------------------------------------------------*/ +static inline void +clear_first_request() +{ + dynamic_adaptation_params &= ~FIRST_REQUEST_MASK; +} +/*---------------------------------------------------------------------------*/ +static inline void +clear_handler_from_notification() +{ + dynamic_adaptation_params &= ~HANDLER_FROM_NOTIFICATION_MASK; +} #endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ #endif /* LWM2M_QUEUE_MODE_ENABLED */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-queue-mode.h b/os/services/lwm2m/lwm2m-queue-mode.h index cc3bd3290..5c65face5 100644 --- a/os/services/lwm2m/lwm2m-queue-mode.h +++ b/os/services/lwm2m/lwm2m-queue-mode.h @@ -36,7 +36,7 @@ /** * \file * Header file for the Contiki OMA LWM2M Queue Mode implementation - to manage the parameters + to manage the parameters * \author * Carlos Gonzalo Peces */ @@ -51,11 +51,21 @@ uint16_t lwm2m_queue_mode_get_awake_time(); void lwm2m_queue_mode_set_awake_time(uint16_t time); uint32_t lwm2m_queue_mode_get_sleep_time(); void lwm2m_queue_mode_set_sleep_time(uint32_t time); + #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION uint8_t lwm2m_queue_mode_get_dynamic_adaptation_flag(); void lwm2m_queue_mode_set_dynamic_adaptation_flag(uint8_t flag); void lwm2m_queue_mode_add_time_to_window(uint16_t time); #endif +uint8_t lwm2m_queue_mode_is_waked_up_by_notification(); +void lwm2m_queue_mode_clear_waked_up_by_notification(); +void lwm2m_queue_mode_set_waked_up_by_notification(); + +void lwm2m_queue_mode_set_first_request(); +void lwm2m_queue_mode_set_handler_from_notification(); + +void lwm2m_queue_mode_request_received(); + #endif /* LWM2M_QUEUE_MODE_H_ */ /** @} */ diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index da8d276d0..63c9443e1 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -448,7 +448,7 @@ registration_callback(coap_request_state_t *state) #if LWM2M_QUEUE_MODE_ENABLED #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { - lwm2m_engine_set_first_request(); + lwm2m_queue_mode_set_first_request(); } #endif lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ @@ -501,14 +501,14 @@ update_callback(coap_request_state_t *state) last_update = coap_timer_uptime(); #if LWM2M_QUEUE_MODE_ENABLED /* If it has been waked up by a notification, send the stored notifications in queue */ - if(lwm2m_engine_is_waked_up_by_notification()) { + if(lwm2m_queue_mode_is_waked_up_by_notification()) { - lwm2m_engine_clear_waked_up_by_notification(); + lwm2m_queue_mode_clear_waked_up_by_notification(); lwm2m_notification_queue_send_notifications(); } #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) { - lwm2m_engine_set_first_request(); + lwm2m_queue_mode_set_first_request(); } #endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ From 262cea11f1168afb3fe5320db07e421c106b73fe Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Wed, 23 May 2018 15:59:43 +0200 Subject: [PATCH 11/12] Implemented instant feedback in CoAp_send_request --- os/net/app-layer/coap/coap-callback-api.c | 8 +++++--- os/net/app-layer/coap/coap-callback-api.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/os/net/app-layer/coap/coap-callback-api.c b/os/net/app-layer/coap/coap-callback-api.c index b1b05597e..0f0ab2c99 100644 --- a/os/net/app-layer/coap/coap-callback-api.c +++ b/os/net/app-layer/coap/coap-callback-api.c @@ -65,7 +65,7 @@ static void coap_request_callback(void *callback_data, coap_message_t *response) /*---------------------------------------------------------------------------*/ -static void +static int progress_request(coap_request_state_t *state) { coap_message_t *request = state->request; request->mid = coap_get_mid(); @@ -83,7 +83,9 @@ progress_request(coap_request_state_t *state) { coap_send_transaction(state->transaction); LOG_DBG("Requested #%"PRIu32" (MID %u)\n", state->block_num, request->mid); + return 1; } + return 0; } /*---------------------------------------------------------------------------*/ @@ -134,7 +136,7 @@ coap_request_callback(void *callback_data, coap_message_t *response) /*---------------------------------------------------------------------------*/ -void +int coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, coap_message_t *request, void (*callback)(coap_request_state_t *state)) @@ -151,7 +153,7 @@ coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, state->remote_endpoint = endpoint; state->callback = callback; - progress_request(state); + return progress_request(state); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/net/app-layer/coap/coap-callback-api.h b/os/net/app-layer/coap/coap-callback-api.h index 6de7ab587..7f144af96 100644 --- a/os/net/app-layer/coap/coap-callback-api.h +++ b/os/net/app-layer/coap/coap-callback-api.h @@ -65,7 +65,7 @@ struct coap_request_state { void (*callback)(coap_request_state_t *state); }; -void coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, +int coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, coap_message_t *request, void (*callback)(coap_request_state_t *state)); From b50d143966d89895117dd67974833b76f56d3758 Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Thu, 24 May 2018 08:53:33 +0200 Subject: [PATCH 12/12] Added doxygen annotation to the prototype --- os/net/app-layer/coap/coap-callback-api.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/os/net/app-layer/coap/coap-callback-api.h b/os/net/app-layer/coap/coap-callback-api.h index 7f144af96..69ceea4f5 100644 --- a/os/net/app-layer/coap/coap-callback-api.h +++ b/os/net/app-layer/coap/coap-callback-api.h @@ -65,6 +65,14 @@ struct coap_request_state { void (*callback)(coap_request_state_t *state); }; +/** + * \brief Send a CoAP request to a remote endpoint + * \param state The state to handle the CoAP request + * \param endpoint The destination endpoint + * \param request The request to be sent + * \param callback callback to execute when the response arrives or the timeout expires + * \return 1 if there is a transaction available to send, 0 otherwise + */ int coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, coap_message_t *request, void (*callback)(coap_request_state_t *state));