Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Tue Jul 12 2022 19:01:35 by 1.7.2