diff --git a/scenarios/ArMemExample/config/ArMemExampleClient.cfg b/scenarios/ArMemExample/config/ArMemExampleClient.cfg index 55696f12e2f3b55f140305856f7a5a318484304a..ceaa86ed36d6745a23d3fd00018e667d2cf289f4 100644 --- a/scenarios/ArMemExample/config/ArMemExampleClient.cfg +++ b/scenarios/ArMemExample/config/ArMemExampleClient.cfg @@ -86,6 +86,14 @@ # ArmarX.ArMemExampleClient.tpc.pub.DebugObserver = DebugObserver +# ArmarX.ArMemExampleClient.tpc.sub.MemoryListener: Name of the `MemoryListener` topic to subscribe to. +# Attributes: +# - Default: MemoryUpdates +# - Case sensitivity: yes +# - Required: no +ArmarX.ArMemExampleClient.tpc.sub.MemoryListener = MemoryUpdates + + # ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_USER_CONFIG_DIR is set, the cache path will be made relative to ARMARX_USER_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${HOME}/.armarx) # Attributes: # - Default: mongo/.cache @@ -225,6 +233,6 @@ # - Case sensitivity: yes # - Required: no # - Possible values: {Debug, Error, Fatal, Important, Info, Undefined, Verbose, Warning} -# ArmarX.Verbosity = Info +ArmarX.Verbosity = Debug diff --git a/scenarios/ArMemExample/config/ArMemExampleMemory.cfg b/scenarios/ArMemExample/config/ArMemExampleMemory.cfg index 73c5d42b874edbc0decd4a94a8e3eb8e9450f8b1..5a8764611d35007fb9d7884f7b8101f451016897 100644 --- a/scenarios/ArMemExample/config/ArMemExampleMemory.cfg +++ b/scenarios/ArMemExample/config/ArMemExampleMemory.cfg @@ -103,6 +103,14 @@ # ArmarX.ArMemExampleMemory.tpc.pub.DebugObserver = DebugObserver +# ArmarX.ArMemExampleMemory.tpc.pub.MemoryListener: Name of the `MemoryListener` topic to publish data to. +# Attributes: +# - Default: MemoryUpdates +# - Case sensitivity: yes +# - Required: no +ArmarX.ArMemExampleMemory.tpc.pub.MemoryListener = MemoryUpdates + + # ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_USER_CONFIG_DIR is set, the cache path will be made relative to ARMARX_USER_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${HOME}/.armarx) # Attributes: # - Default: mongo/.cache diff --git a/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.cpp b/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.cpp index c591b97c9b3eb381f8aae0974c5bc6d427178522..37a59b28d5649cad9ed539857d9a19ffcc5de1fc 100644 --- a/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.cpp +++ b/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.cpp @@ -28,7 +28,6 @@ #include <RobotAPI/interface/aron.h> #include <RobotAPI/libraries/armem/component/MemoryRemoteGui.h> -#include <RobotAPI/libraries/armem/client/MemoryWriter.h> #include <RobotAPI/libraries/armem/memory/ice_conversions.h> #include <RobotAPI/components/armem/ArMemExampleMemory/aron/Primitive.aron.generated.h> @@ -86,7 +85,6 @@ namespace armarx } ARMARX_CHECK_NOT_NULL(memory); - armem::MemoryID providerID; if (true) { armem::data::AddSegmentInput input; @@ -111,11 +109,38 @@ namespace armarx providerID = armem::MemoryID::fromString(result.segmentID); } - armem::MemoryWriter writer(memory); - - armem::MemoryID entityID = providerID; + entityID = providerID; entityID.entityName = "example_entity"; + // Subscribe to example_entity updates + memoryReader.subscribe(entityID, [&](const armem::MemoryID & sid, const std::vector<armem::MemoryID>& sids) + { + example_entityUpdated(sid); + }); + + task = new RunningTask<ArMemExampleClient>(this, &ArMemExampleClient::run); + task->start(); + } + + + void ArMemExampleClient::onDisconnectComponent() + { + } + + + void ArMemExampleClient::onExitComponent() + { + } + + + void ArMemExampleClient::run() + { + sleep(2); + ARMARX_IMPORTANT << "Running now."; + + armem::client::Writer writer(memory); + + armem::MemoryID snapshotID; { armem::Commit commit; @@ -266,21 +291,17 @@ namespace armarx { primitives(writer); } - } - void ArMemExampleClient::onDisconnectComponent() - { - } - - - void ArMemExampleClient::onExitComponent() + void ArMemExampleClient::example_entityUpdated(const armem::MemoryID& id) { + ARMARX_IMPORTANT << "example_entity got updated"; + // Fetch new data of example_entity and do something with it. } - bool ArMemExampleClient::primitives(armem::MemoryWriter& writer) + bool ArMemExampleClient::primitives(armem::client::Writer& writer) { ARMARX_IMPORTANT << "Adding segment " << "Primitive" << "/" << getName(); diff --git a/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.h b/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.h index af51519fd0d8d8f896dd92017a9f65116ecb4752..5fffaebff03b9b89f9b620a895ba74af012d8af4 100644 --- a/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.h +++ b/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.h @@ -20,21 +20,21 @@ * GNU General Public License */ + #pragma once +// ArmarX #include <ArmarXCore/core/Component.h> - #include <ArmarXCore/interface/observers/ObserverInterface.h> - +#include <ArmarXCore/util/tasks.h> #include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/LightweightRemoteGuiComponentPlugin.h> -// #include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h> - +// RobotAPI +//#include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h> #include <RobotAPI/interface/armem/MemoryInterface.h> #include <RobotAPI/interface/armem/MemoryNameSystemInterface.h> - -#include <RobotAPI/libraries/armem/client/MemoryClientComponentPlugin.h> +#include <RobotAPI/libraries/armem/client/ComponentPlugin.h> #include <RobotAPI/libraries/armem/memory/Memory.h> @@ -52,7 +52,6 @@ namespace armarx }; - /** * @defgroup Component-ArMemExampleClient ArMemExampleClient * @ingroup RobotAPI-Components @@ -65,9 +64,9 @@ namespace armarx * Detailed description of class ArMemExampleClient. */ class ArMemExampleClient : - virtual public armarx::Component - , virtual public armarx::armem::MemoryClientComponentPluginUser - , virtual public LightweightRemoteGuiComponentPluginUser + virtual public armarx::Component, + virtual public armarx::armem::client::ComponentPluginUser, + virtual public LightweightRemoteGuiComponentPluginUser { public: @@ -98,14 +97,25 @@ namespace armarx /// @see PropertyUser::createPropertyDefinitions() armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; + void run(); + private: + + armem::MemoryID providerID; + armem::MemoryID entityID; + + // Callback for updates on `example_entity`. + void example_entityUpdated(const armem::MemoryID& id); + // Examples - bool primitives(armem::MemoryWriter& writer); + bool primitives(armem::client::Writer& writer); private: + armarx::RunningTask<ArMemExampleClient>::pointer_type task; + armarx::DebugObserverInterfacePrx debugObserver; std::string memoryName = "Example"; diff --git a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp index fcd59af3018b6459bf20d43281cff022439c93f2..7fd18a174502d8ff9fbe22ff0a60bd4122e2ca2c 100644 --- a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp @@ -142,7 +142,7 @@ namespace armarx if (memoryName.size() > 0) { getProxy(memory, memoryName); - memoryReader = armem::MemoryReader(memory); + memoryReader = armem::client::Reader(memory); } // DebugObserver is optional (check for null on every call) if (!debugObserverName.empty()) diff --git a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.h b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.h index 36d618adb8979f718747ac89702ad34cf11851fe..7f5b2ac810a6a86dfe464ecf19a46480bc98c34c 100644 --- a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.h +++ b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.h @@ -33,7 +33,7 @@ #include <ArmarXCore/core/system/ImportExportComponent.h> #include <RobotAPI/interface/armem/MemoryInterface.h> -#include <RobotAPI/libraries/armem/client/MemoryReader.h> +#include <RobotAPI/libraries/armem/client/Reader.h> #include <RobotAPI/libraries/armem_gui/InstanceTreeWidget.h> #include <RobotAPI/libraries/armem_gui/MemoryQueryWidget.h> #include <RobotAPI/libraries/armem_gui/MemoryTreeWidget.h> @@ -126,7 +126,7 @@ namespace armarx std::string memoryName; armem::MemoryInterfacePrx memory; - armem::MemoryReader memoryReader; + armem::client::Reader memoryReader; armem::MemoryPtr memoryData; diff --git a/source/RobotAPI/interface/CMakeLists.txt b/source/RobotAPI/interface/CMakeLists.txt index 5eef8924c0732a542aee27778171a26053e92f33..09a7502102c009e07733934a998385dc5703a9db 100644 --- a/source/RobotAPI/interface/CMakeLists.txt +++ b/source/RobotAPI/interface/CMakeLists.txt @@ -106,6 +106,7 @@ set(SLICE_FILES armem/ReadingInterface.ice armem/WritingInterface.ice armem/MemoryInterface.ice + armem/MemoryListenerInterface.ice armem/MemoryNameSystemInterface.ice armem/query.ice diff --git a/source/RobotAPI/interface/armem.ice b/source/RobotAPI/interface/armem.ice index 6fa4705257ad47e82ec53d8804f9e5d5cadce39c..a01037e52a60b33cf9422b5c69b61eeb858a4e44 100644 --- a/source/RobotAPI/interface/armem.ice +++ b/source/RobotAPI/interface/armem.ice @@ -3,6 +3,7 @@ #include <RobotAPI/interface/armem/ReadingInterface.ice> #include <RobotAPI/interface/armem/WritingInterface.ice> #include <RobotAPI/interface/armem/MemoryInterface.ice> +#include <RobotAPI/interface/armem/MemoryListenerInterface.ice> module armarx diff --git a/source/RobotAPI/interface/armem/MemoryListenerInterface.ice b/source/RobotAPI/interface/armem/MemoryListenerInterface.ice new file mode 100644 index 0000000000000000000000000000000000000000..be95f31ada2eb87a25c92f1c206714b0fbe34d5e --- /dev/null +++ b/source/RobotAPI/interface/armem/MemoryListenerInterface.ice @@ -0,0 +1,18 @@ +#pragma once + + +#include <RobotAPI/interface/armem/memory.ice> + + +module armarx +{ + module armem + { + + interface MemoryListenerInterface + { + void memoryUpdated(data::MemoryIDs updatedIDs); + }; + + }; +}; diff --git a/source/RobotAPI/interface/armem/memory.ice b/source/RobotAPI/interface/armem/memory.ice index 352684de14d07f884f15fa8023bd261dfe29e0f2..b501eaf9e54a793dd3188182ba77ad2291af7abe 100644 --- a/source/RobotAPI/interface/armem/memory.ice +++ b/source/RobotAPI/interface/armem/memory.ice @@ -21,6 +21,8 @@ module armarx int instanceIndex = -1; } + sequence<MemoryID> MemoryIDs; + module detail { class MemoryItem diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt index da280dd43534197b9f6f879c303e9b8075d18bc0..d3505babc138b2b53e495bfce28de1bccb144a31 100644 --- a/source/RobotAPI/libraries/armem/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/CMakeLists.txt @@ -40,9 +40,11 @@ set(LIB_FILES mns/MemoryNameSystemClientPlugin.cpp mns/MemoryNameSystemComponentPlugin.cpp - client/MemoryWriter.cpp - client/MemoryReader.cpp - client/MemoryClientComponentPlugin.cpp + client/ComponentPlugin.cpp + client/Reader.cpp + client/ReaderComponentPlugin.cpp + client/Writer.cpp + client/WriterComponentPlugin.cpp component/IceMemory.cpp component/MemoryComponentPlugin.cpp @@ -83,9 +85,11 @@ set(LIB_HEADERS mns/MemoryNameSystemClientPlugin.h mns/MemoryNameSystemComponentPlugin.h - client/MemoryWriter.h - client/MemoryReader.h - client/MemoryClientComponentPlugin.h + client/ComponentPlugin.h + client/Reader.h + client/ReaderComponentPlugin.h + client/Writer.h + client/WriterComponentPlugin.h component/IceMemory.h component/MemoryComponentPlugin.h diff --git a/source/RobotAPI/libraries/armem/client/ComponentPlugin.cpp b/source/RobotAPI/libraries/armem/client/ComponentPlugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f67ed63b52a23149b1888e0fe96aa3be184091bd --- /dev/null +++ b/source/RobotAPI/libraries/armem/client/ComponentPlugin.cpp @@ -0,0 +1,21 @@ +#include <RobotAPI/libraries/armem/client/ComponentPlugin.h> + + +// ArmarX +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +// RobotAPI +#include <RobotAPI/libraries/armem/error.h> + + +armarx::armem::client::ComponentPluginUser::ComponentPluginUser() +{ + // pass +} + + +armarx::armem::client::ComponentPluginUser::~ComponentPluginUser() +{ + // pass +} + diff --git a/source/RobotAPI/libraries/armem/client/ComponentPlugin.h b/source/RobotAPI/libraries/armem/client/ComponentPlugin.h new file mode 100644 index 0000000000000000000000000000000000000000..cb8f3cd0bb35387236c6676bfcf09af5942892cd --- /dev/null +++ b/source/RobotAPI/libraries/armem/client/ComponentPlugin.h @@ -0,0 +1,33 @@ +#pragma once + + +// ArmarX +#include <ArmarXCore/core/Component.h> + +// RobotAPI +#include <RobotAPI/interface/armem/MemoryInterface.h> +#include <RobotAPI/interface/armem/MemoryNameSystemInterface.h> +#include <RobotAPI/libraries/armem/client/ReaderComponentPlugin.h> +#include <RobotAPI/libraries/armem/client/WriterComponentPlugin.h> +#include <RobotAPI/libraries/armem/mns/MemoryNameSystemClientPlugin.h> + + +namespace armarx::armem::client +{ + + /** + * @brief Utility for connecting a Memory to Ice. + */ + class ComponentPluginUser : + virtual public ReaderComponentPluginUser, + virtual public WriterComponentPluginUser + { + + public: + + ComponentPluginUser(); + ~ComponentPluginUser() override; + + }; + +} diff --git a/source/RobotAPI/libraries/armem/client/MemoryClientComponentPlugin.cpp b/source/RobotAPI/libraries/armem/client/MemoryClientComponentPlugin.cpp deleted file mode 100644 index 1d480535c9cfa793a54f5c1aedd93579b7722c9d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/client/MemoryClientComponentPlugin.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "MemoryClientComponentPlugin.h" - -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - -#include "../error.h" - - -namespace armarx::armem::plugins -{ - - MemoryClientComponentPlugin::~MemoryClientComponentPlugin() - { - } - -} - - -namespace armarx::armem -{ - - MemoryClientComponentPluginUser::MemoryClientComponentPluginUser() - { - addPlugin(plugin); - } - -} diff --git a/source/RobotAPI/libraries/armem/client/MemoryClientComponentPlugin.h b/source/RobotAPI/libraries/armem/client/MemoryClientComponentPlugin.h deleted file mode 100644 index 318c08c4c58a3a89a9ded0c2ac288dd448187cc2..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/client/MemoryClientComponentPlugin.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include <mutex> - -#include <ArmarXCore/core/Component.h> - -#include <RobotAPI/interface/armem/MemoryInterface.h> -#include <RobotAPI/interface/armem/MemoryNameSystemInterface.h> - -#include "../mns/MemoryNameSystemClientPlugin.h" -#include "MemoryReader.h" -#include "MemoryWriter.h" - - - -namespace armarx::armem::plugins -{ - - class MemoryClientComponentPlugin : public MemoryNameSystemClientPlugin - { - public: - - using MemoryNameSystemClientPlugin::MemoryNameSystemClientPlugin; - virtual ~MemoryClientComponentPlugin() override; - - - }; - -} - - -namespace armarx::armem -{ - - /** - * @brief Utility for connecting a Memory to Ice. - */ - class MemoryClientComponentPluginUser : - virtual public ManagedIceObject - , virtual public plugins::MemoryNameSystemClientPluginUser - { - public: - - MemoryClientComponentPluginUser(); - - - private: - - armem::plugins::MemoryClientComponentPlugin* plugin = nullptr; - - - }; - - -} diff --git a/source/RobotAPI/libraries/armem/client/MemoryReader.cpp b/source/RobotAPI/libraries/armem/client/Reader.cpp similarity index 59% rename from source/RobotAPI/libraries/armem/client/MemoryReader.cpp rename to source/RobotAPI/libraries/armem/client/Reader.cpp index c14180fd45087d31fde9af20d3578423ff3c4304..0a0985bd2fea1f47a7ce0bed55c49721636db1fd 100644 --- a/source/RobotAPI/libraries/armem/client/MemoryReader.cpp +++ b/source/RobotAPI/libraries/armem/client/Reader.cpp @@ -1,19 +1,19 @@ -#include "MemoryReader.h" +#include "Reader.h" #include <ArmarXCore/core/logging/Logging.h> #include "../memory/ice_conversions.h" -namespace armarx::armem +namespace armarx::armem::client { - MemoryReader::MemoryReader(ReadingInterfacePrx memory) : memory(memory) + Reader::Reader(ReadingInterfacePrx memory) : memory(memory) { } - MemoryPtr MemoryReader::getLatestSnapshots() + MemoryPtr Reader::getLatestSnapshots() { armem::query::EntityQueryPtr entityQuery = new armem::query::entity::Single(); armem::query::ProviderSegmentQueryPtr providerQuery = new armem::query::provider::All({entityQuery}); @@ -23,7 +23,7 @@ namespace armarx::armem return queryToCpp(memoryQuery); } - MemoryPtr MemoryReader::getAllData() + MemoryPtr Reader::getAllData() { armem::query::EntityQueryPtr entityQuery = new armem::query::entity::All(); armem::query::ProviderSegmentQueryPtr providerQuery = new armem::query::provider::All({entityQuery}); @@ -33,12 +33,12 @@ namespace armarx::armem return queryToCpp(memoryQuery); } - data::MemoryPtr MemoryReader::query(query::MemoryQueryPtr query) + data::MemoryPtr Reader::query(query::MemoryQueryPtr query) { return this->query(query::MemoryQuerySeq{query}); } - data::MemoryPtr MemoryReader::query(query::MemoryQuerySeq queries) + data::MemoryPtr Reader::query(query::MemoryQuerySeq queries) { try { @@ -59,14 +59,44 @@ namespace armarx::armem return nullptr; } - MemoryPtr MemoryReader::queryToCpp(query::MemoryQueryPtr query) + MemoryPtr Reader::queryToCpp(query::MemoryQueryPtr query) { return armem::fromIce<armem::MemoryPtr>(this->query(query)); } - MemoryPtr MemoryReader::queryToCpp(query::MemoryQuerySeq queries) + MemoryPtr Reader::queryToCpp(query::MemoryQuerySeq queries) { return armem::fromIce<armem::MemoryPtr>(this->query(queries)); } + + void + Reader::updated(const std::vector<MemoryID>& updatedSnapshotIDs) + { + for (const auto& [subscription, callback] : callbacks) + { + std::vector<MemoryID> matchingSnapshotIDs; + + for (const MemoryID& updatedSnapshotID : updatedSnapshotIDs) + { + if (contains(subscription, updatedSnapshotID)) + { + matchingSnapshotIDs.push_back(updatedSnapshotID); + } + } + + if (not matchingSnapshotIDs.empty()) + { + callback(subscription, matchingSnapshotIDs); + } + } + } + + + void + Reader::subscribe(const MemoryID& id, callback callback) + { + callbacks[id] = callback; + } + } diff --git a/source/RobotAPI/libraries/armem/client/MemoryReader.h b/source/RobotAPI/libraries/armem/client/Reader.h similarity index 59% rename from source/RobotAPI/libraries/armem/client/MemoryReader.h rename to source/RobotAPI/libraries/armem/client/Reader.h index 240c2a3ef188848b49ac18a4df195bb8722fdc86..3ab4b5e4500ceeff464c3fb66a83b360852a0eb9 100644 --- a/source/RobotAPI/libraries/armem/client/MemoryReader.h +++ b/source/RobotAPI/libraries/armem/client/Reader.h @@ -1,26 +1,36 @@ #pragma once -#include <RobotAPI/interface/armem/ReadingInterface.h> +// STD/STL +#include <functional> +#include <unordered_map> +#include <vector> + +// RobotAPI +#include <RobotAPI/interface/armem/ReadingInterface.h> +#include <RobotAPI/interface/armem/MemoryListenerInterface.h> #include <RobotAPI/libraries/armem/core/ice_conversions.h> #include <RobotAPI/libraries/armem/memory/Memory.h> -namespace armarx::armem +namespace armarx::armem::client { /** * @brief Helps sending data to a memory. */ - class MemoryReader + class Reader { + + using callback = std::function<void(const MemoryID& subscriptionID, const std::vector<MemoryID>& updatedSnapshotIDs)>; + public: /** * @brief Construct a memory reader. * @param memory The memory proxy. */ - MemoryReader(ReadingInterfacePrx memory = nullptr); + Reader(ReadingInterfacePrx memory = nullptr); MemoryPtr getLatestSnapshots(); @@ -32,17 +42,21 @@ namespace armarx::armem MemoryPtr queryToCpp(query::MemoryQueryPtr query); MemoryPtr queryToCpp(query::MemoryQuerySeq queries); + void updated(const std::vector<MemoryID>& updatedIDs); + void subscribe(const MemoryID& entityID, callback callback); operator bool() const { return bool(memory); } - public: ReadingInterfacePrx memory; + private: + + std::unordered_map<MemoryID, callback> callbacks; }; diff --git a/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.cpp b/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed1fc7b8735d2e36ffc2b05d846c0a45754cb80c --- /dev/null +++ b/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.cpp @@ -0,0 +1,43 @@ +#include <RobotAPI/libraries/armem/client/ReaderComponentPlugin.h> + + +// ArmarX +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +// RobotAPI +#include <RobotAPI/libraries/armem/error.h> + + +armarx::armem::client::ReaderComponentPlugin::~ReaderComponentPlugin() +{ + // pass +} + + +void +armarx::armem::client::ReaderComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) +{ + MemoryNameSystemClientPlugin::postCreatePropertyDefinitions(properties); + properties->topic<MemoryListenerInterface>("MemoryUpdates"); +} + + +armarx::armem::client::ReaderComponentPluginUser::ReaderComponentPluginUser() +{ + addPlugin(plugin); +} + + +armarx::armem::client::ReaderComponentPluginUser::~ReaderComponentPluginUser() +{ + // pass +} + + +void +armarx::armem::client::ReaderComponentPluginUser::memoryUpdated(const std::vector<data::MemoryID>& updatedIDsIce, const Ice::Current& current) +{ + std::vector<MemoryID> updatedIDs; + fromIce(updatedIDsIce, updatedIDs); + memoryReader.updated(updatedIDs); +} diff --git a/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.h b/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.h new file mode 100644 index 0000000000000000000000000000000000000000..20680ab189fba0dadf1f849ed1036f3fad1aa693 --- /dev/null +++ b/source/RobotAPI/libraries/armem/client/ReaderComponentPlugin.h @@ -0,0 +1,58 @@ +#pragma once + + +// STD/STL +#include <vector> + +// ArmarX +#include <ArmarXCore/core/Component.h> + +// RobotAPI +#include <RobotAPI/interface/armem/MemoryInterface.h> +#include <RobotAPI/interface/armem/MemoryListenerInterface.h> +#include <RobotAPI/interface/armem/MemoryNameSystemInterface.h> +#include <RobotAPI/libraries/armem/client/Reader.h> +#include <RobotAPI/libraries/armem/mns/MemoryNameSystemClientPlugin.h> + + +namespace armarx::armem::client +{ + + class ReaderComponentPlugin : + public plugins::MemoryNameSystemClientPlugin + { + + public: + + using plugins::MemoryNameSystemClientPlugin::MemoryNameSystemClientPlugin; + ~ReaderComponentPlugin() override; + + void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override; + + }; + + + class ReaderComponentPluginUser : + virtual public ManagedIceObject, + virtual public plugins::MemoryNameSystemClientPluginUser, + virtual public MemoryListenerInterface + { + + public: + + ReaderComponentPluginUser(); + ~ReaderComponentPluginUser() override; + + void memoryUpdated(const std::vector<data::MemoryID>& updatedIDs, const Ice::Current& current) override; + + protected: + + Reader memoryReader; + + private: + + ReaderComponentPlugin* plugin = nullptr; + + }; + +} diff --git a/source/RobotAPI/libraries/armem/client/MemoryWriter.cpp b/source/RobotAPI/libraries/armem/client/Writer.cpp similarity index 77% rename from source/RobotAPI/libraries/armem/client/MemoryWriter.cpp rename to source/RobotAPI/libraries/armem/client/Writer.cpp index 03025a45d82eb0133925fb78958c310901ff3c12..cd6b409f8880c41eee3e7f66a39e88dd08afe0ac 100644 --- a/source/RobotAPI/libraries/armem/client/MemoryWriter.cpp +++ b/source/RobotAPI/libraries/armem/client/Writer.cpp @@ -1,18 +1,18 @@ -#include "MemoryWriter.h" +#include "Writer.h" #include <ArmarXCore/core/exceptions/local/ExpressionException.h> #include "../error.h" -namespace armarx::armem +namespace armarx::armem::client { - MemoryWriter::MemoryWriter(WritingInterfacePrx memory) : memory(memory) + Writer::Writer(WritingInterfacePrx memory) : memory(memory) { } - data::AddSegmentResult MemoryWriter::addSegment(const std::string& coreSegmentName, const std::string& providerSegmentName) + data::AddSegmentResult Writer::addSegment(const std::string& coreSegmentName, const std::string& providerSegmentName) { data::AddSegmentInput input; input.coreSegmentName = coreSegmentName; @@ -20,14 +20,14 @@ namespace armarx::armem return addSegment(input); } - data::AddSegmentResult MemoryWriter::addSegment(const data::AddSegmentInput& input) + data::AddSegmentResult Writer::addSegment(const data::AddSegmentInput& input) { data::AddSegmentsResult results = addSegments({input}); ARMARX_CHECK_EQUAL(results.size(), 1); return results.at(0); } - data::AddSegmentsResult MemoryWriter::addSegments(const data::AddSegmentsInput& inputs) + data::AddSegmentsResult Writer::addSegments(const data::AddSegmentsInput& inputs) { ARMARX_CHECK_NOT_NULL(memory); data::AddSegmentsResult results = memory->addSegments(inputs); @@ -36,7 +36,7 @@ namespace armarx::armem } - CommitResult MemoryWriter::commit(Commit commit) + CommitResult Writer::commit(Commit commit) { ARMARX_CHECK_NOT_NULL(memory); @@ -74,7 +74,7 @@ namespace armarx::armem } - EntityUpdateResult MemoryWriter::commit(const EntityUpdate& update) + EntityUpdateResult Writer::commit(const EntityUpdate& update) { armem::Commit commit; commit.updates.push_back(update); diff --git a/source/RobotAPI/libraries/armem/client/MemoryWriter.h b/source/RobotAPI/libraries/armem/client/Writer.h similarity index 88% rename from source/RobotAPI/libraries/armem/client/MemoryWriter.h rename to source/RobotAPI/libraries/armem/client/Writer.h index eda2d506edc67fd121e42f79b890b53e8ce7a780..e7c7d67c17e63ae2f801eb99053391aba5ce5b87 100644 --- a/source/RobotAPI/libraries/armem/client/MemoryWriter.h +++ b/source/RobotAPI/libraries/armem/client/Writer.h @@ -5,13 +5,13 @@ #include <RobotAPI/libraries/armem/core/ice_conversions.h> -namespace armarx::armem +namespace armarx::armem::client { /** * @brief Helps sending data to a memory. */ - class MemoryWriter + class Writer { public: @@ -19,7 +19,7 @@ namespace armarx::armem * @brief Construct a memory writer. * @param memory The memory proxy. */ - MemoryWriter(WritingInterfacePrx memory = nullptr); + Writer(WritingInterfacePrx memory = nullptr); data::AddSegmentResult addSegment(const std::string& coreSegmentName, const std::string& providerSegmentName); diff --git a/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.cpp b/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b8780f32a5aa9ddf61dbf69d5d2ba7d83fb86f3 --- /dev/null +++ b/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.cpp @@ -0,0 +1,26 @@ +#include <RobotAPI/libraries/armem/client/WriterComponentPlugin.h> + + +// ArmarX +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +// RobotAPI +#include <RobotAPI/libraries/armem/error.h> + + +armarx::armem::client::WriterComponentPlugin::~WriterComponentPlugin() +{ + // pass +} + + +armarx::armem::client::WriterComponentPluginUser::WriterComponentPluginUser() +{ + addPlugin(plugin); +} + + +armarx::armem::client::WriterComponentPluginUser::~WriterComponentPluginUser() +{ + // pass +} diff --git a/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.h b/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.h new file mode 100644 index 0000000000000000000000000000000000000000..ea8136d9793b4999d57d382ea616c0fb6c4ed967 --- /dev/null +++ b/source/RobotAPI/libraries/armem/client/WriterComponentPlugin.h @@ -0,0 +1,49 @@ +#pragma once + + +// ArmarX +#include <ArmarXCore/core/Component.h> + +// RobotAPI +#include <RobotAPI/interface/armem/MemoryInterface.h> +#include <RobotAPI/interface/armem/MemoryNameSystemInterface.h> +#include <RobotAPI/libraries/armem/client/Writer.h> +#include <RobotAPI/libraries/armem/mns/MemoryNameSystemClientPlugin.h> + + +namespace armarx::armem::client +{ + + class WriterComponentPlugin : + public plugins::MemoryNameSystemClientPlugin + { + + public: + + using plugins::MemoryNameSystemClientPlugin::MemoryNameSystemClientPlugin; + ~WriterComponentPlugin() override; + + }; + + + class WriterComponentPluginUser : + virtual public ManagedIceObject, + virtual public plugins::MemoryNameSystemClientPluginUser + { + + public: + + WriterComponentPluginUser(); + ~WriterComponentPluginUser() override; + + protected: + + Writer memoryWriter; + + private: + + WriterComponentPlugin* plugin = nullptr; + + }; + +} diff --git a/source/RobotAPI/libraries/armem/component/IceMemory.cpp b/source/RobotAPI/libraries/armem/component/IceMemory.cpp index 4380907087f231a8e102379872d2b41bd1c157de..870a8304da8b4e521a192b9de6f640d73a495a27 100644 --- a/source/RobotAPI/libraries/armem/component/IceMemory.cpp +++ b/source/RobotAPI/libraries/armem/component/IceMemory.cpp @@ -15,6 +15,12 @@ namespace armarx::armem } + void IceMemory::setMemoryListener(MemoryListenerInterfacePrx memoryListener) + { + this->memoryListener = memoryListener; + } + + // WRITING armem::data::AddSegmentResult IceMemory::addSegment(const armem::data::AddSegmentInput& input, bool addCoreSegments) @@ -107,6 +113,9 @@ namespace armarx::armem armem::CommitResult IceMemory::commit(const armem::InternalCommit& commit) { + std::vector<data::MemoryID> updatedIDs; + const bool publishUpdates = memoryListener; + armem::CommitResult commitResult; for (const auto& update : commit.updates) { @@ -118,6 +127,12 @@ namespace armarx::armem result.success = true; result.snapshotID = snapshotID; result.timeArrived = update.timeArrived; + + if (publishUpdates) + { + data::MemoryID& id = updatedIDs.emplace_back(); + armem::toIce(id, snapshotID); + } } catch (const armem::error::ArMemError& e) { @@ -125,6 +140,12 @@ namespace armarx::armem result.errorMessage = e.what(); } } + + if (publishUpdates) + { + memoryListener->memoryUpdated(updatedIDs); + } + return commitResult; } diff --git a/source/RobotAPI/libraries/armem/component/IceMemory.h b/source/RobotAPI/libraries/armem/component/IceMemory.h index 4f3cf09b3f07fdaa80c0d1d445e2e39b8ac0a195..0ffcd932be4018a3513ed29d071a61a84a6a5df6 100644 --- a/source/RobotAPI/libraries/armem/component/IceMemory.h +++ b/source/RobotAPI/libraries/armem/component/IceMemory.h @@ -1,6 +1,7 @@ #pragma once #include <RobotAPI/interface/armem/MemoryInterface.h> +#include <RobotAPI/interface/armem/MemoryListenerInterface.h> #include "../memory/Memory.h" @@ -22,6 +23,8 @@ namespace armarx::armem /// Construct an IceMemory from an existing Memory. IceMemory(Memory* memory = nullptr); + void setMemoryListener(MemoryListenerInterfacePrx memoryListener); + // WRITING @@ -46,6 +49,8 @@ namespace armarx::armem Memory* memory; + MemoryListenerInterfacePrx memoryListener; + }; diff --git a/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.cpp b/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.cpp index 7fbebbfbf79b92d552b8ccb07546abf67b92d16d..ac3f912bdac7c48d60c0b66580f5a4f763fac1af 100644 --- a/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.cpp +++ b/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.cpp @@ -13,6 +13,14 @@ namespace armarx::armem::plugins MemoryComponentPlugin::~MemoryComponentPlugin() {} + + void MemoryComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) + { + MemoryNameSystemClientPlugin::postCreatePropertyDefinitions(properties); + properties->topic(memoryListener, "MemoryUpdates"); + } + + void MemoryComponentPlugin::postOnConnectComponent() { MemoryComponentPluginUser& parent = this->parent<MemoryComponentPluginUser>(); @@ -20,6 +28,7 @@ namespace armarx::armem::plugins { registerMemory(parent); } + parent.iceMemory.setMemoryListener(memoryListener); } diff --git a/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.h b/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.h index a1e0bd423dff46d6ae9914917d85013bd7a01c7e..5f59d7563d77a4821798d9cf6d337c40d8edb22b 100644 --- a/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.h +++ b/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.h @@ -5,6 +5,7 @@ #include <ArmarXCore/core/Component.h> #include <RobotAPI/interface/armem/MemoryInterface.h> +#include <RobotAPI/interface/armem/MemoryListenerInterface.h> #include <RobotAPI/interface/armem/MemoryNameSystemInterface.h> #include "../memory/Memory.h" @@ -28,6 +29,7 @@ namespace armarx::armem::plugins using MemoryNameSystemClientPlugin::MemoryNameSystemClientPlugin; virtual ~MemoryComponentPlugin() override; + void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override; void postOnConnectComponent() override; void preOnDisconnectComponent() override; @@ -44,6 +46,7 @@ namespace armarx::armem::plugins */ data::RemoveMemoryResult removeMemory(MemoryComponentPluginUser& parent); + MemoryListenerInterfacePrx memoryListener; }; } diff --git a/source/RobotAPI/libraries/armem/core/MemoryID.cpp b/source/RobotAPI/libraries/armem/core/MemoryID.cpp index dfb8d98b6f66743353cfaa590662758d056b9b92..493a7fb2ca5df6a6761a575e2ba1d83b0b09e032 100644 --- a/source/RobotAPI/libraries/armem/core/MemoryID.cpp +++ b/source/RobotAPI/libraries/armem/core/MemoryID.cpp @@ -54,6 +54,7 @@ namespace armarx::armem this->instanceIndex = instanceIndexFromStr(*it); } + std::string MemoryID::str() const { std::vector<std::string> items = getAllItems(); @@ -280,5 +281,64 @@ namespace armarx::armem } + bool + contains(const MemoryID& general, const MemoryID& specific) + { + if (general.memoryName.empty()) + { + return true; + } + else if (general.memoryName != specific.memoryName) + { + return false; + } + + if (general.coreSegmentName.empty()) + { + return true; + } + else if (general.coreSegmentName != specific.coreSegmentName) + { + return false; + } + + if (general.providerSegmentName.empty()) + { + return true; + } + else if (general.providerSegmentName != specific.providerSegmentName) + { + return false; + } + + if (general.entityName.empty()) + { + return true; + } + else if (general.entityName != specific.entityName) + { + return false; + } + + if (general.timestamp.toMicroSeconds() < 0) + { + return true; + } + else if (general.timestamp != specific.timestamp) + { + return false; + } + + if (general.instanceIndex < 0) + { + return true; + } + else if (general.instanceIndex != specific.instanceIndex) + { + return false; + } + + return true; + } } diff --git a/source/RobotAPI/libraries/armem/core/MemoryID.h b/source/RobotAPI/libraries/armem/core/MemoryID.h index d21981f570c64dc21a8e5b16aa35251857cbfe5b..95b2637caa61c5ca375dbb124f31ded2acc3984f 100644 --- a/source/RobotAPI/libraries/armem/core/MemoryID.h +++ b/source/RobotAPI/libraries/armem/core/MemoryID.h @@ -115,6 +115,15 @@ namespace armarx::armem friend std::ostream& operator<<(std::ostream& os, const MemoryID id); + bool operator== (const MemoryID& other) const + { + return memoryName == other.memoryName + and coreSegmentName == other.coreSegmentName + and providerSegmentName == other.providerSegmentName + and entityName == other.entityName + and timestamp == other.timestamp + and instanceIndex == other.instanceIndex; + } private: @@ -122,4 +131,25 @@ namespace armarx::armem }; + + bool + contains(const MemoryID& general, const MemoryID& specific); + } + + +namespace std +{ + + template <> + struct hash<armarx::armem::MemoryID> + { + std::size_t operator()(const armarx::armem::MemoryID& id) const + { + const std::string sid = id.str(); + return std::hash<string>()(sid); + } + }; + +} + diff --git a/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d811c053ba4c57864030eaa8b0d5a7485a6df58c --- /dev/null +++ b/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp @@ -0,0 +1,54 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::ArmarXObjects::armem + * @author Simon Ottenhaus ( simon dot ottenhaus at kit dot edu ) + * @date 2020 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#define BOOST_TEST_MODULE RobotAPI::ArmarXLibraries::armem + +#define ARMARX_BOOST_TEST + +#include <RobotAPI/Test.h> +#include "../core/MemoryID.h" + +#include <iostream> + + +namespace armem = armarx::armem; + + +BOOST_AUTO_TEST_CASE(test_memoryid_contains) +{ + armem::MemoryID general, specific; + + BOOST_CHECK(armem::contains(general, specific)); + + general.memoryName = "a"; + specific.memoryName = "b"; + + BOOST_CHECK(not armem::contains(general, specific)); + + specific.memoryName = "a"; + + BOOST_CHECK(armem::contains(general, specific)); + + specific.providerSegmentName = "aa"; + + BOOST_CHECK(armem::contains(general, specific)); +} diff --git a/source/RobotAPI/libraries/armem/test/CMakeLists.txt b/source/RobotAPI/libraries/armem/test/CMakeLists.txt index 9f5c3197ed6ea94551332b546cabd3d8b44d528c..28ea21d32f23d02a9b27137c5eed663a09c87565 100644 --- a/source/RobotAPI/libraries/armem/test/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/test/CMakeLists.txt @@ -3,6 +3,6 @@ SET(LIBS ${LIBS} ArmarXCore ${LIB_NAME}) armarx_add_test(ArMemMemoryTest ArMemMemoryTest.cpp "${LIBS}") +armarx_add_test(ArMemMemoryIDTest ArMemMemoryIDTest.cpp "${LIBS}") armarx_add_test(ArMemIceConversionsTest ArMemIceConversionsTest.cpp "${LIBS}") armarx_add_test(ArMemQueryTest ArMemQueryTest.cpp "${LIBS}") -