Compute Graph Framework SDK Reference  5.14
ManagedPort.hpp
Go to the documentation of this file.
1
2//
3// Notice
4// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
5// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
6// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
7// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8//
9// NVIDIA CORPORATION & AFFILIATES assumes no responsibility for the consequences of use of such
10// information or for any infringement of patents or other rights of third parties that may
11// result from its use. No license is granted by implication or otherwise under any patent
12// or patent rights of NVIDIA CORPORATION & AFFILIATES. No third party distribution is allowed unless
13// expressly authorized by NVIDIA. Details are subject to change without notice.
14// This code supersedes and replaces all information previously supplied.
15// NVIDIA CORPORATION & AFFILIATES products are not authorized for use as critical
16// components in life support devices or systems without express written approval of
17// NVIDIA CORPORATION & AFFILIATES.
18//
19// SPDX-FileCopyrightText: Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
20// SPDX-License-Identifier: LicenseRef-NvidiaProprietary
21//
22// NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
23// property and proprietary rights in and to this material, related
24// documentation and any modifications thereto. Any use, reproduction,
25// disclosure or distribution of this material and related documentation
26// without an express license agreement from NVIDIA CORPORATION or
27// its affiliates is strictly prohibited.
28//
30
31#ifndef DW_FRAMEWORK_MANAGEDPORT_HPP_
32#define DW_FRAMEWORK_MANAGEDPORT_HPP_
33
35#include <dwcgf/port/Port.hpp>
39#include <dwshared/dwfoundation/dw/core/language/Optional.hpp>
40#include <dwshared/dwfoundation/dw/core/container/RingBuffer.hpp>
41#include <dwshared/dwfoundation/dw/core/container/StringView.hpp>
42#include <dwshared/dwfoundation/dw/core/language/Function.hpp>
43#include <type_traits>
44#include <utility>
45
46namespace dw
47{
48namespace framework
49{
50
52{
53public:
54 ManagedPortBase(const dw::core::StringView& name);
55
56 virtual ~ManagedPortBase() = default;
57
62 ManagedPortBase(const ManagedPortBase& other) = delete;
63 ManagedPortBase& operator=(const ManagedPortBase& other) = delete;
66
74 virtual void bindChannel(ChannelObject* channel) = 0;
75
82
86 virtual bool isBound() const noexcept = 0;
87
89 const dw::core::StringView& getName() const;
90
92 const dw::core::StringView& getNodeName() const;
93
95 void setNodeName(const dw::core::StringView& nodeName) noexcept;
96
100 void setCycleCount(uint32_t cycleCount);
101
105 void setPeriod(uint32_t period);
106
111 virtual void reset();
112
118
119protected:
121 dw::core::StringView m_name;
123 dw::core::StringView m_nodeName;
124 uint32_t m_cycleCount;
125 uint32_t m_period;
127 dw::framework::lockstep::ILockstepSyncClient* m_lockstepSyncClient;
128};
129
134{
135public:
136 // Due to single TU checking
137 // coverity[autosar_cpp14_a0_1_1_violation]
138 static constexpr char LOG_TAG[]{"ManagedPortOutputBase"};
139
141 {
142 };
143
145 {
150 bool syncEnabled = false;
151 };
152
154 {
157 };
161 bool isBufferAvailable() const noexcept;
162
166 dw::core::VectorFixed<GenericData> getAllBuffers();
167
175 void acquire();
176
184 void send();
185
186 const Properties& getProperties() const noexcept;
187
191 void setCallbackBeforeSend(dw::core::Function<dwStatus()> callback);
192
193 // Implemented inherited methods
194 void bindChannel(ChannelObject* channel) override;
195 bool isBound() const noexcept override;
196
201 void reset() override;
202
207 ChannelMetadata& getMetadata();
208
212 void sendAdvTimestamp();
213
214protected:
215 explicit ManagedPortOutputBase(const dw::core::StringView& name, ConstructProperties props, GenericDataReference&& ref);
216 GenericData getBufferGeneric();
217
218private:
219 static BoundProperties getBoundProperties(const ChannelObject& channel);
220 void populateDefaultMetadata(ChannelMetadata& header);
222 ChannelObject::Producer* m_channelProducer;
223 Properties m_props;
224 dw::core::Optional<GenericData> m_buffer;
225 dw::core::Function<dwStatus()> m_callbackBeforeSend;
226 uint32_t m_sendSeqNum;
227};
228
233{
234public:
235 using RingBuffer = dw::core::RingBuffer<GenericData>;
236
238 {
242 uint32_t maxBuffers = 1U;
248 dwTime_t waitTime = 0;
249 };
250
252 {
262 bool enableReuse = false;
263
267 bool syncEnabled = false;
272 uint32_t dataOffset = 0U;
273 };
274
276 {
285 };
286
290 const Properties& getProperties() const noexcept;
291
301 void recv();
302
308 void release();
309
314 void reset() override;
315
319 bool isBufferAvailable() const noexcept;
320
324 dw::core::VectorFixed<GenericData> getAllBuffers();
325
326 // Implemented inherited methods
327 void bindChannel(ChannelObject* channel) override;
328 bool isBound() const noexcept override;
329
334 void setCallbackAfterRecv(dw::core::Function<dwStatus()> callback);
335
340 const ChannelMetadata& getMetadata();
341
345 void sendAdvTimestamp();
346
347protected:
348 ManagedPortInputBase(const dw::core::StringView& name, ConstructProperties props, GenericDataReference&& ref);
349 GenericData getBufferGeneric() const;
350 GenericData popBufferGeneric();
351 void releaseToChannel(void* data);
352
353private:
354 static BoundProperties getBoundProperties(const ChannelObject& channel);
355 bool recvSingle(dwTime_t waitTime);
356 bool stashConsumed();
357 bool packetStashed(GenericData packet);
358 void handleReuseDrop();
359
360 void releaseSingle();
361 bool postProcessLockstepReplayData(GenericData packet);
362 dwTime_t getWaitTime();
363 bool recvData();
364 bool waitForData();
365 void handleWaitFailure(dwStatus status);
366 void handleCallbackAfterRecv();
367
368 Properties m_props;
370 ChannelObject::Consumer* m_channelConsumer;
371 bool m_shouldDropFirstBuffer;
372 dw::core::Function<dwStatus()> m_callbackAfterRecv;
373
374protected:
375 RingBuffer m_buffers;
376 GenericData m_stashedFuturePacket;
377 bool m_stashValid;
378};
379
380namespace detail
381{
382
383template <typename T>
384// coverity[autosar_cpp14_a2_10_5_violation] FP: nvbugs/3907242
385T* getBufferTyped(GenericData buffer)
386{
387 MetadataPayload* metadataPacket{extractMetadata(buffer)};
388 T* ptr{metadataPacket->data.template getData<T>()};
389
390 if (ptr == nullptr)
391 {
392 throw ExceptionWithStatus(DW_INVALID_ARGUMENT, "getBufferTyped: type mismatch");
393 }
394 return ptr;
395}
396
397// coverity[autosar_cpp14_a14_1_1_violation]
398template <typename T>
399struct vectorIterable
400{
401 explicit vectorIterable(dw::core::VectorFixed<GenericData> allBuffers)
402 : m_allBuffers(std::move(allBuffers))
403 {
404 }
405
407 // There are no specific requirements on the template type
408 // coverity[autosar_cpp14_a14_1_1_violation]
409 template <class TT>
410 class iterator : public dw::core::VectorFixed<GenericData>::iterator
411 {
412 public:
413 using Base = dw::core::VectorFixed<GenericData>::iterator;
414 // Same naming is used in dwshared, hence keeping the iterator name and its accessors for now
415 // coverity[cert_dcl51_cpp_violation]
416 iterator(Base&& base)
417 : Base(base)
418 {
419 }
420
421 const Base& baseFromThis() const
422 {
423 return *this;
424 }
425
426 auto operator*() const
427 {
428 GenericData buffer = *baseFromThis();
429 return getBufferTyped<TT>(buffer);
430 }
431 };
432
433 // coverity[cert_dcl51_cpp_violation]
434 iterator<T> begin() { return iterator<T>(m_allBuffers.begin()); }
435
436 // coverity[cert_dcl51_cpp_violation]
437 iterator<T> end() { return iterator<T>(m_allBuffers.end()); }
438
439 // coverity[cert_dcl51_cpp_violation]
440 iterator<const T> begin() const { return iterator<const T>(m_allBuffers.begin()); }
441
442 // coverity[cert_dcl51_cpp_violation]
443 iterator<const T> end() const { return iterator<const T>(m_allBuffers.end()); }
444
445private:
446 dw::core::VectorFixed<GenericData> m_allBuffers;
447};
448
449} // namespace detail
450
454template <typename T>
456{
458 "Channel packet type not declared. Ensure channel packet type "
459 "handling is declared with DWFRAMEWORK_DECLARE_PACKET_TYPE_POD "
460 "or DWFRAMEWORK_DECLARE_PACKET_TYPE_RELATION");
461
462 using SpecimenT = typename parameter_traits<T>::SpecimenT;
463
464public:
471 template <typename T2 = T, typename std::enable_if_t<parameter_traits<T2>::PacketTID != DWFRAMEWORK_PACKET_ID_DEFAULT, void>* = nullptr>
472 ManagedPortOutput(const dw::core::StringView& name, ConstructProperties props, SpecimenT& ref)
473 : ManagedPortOutputBase(name, std::move(props), make_specimen<T>(&ref))
474 {
475 }
476
482 template <typename T2 = T, typename std::enable_if_t<parameter_traits<T2>::PacketTID != DWFRAMEWORK_PACKET_ID_DEFAULT, void>* = nullptr>
483 ManagedPortOutput(const dw::core::StringView& name, SpecimenT& ref)
484 : ManagedPortOutputBase(name, {}, make_specimen<T>(&ref))
485 {
486 }
487
492 template <typename T2 = T, typename std::enable_if_t<parameter_traits<T2>::PacketTID == DWFRAMEWORK_PACKET_ID_DEFAULT, void>* = nullptr>
493 ManagedPortOutput(const dw::core::StringView& name, ConstructProperties props)
494 : ManagedPortOutputBase(name, std::move(props), make_specimen<T>(nullptr))
495 {
496 }
497
501 template <typename T2 = T, typename std::enable_if_t<parameter_traits<T2>::PacketTID == DWFRAMEWORK_PACKET_ID_DEFAULT, void>* = nullptr>
502 ManagedPortOutput(const dw::core::StringView& name)
503 : ManagedPortOutputBase(name, {}, make_specimen<T>(nullptr))
504 {
505 }
506
510 // coverity[autosar_cpp14_a7_1_5_violation]
512 {
513 return detail::vectorIterable<T>(getAllBuffers());
514 }
515
521 auto getBuffer() -> T*
522 {
523 return detail::getBufferTyped<T>(getBufferGeneric());
524 }
525};
526
530template <typename T>
532{
534 "Channel packet type not declared. Ensure channel packet type "
535 "handling is declared with DWFRAMEWORK_DECLARE_PACKET_TYPE_POD "
536 "or DWFRAMEWORK_DECLARE_PACKET_TYPE_RELATION");
537 // coverity[autosar_cpp14_a0_1_6_violation]
538 using SpecimenT = typename parameter_traits<T>::SpecimenT;
539
540 struct PacketDeleter;
541
542public:
543 struct iterable;
544
549 ManagedPortInput(const dw::core::StringView& name, ConstructProperties props)
550 : ManagedPortInputBase(name, std::move(props), make_specimen<T>(nullptr))
551 {
552 }
553
554 ManagedPortInput(const dw::core::StringView& name)
555 : ManagedPortInputBase(name, {}, make_specimen<T>(nullptr))
556 {
557 }
558
559 ManagedPortInput(const dw::core::StringView& name, ConstructProperties props, SpecimenT specimen)
560 : ManagedPortInputBase(name, std::move(props), make_specimen<T>(&specimen))
561 {
562 }
563
567 detail::vectorIterable<T> getAllBufferIter()
568 {
569 return detail::vectorIterable<T>(getAllBuffers());
570 }
571
578 {
579 return iterable(*this);
580 }
581
587 auto getBuffer() -> T*
588 {
589 return detail::getBufferTyped<T>(getBufferGeneric());
590 }
591
598 {
599 if (isBufferAvailable())
600 {
601 const dw::core::Optional<dwValidityStatus> valid{getValidityStatus(getMetadata())};
602 // At the moment if validity is not set it counts as valid
603 // Once all the publishers set the validity signal it can be changed
604 const bool isValid{!valid.has_value() || (valid->validity == DW_VALIDITY_VALID)};
605 if (isValid)
606 {
607 return getBuffer();
608 }
609 }
610 return nullptr;
611 }
612
619 auto getOptionalBuffer() -> T*
620 {
621 return isBufferAvailable() ? getBuffer() : nullptr;
622 }
623
624 using UniquePacketPtr = std::unique_ptr<T, PacketDeleter>;
625
627 {
628 GenericData packet{popBufferGeneric()};
629 T* ptr{detail::getBufferTyped<T>(packet)};
630 void* releasePtr{packet.getPointer()};
631 return UniquePacketPtr(ptr, PacketDeleter{this, releasePtr});
632 }
633
634 struct iterable
635 {
637 : m_port(port)
638 {
639 }
640
642 // There are no specific requirements on the template type
643 // coverity[autosar_cpp14_a14_1_1_violation]
644 template <class TT>
645 class iterator : public ManagedPortInputBase::RingBuffer::iterator
646 {
647 using Base = ManagedPortInputBase::RingBuffer::iterator;
648
649 public:
650 // Same naming is used in dwshared, hence keeping the iterator name and its accessors for now
651 // coverity[cert_dcl51_cpp_violation]
652 iterator(Base&& base, ManagedPortInput<T>& port)
653 : Base(std::move(base))
654 , m_port(port)
655 {
656 }
657
658 const Base& baseFromThis() const
659 {
660 return *this;
661 }
662
663 auto operator*() const -> TT*
664 {
665 GenericData buffer{*baseFromThis()};
666 return detail::getBufferTyped<TT>(buffer);
667 }
668
669 private:
670 ManagedPortInput<T>& m_port;
671 };
672
673 // coverity[cert_dcl51_cpp_violation]
674 iterator<T> begin() { return iterator<T>(m_port.m_buffers.begin(), m_port); }
675
676 // coverity[cert_dcl51_cpp_violation]
677 iterator<T> end() { return iterator<T>(m_port.m_buffers.end(), m_port); }
678
679 // coverity[cert_dcl51_cpp_violation]
680 iterator<const T> begin() const { return iterator<const T>(m_port.m_buffers.begin(), m_port); }
681
682 // coverity[cert_dcl51_cpp_violation]
683 iterator<const T> end() const { return iterator<const T>(m_port.m_buffers.end(), m_port); }
684
685 private:
686 ManagedPortInput<T>& m_port;
687 };
688
689private:
690 struct PacketDeleter
691 {
692 void operator()(T* p)
693 {
694 static_cast<void>(p);
695 port->releaseToChannel(releasePtr);
696 }
697 ManagedPortInput* port;
698 void* releasePtr;
699 };
700};
701
702template <typename T>
704
705// Create a port type specimen for a given port index
706namespace detail
707{
708template <
709 typename NodeT,
710 PortDirection Direction,
711 uint64_t DescriptorIndex>
712struct IsOutputNonPOD : std::integral_constant<bool, Direction == PortDirection::OUTPUT && parameter_traits<decltype(portDescriptorType<NodeT, Direction, DescriptorIndex>())>::PacketTID != DWFRAMEWORK_PACKET_ID_DEFAULT>
713{
714 static_assert(DescriptorIndex < portDescriptorSize<NodeT, Direction>(), "Invalid PortIndex.");
715};
716
717template <
718 typename NodeT,
719 PortDirection Direction,
720 uint64_t DescriptorIndex>
721typename std::enable_if<
722 !IsOutputNonPOD<NodeT, Direction, DescriptorIndex>::value,
724 // coverity[autosar_cpp14_a2_10_5_violation] FP: nvbugs/3907242
725 createPortSpecimenByStaticIndex()
726{
727 GenericDataReference ref{make_specimen<decltype(portDescriptorType<NodeT, Direction, DescriptorIndex>())>(nullptr)};
728 ref.packetTypeID = dw::core::safeAdd(static_cast<dw::framework::ChannelPacketTypeID>(DWFRAMEWORK_METADATA_PACKET_TYPE_ID_OFFSET), static_cast<uint32_t>(ref.packetTypeID)).value();
729 return ref;
730}
731
732template <
733 typename NodeT,
734 PortDirection Direction,
735 uint64_t DescriptorIndex>
736typename std::enable_if<
737 IsOutputNonPOD<NodeT, Direction, DescriptorIndex>::value,
739 // coverity[autosar_cpp14_a2_10_5_violation] FP: nvbugs/3907242
740 createPortSpecimenByStaticIndex()
741{
742 throw ExceptionWithStatus(DW_NOT_SUPPORTED, "createPortSpecimenByStaticIndex: Non POD output port is not supported");
743}
744
745template <
746 typename NodeT,
747 PortDirection Direction,
748 uint64_t... Idx>
749typename std::enable_if<(sizeof...(Idx) > 1), GenericDataReference>::type
750 // coverity[autosar_cpp14_a2_10_5_violation] FP: nvbugs/4040101
751 createPortSpecimenImpl(size_t descriptorIndex, std::index_sequence<Idx...>)
752{
753 constexpr size_t ArraySize{sizeof...(Idx)};
754 if (descriptorIndex < ArraySize)
755 {
756 std::array<GenericDataReference, ArraySize> specimens{
757 (Idx == descriptorIndex ? createPortSpecimenByStaticIndex<NodeT, Direction, Idx>() : GenericDataReference{})...};
758 return specimens[descriptorIndex];
759 }
760 throw ExceptionWithStatus(DW_OUT_OF_BOUNDS, "createPortSpecimenImpl: index out of bound.");
761}
762
763// Above createPortSpecimenImpl actually covers correctly for all sizeof...(Idx)
764// but AutoSAR complaining about dead code and unreachable code branch when sizeof...(Idx) == 1.
765// Thus split it into three different implementations.
766template <
767 typename NodeT,
768 PortDirection Direction,
769 uint64_t... Idx>
770typename std::enable_if<(sizeof...(Idx) == 1), GenericDataReference>::type
771 // coverity[autosar_cpp14_a2_10_5_violation] FP: nvbugs/4040101
772 createPortSpecimenImpl(size_t descriptorIndex, std::index_sequence<Idx...>)
773{
774 constexpr size_t ArraySize{sizeof...(Idx)};
775 if (descriptorIndex < ArraySize)
776 {
777 return createPortSpecimenByStaticIndex<NodeT, Direction, 0>();
778 }
779 throw ExceptionWithStatus(DW_OUT_OF_BOUNDS, "createPortSpecimenImpl: index out of bound.");
780}
781
782template <
783 typename NodeT,
784 PortDirection Direction,
785 uint64_t... Idx>
786typename std::enable_if<(sizeof...(Idx) == 0), GenericDataReference>::type
787 // coverity[autosar_cpp14_a2_10_5_violation] FP: nvbugs/4040101
788 createPortSpecimenImpl(size_t, std::index_sequence<Idx...>)
789{
790 throw ExceptionWithStatus(DW_OUT_OF_BOUNDS, "createPortSpecimenImpl: index out of bound.");
791}
792
793template <
794 typename NodeT,
795 PortDirection Direction>
796// coverity[autosar_cpp14_a2_10_5_violation] FP: nvbugs/4040101
797GenericDataReference createPortSpecimen(size_t descriptorIndex)
798{
799 return detail::createPortSpecimenImpl<NodeT, Direction>(
801 std::make_index_sequence<portDescriptorSize<NodeT, Direction>()>{});
802}
803} // namespace detail
804
805} // namespace framework
806} // namespace dw
807
808#endif // DW_FRAMEWORK_MANAGEDPORT_HPP_
dw::core::StringView m_name
The unique name within set of ports with the same direction.
ManagedPortBase & operator=(ManagedPortBase &&other)=delete
virtual bool isBound() const noexcept=0
void setNodeName(const dw::core::StringView &nodeName) noexcept
Set the name of the node this port belongs to.
virtual ~ManagedPortBase()=default
const dw::core::StringView & getNodeName() const
Get the name of the node this port belongs to.
ManagedPortBase(const ManagedPortBase &other)=delete
virtual void bindChannel(ChannelObject *channel)=0
ChannelObject * getChannel()
ManagedPortBase(ManagedPortBase &&other)=delete
ManagedPortBase & operator=(const ManagedPortBase &other)=delete
const dw::core::StringView & getName() const
Get the name of the port.
void bindLockstepSyncClient(dw::framework::lockstep::ILockstepSyncClient *syncClient)
dw::framework::lockstep::ILockstepSyncClient * m_lockstepSyncClient
ManagedPortBase(const dw::core::StringView &name)
dw::core::StringView m_nodeName
The name of the node this port belongs to.
void setCycleCount(uint32_t cycleCount)
void setPeriod(uint32_t period)
dw::core::RingBuffer< GenericData > RingBuffer
const Properties & getProperties() const noexcept
iterator(Base &&base, ManagedPortInput< T > &port)
detail::vectorIterable< T > getAllBufferIter()
ManagedPortInput(const dw::core::StringView &name)
std::unique_ptr< T, PacketDeleter > UniquePacketPtr
ManagedPortInput(const dw::core::StringView &name, ConstructProperties props, SpecimenT specimen)
auto getBufferIfAvailableAndValid() -> T *
ManagedPortInput(const dw::core::StringView &name, ConstructProperties props)
bool isBufferAvailable() const noexcept
ManagedPortOutput(const dw::core::StringView &name, SpecimenT &ref)
ManagedPortOutput(const dw::core::StringView &name, ConstructProperties props)
ManagedPortOutput(const dw::core::StringView &name)
ManagedPortOutput(const dw::core::StringView &name, ConstructProperties props, SpecimenT &ref)
static constexpr const uint32_t DWFRAMEWORK_METADATA_PACKET_TYPE_ID_OFFSET
static GenericDataReference make_specimen(typename parameter_traits< T >::SpecimenT *specimen)
MetadataPayload * extractMetadata(GenericData packet)
ChannelPacketTypeID packetTypeID
The ID of the type of the endpoint.
dw::core::Optional< dwValidityStatus > getValidityStatus(ChannelMetadata const &header)
uint32_t ChannelPacketTypeID
constexpr ChannelPacketTypeID DWFRAMEWORK_PACKET_ID_DEFAULT
typename ManagedPortInput< T >::UniquePacketPtr UniquePacketPtr
constexpr size_t descriptorIndex()
Definition: Buffer.hpp:40
iterator< const T > begin() const
iterable(ManagedPortInput< T > &port)