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.
m2mresourceinstance.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 #include <stdlib.h> 00017 #include "mbed-client/m2mresource.h" 00018 #include "mbed-client/m2mconstants.h" 00019 #include "mbed-client/m2mobservationhandler.h" 00020 #include "mbed-client/m2mobject.h" 00021 #include "mbed-client/m2mobjectinstance.h" 00022 #include "include/m2mreporthandler.h" 00023 #include "include/nsdllinker.h" 00024 #include "mbed-client/m2mblockmessage.h" 00025 #include "mbed-trace/mbed_trace.h" 00026 00027 #define TRACE_GROUP "mClt" 00028 00029 M2MResourceInstance::M2MResourceInstance(M2MResource &parent, 00030 const String &res_name, 00031 const String &resource_type, 00032 M2MResourceInstance::ResourceType type, 00033 const uint16_t object_instance_id, 00034 char* path, 00035 bool external_blockwise_store) 00036 : M2MBase(res_name, 00037 M2MBase::Dynamic, 00038 resource_type, 00039 path, 00040 external_blockwise_store), 00041 _parent_resource(parent), 00042 _value(NULL), 00043 _value_length(0), 00044 _block_message_data(NULL), 00045 _execute_callback(NULL), 00046 _resource_callback(NULL), 00047 _execute_function_pointer(NULL), 00048 _notification_sent_function_pointer(NULL), 00049 _incoming_block_message_cb(NULL), 00050 _outgoing_block_message_cb(NULL), 00051 _notification_sent_callback(NULL), 00052 _object_instance_id(object_instance_id), 00053 _resource_type(type) 00054 { 00055 M2MBase::set_base_type(M2MBase::ResourceInstance); 00056 } 00057 00058 M2MResourceInstance::M2MResourceInstance(M2MResource &parent, 00059 const String &res_name, 00060 const String &resource_type, 00061 M2MResourceInstance::ResourceType type, 00062 const uint8_t *value, 00063 const uint8_t value_length, 00064 const uint16_t object_instance_id, 00065 char* path, 00066 bool external_blockwise_store) 00067 : M2MBase(res_name, 00068 M2MBase::Static, 00069 resource_type, 00070 path, 00071 external_blockwise_store), 00072 _parent_resource(parent), 00073 _value(NULL), 00074 _value_length(0), 00075 _block_message_data(NULL), 00076 _execute_callback(NULL), 00077 _resource_callback(NULL), 00078 _execute_function_pointer(NULL), 00079 _notification_sent_function_pointer(NULL), 00080 _incoming_block_message_cb(NULL), 00081 _outgoing_block_message_cb(NULL), 00082 _notification_sent_callback(NULL), 00083 _object_instance_id(object_instance_id), 00084 _resource_type(type) 00085 { 00086 M2MBase::set_base_type(M2MBase::Resource); 00087 if (mode() == M2MBase::Dynamic) { 00088 if( value != NULL && value_length > 0 ) { 00089 _value = alloc_string_copy(value, value_length); 00090 if(_value) { 00091 _value_length = value_length; 00092 } 00093 } 00094 } 00095 // Copy resource value to struct since static resources are handled in mbed-client-c 00096 else if (mode() == M2MBase::Static) { 00097 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00098 sn_nsdl_static_resource_parameters_s* params = (sn_nsdl_static_resource_parameters_s*)res->static_resource_parameters; 00099 params->resource = alloc_string_copy(value, value_length); 00100 params->resourcelen = value_length; 00101 } 00102 else { 00103 // Directory, not supported 00104 } 00105 } 00106 00107 M2MResourceInstance::M2MResourceInstance(M2MResource &parent, 00108 const lwm2m_parameters_s* s, 00109 M2MResourceInstance::ResourceType type, 00110 const uint16_t object_instance_id) 00111 : M2MBase(s), 00112 _parent_resource(parent), 00113 _value(NULL), 00114 _value_length(0), 00115 _block_message_data(NULL), 00116 _execute_callback(NULL), 00117 _resource_callback(NULL), 00118 _execute_function_pointer(NULL), 00119 _notification_sent_function_pointer(NULL), 00120 _incoming_block_message_cb(NULL), 00121 _outgoing_block_message_cb(NULL), 00122 _notification_sent_callback(NULL), 00123 _object_instance_id(object_instance_id), 00124 _resource_type(type) 00125 { 00126 //TBD: put to flash, or parse from the uri_path!!!! 00127 //same for the _object_instance_id. 00128 // TBD: we dont need _value here, because in c-struct there is resource field!!!! 00129 if( s->dynamic_resource_params->static_resource_parameters->resource != NULL && 00130 s->dynamic_resource_params->static_resource_parameters->resourcelen > 0 ) { 00131 _value = alloc_string_copy(s->dynamic_resource_params->static_resource_parameters->resource, 00132 s->dynamic_resource_params->static_resource_parameters->resourcelen); 00133 if(_value) { 00134 _value_length = s->dynamic_resource_params->static_resource_parameters->resourcelen; 00135 } 00136 } 00137 //M2MBase::set_base_type(M2MBase::ResourceInstance); 00138 } 00139 00140 M2MResourceInstance::~M2MResourceInstance() 00141 { 00142 free(_value); 00143 delete _execute_function_pointer; 00144 delete _execute_callback; 00145 delete _notification_sent_function_pointer; 00146 delete _incoming_block_message_cb; 00147 delete _outgoing_block_message_cb; 00148 delete _notification_sent_callback; 00149 delete _block_message_data; 00150 } 00151 00152 M2MBase::BaseType M2MResourceInstance::base_type() const 00153 { 00154 return M2MBase::base_type(); 00155 } 00156 00157 M2MResourceInstance::ResourceType M2MResourceInstance::resource_instance_type() const 00158 { 00159 return _resource_type; 00160 } 00161 00162 bool M2MResourceInstance::handle_observation_attribute(const char *query) 00163 { 00164 tr_debug("M2MResourceInstance::handle_observation_attribute - is_under_observation(%d)", is_under_observation()); 00165 bool success = false; 00166 00167 M2MReportHandler *handler = M2MBase::report_handler(); 00168 if (!handler) { 00169 handler = M2MBase::create_report_handler(); 00170 } 00171 00172 if (handler) { 00173 success = handler->parse_notification_attribute(query, 00174 M2MBase::base_type(), _resource_type); 00175 if(success) { 00176 if (is_under_observation()) { 00177 handler->set_under_observation(true); 00178 } 00179 } else { 00180 handler->set_default_values(); 00181 } 00182 } 00183 return success; 00184 } 00185 00186 void M2MResourceInstance::set_execute_function(execute_callback callback) 00187 { 00188 delete _execute_callback; 00189 _execute_callback = new execute_callback (callback); 00190 } 00191 00192 void M2MResourceInstance::set_execute_function(execute_callback_2 callback) 00193 { 00194 delete _execute_function_pointer; 00195 00196 _execute_function_pointer = new FP1<void, void*> (callback); 00197 set_execute_function(execute_callback (_execute_function_pointer, &FP1<void, void*>::call)); 00198 } 00199 00200 void M2MResourceInstance::clear_value() 00201 { 00202 tr_debug("M2MResourceInstance::clear_value"); 00203 00204 free(_value); 00205 _value = NULL; 00206 _value_length = 0; 00207 00208 report(); 00209 } 00210 00211 bool M2MResourceInstance::set_value(int64_t value) 00212 { 00213 bool success; 00214 // max len of "-9223372036854775808" plus zero termination 00215 char buffer[20+1]; 00216 uint32_t size = m2m::itoa_c(value, buffer); 00217 00218 success = set_value((const uint8_t*)buffer, size); 00219 00220 return success; 00221 } 00222 00223 bool M2MResourceInstance::set_value(const uint8_t *value, 00224 const uint32_t value_length) 00225 { 00226 tr_debug("M2MResourceInstance::set_value()"); 00227 bool success = false; 00228 bool value_changed = false; 00229 if(is_value_changed(value,value_length)) { 00230 value_changed = true; 00231 } 00232 if( value != NULL && value_length > 0 ) { 00233 success = true; 00234 00235 free(_value); 00236 _value_length = 0; 00237 00238 _value = alloc_string_copy(value, value_length); 00239 if(_value) { 00240 _value_length = value_length; 00241 if( value_changed ) { // 00242 if (_resource_type == M2MResourceInstance::STRING) { 00243 M2MReportHandler *report_handler = M2MBase::report_handler(); 00244 if(report_handler && is_under_observation()) { 00245 report_handler->set_notification_trigger(); 00246 } 00247 } 00248 else { 00249 report(); 00250 } 00251 } 00252 } 00253 } 00254 return success; 00255 } 00256 00257 void M2MResourceInstance::report() 00258 { 00259 tr_debug("M2MResourceInstance::report()"); 00260 M2MBase::Observation observation_level = M2MBase::observation_level(); 00261 tr_debug("M2MResourceInstance::report() - level %d", observation_level); 00262 if((M2MBase::O_Attribute & observation_level) == M2MBase::O_Attribute || 00263 (M2MBase::OI_Attribute & observation_level) == M2MBase::OI_Attribute) { 00264 tr_debug("M2MResourceInstance::report() -- object/instance level"); 00265 M2MObjectInstance& object_instance = get_parent_resource().get_parent_object_instance(); 00266 object_instance.notification_update(observation_level); 00267 } 00268 00269 if(M2MBase::Dynamic == mode() && 00270 (M2MBase::R_Attribute & observation_level) == M2MBase::R_Attribute) { 00271 tr_debug("M2MResourceInstance::report() - resource level"); 00272 if(!_resource_callback && _resource_type != M2MResourceInstance::STRING) { 00273 M2MReportHandler *report_handler = M2MBase::report_handler(); 00274 if (report_handler && is_observable()) { 00275 if(_value) { 00276 report_handler->set_value(atof((const char*)_value)); 00277 } else { 00278 report_handler->set_value(0); 00279 } 00280 } 00281 } 00282 else { 00283 if (_resource_callback && base_type() == M2MBase::ResourceInstance) { 00284 _resource_callback->notification_update(); 00285 } 00286 } 00287 } else if(M2MBase::Static == mode()) { 00288 M2MObservationHandler *observation_handler = M2MBase::observation_handler(); 00289 if(observation_handler) { 00290 observation_handler->value_updated(this); 00291 } 00292 } else { 00293 tr_debug("M2MResourceInstance::report() - mode = %d, is_observable = %d", mode(), is_observable()); 00294 } 00295 } 00296 00297 bool M2MResourceInstance::is_value_changed(const uint8_t* value, const uint32_t value_len) 00298 { 00299 bool changed = false; 00300 if(value_len != _value_length) { 00301 changed = true; 00302 } else if(value && !_value) { 00303 changed = true; 00304 } else if(_value && !value) { 00305 changed = true; 00306 } else { 00307 if (_value) { 00308 if (strcmp((char*)value, (char*)_value) != 0) { 00309 changed = true; 00310 } 00311 } 00312 } 00313 tr_debug("M2MResourceInstance::is_value_changed() -- %s", changed ? "true" : "false"); 00314 return changed; 00315 } 00316 00317 void M2MResourceInstance::execute(void *arguments) 00318 { 00319 tr_debug("M2MResourceInstance::execute"); 00320 if(_execute_callback) { 00321 (*_execute_callback)(arguments); 00322 } 00323 } 00324 00325 void M2MResourceInstance::get_value(uint8_t *&value, uint32_t &value_length) 00326 { 00327 value_length = 0; 00328 if(value) { 00329 free(value); 00330 value = NULL; 00331 } 00332 if(_value && _value_length > 0) { 00333 value = alloc_string_copy(_value, _value_length); 00334 if(value) { 00335 value_length = _value_length; 00336 } 00337 } 00338 } 00339 00340 int M2MResourceInstance::get_value_int() 00341 { 00342 int value_int = 0; 00343 // Get the value and convert it into integer. This is not the most 00344 // efficient way, as it takes pointless heap copy to get the zero termination. 00345 uint8_t* buffer = NULL; 00346 uint32_t length; 00347 get_value(buffer,length); 00348 if(buffer) { 00349 value_int = atoi((const char*)buffer); 00350 free(buffer); 00351 } 00352 return value_int; 00353 } 00354 00355 String M2MResourceInstance::get_value_string() const 00356 { 00357 // XXX: do a better constructor to avoid pointless malloc 00358 String value; 00359 if (_value) { 00360 value.append_raw((char*)_value, _value_length); 00361 } 00362 00363 return value; 00364 } 00365 00366 uint8_t* M2MResourceInstance::value() const 00367 { 00368 return _value; 00369 } 00370 00371 uint32_t M2MResourceInstance::value_length() const 00372 { 00373 return _value_length; 00374 } 00375 00376 sn_coap_hdr_s* M2MResourceInstance::handle_get_request(nsdl_s *nsdl, 00377 sn_coap_hdr_s *received_coap_header, 00378 M2MObservationHandler *observation_handler) 00379 { 00380 tr_debug("M2MResourceInstance::handle_get_request()"); 00381 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00382 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00383 received_coap_header, 00384 msg_code); 00385 if(received_coap_header) { 00386 // process the GET if we have registered a callback for it 00387 if ((operation() & SN_GRS_GET_ALLOWED) != 0) { 00388 if(coap_response) { 00389 if(_resource_type == M2MResourceInstance::OPAQUE) { 00390 coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_OPAQUE_TYPE); 00391 } else { 00392 coap_response->content_format = sn_coap_content_format_e(0); 00393 } 00394 // fill in the CoAP response payload 00395 coap_response->payload_ptr = NULL; 00396 uint32_t payload_len = 0; 00397 00398 //If handler exists it means that resource value is stored in application side 00399 if (block_message() && block_message()->is_block_message()) { 00400 if(_outgoing_block_message_cb) { 00401 String name = ""; 00402 if (received_coap_header->uri_path_ptr != NULL && 00403 received_coap_header->uri_path_len > 0) { 00404 name.append_raw((char *)received_coap_header->uri_path_ptr, 00405 received_coap_header->uri_path_len); 00406 } 00407 (*_outgoing_block_message_cb)(name, coap_response->payload_ptr, payload_len); 00408 } 00409 } else { 00410 get_value(coap_response->payload_ptr,payload_len); 00411 } 00412 00413 coap_response->payload_len = payload_len; 00414 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); 00415 00416 coap_response->options_list_ptr->max_age = max_age(); 00417 00418 if(received_coap_header->options_list_ptr) { 00419 if(received_coap_header->options_list_ptr->observe != -1) { 00420 if (is_observable()) { 00421 uint32_t number = 0; 00422 uint8_t observe_option = 0; 00423 observe_option = received_coap_header->options_list_ptr->observe; 00424 00425 if(START_OBSERVATION == observe_option) { 00426 tr_debug("M2MResourceInstance::handle_get_request - Starts Observation"); 00427 // If the observe length is 0 means register for observation. 00428 if(received_coap_header->options_list_ptr->observe != -1) { 00429 number = received_coap_header->options_list_ptr->observe; 00430 } 00431 if(received_coap_header->token_ptr) { 00432 tr_debug("M2MResourceInstance::handle_get_request - Sets Observation Token to resource"); 00433 set_observation_token(received_coap_header->token_ptr, 00434 received_coap_header->token_len); 00435 } 00436 // If the observe value is 0 means register for observation. 00437 if(number == 0) { 00438 tr_debug("M2MResourceInstance::handle_get_request - Put Resource under Observation"); 00439 set_under_observation(true,observation_handler); 00440 M2MBase::add_observation_level(M2MBase::R_Attribute); 00441 coap_response->options_list_ptr->observe = observation_number(); 00442 } 00443 } else if (STOP_OBSERVATION == observe_option) { 00444 tr_debug("M2MResourceInstance::handle_get_request - Stops Observation"); 00445 set_under_observation(false,NULL); 00446 M2MBase::remove_observation_level(M2MBase::R_Attribute); 00447 } 00448 } else { 00449 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00450 } 00451 } 00452 } 00453 } 00454 }else { 00455 tr_error("M2MResourceInstance::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00456 // Operation is not allowed. 00457 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00458 } 00459 } else { 00460 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00461 } 00462 if(coap_response) { 00463 coap_response->msg_code = msg_code; 00464 } 00465 return coap_response; 00466 } 00467 00468 sn_coap_hdr_s* M2MResourceInstance::handle_put_request(nsdl_s *nsdl, 00469 sn_coap_hdr_s *received_coap_header, 00470 M2MObservationHandler *observation_handler, 00471 bool &execute_value_updated) 00472 { 00473 tr_debug("M2MResourceInstance::handle_put_request()"); 00474 00475 00476 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00477 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00478 received_coap_header, 00479 msg_code); 00480 // process the PUT if we have registered a callback for it 00481 if(received_coap_header && coap_response) { 00482 uint16_t coap_content_type = 0; 00483 if(received_coap_header->content_format != COAP_CT_NONE) { 00484 coap_content_type = received_coap_header->content_format; 00485 } 00486 if(received_coap_header->options_list_ptr && 00487 received_coap_header->options_list_ptr->uri_query_ptr) { 00488 char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, 00489 received_coap_header->options_list_ptr->uri_query_len); 00490 if (query){ 00491 tr_debug("M2MResourceInstance::handle_put_request() - Query %s", query); 00492 00493 // if anything was updated, re-initialize the stored notification attributes 00494 if (!handle_observation_attribute(query)){ 00495 tr_debug("M2MResourceInstance::handle_put_request() - Invalid query"); 00496 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 00497 } 00498 free(query); 00499 } 00500 } else if ((operation() & SN_GRS_PUT_ALLOWED) != 0) { 00501 tr_debug("M2MResourceInstance::handle_put_request() - Request Content-Type %d", coap_content_type); 00502 00503 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) { 00504 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; 00505 } else { 00506 bool external_block_store = false; 00507 if (block_message()) { 00508 block_message()->set_message_info(received_coap_header); 00509 if (block_message()->is_block_message()) { 00510 external_block_store = true; 00511 if(_incoming_block_message_cb) { 00512 (*_incoming_block_message_cb)(_block_message_data); 00513 } 00514 if (block_message()->is_last_block()) { 00515 block_message()->clear_values(); 00516 coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED; 00517 } else { 00518 coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING; 00519 } 00520 if (block_message()->error_code() != M2MBlockMessage::ErrorNone) { 00521 block_message()->clear_values(); 00522 } 00523 } 00524 } 00525 if (!external_block_store) { 00526 set_value(received_coap_header->payload_ptr, received_coap_header->payload_len); 00527 } 00528 if(received_coap_header->payload_ptr) { 00529 tr_debug("M2MResourceInstance::handle_put_request() - Update Resource with new values"); 00530 if(observation_handler) { 00531 String value = ""; 00532 if (received_coap_header->uri_path_ptr != NULL && 00533 received_coap_header->uri_path_len > 0) { 00534 value.append_raw((char*)received_coap_header->uri_path_ptr, received_coap_header->uri_path_len); 00535 } 00536 execute_value_updated = true; 00537 } 00538 } 00539 } 00540 } else { 00541 // Operation is not allowed. 00542 tr_error("M2MResourceInstance::handle_put_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00543 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00544 } 00545 } else { 00546 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00547 } 00548 if(coap_response) { 00549 coap_response->msg_code = msg_code; 00550 } 00551 00552 return coap_response; 00553 } 00554 00555 void M2MResourceInstance::set_resource_observer(M2MResourceCallback *resource) 00556 { 00557 _resource_callback = resource; 00558 } 00559 00560 uint16_t M2MResourceInstance::object_instance_id() const 00561 { 00562 return _object_instance_id; 00563 } 00564 00565 M2MBlockMessage* M2MResourceInstance::block_message() const 00566 { 00567 return _block_message_data; 00568 } 00569 00570 void M2MResourceInstance::set_incoming_block_message_callback(incoming_block_message_callback callback) 00571 { 00572 // copy the callback object. This will change on next version to be a direct pointer to a interface class, 00573 // this FPn<> is just too heavy for this usage. 00574 delete _incoming_block_message_cb; 00575 _incoming_block_message_cb = new incoming_block_message_callback(callback); 00576 00577 delete _block_message_data; 00578 _block_message_data = NULL; 00579 _block_message_data = new M2MBlockMessage(); 00580 } 00581 00582 void M2MResourceInstance::set_outgoing_block_message_callback(outgoing_block_message_callback callback) 00583 { 00584 delete _outgoing_block_message_cb; 00585 _outgoing_block_message_cb = new outgoing_block_message_callback(callback); 00586 } 00587 00588 void M2MResourceInstance::set_notification_sent_callback(notification_sent_callback callback) 00589 { 00590 delete _notification_sent_callback; 00591 _notification_sent_callback = new notification_sent_callback(callback); 00592 } 00593 00594 void M2MResourceInstance::set_notification_sent_callback(notification_sent_callback_2 callback) 00595 { 00596 delete _notification_sent_function_pointer; 00597 00598 _notification_sent_function_pointer = new FP0<void>(callback); 00599 set_notification_sent_callback( 00600 notification_sent_callback(_notification_sent_function_pointer, &FP0<void>::call)); 00601 } 00602 00603 void M2MResourceInstance::notification_sent() 00604 { 00605 if (_notification_sent_callback) { 00606 (*_notification_sent_callback)(); 00607 } 00608 } 00609 00610 M2MResource& M2MResourceInstance::get_parent_resource() const 00611 { 00612 return _parent_resource; 00613 } 00614 00615 const char* M2MResourceInstance::object_name() const 00616 { 00617 const M2MObjectInstance& parent_object_instance = _parent_resource.get_parent_object_instance(); 00618 const M2MObject& parent_object = parent_object_instance.get_parent_object(); 00619 00620 return parent_object.name(); 00621 }
Generated on Tue Jul 12 2022 21:20:28 by
