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