Simulated product dispenser
Fork of mbed-cloud-workshop-connect-HTS221 by
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 19:12:13 by 1.7.2