Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: mbed-cloud-client/mbed-client/source/m2mreporthandler.cpp
- Revision:
- 0:276e7a263c35
diff -r 000000000000 -r 276e7a263c35 mbed-cloud-client/mbed-client/source/m2mreporthandler.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-cloud-client/mbed-client/source/m2mreporthandler.cpp Mon Jul 02 06:30:39 2018 +0000
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2015 ARM Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// fixup the compilation on ARMCC for PRId32
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include "mbed-client/m2mreportobserver.h"
+#include "mbed-client/m2mconstants.h"
+#include "mbed-client/m2mtimer.h"
+#include "include/m2mreporthandler.h"
+#include "mbed-trace/mbed_trace.h"
+#include <string.h>
+#include <stdlib.h>
+
+#define TRACE_GROUP "mClt"
+
+M2MReportHandler::M2MReportHandler(M2MReportObserver &observer)
+: _observer(observer),
+ _is_under_observation(false),
+ _observation_level(M2MBase::None),
+ _attribute_state(0),
+ _token_length(0),
+ _notify(false),
+ _pmin_exceeded(false),
+ _pmax_exceeded(false),
+ _observation_number(0),
+ _pmin_timer(*this),
+ _pmax_timer(*this),
+ _token(NULL),
+ _pmax(-1.0f),
+ _pmin(1.0f),
+ _current_value(0.0f),
+ _gt(0.0f),
+ _lt(0.0f),
+ _st(0.0f),
+ _high_step(0.0f),
+ _low_step(0.0f),
+ _last_value(-1.0f)
+{
+ tr_debug("M2MReportHandler::M2MReportHandler()");
+}
+
+M2MReportHandler::~M2MReportHandler()
+{
+ tr_debug("M2MReportHandler::~M2MReportHandler()");
+ free(_token);
+}
+
+void M2MReportHandler::set_under_observation(bool observed)
+{
+ tr_debug("M2MReportHandler::set_under_observation(observed %d)", (int)observed);
+
+ _is_under_observation = observed;
+
+ stop_timers();
+ if(observed) {
+ handle_timers();
+ }
+ else {
+ set_default_values();
+ }
+}
+
+void M2MReportHandler::set_value(float value)
+{
+ tr_debug("M2MReportHandler::set_value() - current %f, last %f", value, _last_value);
+ _current_value = value;
+ if(_current_value != _last_value) {
+ tr_debug("M2MReportHandler::set_value() - UNDER OBSERVATION");
+ if (check_threshold_values()) {
+ schedule_report();
+ }
+ else {
+ tr_debug("M2MReportHandler::set_value - value not in range");
+ _notify = false;
+ _last_value = _current_value;
+ if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt ||
+ (_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt ||
+ (_attribute_state & M2MReportHandler::St) == M2MReportHandler::St) {
+ tr_debug("M2MReportHandler::set_value - stop pmin timer");
+ _pmin_timer.stop_timer();
+ _pmin_exceeded = true;
+ }
+ }
+ _high_step = _current_value + _st;
+ _low_step = _current_value - _st;
+ }
+}
+
+void M2MReportHandler::set_notification_trigger(uint16_t obj_instance_id)
+{
+ tr_debug("M2MReportHandler::set_notification_trigger(): %d", obj_instance_id);
+ // Add to array if not there yet
+ m2m::Vector<uint16_t>::const_iterator it;
+ it = _changed_instance_ids.begin();
+ bool found = false;
+ for ( ; it != _changed_instance_ids.end(); it++) {
+ if ((*it) == obj_instance_id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ _changed_instance_ids.push_back(obj_instance_id);
+ }
+
+ _current_value = 0.0f;
+ _last_value = 1.0f;
+ schedule_report();
+}
+
+bool M2MReportHandler::parse_notification_attribute(const char *query,
+ M2MBase::BaseType type,
+ M2MResourceInstance::ResourceType resource_type)
+{
+ tr_debug("M2MReportHandler::parse_notification_attribute(Query %s, Base type %d)", query, (int)type);
+ bool success = false;
+ const char* sep_pos = strchr(query, '&');
+ const char* rest = query;
+ if( sep_pos != NULL ){
+ char query_options[5][20];
+ float pmin = _pmin;
+ float pmax = _pmax;
+ float lt = _lt;
+ float gt = _gt;
+ float st = _st;
+ float high = _high_step;
+ float low = _low_step;
+ uint8_t attr = _attribute_state;
+
+ memset(query_options, 0, sizeof(query_options[0][0]) * 5 * 20);
+ uint8_t num_options = 0;
+ while( sep_pos != NULL && num_options < 5){
+ size_t len = (size_t)(sep_pos-rest);
+ if( len > 19 ){
+ len = 19;
+ }
+ memcpy(query_options[num_options], rest, len);
+ sep_pos++;
+ rest = sep_pos;
+ sep_pos = strchr(rest, '&');
+ num_options++;
+ }
+ if( num_options < 5 && strlen(rest) > 0){
+ size_t len = (size_t)strlen(rest);
+ if( len > 19 ){
+ len = 19;
+ }
+ memcpy(query_options[num_options++], rest, len);
+ }
+
+ for (int option = 0; option < num_options; option++) {
+ success = set_notification_attribute(query_options[option],type, resource_type);
+ if (!success) {
+ tr_debug("M2MReportHandler::parse_notification_attribute - break");
+ break;
+ }
+ }
+
+ if(success) {
+ success = check_attribute_validity();
+ }
+ else {
+ tr_debug("M2MReportHandler::parse_notification_attribute - not valid query");
+ _pmin = pmin;
+ _pmax = pmax;
+ _st = st;
+ _lt = lt;
+ _gt = gt;
+ _high_step = high;
+ _low_step = low;
+ _attribute_state = attr;
+ }
+ }
+ else {
+ if(set_notification_attribute(query, type, resource_type)) {
+ success = check_attribute_validity();
+ }
+ }
+
+ return success;
+}
+
+void M2MReportHandler::timer_expired(M2MTimerObserver::Type type)
+{
+ switch(type) {
+ case M2MTimerObserver::PMinTimer: {
+ tr_debug("M2MReportHandler::timer_expired - PMIN");
+ _pmin_exceeded = true;
+ if (_notify ||
+ (_pmin > 0 &&
+ (_attribute_state & M2MReportHandler::Pmax) != M2MReportHandler::Pmax)){
+ report();
+ }
+ }
+ break;
+ case M2MTimerObserver::PMaxTimer: {
+ tr_debug("M2MReportHandler::timer_expired - PMAX");
+ _pmax_exceeded = true;
+ if (_pmin_exceeded ||
+ (_attribute_state & M2MReportHandler::Pmin) != M2MReportHandler::Pmin ) {
+ report();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool M2MReportHandler::set_notification_attribute(const char* option,
+ M2MBase::BaseType type,
+ M2MResourceInstance::ResourceType resource_type)
+{
+ tr_debug("M2MReportHandler::set_notification_attribute()");
+ bool success = false;
+ char attribute[20];
+ char value[20];
+ memset(&attribute, 0, 20);
+ memset(&value, 0, 20);
+
+ const char* pos = strstr(option, EQUAL);
+ if( pos != NULL ){
+ memcpy(attribute, option, (size_t)(pos-option));
+ pos++;
+ memcpy(value, pos, strlen(pos));
+ }else{
+ memcpy(attribute, option, (size_t)strlen(option) + 1);
+ }
+
+ if (strlen(value)) {
+ if (strcmp(attribute, PMIN) == 0) {
+ _pmin = atoi(value);
+ success = true;
+ _attribute_state |= M2MReportHandler::Pmin;
+ tr_info("M2MReportHandler::set_notification_attribute %s to %" PRId32, attribute, _pmin);
+ }
+ else if(strcmp(attribute, PMAX) == 0) {
+ _pmax = atoi(value);
+ success = true;
+ _attribute_state |= M2MReportHandler::Pmax;
+ tr_info("M2MReportHandler::set_notification_attribute %s to %" PRId32, attribute, _pmax);
+ }
+ else if(strcmp(attribute, GT) == 0 &&
+ (M2MBase::Resource == type)){
+ _gt = atof(value);
+ success = true;
+ _attribute_state |= M2MReportHandler::Gt;
+ tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _gt);
+ }
+ else if(strcmp(attribute, LT) == 0 &&
+ (M2MBase::Resource == type)){
+ _lt = atof(value);
+ success = true;
+ _attribute_state |= M2MReportHandler::Lt;
+ tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _lt);
+ }
+ else if((strcmp(attribute, ST_SIZE) == 0 || (strcmp(attribute, STP) == 0))
+ && (M2MBase::Resource == type)){
+ _st = atof(value);
+ success = true;
+ _high_step = _current_value + _st;
+ _low_step = _current_value - _st;
+ _attribute_state |= M2MReportHandler::St;
+ tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _st);
+ }
+ // Return false if try to set gt,lt or st when the resource type is something else than numerical
+ if ((resource_type != M2MResourceInstance::INTEGER &&
+ resource_type != M2MResourceInstance::FLOAT) &&
+ ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt ||
+ (_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt ||
+ (_attribute_state & M2MReportHandler::St) == M2MReportHandler::St)) {
+ tr_debug("M2MReportHandler::set_notification_attribute - not numerical resource");
+ success = false;
+ }
+ }
+ return success;
+}
+
+void M2MReportHandler::schedule_report()
+{
+ tr_debug("M2MReportHandler::schedule_report()");
+ _notify = true;
+ if ((_attribute_state & M2MReportHandler::Pmin) != M2MReportHandler::Pmin ||
+ _pmin_exceeded) {
+ report();
+ }
+}
+
+void M2MReportHandler::report()
+{
+ tr_debug("M2MReportHandler::report()");
+ if(_current_value != _last_value && _notify) {
+ if (_pmin_exceeded) {
+ tr_debug("M2MReportHandler::report()- send with PMIN expiration");
+ } else {
+ tr_debug("M2MReportHandler::report()- send with VALUE change");
+ }
+ _pmin_exceeded = false;
+ _pmax_exceeded = false;
+ _notify = false;
+ _observation_number++;
+ if(_observation_number == 1) {
+ // Increment the observation number by 1 if it is already 1 because CoAP specification has reserved 1 for DEREGISTER notification
+ _observation_number++;
+ }
+ _observer.observation_to_be_sent(_changed_instance_ids, observation_number());
+ _changed_instance_ids.clear();
+ _pmax_timer.stop_timer();
+ }
+ else {
+ if (_pmax_exceeded) {
+ tr_debug("M2MReportHandler::report()- send with PMAX expiration");
+ _observation_number++;
+ if(_observation_number == 1) {
+ // Increment the observation number by 1 if it is already 1 because CoAP specification has reserved 1 for DEREGISTER notification
+ _observation_number++;
+ }
+ _observer.observation_to_be_sent(_changed_instance_ids, observation_number(),true);
+ _changed_instance_ids.clear();
+ }
+ else {
+ tr_debug("M2MReportHandler::report()- no need to send");
+ }
+ }
+ handle_timers();
+ _last_value = _current_value;
+}
+
+void M2MReportHandler::handle_timers()
+{
+ tr_debug("M2MReportHandler::handle_timers()");
+ uint64_t time_interval = 0;
+ if ((_attribute_state & M2MReportHandler::Pmin) == M2MReportHandler::Pmin) {
+ if (_pmin == _pmax) {
+ _pmin_exceeded = true;
+ } else {
+ _pmin_exceeded = false;
+ time_interval = (uint64_t) ((uint64_t)_pmin * 1000);
+ tr_debug("M2MReportHandler::handle_timers() - Start PMIN interval: %d", (int)time_interval);
+ _pmin_timer.start_timer(time_interval,
+ M2MTimerObserver::PMinTimer,
+ true);
+ }
+ }
+ if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax) {
+ if (_pmax > 0) {
+ time_interval = (uint64_t) ((uint64_t)_pmax * 1000);
+ tr_debug("M2MReportHandler::handle_timers() - Start PMAX interval: %d", (int)time_interval);
+ _pmax_timer.start_timer(time_interval,
+ M2MTimerObserver::PMaxTimer,
+ true);
+ }
+ }
+}
+
+bool M2MReportHandler::check_attribute_validity() const
+{
+ bool success = true;
+ if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax &&
+ ((_pmax >= -1.0) && (_pmin > _pmax))) {
+ success = false;
+ }
+ float low = _lt + 2 * _st;
+ if ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt &&
+ (low >= _gt)) {
+ success = false;
+ }
+ return success;
+}
+
+void M2MReportHandler::stop_timers()
+{
+ tr_debug("M2MReportHandler::stop_timers()");
+
+ _pmin_exceeded = false;
+ _pmin_timer.stop_timer();
+
+ _pmax_exceeded = false;
+ _pmax_timer.stop_timer();
+
+ tr_debug("M2MReportHandler::stop_timers() - out");
+}
+
+void M2MReportHandler::set_default_values()
+{
+ tr_debug("M2MReportHandler::set_default_values");
+ _pmax = -1.0;
+ _pmin = 1.0;
+ _gt = 0.0f;
+ _lt = 0.0f;
+ _st = 0.0f;
+ _high_step = 0.0f;
+ _low_step = 0.0f;
+ _pmin_exceeded = false;
+ _pmax_exceeded = false;
+ _last_value = -1.0f;
+ _attribute_state = 0;
+ _changed_instance_ids.clear();
+}
+
+bool M2MReportHandler::check_threshold_values() const
+{
+ tr_debug("M2MReportHandler::check_threshold_values");
+ tr_debug("Current value: %f", _current_value);
+ tr_debug("High step: %f", _high_step);
+ tr_debug("Low step: %f", _low_step);
+ tr_debug("Less than: %f", _lt);
+ tr_debug("Greater than: %f", _gt);
+ tr_debug("Step: %f", _st);
+ bool can_send = false;
+ // Check step condition
+ if ((_attribute_state & M2MReportHandler::St) == M2MReportHandler::St) {
+ if ((_current_value >= _high_step ||
+ _current_value <= _low_step)) {
+ can_send = true;
+ }
+ else {
+ if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt ||
+ (_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt ) {
+ can_send = check_gt_lt_params();
+ }
+ else {
+ can_send = false;
+ }
+ }
+ }
+ else {
+ can_send = check_gt_lt_params();
+ }
+ tr_debug("M2MReportHandler::check_threshold_values - value in range = %d", (int)can_send);
+ return can_send;
+}
+
+bool M2MReportHandler::check_gt_lt_params() const
+{
+ tr_debug("M2MReportHandler::check_gt_lt_params");
+ bool can_send = false;
+ // GT & LT set.
+ if ((_attribute_state & (M2MReportHandler::Lt | M2MReportHandler::Gt))
+ == (M2MReportHandler::Lt | M2MReportHandler::Gt)) {
+ if (_current_value > _gt || _current_value < _lt) {
+ can_send = true;
+ }
+ else {
+ can_send = false;
+ }
+ }
+ // Only LT
+ else if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt &&
+ (_attribute_state & M2MReportHandler::Gt) == 0 ) {
+ if (_current_value < _lt) {
+ can_send = true;
+ }
+ else {
+ can_send = false;
+ }
+ }
+ // Only GT
+ else if ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt &&
+ (_attribute_state & M2MReportHandler::Lt) == 0 ) {
+ if (_current_value > _gt) {
+ can_send = true;
+ }
+ else {
+ can_send = false;
+ }
+ }
+ // GT & LT not set.
+ else {
+ can_send = true;
+ }
+ tr_debug("M2MReportHandler::check_gt_lt_params - value in range = %d", (int)can_send);
+ return can_send;
+}
+
+uint8_t M2MReportHandler::attribute_flags() const
+{
+ return _attribute_state;
+}
+
+void M2MReportHandler::set_observation_token(const uint8_t *token, const uint8_t length)
+{
+ free(_token);
+ _token = NULL;
+ _token_length = 0;
+
+ if( token != NULL && length > 0 ) {
+ _token = alloc_string_copy((uint8_t *)token, length);
+ if(_token) {
+ _token_length = length;
+ }
+ }
+}
+
+void M2MReportHandler::get_observation_token(uint8_t *token, uint8_t &token_length) const
+{
+ memcpy(token, _token, _token_length);
+ token_length = _token_length;
+}
+
+uint16_t M2MReportHandler::observation_number() const
+{
+ return _observation_number;
+}
+
+void M2MReportHandler::add_observation_level(M2MBase::Observation obs_level)
+{
+ _observation_level = (M2MBase::Observation)(_observation_level | obs_level);
+}
+
+void M2MReportHandler::remove_observation_level(M2MBase::Observation obs_level)
+{
+ _observation_level = (M2MBase::Observation)(_observation_level & ~obs_level);
+}
+
+M2MBase::Observation M2MReportHandler::observation_level() const
+{
+ return _observation_level;
+}
+
+bool M2MReportHandler::is_under_observation() const
+{
+ return _is_under_observation;
+}
+
+uint8_t* M2MReportHandler::alloc_string_copy(const uint8_t* source, uint32_t size)
+{
+ assert(source != NULL);
+
+ uint8_t* result = (uint8_t*)malloc(size + 1);
+ if (result) {
+ memcpy(result, source, size);
+ result[size] = '\0';
+ }
+ return result;
+}