Simulated product dispenser
Fork of mbed-cloud-workshop-connect-HTS221 by
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() & SN_GRS_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 if (is_observable()) { 00283 uint32_t number = 0; 00284 uint8_t observe_option = 0; 00285 observe_option = received_coap_header->options_list_ptr->observe; 00286 00287 if(START_OBSERVATION == observe_option) { 00288 // If the observe length is 0 means register for observation. 00289 if(received_coap_header->options_list_ptr->observe != -1) { 00290 number = received_coap_header->options_list_ptr->observe; 00291 } 00292 00293 // If the observe value is 0 means register for observation. 00294 if(number == 0) { 00295 tr_info("M2MObject::handle_get_request - put resource under observation"); 00296 set_under_observation(true,observation_handler); 00297 add_observation_level(M2MBase::O_Attribute); 00298 send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED); 00299 if(coap_response->options_list_ptr){ 00300 coap_response->options_list_ptr->observe = observation_number(); 00301 } 00302 } 00303 00304 if(received_coap_header->token_ptr) { 00305 set_observation_token(received_coap_header->token_ptr, 00306 received_coap_header->token_len); 00307 } 00308 } else if (STOP_OBSERVATION == observe_option) { 00309 tr_info("M2MObject::handle_get_request - stops observation"); 00310 // If the observe options_list_ptr->observe value is 1 means de-register from observation. 00311 set_under_observation(false, NULL); 00312 remove_observation_level(M2MBase::O_Attribute); 00313 send_notification_delivery_status(*this, NOTIFICATION_STATUS_UNSUBSCRIBED); 00314 } 00315 msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00316 } 00317 else { 00318 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00319 } 00320 } 00321 } 00322 } else { 00323 msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; // Content format not supported 00324 } 00325 } else { 00326 tr_error("M2MObject::handle_get_request() - Content-Type %d not supported", coap_response->content_format); 00327 msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; 00328 } 00329 } 00330 }else { 00331 tr_error("M2MResource::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00332 // Operation is not allowed. 00333 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00334 } 00335 } else { 00336 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00337 } 00338 if(coap_response) { 00339 coap_response->msg_code = msg_code; 00340 } 00341 return coap_response; 00342 } 00343 00344 sn_coap_hdr_s* M2MObject::handle_put_request(nsdl_s *nsdl, 00345 sn_coap_hdr_s *received_coap_header, 00346 M2MObservationHandler */*observation_handler*/, 00347 bool &/*execute_value_updated*/) 00348 { 00349 tr_info("M2MObject::handle_put_request()"); 00350 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00351 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00352 received_coap_header, 00353 msg_code); 00354 if(received_coap_header) { 00355 if(received_coap_header->content_format != COAP_CT_NONE) { 00356 set_coap_content_type(received_coap_header->content_format); 00357 } 00358 if(received_coap_header->options_list_ptr && 00359 received_coap_header->options_list_ptr->uri_query_ptr) { 00360 char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, 00361 received_coap_header->options_list_ptr->uri_query_len); 00362 00363 if (query){ 00364 tr_info("M2MObject::handle_put_request() - query %s", query); 00365 // if anything was updated, re-initialize the stored notification attributes 00366 if (!handle_observation_attribute(query)){ 00367 tr_debug("M2MObject::handle_put_request() - Invalid query"); 00368 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 00369 } 00370 free(query); 00371 } 00372 } else { 00373 tr_error("M2MObject::handle_put_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Empty URI_QUERY"); 00374 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00375 } 00376 } else { 00377 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00378 } 00379 if(coap_response) { 00380 coap_response->msg_code = msg_code; 00381 } 00382 return coap_response; 00383 } 00384 00385 00386 sn_coap_hdr_s* M2MObject::handle_post_request(nsdl_s *nsdl, 00387 sn_coap_hdr_s *received_coap_header, 00388 M2MObservationHandler *observation_handler, 00389 bool &execute_value_updated, 00390 sn_nsdl_addr_s *) 00391 { 00392 tr_info("M2MObject::handle_post_request()"); 00393 sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 00394 // process the POST if we have registered a callback for it 00395 sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, 00396 received_coap_header, 00397 msg_code); 00398 00399 if (received_coap_header) { 00400 if ((operation() & SN_GRS_POST_ALLOWED) != 0) { 00401 if (received_coap_header->content_format != COAP_CT_NONE) { 00402 set_coap_content_type(received_coap_header->content_format); 00403 } 00404 if(received_coap_header->payload_ptr) { 00405 tr_debug("M2MObject::handle_post_request() - Update Object with new values"); 00406 uint16_t coap_content_type = 0; 00407 bool content_type_present = false; 00408 if(received_coap_header->content_format != COAP_CT_NONE) { 00409 content_type_present = true; 00410 if(coap_response) { 00411 coap_content_type = received_coap_header->content_format; 00412 } 00413 } // if(received_coap_header->content_format) 00414 if(!content_type_present && 00415 (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || 00416 M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { 00417 coap_content_type = M2MBase::coap_content_type(); 00418 } 00419 00420 tr_debug("M2MObject::handle_post_request() - Request Content-type: %d", coap_content_type); 00421 00422 if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type || 00423 COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type) { 00424 set_coap_content_type(coap_content_type); 00425 uint32_t instance_id = 0; 00426 // Check next free instance id 00427 for(instance_id = 0; instance_id <= MAX_UNINT_16_COUNT; instance_id++) { 00428 if(NULL == object_instance(instance_id)) { 00429 break; 00430 } 00431 if(instance_id == MAX_UNINT_16_COUNT) { 00432 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00433 break; 00434 } 00435 } 00436 if(COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) { 00437 bool is_obj_instance = false; 00438 bool obj_instance_exists = false; 00439 is_obj_instance = M2MTLVDeserializer::is_object_instance(received_coap_header->payload_ptr); 00440 if (is_obj_instance) { 00441 instance_id = M2MTLVDeserializer::instance_id(received_coap_header->payload_ptr); 00442 tr_debug("M2MObject::handle_post_request() - instance id in TLV: %" PRIu32, instance_id); 00443 // Check if instance id already exists 00444 if (object_instance(instance_id)){ 00445 obj_instance_exists = true; 00446 } 00447 } 00448 if (!obj_instance_exists && coap_response) { 00449 M2MObjectInstance *obj_instance = create_object_instance(instance_id); 00450 if (obj_instance) { 00451 obj_instance->set_operation(M2MBase::GET_PUT_ALLOWED); 00452 } 00453 00454 M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; 00455 if(is_obj_instance) { 00456 tr_debug("M2MObject::handle_post_request() - TLV data contains ObjectInstance"); 00457 error = M2MTLVDeserializer::deserialise_object_instances(received_coap_header->payload_ptr, 00458 received_coap_header->payload_len, 00459 *this, 00460 M2MTLVDeserializer::Post); 00461 } else if(obj_instance && 00462 (M2MTLVDeserializer::is_resource(received_coap_header->payload_ptr) || 00463 M2MTLVDeserializer::is_multiple_resource(received_coap_header->payload_ptr))) { 00464 tr_debug("M2MObject::handle_post_request() - TLV data contains Resources"); 00465 error = M2MTLVDeserializer::deserialize_resources(received_coap_header->payload_ptr, 00466 received_coap_header->payload_len, 00467 *obj_instance, 00468 M2MTLVDeserializer::Post); 00469 } else { 00470 error = M2MTLVDeserializer::NotValid; 00471 } 00472 switch(error) { 00473 case M2MTLVDeserializer::None: 00474 if(observation_handler) { 00475 execute_value_updated = true; 00476 } 00477 coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); 00478 00479 if (coap_response->options_list_ptr) { 00480 00481 StringBuffer<MAX_OBJECT_PATH_NAME> obj_name; 00482 00483 if (obj_name.ensure_space(M2MBase::resource_name_length() + (1 + 5 + 1))) { 00484 obj_name.append(M2MBase::name()); 00485 obj_name.append('/'); 00486 obj_name.append_int(instance_id); 00487 00488 coap_response->options_list_ptr->location_path_len = obj_name.get_size(); 00489 coap_response->options_list_ptr->location_path_ptr = 00490 alloc_copy((uint8_t*)obj_name.c_str(), obj_name.get_size()); 00491 // todo: else return error 00492 } 00493 } 00494 // todo: else return error 00495 msg_code = COAP_MSG_CODE_RESPONSE_CREATED; 00496 break; 00497 case M2MTLVDeserializer::NotAllowed: 00498 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00499 break; 00500 case M2MTLVDeserializer::NotValid: 00501 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00502 break; 00503 case M2MTLVDeserializer::NotFound: 00504 msg_code = COAP_MSG_CODE_RESPONSE_NOT_FOUND; 00505 break; 00506 case M2MTLVDeserializer::OutOfMemory: 00507 msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; 00508 break; 00509 } 00510 00511 } else { 00512 tr_error("M2MObject::handle_post_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST"); 00513 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; 00514 } 00515 } 00516 } else { 00517 msg_code =COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; 00518 } // if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) 00519 } else { 00520 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Missing Payload"); 00521 msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 00522 } 00523 } else { // if ((object->operation() & SN_GRS_POST_ALLOWED) != 0) 00524 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00525 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 00526 } 00527 } else { //if(received_coap_header) 00528 tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); 00529 msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 00530 } 00531 00532 if(coap_response) { 00533 coap_response->msg_code = msg_code; 00534 } 00535 return coap_response; 00536 } 00537 00538 void M2MObject::notification_update(uint16_t obj_instance_id) 00539 { 00540 tr_debug("M2MObject::notification_update - id: %d", obj_instance_id); 00541 M2MReportHandler *report_handler = M2MBase::report_handler(); 00542 if(report_handler && is_under_observation()) { 00543 report_handler->set_notification_trigger(obj_instance_id); 00544 } 00545 } 00546 00547 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 00548 void M2MObject::set_endpoint(M2MEndpoint *endpoint) 00549 { 00550 _endpoint = endpoint; 00551 } 00552 00553 M2MEndpoint* M2MObject::get_endpoint() const 00554 { 00555 return _endpoint; 00556 } 00557 #endif 00558 00559 M2MBase *M2MObject::get_parent() const 00560 { 00561 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION 00562 return (M2MBase *) get_endpoint(); 00563 #else 00564 return NULL; 00565 #endif 00566 }
Generated on Tue Jul 12 2022 19:12:13 by 1.7.2