Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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