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