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.
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 _notification_send_in_progress(false), 00054 _notification_in_queue(false), 00055 _blockwise_notify(false), 00056 _pmin_quiet_period(false) 00057 { 00058 tr_debug("M2MReportHandler::M2MReportHandler()"); 00059 } 00060 00061 M2MReportHandler::~M2MReportHandler() 00062 { 00063 tr_debug("M2MReportHandler::~M2MReportHandler()"); 00064 free(_token); 00065 } 00066 00067 void M2MReportHandler::set_under_observation(bool observed) 00068 { 00069 tr_debug("M2MReportHandler::set_under_observation(observed %d)", (int)observed); 00070 00071 _is_under_observation = observed; 00072 00073 stop_timers(); 00074 if (observed) { 00075 handle_timers(); 00076 } 00077 else { 00078 set_default_values(); 00079 } 00080 } 00081 00082 void M2MReportHandler::set_value(float value) 00083 { 00084 tr_debug("M2MReportHandler::set_value() - current %f, last %f", value, _last_value); 00085 _current_value = value; 00086 00087 if (_current_value != _last_value) { 00088 tr_debug("M2MReportHandler::set_value() - new value"); 00089 set_notification_in_queue(true); 00090 if (check_threshold_values()) { 00091 schedule_report(); 00092 } else { 00093 tr_debug("M2MReportHandler::set_value - value not in range"); 00094 _notify = false; 00095 if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt || 00096 (_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt || 00097 (_attribute_state & M2MReportHandler::St) == M2MReportHandler::St) { 00098 tr_debug("M2MReportHandler::set_value - stop pmin timer"); 00099 _pmin_timer.stop_timer(); 00100 _pmin_exceeded = true; 00101 } 00102 } 00103 _high_step = _last_value + _st; 00104 _low_step = _last_value - _st; 00105 } 00106 } 00107 00108 void M2MReportHandler::set_notification_trigger(uint16_t obj_instance_id) 00109 { 00110 tr_debug("M2MReportHandler::set_notification_trigger(): %d", obj_instance_id); 00111 // Add to array if not there yet 00112 m2m::Vector<uint16_t>::const_iterator it; 00113 it = _changed_instance_ids.begin(); 00114 bool found = false; 00115 for ( ; it != _changed_instance_ids.end(); it++) { 00116 if ((*it) == obj_instance_id) { 00117 found = true; 00118 break; 00119 } 00120 } 00121 if (!found) { 00122 _changed_instance_ids.push_back(obj_instance_id); 00123 } 00124 00125 _current_value = 0.0f; 00126 _last_value = 1.0f; 00127 set_notification_in_queue(true); 00128 schedule_report(); 00129 } 00130 00131 bool M2MReportHandler::parse_notification_attribute(const char *query, 00132 M2MBase::BaseType type, 00133 M2MResourceInstance::ResourceType resource_type) 00134 { 00135 tr_debug("M2MReportHandler::parse_notification_attribute(Query %s, Base type %d)", query, (int)type); 00136 bool success = false; 00137 const char* sep_pos = strchr(query, '&'); 00138 const char* rest = query; 00139 if( sep_pos != NULL ){ 00140 char query_options[5][20]; 00141 float pmin = _pmin; 00142 float pmax = _pmax; 00143 float lt = _lt; 00144 float gt = _gt; 00145 float st = _st; 00146 float high = _high_step; 00147 float low = _low_step; 00148 uint8_t attr = _attribute_state; 00149 00150 memset(query_options, 0, sizeof(query_options[0][0]) * 5 * 20); 00151 uint8_t num_options = 0; 00152 while( sep_pos != NULL && num_options < 5){ 00153 size_t len = (size_t)(sep_pos-rest); 00154 if( len > 19 ){ 00155 len = 19; 00156 } 00157 memcpy(query_options[num_options], rest, len); 00158 sep_pos++; 00159 rest = sep_pos; 00160 sep_pos = strchr(rest, '&'); 00161 num_options++; 00162 } 00163 if( num_options < 5 && strlen(rest) > 0){ 00164 size_t len = (size_t)strlen(rest); 00165 if( len > 19 ){ 00166 len = 19; 00167 } 00168 memcpy(query_options[num_options++], rest, len); 00169 } 00170 00171 for (int option = 0; option < num_options; option++) { 00172 success = set_notification_attribute(query_options[option],type, resource_type); 00173 if (!success) { 00174 tr_debug("M2MReportHandler::parse_notification_attribute - break"); 00175 break; 00176 } 00177 } 00178 00179 if(success) { 00180 success = check_attribute_validity(); 00181 } 00182 else { 00183 tr_debug("M2MReportHandler::parse_notification_attribute - not valid query"); 00184 _pmin = pmin; 00185 _pmax = pmax; 00186 _st = st; 00187 _lt = lt; 00188 _gt = gt; 00189 _high_step = high; 00190 _low_step = low; 00191 _attribute_state = attr; 00192 } 00193 } 00194 else { 00195 if(set_notification_attribute(query, type, resource_type)) { 00196 success = check_attribute_validity(); 00197 } 00198 } 00199 00200 return success; 00201 } 00202 00203 void M2MReportHandler::timer_expired(M2MTimerObserver::Type type) 00204 { 00205 switch(type) { 00206 case M2MTimerObserver::PMinTimer: { 00207 tr_debug("M2MReportHandler::timer_expired - PMIN"); 00208 00209 _pmin_exceeded = true; 00210 if (_notify || 00211 (_pmin > 0 && (_attribute_state & M2MReportHandler::Pmax) != M2MReportHandler::Pmax)){ 00212 report(); 00213 } 00214 00215 // If value hasn't changed since last expiration, next value change should send notification immediately 00216 if (_current_value == _last_value) { 00217 _pmin_quiet_period = true; 00218 } 00219 } 00220 break; 00221 case M2MTimerObserver::PMaxTimer: { 00222 tr_debug("M2MReportHandler::timer_expired - PMAX"); 00223 _pmax_exceeded = true; 00224 if (_pmin_exceeded || 00225 (_attribute_state & M2MReportHandler::Pmin) != M2MReportHandler::Pmin ) { 00226 report(); 00227 } 00228 } 00229 break; 00230 default: 00231 break; 00232 } 00233 } 00234 00235 bool M2MReportHandler::set_notification_attribute(const char* option, 00236 M2MBase::BaseType type, 00237 M2MResourceInstance::ResourceType resource_type) 00238 { 00239 tr_debug("M2MReportHandler::set_notification_attribute()"); 00240 bool success = false; 00241 char attribute[20]; 00242 char value[20]; 00243 memset(&attribute, 0, 20); 00244 memset(&value, 0, 20); 00245 00246 const char* pos = strstr(option, EQUAL); 00247 if( pos != NULL ){ 00248 memcpy(attribute, option, (size_t)(pos-option)); 00249 pos++; 00250 memcpy(value, pos, strlen(pos)); 00251 }else{ 00252 memcpy(attribute, option, (size_t)strlen(option) + 1); 00253 } 00254 00255 if (strlen(value)) { 00256 if (strcmp(attribute, PMIN) == 0) { 00257 _pmin = atoi(value); 00258 success = true; 00259 _attribute_state |= M2MReportHandler::Pmin; 00260 tr_info("M2MReportHandler::set_notification_attribute %s to %" PRId32, attribute, _pmin); 00261 } 00262 else if(strcmp(attribute, PMAX) == 0) { 00263 _pmax = atoi(value); 00264 success = true; 00265 _attribute_state |= M2MReportHandler::Pmax; 00266 tr_info("M2MReportHandler::set_notification_attribute %s to %" PRId32, attribute, _pmax); 00267 } 00268 else if(strcmp(attribute, GT) == 0 && 00269 (M2MBase::Resource == type)){ 00270 _gt = atof(value); 00271 success = true; 00272 _attribute_state |= M2MReportHandler::Gt; 00273 tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _gt); 00274 } 00275 else if(strcmp(attribute, LT) == 0 && 00276 (M2MBase::Resource == type)){ 00277 _lt = atof(value); 00278 success = true; 00279 _attribute_state |= M2MReportHandler::Lt; 00280 tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _lt); 00281 } 00282 else if((strcmp(attribute, ST_SIZE) == 0 || (strcmp(attribute, STP) == 0)) 00283 && (M2MBase::Resource == type)){ 00284 _st = atof(value); 00285 success = true; 00286 _high_step = _current_value + _st; 00287 _low_step = _current_value - _st; 00288 _attribute_state |= M2MReportHandler::St; 00289 tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _st); 00290 } 00291 // Return false if try to set gt,lt or st when the resource type is something else than numerical 00292 if ((resource_type != M2MResourceInstance::INTEGER && 00293 resource_type != M2MResourceInstance::FLOAT) && 00294 ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt || 00295 (_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt || 00296 (_attribute_state & M2MReportHandler::St) == M2MReportHandler::St)) { 00297 tr_debug("M2MReportHandler::set_notification_attribute - not numerical resource"); 00298 success = false; 00299 } 00300 } 00301 return success; 00302 } 00303 00304 void M2MReportHandler::schedule_report(bool in_queue) 00305 { 00306 tr_debug("M2MReportHandler::schedule_report()"); 00307 _notify = true; 00308 00309 if ((_attribute_state & M2MReportHandler::Pmin) != M2MReportHandler::Pmin || 00310 _pmin_exceeded || 00311 _pmin_quiet_period) { 00312 report(in_queue); 00313 } 00314 } 00315 00316 void M2MReportHandler::report(bool in_queue) 00317 { 00318 tr_debug("M2MReportHandler::report() - current %2f, last %2f, notify %d, queued %d", _current_value, _last_value, _notify, in_queue); 00319 00320 if((_current_value != _last_value && _notify) || in_queue) { 00321 if (_pmin_exceeded) { 00322 tr_debug("M2MReportHandler::report()- send with PMIN expiration"); 00323 } else { 00324 tr_debug("M2MReportHandler::report()- send with VALUE change"); 00325 } 00326 00327 _pmin_exceeded = false; 00328 _pmax_exceeded = false; 00329 _notify = false; 00330 _pmin_quiet_period = false; 00331 _observation_number++; 00332 00333 if (_observation_number == 1) { 00334 // Increment the observation number by 1 if it is already 1 because CoAP specification has reserved 1 for DEREGISTER notification 00335 _observation_number++; 00336 } 00337 00338 if (_observer.observation_to_be_sent(_changed_instance_ids, observation_number())) { 00339 _changed_instance_ids.clear(); 00340 set_notification_send_in_progress(true); 00341 } 00342 00343 _pmax_timer.stop_timer(); 00344 } 00345 else { 00346 if (_pmax_exceeded) { 00347 tr_debug("M2MReportHandler::report()- send with PMAX expiration"); 00348 _observation_number++; 00349 00350 if (_observation_number == 1) { 00351 // Increment the observation number by 1 if it is already 1 because CoAP specification has reserved 1 for DEREGISTER notification 00352 _observation_number++; 00353 } 00354 00355 if (_observer.observation_to_be_sent(_changed_instance_ids, observation_number(), true)) { 00356 _changed_instance_ids.clear(); 00357 set_notification_send_in_progress(true); 00358 } else { 00359 set_notification_in_queue(true); 00360 } 00361 } 00362 else { 00363 tr_debug("M2MReportHandler::report()- no need to send"); 00364 } 00365 } 00366 handle_timers(); 00367 _last_value = _current_value; 00368 } 00369 00370 void M2MReportHandler::handle_timers() 00371 { 00372 tr_debug("M2MReportHandler::handle_timers()"); 00373 uint64_t time_interval = 0; 00374 if ((_attribute_state & M2MReportHandler::Pmin) == M2MReportHandler::Pmin) { 00375 if (_pmin == _pmax) { 00376 _pmin_exceeded = true; 00377 } else { 00378 _pmin_exceeded = false; 00379 time_interval = (uint64_t) ((uint64_t)_pmin * 1000); 00380 tr_debug("M2MReportHandler::handle_timers() - Start PMIN interval: %d", (int)time_interval); 00381 _pmin_timer.start_timer(time_interval, 00382 M2MTimerObserver::PMinTimer, 00383 true); 00384 } 00385 } 00386 if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax) { 00387 if (_pmax > 0) { 00388 time_interval = (uint64_t) ((uint64_t)_pmax * 1000); 00389 tr_debug("M2MReportHandler::handle_timers() - Start PMAX interval: %d", (int)time_interval); 00390 _pmax_timer.start_timer(time_interval, 00391 M2MTimerObserver::PMaxTimer, 00392 true); 00393 } 00394 } 00395 } 00396 00397 bool M2MReportHandler::check_attribute_validity() const 00398 { 00399 bool success = true; 00400 if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax && 00401 ((_pmax >= -1.0) && (_pmin > _pmax))) { 00402 success = false; 00403 } 00404 float low = _lt + 2 * _st; 00405 if ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt && 00406 (low >= _gt)) { 00407 success = false; 00408 } 00409 return success; 00410 } 00411 00412 void M2MReportHandler::stop_timers() 00413 { 00414 tr_debug("M2MReportHandler::stop_timers()"); 00415 00416 _pmin_exceeded = false; 00417 _pmin_timer.stop_timer(); 00418 00419 _pmax_exceeded = false; 00420 _pmax_timer.stop_timer(); 00421 00422 tr_debug("M2MReportHandler::stop_timers() - out"); 00423 } 00424 00425 void M2MReportHandler::set_default_values() 00426 { 00427 tr_debug("M2MReportHandler::set_default_values"); 00428 _pmax = -1.0; 00429 _pmin = 1.0; 00430 _gt = 0.0f; 00431 _lt = 0.0f; 00432 _st = 0.0f; 00433 _high_step = 0.0f; 00434 _low_step = 0.0f; 00435 _pmin_exceeded = false; 00436 _pmax_exceeded = false; 00437 _last_value = -1.0f; 00438 _attribute_state = 0; 00439 _changed_instance_ids.clear(); 00440 _notification_in_queue = false; 00441 _notification_send_in_progress = false; 00442 _pmin_quiet_period = false; 00443 } 00444 00445 bool M2MReportHandler::check_threshold_values() const 00446 { 00447 tr_debug("M2MReportHandler::check_threshold_values"); 00448 tr_debug("Current value: %f", _current_value); 00449 tr_debug("Last value: %f", _last_value); 00450 tr_debug("High step: %f", _high_step); 00451 tr_debug("Low step: %f", _low_step); 00452 tr_debug("Less than: %f", _lt); 00453 tr_debug("Greater than: %f", _gt); 00454 tr_debug("Step: %f", _st); 00455 00456 bool can_send = check_gt_lt_params(); 00457 if (can_send) { 00458 if ((_attribute_state & M2MReportHandler::St) == M2MReportHandler::St) { 00459 if ((_current_value >= _high_step || 00460 _current_value <= _low_step)) { 00461 can_send = true; 00462 } else { 00463 can_send = false; 00464 } 00465 } 00466 } 00467 00468 tr_debug("M2MReportHandler::check_threshold_values - value can be sent = %d", (int)can_send); 00469 return can_send; 00470 } 00471 00472 bool M2MReportHandler::check_gt_lt_params() const 00473 { 00474 tr_debug("M2MReportHandler::check_gt_lt_params"); 00475 bool can_send = false; 00476 // GT & LT set. 00477 if ((_attribute_state & (M2MReportHandler::Lt | M2MReportHandler::Gt)) == 00478 (M2MReportHandler::Lt | M2MReportHandler::Gt)) { 00479 if (_current_value > _gt || _current_value < _lt) { 00480 can_send = true; 00481 } 00482 else { 00483 can_send = false; 00484 } 00485 } 00486 // Only LT 00487 else if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt && 00488 (_attribute_state & M2MReportHandler::Gt) == 0 ) { 00489 if (_current_value < _lt) { 00490 can_send = true; 00491 } 00492 else { 00493 can_send = false; 00494 } 00495 } 00496 // Only GT 00497 else if ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt && 00498 (_attribute_state & M2MReportHandler::Lt) == 0 ) { 00499 if (_current_value > _gt) { 00500 can_send = true; 00501 } 00502 else { 00503 can_send = false; 00504 } 00505 } 00506 // GT & LT not set. 00507 else { 00508 can_send = true; 00509 } 00510 tr_debug("M2MReportHandler::check_gt_lt_params - value in range = %d", (int)can_send); 00511 return can_send; 00512 } 00513 00514 uint8_t M2MReportHandler::attribute_flags() const 00515 { 00516 return _attribute_state; 00517 } 00518 00519 void M2MReportHandler::set_observation_token(const uint8_t *token, const uint8_t length) 00520 { 00521 free(_token); 00522 _token = NULL; 00523 _token_length = 0; 00524 00525 if( token != NULL && length > 0 ) { 00526 _token = alloc_string_copy((uint8_t *)token, length); 00527 if(_token) { 00528 _token_length = length; 00529 } 00530 } 00531 } 00532 00533 void M2MReportHandler::get_observation_token(uint8_t *token, uint8_t &token_length) const 00534 { 00535 memcpy(token, _token, _token_length); 00536 token_length = _token_length; 00537 } 00538 00539 uint16_t M2MReportHandler::observation_number() const 00540 { 00541 return _observation_number; 00542 } 00543 00544 void M2MReportHandler::add_observation_level(M2MBase::Observation obs_level) 00545 { 00546 _observation_level = (M2MBase::Observation)(_observation_level | obs_level); 00547 } 00548 00549 void M2MReportHandler::remove_observation_level(M2MBase::Observation obs_level) 00550 { 00551 _observation_level = (M2MBase::Observation)(_observation_level & ~obs_level); 00552 } 00553 00554 M2MBase::Observation M2MReportHandler::observation_level() const 00555 { 00556 return _observation_level; 00557 } 00558 00559 bool M2MReportHandler::is_under_observation() const 00560 { 00561 return _is_under_observation; 00562 } 00563 00564 uint8_t* M2MReportHandler::alloc_string_copy(const uint8_t* source, uint32_t size) 00565 { 00566 assert(source != NULL); 00567 00568 uint8_t* result = (uint8_t*)malloc(size + 1); 00569 if (result) { 00570 memcpy(result, source, size); 00571 result[size] = '\0'; 00572 } 00573 return result; 00574 } 00575 00576 void M2MReportHandler::set_notification_in_queue(bool to_queue) 00577 { 00578 _notification_in_queue = to_queue; 00579 } 00580 00581 bool M2MReportHandler::notification_in_queue() const 00582 { 00583 return _notification_in_queue; 00584 } 00585 00586 void M2MReportHandler::set_notification_send_in_progress(bool progress) 00587 { 00588 _notification_send_in_progress = progress; 00589 } 00590 00591 bool M2MReportHandler::notification_send_in_progress() const 00592 { 00593 return _notification_send_in_progress; 00594 } 00595 00596 void M2MReportHandler::set_blockwise_notify(bool blockwise_notify) 00597 { 00598 _blockwise_notify = blockwise_notify; 00599 } 00600 00601 bool M2MReportHandler::blockwise_notify() const 00602 { 00603 return _blockwise_notify; 00604 }
Generated on Tue Jul 12 2022 16:24:15 by
1.7.2