From a8b8da86961dd16f148d563771fee89079e56acc Mon Sep 17 00:00:00 2001 From: GwnDaan Date: Sun, 5 Jan 2025 22:28:14 +0100 Subject: [PATCH] feat(tc): allow deserializing into existing DDOP object in order to extend it --- .../isobus_device_descriptor_object_pool.hpp | 27 +++++++++++--- .../isobus_device_descriptor_object_pool.cpp | 35 ++++++++++++++++++- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/isobus/include/isobus/isobus/isobus_device_descriptor_object_pool.hpp b/isobus/include/isobus/isobus/isobus_device_descriptor_object_pool.hpp index eed369d2..29505f26 100644 --- a/isobus/include/isobus/isobus/isobus_device_descriptor_object_pool.hpp +++ b/isobus/include/isobus/isobus/isobus_device_descriptor_object_pool.hpp @@ -13,6 +13,7 @@ #include "isobus/isobus/can_NAME.hpp" #include "isobus/isobus/isobus_task_controller_client_objects.hpp" +#include #include namespace isobus @@ -107,25 +108,43 @@ namespace isobus std::uint8_t numberDecimals, std::uint16_t uniqueID); + /// @brief Removes all objects from the DDOP that have a certain type + /// @param objectType The type of object to remove + /// @returns `true` if any objects were removed, `false` if no objects were removed + bool remove_objects_with_type(task_controller_object::ObjectTypes objectType); + + /// @brief Removes all objects from the DDOP that have a certain object ID + /// @param objectID The object ID to remove + /// @returns `true` if any objects were removed, `false` if no objects were removed + bool remove_object_with_id(std::uint16_t objectID); + + /// @brief Removes all objects from the DDOP that match a certain predicate + /// @param predicate The predicate to match against + /// @returns `true` if any objects were removed, `false` if no objects were removed + bool remove_where(std::function predicate); + /// @brief Attempts to take a binary object pool and convert it back into - /// C++ objects. Useful for a task controller server or to view the content + /// C++ objects. The object's will be added to the list of objects, + /// or replaced if an object already exists with the same identifier. /// of a DDOP captured in a CAN log, for example. /// @param binaryPool The binary object pool, as an array of bytes. /// @param clientNAME The ISO NAME of the source ECU for this DDOP, or NAME(0) to ignore checking against actual ECU NAME /// @returns True if the object pool was successfully deserialized, otherwise false. - /// NOTE: This only means that the pool was deserialized. It does not mean that the + /// @note This only means that the pool was deserialized. It does not mean that the /// relationship between objects is valid. You may have to do additional /// checking on the pool before using it. bool deserialize_binary_object_pool(std::vector &binaryPool, NAME clientNAME = NAME(0)); /// @brief Attempts to take a binary object pool and convert it back into - /// C++ objects. Useful for a task controller server or to view the content + /// C++ objects. The object's will be added to the list of objects, + /// or replaced if an object already exists with the same identifier. + /// Useful for a task controller server or to view the content /// of a DDOP captured in a CAN log, for example. /// @param binaryPool The binary object pool, as an array of bytes. /// @param binaryPoolSizeBytes The size of the DDOP to process in bytes. /// @param clientNAME The ISO NAME of the source ECU for this DDOP, or NAME(0) to ignore checking against actual ECU NAME /// @returns True if the object pool was successfully deserialized, otherwise false. - /// NOTE: This only means that the pool was deserialized. It does not mean that the + /// @note This only means that the pool was deserialized. It does not mean that the /// relationship between objects is valid. You may have to do additional /// checking on the pool before using it. bool deserialize_binary_object_pool(const std::uint8_t *binaryPool, std::uint32_t binaryPoolSizeBytes, NAME clientNAME = NAME(0)); diff --git a/isobus/src/isobus_device_descriptor_object_pool.cpp b/isobus/src/isobus_device_descriptor_object_pool.cpp index dc2083f2..6c8a03c4 100644 --- a/isobus/src/isobus_device_descriptor_object_pool.cpp +++ b/isobus/src/isobus_device_descriptor_object_pool.cpp @@ -345,6 +345,35 @@ namespace isobus return retVal; } + bool DeviceDescriptorObjectPool::remove_objects_with_type(task_controller_object::ObjectTypes objectType) + { + return remove_where([objectType](const task_controller_object::Object &object) { return object.get_object_type() == objectType; }); + } + + bool DeviceDescriptorObjectPool::remove_object_with_id(std::uint16_t objectID) + { + return remove_where([objectID](const task_controller_object::Object &object) { return object.get_object_id() == objectID; }); + } + + bool DeviceDescriptorObjectPool::remove_where(std::function predicate) + { + bool retVal = false; + + for (auto it = objectList.begin(); it != objectList.end();) + { + if (predicate(*(*it))) + { + it = objectList.erase(it); + retVal = true; + } + else + { + ++it; + } + } + return retVal; + } + bool DeviceDescriptorObjectPool::deserialize_binary_object_pool(std::vector &binaryPool, NAME clientNAME) { return deserialize_binary_object_pool(binaryPool.data(), static_cast(binaryPool.size()), clientNAME); @@ -357,7 +386,6 @@ namespace isobus if ((nullptr != binaryPool) && (0 != binaryPoolSizeBytes)) { LOG_DEBUG("[DDOP]: Attempting to deserialize a binary object pool with size %u.", binaryPoolSizeBytes); - clear(); // Iterate over the DDOP and convert to objects. // Using the size to track how much is left to process. @@ -489,6 +517,7 @@ namespace isobus extendedStructureLabel.push_back(binaryPool[31 + numberDeviceSerialNumberBytes + numberDesignatorBytes + numberSoftwareVersionBytes + i]); } + remove_objects_with_type(task_controller_object::ObjectTypes::Device); // Make sure the previous device object is removed if (add_device(deviceDesignator, deviceSoftwareVersion, deviceSerialNumber, deviceStructureLabel, localizationLabel, extendedStructureLabel, clientNAME.get_full_name())) { binaryPoolSizeBytes -= expectedSize; @@ -553,6 +582,7 @@ namespace isobus deviceElementDesignator.push_back(binaryPool[7 + i]); } + remove_object_with_id(uniqueID); // Make sure the previous device element object is removed if (add_device_element(deviceElementDesignator, elementNumber, parentObject, type, uniqueID)) { auto DETObject = std::static_pointer_cast(get_object_by_id(uniqueID)); @@ -611,6 +641,7 @@ namespace isobus processDataDesignator.push_back(binaryPool[10 + i]); } + remove_object_with_id(uniqueID); // Make sure the previous device process data object is removed if (add_device_process_data(processDataDesignator, DDI, presentationObjectID, binaryPool[7], binaryPool[8], uniqueID)) { binaryPoolSizeBytes -= expectedSize; @@ -661,6 +692,7 @@ namespace isobus designator.push_back(binaryPool[12 + i]); } + remove_object_with_id(uniqueID); // Make sure the previous device property object is removed if (add_device_property(designator, propertyValue, DDI, presentationObjectID, uniqueID)) { binaryPoolSizeBytes -= expectedSize; @@ -723,6 +755,7 @@ namespace isobus designator.push_back(binaryPool[15 + i]); } + remove_object_with_id(uniqueID); // Make sure the previous device value presentation object is removed if (add_device_value_presentation(designator, offset, scale, binaryPool[13], uniqueID)) { binaryPoolSizeBytes -= expectedSize;