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.
m2mresourcebase.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 // Needed for PRIu64 on FreeRTOS 00018 #include <stdio.h> 00019 // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX 00020 #ifndef __STDC_LIMIT_MACROS 00021 #define __STDC_LIMIT_MACROS 00022 #endif 00023 00024 // Note: this macro is needed on armcc to get the the PRI*32 macros 00025 // from inttypes.h in a C++ code. 00026 #ifndef __STDC_FORMAT_MACROS 00027 #define __STDC_FORMAT_MACROS 00028 #endif 00029 00030 #include <stdlib.h> 00031 #include "mbed-client/m2mresourcebase.h" 00032 #include "mbed-client/m2mconstants.h" 00033 #include "mbed-client/m2mobservationhandler.h" 00034 #include "mbed-client/m2mobject.h" 00035 #include "mbed-client/m2mobjectinstance.h" 00036 #include "include/m2mcallbackstorage.h" 00037 #include "include/m2mreporthandler.h" 00038 #include "include/nsdllinker.h" 00039 #include "include/m2mtlvserializer.h" 00040 #include "mbed-client/m2mblockmessage.h" 00041 #include "mbed-trace/mbed_trace.h" 00042 00043 #define TRACE_GROUP "mClt" 00044 00045 // -9223372036854775808 - +9223372036854775807 00046 // max length of int64_t string is 20 bytes + nil 00047 #define REGISTRY_INT64_STRING_MAX_LEN 21 00048 // (space needed for -3.402823 × 10^38) + (magic decimal 6 digits added as no precision is added to "%f") + trailing zero 00049 #define REGISTRY_FLOAT_STRING_MAX_LEN 48 00050 00051 00052 00053 M2MResourceBase::M2MResourceBase( 00054 const String &res_name, 00055 M2MBase::Mode resource_mode, 00056 const String &resource_type, 00057 M2MBase::DataType type, 00058 char* path, 00059 bool external_blockwise_store, 00060 bool multiple_instance) 00061 : M2MBase(res_name, 00062 resource_mode, 00063 #ifndef DISABLE_RESOURCE_TYPE 00064 resource_type, 00065 #endif 00066 path, 00067 external_blockwise_store, 00068 multiple_instance, 00069 type) 00070 #ifndef DISABLE_BLOCK_MESSAGE 00071 ,_block_message_data(NULL), 00072 #endif 00073 _notification_status(M2MResourceBase::INIT) 00074 { 00075 } 00076 00077 M2MResourceBase::M2MResourceBase( 00078 const String &res_name, 00079 M2MBase::Mode resource_mode, 00080 const String &resource_type, 00081 M2MBase::DataType type, 00082 const uint8_t *value, 00083 const uint8_t value_length, 00084 char* path, 00085 bool external_blockwise_store, 00086 bool multiple_instance) 00087 : M2MBase(res_name, 00088 resource_mode, 00089 #ifndef DISABLE_RESOURCE_TYPE 00090 resource_type, 00091 #endif 00092 path, 00093 external_blockwise_store, 00094 multiple_instance, 00095 type) 00096 #ifndef DISABLE_BLOCK_MESSAGE 00097 ,_block_message_data(NULL), 00098 #endif 00099 _notification_status(M2MResourceBase::INIT) 00100 { 00101 M2MBase::set_base_type(M2MBase::ResourceInstance); 00102 if( value != NULL && value_length > 0 ) { 00103 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00104 res->resource = alloc_string_copy(value, value_length); 00105 res->resource_len = value_length; 00106 } 00107 } 00108 00109 M2MResourceBase::M2MResourceBase( 00110 const lwm2m_parameters_s* s, 00111 M2MBase::DataType /*type*/) 00112 : M2MBase(s) 00113 #ifndef DISABLE_BLOCK_MESSAGE 00114 ,_block_message_data(NULL), 00115 #endif 00116 _notification_status(M2MResourceBase::INIT) 00117 { 00118 // we are not there yet for this check as this is called from M2MResource(): assert(base_type() == M2MBase::ResourceInstance); 00119 } 00120 00121 M2MResourceBase::~M2MResourceBase() 00122 { 00123 execute_callback* callback = (execute_callback*)M2MCallbackStorage::remove_callback(*this, 00124 M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); 00125 delete callback; 00126 00127 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); 00128 #ifndef DISABLE_BLOCK_MESSAGE 00129 incoming_block_message_callback *in_callback = (incoming_block_message_callback*)M2MCallbackStorage::remove_callback(*this, 00130 M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); 00131 delete in_callback; 00132 00133 outgoing_block_message_callback *out_callback = (outgoing_block_message_callback*)M2MCallbackStorage::remove_callback(*this, 00134 M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); 00135 delete out_callback; 00136 #endif 00137 00138 notification_sent_callback *notif_callback = (notification_sent_callback*)M2MCallbackStorage::remove_callback(*this, 00139 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); 00140 delete notif_callback; 00141 00142 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); 00143 00144 notification_status_callback *notif_status_callback = (notification_status_callback*)M2MCallbackStorage::remove_callback(*this, 00145 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); 00146 delete notif_status_callback; 00147 00148 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); 00149 00150 #ifndef DISABLE_BLOCK_MESSAGE 00151 delete _block_message_data; 00152 #endif 00153 } 00154 00155 M2MResourceBase::ResourceType M2MResourceBase::resource_instance_type() const 00156 { 00157 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00158 M2MBase::DataType type = param->data_type; 00159 return convert_data_type(type); 00160 } 00161 00162 00163 bool M2MResourceBase::set_execute_function(execute_callback callback) 00164 { 00165 execute_callback* old_callback = (execute_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); 00166 delete old_callback; 00167 // XXX: create a copy of the copy of callback object. Perhaps it would better to 00168 // give a reference as parameter and just store that, as it would save some memory. 00169 execute_callback* new_callback = new execute_callback(callback); 00170 00171 return M2MCallbackStorage::add_callback(*this, new_callback, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); 00172 } 00173 00174 bool M2MResourceBase::set_execute_function(execute_callback_2 callback) 00175 { 00176 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); 00177 00178 return M2MCallbackStorage::add_callback(*this, (void*)callback, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); 00179 } 00180 00181 bool M2MResourceBase::set_resource_read_callback(read_resource_value_callback callback, void *client_args) 00182 { 00183 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueReadCallback); 00184 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00185 param->read_write_callback_set = true; 00186 return M2MCallbackStorage::add_callback(*this, 00187 (void*)callback, 00188 M2MCallbackAssociation::M2MResourceBaseValueReadCallback, 00189 client_args); 00190 00191 } 00192 00193 bool M2MResourceBase::set_resource_write_callback(write_resource_value_callback callback, void *client_args) 00194 { 00195 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueWriteCallback); 00196 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00197 param->read_write_callback_set = true; 00198 00199 return M2MCallbackStorage::add_callback(*this, 00200 (void*)callback, 00201 M2MCallbackAssociation::M2MResourceBaseValueWriteCallback, 00202 client_args); 00203 } 00204 00205 void M2MResourceBase::clear_value() 00206 { 00207 tr_debug("M2MResourceBase::clear_value"); 00208 00209 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00210 free(res->resource); 00211 res->resource = NULL; 00212 res->resource_len = 0; 00213 00214 report(); 00215 } 00216 00217 bool M2MResourceBase::set_value_float(float value) 00218 { 00219 bool success; 00220 char buffer[REGISTRY_FLOAT_STRING_MAX_LEN]; 00221 00222 // Convert value to string 00223 /* write the float value to a decimal number string and copy it into a buffer allocated for caller */ 00224 uint32_t size = snprintf(buffer, REGISTRY_FLOAT_STRING_MAX_LEN, "%f", value); 00225 00226 success = set_value((const uint8_t*)buffer, size); 00227 00228 return success; 00229 } 00230 00231 bool M2MResourceBase::set_value(int64_t value) 00232 { 00233 bool success; 00234 char buffer[REGISTRY_INT64_STRING_MAX_LEN]; 00235 uint32_t size = m2m::itoa_c(value, buffer); 00236 00237 success = set_value((const uint8_t*)buffer, size); 00238 00239 return success; 00240 } 00241 00242 bool M2MResourceBase::set_value(const uint8_t *value, 00243 const uint32_t value_length) 00244 { 00245 tr_debug("M2MResourceBase::set_value()"); 00246 bool success = false; 00247 if( value != NULL && value_length > 0 ) { 00248 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00249 if (param->read_write_callback_set) { 00250 return write_resource_value(*this, value, value_length); 00251 } else { 00252 uint8_t *value_copy = alloc_string_copy(value, value_length); 00253 if (value_copy) { 00254 value_set_callback callback = (value_set_callback)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueSetCallback); 00255 if (callback) { 00256 (*callback)((const M2MResourceBase*)this, value_copy, value_length); 00257 } 00258 else { 00259 update_value(value_copy, value_length); 00260 } 00261 success = true; 00262 } 00263 } 00264 } 00265 return success; 00266 } 00267 00268 bool M2MResourceBase::set_value_raw(uint8_t *value, 00269 const uint32_t value_length) 00270 00271 { 00272 tr_debug("M2MResourceBase::set_value_raw()"); 00273 bool success = false; 00274 if( value != NULL && value_length > 0 ) { 00275 success = true; 00276 value_set_callback callback = (value_set_callback)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueSetCallback); 00277 if (callback) { 00278 (*callback)((const M2MResourceBase*)this, value, value_length); 00279 } 00280 else { 00281 update_value(value, value_length); 00282 } 00283 } 00284 return success; 00285 } 00286 00287 void M2MResourceBase::update_value(uint8_t *value, const uint32_t value_length) 00288 { 00289 bool changed = has_value_changed(value,value_length); 00290 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00291 free(res->resource); 00292 res->resource = value; 00293 res->resource_len = value_length; 00294 if (changed) { 00295 report_value_change(); 00296 } 00297 } 00298 00299 void M2MResourceBase::report() 00300 { 00301 M2MBase::Observation observation_level = M2MBase::observation_level(); 00302 tr_debug("M2MResourceBase::report() - level %d", observation_level); 00303 00304 // We must combine the parent object/objectinstance/resource observation information 00305 // when determining if there is observation set or not. 00306 M2MObjectInstance& object_instance = get_parent_resource().get_parent_object_instance(); 00307 int parent_observation_level = (int)object_instance.observation_level(); 00308 00309 parent_observation_level |= (int)object_instance.get_parent_object().observation_level(); 00310 parent_observation_level |= (int)get_parent_resource().observation_level(); 00311 parent_observation_level |= (int)observation_level; 00312 00313 tr_debug("M2MResourceBase::report() - combined level %d", parent_observation_level); 00314 00315 if((M2MBase::O_Attribute & parent_observation_level) == M2MBase::O_Attribute || 00316 (M2MBase::OI_Attribute & parent_observation_level) == M2MBase::OI_Attribute) { 00317 tr_debug("M2MResourceBase::report() -- object/instance level"); 00318 M2MObjectInstance& object_instance = get_parent_resource().get_parent_object_instance(); 00319 object_instance.notification_update((M2MBase::Observation)parent_observation_level); 00320 } 00321 00322 if(M2MBase::Dynamic == mode() && 00323 (M2MBase::R_Attribute & parent_observation_level) == M2MBase::R_Attribute) { 00324 tr_debug("M2MResourceBase::report() - resource level"); 00325 00326 if (((resource_instance_type() != M2MResourceBase::STRING) && 00327 (resource_instance_type() != M2MResourceBase::OPAQUE)) && 00328 (observation_level != M2MBase::None)) { 00329 M2MReportHandler *report_handler = M2MBase::report_handler(); 00330 if (report_handler && is_observable()) { 00331 const float float_value = get_value_float(); 00332 report_handler->set_value(float_value); 00333 } 00334 } 00335 else { 00336 if (base_type() == M2MBase::ResourceInstance) { 00337 const M2MResource& parent_resource = get_parent_resource(); 00338 M2MReportHandler *report_handler = parent_resource.report_handler(); 00339 if(report_handler && parent_resource.is_observable()) { 00340 report_handler->set_notification_trigger(parent_resource.get_parent_object_instance().instance_id()); 00341 } 00342 } 00343 } 00344 } else if(M2MBase::Static == mode()) { 00345 M2MObservationHandler *obs_handler = observation_handler(); 00346 if(obs_handler) { 00347 obs_handler->value_updated(this); 00348 } 00349 } else { 00350 if (is_observable()) { 00351 tr_warn("M2MResourceBase::report() - resource %s is observable but not yet subscribed!", uri_path()); 00352 } 00353 tr_debug("M2MResourceBase::report() - mode = %d, is_observable = %d", mode(), is_observable()); 00354 } 00355 } 00356 00357 bool M2MResourceBase::has_value_changed(const uint8_t* value, const uint32_t value_len) 00358 { 00359 bool changed = false; 00360 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00361 00362 if(value_len != res->resource_len) { 00363 changed = true; 00364 } else if(value && !res->resource) { 00365 changed = true; 00366 } else if(res->resource && !value) { 00367 changed = true; 00368 } else { 00369 if (res->resource) { 00370 if (memcmp(value, res->resource, res->resource_len) != 0) { 00371 changed = true; 00372 } 00373 } 00374 } 00375 return changed; 00376 } 00377 00378 void M2MResourceBase::report_value_change() 00379 { 00380 if (resource_instance_type() == M2MResourceBase::STRING || 00381 resource_instance_type() == M2MResourceBase::OPAQUE) { 00382 M2MReportHandler *report_handler = M2MBase::report_handler(); 00383 if(report_handler && is_under_observation()) { 00384 report_handler->set_notification_trigger(); 00385 } 00386 } 00387 report(); 00388 } 00389 00390 void M2MResourceBase::execute(void *arguments) 00391 { 00392 // XXX: this line is expected by seven testcases and until this code hits master branch 00393 // the testcases can not be modified and we need to print the false information too. 00394 tr_debug("M2MResourceBase::execute"); 00395 00396 execute_callback* callback = (execute_callback*)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); 00397 00398 if (callback) { 00399 (*callback)(arguments); 00400 } 00401 00402 execute_callback_2 callback2 = (execute_callback_2)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); 00403 if (callback2) { 00404 (*callback2)(arguments); 00405 } 00406 } 00407 00408 int M2MResourceBase::read_resource_value(const M2MResourceBase &resource, void *buffer, size_t *buffer_len) 00409 { 00410 tr_debug("M2MResourceBase::read_resource_value"); 00411 00412 M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(resource, 00413 M2MCallbackAssociation::M2MResourceBaseValueReadCallback); 00414 00415 if (item) { 00416 read_resource_value_callback callback = (read_resource_value_callback)item->_callback; 00417 assert(callback); 00418 return (*callback)(resource, buffer, buffer_len, item->_client_args); 00419 } else { 00420 if (value_length() > *buffer_len) { 00421 return -1; 00422 } else { 00423 memcpy(buffer, value(), value_length()); 00424 *buffer_len = value_length(); 00425 return 0; 00426 } 00427 } 00428 } 00429 00430 bool M2MResourceBase::write_resource_value(const M2MResourceBase &resource, const uint8_t *buffer, const size_t buffer_size) 00431 { 00432 tr_debug("M2MResourceBase::write_resource_value"); 00433 M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(resource, 00434 M2MCallbackAssociation::M2MResourceBaseValueWriteCallback); 00435 if (item) { 00436 write_resource_value_callback callback = (write_resource_value_callback)item->_callback; 00437 if (callback) { 00438 return (*callback)(resource, buffer, buffer_size, item->_client_args); 00439 } 00440 } 00441 00442 return false; 00443 } 00444 00445 void M2MResourceBase::get_value(uint8_t *&value, uint32_t &value_length) 00446 { 00447 value_length = 0; 00448 if(value) { 00449 free(value); 00450 value = NULL; 00451 } 00452 00453 sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); 00454 if(res->resource && res->resource_len > 0) { 00455 value = alloc_string_copy(res->resource, res->resource_len); 00456 if(value) { 00457 value_length = res->resource_len; 00458 } 00459 } 00460 } 00461 00462 int64_t M2MResourceBase::get_value_int() const 00463 { 00464 int64_t value_int = 0; 00465 00466 const char *value_string = (char *)value(); 00467 const uint32_t value_len = value_length(); 00468 00469 if ((value_string) && (value_len <= REGISTRY_INT64_STRING_MAX_LEN)) { 00470 00471 // -9223372036854775808 - +9223372036854775807 00472 // max length of int64_t string is 20 bytes + nil 00473 // The +1 here is there in case the string was already zero terminated. 00474 char temp[REGISTRY_INT64_STRING_MAX_LEN + 1]; 00475 00476 memcpy(temp, value_string, value_len); 00477 temp[value_len] = 0; 00478 00479 value_int = atoll(temp); 00480 } 00481 return value_int; 00482 } 00483 00484 String M2MResourceBase::get_value_string() const 00485 { 00486 // XXX: do a better constructor to avoid pointless malloc 00487 String value; 00488 if (get_nsdl_resource()->resource) { 00489 value.append_raw((char*)get_nsdl_resource()->resource, get_nsdl_resource()->resource_len); 00490 } 00491 return value; 00492 } 00493 00494 float M2MResourceBase::get_value_float() const 00495 { 00496 float value_float = 0; 00497 00498 const char *value_string = (char *)value(); 00499 const uint32_t value_len = value_length(); 00500 00501 if ((value_string) && (value_len <= REGISTRY_FLOAT_STRING_MAX_LEN)) { 00502 00503 // (space needed for -3.402823 × 10^38) + (magic decimal 6 digits added as no precision is added to "%f") + trailing zero 00504 // The +1 here is there in case the string was already zero terminated. 00505 char temp[REGISTRY_FLOAT_STRING_MAX_LEN + 1]; 00506 00507 memcpy(temp, value_string, value_len); 00508 temp[value_len] = 0; 00509 00510 value_float = atof(temp); 00511 } 00512 00513 return value_float; 00514 } 00515 00516 uint8_t* M2MResourceBase::value() const 00517 { 00518 return get_nsdl_resource()->resource; 00519 } 00520 00521 uint32_t M2MResourceBase::value_length() const 00522 { 00523 return get_nsdl_resource()->resource_len; 00524 } 00525 00526 void M2MResourceBase::set_value_set_callback(value_set_callback callback) 00527 { 00528 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceBaseValueSetCallback); 00529 M2MCallbackStorage::add_callback(*this, (void*)callback, M2MCallbackAssociation::M2MResourceBaseValueSetCallback); 00530 } 00531 00532 sn_coap_hdr_s* M2MResourceBase::handle_get_request(nsdl_s *nsdl, 00533 sn_coap_hdr_s *received_coap_header, 00534 M2MObservationHandler *observation_handler) 00535 { 00536 tr_info("M2MResourceBase::handle_get_request()"); 00537 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00538 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00539 received_coap_header, 00540 msg_code); 00541 if (received_coap_header) { 00542 // process the GET if we have registered a callback for it 00543 if ((operation() & SN_GRS_GET_ALLOWED) != 0) { 00544 if (coap_response) { 00545 bool content_type_present = false; 00546 if (received_coap_header->options_list_ptr && 00547 received_coap_header->options_list_ptr->accept != COAP_CT_NONE) { 00548 content_type_present = true; 00549 coap_response->content_format = received_coap_header->options_list_ptr->accept; 00550 set_coap_content_type(coap_response->content_format); 00551 } 00552 if (!content_type_present) { 00553 if (resource_instance_type() == M2MResourceInstance::OPAQUE) { 00554 coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_OPAQUE_TYPE); 00555 } else { 00556 coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_PLAIN_TEXT_TYPE); 00557 } 00558 } 00559 // fill in the CoAP response payload 00560 coap_response->payload_ptr = NULL; 00561 uint32_t payload_len = 0; 00562 #ifndef DISABLE_BLOCK_MESSAGE 00563 //If handler exists it means that resource value is stored in application side 00564 if (block_message() && block_message()->is_block_message()) { 00565 outgoing_block_message_callback* outgoing_block_message_cb = (outgoing_block_message_callback*)M2MCallbackStorage::get_callback(*this, 00566 M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); 00567 if (outgoing_block_message_cb) { 00568 String name = ""; 00569 if (received_coap_header->uri_path_ptr != NULL && 00570 received_coap_header->uri_path_len > 0) { 00571 name.append_raw((char *)received_coap_header->uri_path_ptr, received_coap_header->uri_path_len); 00572 } 00573 (*outgoing_block_message_cb)(name, coap_response->payload_ptr, payload_len); 00574 } 00575 } else { 00576 #endif 00577 if (coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE || 00578 coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE_OLD) { 00579 coap_response->payload_ptr = M2MTLVSerializer::serialize(&get_parent_resource(), payload_len); 00580 } else { 00581 get_value(coap_response->payload_ptr,payload_len); 00582 } 00583 #ifndef DISABLE_BLOCK_MESSAGE 00584 } 00585 #endif 00586 tr_debug("M2MResourceBase::handle_get_request() - Request Content-type: %d", coap_response->content_format); 00587 coap_response->payload_len = payload_len; 00588 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); 00589 if (coap_response->options_list_ptr) { 00590 coap_response->options_list_ptr->max_age = max_age(); 00591 } 00592 00593 if (received_coap_header->options_list_ptr) { 00594 if (received_coap_header->options_list_ptr->observe != -1) { 00595 if (is_observable()) { 00596 uint32_t number = 0; 00597 uint8_t observe_option = 0; 00598 observe_option = received_coap_header->options_list_ptr->observe; 00599 00600 if (START_OBSERVATION == observe_option) { 00601 // If the observe length is 0 means register for observation. 00602 if (received_coap_header->options_list_ptr->observe != -1) { 00603 number = received_coap_header->options_list_ptr->observe; 00604 } 00605 00606 // If the observe value is 0 means register for observation. 00607 if (number == 0) { 00608 tr_info("M2MResourceBase::handle_get_request - put resource under observation"); 00609 set_under_observation(true,observation_handler); 00610 send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED); 00611 M2MBase::add_observation_level(M2MBase::R_Attribute); 00612 if (coap_response->options_list_ptr) { 00613 coap_response->options_list_ptr->observe = observation_number(); 00614 } 00615 } 00616 00617 if (received_coap_header->token_ptr) { 00618 set_observation_token(received_coap_header->token_ptr, 00619 received_coap_header->token_len); 00620 } 00621 00622 } else if (STOP_OBSERVATION == observe_option) { 00623 tr_info("M2MResourceBase::handle_get_request - stops observation"); 00624 set_under_observation(false,NULL); 00625 M2MBase::remove_observation_level(M2MBase::R_Attribute); 00626 send_notification_delivery_status(*this, NOTIFICATION_STATUS_UNSUBSCRIBED); 00627 } 00628 } else { 00629 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00630 } 00631 } 00632 } 00633 } 00634 } else { 00635 tr_error("M2MResourceBase::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00636 // Operation is not allowed. 00637 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00638 } 00639 } else { 00640 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00641 } 00642 00643 if (coap_response) { 00644 coap_response->msg_code = msg_code; 00645 } 00646 00647 return coap_response; 00648 } 00649 00650 sn_coap_hdr_s* M2MResourceBase::handle_put_request(nsdl_s *nsdl, 00651 sn_coap_hdr_s *received_coap_header, 00652 M2MObservationHandler *observation_handler, 00653 bool &execute_value_updated) 00654 { 00655 tr_info("M2MResourceBase::handle_put_request()"); 00656 00657 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00658 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00659 received_coap_header, 00660 msg_code); 00661 // process the PUT if we have registered a callback for it 00662 if(received_coap_header && coap_response) { 00663 uint16_t coap_content_type = 0; 00664 if(received_coap_header->content_format != COAP_CT_NONE) { 00665 coap_content_type = received_coap_header->content_format; 00666 } 00667 if(received_coap_header->options_list_ptr && 00668 received_coap_header->options_list_ptr->uri_query_ptr) { 00669 char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, 00670 received_coap_header->options_list_ptr->uri_query_len); 00671 if (query){ 00672 tr_info("M2MResourceBase::handle_put_request() - query %s", query); 00673 00674 // if anything was updated, re-initialize the stored notification attributes 00675 if (!handle_observation_attribute(query)){ 00676 tr_error("M2MResourceBase::handle_put_request() - Invalid query"); 00677 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00678 } 00679 free(query); 00680 } 00681 else { 00682 // memory allocation for query fails 00683 tr_error("M2MResourceBase::handle_put_request() - Out of memory !!!"); 00684 msg_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR; // 4.00 00685 } 00686 } else if ((operation() & SN_GRS_PUT_ALLOWED) != 0) { 00687 tr_debug("M2MResourceBase::handle_put_request() - Request Content-type: %d", coap_content_type); 00688 00689 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type || 00690 COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type) { 00691 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; 00692 } else { 00693 #ifndef DISABLE_BLOCK_MESSAGE 00694 if (block_message()) { 00695 block_message()->set_message_info(received_coap_header); 00696 if (block_message()->is_block_message()) { 00697 incoming_block_message_callback* incoming_block_message_cb = (incoming_block_message_callback*)M2MCallbackStorage::get_callback(*this, 00698 M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); 00699 if (incoming_block_message_cb) { 00700 (*incoming_block_message_cb)(_block_message_data); 00701 } 00702 if (block_message()->is_last_block()) { 00703 block_message()->clear_values(); 00704 coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED; 00705 } else { 00706 coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING; 00707 } 00708 if (block_message()->error_code() != M2MBlockMessage::ErrorNone) { 00709 block_message()->clear_values(); 00710 } 00711 } 00712 } 00713 #endif 00714 // Firmware object uri path is limited to be max 255 bytes 00715 if ((strcmp(uri_path(), FIRMAWARE_PACKAGE_URI_PATH) == 0) && 00716 received_coap_header->payload_len > 255) { 00717 msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; 00718 } else if ((strcmp(uri_path(), SERVER_LIFETIME_PATH) == 0)) { 00719 // Check that lifetime can't go below 60s 00720 char *query = (char*)alloc_string_copy(received_coap_header->payload_ptr, 00721 received_coap_header->payload_len); 00722 00723 if (query) { 00724 int32_t lifetime = atol(query); 00725 if (lifetime < MINIMUM_REGISTRATION_TIME) { 00726 tr_error("M2MResourceBase::handle_put_request() - lifetime value % " PRId32 " not acceptable", lifetime); 00727 msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; 00728 } 00729 free(query); 00730 } 00731 else { 00732 // memory allocation for query fails 00733 tr_error("M2MResourceBase::handle_put_request() - Out of memory !!!"); 00734 msg_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR; 00735 } 00736 } 00737 00738 // Do not update resource value in error case. 00739 if ((received_coap_header->payload_ptr) && (msg_code == COAP_MSG_CODE_RESPONSE_CHANGED)) { 00740 execute_value_updated = true; 00741 } 00742 } 00743 } else { 00744 // Operation is not allowed. 00745 tr_error("M2MResourceBase::handle_put_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00746 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00747 } 00748 } else { 00749 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00750 } 00751 if(coap_response) { 00752 coap_response->msg_code = msg_code; 00753 } 00754 00755 return coap_response; 00756 } 00757 00758 00759 #ifndef DISABLE_BLOCK_MESSAGE 00760 00761 M2MBlockMessage* M2MResourceBase::block_message() const 00762 { 00763 return _block_message_data; 00764 } 00765 00766 bool M2MResourceBase::set_incoming_block_message_callback(incoming_block_message_callback callback) 00767 { 00768 incoming_block_message_callback* old_callback = (incoming_block_message_callback*)M2MCallbackStorage::remove_callback(*this, 00769 M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); 00770 delete old_callback; 00771 00772 // copy the callback object. This will change on next version to be a direct pointer to a interface class, 00773 // this FPn<> is just too heavy for this usage. 00774 incoming_block_message_callback* new_callback = new incoming_block_message_callback(callback); 00775 00776 delete _block_message_data; 00777 _block_message_data = NULL; 00778 _block_message_data = new M2MBlockMessage(); 00779 00780 return M2MCallbackStorage::add_callback(*this, 00781 new_callback, 00782 M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); 00783 } 00784 00785 bool M2MResourceBase::set_outgoing_block_message_callback(outgoing_block_message_callback callback) 00786 { 00787 outgoing_block_message_callback *old_callback = (outgoing_block_message_callback*)M2MCallbackStorage::remove_callback(*this, 00788 M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); 00789 delete old_callback; 00790 00791 outgoing_block_message_callback *new_callback = new outgoing_block_message_callback(callback); 00792 return M2MCallbackStorage::add_callback(*this, 00793 new_callback, 00794 M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); 00795 } 00796 #endif 00797 00798 bool M2MResourceBase::set_notification_sent_callback(notification_sent_callback callback) 00799 { 00800 notification_sent_callback *old_callback = (notification_sent_callback*)M2MCallbackStorage::remove_callback(*this, 00801 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); 00802 delete old_callback; 00803 00804 notification_sent_callback *new_callback = new notification_sent_callback(callback); 00805 return M2MCallbackStorage::add_callback(*this, 00806 new_callback, 00807 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); 00808 } 00809 00810 bool M2MResourceBase::set_notification_sent_callback(notification_sent_callback_2 callback) 00811 { 00812 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); 00813 00814 return M2MCallbackStorage::add_callback(*this, 00815 (void*)callback, 00816 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); 00817 } 00818 00819 bool M2MResourceBase::set_notification_status_callback(notification_status_callback callback) 00820 { 00821 notification_status_callback *old_callback = (notification_status_callback*)M2MCallbackStorage::remove_callback(*this, 00822 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); 00823 delete old_callback; 00824 00825 notification_status_callback *new_callback = new notification_status_callback(callback); 00826 return M2MCallbackStorage::add_callback(*this, 00827 new_callback, 00828 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); 00829 } 00830 00831 bool M2MResourceBase::set_notification_status_callback(notification_status_callback_2 callback) 00832 { 00833 M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); 00834 00835 return M2MCallbackStorage::add_callback(*this, 00836 (void*)callback, 00837 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); 00838 } 00839 00840 void M2MResourceBase::notification_sent() 00841 { 00842 // Now we will call both callbacks, if they are set. This is different from original behavior. 00843 notification_sent_callback* callback = 00844 (notification_sent_callback*)M2MCallbackStorage::get_callback(*this, 00845 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); 00846 if (callback) { 00847 (*callback)(); 00848 } 00849 00850 notification_sent_callback_2 callback2 = 00851 (notification_sent_callback_2)M2MCallbackStorage::get_callback(*this, 00852 M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); 00853 if (callback2) { 00854 (*callback2)(); 00855 } 00856 } 00857 00858 void M2MResourceBase::notification_status(const uint16_t msg_id, const NotificationStatus status) 00859 { 00860 if (_notification_status != status) { 00861 _notification_status = status; 00862 // Now we will call both callbacks, if they are set. This is different from original behavior. 00863 notification_status_callback* callback = 00864 (notification_status_callback*)M2MCallbackStorage::get_callback(*this, 00865 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); 00866 if (callback) { 00867 (*callback)(msg_id, status); 00868 } 00869 00870 notification_status_callback_2 callback2 = 00871 (notification_status_callback_2)M2MCallbackStorage::get_callback(*this, 00872 M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); 00873 if (callback2) { 00874 (*callback2)(msg_id, status); 00875 } 00876 } 00877 } 00878 00879 M2MResourceBase::ResourceType M2MResourceBase::convert_data_type(M2MBase::DataType type) const 00880 { 00881 M2MResourceBase::ResourceType res_type = M2MResourceBase::OBJLINK; 00882 switch(type) { 00883 case M2MBase::STRING: 00884 res_type = M2MResourceBase::STRING; 00885 break; 00886 case M2MBase::INTEGER: 00887 res_type = M2MResourceBase::INTEGER; 00888 break; 00889 case M2MBase::FLOAT: 00890 res_type = M2MResourceBase::FLOAT; 00891 break; 00892 case M2MBase::OPAQUE: 00893 res_type = M2MResourceBase::OPAQUE; 00894 break; 00895 case M2MBase::BOOLEAN: 00896 res_type = M2MResourceBase::BOOLEAN; 00897 break; 00898 case M2MBase::TIME: 00899 res_type = M2MResourceBase::TIME; 00900 break; 00901 case M2MBase::OBJLINK: 00902 res_type = M2MResourceBase::OBJLINK; 00903 break; 00904 } 00905 return res_type; 00906 } 00907 00908 M2MResourceBase::NotificationStatus M2MResourceBase::notification_status() const 00909 { 00910 return _notification_status; 00911 } 00912 00913 void M2MResourceBase::clear_notification_status() 00914 { 00915 _notification_status = M2MResourceBase::INIT; 00916 } 00917 00918 void M2MResourceBase::publish_value_in_registration_msg(bool publish_value) 00919 { 00920 M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); 00921 assert(param->data_type == M2MBase::INTEGER || 00922 param->data_type == M2MBase::STRING || 00923 param->data_type == M2MBase::FLOAT || 00924 param->data_type == M2MBase::BOOLEAN || 00925 param->data_type == M2MBase::OPAQUE); 00926 00927 uint8_t pub_value = publish_value; 00928 00929 if (param->data_type == M2MBase::OPAQUE) { 00930 pub_value = 2; 00931 } else { 00932 pub_value = (uint8_t)publish_value; 00933 } 00934 param->dynamic_resource_params->publish_value = pub_value; 00935 }
Generated on Tue Jul 12 2022 16:24:15 by
1.7.2