Example
Dependencies: FXAS21002 FXOS8700Q
Diff: simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mtlvdeserializer.cpp
- Revision:
- 0:11cc2b7889af
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mtlvdeserializer.cpp Tue Nov 19 09:49:38 2019 +0000 @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Needed for PRIu64 on FreeRTOS +#include <stdio.h> +// Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include "include/m2mtlvdeserializer.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-trace/mbed_trace.h" +#include "common_functions.h" + +#define TRACE_GROUP "mClt" +#define BUFFER_SIZE 10 + +bool M2MTLVDeserializer::is_object_instance(const uint8_t *tlv) +{ + return is_object_instance(tlv, 0); +} + +bool M2MTLVDeserializer::is_resource(const uint8_t *tlv) +{ + return is_resource(tlv, 0); +} + +bool M2MTLVDeserializer::is_multiple_resource(const uint8_t *tlv) +{ + return is_multiple_resource(tlv, 0); +} + +bool M2MTLVDeserializer::is_resource_instance(const uint8_t *tlv) +{ + return is_resource_instance(tlv, 0); +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialise_object_instances(const uint8_t* tlv, + uint32_t tlv_size, + M2MObject &object, + M2MTLVDeserializer::Operation operation) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + if (is_object_instance(tlv) ) { + tr_debug("M2MTLVDeserializer::deserialise_object_instances"); + error = deserialize_object_instances(tlv, tlv_size, 0, object,operation,false); + if(M2MTLVDeserializer::None == error) { + error = deserialize_object_instances(tlv, tlv_size, 0, object,operation,true); + } + } else { + tr_debug("M2MTLVDeserializer::deserialise_object_instances ::NotValid"); + error = M2MTLVDeserializer::NotValid; + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resources(const uint8_t *tlv, + uint32_t tlv_size, + M2MObjectInstance &object_instance, + M2MTLVDeserializer::Operation operation) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + if (!is_resource(tlv) && !is_multiple_resource(tlv)) { + error = M2MTLVDeserializer::NotValid; + } else { + error = deserialize_resources(tlv, tlv_size, 0, object_instance, operation,false); + if(M2MTLVDeserializer::None == error) { + if (M2MTLVDeserializer::Put == operation) { + remove_resources(tlv, tlv_size, object_instance, 0); + } + error = deserialize_resources(tlv, tlv_size, 0, object_instance, operation,true); + } + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + M2MResource &resource, + M2MTLVDeserializer::Operation operation) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + if (!is_multiple_resource(tlv)) { + error = M2MTLVDeserializer::NotValid; + } else { + tr_debug("M2MTLVDeserializer::deserialize_resource_instances()"); + uint8_t offset = 2; + + ((tlv[0] & 0x20) == 0) ? offset : offset++; + + uint8_t length = tlv[0] & 0x18; + if(length == 0x08) { + offset += 1; + } else if(length == 0x10) { + offset += 2; + } else if(length == 0x18) { + offset += 3; + } + + tr_debug("M2MTLVDeserializer::deserialize_resource_instances() Offset %d", offset); + error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation,false); + if(M2MTLVDeserializer::None == error) { + if (M2MTLVDeserializer::Put == operation) { + remove_resource_instances(tlv, tlv_size, resource, offset); + } + error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation,true); + } + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_object_instances(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MObject &object, + M2MTLVDeserializer::Operation operation, + bool update_value) +{ + tr_debug("M2MTLVDeserializer::deserialize_object_instances()"); + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + + const M2MObjectInstanceList &list = object.instances(); + M2MObjectInstanceList::const_iterator it; + it = list.begin(); + + if (TYPE_OBJECT_INSTANCE == til._type) { + for (; it!=list.end(); it++) { + if((*it)->instance_id() == til._id) { + error = deserialize_resources(tlv, tlv_size, offset, (**it),operation, update_value); + } + } + offset += til._length; + + if(offset < tlv_size) { + error = deserialize_object_instances(tlv, tlv_size, offset, object, operation, update_value); + } + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resources(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MObjectInstance &object_instance, + M2MTLVDeserializer::Operation operation, + bool update_value) +{ + tr_debug("M2MTLVDeserializer::deserialize_resources()"); + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + + const M2MResourceList &list = object_instance.resources(); + M2MResourceList::const_iterator it; + it = list.begin(); + + bool found = false; + bool multi = false; + if (TYPE_RESOURCE == til._type || TYPE_RESOURCE_INSTANCE == til._type) { + multi = false; + for (; it!=list.end(); it++) { + if((*it)->name_id() == til._id){ + tr_debug("M2MTLVDeserializer::deserialize_resources() - Resource ID %d ", til._id); + found = true; + if(update_value) { + if(til._length > 0) { + tr_debug("M2MTLVDeserializer::deserialize_resources() - Update value"); + if (!set_resource_instance_value((*it), tlv+offset, til._length)) { + error = M2MTLVDeserializer::OutOfMemory; + break; + } + } else { + tr_debug("M2MTLVDeserializer::deserialize_resources() - Clear Value"); + (*it)->clear_value(); + } + break; + } else if(0 == ((*it)->operation() & M2MBase::PUT_ALLOWED)) { + tr_debug("M2MTLVDeserializer::deserialize_resources() - NOT_ALLOWED"); + error = M2MTLVDeserializer::NotAllowed; + break; + } + } + } + } else if (TYPE_MULTIPLE_RESOURCE == til._type) { + multi = true; + for (; it!=list.end(); it++) { + if((*it)->supports_multiple_instances() && + (*it)->name_id() == til._id) { + found = true; + error = deserialize_resource_instances(tlv, tlv_size, offset, (**it), object_instance, operation, update_value); + } + } + } else { + error = M2MTLVDeserializer::NotValid; + return error; + } + + if (!found) { + if (M2MTLVDeserializer::Post == operation) { + //Create a new Resource + String id; + id.append_int(til._id); + M2MResource *resource = object_instance.create_dynamic_resource(id, "", M2MResourceInstance::OPAQUE, true, multi); + if (resource) { + resource->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED); + if (TYPE_MULTIPLE_RESOURCE == til._type) { + error = deserialize_resource_instances(tlv, tlv_size, offset, (*resource), object_instance, operation, update_value); + } + } + } else if (M2MTLVDeserializer::Put == operation) { + error = M2MTLVDeserializer::NotFound; + } + } + + offset += til._length; + + if (offset < tlv_size) { + error = deserialize_resources(tlv, tlv_size, offset, object_instance, operation, update_value); + } + + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MResource &resource, + M2MObjectInstance &object_instance, + M2MTLVDeserializer::Operation operation, + bool update_value) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + + if (TYPE_MULTIPLE_RESOURCE == til._type || TYPE_RESOURCE_INSTANCE == til._type) { + const M2MResourceInstanceList &list = resource.resource_instances(); + M2MResourceInstanceList::const_iterator it; + it = list.begin(); + bool found = false; + for (; it!=list.end(); it++) { + if((*it)->instance_id() == til._id && TYPE_RESOURCE_INSTANCE == til._type) { + found = true; + if(update_value) { + if(til._length > 0) { + if (!set_resource_instance_value((*it), tlv+offset, til._length)) { + error = M2MTLVDeserializer::OutOfMemory; + break; + } + } else { + (*it)->clear_value(); + } + break; + } else if(0 == ((*it)->operation() & M2MBase::PUT_ALLOWED)) { + error = M2MTLVDeserializer::NotAllowed; + break; + } + } + } + + if(!found) { + if(M2MTLVDeserializer::Post == operation) { + // Create a new Resource Instance + M2MResourceInstance *res_instance = object_instance.create_dynamic_resource_instance(resource.name(),"", + resource.resource_instance_type(), + true, + til._id); + if(res_instance) { + res_instance->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED); + } + } else if(M2MTLVDeserializer::Put == operation) { + error = M2MTLVDeserializer::NotFound; + } + } + } else { + error = M2MTLVDeserializer::NotValid; + return error; + } + + offset += til._length; + + if(offset < tlv_size) { + error = deserialize_resource_instances(tlv, tlv_size, offset, resource, object_instance, operation, update_value); + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MResource &resource, + M2MTLVDeserializer::Operation operation, + bool update_value) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + + if (TYPE_RESOURCE_INSTANCE == til._type) { + const M2MResourceInstanceList &list = resource.resource_instances(); + M2MResourceInstanceList::const_iterator it; + it = list.begin(); + bool found = false; + for (; it!=list.end(); it++) { + if((*it)->instance_id() == til._id) { + found = true; + if(update_value) { + if(til._length > 0) { + if (!set_resource_instance_value((*it),tlv+offset, til._length)) { + error = M2MTLVDeserializer::OutOfMemory; + break; + } + } else { + (*it)->clear_value(); + } + break; + } else if(0 == ((*it)->operation() & M2MBase::PUT_ALLOWED)) { + error = M2MTLVDeserializer::NotAllowed; + break; + } + } + } + if(!found) { + if(M2MTLVDeserializer::Post == operation) { + error = M2MTLVDeserializer::NotAllowed; + } else if(M2MTLVDeserializer::Put == operation) { + error = M2MTLVDeserializer::NotFound; + } + } + } else { + error = M2MTLVDeserializer::NotValid; + return error; + } + + offset += til._length; + + if(offset < tlv_size) { + error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation, update_value); + } + return error; +} + +bool M2MTLVDeserializer::is_object_instance(const uint8_t *tlv, uint32_t offset) +{ + bool ret = false; + if (tlv) { + uint8_t value = tlv[offset]; + ret = (TYPE_OBJECT_INSTANCE == (value & TYPE_RESOURCE)); + } + return ret; +} + +uint16_t M2MTLVDeserializer::instance_id(const uint8_t *tlv) +{ + TypeIdLength til(tlv, 0); + til.deserialize(); + uint16_t id = til._id; + return id; +} + +bool M2MTLVDeserializer::is_resource(const uint8_t *tlv, uint32_t offset) +{ + bool ret = false; + if (tlv) { + ret = (TYPE_RESOURCE == (tlv[offset] & TYPE_RESOURCE)); + } + return ret; +} + +bool M2MTLVDeserializer::is_multiple_resource(const uint8_t *tlv, uint32_t offset) +{ + bool ret = false; + if (tlv) { + ret = (TYPE_MULTIPLE_RESOURCE == (tlv[offset] & TYPE_RESOURCE)); + } + return ret; +} + +bool M2MTLVDeserializer::is_resource_instance(const uint8_t *tlv, uint32_t offset) +{ + bool ret = false; + if (tlv) { + ret = (TYPE_RESOURCE_INSTANCE == (tlv[offset] & TYPE_RESOURCE)); + } + return ret; +} + +bool M2MTLVDeserializer::set_resource_instance_value(M2MResourceBase *res, const uint8_t *tlv, const uint32_t size) +{ + bool success = true; + switch (res->resource_instance_type()) { + case M2MResourceBase::INTEGER: + case M2MResourceBase::BOOLEAN: + case M2MResourceBase::TIME: + { + int64_t value = String::convert_array_to_integer(tlv, size); + if (!res->set_value(value)) { + success = false; + } + break; + // Todo! implement conversion for other types as well + } + case M2MResourceBase::STRING: + case M2MResourceBase::OPAQUE: + case M2MResourceBase::OBJLINK: + if (!res->set_value(tlv, size)) { + success = false; + } + break; + case M2MResourceBase::FLOAT: + { + uint32_t value = common_read_32_bit(tlv); + if (!res->set_value_float(*(float*)&value)) { + success = false; + } + break; + } + default: + success = false; + break; + } + + return success; +} + +void M2MTLVDeserializer::remove_resources(const uint8_t *tlv, + uint32_t tlv_size, + M2MObjectInstance &object_instance, + uint32_t offset_size) +{ + tr_debug("M2MTLVDeserializer::remove_resources"); + uint32_t offset = offset_size; + const M2MResourceList &list = object_instance.resources(); + M2MResourceList::const_iterator it; + + it = list.begin(); + for (; it!=list.end();) { + bool found = false; + while(offset < tlv_size) { + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + offset += til._length; + if((*it)->name_id() == til._id){ + offset = offset_size; + found = true; + break; + } + } + offset = offset_size; + + // Remove resource if not part of the TLV message + if (!found) { + tr_debug("M2MTLVDeserializer::remove_resources - remove resource %" PRId32, (*it)->name_id()); + object_instance.remove_resource((*it)->name()); + } else { + ++it; + } + } +} + +void M2MTLVDeserializer::remove_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + M2MResource &resource, + uint32_t offset_size) +{ + tr_debug("M2MTLVDeserializer::remove_resource_instances"); + uint32_t offset = offset_size; + const M2MResourceInstanceList &list = resource.resource_instances(); + M2MResourceInstanceList::const_iterator it; + it = list.begin(); + + for (; it!=list.end();) { + bool found = false; + while (offset < tlv_size) { + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + offset += til._length; + if ((*it)->instance_id() == til._id){ + offset = offset_size; + found = true; + break; + } + } + offset = offset_size; + + // Remove resource instance if not part of the TLV message + if (!found) { + tr_debug("M2MTLVDeserializer::remove_resource_instances - remove resource instance %d", (*it)->instance_id()); + resource.remove_resource_instance((*it)->instance_id()); + } else { + ++it; + } + } +} + +TypeIdLength::TypeIdLength(const uint8_t *tlv, uint32_t offset) +: _tlv(tlv), _offset(offset), _type(tlv[offset] & 0xC0), _id(0), _length(0) +{ +} + +void TypeIdLength::deserialize() +{ + uint32_t idLength = _tlv[_offset] & ID16; + uint32_t lengthType = _tlv[_offset] & LENGTH24; + if (0 == lengthType) { + _length = _tlv[_offset] & 0x07; + } + _offset++; + + deserialiseID(idLength); + deserialiseLength(lengthType); +} + +void TypeIdLength::deserialiseID(uint32_t idLength) +{ + _id = _tlv[_offset++] & 0xFF; + if (ID16 == idLength) { + _id = (_id << 8) + (_tlv[_offset++] & 0xFF); + } +} + +void TypeIdLength::deserialiseLength(uint32_t lengthType) +{ + if (lengthType > 0) { + _length = _tlv[_offset++] & 0xFF; + } + if (lengthType > LENGTH8) { + _length = (_length << 8) + (_tlv[_offset++] & 0xFF); + } + if (lengthType > LENGTH16) { + _length = (_length << 8) + (_tlv[_offset++] & 0xFF); + } +}