joey shelton / LED_Demo

Dependencies:   MAX44000 PWM_Tone_Library nexpaq_mdk

Fork of LED_Demo by Maxim nexpaq

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mobject.cpp Source File

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