Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mbase.cpp Source File

m2mbase.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 #include "mbed-client/m2mbase.h"
00018 #include "mbed-client/m2mobservationhandler.h"
00019 #include "mbed-client/m2mconstants.h"
00020 #include "mbed-client/m2mtimer.h"
00021 
00022 #include "mbed-client/m2mendpoint.h"
00023 #include "mbed-client/m2mobject.h"
00024 #include "mbed-client/m2mobjectinstance.h"
00025 #include "mbed-client/m2mresource.h"
00026 
00027 #include "include/m2mreporthandler.h"
00028 #include "include/nsdlaccesshelper.h"
00029 #include "include/m2mcallbackstorage.h"
00030 #include "mbed-trace/mbed_trace.h"
00031 
00032 #include "sn_nsdl_lib.h"
00033 #include <assert.h>
00034 #include <ctype.h>
00035 #include <string.h>
00036 #include <stdlib.h>
00037 #include "common_functions.h"
00038 
00039 #define TRACE_GROUP "mClt"
00040 
00041 M2MBase::M2MBase(const String& resource_name,
00042                  M2MBase::Mode mode,
00043 #ifndef DISABLE_RESOURCE_TYPE
00044                  const String &resource_type,
00045 #endif
00046                  char *path,
00047                  bool external_blockwise_store,
00048                  bool multiple_instance,
00049                  M2MBase::DataType type)
00050 :
00051   _sn_resource(NULL),
00052   _report_handler(NULL)
00053 {
00054     // Checking the name length properly, i.e returning error is impossible from constructor without exceptions
00055     assert(resource_name.length() <= MAX_ALLOWED_STRING_LENGTH);
00056 
00057     _sn_resource = (lwm2m_parameters_s*)memory_alloc(sizeof(lwm2m_parameters_s));
00058     if(_sn_resource) {
00059         memset(_sn_resource, 0, sizeof(lwm2m_parameters_s));
00060         _sn_resource->free_on_delete = true;
00061         _sn_resource->multiple_instance = multiple_instance;
00062         _sn_resource->data_type = type;
00063         _sn_resource->read_write_callback_set = false;
00064         _sn_resource->dynamic_resource_params =
00065                 (sn_nsdl_dynamic_resource_parameters_s*)memory_alloc(sizeof(sn_nsdl_dynamic_resource_parameters_s));
00066         if(_sn_resource->dynamic_resource_params) {
00067             memset(_sn_resource->dynamic_resource_params,
00068                    0, sizeof(sn_nsdl_dynamic_resource_parameters_s));
00069             _sn_resource->dynamic_resource_params->static_resource_parameters =
00070                     (sn_nsdl_static_resource_parameters_s*)memory_alloc(sizeof(sn_nsdl_static_resource_parameters_s));
00071 
00072             // Set callback function in case of both dynamic and static resource
00073             _sn_resource->dynamic_resource_params->sn_grs_dyn_res_callback = __nsdl_c_callback;
00074 
00075             if(_sn_resource->dynamic_resource_params->static_resource_parameters) {
00076                 // Cast const away to able to compile using MEMORY_OPTIMIZED_API flag
00077                 sn_nsdl_static_resource_parameters_s *params =
00078                         const_cast<sn_nsdl_static_resource_parameters_s *>(_sn_resource->dynamic_resource_params->static_resource_parameters);
00079                 memset(params, 0, sizeof(sn_nsdl_static_resource_parameters_s));
00080                 const size_t len = strlen(resource_type.c_str());
00081                 params->free_on_delete = true;
00082                 if (len > 0) {
00083 #ifndef RESOURCE_ATTRIBUTES_LIST
00084 #ifndef DISABLE_RESOURCE_TYPE
00085                     params->resource_type_ptr = (char*)alloc_string_copy((uint8_t*) resource_type.c_str(), len);
00086 #endif
00087 #else
00088                     sn_nsdl_attribute_item_s item;
00089                     item.attribute_name = ATTR_RESOURCE_TYPE;
00090                     item.value = (char*)alloc_string_copy((uint8_t*) resource_type.c_str(), len);
00091                     sn_nsdl_set_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, &item);
00092 #endif
00093                 }
00094                 params->path = path;
00095                 params->mode = (unsigned)mode;
00096                 params->external_memory_block = external_blockwise_store;
00097                 _sn_resource->dynamic_resource_params->static_resource_parameters = params;
00098             }
00099         }
00100 
00101         if((!resource_name.empty())) {
00102             _sn_resource->identifier_int_type = false;
00103             _sn_resource->identifier.name = stringdup((char*)resource_name.c_str());
00104         } else {
00105             tr_debug("M2MBase::M2Mbase resource name is EMPTY ===========");
00106             _sn_resource->identifier_int_type = true;
00107             _sn_resource->identifier.instance_id = 0;
00108         }
00109         _sn_resource->dynamic_resource_params->publish_uri = true;
00110         _sn_resource->dynamic_resource_params->free_on_delete = true;
00111         _sn_resource->dynamic_resource_params->auto_observable = false;
00112         _sn_resource->dynamic_resource_params->publish_value = false;
00113     }
00114 }
00115 
00116 M2MBase::M2MBase(const lwm2m_parameters_s *s):
00117     _sn_resource((lwm2m_parameters_s*) s),
00118     _report_handler(NULL)
00119 {
00120     tr_debug("M2MBase::M2MBase(const lwm2m_parameters_s *s)");
00121     // Set callback function in case of both dynamic and static resource
00122     _sn_resource->dynamic_resource_params->sn_grs_dyn_res_callback = __nsdl_c_callback;
00123 }
00124 
00125 M2MBase::~M2MBase()
00126 {
00127     tr_debug("M2MBase::~M2MBase() %p", this);
00128     delete _report_handler;
00129 
00130     value_updated_callback* callback = (value_updated_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback);
00131     delete callback;
00132 
00133     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2);
00134     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback);
00135 #ifdef ENABLE_ASYNC_REST_RESPONSE
00136     M2MCallbackStorage::remove_callback(*this,M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback);
00137 #endif
00138 }
00139 
00140 char* M2MBase::create_path_base(const M2MBase &parent, const char *name)
00141 {
00142     char * result = NULL;
00143     // Expectation is that every element can be MAX_NAME_SZE, + 4 /'s + \0
00144     StringBuffer<(MAX_NAME_SIZE * 4 + (4 + 1))> path;
00145     path.append(parent.uri_path());
00146     path.append('/');
00147     path.append(name);
00148     result = stringdup(path.c_str());
00149 
00150     return result;
00151 }
00152 
00153 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION
00154 char* M2MBase::create_path(const M2MEndpoint &parent, const char *name)
00155 {
00156     return create_path_base(parent, name);
00157 }
00158 #endif
00159 
00160 char* M2MBase::create_path(const M2MObject &parent, uint16_t object_instance)
00161 {
00162     StringBuffer<6> obj_inst_id;
00163     obj_inst_id.append_int(object_instance);
00164 
00165     return create_path_base(parent, obj_inst_id.c_str());
00166 }
00167 
00168 char* M2MBase::create_path(const M2MObject &parent, const char *name)
00169 {
00170     return create_path_base(parent, name);
00171 }
00172 
00173 char* M2MBase::create_path(const M2MResource &parent, uint16_t resource_instance)
00174 {
00175     StringBuffer<6> res_inst;
00176     res_inst.append_int(resource_instance);
00177 
00178     return create_path_base(parent, res_inst.c_str());
00179 }
00180 
00181 char* M2MBase::create_path(const M2MResource &parent, const char *name)
00182 {
00183     return create_path_base(parent, name);
00184 }
00185 
00186 char* M2MBase::create_path(const M2MObjectInstance &parent, const char *name)
00187 {
00188     return create_path_base(parent, name);
00189 }
00190 
00191 void M2MBase::set_operation(M2MBase::Operation opr)
00192 {
00193     // If the mode is Static, there is only GET_ALLOWED supported.
00194     if(M2MBase::Static == mode()) {
00195         _sn_resource->dynamic_resource_params->access = M2MBase::GET_ALLOWED;
00196     } else {
00197         _sn_resource->dynamic_resource_params->access = opr;
00198     }
00199 }
00200 
00201 #ifndef RESOURCE_ATTRIBUTES_LIST
00202 #ifndef MEMORY_OPTIMIZED_API
00203 #ifndef DISABLE_INTERFACE_DESCRIPTION
00204 void M2MBase::set_interface_description(const char *desc)
00205 {
00206     assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete);
00207     free(_sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr);
00208     _sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr = NULL;
00209     const size_t len = strlen(desc);
00210     if (len > 0 ) {
00211         _sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr =
00212                 (char*)alloc_string_copy((uint8_t*) desc, len);
00213     }
00214     set_changed();
00215 }
00216 
00217 void M2MBase::set_interface_description(const String &desc)
00218 {
00219     assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete);
00220     set_interface_description(desc.c_str());
00221 }
00222 #endif // DISABLE_INTERFACE_DESCRIPTION
00223 
00224 #ifndef DISABLE_RESOURCE_TYPE
00225 void M2MBase::set_resource_type(const String &res_type)
00226 {
00227     assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete);
00228     set_resource_type(res_type.c_str());
00229 }
00230 
00231 void M2MBase::set_resource_type(const char *res_type)
00232 {
00233     assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete);
00234     free(_sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr);
00235     _sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr = NULL;
00236     const size_t len = strlen(res_type);
00237     if (len > 0) {
00238         _sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr = (char*)
00239                 alloc_string_copy((uint8_t*) res_type, len);
00240     }
00241     set_changed();
00242 }
00243 #endif // DISABLE_RESOURCE_TYPE
00244 #endif //MEMORY_OPTIMIZED_API
00245 #else // RESOURCE_ATTRIBUTES_LIST
00246 void M2MBase::set_interface_description(const char *desc)
00247 {
00248     assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete);
00249     const size_t len = strlen(desc);
00250     if (len > 0 ) {
00251         sn_nsdl_attribute_item_s item;
00252         item.attribute_name = ATTR_INTERFACE_DESCRIPTION;
00253         item.value = (char*)alloc_string_copy((uint8_t*) desc, len);
00254         sn_nsdl_set_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, &item);
00255         set_changed();
00256     }
00257 }
00258 
00259 void M2MBase::set_interface_description(const String &desc)
00260 {
00261     assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete);
00262     set_interface_description(desc.c_str());
00263 }
00264 
00265 void M2MBase::set_resource_type(const String &res_type)
00266 {
00267     assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete);
00268     set_resource_type(res_type.c_str());
00269 }
00270 
00271 void M2MBase::set_resource_type(const char *res_type)
00272 {
00273     assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete);
00274     const size_t len = strlen(res_type);
00275     if (len > 0) {
00276         sn_nsdl_attribute_item_s item;
00277         item.attribute_name = ATTR_RESOURCE_TYPE;
00278         item.value = (char*)alloc_string_copy((uint8_t*) res_type, len);
00279         sn_nsdl_set_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, &item);
00280         set_changed();
00281     }
00282 }
00283 #endif // RESOURCE_ATTRIBUTES_LIST
00284 
00285 void M2MBase::set_coap_content_type(const uint16_t con_type)
00286 {
00287     _sn_resource->dynamic_resource_params->coap_content_type = con_type;
00288     set_changed();
00289 }
00290 
00291 void M2MBase::set_observable(bool observable)
00292 {
00293     _sn_resource->dynamic_resource_params->observable = observable;
00294     set_changed();
00295 }
00296 
00297 void M2MBase::set_auto_observable(bool auto_observable)
00298 {
00299     _sn_resource->dynamic_resource_params->auto_observable = auto_observable;
00300     set_changed();
00301 }
00302 
00303 void M2MBase::add_observation_level(M2MBase::Observation obs_level)
00304 {
00305     if(_report_handler) {
00306         _report_handler->add_observation_level(obs_level);
00307     }
00308 }
00309 
00310 void M2MBase::remove_observation_level(M2MBase::Observation obs_level)
00311 {
00312     if(_report_handler) {
00313         _report_handler->remove_observation_level(obs_level);
00314     }
00315 }
00316 
00317 
00318 void M2MBase::set_under_observation(bool observed,
00319                                     M2MObservationHandler *handler)
00320 {
00321     tr_debug("M2MBase::set_under_observation - observed: %d", observed);
00322     tr_debug("M2MBase::set_under_observation - base_type: %d", base_type());
00323     if(_report_handler) {
00324         _report_handler->set_under_observation(observed);
00325     }
00326 
00327     set_observation_handler(handler);
00328 
00329     if (handler) {
00330         if (base_type() != M2MBase::ResourceInstance) {
00331             // Create report handler only if it does not exist and one wants observation
00332             // This saves 76 bytes of memory on most usual case.
00333             if (observed) {
00334                 if(!_report_handler) {
00335                     _report_handler = new M2MReportHandler(*this, _sn_resource->data_type);
00336                 }
00337             }
00338             if (_report_handler) {
00339                 _report_handler->set_under_observation(observed);
00340             }
00341         }
00342     } else {
00343         delete _report_handler;
00344         _report_handler = NULL;
00345     }
00346 }
00347 
00348 void M2MBase::set_observation_token(const uint8_t *token, const uint8_t length)
00349 {
00350     if (_report_handler) {
00351         _report_handler->set_observation_token(token, length);
00352         // This relates to sn_nsdl_auto_obs_token_callback in sn_nsdl.c
00353         set_changed();
00354     }
00355 }
00356 
00357 void M2MBase::set_instance_id(const uint16_t inst_id)
00358 {
00359     _sn_resource->identifier_int_type = true;
00360     _sn_resource->identifier.instance_id = inst_id;
00361 }
00362 
00363 void M2MBase::set_max_age(const uint32_t max_age)
00364 {
00365     _sn_resource->max_age = max_age;
00366 }
00367 
00368 M2MBase::BaseType M2MBase::base_type() const
00369 {
00370     return (M2MBase::BaseType)_sn_resource->base_type;
00371 }
00372 
00373 M2MBase::Operation M2MBase::operation() const
00374 {
00375     return (M2MBase::Operation)_sn_resource->dynamic_resource_params->access;
00376 }
00377 
00378 const char* M2MBase::name() const
00379 {
00380     assert(_sn_resource->identifier_int_type == false);
00381     return _sn_resource->identifier.name;
00382 }
00383 
00384 int32_t M2MBase::name_id() const
00385 {
00386     int32_t name_id = -1;
00387     assert(_sn_resource->identifier_int_type == false);
00388     if(is_integer(_sn_resource->identifier.name) && strlen(_sn_resource->identifier.name) <= MAX_ALLOWED_STRING_LENGTH) {
00389         name_id = strtoul(_sn_resource->identifier.name, NULL, 10);
00390         if(name_id > 65535){
00391             name_id = -1;
00392         }
00393     }
00394     return name_id;
00395 }
00396 
00397 uint16_t M2MBase::instance_id() const
00398 {
00399     assert(_sn_resource->identifier_int_type == true);
00400     return _sn_resource->identifier.instance_id;
00401 }
00402 
00403 #ifndef RESOURCE_ATTRIBUTES_LIST
00404 #ifndef DISABLE_INTERFACE_DESCRIPTION
00405 #ifndef MEMORY_OPTIMIZED_API
00406 const char* M2MBase::interface_description() const
00407 {
00408     return (reinterpret_cast<char*>(
00409         _sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr));
00410 }
00411 #endif
00412 #endif
00413 
00414 #ifndef DISABLE_RESOURCE_TYPE
00415 #ifndef MEMORY_OPTIMIZED_API
00416 const char* M2MBase::resource_type() const
00417 {
00418     return (reinterpret_cast<char*>(
00419         _sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr));
00420 }
00421 #endif
00422 #endif
00423 #else // RESOURCE_ATTRIBUTES_LIST
00424 #ifndef DISABLE_INTERFACE_DESCRIPTION
00425 const char* M2MBase::interface_description() const
00426 {
00427     return sn_nsdl_get_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, ATTR_INTERFACE_DESCRIPTION);
00428 }
00429 #endif
00430 
00431 #ifndef DISABLE_RESOURCE_TYPE
00432 const char* M2MBase::resource_type() const
00433 {
00434     return sn_nsdl_get_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, ATTR_RESOURCE_TYPE);
00435 }
00436 #endif
00437 #endif // RESOURCE_ATTRIBUTES_LIST
00438 const char* M2MBase::uri_path() const
00439 {
00440     return (reinterpret_cast<char*>(
00441         _sn_resource->dynamic_resource_params->static_resource_parameters->path));
00442 }
00443 
00444 uint16_t M2MBase::coap_content_type() const
00445 {
00446     return _sn_resource->dynamic_resource_params->coap_content_type;
00447 }
00448 
00449 bool M2MBase::is_observable() const
00450 {
00451     return _sn_resource->dynamic_resource_params->observable;
00452 }
00453 
00454 bool M2MBase::is_auto_observable() const
00455 {
00456     return _sn_resource->dynamic_resource_params->auto_observable;
00457 }
00458 
00459 M2MBase::Observation M2MBase::observation_level() const
00460 {
00461     M2MBase::Observation obs_level = M2MBase::None;
00462     if(_report_handler) {
00463         obs_level = _report_handler->observation_level();
00464     }
00465     return obs_level;
00466 }
00467 
00468 void M2MBase::get_observation_token(uint8_t *token, uint8_t &token_length) const
00469 {
00470     if(_report_handler) {
00471         _report_handler->get_observation_token(token, token_length);
00472     }
00473 }
00474 
00475 M2MBase::Mode M2MBase::mode() const
00476 {
00477     return (M2MBase::Mode)_sn_resource->dynamic_resource_params->static_resource_parameters->mode;
00478 }
00479 
00480 uint16_t M2MBase::observation_number() const
00481 {
00482     uint16_t obs_number = 0;
00483     if(_report_handler) {
00484         obs_number = _report_handler->observation_number();
00485     }
00486     return obs_number;
00487 }
00488 
00489 uint32_t M2MBase::max_age() const
00490 {
00491     return _sn_resource->max_age;
00492 }
00493 
00494 bool M2MBase::handle_observation_attribute(const char *query)
00495 {
00496     tr_debug("M2MBase::handle_observation_attribute - under observation(%d)", is_under_observation());
00497     bool success = false;
00498     // Create handler if not already exists. Client must able to parse write attributes even when
00499     // observation is not yet set
00500     if (!_report_handler) {
00501         _report_handler = new M2MReportHandler(*this, _sn_resource->data_type);
00502     }
00503 
00504     success = _report_handler->parse_notification_attribute(query,base_type());
00505     if (success) {
00506         if (is_under_observation()) {
00507             _report_handler->set_under_observation(true);
00508         }
00509      } else {
00510         _report_handler->set_default_values();
00511     }
00512     return success;
00513 }
00514 
00515 bool M2MBase::observation_to_be_sent(const m2m::Vector<uint16_t> &changed_instance_ids,
00516                                      uint16_t obs_number,
00517                                      bool send_object)
00518 {
00519     //TODO: Move this to M2MResourceInstance
00520     M2MObservationHandler *obs_handler = observation_handler();
00521     if (obs_handler) {
00522         return obs_handler->observation_to_be_sent(this,
00523                                             obs_number,
00524                                             changed_instance_ids,
00525                                             send_object);
00526     }
00527     return false;
00528 }
00529 
00530 void M2MBase::set_base_type(M2MBase::BaseType type)
00531 {
00532     assert(_sn_resource->free_on_delete);
00533     _sn_resource->base_type = type;
00534 }
00535 
00536 sn_coap_hdr_s* M2MBase::handle_get_request(nsdl_s */*nsdl*/,
00537                                            sn_coap_hdr_s */*received_coap_header*/,
00538                                            M2MObservationHandler */*observation_handler*/)
00539 {
00540     //Handled in M2MResource, M2MObjectInstance and M2MObject classes
00541     return NULL;
00542 }
00543 
00544 sn_coap_hdr_s* M2MBase::handle_put_request(nsdl_s */*nsdl*/,
00545                                            sn_coap_hdr_s */*received_coap_header*/,
00546                                            M2MObservationHandler */*observation_handler*/,
00547                                            bool &)
00548 {
00549     //Handled in M2MResource, M2MObjectInstance and M2MObject classes
00550     return NULL;
00551 }
00552 
00553 sn_coap_hdr_s* M2MBase::handle_post_request(nsdl_s */*nsdl*/,
00554                                             sn_coap_hdr_s */*received_coap_header*/,
00555                                             M2MObservationHandler */*observation_handler*/,
00556                                             bool &,
00557                                             sn_nsdl_addr_s *)
00558 {
00559     //Handled in M2MResource, M2MObjectInstance and M2MObject classes
00560     return NULL;
00561 }
00562 
00563 void *M2MBase::memory_alloc(uint32_t size)
00564 {
00565     if(size)
00566         return malloc(size);
00567     else
00568         return 0;
00569 }
00570 
00571 void M2MBase::memory_free(void *ptr)
00572 {
00573     free(ptr);
00574 }
00575 
00576 char* M2MBase::alloc_string_copy(const char* source)
00577 {
00578     assert(source != NULL);
00579 
00580     // Note: the armcc's libc does not have strdup, so we need to implement it here
00581     const size_t len = strlen(source);
00582 
00583     return (char*)alloc_string_copy((uint8_t*)source, len);
00584 }
00585 
00586 uint8_t* M2MBase::alloc_string_copy(const uint8_t* source, uint32_t size)
00587 {
00588     assert(source != NULL);
00589 
00590     uint8_t* result = (uint8_t*)memory_alloc(size + 1);
00591     if (result) {
00592         memcpy(result, source, size);
00593         result[size] = '\0';
00594     }
00595     return result;
00596 }
00597 
00598 uint8_t* M2MBase::alloc_copy(const uint8_t* source, uint32_t size)
00599 {
00600     assert(source != NULL);
00601 
00602     uint8_t* result = (uint8_t*)memory_alloc(size);
00603     if (result) {
00604         memcpy(result, source, size);
00605     }
00606     return result;
00607 }
00608 
00609 bool M2MBase::validate_string_length(const String &string, size_t min_length, size_t max_length)
00610 {
00611     bool valid = false;
00612 
00613     const size_t len = string.length();
00614     if ((len >= min_length) && (len <= max_length)) {
00615         valid = true;
00616     }
00617 
00618     return valid;
00619 }
00620 
00621 bool M2MBase::validate_string_length(const char* string, size_t min_length, size_t max_length)
00622 {
00623     bool valid = false;
00624 
00625     if (string != NULL) {
00626         const size_t len = strlen(string);
00627         if ((len >= min_length) && (len <= max_length)) {
00628             valid = true;
00629         }
00630     }
00631     return valid;
00632 }
00633 
00634 M2MReportHandler* M2MBase::create_report_handler()
00635 {
00636     if (!_report_handler) {
00637         _report_handler = new M2MReportHandler(*this, _sn_resource->data_type);
00638     }
00639     return _report_handler;
00640 }
00641 
00642 M2MReportHandler* M2MBase::report_handler() const
00643 {
00644     return _report_handler;
00645 }
00646 
00647 void M2MBase::set_register_uri(bool register_uri)
00648 {
00649     _sn_resource->dynamic_resource_params->publish_uri = register_uri;
00650 }
00651 
00652 bool M2MBase::register_uri()
00653 {
00654     return _sn_resource->dynamic_resource_params->publish_uri;
00655 }
00656 
00657 bool M2MBase::is_integer(const String &value)
00658 {
00659     const char *s = value.c_str();
00660     if(value.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) {
00661         return false;
00662     }
00663     char * p;
00664     strtol(value.c_str(), &p, 10);
00665     return (*p == 0);
00666 }
00667 
00668 bool M2MBase::is_integer(const char *value)
00669 {
00670     assert(value != NULL);
00671 
00672     if((strlen(value) < 1) || ((!isdigit(value[0])) && (value[0] != '-') && (value[0] != '+'))) {
00673         return false;
00674     }
00675     char * p;
00676     strtol(value, &p, 10);
00677     return (*p == 0);
00678 }
00679 
00680 bool M2MBase::is_under_observation() const
00681 {
00682    bool under_observation = false;
00683     if(_report_handler) {
00684         under_observation = _report_handler->is_under_observation();
00685     }
00686     return under_observation;
00687 }
00688 
00689 bool M2MBase::set_value_updated_function(value_updated_callback callback)
00690 {
00691     value_updated_callback* old_callback = (value_updated_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback);
00692     delete old_callback;
00693     // XXX: create a copy of the copy of callback object. Perhaps it would better to
00694     // give a reference as parameter and just store that, as it would save some memory.
00695     value_updated_callback* new_callback = new value_updated_callback(callback);
00696 
00697     return M2MCallbackStorage::add_callback(*this, new_callback, M2MCallbackAssociation::M2MBaseValueUpdatedCallback);
00698 }
00699 
00700 bool M2MBase::set_value_updated_function(value_updated_callback2 callback)
00701 {
00702     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2);
00703 
00704     return M2MCallbackStorage::add_callback(*this, (void*)callback, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2);
00705 }
00706 
00707 bool M2MBase::is_value_updated_function_set() const
00708 {
00709     bool func_set = false;
00710     if ((M2MCallbackStorage::does_callback_exist(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback) == true) ||
00711         (M2MCallbackStorage::does_callback_exist(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2) == true)) {
00712 
00713         func_set = true;
00714     }
00715     return func_set;
00716 }
00717 
00718 void M2MBase::execute_value_updated(const String& name)
00719 {
00720     // Q: is there a point to call both callback types? Or should we call just one of them?
00721 
00722     value_updated_callback* callback = (value_updated_callback*)M2MCallbackStorage::get_callback(*this,
00723                                                                                                  M2MCallbackAssociation::M2MBaseValueUpdatedCallback);
00724     if (callback) {
00725         (*callback)(name.c_str());
00726     }
00727 
00728     value_updated_callback2 callback2 = (value_updated_callback2)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2);
00729     if (callback2) {
00730         (*callback2)(name.c_str());
00731     }
00732 }
00733 
00734 bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE> &buffer, const char *s1, uint16_t i1, const char *s2, uint16_t i2)
00735 {
00736 
00737     if(!buffer.ensure_space(strlen(s1) + strlen(s2) + (MAX_INSTANCE_SIZE * 2) + 3 + 1)){
00738         return false;
00739     }
00740 
00741     buffer.append(s1);
00742     buffer.append('/');
00743     buffer.append_int(i1);
00744     buffer.append('/');
00745     buffer.append(s2);
00746     buffer.append('/');
00747     buffer.append_int(i2);
00748 
00749     return true;
00750 
00751 }
00752 
00753 bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE_2> &buffer, const char *s1, uint16_t i1, const char *s2)
00754 {
00755     if(!buffer.ensure_space(strlen(s1) + strlen(s2) + MAX_INSTANCE_SIZE + 2 + 1)){
00756         return false;
00757     }
00758 
00759     buffer.append(s1);
00760     buffer.append('/');
00761     buffer.append_int(i1);
00762     buffer.append('/');
00763     buffer.append(s2);
00764 
00765     return true;
00766 }
00767 
00768 bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE_3> &buffer, const char *s1, uint16_t i1, uint16_t i2)
00769 {
00770     if(!buffer.ensure_space(strlen(s1) + (MAX_INSTANCE_SIZE * 2) + 2 + 1)){
00771         return false;
00772     }
00773 
00774     buffer.append(s1);
00775     buffer.append('/');
00776     buffer.append_int(i1);
00777     buffer.append('/');
00778     buffer.append_int(i2);
00779 
00780     return true;
00781 }
00782 
00783 bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE_4> &buffer, const char *s1, uint16_t i1)
00784 {
00785     if(!buffer.ensure_space(strlen(s1) + MAX_INSTANCE_SIZE + 1 + 1)){
00786         return false;
00787     }
00788 
00789     buffer.append(s1);
00790     buffer.append('/');
00791     buffer.append_int(i1);
00792 
00793     return true;
00794 }
00795 
00796 char* M2MBase::stringdup(const char* src)
00797 {
00798     assert(src != NULL);
00799 
00800     const size_t len = strlen(src) + 1;
00801 
00802     char *dest = (char*)malloc(len);
00803 
00804     if (dest) {
00805         memcpy(dest, src, len);
00806     }
00807     return dest;
00808 }
00809 
00810 void M2MBase::free_resources()
00811 {
00812     // remove the nsdl structures from the nsdlinterface's lists.
00813     M2MObservationHandler *obs_handler = observation_handler();
00814     if (obs_handler) {
00815         tr_debug("M2MBase::free_resources()");
00816         obs_handler->resource_to_be_deleted(this);
00817     }
00818 
00819     if (_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete) {
00820         sn_nsdl_static_resource_parameters_s *params =
00821                 const_cast<sn_nsdl_static_resource_parameters_s *>(_sn_resource->dynamic_resource_params->static_resource_parameters);
00822 
00823         free(params->path);
00824         //free(params->resource);
00825 #ifndef RESOURCE_ATTRIBUTES_LIST
00826 #ifndef DISABLE_RESOURCE_TYPE
00827         free(params->resource_type_ptr);
00828 #endif
00829 #ifndef DISABLE_INTERFACE_DESCRIPTION
00830         free(params->interface_description_ptr);
00831 #endif
00832 #else
00833         sn_nsdl_free_resource_attributes_list(_sn_resource->dynamic_resource_params->static_resource_parameters);
00834 #endif
00835         free(params);
00836     }
00837     if (_sn_resource->dynamic_resource_params->free_on_delete) {
00838         free(_sn_resource->dynamic_resource_params->resource);
00839         free(_sn_resource->dynamic_resource_params);
00840     }
00841 
00842     if(_sn_resource->free_on_delete && _sn_resource->identifier_int_type == false) {
00843         tr_debug("M2MBase::free_resources()");
00844         free(_sn_resource->identifier.name);
00845     }
00846     if(_sn_resource->free_on_delete) {
00847         free(_sn_resource);
00848     }
00849 }
00850 
00851 size_t M2MBase::resource_name_length() const
00852 {
00853     assert(_sn_resource->identifier_int_type == false);
00854     return strlen(_sn_resource->identifier.name);
00855 }
00856 
00857 sn_nsdl_dynamic_resource_parameters_s* M2MBase::get_nsdl_resource() const
00858 {
00859     return _sn_resource->dynamic_resource_params;
00860 }
00861 
00862 M2MBase::lwm2m_parameters_s* M2MBase::get_lwm2m_parameters() const
00863 {
00864     return _sn_resource;
00865 }
00866 
00867 #ifdef ENABLE_ASYNC_REST_RESPONSE
00868 bool M2MBase::send_async_response_with_code(const uint8_t *payload,
00869                                             size_t payload_len,
00870                                             const uint8_t* token,
00871                                             const uint8_t token_len,
00872                                             coap_response_code_e code)
00873 {
00874     bool success = false;
00875     if(is_async_coap_request_callback_set()) {
00876         success = true;
00877         // At least on some unit tests the resource object is not fully constructed, which would
00878         // cause issues if the observation_handler is NULL. So do the check before dereferencing pointer.
00879         M2MObservationHandler* obs = observation_handler();
00880         if (obs) {
00881             obs->send_asynchronous_response(this, payload, payload_len, token, token_len, code);
00882         }
00883     }
00884     return success;
00885 }
00886 
00887 bool M2MBase::set_async_coap_request_cb(handle_async_coap_request_cb callback, void *client_args)
00888 {
00889     M2MCallbackStorage::remove_callback(*this,
00890                                         M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback);
00891 
00892     return M2MCallbackStorage::add_callback(*this,
00893                                             (void*)callback,
00894                                             M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback,
00895                                             client_args);
00896 }
00897 
00898 void M2MBase::call_async_coap_request_callback(sn_coap_hdr_s *coap_request,
00899                                                M2MBase::Operation operation,
00900                                                bool &handled)
00901 {
00902     M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(*this,
00903                                                                             M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback);
00904     if (item) {
00905         handle_async_coap_request_cb callback = (handle_async_coap_request_cb)item->_callback;
00906         assert(callback);
00907         assert(coap_request);
00908         handled = true;
00909         (*callback)(*this,
00910                     operation,
00911                     coap_request->token_ptr,
00912                     coap_request->token_len,
00913                     coap_request->payload_ptr,
00914                     coap_request->payload_len,
00915                     item->_client_args);
00916     }
00917 }
00918 
00919 bool M2MBase::is_async_coap_request_callback_set()
00920 {
00921     M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(*this, M2MCallbackAssociation::M2MBaseAsyncCoapRequestCallback);
00922     return (item) ? true : false;
00923 
00924 }
00925 #endif // ENABLE_ASYNC_REST_RESPONSE
00926 
00927 uint16_t M2MBase::get_notification_msgid() const
00928 {
00929     return 0;
00930 }
00931 
00932 void M2MBase::set_notification_msgid(uint16_t /*msgid*/)
00933 {
00934 
00935 }
00936 
00937 bool M2MBase::set_notification_delivery_status_cb(notification_delivery_status_cb callback, void *client_args)
00938 {
00939     M2MCallbackStorage::remove_callback(*this,
00940                                         M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback);
00941 
00942     return M2MCallbackStorage::add_callback(*this,
00943                                             (void*)callback,
00944                                             M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback,
00945                                             client_args);
00946 }
00947 
00948 bool M2MBase::set_message_delivery_status_cb(message_delivery_status_cb callback, void *client_args)
00949 {
00950     M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseMessageDeliveryStatusCallback);
00951 
00952     return M2MCallbackStorage::add_callback(*this,
00953                                             (void*)callback,
00954                                             M2MCallbackAssociation::M2MBaseMessageDeliveryStatusCallback,
00955                                             client_args);
00956 }
00957 
00958 void M2MBase::send_notification_delivery_status(const M2MBase& object, const NotificationDeliveryStatus status)
00959 {
00960     M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(object,
00961                                                                             M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback);
00962     if (item) {
00963         notification_delivery_status_cb callback = (notification_delivery_status_cb)item->_callback;
00964         if (callback) {
00965             (*callback)(object, status, item->_client_args);
00966         }
00967     }
00968 }
00969 
00970 void M2MBase::send_message_delivery_status(const M2MBase& object, const MessageDeliveryStatus status, const MessageType type)
00971 {
00972     M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(object,
00973                                                                             M2MCallbackAssociation::M2MBaseMessageDeliveryStatusCallback);
00974     if (item) {
00975         message_delivery_status_cb callback = (message_delivery_status_cb)item->_callback;
00976         if (callback) {
00977             (*callback)(object, status, type, item->_client_args);
00978         }
00979     }
00980 }
00981 
00982 void M2MBase::set_changed()
00983 {
00984 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION
00985     M2MBase *parent = get_parent();
00986     if (parent) {
00987         parent->set_changed();
00988     }
00989 #endif
00990 }
00991 
00992 M2MBase *M2MBase::get_parent() const
00993 {
00994     return NULL;
00995 }
00996 
00997 bool M2MBase::is_blockwise_needed(const nsdl_s *nsdl, uint32_t payload_len)
00998 {
00999 
01000     uint16_t block_size = sn_nsdl_get_block_size(nsdl);
01001 
01002     if (payload_len > block_size && block_size > 0) {
01003         return true;
01004     } else {
01005         return false;
01006     }
01007 }
01008 
01009 void M2MBase::handle_observation(nsdl_s *nsdl,
01010                                  const sn_coap_hdr_s &received_coap_header,
01011                                  sn_coap_hdr_s &coap_response,
01012                                  M2MObservationHandler *observation_handler,
01013                                  sn_coap_msg_code_e &response_code)
01014 {
01015     tr_debug("M2MBase::handle_observation()");
01016     assert(nsdl);
01017     assert(received_coap_header.options_list_ptr);
01018 
01019     response_code = COAP_MSG_CODE_RESPONSE_CONTENT;
01020 
01021     if (is_auto_observable() || received_coap_header.token_ptr == NULL) {
01022         tr_error("M2MBase::handle_observation() - already auto-observable or missing token!");
01023         response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST;
01024         return;
01025     }
01026 
01027     if (!is_observable()) {
01028         tr_error("M2MBase::handle_observation() - not observable!");
01029         response_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED;
01030         return;
01031     }
01032 
01033     // Add observe value to response
01034     if (coap_response.options_list_ptr) {
01035         coap_response.options_list_ptr->observe = observation_number();
01036     }
01037 
01038     // In case of blockwise, delivery status callback is handled in m2mnsdlinterface after all the block have been transfered
01039     if (M2MBase::is_blockwise_needed(nsdl, coap_response.payload_len)) {
01040         tr_debug("M2MBase::handle_observation() - block message");
01041         return;
01042     }
01043 
01044     uint32_t obs_number = received_coap_header.options_list_ptr->observe;
01045 
01046     // If the observe number is 0 means register for observation.
01047     if (START_OBSERVATION == obs_number) {
01048 
01049         start_observation(received_coap_header, observation_handler);
01050 
01051     } else if (STOP_OBSERVATION == obs_number) {
01052         tr_info("M2MBase::handle_observation() - stops observation");
01053 
01054         set_under_observation(false, NULL);
01055         send_notification_delivery_status(*this, NOTIFICATION_STATUS_UNSUBSCRIBED);
01056         send_message_delivery_status(*this, M2MBase::MESSAGE_STATUS_UNSUBSCRIBED, M2MBase::NOTIFICATION);
01057 
01058         switch (base_type()) {
01059             case M2MBase::Object:
01060                 M2MBase::remove_observation_level(M2MBase::O_Attribute);
01061                 break;
01062 
01063             case M2MBase::ObjectInstance:
01064                 M2MBase::remove_observation_level(M2MBase::OI_Attribute);
01065                 break;
01066 
01067             case M2MBase::Resource:
01068             case M2MBase::ResourceInstance:
01069                 M2MBase::remove_observation_level(M2MBase::R_Attribute);
01070                 break;
01071 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION
01072             case M2MBase::ObjectDirectory:
01073                 // Observation not supported!
01074                 break;
01075 #endif
01076         }
01077     }
01078 }
01079 
01080 void M2MBase::start_observation(const sn_coap_hdr_s &received_coap_header, M2MObservationHandler *observation_handler)
01081 {
01082     set_under_observation(true, observation_handler);
01083 
01084     switch (base_type()) {
01085         case M2MBase::Object:
01086             M2MBase::add_observation_level(M2MBase::O_Attribute);
01087             break;
01088 
01089         case M2MBase::ObjectInstance:
01090             M2MBase::add_observation_level(M2MBase::OI_Attribute);
01091             break;
01092 
01093         case M2MBase::Resource:
01094         case M2MBase::ResourceInstance:
01095             M2MBase::add_observation_level(M2MBase::R_Attribute);
01096             break;
01097 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION
01098         case M2MBase::ObjectDirectory:
01099             // Observation not supported!
01100             break;
01101 #endif
01102     }
01103 
01104     send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED);
01105     send_message_delivery_status(*this, M2MBase::MESSAGE_STATUS_SUBSCRIBED, M2MBase::NOTIFICATION);
01106 
01107     set_observation_token(received_coap_header.token_ptr,
01108                           received_coap_header.token_len);
01109 
01110 }
01111 
01112 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION
01113 
01114 void M2MBase::set_deleted()
01115 {
01116     // no-op
01117 }
01118 
01119 bool M2MBase::is_deleted()
01120 {
01121     return false;
01122 }
01123 
01124 #endif // MBED_CLOUD_CLIENT_EDGE_EXTENSION