Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mtlvdeserializer.cpp Source File

m2mtlvdeserializer.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 // Needed for PRIu64 on FreeRTOS
00017 #include <stdio.h>
00018 // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX
00019 #ifndef __STDC_LIMIT_MACROS
00020 #define __STDC_LIMIT_MACROS
00021 #endif
00022 
00023 // Note: this macro is needed on armcc to get the the PRI*32 macros
00024 // from inttypes.h in a C++ code.
00025 #ifndef __STDC_FORMAT_MACROS
00026 #define __STDC_FORMAT_MACROS
00027 #endif
00028 
00029 #include "include/m2mtlvdeserializer.h"
00030 #include "mbed-client/m2mconstants.h"
00031 #include "mbed-trace/mbed_trace.h"
00032 
00033 #define TRACE_GROUP "mClt"
00034 #define BUFFER_SIZE 10
00035 
00036 bool M2MTLVDeserializer::is_object_instance(const uint8_t *tlv)
00037 {
00038     return is_object_instance(tlv, 0);
00039 }
00040 
00041 bool M2MTLVDeserializer::is_resource(const uint8_t *tlv)
00042 {
00043     return is_resource(tlv, 0);
00044 }
00045 
00046 bool M2MTLVDeserializer::is_multiple_resource(const uint8_t *tlv)
00047 {
00048     return is_multiple_resource(tlv, 0);
00049 }
00050 
00051 bool M2MTLVDeserializer::is_resource_instance(const uint8_t *tlv)
00052 {
00053     return is_resource_instance(tlv, 0);
00054 }
00055 
00056 M2MTLVDeserializer::Error M2MTLVDeserializer::deserialise_object_instances(const uint8_t* tlv,
00057                                                                            uint32_t tlv_size,
00058                                                                            M2MObject &object,
00059                                                                            M2MTLVDeserializer::Operation operation)
00060 {
00061     M2MTLVDeserializer::Error error = M2MTLVDeserializer::None;
00062     if (is_object_instance(tlv) ) {
00063         tr_debug("M2MTLVDeserializer::deserialise_object_instances");
00064         error = deserialize_object_instances(tlv, tlv_size, 0, object,operation,false);
00065         if(M2MTLVDeserializer::None == error) {
00066             error = deserialize_object_instances(tlv, tlv_size, 0, object,operation,true);
00067         }
00068     } else {
00069         tr_debug("M2MTLVDeserializer::deserialise_object_instances ::NotValid");
00070         error = M2MTLVDeserializer::NotValid;
00071     }
00072     return error;
00073 }
00074 
00075 M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resources(const uint8_t *tlv,
00076                                                                     uint32_t tlv_size,
00077                                                                     M2MObjectInstance &object_instance,
00078                                                                     M2MTLVDeserializer::Operation operation)
00079 {
00080     M2MTLVDeserializer::Error error = M2MTLVDeserializer::None;
00081     if (!is_resource(tlv) && !is_multiple_resource(tlv)) {
00082         error = M2MTLVDeserializer::NotValid;
00083     } else {
00084         error = deserialize_resources(tlv, tlv_size, 0, object_instance, operation,false);
00085         if(M2MTLVDeserializer::None == error) {
00086             if (M2MTLVDeserializer::Put == operation) {
00087                 remove_resources(tlv, tlv_size, object_instance, 0);
00088             }
00089             error = deserialize_resources(tlv, tlv_size, 0, object_instance, operation,true);
00090         }
00091     }
00092     return error;
00093 }
00094 
00095 M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv,
00096                                                                              uint32_t tlv_size,
00097                                                                              M2MResource &resource,
00098                                                                              M2MTLVDeserializer::Operation operation)
00099 {
00100     M2MTLVDeserializer::Error error = M2MTLVDeserializer::None;
00101     if (!is_multiple_resource(tlv)) {
00102         error = M2MTLVDeserializer::NotValid;
00103     } else {
00104         tr_debug("M2MTLVDeserializer::deserialize_resource_instances()");
00105         uint8_t offset = 2;
00106 
00107         ((tlv[0] & 0x20) == 0) ? offset : offset++;
00108 
00109         uint8_t length = tlv[0] & 0x18;
00110         if(length == 0x08) {
00111             offset += 1;
00112         } else if(length == 0x10) {
00113             offset += 2;
00114         } else if(length == 0x18) {
00115             offset += 3;
00116         }
00117 
00118         tr_debug("M2MTLVDeserializer::deserialize_resource_instances() Offset %d", offset);
00119         error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation,false);
00120         if(M2MTLVDeserializer::None == error) {
00121             if (M2MTLVDeserializer::Put == operation) {
00122                 remove_resource_instances(tlv, tlv_size, resource, offset);
00123             }
00124             error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation,true);
00125         }
00126     }
00127     return error;
00128 }
00129 
00130 M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_object_instances(const uint8_t *tlv,
00131                                                                            uint32_t tlv_size,
00132                                                                            uint32_t offset,
00133                                                                            M2MObject &object,
00134                                                                            M2MTLVDeserializer::Operation operation,
00135                                                                            bool update_value)
00136 {
00137     tr_debug("M2MTLVDeserializer::deserialize_object_instances()");
00138     M2MTLVDeserializer::Error error = M2MTLVDeserializer::None;
00139     TypeIdLength til(tlv, offset);
00140     til.deserialize();
00141     offset = til._offset;
00142 
00143     const M2MObjectInstanceList &list = object.instances();
00144     M2MObjectInstanceList::const_iterator it;
00145     it = list.begin();
00146 
00147     if (TYPE_OBJECT_INSTANCE == til._type) {
00148         for (; it!=list.end(); it++) {
00149             if((*it)->instance_id() == til._id) {
00150                 error = deserialize_resources(tlv, tlv_size, offset, (**it),operation, update_value);
00151             }
00152         }
00153         offset += til._length;
00154 
00155         if(offset < tlv_size) {
00156             error = deserialize_object_instances(tlv, tlv_size, offset, object, operation, update_value);
00157         }
00158     }
00159     return error;
00160 }
00161 
00162 M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resources(const uint8_t *tlv,
00163                                                                     uint32_t tlv_size,
00164                                                                     uint32_t offset,
00165                                                                     M2MObjectInstance &object_instance,
00166                                                                     M2MTLVDeserializer::Operation operation,
00167                                                                     bool update_value)
00168 {
00169     tr_debug("M2MTLVDeserializer::deserialize_resources()");
00170     M2MTLVDeserializer::Error error = M2MTLVDeserializer::None;
00171     TypeIdLength til(tlv, offset);
00172     til.deserialize();
00173     offset = til._offset;
00174 
00175     const M2MResourceList &list = object_instance.resources();
00176     M2MResourceList::const_iterator it;
00177     it = list.begin();
00178 
00179     bool found = false;
00180     bool multi = false;
00181     if (TYPE_RESOURCE == til._type || TYPE_RESOURCE_INSTANCE == til._type) {
00182         multi = false;
00183         for (; it!=list.end(); it++) {
00184             if((*it)->name_id() == til._id){
00185                 tr_debug("M2MTLVDeserializer::deserialize_resources() - Resource ID %d ", til._id);
00186                 found = true;
00187                 if(update_value) {
00188                     if(til._length > 0) {
00189                         tr_debug("M2MTLVDeserializer::deserialize_resources() - Update value");
00190                         if (!set_resource_instance_value((*it), tlv+offset, til._length)) {
00191                             error = M2MTLVDeserializer::OutOfMemory;
00192                             break;
00193                         }
00194                     } else {
00195                         tr_debug("M2MTLVDeserializer::deserialize_resources() - Clear Value");
00196                         (*it)->clear_value();
00197                     }
00198                     break;
00199                 } else if(0 == ((*it)->operation() & SN_GRS_PUT_ALLOWED)) {
00200                     tr_debug("M2MTLVDeserializer::deserialize_resources() - NOT_ALLOWED");
00201                     error = M2MTLVDeserializer::NotAllowed;
00202                     break;
00203                 }
00204             }
00205         }
00206     } else if (TYPE_MULTIPLE_RESOURCE == til._type) {
00207         multi = true;
00208         for (; it!=list.end(); it++) {
00209             if((*it)->supports_multiple_instances() &&
00210                     (*it)->name_id() == til._id) {
00211                 found = true;
00212                 error = deserialize_resource_instances(tlv, tlv_size, offset, (**it), object_instance, operation, update_value);
00213             }
00214         }
00215     } else {
00216         error = M2MTLVDeserializer::NotValid;
00217         return error;
00218     }
00219 
00220     if(!found) {
00221         if(M2MTLVDeserializer::Post == operation) {
00222             //Create a new Resource
00223             String id;
00224             id.append_int(til._id);
00225             M2MResource *resource = object_instance.create_dynamic_resource(id,"",M2MResourceInstance::OPAQUE,true,multi);
00226             if(resource) {
00227                 resource->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED);
00228             }
00229             if( TYPE_MULTIPLE_RESOURCE == til._type ) {
00230                 error = deserialize_resource_instances(tlv, tlv_size, offset, (*resource), object_instance, operation, update_value);
00231             }
00232         } else if(M2MTLVDeserializer::Put == operation) {
00233             error = M2MTLVDeserializer::NotFound;
00234         }
00235     }
00236 
00237 
00238     offset += til._length;
00239 
00240     if(offset < tlv_size) {
00241         error = deserialize_resources(tlv, tlv_size, offset, object_instance, operation, update_value);
00242     }
00243     return error;
00244 }
00245 
00246 M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv,
00247                                                                              uint32_t tlv_size,
00248                                                                              uint32_t offset,
00249                                                                              M2MResource &resource,
00250                                                                              M2MObjectInstance &object_instance,
00251                                                                              M2MTLVDeserializer::Operation operation,
00252                                                                              bool update_value)
00253 {
00254     M2MTLVDeserializer::Error error = M2MTLVDeserializer::None;
00255     TypeIdLength til(tlv, offset);
00256     til.deserialize();
00257     offset = til._offset;
00258 
00259     if (TYPE_MULTIPLE_RESOURCE == til._type || TYPE_RESOURCE_INSTANCE == til._type) {
00260         const M2MResourceInstanceList &list = resource.resource_instances();
00261         M2MResourceInstanceList::const_iterator it;
00262         it = list.begin();
00263         bool found = false;
00264         for (; it!=list.end(); it++) {
00265             if((*it)->instance_id() == til._id && TYPE_RESOURCE_INSTANCE == til._type) {
00266                 found = true;
00267                 if(update_value) {
00268                     if(til._length > 0) {
00269                         if (!set_resource_instance_value((*it), tlv+offset, til._length)) {
00270                             error = M2MTLVDeserializer::OutOfMemory;
00271                             break;
00272                         }
00273                     } else {
00274                         (*it)->clear_value();
00275                     }
00276                     break;
00277                 } else if(0 == ((*it)->operation() & SN_GRS_PUT_ALLOWED)) {
00278                     error = M2MTLVDeserializer::NotAllowed;
00279                     break;
00280                 }
00281             }
00282         }
00283 
00284         if(!found) {
00285             if(M2MTLVDeserializer::Post == operation) {
00286                 // Create a new Resource Instance
00287                 M2MResourceInstance *res_instance = object_instance.create_dynamic_resource_instance(resource.name(),"",
00288                                                                                                  resource.resource_instance_type(),
00289                                                                                                  true,
00290                                                                                                  til._id);
00291                 if(res_instance) {
00292                     res_instance->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED);
00293                 }
00294             } else if(M2MTLVDeserializer::Put == operation) {
00295                 error = M2MTLVDeserializer::NotFound;
00296             }
00297         }
00298     } else {
00299         error = M2MTLVDeserializer::NotValid;
00300         return error;
00301     }
00302 
00303     offset += til._length;
00304 
00305     if(offset < tlv_size) {
00306       error = deserialize_resource_instances(tlv, tlv_size, offset, resource, object_instance, operation, update_value);
00307     }
00308     return error;
00309 }
00310 
00311 M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv,
00312                                                                              uint32_t tlv_size,
00313                                                                              uint32_t offset,
00314                                                                              M2MResource &resource,
00315                                                                              M2MTLVDeserializer::Operation operation,
00316                                                                              bool update_value)
00317 {
00318     M2MTLVDeserializer::Error error = M2MTLVDeserializer::None;
00319     TypeIdLength til(tlv, offset);
00320     til.deserialize();
00321     offset = til._offset;
00322 
00323     if (TYPE_RESOURCE_INSTANCE == til._type) {
00324         const M2MResourceInstanceList &list = resource.resource_instances();
00325         M2MResourceInstanceList::const_iterator it;
00326         it = list.begin();
00327         bool found = false;
00328         for (; it!=list.end(); it++) {
00329             if((*it)->instance_id() == til._id) {
00330                 found = true;
00331                 if(update_value) {
00332                     if(til._length > 0) {
00333                         if (!set_resource_instance_value((*it),tlv+offset, til._length)) {
00334                             error = M2MTLVDeserializer::OutOfMemory;
00335                             break;
00336                         }
00337                     } else {
00338                         (*it)->clear_value();
00339                     }
00340                     break;
00341                 } else if(0 == ((*it)->operation() & SN_GRS_PUT_ALLOWED)) {
00342                     error = M2MTLVDeserializer::NotAllowed;
00343                     break;
00344                 }
00345             }
00346         }
00347         if(!found) {
00348             if(M2MTLVDeserializer::Post == operation) {
00349                 error = M2MTLVDeserializer::NotAllowed;
00350             } else if(M2MTLVDeserializer::Put == operation) {
00351                 error = M2MTLVDeserializer::NotFound;
00352             }
00353         }
00354     } else {
00355         error = M2MTLVDeserializer::NotValid;
00356         return error;
00357     }
00358 
00359     offset += til._length;
00360 
00361     if(offset < tlv_size) {
00362          error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation, update_value);
00363     }
00364     return error;
00365 }
00366 
00367 bool M2MTLVDeserializer::is_object_instance(const uint8_t *tlv, uint32_t offset)
00368 {
00369     bool ret = false;
00370     if (tlv) {
00371         uint8_t value = tlv[offset];
00372         ret = (TYPE_OBJECT_INSTANCE == (value & TYPE_RESOURCE));
00373     }
00374     return ret;
00375 }
00376 
00377 uint16_t M2MTLVDeserializer::instance_id(const uint8_t *tlv)
00378 {
00379     TypeIdLength til(tlv, 0);
00380     til.deserialize();
00381     uint16_t id = til._id;
00382     return id;
00383 }
00384 
00385 bool M2MTLVDeserializer::is_resource(const uint8_t *tlv, uint32_t offset)
00386 {
00387     bool ret = false;
00388     if (tlv) {
00389         ret = (TYPE_RESOURCE == (tlv[offset] & TYPE_RESOURCE));
00390     }
00391     return ret;
00392 }
00393 
00394 bool M2MTLVDeserializer::is_multiple_resource(const uint8_t *tlv, uint32_t offset)
00395 {
00396     bool ret = false;
00397     if (tlv) {
00398         ret = (TYPE_MULTIPLE_RESOURCE == (tlv[offset] & TYPE_RESOURCE));
00399     }
00400     return ret;
00401 }
00402 
00403 bool M2MTLVDeserializer::is_resource_instance(const uint8_t *tlv, uint32_t offset)
00404 {
00405     bool ret = false;
00406     if (tlv) {
00407         ret = (TYPE_RESOURCE_INSTANCE == (tlv[offset] & TYPE_RESOURCE));
00408     }
00409     return ret;
00410 }
00411 
00412 bool M2MTLVDeserializer::set_resource_instance_value(M2MResourceBase *res, const uint8_t *tlv, const uint32_t size)
00413 {
00414     int64_t value = 0;
00415     bool success = true;
00416     switch (res->resource_instance_type()) {
00417         case M2MResourceBase::INTEGER:
00418         case M2MResourceBase::BOOLEAN:
00419         case M2MResourceBase::TIME:
00420             value = String::convert_array_to_integer(tlv, size);
00421             if (!res->set_value(value)) {
00422                 success = false;
00423             }
00424             break;
00425         // Todo! implement conversion for other types as well
00426         case M2MResourceBase::STRING:
00427         case M2MResourceBase::FLOAT:
00428         case M2MResourceBase::OPAQUE:
00429         case M2MResourceBase::OBJLINK:
00430             if (!res->set_value(tlv, size)) {
00431                 success = false;
00432             }
00433             break;
00434         default:
00435             break;
00436     }
00437 
00438     return success;
00439 }
00440 
00441 void M2MTLVDeserializer::remove_resources(const uint8_t *tlv,
00442                                           uint32_t tlv_size,
00443                                           M2MObjectInstance &object_instance,
00444                                           uint32_t offset_size)
00445 {
00446     tr_debug("M2MTLVDeserializer::remove_resources");
00447     uint32_t offset = offset_size;
00448     const M2MResourceList &list = object_instance.resources();
00449     M2MResourceList::const_iterator it;
00450 
00451     it = list.begin();
00452     for (; it!=list.end();) {
00453         bool found = false;
00454         while(offset < tlv_size) {
00455             TypeIdLength til(tlv, offset);
00456             til.deserialize();
00457             offset = til._offset;
00458             offset += til._length;
00459             if((*it)->name_id() == til._id){
00460                 offset = offset_size;
00461                 found = true;
00462                 break;
00463             }
00464         }
00465         offset = offset_size;
00466 
00467         // Remove resource if not part of the TLV message
00468         if (!found) {
00469             tr_debug("M2MTLVDeserializer::remove_resources - remove resource %" PRId32, (*it)->name_id());
00470             object_instance.remove_resource((*it)->name());
00471         } else {
00472             ++it;
00473         }
00474     }
00475 }
00476 
00477 void M2MTLVDeserializer::remove_resource_instances(const uint8_t *tlv,
00478                                           uint32_t tlv_size,
00479                                           M2MResource &resource,
00480                                           uint32_t offset_size)
00481 {
00482     tr_debug("M2MTLVDeserializer::remove_resource_instances");
00483     uint32_t offset = offset_size;
00484     const M2MResourceInstanceList &list = resource.resource_instances();
00485     M2MResourceInstanceList::const_iterator it;
00486     it = list.begin();
00487 
00488     for (; it!=list.end();) {
00489         bool found = false;
00490         while (offset < tlv_size) {
00491             TypeIdLength til(tlv, offset);
00492             til.deserialize();
00493             offset = til._offset;
00494             offset += til._length;
00495             if ((*it)->instance_id() == til._id){
00496                 offset = offset_size;
00497                 found = true;
00498                 break;
00499             }
00500         }
00501         offset = offset_size;
00502 
00503         // Remove resource instance if not part of the TLV message
00504         if (!found) {
00505             tr_debug("M2MTLVDeserializer::remove_resource_instances - remove resource instance %d", (*it)->instance_id());
00506             resource.remove_resource_instance((*it)->instance_id());
00507         } else {
00508             ++it;
00509         }
00510     }
00511 }
00512 
00513 TypeIdLength::TypeIdLength(const uint8_t *tlv, uint32_t offset)
00514 : _tlv(tlv), _offset(offset), _type(tlv[offset] & 0xC0), _id(0), _length(0)
00515 {
00516 }
00517 
00518 void TypeIdLength::deserialize()
00519 {
00520     uint32_t idLength = _tlv[_offset] & ID16;
00521     uint32_t lengthType = _tlv[_offset] & LENGTH24;
00522     if (0 == lengthType) {
00523         _length = _tlv[_offset] & 0x07;
00524     }
00525     _offset++;
00526 
00527     deserialiseID(idLength);
00528     deserialiseLength(lengthType);
00529 }
00530 
00531 void TypeIdLength::deserialiseID(uint32_t idLength)
00532 {
00533     _id = _tlv[_offset++] & 0xFF;
00534     if (ID16 == idLength) {
00535         _id = (_id << 8) + (_tlv[_offset++] & 0xFF);
00536     }
00537 }
00538 
00539 void TypeIdLength::deserialiseLength(uint32_t lengthType)
00540 {
00541     if (lengthType > 0) {
00542         _length = _tlv[_offset++] & 0xFF;
00543     }
00544     if (lengthType > LENGTH8) {
00545         _length = (_length << 8) + (_tlv[_offset++] & 0xFF);
00546     }
00547     if (lengthType > LENGTH16) {
00548         _length = (_length << 8) + (_tlv[_offset++] & 0xFF);
00549     }
00550 }