mbed client lightswitch demo

Dependencies:   mbed Socket lwip-eth lwip-sys lwip

Fork of mbed-client-classic-example-lwip by Austin Blackstone

mbed-client/source/m2mreporthandler.cpp

Committer:
mbedAustin
Date:
2016-06-09
Revision:
11:cada08fc8a70

File content as of revision 11:cada08fc8a70:

/*
 * 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 "ns_trace.h"
#include <stdio.h>
#include <string.h>

M2MReportHandler::M2MReportHandler(M2MReportObserver &observer)
: _observer(observer),
  _pmax(-1.0f),
  _pmin(1.0f),
  _gt(0.0f),
  _lt(0.0f),
  _st(0.0f),
  _pmin_exceeded(false),
  _pmax_exceeded(false),
  _pmin_timer(NULL),
  _pmax_timer(NULL),  
  _high_step(0.0f),
  _low_step(0.0f),
  _current_value(0.0f),
  _last_value(0.0f),
  _attribute_state(0),
  _notify(false)
{
    tr_debug("M2MReportHandler::M2MReportHandler()");
}

M2MReportHandler::~M2MReportHandler()
{
    tr_debug("M2MReportHandler::~M2MReportHandler()");
    if(_pmax_timer) {
        delete _pmax_timer;
    }
    if(_pmin_timer) {
        delete _pmin_timer;
    }
}

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_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");
                if (_pmin_timer) {
                    _pmin_timer->stop_timer();
                    _pmin_exceeded = true;
                }
            }
        }
        _high_step = _current_value + _st;
        _low_step = _current_value - _st;
    }
}

void M2MReportHandler::set_notification_trigger()
{
    tr_debug("M2MReportHandler::set_notification_trigger()");
    _current_value = 0.0f;
    _last_value = 1.0f;    
    schedule_report();
}

bool M2MReportHandler::parse_notification_attribute(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;
    char* sep_pos = strchr(query, '&');
    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(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);

    char* pos = strstr(option, EQUAL.c_str());
    if( pos != NULL ){
        memcpy(attribute, option, (size_t)(pos-option));
        pos++;
        memcpy(value, pos, 20);
    }else{
        memcpy(attribute, option, (size_t)strlen(option) + 1);
    }

    if (strcmp(attribute, PMIN.c_str()) == 0) {
        sscanf(value, "%f", &_pmin);
        success = true;
        _attribute_state |= M2MReportHandler::Pmin;
        tr_debug("M2MReportHandler::set_notification_attribute %s to %f", attribute, _pmin);
    }
    else if(strcmp(attribute, PMAX.c_str()) == 0) {
        sscanf(value, "%f", &_pmax);
        success = true;        
        _attribute_state |= M2MReportHandler::Pmax;
        tr_debug("M2MReportHandler::set_notification_attribute %s to %f", attribute, _pmax);
    }
    else if(strcmp(attribute, GT.c_str()) == 0 &&
            (M2MBase::Resource == type)){
        sscanf(value, "%f", &_gt);
        success = true;        
        _attribute_state |= M2MReportHandler::Gt;
        tr_debug("M2MReportHandler::set_notification_attribute %s to %f", attribute, _gt);
    }
    else if(strcmp(attribute, LT.c_str()) == 0 &&
            (M2MBase::Resource == type)){
        sscanf(value, "%f", &_lt);
        success = true;
        _attribute_state |= M2MReportHandler::Lt;
        tr_debug("M2MReportHandler::set_notification_attribute %s to %f", attribute, _lt);
    }
    else if(strcmp(attribute, ST.c_str()) == 0 &&
            (M2MBase::Resource == type)){
        sscanf(value, "%f", &_st);
        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);
    }
    else if(strcmp(attribute, CANCEL.c_str()) == 0) {
        success = true;
        _attribute_state |= M2MReportHandler::Cancel;
        tr_debug("M2MReportHandler::set_notification_attribute cancel");
    }   

    // 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();
        if (_pmax_timer) {
            _pmax_timer->stop_timer();
        }
    }
    else {
        if (_pmax_exceeded) {
            tr_debug("M2MReportHandler::report()- send with PMAX");
            _observer.observation_to_be_sent();
        }
        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)(_pmin * 1000);
            tr_debug("M2MReportHandler::handle_timers() - Start PMIN interval: %d", (int)time_interval);
            if (!_pmin_timer) {
                _pmin_timer = new M2MTimer(*this);
            }
            _pmin_timer->start_timer(time_interval,
                                     M2MTimerObserver::PMinTimer,
                                     true);
        }
    }
    if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax) {
        if (_pmax > 0) {
            if (!_pmax_timer) {
                _pmax_timer = new M2MTimer(*this);
            }
            time_interval = (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.0f) && (_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()");
    if (_pmin_timer) {
        _pmin_exceeded = false;
        _pmin_timer->stop_timer();

        delete _pmin_timer;
        _pmin_timer = NULL;
    }
    if (_pmax_timer) {
        _pmax_exceeded = false;
        _pmax_timer->stop_timer();
        delete _pmax_timer;
        _pmax_timer = NULL;
    }
    tr_debug("M2MReportHandler::stop_timers() - out");
}

void M2MReportHandler::set_default_values()
{
    tr_debug("M2MReportHandler::set_default_values");
    _pmax = -1.0f;
    _pmin = 1.0f;
    _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 = 0.0f;
    _attribute_state = 0;
}

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;
}