A metronome using the FRDM K64F board

Revision:
0:a7a43371b306
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-client/source/m2mreporthandler.cpp	Sun May 14 18:40:18 2017 +0000
@@ -0,0 +1,468 @@
+/*
+ * 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.
+ */
+#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),
+  _attribute_state(0),
+  _notify(false),
+  _pmin_exceeded(false),
+  _pmax_exceeded(false),
+  _pmin_timer(*this),
+  _pmax_timer(*this),
+  _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()");
+}
+
+void M2MReportHandler::set_under_observation(bool observed)
+{
+    tr_debug("M2MReportHandler::set_under_observation(observed %d)", (int)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");
+            if (_notify ||
+                    (_pmin > 0 &&
+                     (_attribute_state & M2MReportHandler::Pmax) != M2MReportHandler::Pmax)){
+                report();
+            }
+            else{
+                _pmin_exceeded = true;
+            }
+        }
+        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_debug("M2MReportHandler::set_notification_attribute %s to %d", attribute, _pmin);
+        }
+        else if(strcmp(attribute, PMAX) == 0) {
+            _pmax = atoi(value);
+            success = true;
+            _attribute_state |= M2MReportHandler::Pmax;
+            tr_debug("M2MReportHandler::set_notification_attribute %s to %d", attribute, _pmax);
+        }
+        else if(strcmp(attribute, GT) == 0 &&
+                (M2MBase::Resource == type)){
+            _gt = atof(value);
+            success = true;
+            _attribute_state |= M2MReportHandler::Gt;
+            tr_debug("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_debug("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_debug("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) {
+        tr_debug("M2MReportHandler::report()- send with PMIN");
+        _pmin_exceeded = false;
+        _pmax_exceeded = false;
+        _notify = false;
+        _observer.observation_to_be_sent(_changed_instance_ids);
+        _changed_instance_ids.clear();
+        _pmax_timer.stop_timer();
+    }
+    else {
+        if (_pmax_exceeded) {
+            tr_debug("M2MReportHandler::report()- send with PMAX");
+            _observer.observation_to_be_sent(_changed_instance_ids, 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()
+{
+    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()
+{
+    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()
+{
+    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()
+{
+    return _attribute_state;
+}