Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
0900065
Added new example_10
serges147 Aug 26, 2024
b405bf5
Implemented raw subscriber #verification #docs #sonar
serges147 Aug 26, 2024
148ac93
latest cavl #verification #docs #sonar
serges147 Aug 26, 2024
6f9b1f8
better coverage of raw subscriber #verification #docs #sonar
serges147 Aug 26, 2024
00835c3
a bit reduce code duplication around subscriber impl creation #verifi…
serges147 Aug 26, 2024
bf9812f
more docs about extent bytes #verification #docs #sonar
serges147 Aug 26, 2024
c90cc9f
implemented rpc server #verification #docs #sonar
serges147 Aug 28, 2024
230dd3e
PR review fixes
serges147 Aug 28, 2024
bb34f63
Merge remote-tracking branch 'origin/sshirokov/examples' into sshirok…
serges147 Aug 28, 2024
eb3b39e
example todo #verification #docs #sonar
serges147 Aug 28, 2024
4be2aa5
Merge remote-tracking branch 'origin/main' into sshirokov/rpc_server
serges147 Aug 29, 2024
df19cab
example todo #verification #docs #sonar
serges147 Aug 29, 2024
f1a00cb
rename examples
serges147 Aug 29, 2024
01040e8
Implemented all `makeServer` overloads #verification #docs #sonar
serges147 Aug 30, 2024
b6e18a6
Sonar fixes; call duration stats #verification #docs #sonar
serges147 Aug 30, 2024
d2f2d99
Addressed some todos #verification #docs #sonar
serges147 Aug 30, 2024
3a285f0
added activity icons #verification #docs #sonar
serges147 Aug 30, 2024
813ffee
more coverage #verification #docs #sonar
serges147 Aug 30, 2024
c025b08
first draft of RPC client #verification #docs #sonar
serges147 Aug 31, 2024
e9377a9
Added `makeClient` overloads #verification #docs #sonar
serges147 Sep 1, 2024
71b9151
Added get/set priority methods #verification #docs #sonar
serges147 Sep 1, 2024
d8e690e
tranport matchers; sonar fixes #verification #docs #sonar
serges147 Sep 1, 2024
cb8f5c3
msg transport matchers #verification #docs #sonar
serges147 Sep 1, 2024
31fe12f
more client coverage #verification #docs #sonar
serges147 Sep 1, 2024
c470cbc
first draft of response promise
serges147 Sep 2, 2024
1a08445
add promise `Result`, `Expired` and `Waiting` options
serges147 Sep 2, 2024
40cacb5
implemented client `request` methods #verification #docs #sonar
serges147 Sep 4, 2024
8e799a9
implemented promise callbacks methods #verification #docs #sonar
serges147 Sep 4, 2024
886d7b2
sonar fixes #verification #docs #sonar
serges147 Sep 4, 2024
59e95f4
less boilerplate code at client tests #verification #docs #sonar
serges147 Sep 5, 2024
7925086
more client coverage for failures #verification #docs #sonar
serges147 Sep 5, 2024
3dfcb13
implemented response promise deadlines #verification #docs #sonar
serges147 Sep 5, 2024
4ab7503
better coverage of response promise deadlines #verification #docs #sonar
serges147 Sep 5, 2024
0204096
minor PR review fixes
serges147 Sep 5, 2024
6742854
Merge branch 'sshirokov/rpc_server' into sshirokov/rpc_client
serges147 Sep 5, 2024
551772b
minor sonar fixes
serges147 Sep 5, 2024
4a9e921
Merge branch 'main' into sshirokov/rpc_client
serges147 Sep 5, 2024
c35f767
Fixed build on mac ("linux" word should be part of a linux specific e…
serges147 Sep 5, 2024
d747e32
#verification #docs #sonar
serges147 Sep 5, 2024
214d7bb
transfer id allocator WIP
serges147 Sep 6, 2024
a09d6c7
1. Reworked presentation level PMR allocations
serges147 Sep 6, 2024
4b4f04e
Implemented `SmallRangeTransferIdGenerator`
serges147 Sep 6, 2024
c209e8d
minor sonar fixes
serges147 Sep 6, 2024
b539cb8
better coverage
serges147 Sep 8, 2024
4fe7a3d
better coverage
serges147 Sep 8, 2024
d607297
better coverage for different modulo
serges147 Sep 8, 2024
eb8f11c
better coverage for unhappy scenarios
serges147 Sep 9, 2024
f51d401
better coverage for unhappy scenarios
serges147 Sep 9, 2024
12d6c48
better coverage for unhappy scenarios
serges147 Sep 9, 2024
372bfc4
better coverage for unhappy scenarios
serges147 Sep 9, 2024
a4dca11
better coverage for unhappy scenarios
serges147 Sep 9, 2024
a973018
build fixes
serges147 Sep 10, 2024
1ad851a
fix build
serges147 Sep 10, 2024
7f057f9
more docs
serges147 Sep 10, 2024
0a69d2b
PR review fixes
serges147 Sep 11, 2024
0d708aa
minor fix
serges147 Sep 11, 2024
765d99e
move promise-related errors next to the promise itself
serges147 Sep 11, 2024
cfa7a1a
added can example
serges147 Sep 12, 2024
3ec3ca8
Add CAN transport unit test to cover multiple, out of order service r…
serges147 Sep 13, 2024
34d16cb
fix build
serges147 Sep 13, 2024
82177b6
fix build
serges147 Sep 13, 2024
b9377f2
PR review fixes:
serges147 Sep 16, 2024
1b94150
Merge branch 'sshirokov/rpc_client' into sshirokov/rpc_can_example
serges147 Sep 16, 2024
0a99f42
Merge branch 'main' into sshirokov/rpc_can_example
serges147 Sep 16, 2024
9465657
address "Switch to `transport::PayloadFragments`" todo
serges147 Sep 16, 2024
0284932
Address some todos:
serges147 Sep 16, 2024
5e9d6bc
#verification #docs #sonar
serges147 Sep 16, 2024
69a94a1
apply canard fix for issue 228
serges147 Sep 24, 2024
6f2b997
Merge branch 'main' into sshirokov/canard_issue_228
serges147 Oct 7, 2024
9f9fda9
latest libcanard
serges147 Oct 7, 2024
bc5c75c
Merge branch 'main' into issue/registry
serges147 Oct 8, 2024
5176f62
First draft of Registry (#388)
serges147 Oct 14, 2024
7cf4ca8
Optional Registry Provider at Node (#389)
serges147 Oct 17, 2024
52b9e2a
Use `cetl::string_view` (#390)
serges147 Oct 29, 2024
770cb53
Merge branch 'main' into issue/registry
serges147 Oct 30, 2024
0793514
Simplified registry implementation (#392)
serges147 Oct 31, 2024
38bd841
Defined `platform::storage::IKeyValue` interface (#393)
serges147 Nov 5, 2024
af6b092
Set default PMR, so that default behavior of `std::polymorphic_alloca…
serges147 Nov 5, 2024
7a253d5
switch to `3.0.preview` branch of Nunavut
serges147 Nov 5, 2024
28757d0
Implemented subscriber message type id from its name and version #ver…
serges147 Nov 6, 2024
5fb5ee4
Drop not needed anymore `#include <cassert>` #verification #docs #sonar
serges147 Nov 6, 2024
20cc478
minor fix (of N/A todo) #verification #docs #sonar
serges147 Nov 6, 2024
4fa6a92
Added several setters at Get Info provider.
serges147 Nov 8, 2024
0e0ad04
Set default PMR (#394)
serges147 Nov 8, 2024
a5da7a2
Merge branch 'issue/registry' into sshirokov/type_name
serges147 Nov 8, 2024
5193208
Merge remote-tracking branch 'origin/main' into sshirokov/type_name
serges147 Nov 8, 2024
077b80d
Eliminated `#include <cassert> // NOLINT for NUNAVUT_ASSERT`
serges147 Nov 8, 2024
daacaec
clang-tidy fixes
serges147 Nov 8, 2024
aab425c
Added setSoftwareVcsRevisionId & setSoftwareImageCrc
serges147 Nov 8, 2024
8af7280
grammar
serges147 Nov 8, 2024
1e96de4
sonar fix
serges147 Nov 8, 2024
7dc156a
latest 3.0.preview Nunavut
serges147 Nov 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include <libcyphal/transport/udp/udp_transport_impl.hpp>
#include <libcyphal/types.hpp>

#include <cassert> // NOLINT for NUNAVUT_ASSERT
#include <nunavut/support/serialization.hpp>

#include <gmock/gmock.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ TEST_F(Example_1_Presentation_2_Heartbeat_GetInfo_Udp, main)
ASSERT_THAT(heartbeat_subscriber, testing::Optional(testing::_));
heartbeat_subscriber->setOnReceiveCallback([&](const auto& arg) {
//
state.heartbeat_.print(arg.approx_now - startup_time_, arg.message, arg.metadata);
NodeHelpers::Heartbeat::print(arg.approx_now - startup_time_, arg.message, arg.metadata);
});

// Bring up 'GetInfo' server.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,9 @@
#include <libcyphal/transport/types.hpp>
#include <libcyphal/types.hpp>

#include <cassert> // NOLINT for NUNAVUT_ASSERT
#include <nunavut/support/serialization.hpp>
#include <uavcan/node/GetInfo_1_0.hpp>
#include <uavcan/node/Health_1_0.hpp>
#include <uavcan/node/Heartbeat_1_0.hpp>
#include <uavcan/node/Mode_1_0.hpp>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <gtest/gtest.h>

#include <algorithm>
#include <array>
#include <chrono>
#include <cstdint>
#include <cstdlib>
Expand Down Expand Up @@ -153,10 +154,13 @@ TEST_F(Example_2_Application_0_NodeHeartbeatGetInfo_Udp, main)
ASSERT_THAT(maybe_node, testing::VariantWith<Node>(testing::_)) << "Can't create node.";
auto node = cetl::get<Node>(std::move(maybe_node));
//
const std::string node_name{"org.opencyphal.Ex_2_App_0_Node_UDP"};
std::copy_n(node_name.begin(),
std::min(node_name.size(), 50UL),
std::back_inserter(node.getInfoProvider().response().name));
auto& get_info_prov = node.getInfoProvider();
get_info_prov //
.setSoftwareVersion(0, 1)
.setHardwareVersion(0, 2)
.setName("org.opencyphal.Ex_2_App_0_Node_UDP")
.setCertificateOfAuthenticity("my_cert")
.setUniqueId(std::array<std::uint8_t, 3>{0x12, 0x34, 0x56});

// 4. Bring up registry provider, and expose several registers. Load persistent storage.
//
Expand All @@ -167,15 +171,14 @@ TEST_F(Example_2_Application_0_NodeHeartbeatGetInfo_Udp, main)
const BitArray param_ro_val{BitArray::_traits_::TypeOf::value{{true, false}, mr_alloc_}, mr_alloc_};
auto param_ro = rgy.route("ro", [&param_ro_val] { return param_ro_val; });
//
auto& get_info = node.getInfoProvider().response();
auto param_name = rgy.route( //
auto param_name = rgy.route( //
"uavcan.node.description",
[this, &get_info] { return makeStringValue(registry::makeStringView(get_info.name)); },
[&get_info](const registry::IRegister::Value& value) -> cetl::optional<registry::SetError> {
[this, &get_info_prov] { return makeStringValue(registry::makeStringView(get_info_prov.response().name)); },
[&get_info_prov](const registry::IRegister::Value& value) -> cetl::optional<registry::SetError> {
//
if (const auto* const str = value.get_string_if())
{
get_info.name = str->value;
get_info_prov.setName(registry::makeStringView(str->value));
return cetl::nullopt;
}
return registry::SetError::Semantics;
Expand Down
1 change: 0 additions & 1 deletion docs/examples/platform/node_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include <libcyphal/transport/types.hpp>
#include <libcyphal/types.hpp>

#include <cassert> // NOLINT for NUNAVUT_ASSERT
#include <nunavut/support/serialization.hpp>
#include <uavcan/node/GetInfo_1_0.hpp>
#include <uavcan/node/Health_1_0.hpp>
Expand Down
124 changes: 122 additions & 2 deletions include/libcyphal/application/node/get_info_provider.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@
#include "libcyphal/types.hpp"

#include <cetl/pf17/cetlpf.hpp>
#include <cetl/pf20/cetlpf.hpp>

#include <uavcan/node/GetInfo_1_0.hpp>

#include <algorithm>
#include <chrono>
#include <cstdint>
#include <iterator>
#include <utility>

namespace libcyphal
Expand Down Expand Up @@ -86,14 +90,120 @@ class GetInfoProvider final // NOSONAR cpp:S4963
/// @brief Sets the response transmission timeout (default is 1s).
///
/// @param timeout Duration of the response transmission timeout. Applied for the next response transmission.
/// @return Reference to self for method chaining.
///
void setResponseTimeout(const Duration& timeout) noexcept
GetInfoProvider& setResponseTimeout(const Duration& timeout) noexcept
{
response_timeout_ = timeout;
return *this;
}

/// @brief Sets the node unique 128-bit id in the GetInfo response.
///
/// Default is all zeros.
/// Truncates the id if it exceeds 16 bytes capacity of the response field.
///
/// @return Reference to self for method chaining.
///
GetInfoProvider& setUniqueId(const cetl::span<const std::uint8_t> id) noexcept
{
response_.unique_id = {};
(void) std::copy_n(id.data(), std::min(id.size(), response_.unique_id.size()), response_.unique_id.begin());
return *this;
}

/// @brief Sets the node protocol version in the GetInfo response.
///
/// Default is '1.0'.
///
/// @return Reference to self for method chaining.
///
GetInfoProvider& setProtocolVersion(const std::uint8_t major, const std::uint8_t minor) noexcept // NOLINT
{
response_.protocol_version.major = major;
response_.protocol_version.minor = minor;
return *this;
}

/// @brief Sets the node hardware version in the GetInfo response.
///
/// Default is '0.0'.
///
/// @return Reference to self for method chaining.
///
GetInfoProvider& setHardwareVersion(const std::uint8_t major, const std::uint8_t minor) noexcept // NOLINT
{
response_.hardware_version.major = major;
response_.hardware_version.minor = minor;
return *this;
}

/// @brief Sets the node software version in the GetInfo response.
///
/// Default is '0.0'.
///
/// @return Reference to self for method chaining.
///
GetInfoProvider& setSoftwareVersion(const std::uint8_t major, const std::uint8_t minor) noexcept // NOLINT
{
response_.software_version.major = major;
response_.software_version.minor = minor;
return *this;
}

/// @brief Sets the node software Version Control System (VCS) revision in the GetInfo response.
///
/// Default is `0`.
///
/// @return Reference to self for method chaining.
///
GetInfoProvider& setSoftwareVcsRevisionId(const std::uint64_t revision_id)
{
response_.software_vcs_revision_id = revision_id;
return *this;
}

/// @brief Sets the node software image CRC in the GetInfo response.
///
/// Default is empty (not present).
///
/// @return Reference to self for method chaining.
///
GetInfoProvider& setSoftwareImageCrc(const std::uint64_t crc)
{
response_.software_image_crc.clear();
response_.software_image_crc.push_back(crc);
return *this;
}

/// @brief Sets the node name in the GetInfo response.
///
/// Default is ''.
/// Truncates the name if it exceeds the capacity of the response field.
///
/// @return Reference to self for method chaining.
///
GetInfoProvider& setName(const cetl::string_view name)
{
return setStringField<ArrayCapacity::name>(response_.name, name);
}

/// @brief Sets the node certificate of authenticity in the GetInfo response.
///
/// Default is ''.
/// Truncates the certificate if it exceeds the capacity of the response field.
///
/// @return Reference to self for method chaining.
///
GetInfoProvider& setCertificateOfAuthenticity(const cetl::string_view certificate)
{
return setStringField<ArrayCapacity::certificate_of_authenticity>(response_.certificate_of_authenticity,
certificate);
}

private:
using Server = presentation::ServiceServer<Service>;
using ArrayCapacity = Response::_traits_::ArrayCapacity;
using Server = presentation::ServiceServer<Service>;

GetInfoProvider(presentation::Presentation& presentation, Server&& server)
: presentation_{presentation}
Expand All @@ -115,6 +225,16 @@ class GetInfoProvider final // NOSONAR cpp:S4963
});
}

template <std::size_t Capacity, typename Field>
GetInfoProvider& setStringField(Field& field, const cetl::string_view value)
{
const auto dst_size = std::min(value.size(), Capacity);
field.clear();
field.reserve(dst_size);
(void) std::copy_n(value.begin(), dst_size, std::back_inserter(field));
return *this;
}

// MARK: Data members:

presentation::Presentation& presentation_;
Expand Down
4 changes: 2 additions & 2 deletions include/libcyphal/application/node/heartbeat_producer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class HeartbeatProducer final // NOSONAR cpp:S4963
///
struct Arg
{
/// Holds current heartbeat message.
/// Holds the current heartbeat message.
Message& message;

/// Holds the approximate time when the callback was called.
Expand All @@ -110,7 +110,7 @@ class HeartbeatProducer final // NOSONAR cpp:S4963

/// @brief Defines signature of the heartbeat update callback function.
///
/// Size of the function is arbitrary (4 pointers), but should be enough for simple lambdas.
/// The size of the function is arbitrary (4 pointers), but should be enough for simple lambdas.
///
static constexpr std::size_t FunctionSize = sizeof(void*) * 4;
using Function = cetl::pmr::function<void(const Arg& arg), FunctionSize>;
Expand Down
7 changes: 4 additions & 3 deletions include/libcyphal/application/registry/register.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,12 @@ using Register = ImplementationCell<IRegister, cetl::unbounded_variant<Footprint
inline uavcan::_register::Name_1_0 makeRegisterName(const uavcan::_register::Name_1_0::allocator_type& alloc,
const IRegister::Name name)
{
uavcan::_register::Name_1_0 out{alloc};
using uavcan::_register::Name_1_0;

Name_1_0 out{alloc};
if (!name.empty())
{
// TODO: Fix Nunavut to expose `ARRAY_CAPACITY` so we can use it here instead of 255 hardcode.
constexpr std::size_t NameCapacity = 255U;
constexpr auto NameCapacity = Name_1_0::_traits_::ArrayCapacity::name;
out.name.resize(std::min(name.size(), NameCapacity));

// No Sonar `cpp:S5356` b/c we need to pass name payload as raw data.
Expand Down
1 change: 0 additions & 1 deletion include/libcyphal/presentation/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include <cetl/pf17/cetlpf.hpp>
#include <cetl/pf20/cetlpf.hpp>

#include <cassert> // NOLINT for NUNAVUT_ASSERT
#include <nunavut/support/serialization.hpp>

#include <array>
Expand Down
1 change: 0 additions & 1 deletion include/libcyphal/presentation/common_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

#include <cetl/pf17/cetlpf.hpp>

#include <cassert> // NOLINT for NUNAVUT_ASSERT
#include <nunavut/support/serialization.hpp>

#include <cstdint>
Expand Down
1 change: 0 additions & 1 deletion include/libcyphal/presentation/publisher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include <cetl/pf17/cetlpf.hpp>
#include <cetl/pf20/cetlpf.hpp>

#include <cassert> // NOLINT for NUNAVUT_ASSERT
#include <nunavut/support/serialization.hpp>

#include <array>
Expand Down
1 change: 0 additions & 1 deletion include/libcyphal/presentation/response_promise.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include <cetl/pf17/cetlpf.hpp>
#include <cetl/pmr/function.hpp>

#include <cassert> // NOLINT for NUNAVUT_ASSERT
#include <nunavut/support/serialization.hpp>

#include <cstddef>
Expand Down
1 change: 0 additions & 1 deletion include/libcyphal/presentation/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include <cetl/pf20/cetlpf.hpp>
#include <cetl/pmr/function.hpp>

#include <cassert> // NOLINT for NUNAVUT_ASSERT
#include <nunavut/support/serialization.hpp>

#include <array>
Expand Down
10 changes: 6 additions & 4 deletions include/libcyphal/presentation/subscriber.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ class SubscriberBase : public SubscriberImpl::CallbackNode // NOSONAR cpp:S4963
///
/// @tparam Message The message type of the subscriber. This type has the following requirements:
/// - contains nested `allocator_type`, which is a PMR allocator
/// - constructible with the PMR allocator.
/// - constructible with the PMR allocator
/// - contains `_traits_::ExtentBytes` constant
/// - has freestanding `deserialize` function under its namespace (so that ADL will find it).
/// - contains `_traits_::FullNameAndVersion()` static constexpr method (-> `const char*`)
/// - has freestanding `deserialize` function under its namespace (so that ADL will find it)
///
template <typename Message>
class Subscriber final : public detail::SubscriberBase
Expand Down Expand Up @@ -147,7 +148,7 @@ class Subscriber final : public detail::SubscriberBase

explicit Subscriber(detail::SubscriberImpl* const impl)
: SubscriberBase{impl,
{Deserializer::getTypeId<Message>(),
{Deserializer::TypeIdGenerator<Message>::get(),
Deserializer::deserializeMsgOnceForManySubs<Message, Subscriber>}}
{
}
Expand Down Expand Up @@ -209,7 +210,8 @@ class Subscriber<void> final : public detail::SubscriberBase
friend class detail::SubscriberImpl;

explicit Subscriber(detail::SubscriberImpl* const impl)
: SubscriberBase{impl, {Deserializer::getTypeId<void>(), Deserializer::passRawMessageAsIs<Subscriber>}}
: SubscriberBase{impl,
{Deserializer::TypeIdGenerator<void>::get(), Deserializer::passRawMessageAsIs<Subscriber>}}
{
}

Expand Down
28 changes: 19 additions & 9 deletions include/libcyphal/presentation/subscriber_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "shared_object.hpp"

#include "libcyphal/common/cavl/cavl.hpp"
#include "libcyphal/common/crc.hpp"
#include "libcyphal/transport/msg_sessions.hpp"
#include "libcyphal/transport/scattered_buffer.hpp"
#include "libcyphal/transport/types.hpp"
Expand Down Expand Up @@ -53,18 +54,18 @@ class SubscriberImpl final : public cavl::Node<SubscriberImpl>, public SharedObj

}; // Context

using TypeId = std::uintptr_t;
using TypeId = std::uint64_t;
template <typename Message>
static TypeId getTypeId() noexcept
struct TypeIdGenerator
{
static const struct
static TypeId get() noexcept
{
} placeholder{};
// No Lint and Sonar cpp:S3630 "reinterpret_cast" should not be used" b/c it's a part of
// the type id/erasure pattern - we use this cast to be able to compare deserializers.
// NOLINTNEXTLINE(*-pro-type-reinterpret-cast)
return reinterpret_cast<TypeId>(&placeholder); // NOSONAR : cpp:S3630
}
const cetl::string_view type_name{Message::_traits_::FullNameAndVersion()};
const common::CRC64WE crc64{type_name.cbegin(), type_name.cend()};
return crc64.get();
}

}; // TypeIdGenerator

template <typename Message, typename Subscriber>
static void deserializeMsgOnceForManySubs(Context& context)
Expand Down Expand Up @@ -302,6 +303,15 @@ class SubscriberImpl final : public cavl::Node<SubscriberImpl>, public SharedObj

}; // SubscriberImpl

template <>
struct SubscriberImpl::CallbackNode::Deserializer::TypeIdGenerator<void>
{
static constexpr TypeId get() noexcept
{
return 0U;
}
};

} // namespace detail
} // namespace presentation
} // namespace libcyphal
Expand Down
Loading