This is an example of BLE GATT Client, which receives broadcast data from BLE_Server_BME280 ( a GATT server) , then transfers values up to mbed Device Connector (cloud).
Please refer details about BLEClient_mbedDevConn below. https://github.com/soramame21/BLEClient_mbedDevConn
The location of required BLE GATT server, BLE_Server_BME280, is at here. https://developer.mbed.org/users/edamame22/code/BLE_Server_BME280/
Diff: mbed-client/source/m2mreporthandler.cpp
- Revision:
- 0:29983394c6b6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-client/source/m2mreporthandler.cpp Thu Apr 13 04:48:11 2017 +0000 @@ -0,0 +1,468 @@ +/* + * 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 "mbed-trace/mbed_trace.h" +#include <string.h> +#include <stdlib.h> + +#define TRACE_GROUP "mClt" + +M2MReportHandler::M2MReportHandler(M2MReportObserver &observer) +: _observer(observer), + _attribute_state(0), + _notify(false), + _pmin_exceeded(false), + _pmax_exceeded(false), + _pmin_timer(*this), + _pmax_timer(*this), + _pmax(-1.0f), + _pmin(1.0f), + _current_value(0.0f), + _gt(0.0f), + _lt(0.0f), + _st(0.0f), + _high_step(0.0f), + _low_step(0.0f), + _last_value(-1.0f) +{ + tr_debug("M2MReportHandler::M2MReportHandler()"); +} + +M2MReportHandler::~M2MReportHandler() +{ + tr_debug("M2MReportHandler::~M2MReportHandler()"); +} + +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 %f, last %f", value, _last_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"); + _pmin_timer.stop_timer(); + _pmin_exceeded = true; + } + } + _high_step = _current_value + _st; + _low_step = _current_value - _st; + } +} + +void M2MReportHandler::set_notification_trigger(uint16_t obj_instance_id) +{ + tr_debug("M2MReportHandler::set_notification_trigger(): %d", obj_instance_id); + // Add to array if not there yet + m2m::Vector<uint16_t>::const_iterator it; + it = _changed_instance_ids.begin(); + bool found = false; + for ( ; it != _changed_instance_ids.end(); it++) { + if ((*it) == obj_instance_id) { + found = true; + break; + } + } + if (!found) { + _changed_instance_ids.push_back(obj_instance_id); + } + + _current_value = 0.0f; + _last_value = 1.0f; + schedule_report(); +} + +bool M2MReportHandler::parse_notification_attribute(const 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; + const char* sep_pos = strchr(query, '&'); + const 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(const 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); + + const char* pos = strstr(option, EQUAL); + if( pos != NULL ){ + memcpy(attribute, option, (size_t)(pos-option)); + pos++; + memcpy(value, pos, strlen(pos)); + }else{ + memcpy(attribute, option, (size_t)strlen(option) + 1); + } + + if (strlen(value)) { + if (strcmp(attribute, PMIN) == 0) { + _pmin = atoi(value); + success = true; + _attribute_state |= M2MReportHandler::Pmin; + tr_debug("M2MReportHandler::set_notification_attribute %s to %d", attribute, _pmin); + } + else if(strcmp(attribute, PMAX) == 0) { + _pmax = atoi(value); + success = true; + _attribute_state |= M2MReportHandler::Pmax; + tr_debug("M2MReportHandler::set_notification_attribute %s to %d", attribute, _pmax); + } + else if(strcmp(attribute, GT) == 0 && + (M2MBase::Resource == type)){ + _gt = atof(value); + success = true; + _attribute_state |= M2MReportHandler::Gt; + tr_debug("M2MReportHandler::set_notification_attribute %s to %f", attribute, _gt); + } + else if(strcmp(attribute, LT) == 0 && + (M2MBase::Resource == type)){ + _lt = atof(value); + success = true; + _attribute_state |= M2MReportHandler::Lt; + tr_debug("M2MReportHandler::set_notification_attribute %s to %f", attribute, _lt); + } + else if((strcmp(attribute, ST_SIZE) == 0 || (strcmp(attribute, STP) == 0)) + && (M2MBase::Resource == type)){ + _st = atof(value); + 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); + } + // 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(_changed_instance_ids); + _changed_instance_ids.clear(); + _pmax_timer.stop_timer(); + } + else { + if (_pmax_exceeded) { + tr_debug("M2MReportHandler::report()- send with PMAX"); + _observer.observation_to_be_sent(_changed_instance_ids, true); + _changed_instance_ids.clear(); + } + 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) ((uint64_t)_pmin * 1000); + tr_debug("M2MReportHandler::handle_timers() - Start PMIN interval: %d", (int)time_interval); + _pmin_timer.start_timer(time_interval, + M2MTimerObserver::PMinTimer, + true); + } + } + if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax) { + if (_pmax > 0) { + time_interval = (uint64_t) ((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.0) && (_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()"); + + _pmin_exceeded = false; + _pmin_timer.stop_timer(); + + _pmax_exceeded = false; + _pmax_timer.stop_timer(); + + tr_debug("M2MReportHandler::stop_timers() - out"); +} + +void M2MReportHandler::set_default_values() +{ + tr_debug("M2MReportHandler::set_default_values"); + _pmax = -1.0; + _pmin = 1.0; + _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 = -1.0f; + _attribute_state = 0; + _changed_instance_ids.clear(); +} + +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; +}