diff --git a/MODULE.bazel b/MODULE.bazel index 847493c5f..45cbd27a9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -102,6 +102,12 @@ git_override( remote = "https://github.com/eclipse-score/score-crates.git", ) +bazel_dep(name = "iceoryx2", version = "0.7.0") +local_path_override( + module_name = "iceoryx2", + path = "/home/piotr/score/iceoryx2", +) + bazel_dep(name = "boost.program_options", version = "1.87.0") bazel_dep(name = "download_utils", version = "1.0.1") diff --git a/score/mw/com/impl/BUILD b/score/mw/com/impl/BUILD index 908c0aa29..ab507b317 100644 --- a/score/mw/com/impl/BUILD +++ b/score/mw/com/impl/BUILD @@ -173,6 +173,7 @@ cc_library( ":skeleton_field", "//score/mw/com/impl/methods:skeleton_method", "//score/mw/com/impl/plumbing:event", + "@iceoryx2//:iceoryx2-cxx-static", ], ) @@ -272,6 +273,7 @@ cc_library( "//score/mw/com/impl/plumbing", "//score/mw/com/impl/tracing:skeleton_tracing", "@score_baselibs//score/language/futurecpp", + "@iceoryx2//:iceoryx2-cxx-static", ], ) @@ -323,6 +325,7 @@ cc_library( "//score/mw/com/impl/plumbing", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/result", + "@iceoryx2//:iceoryx2-cxx-static", ], ) @@ -348,6 +351,7 @@ cc_library( "//score/mw/com/impl/tracing:proxy_event_tracing_data", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/language/safecpp/scoped_function:scope", + "@iceoryx2//:iceoryx2-cxx-static", ], ) diff --git a/score/mw/com/impl/plumbing/BUILD b/score/mw/com/impl/plumbing/BUILD index 67128aa34..0dbaa8202 100644 --- a/score/mw/com/impl/plumbing/BUILD +++ b/score/mw/com/impl/plumbing/BUILD @@ -523,7 +523,10 @@ cc_library( features = COMPILER_WARNING_FEATURES, tags = ["FFI"], visibility = ["//score/mw/com/impl:__subpackages__"], - deps = ["//score/mw/com/impl/bindings/lola:event"], + deps = [ + "//score/mw/com/impl/bindings/lola:event", + "@iceoryx2//:iceoryx2-cxx-static", + ], ) cc_library( diff --git a/score/mw/com/impl/plumbing/sample_allocatee_ptr.h b/score/mw/com/impl/plumbing/sample_allocatee_ptr.h index c12d712d1..64ac12c66 100644 --- a/score/mw/com/impl/plumbing/sample_allocatee_ptr.h +++ b/score/mw/com/impl/plumbing/sample_allocatee_ptr.h @@ -23,6 +23,8 @@ #include #include +#include "iox2/iceoryx2.hpp" + namespace score::mw::com::impl { @@ -105,7 +107,7 @@ class SampleAllocateePtr // coverity[autosar_cpp14_a15_5_3_violation : FALSE] pointer operator->() const noexcept; - private: + template // Suppress "AUTOSAR C++14 A0-1-3" rule finding. This rule states: "Every function defined in an anonymous // namespace, or static function with internal linkage, or private member function shall be used.". @@ -114,7 +116,17 @@ class SampleAllocateePtr explicit SampleAllocateePtr(T ptr) : internal_{std::move(ptr)} { } + template + explicit SampleAllocateePtr(T ptr, std::shared_ptr> iox2_sample) : + internal_{std::move(ptr)}, iox2_sample_{std::move(iox2_sample)} + { + } + std::shared_ptr> GetIox2Sample() const noexcept + { + return iox2_sample_; + } + private: // Suppress "AUTOSAR C++14 A11-3-1", The rule states: "Friend declarations shall not be used". // Friend class required to access private constructor as we do not have everything we need public. // This is because we want to shield the end user from implementation details and avoid wrong usage. @@ -133,7 +145,8 @@ class SampleAllocateePtr friend class SampleAllocateePtrMutableView; // We don't use the pimpl idiom because it would require dynamic memory allocation (that we want to avoid) - std::variant, std::unique_ptr> internal_; + std::variant, std::unique_ptr, SampleType*> internal_; + std::shared_ptr> iox2_sample_; }; template @@ -175,8 +188,13 @@ void SampleAllocateePtr::reset() noexcept internal_ptr.reset(nullptr); }, // coverity[autosar_cpp14_a7_1_7_violation] - [](const score::cpp::blank&) noexcept -> void {}); + [](const score::cpp::blank&) noexcept -> void {}, + [](SampleType* internal_ptr) noexcept -> void { + internal_ptr = nullptr; + } + ); std::visit(visitor, internal_); + //iox2_sample_.reset(); } template @@ -185,6 +203,7 @@ void SampleAllocateePtr::Swap(SampleAllocateePtr& other) // Search for custom swap functions via ADL, and use std::swap if none are found. using std::swap; swap(internal_, other.internal_); + swap(iox2_sample_, other.iox2_sample_); } template @@ -213,7 +232,12 @@ auto SampleAllocateePtr::Get() const noexcept -> pointer // coverity[autosar_cpp14_a7_1_7_violation] [](const score::cpp::blank&) noexcept -> ReturnType { return nullptr; - }); + }, + [](SampleType* internal_ptr) noexcept -> ReturnType { + return internal_ptr; + } + + ); return std::visit(visitor, internal_); } @@ -241,7 +265,11 @@ SampleAllocateePtr::operator bool() const noexcept // coverity[autosar_cpp14_a7_1_7_violation] [](const score::cpp::blank&) noexcept -> bool { return false; - }); + }, + [](SampleType* internal_ptr) noexcept -> bool { + return internal_ptr != nullptr; + } + ); return std::visit(visitor, internal_); } @@ -273,7 +301,11 @@ typename std::add_lvalue_reference::type SampleAllocateePtr ReturnType { std::terminate(); - }); + }, + [](SampleType* internal_ptr) noexcept -> ReturnType { + return *internal_ptr; + } + ); return std::visit(visitor, internal_); } @@ -304,7 +336,11 @@ auto SampleAllocateePtr::operator->() const noexcept -> pointer // coverity[autosar_cpp14_a7_1_7_violation] [](const score::cpp::blank&) noexcept -> ReturnType { std::terminate(); - }); + }, + [](SampleType* internal_ptr) noexcept -> ReturnType { + return internal_ptr; + } + ); return std::visit(visitor, internal_); } @@ -353,7 +389,7 @@ class SampleAllocateePtrView return std::get_if(&ptr_.internal_); } - const std::variant, std::unique_ptr>& + const std::variant, std::unique_ptr, SampleType*>& GetUnderlyingVariant() const noexcept { return ptr_.internal_; @@ -370,7 +406,7 @@ class SampleAllocateePtrMutableView public: explicit SampleAllocateePtrMutableView(SampleAllocateePtr& ptr) : ptr_{ptr} {} - std::variant, std::unique_ptr>& + std::variant, std::unique_ptr, SampleType*>& GetUnderlyingVariant() noexcept { // Suppress "AUTOSAR C++14 A9-3-1", The rule states: "Member functions shall not return non-const “raw” pointers diff --git a/score/mw/com/impl/proxy_base.cpp b/score/mw/com/impl/proxy_base.cpp index 007d0ad6c..36e6f7ce5 100644 --- a/score/mw/com/impl/proxy_base.cpp +++ b/score/mw/com/impl/proxy_base.cpp @@ -35,6 +35,9 @@ ProxyBase::ProxyBase(std::unique_ptr proxy_binding, HandleType han fields_{}, methods_{} { + iox2_node_ = std::make_unique>( + iox2::NodeBuilder().create().expect("successful node creation") + ); } ProxyBase::ProxyBase(ProxyBase&& other) noexcept diff --git a/score/mw/com/impl/proxy_base.h b/score/mw/com/impl/proxy_base.h index efb8d95cf..2ce558138 100644 --- a/score/mw/com/impl/proxy_base.h +++ b/score/mw/com/impl/proxy_base.h @@ -26,6 +26,8 @@ #include +#include "iox2/iceoryx2.hpp" + namespace score::mw::com::impl { @@ -82,6 +84,8 @@ class ProxyBase /// \return Handle identifying the service that this proxy is connected to. const HandleType& GetHandle() const noexcept; + std::unique_ptr> iox2_node_; + protected: using ProxyEvents = std::map>; using ProxyFields = std::map>; diff --git a/score/mw/com/impl/proxy_event.h b/score/mw/com/impl/proxy_event.h index 70e2351a6..f77404492 100644 --- a/score/mw/com/impl/proxy_event.h +++ b/score/mw/com/impl/proxy_event.h @@ -34,6 +34,8 @@ #include #include +#include "iox2/iceoryx2.hpp" + namespace score::mw::com::impl { @@ -122,6 +124,8 @@ class ProxyEvent final : public ProxyEventBase template Result GetNewSamples(F&& receiver, std::size_t max_num_samples) noexcept; + Result GetNumNewSamplesAvailable() const noexcept; + void InjectMock(IProxyEvent& proxy_event_mock) { proxy_event_mock_ = &proxy_event_mock; @@ -130,7 +134,8 @@ class ProxyEvent final : public ProxyEventBase private: ProxyEventBinding* GetTypedEventBinding() const noexcept; - + std::unique_ptr> iox2_service_; + std::unique_ptr> iox2_subscriber_; IProxyEvent* proxy_event_mock_; /// \brief Indicates whether this event is a field event (i.e. owned by a ProxyField, which is a composite of @@ -154,6 +159,28 @@ ProxyEvent::ProxyEvent(ProxyBase& base, proxy_base_view.MarkServiceElementBindingInvalid(); return; } + + const auto& instance_identifier = proxy_base_view.GetAssociatedHandleType().GetInstanceIdentifier(); + const auto& service_instance_deployment = InstanceIdentifierView{instance_identifier}.GetServiceInstanceDeployment(); + auto instance_specifier = service_instance_deployment.instance_specifier_.ToString(); + std::cout << "Creating ProxyEvent for instance specifier: " << instance_specifier << std::endl; + std::string service_name = (std::string(instance_specifier) + "/" + std::string(event_name)); + std::cout << "Creating iox2 service with name: " << service_name << std::endl; + iox2_service_ = std::make_unique>( + base.iox2_node_->service_builder( + iox2::ServiceName::create(service_name.c_str()).expect("valid service name") + ) + .publish_subscribe() + .open_or_create() + .expect("successful service creation/opening") + ); + iox2_subscriber_ = std::make_unique>( + iox2_service_->subscriber_builder().create().expect("successful subscriber creation") + ); + if(iox2_subscriber_ != nullptr) + { + std::cout << "iox2 subscriber created successfully for event: " << event_name << std::endl; + } } template @@ -193,6 +220,8 @@ ProxyEvent::ProxyEvent(ProxyEvent&& other) noexcept proxy_event_mock_{std::move(other.proxy_event_mock_)}, is_field_event_{std::move(other.is_field_event_)} { + iox2_service_ = std::move(other.iox2_service_); + iox2_subscriber_ = std::move(other.iox2_subscriber_); if (!is_field_event_) { // Since the address of this event has changed, we need update the address stored in the parent proxy. @@ -225,10 +254,27 @@ auto ProxyEvent::operator=(ProxyEvent&& other) & noexcept -> ProxyEv return *this; } +template +Result ProxyEvent::GetNumNewSamplesAvailable() const noexcept +{ + bool has_samples = iox2_subscriber_->has_samples().expect("has_samples succeeds"); + return has_samples ? 1 : 0; +} + template template Result ProxyEvent::GetNewSamples(F&& receiver, std::size_t max_num_samples) noexcept { + size_t samples_num = 0; + auto sample = iox2_subscriber_->receive().expect("receive succeeds"); + while (sample.has_value()) { + samples_num++; + SampleReferenceGuard reference_guard{}; + receiver(SamplePtr(std::make_unique(sample->payload()), std::move(reference_guard))); + sample = iox2_subscriber_->receive().expect("receive succeeds"); + } + return samples_num; + if (proxy_event_mock_ != nullptr) { typename IProxyEvent::Callback mock_callback = diff --git a/score/mw/com/impl/skeleton_base.cpp b/score/mw/com/impl/skeleton_base.cpp index 280a95867..dca265b59 100644 --- a/score/mw/com/impl/skeleton_base.cpp +++ b/score/mw/com/impl/skeleton_base.cpp @@ -93,6 +93,9 @@ SkeletonBase::SkeletonBase(std::unique_ptr skeleton_binding, skeleton_mock_{nullptr}, service_offered_flag_{} { + iox2_node_ = std::make_unique>( + iox2::NodeBuilder().create().expect("successful node creation") + ); } SkeletonBase::~SkeletonBase() diff --git a/score/mw/com/impl/skeleton_base.h b/score/mw/com/impl/skeleton_base.h index e949652d6..ba6b389e7 100644 --- a/score/mw/com/impl/skeleton_base.h +++ b/score/mw/com/impl/skeleton_base.h @@ -35,6 +35,8 @@ #include #include +#include "iox2/iceoryx2.hpp" + namespace score::mw::com::impl { @@ -99,6 +101,8 @@ class SkeletonBase skeleton_mock_ = &skeleton_mock; } + std::unique_ptr> iox2_node_; + protected: bool AreBindingsValid() const noexcept; diff --git a/score/mw/com/impl/skeleton_event.h b/score/mw/com/impl/skeleton_event.h index c66ba3b39..66724b6ef 100644 --- a/score/mw/com/impl/skeleton_event.h +++ b/score/mw/com/impl/skeleton_event.h @@ -30,6 +30,9 @@ #include #include #include +#include + +#include "iox2/iceoryx2.hpp" namespace score::mw::com::impl { @@ -110,6 +113,8 @@ class SkeletonEvent : public SkeletonEventBase } private: + std::unique_ptr> iox2_service_; + std::unique_ptr> iox2_publisher_; SkeletonEventBinding* GetTypedEventBinding() const noexcept; ISkeletonEvent* skeleton_event_mock_; }; @@ -127,6 +132,23 @@ SkeletonEvent::SkeletonEvent(SkeletonBase& skeleton_base, const SkeletonBaseView base_skeleton_view{skeleton_base}; base_skeleton_view.RegisterEvent(event_name, *this); + const auto& instance_identifier = base_skeleton_view.GetAssociatedInstanceIdentifier(); + const auto& service_instance_deployment = InstanceIdentifierView{instance_identifier}.GetServiceInstanceDeployment(); + auto instance_specifier = service_instance_deployment.instance_specifier_.ToString(); + std::string service_name = (std::string(instance_specifier) + "/" + std::string(event_name)); + std::cout << "Creating iox2 service with name: " << service_name << std::endl; + iox2_service_ = std::make_unique>( + skeleton_base.iox2_node_->service_builder( + iox2::ServiceName::create(service_name.c_str()).expect("valid service name") + ) + .publish_subscribe() + .open_or_create() + .expect("successful service creation/opening") + ); + iox2_publisher_ = std::make_unique>( + iox2_service_->publisher_builder().create().expect("successful publisher creation") + ); + if (binding_ != nullptr) { const SkeletonBaseView skeleton_base_view{skeleton_base}; @@ -166,8 +188,11 @@ SkeletonEvent::SkeletonEvent(SkeletonBase& skeleton_base, template SkeletonEvent::SkeletonEvent(SkeletonEvent&& other) noexcept - : SkeletonEventBase(std::move(other)), skeleton_event_mock_{std::move(other.skeleton_event_mock_)} + : SkeletonEventBase(std::move(other)), + iox2_service_{std::move(other.iox2_service_)}, iox2_publisher_{std::move(other.iox2_publisher_)}, + skeleton_event_mock_{std::move(other.skeleton_event_mock_)} { + std::cout << "Moving SkeletonEvent" << std::endl; // Since the address of this event has changed, we need update the address stored in the parent skeleton. SkeletonBaseView base_skeleton_view{skeleton_base_.get()}; base_skeleton_view.UpdateEvent(event_name_, *this); @@ -226,6 +251,9 @@ ResultBlank SkeletonEvent::Send(const EventType& sample_value) n template ResultBlank SkeletonEvent::Send(SampleAllocateePtr sample) noexcept { + iox2::send(std::move(*sample.GetIox2Sample())).expect("send successful"); + return Blank{}; + if (skeleton_event_mock_ != nullptr) { return skeleton_event_mock_->Send(std::move(sample)); @@ -254,6 +282,10 @@ ResultBlank SkeletonEvent::Send(SampleAllocateePtr sa template Result> SkeletonEvent::Allocate() noexcept { + auto sample = std::make_shared>(iox2_publisher_->loan().expect("acquire sample")); + SampleDataType* ptr = &(sample->payload_mut()); + return SampleAllocateePtr(std::move(ptr), sample); + if (skeleton_event_mock_ != nullptr) { return skeleton_event_mock_->Allocate(); diff --git a/score/mw/com/impl/tracing/skeleton_event_tracing.h b/score/mw/com/impl/tracing/skeleton_event_tracing.h index 87f0bf091..7bca6b687 100644 --- a/score/mw/com/impl/tracing/skeleton_event_tracing.h +++ b/score/mw/com/impl/tracing/skeleton_event_tracing.h @@ -90,6 +90,9 @@ TracingData ExtractBindingTracingData(const impl::SampleAllocateePtr }, [](const score::cpp::blank&) noexcept -> TracingData { std::terminate(); + }, + [](SampleType* internal_ptr) noexcept -> TracingData { + return {0U, {internal_ptr, sizeof(SampleType)}}; }); return std::visit(visitor, binding_ptr_variant); } @@ -135,6 +138,10 @@ TypeErasedSamplePtr CreateTypeErasedSamplePtr(impl::SampleAllocateePtr TypeErasedSamplePtr { std::terminate(); + }, + [](SampleType* internal_ptr) noexcept -> TypeErasedSamplePtr { + impl::tracing::TypeErasedSamplePtr type_erased_sample_ptr{std::make_unique(*internal_ptr)}; + return type_erased_sample_ptr; }); // LCOV_EXCL_STOP