1313#include " libcyphal/executor.hpp"
1414#include " libcyphal/transport/errors.hpp"
1515#include " libcyphal/transport/svc_sessions.hpp"
16- #include " libcyphal/transport/transfer_id_generators .hpp"
16+ #include " libcyphal/transport/transfer_id_map .hpp"
1717#include " libcyphal/transport/types.hpp"
1818#include " libcyphal/types.hpp"
1919
@@ -34,7 +34,9 @@ namespace presentation
3434namespace detail
3535{
3636
37- class SharedClient : public common ::cavl::Node<SharedClient>, public SharedObject
37+ class SharedClient : public common ::cavl::Node<SharedClient>,
38+ public SharedObject,
39+ protected transport::detail::ITransferIdStorage
3840{
3941public:
4042 using Node::remove;
@@ -134,17 +136,24 @@ class SharedClient : public common::cavl::Node<SharedClient>, public SharedObjec
134136 , svc_request_tx_session_{std::move (svc_request_tx_session)}
135137 , svc_response_rx_session_{std::move (svc_response_rx_session)}
136138 , response_rx_params_{svc_response_rx_session_->getParams ()}
139+ , next_transfer_id_{0 }
137140 , nearest_deadline_{DistantFuture ()}
138141 {
139142 CETL_DEBUG_ASSERT (svc_request_tx_session_ != nullptr , " " );
140143 CETL_DEBUG_ASSERT (svc_response_rx_session_ != nullptr , " " );
141144
145+ if (const auto * const transfer_id_map = delegate.getTransferIdMap ())
146+ {
147+ const SessionSpec session_spec{response_rx_params_.service_id , response_rx_params_.server_node_id };
148+ next_transfer_id_ = transfer_id_map->getIdFor (session_spec);
149+ }
150+
142151 // Override the default (2s) timeout value of the response session.
143152 // This is done to allow multiple overlapping responses to be handled properly.
144153 // Otherwise, the responses would be rejected (as "duplicates") if their transfer IDs are in order.
145154 // Real duplicates (f.e. caused by redundant transports) won't cause any issues
146155 // b/c shared RPC client expects/accepts only one response per transfer ID,
147- // and corresponding promise callback node will be removed after the first response.
156+ // and the corresponding promise callback node will be removed after the first response.
148157 svc_response_rx_session_->setTransferIdTimeout ({});
149158
150159 svc_response_rx_session_->setOnReceiveCallback ([this ](const auto & arg) {
@@ -199,7 +208,7 @@ class SharedClient : public common::cavl::Node<SharedClient>, public SharedObjec
199208 {
200209 if (timeout_node.isTimeoutLinked ())
201210 {
202- // Remove previous timeout node (if any),
211+ // Remove the previous timeout node (if any),
203212 // and then reinsert the node with updated/given new deadline time.
204213 //
205214 timeout_nodes_by_deadline_.remove (&timeout_node);
@@ -240,9 +249,27 @@ class SharedClient : public common::cavl::Node<SharedClient>, public SharedObjec
240249
241250 void destroy () noexcept override
242251 {
252+ if (auto * const transfer_id_map = delegate_.getTransferIdMap ())
253+ {
254+ const SessionSpec session_spec{response_rx_params_.service_id , response_rx_params_.server_node_id };
255+ transfer_id_map->setIdFor (session_spec, next_transfer_id_);
256+ }
257+
243258 delegate_.forgetSharedClient (*this );
244259 }
245260
261+ // MARK: ITransferIdStorage
262+
263+ transport::TransferId load () const noexcept override
264+ {
265+ return next_transfer_id_;
266+ }
267+
268+ void save (const transport::TransferId transfer_id) noexcept override
269+ {
270+ next_transfer_id_ = transfer_id;
271+ }
272+
246273protected:
247274 virtual void insertNewCallbackNode (CallbackNode& callback_node)
248275 {
@@ -273,7 +300,8 @@ class SharedClient : public common::cavl::Node<SharedClient>, public SharedObjec
273300 }
274301
275302private:
276- using Schedule = IExecutor::Callback::Schedule;
303+ using Schedule = IExecutor::Callback::Schedule;
304+ using SessionSpec = transport::ITransferIdMap::SessionSpec;
277305
278306 static constexpr TimePoint DistantFuture ()
279307 {
@@ -388,6 +416,7 @@ class SharedClient : public common::cavl::Node<SharedClient>, public SharedObjec
388416 const UniquePtr<transport::IRequestTxSession> svc_request_tx_session_;
389417 const UniquePtr<transport::IResponseRxSession> svc_response_rx_session_;
390418 const transport::ResponseRxParams response_rx_params_;
419+ transport::TransferId next_transfer_id_;
391420 common::cavl::Tree<CallbackNode> cb_nodes_by_transfer_id_;
392421 TimePoint nearest_deadline_;
393422 common::cavl::Tree<TimeoutNode> timeout_nodes_by_deadline_;
@@ -399,8 +428,8 @@ class SharedClient : public common::cavl::Node<SharedClient>, public SharedObjec
399428
400429// / @brief Defines a shared client implementation that uses a generic transfer ID generator.
401430// /
402- template <typename TransferIdGeneratorMixin >
403- class ClientImpl final : public SharedClient, private TransferIdGeneratorMixin
431+ template <typename TransferIdGenerator >
432+ class ClientImpl final : public SharedClient
404433{
405434public:
406435 ClientImpl (IPresentationDelegate& delegate,
@@ -409,7 +438,7 @@ class ClientImpl final : public SharedClient, private TransferIdGeneratorMixin
409438 UniquePtr<transport::IResponseRxSession> svc_response_rx_session,
410439 const transport::TransferId transfer_id_modulo)
411440 : SharedClient{delegate, executor, std::move (svc_request_tx_session), std::move (svc_response_rx_session)}
412- , TransferIdGeneratorMixin {transfer_id_modulo}
441+ , transfer_id_generator_ {transfer_id_modulo, * this }
413442 {
414443 }
415444
@@ -424,40 +453,41 @@ class ClientImpl final : public SharedClient, private TransferIdGeneratorMixin
424453private:
425454 using Base = SharedClient;
426455
427- // MARK: SharedClient
428-
429- CETL_NODISCARD cetl::optional<transport::TransferId> nextTransferId () noexcept override
430- {
431- return TransferIdGeneratorMixin::nextTransferId ();
432- }
433-
434456 void insertNewCallbackNode (CallbackNode& callback_node) override
435457 {
436458 SharedClient::insertNewCallbackNode (callback_node);
437- TransferIdGeneratorMixin:: retainTransferId (callback_node.getTransferId ());
459+ transfer_id_generator_. retainTransferId (callback_node.getTransferId ());
438460 }
439461
440462 void removeCallbackNode (CallbackNode& callback_node) override
441463 {
442- TransferIdGeneratorMixin:: releaseTransferId (callback_node.getTransferId ());
464+ transfer_id_generator_. releaseTransferId (callback_node.getTransferId ());
443465 SharedClient::removeCallbackNode (callback_node);
444466 }
445467
468+ // MARK: SharedClient
469+
470+ CETL_NODISCARD cetl::optional<transport::TransferId> nextTransferId () noexcept override
471+ {
472+ return transfer_id_generator_.nextTransferId ();
473+ }
474+
475+ TransferIdGenerator transfer_id_generator_;
476+
446477}; // ClientImpl<TransferIdGeneratorMixin>
447478
448479// / @brief Defines a shared client specialization that uses a trivial transfer ID generator.
449480// /
450481template <>
451- class ClientImpl <transport::detail::TrivialTransferIdGenerator> final
452- : public SharedClient,
453- private transport::detail::TrivialTransferIdGenerator
482+ class ClientImpl <transport::detail::TrivialTransferIdGenerator> final : public SharedClient
454483{
455484public:
456485 ClientImpl (IPresentationDelegate& delegate,
457486 IExecutor& executor,
458487 UniquePtr<transport::IRequestTxSession> svc_request_tx_session,
459488 UniquePtr<transport::IResponseRxSession> svc_response_rx_session)
460489 : Base{delegate, executor, std::move (svc_request_tx_session), std::move (svc_response_rx_session)}
490+ , transfer_id_generator_{*this }
461491 {
462492 }
463493
@@ -476,9 +506,11 @@ class ClientImpl<transport::detail::TrivialTransferIdGenerator> final
476506
477507 CETL_NODISCARD cetl::optional<transport::TransferId> nextTransferId () noexcept override
478508 {
479- return TrivialTransferIdGenerator:: nextTransferId ();
509+ return transfer_id_generator_. nextTransferId ();
480510 }
481511
512+ transport::detail::TrivialTransferIdGenerator transfer_id_generator_;
513+
482514}; // ClientImpl<TrivialTransferIdGenerator>
483515
484516} // namespace detail
0 commit comments