Simple interface for Mbed Cloud Client

Dependents:  

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mreporthandler.cpp Source File

m2mreporthandler.cpp

00001 /*
00002  * Copyright (c) 2015 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 // fixup the compilation on ARMCC for PRId32
00018 #define __STDC_FORMAT_MACROS
00019 #include <inttypes.h>
00020 
00021 #include "mbed-client/m2mreportobserver.h"
00022 #include "mbed-client/m2mconstants.h"
00023 #include "mbed-client/m2mtimer.h"
00024 #include "include/m2mreporthandler.h"
00025 #include "mbed-trace/mbed_trace.h"
00026 #include <string.h>
00027 #include <stdlib.h>
00028 
00029 #define TRACE_GROUP "mClt"
00030 
00031 M2MReportHandler::M2MReportHandler(M2MReportObserver &observer)
00032 : _observer(observer),
00033   _is_under_observation(false),
00034   _observation_level(M2MBase::None),
00035   _attribute_state(0),
00036   _token_length(0),
00037   _notify(false),
00038   _pmin_exceeded(false),
00039   _pmax_exceeded(false),
00040   _observation_number(0),
00041   _pmin_timer(*this),
00042   _pmax_timer(*this),
00043   _token(NULL),
00044   _pmax(-1.0f),
00045   _pmin(1.0f),
00046   _current_value(0.0f),
00047   _gt(0.0f),
00048   _lt(0.0f),
00049   _st(0.0f),
00050   _high_step(0.0f),
00051   _low_step(0.0f),
00052   _last_value(-1.0f)
00053 {
00054     tr_debug("M2MReportHandler::M2MReportHandler()");
00055 }
00056 
00057 M2MReportHandler::~M2MReportHandler()
00058 {
00059     tr_debug("M2MReportHandler::~M2MReportHandler()");
00060     free(_token);
00061 }
00062 
00063 void M2MReportHandler::set_under_observation(bool observed)
00064 {
00065     tr_debug("M2MReportHandler::set_under_observation(observed %d)", (int)observed);
00066 
00067     _is_under_observation = observed;
00068 
00069     stop_timers();
00070     if(observed) {
00071         handle_timers();
00072     }
00073     else {
00074         set_default_values();
00075     }
00076 }
00077 
00078 void M2MReportHandler::set_value(float value)
00079 {
00080     tr_debug("M2MReportHandler::set_value() - current %f, last %f", value, _last_value);
00081     _current_value = value;
00082     if(_current_value != _last_value) {
00083         tr_debug("M2MReportHandler::set_value() - UNDER OBSERVATION");
00084         if (check_threshold_values()) {
00085             schedule_report();
00086         }
00087         else {
00088             tr_debug("M2MReportHandler::set_value - value not in range");
00089             _notify = false;
00090             _last_value = _current_value;
00091             if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt ||
00092                     (_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt ||
00093                     (_attribute_state & M2MReportHandler::St) == M2MReportHandler::St) {
00094                 tr_debug("M2MReportHandler::set_value - stop pmin timer");
00095                 _pmin_timer.stop_timer();
00096                 _pmin_exceeded = true;
00097             }
00098         }
00099         _high_step = _current_value + _st;
00100         _low_step = _current_value - _st;
00101     }
00102 }
00103 
00104 void M2MReportHandler::set_notification_trigger(uint16_t obj_instance_id)
00105 {
00106     tr_debug("M2MReportHandler::set_notification_trigger(): %d", obj_instance_id);
00107     // Add to array if not there yet
00108     m2m::Vector<uint16_t>::const_iterator it;
00109     it = _changed_instance_ids.begin();
00110     bool found = false;
00111     for ( ; it != _changed_instance_ids.end(); it++) {
00112         if ((*it) == obj_instance_id) {
00113             found = true;
00114             break;
00115         }
00116     }
00117     if (!found) {
00118         _changed_instance_ids.push_back(obj_instance_id);
00119     }
00120 
00121     _current_value = 0.0f;
00122     _last_value = 1.0f;
00123     schedule_report();
00124 }
00125 
00126 bool M2MReportHandler::parse_notification_attribute(const char *query,
00127                                                     M2MBase::BaseType type,
00128                                                     M2MResourceInstance::ResourceType resource_type)
00129 {
00130     tr_debug("M2MReportHandler::parse_notification_attribute(Query %s, Base type %d)", query, (int)type);
00131     bool success = false;
00132     const char* sep_pos = strchr(query, '&');
00133     const char* rest = query;
00134     if( sep_pos != NULL ){
00135         char query_options[5][20];
00136         float pmin = _pmin;
00137         float pmax = _pmax;
00138         float lt = _lt;
00139         float gt = _gt;
00140         float st = _st;
00141         float high = _high_step;
00142         float low = _low_step;
00143         uint8_t attr = _attribute_state;
00144 
00145         memset(query_options, 0, sizeof(query_options[0][0]) * 5 * 20);
00146         uint8_t num_options = 0;
00147         while( sep_pos != NULL && num_options < 5){
00148             size_t len = (size_t)(sep_pos-rest);
00149             if( len > 19 ){
00150                 len = 19;
00151             }
00152             memcpy(query_options[num_options], rest, len);
00153             sep_pos++;
00154             rest = sep_pos;
00155             sep_pos = strchr(rest, '&');
00156             num_options++;
00157         }
00158         if( num_options < 5 && strlen(rest) > 0){
00159             size_t len = (size_t)strlen(rest);
00160             if( len > 19 ){
00161                 len = 19;
00162             }
00163             memcpy(query_options[num_options++], rest, len);
00164         }
00165 
00166         for (int option = 0; option < num_options; option++) {
00167             success = set_notification_attribute(query_options[option],type, resource_type);
00168             if (!success) {
00169                 tr_debug("M2MReportHandler::parse_notification_attribute - break");
00170                 break;
00171             }
00172         }
00173 
00174         if(success) {
00175              success = check_attribute_validity();
00176         }
00177         else {
00178             tr_debug("M2MReportHandler::parse_notification_attribute - not valid query");
00179             _pmin = pmin;
00180             _pmax = pmax;
00181             _st = st;
00182             _lt = lt;
00183             _gt = gt;
00184             _high_step = high;
00185             _low_step = low;
00186             _attribute_state = attr;
00187         }
00188     }
00189     else {
00190         if(set_notification_attribute(query, type, resource_type)) {
00191             success = check_attribute_validity();
00192         }
00193     }
00194 
00195     return success;
00196 }
00197 
00198 void M2MReportHandler::timer_expired(M2MTimerObserver::Type type)
00199 {
00200     switch(type) {
00201         case M2MTimerObserver::PMinTimer: {
00202             tr_debug("M2MReportHandler::timer_expired - PMIN");
00203             _pmin_exceeded = true;
00204             if (_notify ||
00205                     (_pmin > 0 &&
00206                      (_attribute_state & M2MReportHandler::Pmax) != M2MReportHandler::Pmax)){
00207                 report();
00208             }
00209         }
00210         break;
00211         case M2MTimerObserver::PMaxTimer: {
00212             tr_debug("M2MReportHandler::timer_expired - PMAX");
00213             _pmax_exceeded = true;
00214             if (_pmin_exceeded ||
00215                     (_attribute_state & M2MReportHandler::Pmin) != M2MReportHandler::Pmin ) {
00216                 report();
00217             }
00218         }
00219         break;
00220         default:
00221             break;
00222     }
00223 }
00224 
00225 bool M2MReportHandler::set_notification_attribute(const char* option,
00226                                                   M2MBase::BaseType type,
00227                                                   M2MResourceInstance::ResourceType resource_type)
00228 {
00229     tr_debug("M2MReportHandler::set_notification_attribute()");
00230     bool success = false;
00231     char attribute[20];
00232     char value[20];
00233     memset(&attribute, 0, 20);
00234     memset(&value, 0, 20);
00235 
00236     const char* pos = strstr(option, EQUAL);
00237     if( pos != NULL ){
00238         memcpy(attribute, option, (size_t)(pos-option));
00239         pos++;
00240         memcpy(value, pos, strlen(pos));
00241     }else{
00242         memcpy(attribute, option, (size_t)strlen(option) + 1);
00243     }
00244 
00245     if (strlen(value)) {
00246         if (strcmp(attribute, PMIN) == 0) {
00247            _pmin = atoi(value);
00248             success = true;
00249             _attribute_state |= M2MReportHandler::Pmin;
00250             tr_info("M2MReportHandler::set_notification_attribute %s to %" PRId32, attribute, _pmin);
00251         }
00252         else if(strcmp(attribute, PMAX) == 0) {
00253             _pmax = atoi(value);
00254             success = true;
00255             _attribute_state |= M2MReportHandler::Pmax;
00256             tr_info("M2MReportHandler::set_notification_attribute %s to %" PRId32, attribute, _pmax);
00257         }
00258         else if(strcmp(attribute, GT) == 0 &&
00259                 (M2MBase::Resource == type)){
00260             _gt = atof(value);
00261             success = true;
00262             _attribute_state |= M2MReportHandler::Gt;
00263             tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _gt);
00264         }
00265         else if(strcmp(attribute, LT) == 0 &&
00266                 (M2MBase::Resource == type)){
00267             _lt = atof(value);
00268             success = true;
00269             _attribute_state |= M2MReportHandler::Lt;
00270             tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _lt);
00271         }
00272         else if((strcmp(attribute, ST_SIZE) == 0 || (strcmp(attribute, STP) == 0))
00273                 && (M2MBase::Resource == type)){
00274             _st = atof(value);
00275             success = true;
00276             _high_step = _current_value + _st;
00277             _low_step = _current_value - _st;
00278             _attribute_state |= M2MReportHandler::St;
00279             tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _st);
00280         }
00281         // Return false if try to set gt,lt or st when the resource type is something else than numerical
00282         if ((resource_type != M2MResourceInstance::INTEGER &&
00283                 resource_type != M2MResourceInstance::FLOAT) &&
00284                 ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt ||
00285                 (_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt ||
00286                 (_attribute_state & M2MReportHandler::St) == M2MReportHandler::St)) {
00287             tr_debug("M2MReportHandler::set_notification_attribute - not numerical resource");
00288             success = false;
00289         }
00290     }
00291     return success;
00292 }
00293 
00294 void M2MReportHandler::schedule_report()
00295 {
00296     tr_debug("M2MReportHandler::schedule_report()");
00297     _notify = true;
00298     if ((_attribute_state & M2MReportHandler::Pmin) != M2MReportHandler::Pmin ||
00299          _pmin_exceeded) {
00300         report();
00301     }
00302 }
00303 
00304 void M2MReportHandler::report()
00305 {
00306     tr_debug("M2MReportHandler::report()");
00307     if(_current_value != _last_value && _notify) {
00308         if (_pmin_exceeded) {
00309             tr_debug("M2MReportHandler::report()- send with PMIN expiration");
00310         } else {
00311             tr_debug("M2MReportHandler::report()- send with VALUE change");
00312         }
00313         _pmin_exceeded = false;
00314         _pmax_exceeded = false;
00315         _notify = false;
00316         _observation_number++;
00317         if(_observation_number == 1) {
00318             // Increment the observation number by 1 if it is already 1 because CoAP specification has reserved 1 for DEREGISTER notification
00319             _observation_number++;
00320         }
00321         _observer.observation_to_be_sent(_changed_instance_ids, observation_number());
00322         _changed_instance_ids.clear();
00323         _pmax_timer.stop_timer();
00324     }
00325     else {
00326         if (_pmax_exceeded) {
00327             tr_debug("M2MReportHandler::report()- send with PMAX expiration");
00328             _observation_number++;
00329             if(_observation_number == 1) {
00330                 // Increment the observation number by 1 if it is already 1 because CoAP specification has reserved 1 for DEREGISTER notification
00331                 _observation_number++;
00332             }
00333             _observer.observation_to_be_sent(_changed_instance_ids, observation_number(),true);
00334             _changed_instance_ids.clear();
00335         }
00336         else {
00337             tr_debug("M2MReportHandler::report()- no need to send");
00338         }
00339     }
00340     handle_timers();
00341     _last_value = _current_value;
00342 }
00343 
00344 void M2MReportHandler::handle_timers()
00345 {
00346     tr_debug("M2MReportHandler::handle_timers()");
00347     uint64_t time_interval = 0;
00348     if ((_attribute_state & M2MReportHandler::Pmin) == M2MReportHandler::Pmin) {
00349         if (_pmin == _pmax) {
00350             _pmin_exceeded = true;
00351         } else {
00352             _pmin_exceeded = false;
00353             time_interval = (uint64_t) ((uint64_t)_pmin * 1000);
00354             tr_debug("M2MReportHandler::handle_timers() - Start PMIN interval: %d", (int)time_interval);
00355             _pmin_timer.start_timer(time_interval,
00356                                      M2MTimerObserver::PMinTimer,
00357                                      true);
00358         }
00359     }
00360     if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax) {
00361         if (_pmax > 0) {
00362             time_interval = (uint64_t) ((uint64_t)_pmax * 1000);
00363             tr_debug("M2MReportHandler::handle_timers() - Start PMAX interval: %d", (int)time_interval);
00364             _pmax_timer.start_timer(time_interval,
00365                                      M2MTimerObserver::PMaxTimer,
00366                                      true);
00367         }
00368     }
00369 }
00370 
00371 bool M2MReportHandler::check_attribute_validity() const
00372 {
00373     bool success = true;
00374     if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax &&
00375             ((_pmax >= -1.0) && (_pmin > _pmax))) {
00376         success = false;
00377     }
00378     float low = _lt + 2 * _st;
00379     if ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt &&
00380             (low >= _gt)) {
00381         success = false;
00382     }
00383     return success;
00384 }
00385 
00386 void M2MReportHandler::stop_timers()
00387 {
00388     tr_debug("M2MReportHandler::stop_timers()");
00389 
00390     _pmin_exceeded = false;
00391     _pmin_timer.stop_timer();
00392 
00393     _pmax_exceeded = false;
00394     _pmax_timer.stop_timer();
00395 
00396     tr_debug("M2MReportHandler::stop_timers() - out");
00397 }
00398 
00399 void M2MReportHandler::set_default_values()
00400 {
00401     tr_debug("M2MReportHandler::set_default_values");
00402     _pmax = -1.0;
00403     _pmin = 1.0;
00404     _gt = 0.0f;
00405     _lt = 0.0f;
00406     _st = 0.0f;
00407     _high_step = 0.0f;
00408     _low_step = 0.0f;
00409     _pmin_exceeded = false;
00410     _pmax_exceeded = false;
00411     _last_value = -1.0f;
00412     _attribute_state = 0;
00413     _changed_instance_ids.clear();
00414 }
00415 
00416 bool M2MReportHandler::check_threshold_values() const
00417 {
00418     tr_debug("M2MReportHandler::check_threshold_values");
00419     tr_debug("Current value: %f", _current_value);
00420     tr_debug("High step: %f", _high_step);
00421     tr_debug("Low step: %f", _low_step);
00422     tr_debug("Less than: %f", _lt);
00423     tr_debug("Greater than: %f", _gt);
00424     tr_debug("Step: %f", _st);
00425     bool can_send = false;
00426     // Check step condition
00427     if ((_attribute_state & M2MReportHandler::St) == M2MReportHandler::St) {
00428         if ((_current_value >= _high_step ||
00429             _current_value <= _low_step)) {
00430             can_send = true;
00431         }
00432         else {
00433             if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt ||
00434                     (_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt ) {
00435                 can_send = check_gt_lt_params();
00436             }
00437             else {
00438                 can_send = false;
00439             }
00440         }
00441     }
00442     else {
00443         can_send = check_gt_lt_params();
00444     }
00445     tr_debug("M2MReportHandler::check_threshold_values - value in range = %d", (int)can_send);
00446     return can_send;
00447 }
00448 
00449 bool M2MReportHandler::check_gt_lt_params() const
00450 {
00451     tr_debug("M2MReportHandler::check_gt_lt_params");
00452     bool can_send = false;
00453     // GT & LT set.
00454     if ((_attribute_state & (M2MReportHandler::Lt | M2MReportHandler::Gt))
00455              == (M2MReportHandler::Lt | M2MReportHandler::Gt)) {
00456         if (_current_value > _gt || _current_value < _lt) {
00457             can_send = true;
00458         }
00459         else {
00460             can_send = false;
00461         }
00462     }
00463     // Only LT
00464     else if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt &&
00465            (_attribute_state & M2MReportHandler::Gt) == 0 ) {
00466         if (_current_value < _lt) {
00467             can_send = true;
00468         }
00469         else {
00470             can_send = false;
00471         }
00472     }
00473     // Only GT
00474     else if ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt &&
00475            (_attribute_state & M2MReportHandler::Lt) == 0 ) {
00476         if (_current_value > _gt) {
00477             can_send = true;
00478         }
00479         else {
00480             can_send = false;
00481         }
00482     }
00483     // GT & LT not set.
00484     else {
00485         can_send = true;
00486     }
00487     tr_debug("M2MReportHandler::check_gt_lt_params - value in range = %d", (int)can_send);
00488     return can_send;
00489 }
00490 
00491 uint8_t M2MReportHandler::attribute_flags() const
00492 {
00493     return _attribute_state;
00494 }
00495 
00496 void M2MReportHandler::set_observation_token(const uint8_t *token, const uint8_t length)
00497 {
00498      free(_token);
00499      _token = NULL;
00500      _token_length = 0;
00501 
00502     if( token != NULL && length > 0 ) {
00503         _token = alloc_string_copy((uint8_t *)token, length);
00504         if(_token) {
00505             _token_length = length;
00506         }
00507     }
00508 }
00509 
00510 void M2MReportHandler::get_observation_token(uint8_t *token, uint8_t &token_length) const
00511 {
00512     memcpy(token, _token, _token_length);
00513     token_length = _token_length;
00514 }
00515 
00516 uint16_t M2MReportHandler::observation_number() const
00517 {
00518     return _observation_number;
00519 }
00520 
00521 void M2MReportHandler::add_observation_level(M2MBase::Observation obs_level)
00522 {
00523     _observation_level = (M2MBase::Observation)(_observation_level | obs_level);
00524 }
00525 
00526 void M2MReportHandler::remove_observation_level(M2MBase::Observation obs_level)
00527 {
00528     _observation_level = (M2MBase::Observation)(_observation_level & ~obs_level);
00529 }
00530 
00531 M2MBase::Observation M2MReportHandler::observation_level() const
00532 {
00533     return _observation_level;
00534 }
00535 
00536 bool M2MReportHandler::is_under_observation() const
00537 {
00538     return _is_under_observation;
00539 }
00540 
00541 uint8_t* M2MReportHandler::alloc_string_copy(const uint8_t* source, uint32_t size)
00542 {
00543     assert(source != NULL);
00544 
00545     uint8_t* result = (uint8_t*)malloc(size + 1);
00546     if (result) {
00547         memcpy(result, source, size);
00548         result[size] = '\0';
00549     }
00550     return result;
00551 }