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.
m2mobject.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 // Note: this macro is needed on armcc to get the the PRI*32 macros 00018 // from inttypes.h in a C++ code. 00019 #ifndef __STDC_FORMAT_MACROS 00020 #define __STDC_FORMAT_MACROS 00021 #endif 00022 #include <inttypes.h> 00023 00024 #include "mbed-client/m2mobject.h" 00025 #include "mbed-client/m2mendpoint.h" 00026 #include "mbed-client/m2mconstants.h" 00027 #include "include/m2mtlvserializer.h" 00028 #include "include/m2mtlvdeserializer.h" 00029 #include "include/m2mreporthandler.h" 00030 #include "mbed-trace/mbed_trace.h" 00031 #include "mbed-client/m2mstringbuffer.h" 00032 #include "include/m2mcallbackstorage.h" 00033 00034 #include <stdlib.h> 00035 00036 #define BUFFER_SIZE 10 00037 #define TRACE_GROUP "mClt" 00038 00039 M2MObject::M2MObject(const String &object_name, char *path, bool external_blockwise_store) 00040 : M2MBase(object_name, 00041 M2MBase::Dynamic, 00042 #ifndef DISABLE_RESOURCE_TYPE 00043 "", 00044 #endif 00045 path, 00046 external_blockwise_store, 00047 false), 00048 _observation_handler(NULL) 00049 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 00050 ,_endpoint(NULL) 00051 #endif 00052 { 00053 M2MBase::set_base_type(M2MBase::Object); 00054 M2MBase::set_operation(M2MBase::GET_ALLOWED); 00055 if(M2MBase::name_id() != -1) { 00056 M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); 00057 } 00058 } 00059 00060 M2MObject::M2MObject(const M2MBase::lwm2m_parameters_s* static_res) 00061 : M2MBase(static_res), 00062 _observation_handler(NULL) 00063 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 00064 ,_endpoint(NULL) 00065 #endif 00066 { 00067 M2MBase::set_operation(M2MBase::GET_ALLOWED); 00068 if(M2MBase::name_id() != -1) { 00069 M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); 00070 } 00071 } 00072 00073 M2MObject::~M2MObject() 00074 { 00075 if(!_instance_list.empty()) { 00076 00077 M2MObjectInstanceList::const_iterator it; 00078 it = _instance_list.begin(); 00079 M2MObjectInstance* obj = NULL; 00080 uint16_t index = 0; 00081 for (; it!=_instance_list.end(); it++, index++ ) { 00082 //Free allocated memory for object instances. 00083 obj = *it; 00084 delete obj; 00085 } 00086 00087 _instance_list.clear(); 00088 } 00089 00090 free_resources(); 00091 } 00092 00093 M2MObjectInstance* M2MObject::create_object_instance(uint16_t instance_id) 00094 { 00095 tr_debug("M2MObject::create_object_instance - id: %d", instance_id); 00096 M2MObjectInstance *instance = NULL; 00097 if(!object_instance(instance_id)) { 00098 char* path = create_path(*this, instance_id); 00099 if (path) { 00100 // Note: the object instance's name contains actually object's name. 00101 instance = new M2MObjectInstance(*this, "", path); 00102 if(instance) { 00103 instance->add_observation_level(observation_level()); 00104 instance->set_instance_id(instance_id); 00105 if(M2MBase::name_id() != -1) { 00106 instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); 00107 } 00108 _instance_list.push_back(instance); 00109 set_changed(); 00110 } 00111 } 00112 } 00113 return instance; 00114 } 00115 00116 00117 M2MObjectInstance* M2MObject::create_object_instance(const lwm2m_parameters_s* s) 00118 { 00119 tr_debug("M2MObject::create_object_instance - id: %d", s->identifier.instance_id); 00120 M2MObjectInstance *instance = NULL; 00121 if(!object_instance(s->identifier.instance_id)) { 00122 00123 instance = new M2MObjectInstance(*this, s); 00124 if(instance) { 00125 instance->add_observation_level(observation_level()); 00126 //instance->set_instance_id(instance_id); 00127 //if(M2MBase::name_id() != -1) { 00128 // instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); 00129 //} 00130 _instance_list.push_back(instance); 00131 set_changed(); 00132 } 00133 } 00134 return instance; 00135 } 00136 00137 bool M2MObject::remove_object_instance(uint16_t inst_id) 00138 { 00139 tr_debug("M2MObject::remove_object_instance(inst_id %d)", inst_id); 00140 bool success = false; 00141 if(!_instance_list.empty()) { 00142 M2MObjectInstance* obj = NULL; 00143 M2MObjectInstanceList::const_iterator it; 00144 it = _instance_list.begin(); 00145 int pos = 0; 00146 for ( ; it != _instance_list.end(); it++, pos++ ) { 00147 if((*it)->instance_id() == inst_id) { 00148 // Instance found and deleted. 00149 obj = *it; 00150 00151 _instance_list.erase(pos); 00152 delete obj; 00153 success = true; 00154 set_changed(); 00155 break; 00156 } 00157 } 00158 } 00159 return success; 00160 } 00161 00162 M2MObjectInstance* M2MObject::object_instance(uint16_t inst_id) const 00163 { 00164 tr_debug("M2MObject::object_instance(inst_id %d)", inst_id); 00165 M2MObjectInstance *obj = NULL; 00166 if(!_instance_list.empty()) { 00167 M2MObjectInstanceList::const_iterator it; 00168 it = _instance_list.begin(); 00169 for ( ; it != _instance_list.end(); it++ ) { 00170 if((*it)->instance_id() == inst_id) { 00171 // Instance found. 00172 obj = *it; 00173 break; 00174 } 00175 } 00176 } 00177 return obj; 00178 } 00179 00180 const M2MObjectInstanceList& M2MObject::instances() const 00181 { 00182 return _instance_list; 00183 } 00184 00185 uint16_t M2MObject::instance_count() const 00186 { 00187 return (uint16_t)_instance_list.size(); 00188 } 00189 00190 M2MObservationHandler* M2MObject::observation_handler() const 00191 { 00192 // XXX: need to check the flag too 00193 return _observation_handler; 00194 } 00195 00196 void M2MObject::set_observation_handler(M2MObservationHandler *handler) 00197 { 00198 tr_debug("M2MObject::set_observation_handler - handler: 0x%p", (void*)handler); 00199 _observation_handler = handler; 00200 } 00201 00202 void M2MObject::add_observation_level(M2MBase::Observation observation_level) 00203 { 00204 M2MBase::add_observation_level(observation_level); 00205 if(!_instance_list.empty()) { 00206 M2MObjectInstanceList::const_iterator it; 00207 it = _instance_list.begin(); 00208 for ( ; it != _instance_list.end(); it++ ) { 00209 (*it)->add_observation_level(observation_level); 00210 } 00211 } 00212 } 00213 00214 void M2MObject::remove_observation_level(M2MBase::Observation observation_level) 00215 { 00216 M2MBase::remove_observation_level(observation_level); 00217 if(!_instance_list.empty()) { 00218 M2MObjectInstanceList::const_iterator it; 00219 it = _instance_list.begin(); 00220 for ( ; it != _instance_list.end(); it++ ) { 00221 (*it)->remove_observation_level(observation_level); 00222 } 00223 } 00224 } 00225 00226 sn_coap_hdr_s* M2MObject::handle_get_request(nsdl_s *nsdl, 00227 sn_coap_hdr_s *received_coap_header, 00228 M2MObservationHandler *observation_handler) 00229 { 00230 tr_info("M2MObject::handle_get_request()"); 00231 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00232 sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl, 00233 received_coap_header, 00234 msg_code); 00235 uint8_t *data = NULL; 00236 uint32_t data_length = 0; 00237 if(received_coap_header) { 00238 // process the GET if we have registered a callback for it 00239 if ((operation() & M2MBase::GET_ALLOWED) != 0) { 00240 if(coap_response) { 00241 bool content_type_present = false; 00242 bool is_content_type_supported = true; 00243 00244 if (received_coap_header->options_list_ptr && 00245 received_coap_header->options_list_ptr->accept != COAP_CT_NONE) { 00246 content_type_present = true; 00247 coap_response->content_format = received_coap_header->options_list_ptr->accept; 00248 00249 } 00250 00251 // Check if preferred content type is supported 00252 if (content_type_present) { 00253 if (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD && 00254 coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) { 00255 is_content_type_supported = false; 00256 } 00257 } 00258 00259 if (is_content_type_supported) { 00260 if(!content_type_present && 00261 (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || 00262 M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { 00263 coap_response->content_format = sn_coap_content_format_e(M2MBase::coap_content_type()); 00264 } 00265 00266 // fill in the CoAP response payload 00267 if(COAP_CONTENT_OMA_TLV_TYPE == coap_response->content_format || 00268 COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_response->content_format) { 00269 set_coap_content_type(coap_response->content_format); 00270 data = M2MTLVSerializer::serialize(_instance_list, data_length); 00271 } 00272 00273 coap_response->payload_len = data_length; 00274 coap_response->payload_ptr = data; 00275 if(data){ 00276 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); 00277 if(coap_response->options_list_ptr){ 00278 coap_response->options_list_ptr->max_age = max_age(); 00279 } 00280 if(received_coap_header->options_list_ptr) { 00281 if(received_coap_header->options_list_ptr->observe != -1) { 00282 handle_observation(nsdl, *received_coap_header, *coap_response, observation_handler, msg_code); 00283 } 00284 } 00285 } else { 00286 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; // Content format not supported 00287 } 00288 } else { 00289 tr_error("M2MObject::handle_get_request() - Content-Type %d not supported", coap_response->content_format); 00290 msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; 00291 } 00292 } 00293 }else { 00294 tr_error("M2MResource::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00295 // Operation is not allowed. 00296 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00297 } 00298 } else { 00299 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00300 } 00301 if(coap_response) { 00302 coap_response->msg_code = msg_code; 00303 } 00304 return coap_response; 00305 } 00306 00307 sn_coap_hdr_s* M2MObject::handle_put_request(nsdl_s *nsdl, 00308 sn_coap_hdr_s *received_coap_header, 00309 M2MObservationHandler */*observation_handler*/, 00310 bool &/*execute_value_updated*/) 00311 { 00312 tr_info("M2MObject::handle_put_request()"); 00313 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00314 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00315 received_coap_header, 00316 msg_code); 00317 if(received_coap_header) { 00318 if(received_coap_header->content_format != COAP_CT_NONE) { 00319 set_coap_content_type(received_coap_header->content_format); 00320 } 00321 if(received_coap_header->options_list_ptr && 00322 received_coap_header->options_list_ptr->uri_query_ptr) { 00323 char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, 00324 received_coap_header->options_list_ptr->uri_query_len); 00325 00326 if (query){ 00327 tr_info("M2MObject::handle_put_request() - query %s", query); 00328 // if anything was updated, re-initialize the stored notification attributes 00329 if (!handle_observation_attribute(query)){ 00330 tr_debug("M2MObject::handle_put_request() - Invalid query"); 00331 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 00332 } 00333 free(query); 00334 } 00335 } else { 00336 tr_error("M2MObject::handle_put_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Empty URI_QUERY"); 00337 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00338 } 00339 } else { 00340 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00341 } 00342 if(coap_response) { 00343 coap_response->msg_code = msg_code; 00344 } 00345 return coap_response; 00346 } 00347 00348 00349 sn_coap_hdr_s* M2MObject::handle_post_request(nsdl_s *nsdl, 00350 sn_coap_hdr_s *received_coap_header, 00351 M2MObservationHandler *observation_handler, 00352 bool &execute_value_updated, 00353 sn_nsdl_addr_s *) 00354 { 00355 tr_info("M2MObject::handle_post_request()"); 00356 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00357 // process the POST if we have registered a callback for it 00358 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00359 received_coap_header, 00360 msg_code); 00361 00362 if (received_coap_header) { 00363 if ((operation() & M2MBase::POST_ALLOWED) != 0) { 00364 if (received_coap_header->content_format != COAP_CT_NONE) { 00365 set_coap_content_type(received_coap_header->content_format); 00366 } 00367 if(received_coap_header->payload_ptr) { 00368 tr_debug("M2MObject::handle_post_request() - Update Object with new values"); 00369 uint16_t coap_content_type = 0; 00370 bool content_type_present = false; 00371 if(received_coap_header->content_format != COAP_CT_NONE) { 00372 content_type_present = true; 00373 if(coap_response) { 00374 coap_content_type = received_coap_header->content_format; 00375 } 00376 } // if(received_coap_header->content_format) 00377 if(!content_type_present && 00378 (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || 00379 M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { 00380 coap_content_type = M2MBase::coap_content_type(); 00381 } 00382 00383 tr_debug("M2MObject::handle_post_request() - Request Content-type: %d", coap_content_type); 00384 00385 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type || 00386 COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type) { 00387 set_coap_content_type(coap_content_type); 00388 uint32_t instance_id = 0; 00389 // Check next free instance id 00390 for(instance_id = 0; instance_id <= MAX_UNINT_16_COUNT; instance_id++) { 00391 if(NULL == object_instance(instance_id)) { 00392 break; 00393 } 00394 if(instance_id == MAX_UNINT_16_COUNT) { 00395 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00396 break; 00397 } 00398 } 00399 if(COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) { 00400 bool is_obj_instance = false; 00401 bool obj_instance_exists = false; 00402 is_obj_instance = M2MTLVDeserializer::is_object_instance(received_coap_header->payload_ptr); 00403 if (is_obj_instance) { 00404 instance_id = M2MTLVDeserializer::instance_id(received_coap_header->payload_ptr); 00405 tr_debug("M2MObject::handle_post_request() - instance id in TLV: %" PRIu32, instance_id); 00406 // Check if instance id already exists 00407 if (object_instance(instance_id)){ 00408 obj_instance_exists = true; 00409 } 00410 } 00411 if (!obj_instance_exists && coap_response) { 00412 M2MObjectInstance *obj_instance = create_object_instance(instance_id); 00413 if (obj_instance) { 00414 obj_instance->set_operation(M2MBase::GET_PUT_ALLOWED); 00415 } 00416 00417 M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; 00418 if(is_obj_instance) { 00419 tr_debug("M2MObject::handle_post_request() - TLV data contains ObjectInstance"); 00420 error = M2MTLVDeserializer::deserialise_object_instances(received_coap_header->payload_ptr, 00421 received_coap_header->payload_len, 00422 *this, 00423 M2MTLVDeserializer::Post); 00424 } else if(obj_instance && 00425 (M2MTLVDeserializer::is_resource(received_coap_header->payload_ptr) || 00426 M2MTLVDeserializer::is_multiple_resource(received_coap_header->payload_ptr))) { 00427 tr_debug("M2MObject::handle_post_request() - TLV data contains Resources"); 00428 error = M2MTLVDeserializer::deserialize_resources(received_coap_header->payload_ptr, 00429 received_coap_header->payload_len, 00430 *obj_instance, 00431 M2MTLVDeserializer::Post); 00432 } else { 00433 error = M2MTLVDeserializer::NotValid; 00434 } 00435 switch(error) { 00436 case M2MTLVDeserializer::None: 00437 if(observation_handler) { 00438 execute_value_updated = true; 00439 } 00440 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); 00441 00442 if (coap_response->options_list_ptr) { 00443 00444 StringBuffer<MAX_OBJECT_PATH_NAME> obj_name; 00445 00446 if (obj_name.ensure_space(M2MBase::resource_name_length() + (1 + 5 + 1))) { 00447 obj_name.append(M2MBase::name()); 00448 obj_name.append('/'); 00449 obj_name.append_int(instance_id); 00450 00451 coap_response->options_list_ptr->location_path_len = obj_name.get_size(); 00452 coap_response->options_list_ptr->location_path_ptr = 00453 alloc_copy((uint8_t*)obj_name.c_str(), obj_name.get_size()); 00454 // todo: else return error 00455 } 00456 } 00457 // todo: else return error 00458 msg_code = COAP_MSG_CODE_RESPONSE_CREATED; 00459 break; 00460 case M2MTLVDeserializer::NotAllowed: 00461 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00462 break; 00463 case M2MTLVDeserializer::NotValid: 00464 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00465 break; 00466 case M2MTLVDeserializer::NotFound: 00467 msg_code = COAP_MSG_CODE_RESPONSE_NOT_FOUND; 00468 break; 00469 case M2MTLVDeserializer::OutOfMemory: 00470 msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; 00471 break; 00472 } 00473 00474 } else { 00475 tr_error("M2MObject::handle_post_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST"); 00476 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00477 } 00478 } 00479 } else { 00480 msg_code =COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; 00481 } // if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) 00482 } else { 00483 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Missing Payload"); 00484 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 00485 } 00486 } else { // if ((object->operation() & SN_GRS_POST_ALLOWED) != 0) 00487 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00488 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 00489 } 00490 } else { //if(received_coap_header) 00491 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00492 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 00493 } 00494 00495 if(coap_response) { 00496 coap_response->msg_code = msg_code; 00497 } 00498 return coap_response; 00499 } 00500 00501 void M2MObject::notification_update(uint16_t obj_instance_id) 00502 { 00503 tr_debug("M2MObject::notification_update - id: %d", obj_instance_id); 00504 M2MReportHandler *report_handler = M2MBase::report_handler(); 00505 if(report_handler && is_under_observation()) { 00506 report_handler->set_notification_trigger(obj_instance_id); 00507 } 00508 } 00509 00510 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 00511 void M2MObject::set_endpoint(M2MEndpoint *endpoint) 00512 { 00513 _endpoint = endpoint; 00514 } 00515 00516 M2MEndpoint* M2MObject::get_endpoint() const 00517 { 00518 return _endpoint; 00519 } 00520 #endif 00521 00522 M2MBase *M2MObject::get_parent() const 00523 { 00524 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 00525 return (M2MBase *) get_endpoint(); 00526 #else 00527 return NULL; 00528 #endif 00529 }
Generated on Mon Aug 29 2022 19:53:40 by
