diff --git a/libuavcan/include/uavcan/data_type.hpp b/libuavcan/include/uavcan/data_type.hpp index dad710ed31..e7ee7a47d8 100644 --- a/libuavcan/include/uavcan/data_type.hpp +++ b/libuavcan/include/uavcan/data_type.hpp @@ -98,7 +98,9 @@ public: bool operator!=(DataTypeSignature rhs) const { return !operator==(rhs); } }; - +/** + * This class contains complete description of a data type. + */ class UAVCAN_EXPORT DataTypeDescriptor { DataTypeKind kind_; diff --git a/libuavcan/include/uavcan/driver/can.hpp b/libuavcan/include/uavcan/driver/can.hpp index 5746134b69..ab8c35d748 100644 --- a/libuavcan/include/uavcan/driver/can.hpp +++ b/libuavcan/include/uavcan/driver/can.hpp @@ -18,8 +18,8 @@ namespace uavcan UAVCAN_PACKED_BEGIN struct UAVCAN_EXPORT CanFrame { - static const uint32_t MaskStdID = 0x000007FF; - static const uint32_t MaskExtID = 0x1FFFFFFF; + static const uint32_t MaskStdID = 0x000007FFU; + static const uint32_t MaskExtID = 0x1FFFFFFFU; static const uint32_t FlagEFF = 1U << 31; ///< Extended frame format static const uint32_t FlagRTR = 1U << 30; ///< Remote transmission request static const uint32_t FlagERR = 1U << 29; ///< Error frame @@ -37,13 +37,13 @@ struct UAVCAN_EXPORT CanFrame fill(data, data + MaxDataLen, 0); } - CanFrame(uint32_t arg_id, const uint8_t* arg_data, uint8_t data_len) - : id(arg_id) + CanFrame(uint32_t can_id, const uint8_t* can_data, uint8_t data_len) + : id(can_id) , dlc((data_len > MaxDataLen) ? MaxDataLen : data_len) { - UAVCAN_ASSERT(arg_data != NULL); + UAVCAN_ASSERT(can_data != NULL); UAVCAN_ASSERT(data_len == dlc); - (void)copy(arg_data, arg_data + dlc, this->data); + (void)copy(can_data, can_data + dlc, this->data); } bool operator!=(const CanFrame& rhs) const { return !operator==(rhs); } @@ -57,12 +57,16 @@ struct UAVCAN_EXPORT CanFrame bool isErrorFrame() const { return id & FlagERR; } #if UAVCAN_TOSTRING - enum StringRepresentation { StrTight, StrAligned }; + enum StringRepresentation + { + StrTight, ///< Minimum string length (default) + StrAligned ///< Fixed formatting for any frame + }; std::string toString(StringRepresentation mode = StrTight) const; #endif /** - * CAN frames arbitration rules, particularly STD vs EXT: + * CAN frame arbitration rules, particularly STD vs EXT: * Marco Di Natale - "Understanding and using the Controller Area Network" * http://www6.in.tum.de/pub/Main/TeachingWs2013MSE/CANbus.pdf */ @@ -72,7 +76,9 @@ struct UAVCAN_EXPORT CanFrame UAVCAN_PACKED_END /** - * CAN hardware filter config struct. @ref ICanIface::configureFilters(). + * CAN hardware filter config struct. + * Masks from @ref CanFrame can be applied to define frame type (EFF, EXT, etc.). + * @ref ICanIface::configureFilters(). */ struct UAVCAN_EXPORT CanFilterConfig { @@ -81,7 +87,8 @@ struct UAVCAN_EXPORT CanFilterConfig }; /** - * Events to look for during @ref ICanDriver::select() call + * Events to look for during @ref ICanDriver::select() call. + * Bit position defines iface index, e.g. read = 1 << 2 to read from the third iface. */ struct UAVCAN_EXPORT CanSelectMasks { @@ -94,6 +101,9 @@ struct UAVCAN_EXPORT CanSelectMasks { } }; +/** + * Special IO flags. + */ typedef uint16_t CanIOFlags; static const CanIOFlags CanIOFlagLoopback = 1; ///< Send the frame back to RX with true TX timestamps @@ -153,12 +163,13 @@ public: virtual ~ICanDriver() { } /** - * Returns the interface by index, or null pointer if the index is out of range. + * Returns an interface by index, or null pointer if the index is out of range. */ virtual ICanIface* getIface(uint8_t iface_index) = 0; /** * Total number of available CAN interfaces. + * This value shall not change after initialization. */ virtual uint8_t getNumIfaces() const = 0; @@ -166,6 +177,8 @@ public: * Block until the deadline, or one of the specified interfaces becomes available for read or write. * Iface masks will be modified by the driver to indicate which exactly interfaces are available for IO. * Bit position in the masks defines interface index. + * Note that it is allowed to return from this method even if no requested events actually happened, or if + * there are events that were not requested by the lirary. * @param [in,out] inout_masks Masks indicating which interfaces are needed/available for IO. * @param [in] blocking_deadline Zero means non-blocking operation. * @return Positive number of ready interfaces or negative error code. diff --git a/libuavcan/include/uavcan/dynamic_memory.hpp b/libuavcan/include/uavcan/dynamic_memory.hpp index bc47d6c114..eea858625b 100644 --- a/libuavcan/include/uavcan/dynamic_memory.hpp +++ b/libuavcan/include/uavcan/dynamic_memory.hpp @@ -31,7 +31,10 @@ public: virtual std::size_t getNumBlocks() const = 0; }; - +/** + * Pool manager contains multiple pool allocators of different block sizes and + * finds the most suitable allocator for every allocation request. + */ template class UAVCAN_EXPORT PoolManager : public IPoolAllocator, Noncopyable { @@ -67,7 +70,9 @@ public: virtual std::size_t getNumBlocks() const; }; - +/** + * Classic implementation of a pool allocator (Meyers). + */ template class UAVCAN_EXPORT PoolAllocator : public IPoolAllocator, Noncopyable { @@ -103,7 +108,9 @@ public: unsigned getNumUsedBlocks() const { return NumBlocks - getNumFreeBlocks(); } }; - +/** + * Limits the maximum number of blocks that can be allocated in a given allocator. + */ class LimitedPoolAllocator : public IPoolAllocator { IPoolAllocator& allocator_; diff --git a/libuavcan/include/uavcan/error.hpp b/libuavcan/include/uavcan/error.hpp index a6800676b8..080bc0b0c4 100644 --- a/libuavcan/include/uavcan/error.hpp +++ b/libuavcan/include/uavcan/error.hpp @@ -13,26 +13,37 @@ namespace { /** * Common error codes. + * * Functions that return signed integers may also return inverted error codes, * i.e. returned value should be inverted back to get the actual error code. + * + * Return code 0 (zero) means no error. + * + * @{ */ -const int16_t ErrFailure = 1; +const int16_t ErrFailure = 1; ///< General failure const int16_t ErrInvalidParam = 2; const int16_t ErrMemory = 3; -const int16_t ErrDriver = 4; +const int16_t ErrDriver = 4; ///< Platform driver error const int16_t ErrUnknownDataType = 5; const int16_t ErrInvalidMarshalData = 6; const int16_t ErrInvalidTransferListener = 7; const int16_t ErrNotInited = 8; const int16_t ErrRecursiveCall = 9; const int16_t ErrLogic = 10; -const int16_t ErrPassiveMode = 11; +const int16_t ErrPassiveMode = 11; ///< Operation not permitted in passive mode +/** + * @} + */ } /** * Fatal error handler. - * Throws std::runtime_error() if exceptions are available, otherwise calls UAVCAN_ASSERT(0) then std::abort(). + * Behavior: + * - If exceptions are enabled, throws std::runtime_error() with the supplied message text; + * - If assertions are enabled (no NDEBUG), aborts execution using zero assertion. + * - Otherwise aborts execution via std::abort(). */ #if __GNUC__ __attribute__ ((noreturn)) diff --git a/libuavcan/include/uavcan/helpers/component_status_manager.hpp b/libuavcan/include/uavcan/helpers/component_status_manager.hpp index 1731466059..7b2f74fca6 100644 --- a/libuavcan/include/uavcan/helpers/component_status_manager.hpp +++ b/libuavcan/include/uavcan/helpers/component_status_manager.hpp @@ -10,7 +10,12 @@ namespace uavcan { - +/** + * This helper class stores status codes of multiple components, and provides a method to quickly retrieve the + * worst status code. + * It allows to easily assign the node status code with the worst component status code. + * Refer to the standard message type uavcan.protocol.NodeStatus for available status codes. + */ template class ComponentStatusManager { @@ -30,6 +35,11 @@ public: } } + /** + * Assign the component status by index. Normally, an index would be defined by some enum constant. + * @param component_index Normally an enum constant + * @param status_code Status code from uavcan.protocol.NodeStatus + */ template void setComponentStatus(ComponentIndexType component_index, StatusCode status_code) { @@ -40,6 +50,9 @@ public: } } + /** + * Returns worst status code, i.e. highest value. + */ StatusCode getWorstStatusCode() const { StatusCode result = 0; diff --git a/libuavcan/include/uavcan/impl_constants.hpp b/libuavcan/include/uavcan/impl_constants.hpp index 4acb92c605..92028781d7 100644 --- a/libuavcan/include/uavcan/impl_constants.hpp +++ b/libuavcan/include/uavcan/impl_constants.hpp @@ -15,6 +15,12 @@ /** * UAVCAN can be compiled in C++11 mode. * This macro allows to detect which version of the C++ standard is being used. + * + * UAVCAN_CPP_VERSION can be defined explicitly to override auto detection to force compilation in C++03 mode. + * Valid values are listed below. + * + * Note that C++11 and newer requires C++ standard library, while C++03 does not. So, on platforms that + * don't implement the standard C++ (e.g. NuttX) use of C++03 may be preferred. */ #define UAVCAN_CPP11 2011 #define UAVCAN_CPP03 2003 @@ -31,6 +37,8 @@ /** * UAVCAN can be explicitly told to ignore exceptions, or it can be detected automatically. + * Autodetection is not expected to work with all compilers, so it's safer to define it explicitly. + * If the autodetection fails, exceptions will be disabled by default. */ #ifndef UAVCAN_EXCEPTIONS # if __EXCEPTIONS || _HAS_EXCEPTIONS @@ -42,7 +50,8 @@ /** * Struct layout control. - * Define UAVCAN_PACK_STRUCTS = 1 to reduce memory usage. + * Set UAVCAN_PACK_STRUCTS=1 and define UAVCAN_PACKED_BEGIN and UAVCAN_PACKED_END to reduce memory usage. + * THIS MAY BREAK THE CODE. */ #ifndef UAVCAN_PACK_STRUCTS # define UAVCAN_PACK_STRUCTS 0 @@ -73,7 +82,8 @@ #endif /** - * It might make sense to remove toString() methods for an embedded system + * It might make sense to remove toString() methods for an embedded system. + * If the autodetect fails, toString() will be disabled, so it's pretty safe by default. */ #ifndef UAVCAN_TOSTRING // Objective is to make sure that we're NOT on a resource constrained platform @@ -90,10 +100,9 @@ #endif /** - * Some C++ implementations are half-broken and do not implement the placement new operator. - * Setting this preprocessor symbol to 1 makes libuavcan implement its own operator new (std::size_t, void*), - * and its delete counterpart. - * This option may be removed in future. + * Some C++ implementations are half-broken because they don't implement the placement new operator. + * If UAVCAN_IMPLEMENT_PLACEMENT_NEW is defined, libuavcan will implement its own operator new (std::size_t, void*) + * and its delete() counterpart, instead of relying on the standard header . */ #ifndef UAVCAN_IMPLEMENT_PLACEMENT_NEW # define UAVCAN_IMPLEMENT_PLACEMENT_NEW 0 @@ -102,7 +111,7 @@ /** * Run time checks. * Resolves to the standard assert() by default. - * Can be disabled completely. + * Disabled completely if UAVCAN_NO_ASSERTIONS is defined. */ #ifndef UAVCAN_ASSERT # if UAVCAN_NO_ASSERTIONS @@ -116,9 +125,18 @@ namespace uavcan { /** - * Should be OK for any target arch up to AMD64 and any compiler. + * Memory pool block size. + * + * The default of 64 bytes should be OK for any target arch up to AMD64 and any compiler. + * * The library leverages compile-time checks to ensure that all types that are subject to dynamic allocation - * fit this size; otherwise compilation fails. + * fit this size, otherwise compilation fails. + * + * For platforms featuring small pointer width (16..32 bits), UAVCAN_MEM_POOL_BLOCK_SIZE can often be safely + * reduced to 56 or even 48 bytes, which leads to lower memory footprint. + * + * Note that the pool block size shall be aligned at biggest alignment of the target platform (detected and + * checked automatically at compile time). */ #if UAVCAN_MEM_POOL_BLOCK_SIZE /// Explicitly specified by the user. @@ -139,6 +157,10 @@ static const unsigned MemPoolAlignment = 16; typedef char _alignment_check_for_MEM_POOL_BLOCK_SIZE[((MemPoolBlockSize & (MemPoolAlignment - 1)) == 0) ? 1 : -1]; +/** + * This class that allows to check at compile time whether type T can be allocated using the memory pool. + * If the check fails, compilation fails. + */ template struct UAVCAN_EXPORT IsDynamicallyAllocatable { diff --git a/libuavcan/include/uavcan/marshal/array.hpp b/libuavcan/include/uavcan/marshal/array.hpp index cef940ee67..cde4628bfe 100644 --- a/libuavcan/include/uavcan/marshal/array.hpp +++ b/libuavcan/include/uavcan/marshal/array.hpp @@ -122,7 +122,10 @@ public: }; /** - * Statically allocated array with optional dynamic-like behavior + * Common functionality for both static and dynamic arrays. + * Static arrays are of fixed size; methods that can alter the size (e.g. push_back() and such) will fail to compile. + * Dynamic arrays contain a fixed-size buffer (it's size is enough to fit maximum number of elements) plus the + * currently allocated number of elements. */ template class UAVCAN_EXPORT ArrayImpl : public Select::Result && (T::MaxBitLen == 8 || T::MaxBitLen == 7) && (ArrayMode == ArrayModeDynamic) }; @@ -165,6 +169,10 @@ public: ArrayImpl() { initialize(0); } + /** + * Returns zero-terminated string, same as std::string::c_str(). + * This method will compile only if the array can be interpreted as 8-bit string (ASCII of UTF8). + */ const char* c_str() const { StaticAssert::check(); @@ -173,34 +181,53 @@ public: return reinterpret_cast(data_); } + /** + * Range-checking subscript. + * If the index is out of range: + * - if exceptions are enabled, std::out_of_range will be thrown. + * - if exceptions are disabled and assert() is enabled, execution will be aborted. + * - if exceptions are disabled and assert() is disabled, index will be constrained to the closest valid value. + */ ValueType& at(SizeType pos) { return data_[Base::validateRange(pos)]; } const ValueType& at(SizeType pos) const { return data_[Base::validateRange(pos)]; } + /** + * Range-checking subscript. @ref at() + */ ValueType& operator[](SizeType pos) { return at(pos); } const ValueType& operator[](SizeType pos) const { return at(pos); } + /** + * Standard container methods. Applicable to both dynamic and static arrays. + */ ValueType* begin() { return data_; } const ValueType* begin() const { return data_; } ValueType* end() { return data_ + Base::size(); } const ValueType* end() const { return data_ + Base::size(); } - ValueType& front() { return at(0); } const ValueType& front() const { return at(0); } ValueType& back() { return at(Base::size() - 1); } const ValueType& back() const { return at(Base::size() - 1); } + /** + * Performs standard lexicographical compare of the elements. + */ template bool operator<(const R& rhs) const { return ::uavcan::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end()); } + /** + * Aliases for compatibility with standard containers. + */ typedef ValueType* iterator; typedef const ValueType* const_iterator; }; /** - * Bit array specialization + * Memory-efficient specialization for bit arrays (each element maps to a single bit rather than single byte). + * This should be compatible with std::bitset. */ template class UAVCAN_EXPORT ArrayImpl, ArrayMode, MaxSize> @@ -219,9 +246,15 @@ public: using ArrayBase::size; using ArrayBase::capacity; + /** + * Range-checking subscript. Throws if enabled; assert() if enabled; else constraints the position. + */ Reference at(SizeType pos) { return BitSet::operator[](ArrayBase::validateRange(pos)); } bool at(SizeType pos) const { return BitSet::operator[](ArrayBase::validateRange(pos)); } + /** + * @ref at() + */ Reference operator[](SizeType pos) { return at(pos); } bool operator[](SizeType pos) const { return at(pos); } }; @@ -231,7 +264,16 @@ public: */ template class ArrayImpl; - +/** + * Generic array implementation. + * This class is compatible with most standard library functions operating on containers (e.g. std::sort(), + * std::lexicographical_compare(), etc.). + * No dynamic memory is used. + * All functions that can modify the array or access elements are range checking. If the range error occurs: + * - if exceptions are enabled, std::out_of_range will be thrown; + * - if assert() is enabled, program will be terminated on assert(0); + * - otherwise the index value will be constrained to the closest valid value. + */ template class UAVCAN_EXPORT Array : public ArrayImpl { @@ -446,9 +488,9 @@ class UAVCAN_EXPORT Array : public ArrayImpl } public: - typedef T RawValueType; - typedef typename StorageType::Type ValueType; - typedef typename Base::SizeType SizeType; + typedef T RawValueType; ///< This may be not the same as the element type. + typedef typename StorageType::Type ValueType; ///< This is the actual stored element type. + typedef typename Base::SizeType SizeType; ///< Minimal width size type. using Base::size; using Base::capacity; @@ -484,6 +526,9 @@ public: bool empty() const { return size() == 0; } + /** + * Only for dynamic arrays. Range checking. + */ void pop_back() { Base::shrink(); } void push_back(const ValueType& value) { @@ -491,6 +536,9 @@ public: Base::at(size() - 1) = value; } + /** + * Only for dynamic arrays. Range checking. + */ void resize(SizeType new_size, const ValueType& filler) { if (new_size > size()) @@ -515,13 +563,16 @@ public: } } + /** + * Only for dynamic arrays. Range checking. + */ void resize(SizeType new_size) { resize(new_size, ValueType()); } - /* - * Comparison operators + /** + * This operator accepts any container with size() and []. */ template typename EnableIfsize()) && sizeof((*((const R*)(0U)))[0]), bool>::Type @@ -541,6 +592,10 @@ public: return true; } + /** + * This operator can only be used with string-like arrays; otherwise it will fail to compile. + * @ref c_str() + */ bool operator==(const char* ch) const { if (ch == NULL) @@ -552,8 +607,9 @@ public: template bool operator!=(const R& rhs) const { return !operator==(rhs); } - /* - * Assign/append operators + /** + * This operator can only be used with string-like arrays; otherwise it will fail to compile. + * @ref c_str() */ SelfType& operator=(const char* ch) { @@ -571,6 +627,10 @@ public: return *this; } + /** + * This operator can only be used with string-like arrays; otherwise it will fail to compile. + * @ref c_str() + */ SelfType& operator+=(const char* ch) { StaticAssert::check(); @@ -586,6 +646,9 @@ public: return *this; } + /** + * Appends another Array<> with the same element type. Mode and max size can be different. + */ template SelfType& operator+=(const Array& rhs) { @@ -600,9 +663,12 @@ public: return *this; } - /* + /** * Formatting appender. * This method doesn't raise an overflow error; instead it silently truncates the data to fit the array capacity. + * Works only with string-like arrays, otherwise fails to compile. + * @param format Format string for std::snprintf(), e.g. "%08x", "%f" + * @param value Arbitrary value of a primitive type (should fail to compile if there's a non-primitive type) */ template void appendFormatted(const char* const format, const A value) @@ -610,8 +676,8 @@ public: StaticAssert::check(); StaticAssert::check(); - StaticAssert::check(); // This check allows to weed out most non-trivial types - StaticAssert::check(); // Another stupid check to catch non-trivial types + StaticAssert::check(); // This check allows to weed out most compound types + StaticAssert::check(); // Another stupid check to catch non-primitive types if (!format) { @@ -634,13 +700,14 @@ public: } if (ret < 0) { - UAVCAN_ASSERT(0); // Likely an invalid format string + UAVCAN_ASSERT(0); // Likely an invalid format string (*this) += format; // So we print it as is in release builds } } /** * Fills this array as a packed square matrix from a static array. + * Please refer to the specification to learn more about matrix packing. */ template void packSquareMatrix(const ScalarType (&src_row_major)[MaxSize]) @@ -650,6 +717,7 @@ public: /** * Fills this array as a packed square matrix in place. + * Please refer to the specification to learn more about matrix packing. */ void packSquareMatrix() { @@ -680,6 +748,7 @@ public: /** * Fills this array as a packed square matrix from any container that implements the methods begin() and size(). + * Please refer to the specification to learn more about matrix packing. */ template typename EnableIfbegin()) && sizeof(((const R*)(0U))->size())>::Type @@ -706,6 +775,7 @@ public: /** * Reconstructs full matrix, result will be saved into a static array. + * Please refer to the specification to learn more about matrix packing. */ template void unpackSquareMatrix(ScalarType (&dst_row_major)[MaxSize]) const @@ -715,6 +785,7 @@ public: /** * Reconstructs full matrix in place. + * Please refer to the specification to learn more about matrix packing. */ void unpackSquareMatrix() { @@ -730,6 +801,7 @@ public: /** * Reconstructs full matrix, result will be saved into container that implements begin() and size(). + * Please refer to the specification to learn more about matrix packing. */ template typename EnableIfbegin()) && sizeof(((const R*)(0U))->size())>::Type @@ -749,7 +821,9 @@ public: } } - + /** + * Aliases for compatibility with standard containers. + */ typedef ValueType value_type; typedef SizeType size_type; }; @@ -768,7 +842,9 @@ inline bool operator!=(const R& rhs, const Array& lhs) return lhs.operator!=(rhs); } - +/** + * YAML streamer specification for any Array<> + */ template class UAVCAN_EXPORT YamlStreamer > { @@ -893,6 +969,9 @@ class UAVCAN_EXPORT YamlStreamer > } public: + /** + * Prints Array<> into the stream in YAML format. + */ template static void stream(Stream& s, const ArrayType& array, int level) { diff --git a/libuavcan/include/uavcan/marshal/bit_stream.hpp b/libuavcan/include/uavcan/marshal/bit_stream.hpp index b98f91e686..0efee7a3dd 100644 --- a/libuavcan/include/uavcan/marshal/bit_stream.hpp +++ b/libuavcan/include/uavcan/marshal/bit_stream.hpp @@ -15,6 +15,10 @@ namespace uavcan void bitarrayCopy(const unsigned char* src_org, int src_offset, int src_len, unsigned char* dst_org, int dst_offset); +/** + * This class treats a chunk of memory as an array of bits. + * It is used by the bit codec for serialization/deserialization. + */ class UAVCAN_EXPORT BitStream { static const unsigned MaxBytesPerRW = 16; diff --git a/libuavcan/include/uavcan/marshal/scalar_codec.hpp b/libuavcan/include/uavcan/marshal/scalar_codec.hpp index 4c49ceeff6..7d4b1d6dc6 100644 --- a/libuavcan/include/uavcan/marshal/scalar_codec.hpp +++ b/libuavcan/include/uavcan/marshal/scalar_codec.hpp @@ -12,7 +12,10 @@ namespace uavcan { - +/** + * This class implements fast encoding/decoding of primitive type scalars into/from bit arrays. + * It uses the compile-time type information to eliminate run-time operations where possible. + */ class UAVCAN_EXPORT ScalarCodec { BitStream& stream_; diff --git a/libuavcan/include/uavcan/marshal/type_util.hpp b/libuavcan/include/uavcan/marshal/type_util.hpp index 149f3411f6..3104715dac 100644 --- a/libuavcan/include/uavcan/marshal/type_util.hpp +++ b/libuavcan/include/uavcan/marshal/type_util.hpp @@ -9,12 +9,19 @@ namespace uavcan { - +/** + * Read the specs to learn more about cast modes. + */ enum CastMode { CastModeSaturate, CastModeTruncate }; +/** + * Read the specs to learn more about tail array optimizations. + */ enum TailArrayOptimizationMode { TailArrayOptDisabled, TailArrayOptEnabled }; - +/** + * Compile-time: Returns the number of bits needed to represent an integer value. + */ template struct IntegerBitLen { @@ -26,27 +33,32 @@ struct IntegerBitLen<0> enum { Result = 0 }; }; - +/** + * Compile-time: Returns the number of bytes needed to contain the given number of bits. Assumes 1 byte == 8 bit. + */ template struct BitLenToByteLen { enum { Result = (BitLen + 7) / 8 }; }; - +/** + * Compile-time: Helper for integer and float specialization classes. Returns the platform-specific storage type. + */ template struct StorageType { typedef T Type; }; - template struct StorageType::Type> { typedef typename T::StorageType Type; }; - +/** + * Compile-time: Whether T is a primitive type on this platform. + */ template class IsPrimitiveType { @@ -63,7 +75,9 @@ public: enum { Result = sizeof(test(0)) == sizeof(Yes) }; }; - +/** + * Streams a given value into YAML string. Please see the specializations. + */ template class UAVCAN_EXPORT YamlStreamer; diff --git a/libuavcan/include/uavcan/node/abstract_node.hpp b/libuavcan/include/uavcan/node/abstract_node.hpp index 2c57d4244b..c9e4a4c919 100644 --- a/libuavcan/include/uavcan/node/abstract_node.hpp +++ b/libuavcan/include/uavcan/node/abstract_node.hpp @@ -10,7 +10,11 @@ namespace uavcan { - +/** + * This is the abstract node class. If you're going to implement your own node class for your application, + * please inherit this class so it can be used with default publisher, subscriber, server, etc. classes. + * Normally you don't need to use directly though - please refer to the class Node<>. + */ class UAVCAN_EXPORT INode { public: @@ -28,19 +32,44 @@ public: MonotonicTime getMonotonicTime() const { return getScheduler().getMonotonicTime(); } UtcTime getUtcTime() const { return getScheduler().getUtcTime(); } + /** + * Returns the Node ID of this node. + * If Node ID was not set yet, an invalid value will be returned. + */ NodeID getNodeID() const { return getScheduler().getDispatcher().getNodeID(); } + + /** + * Sets the Node ID of this node. + * Node ID can be assigned only once. This method returns true if the Node ID was successfully assigned, otherwise + * it returns false (e.g. the argument does not represent a valid Node ID, or it was already assigned earlier). + * As long as a valid Node ID is not set, the node will remain in passive mode. + */ bool setNodeID(NodeID nid) { return getScheduler().getDispatcher().setNodeID(nid); } + /** + * Whether the node is in passive mode, i.e. can't transmit anything to the bus. + * Please read the specs to learn more. + */ bool isPassiveMode() const { return getScheduler().getDispatcher().isPassiveMode(); } + /** + * Same as @ref spin(MonotonicDuration), but the deadline is specified as an absolute time value + * rather than duration. + */ int spin(MonotonicTime deadline) { return getScheduler().spin(deadline); } + /** + * Runs the node. + * Normally your application should not block anywhere else. + * Block inside this method forever or call it periodically. + * This method returns 0 if no errors occurred, or a negative error code if something failed (see error.hpp). + */ int spin(MonotonicDuration duration) { return getScheduler().spin(getMonotonicTime() + duration); diff --git a/libuavcan/include/uavcan/node/generic_publisher.hpp b/libuavcan/include/uavcan/node/generic_publisher.hpp index f21b7b4898..38bb31826f 100644 --- a/libuavcan/include/uavcan/node/generic_publisher.hpp +++ b/libuavcan/include/uavcan/node/generic_publisher.hpp @@ -84,6 +84,9 @@ class UAVCAN_EXPORT GenericPublisher : public GenericPublisherBase TransferID* tid, MonotonicTime blocking_deadline); public: + /** + * @param max_transfer_interval Maximum expected time interval between subsequent publications. Leave default. + */ GenericPublisher(INode& node, MonotonicDuration tx_timeout, MonotonicDuration max_transfer_interval = TransferSender::getDefaultMaxTransferInterval()) : GenericPublisherBase(node, tx_timeout, max_transfer_interval) @@ -91,6 +94,10 @@ public: ~GenericPublisher() { } + /** + * Init method can be called prior first publication, but it's not necessary + * because the publisher can be automatically initialized ad-hoc. + */ int init() { return checkInit(); diff --git a/libuavcan/include/uavcan/node/generic_subscriber.hpp b/libuavcan/include/uavcan/node/generic_subscriber.hpp index 29b7cf6f18..161a8d04c8 100644 --- a/libuavcan/include/uavcan/node/generic_subscriber.hpp +++ b/libuavcan/include/uavcan/node/generic_subscriber.hpp @@ -17,7 +17,18 @@ namespace uavcan { - +/** + * This class extends the data structure with extra information obtained from the transport layer, + * such as Source Node ID, timestamps, Transfer ID, index of the interface this transfer was picked up from, etc. + * + * PLEASE NOTE that since this class inherits the data structure type, subscription callbacks can accept either + * object of this class or the data structure type directly if the extra information is not needed. + * + * For example, both of these callbacks can be used with the same data structure 'Foo': + * void first(const ReceivedDataStructure& msg); + * void second(const Foo& msg); + * In the latter case, an implicit cast will happen before the callback is invoked. + */ template class UAVCAN_EXPORT ReceivedDataStructure : public DataType_ { @@ -57,6 +68,10 @@ public: uint8_t getIfaceIndex() const { return safeget(); } }; +/** + * This operator neatly prints the data structure prepended with extra data from the transport layer. + * The extra data will be represented as YAML comment. + */ template static Stream& operator<<(Stream& s, const ReceivedDataStructure& rds) { @@ -86,12 +101,19 @@ protected: void stop(TransferListenerBase* listener); public: + /** + * Returns the number of failed attempts to decode received message. Generally, a failed attempt means either: + * - Transient failure in the transport layer. + * - Incompatible data types. + */ uint32_t getFailureCount() const { return failure_count_; } INode& getNode() const { return node_; } }; - +/** + * This helper class does some compile-time magic on the transport layer machinery. For authorized personnel only. + */ template class UAVCAN_EXPORT TransferListenerInstantiationHelper { @@ -173,6 +195,10 @@ protected: return genericStart(&Dispatcher::registerServiceResponseListener); } + /** + * Terminate the subscription. + * Dispatcher core will remove this instance from the subscribers list. + */ void stop() { GenericSubscriberBase::stop(forwarder_); @@ -180,6 +206,10 @@ protected: TransferListenerType* getTransferListener() { return forwarder_; } + /** + * Returns the mutable reference to the temporary storage for decoded received messages. + * Reference to this storage is used as a parameter for subscription callbacks. + */ ReceivedDataStructure& getReceivedStructStorage() { return message_; } }; diff --git a/libuavcan/include/uavcan/node/global_data_type_registry.hpp b/libuavcan/include/uavcan/node/global_data_type_registry.hpp index 41646751b1..8ee9d39a95 100644 --- a/libuavcan/include/uavcan/node/global_data_type_registry.hpp +++ b/libuavcan/include/uavcan/node/global_data_type_registry.hpp @@ -17,9 +17,26 @@ namespace uavcan { - +/** + * Bit mask where bit at index X is set if there's a Data Type with ID X. + */ typedef BitSet DataTypeIDMask; +/** + * This singleton is shared among all existing node instances. It is instantiated automatically + * when the C++ runtime executes contstructors before main(). + * + * Its purpose is to keep the list of all UAVCAN data types known and used by this application. + * + * Also, the mapping between Data Type name and its Data Type ID is also stored in this singleton. + * UAVCAN data types with default Data Type ID that are autogenerated by the libuavcan DSDL compiler + * are registered automatically before main() (refer to the generated headers to see how exactly). + * Data types that don't have a default Data Type ID must be registered manually using the methods + * of this class (read the method documentation). + * + * Attempt to use a data type that was not registered with this singleton (e.g. publish, subscribe, + * perform a service call etc.) will fail with an error code @ref ErrUnknownDataType. + */ class UAVCAN_EXPORT GlobalDataTypeRegistry : Noncopyable { struct Entry : public LinkedListNode @@ -49,12 +66,15 @@ class UAVCAN_EXPORT GlobalDataTypeRegistry : Noncopyable }; public: + /** + * Result of data type registration + */ enum RegistResult { - RegistResultOk, - RegistResultCollision, - RegistResultInvalidParams, - RegistResultFrozen + RegistResultOk, ///< Success, data type is now registered and can be used. + RegistResultCollision, ///< Data type name or ID is not unique. + RegistResultInvalidParams, ///< Invalid input parameters. + RegistResultFrozen ///< Data Type Registery has been frozen and can't be modified anymore. }; private: @@ -71,24 +91,85 @@ private: RegistResult registImpl(Entry* dtd); public: + /** + * Returns the reference to the singleton. + */ static GlobalDataTypeRegistry& instance(); - /// Last call wins + /** + * Register a data type 'Type' with ID 'id'. + * If this data type was registered earlier, its old registration will be overridden. + * This method will fail if the data type registry is frozen. + * + * @tparam Type Autogenerated UAVCAN data type to register. Data types are generated by the + * libuavcan DSDL compiler from DSDL definitions. + * + * @param id Data Type ID for this data type. + */ template RegistResult regist(DataTypeID id); - /// Further calls to regist<>() will fail + /** + * Data Type registry needs to be frozen before a node instance can use it in + * order to prevent accidental change in data type configuration on a running + * node. + * + * This method will be called automatically by the node during start up, so + * the user does not need to call it from the application manually. Subsequent + * calls will not have any effect. + * + * Once frozen, data type registry can't be unfrozen. + */ void freeze(); bool isFrozen() const { return frozen_; } + /** + * Finds data type descriptor by full data type name, e.g. "uavcan.protocol.NodeStatus". + * Returns null pointer if the data type with this name is not registered. + * @param kind Data Type Kind - message or service + * @param name Full data type name + * @return Descriptor for this data type or null pointer if not found + */ const DataTypeDescriptor* find(DataTypeKind kind, const char* name) const; + + /** + * Finds data type descriptor by data type ID. + * Returns null pointer if the data type with this ID is not registered. + * @param kind Data Type Kind - message or service + * @param dtid Data Type ID + * @return Descriptor for this data type or null pointer if not found + */ const DataTypeDescriptor* find(DataTypeKind kind, DataTypeID dtid) const; + /** + * Computes Aggregate Signature for all known data types selected by the mask. + * Please read the DSDL specification. + * @param[in] kind Data Type Kind - messages or services. + * @param[inout] inout_id_mask Data types to compute aggregate signature for; bits at + * the positions of unknown data types will be cleared. + * @return Computed data type signature. + */ DataTypeSignature computeAggregateSignature(DataTypeKind kind, DataTypeIDMask& inout_id_mask) const; + /** + * Sets the mask so that only bits corresponding to known data types will be set. + * In other words: + * for data_type_id := [0, 1023] + * mask[data_type_id] := data_type_exists(data_type_id) + * + * @param[in] kind Data Type Kind - messages or services. + * @param[out] mask Output mask of known data types. + */ void getDataTypeIDMask(DataTypeKind kind, DataTypeIDMask& mask) const; + /** + * Returns the number of registered message types. + */ unsigned getNumMessageTypes() const { return msgs_.getLength(); } + + /** + * Returns the number of registered service types. + */ unsigned getNumServiceTypes() const { return srvs_.getLength(); } #if UAVCAN_DEBUG @@ -110,7 +191,14 @@ public: #endif }; - +/** + * This class is used by autogenerated data types to register with the + * data type registry automatically before main() is called. Note that + * if a generated data type header file is not included by any translation + * unit of the application, the data type will not be registered. + * + * Data type needs to have a default ID to be registrable by this class. + */ template struct UAVCAN_EXPORT DefaultDataTypeRegistrator { diff --git a/libuavcan/include/uavcan/node/marshal_buffer.hpp b/libuavcan/include/uavcan/node/marshal_buffer.hpp index d0d93fdac4..030919e41d 100644 --- a/libuavcan/include/uavcan/node/marshal_buffer.hpp +++ b/libuavcan/include/uavcan/node/marshal_buffer.hpp @@ -10,7 +10,9 @@ namespace uavcan { - +/** + * Abstract temporary buffer for data marshalling. + */ class UAVCAN_EXPORT IMarshalBuffer : public ITransferBuffer { public: @@ -18,15 +20,31 @@ public: virtual unsigned getDataLength() const = 0; }; - +/** + * Abstract provider of abstract buffer for data marshalling. + */ class UAVCAN_EXPORT IMarshalBufferProvider { public: virtual ~IMarshalBufferProvider() { } + + /** + * Returns pointer to abstract buffer for data marshalling, + * but does not transfer ownership. + * If the requested buffer size is larger than available, + * null pointer will be returned. + * @param size Maximum buffer size needed for marshaling. + * @return Pointer to the buffer, or null pointer if + * the requested size is too large. + */ virtual IMarshalBuffer* getBuffer(unsigned size) = 0; }; - +/** + * Default implementation of marshal buffer provider. + * This implementation provides the buffer large enough to + * serialize any UAVCAN data structure. + */ template class UAVCAN_EXPORT MarshalBufferProvider : public IMarshalBufferProvider { diff --git a/libuavcan/include/uavcan/node/node.hpp b/libuavcan/include/uavcan/node/node.hpp index 8f39b06877..1245c9fe85 100644 --- a/libuavcan/include/uavcan/node/node.hpp +++ b/libuavcan/include/uavcan/node/node.hpp @@ -28,7 +28,31 @@ namespace uavcan { - +/** + * This is the top-level node API. + * A custom node class can be implemented if needed, in which case it shall inherit INode. + * + * @tparam MemPoolSize_ Size of memory pool for this node, in bytes. + * Minimum recommended size is 4K * (number of CAN ifaces + 1). + * For simple nodes this number can be reduced. + * For high-traffic nodes the recommended minimum is + * like 16K * (number of CAN ifaces + 1). + * + * @tparam OutgoingTransferRegistryStaticEntries Number of statically allocated objects + * to track Transfer ID for outgoing transfers. + * Normally it should be equal to expected number of + * publishers and service callers, but it's not necessary. + * Additional objects for Transfer ID tracking will + * be allocated in the memory pool if needed. + * Default value is acceptable for any use case. + * + * @tparam OutgoingTransferMaxPayloadLen Maximum outgoing transfer payload length. + * It's pointless to make this value larger than + * @ref MaxTransferPayloadLen, which is default. + * Note that in tiny mode the default value is actually + * smaller than @ref MaxTransferPayloadLen (may cause + * run-time failures). + */ template = UAVCAN_CPP11 @@ -185,7 +235,13 @@ public: void logError(const char* source, const char* text) { (void)proto_logger_.logError(source, text); } #endif + /** + * @} + */ + /** + * Use this method to configure logging. + */ Logger& getLogger() { return proto_logger_; } #endif // UAVCAN_TINY diff --git a/libuavcan/include/uavcan/node/publisher.hpp b/libuavcan/include/uavcan/node/publisher.hpp index a16c9eb5c7..5d1524f4da 100644 --- a/libuavcan/include/uavcan/node/publisher.hpp +++ b/libuavcan/include/uavcan/node/publisher.hpp @@ -8,15 +8,32 @@ namespace uavcan { - +/** + * Use this class to publish messages to the bus (broadcast, unicast, or both). + * + * @tparam DataType_ Message data type + */ template class UAVCAN_EXPORT Publisher : protected GenericPublisher { typedef GenericPublisher BaseType; public: - typedef DataType_ DataType; + typedef DataType_ DataType; ///< Message data type + /** + * @param node Node instance this publisher will be registered with. + * + * @param tx_timeout If CAN frames of this message are not delivered to the bus + * in this amount of time, they will be discarded. Default value + * is good enough for rather high-frequency, high-priority messages. + * + * @param max_transfer_interval Maximum expected transfer interval. It's absolutely safe + * to leave default value here. It just defines how soon the + * Transfer ID tracking objects associated with this message type + * will be garbage collected by the library if it's no longer + * being published. + */ explicit Publisher(INode& node, MonotonicDuration tx_timeout = getDefaultTxTimeout(), MonotonicDuration max_transfer_interval = TransferSender::getDefaultMaxTransferInterval()) : BaseType(node, tx_timeout, max_transfer_interval) @@ -27,16 +44,30 @@ public: StaticAssert::check(); } + /** + * Broadcast the message. + * Returns negative error code. + */ int broadcast(const DataType& message) { return BaseType::publish(message, TransferTypeMessageBroadcast, NodeID::Broadcast); } + /** + * Warning: You probably don't want to use this method; it's for advanced use cases like + * e.g. network time synchronization. Use the overloaded method with fewer arguments instead. + * This overload allows to explicitly specify Transfer ID. + * Returns negative error code. + */ int broadcast(const DataType& message, TransferID tid) { return BaseType::publish(message, TransferTypeMessageBroadcast, NodeID::Broadcast, tid); } + /** + * Unicast the message to the specified destination Node ID. + * Returns negative error code. + */ int unicast(const DataType& message, NodeID dst_node_id) { if (!dst_node_id.isUnicast()) @@ -49,7 +80,12 @@ public: static MonotonicDuration getDefaultTxTimeout() { return MonotonicDuration::fromMSec(10); } + /** + * Init method can be called prior first publication, but it's not necessary + * because the publisher can be automatically initialized ad-hoc. + */ using BaseType::init; + using BaseType::getTransferSender; using BaseType::getMinTxTimeout; using BaseType::getMaxTxTimeout; diff --git a/libuavcan/include/uavcan/node/scheduler.hpp b/libuavcan/include/uavcan/node/scheduler.hpp index 20623a7555..f283f72e7e 100644 --- a/libuavcan/include/uavcan/node/scheduler.hpp +++ b/libuavcan/include/uavcan/node/scheduler.hpp @@ -55,7 +55,9 @@ public: MonotonicTime getEarliestDeadline() const; }; - +/** + * This class distributes processing time between library components (IO handling, deadline callbacks, ...). + */ class UAVCAN_EXPORT Scheduler : Noncopyable { enum { DefaultDeadlineResolutionMs = 5 }; @@ -85,6 +87,10 @@ public: , inside_spin_(false) { } + /** + * Spin until the deadline, or until some error occurs. + * Returns negative error code. + */ int spin(MonotonicTime deadline); DeadlineScheduler& getDeadlineScheduler() { return deadline_scheduler_; } @@ -96,6 +102,10 @@ public: MonotonicTime getMonotonicTime() const { return dispatcher_.getSystemClock().getMonotonic(); } UtcTime getUtcTime() const { return dispatcher_.getSystemClock().getUtc(); } + /** + * Worst case deadline callback resolution. + * Higher resolution increases CPU usage. + */ MonotonicDuration getDeadlineResolution() const { return deadline_resolution_; } void setDeadlineResolution(MonotonicDuration res) { @@ -104,6 +114,12 @@ public: deadline_resolution_ = res; } + /** + * How often the scheduler will run cleanup (listeners, outgoing transfer registry, ...). + * Cleanup execution time grows linearly with number of listeners and number of items + * in the Outgoing Transfer ID registry. + * Lower period increases CPU usage. + */ MonotonicDuration getCleanupPeriod() const { return cleanup_period_; } void setCleanupPeriod(MonotonicDuration period) { diff --git a/libuavcan/include/uavcan/node/service_client.hpp b/libuavcan/include/uavcan/node/service_client.hpp index df199be2a7..6a54c481d4 100644 --- a/libuavcan/include/uavcan/node/service_client.hpp +++ b/libuavcan/include/uavcan/node/service_client.hpp @@ -27,7 +27,10 @@ public: typedef ServiceResponseTransferListener Type; }; - +/** + * Object of this type will be returned to the application as a result of service call. + * Note that application ALWAYS gets this result, even when it times out or fails because of some other reason. + */ template struct UAVCAN_EXPORT ServiceCallResult { @@ -35,9 +38,9 @@ struct UAVCAN_EXPORT ServiceCallResult enum Status { Success, ErrorTimeout }; - const Status status; - NodeID server_node_id; - ResponseFieldType& response; ///< Either response contents or unspecified response structure + const Status status; ///< Whether successful or not. Failure to decode the response causes timeout. + NodeID server_node_id; ///< Node ID of the server this call was addressed to. + ResponseFieldType& response; ///< Returned data structure. Undefined if the service call has failed. ServiceCallResult(Status arg_status, NodeID arg_server_node_id, ResponseFieldType& arg_response) : status(arg_status) @@ -48,9 +51,16 @@ struct UAVCAN_EXPORT ServiceCallResult UAVCAN_ASSERT((status == Success) || (status == ErrorTimeout)); } + /** + * Shortcut to quickly check whether the call was successful. + */ bool isSuccessful() const { return status == Success; } }; +/** + * This operator neatly prints the service call result prepended with extra data like Server Node ID. + * The extra data will be represented as YAML comment. + */ template static Stream& operator<<(Stream& s, const ServiceCallResult& scr) { @@ -68,7 +78,9 @@ static Stream& operator<<(Stream& s, const ServiceCallResult& scr) return s; } - +/** + * Do not use directly. + */ class ServiceClientBase : protected DeadlineHandler { protected: @@ -86,16 +98,34 @@ protected: int prepareToCall(INode& node, const char* dtname, NodeID server_node_id, TransferID& out_transfer_id); public: + /** + * Returns true if the service call is currently in progress. + */ bool isPending() const { return pending_; } + /** + * It's not recommended to override default timeouts. + */ static MonotonicDuration getDefaultRequestTimeout() { return MonotonicDuration::fromMSec(1000); } static MonotonicDuration getMinRequestTimeout() { return MonotonicDuration::fromMSec(10); } static MonotonicDuration getMaxRequestTimeout() { return MonotonicDuration::fromMSec(60000); } + /** + * Returns the service response waiting deadline, if pending. + */ using DeadlineHandler::getDeadline; }; - +/** + * Use this class to invoke services on remote nodes. + * + * @tparam DataType_ Service data type. + * + * @tparam Callback_ Service response will be delivered through the callback of this type. + * In C++11 mode this type defaults to std::function<>. + * In C++03 mode this type defaults to a plain function pointer; use binder to + * call member functions as callbacks. + */ template = UAVCAN_CPP11 typename Callback_ = std::function&)> @@ -133,6 +163,10 @@ private: virtual void handleDeadline(MonotonicTime); public: + /** + * @param node Node instance this client will be registered with. + * @param callback Callback instance. Optional, can be assigned later. + */ explicit ServiceClient(INode& node, const Callback& callback = Callback()) : SubscriberType(node) , ServiceClientBase(node) @@ -147,23 +181,53 @@ public: virtual ~ServiceClient() { cancel(); } + /** + * Shall be called before first use. + * Returns negative error code. + */ int init() { return publisher_.init(); } + /** + * Performs non-blocking service call. + * This method transmits the service request and returns immediately. + * + * Service response will be delivered into the application via the callback. + * Note that the callback will ALWAYS be called even if the service call has timed out; the + * actual result of the call (success/failure) will be passed to the callback as well. + * + * If this client instance is already pending service response, it will be cancelled and the new + * call will be performed. + * + * Returns negative error code. + */ int call(NodeID server_node_id, const RequestType& request); + /** + * Cancel the pending service call. + * Does nothing if it is not pending. + */ void cancel(); + /** + * Service response callback must be set prior service call. + */ const Callback& getCallback() const { return callback_; } void setCallback(const Callback& cb) { callback_ = cb; } + /** + * Returns the number of failed attempts to decode received response. Generally, a failed attempt means either: + * - Transient failure in the transport layer. + * - Incompatible data types. + */ uint32_t getResponseFailureCount() const { return SubscriberType::getFailureCount(); } - /* - * Request timeouts - * There is no such config as TX timeout - TX timeouts are configured automagically according to request timeouts + /** + * Request timeouts. + * There is no such config as TX timeout - TX timeouts are configured automagically according to request timeouts. + * Not recommended to change. */ MonotonicDuration getRequestTimeout() const { return request_timeout_; } void setRequestTimeout(MonotonicDuration timeout) diff --git a/libuavcan/include/uavcan/node/service_server.hpp b/libuavcan/include/uavcan/node/service_server.hpp index e2c92d304d..cebec91072 100644 --- a/libuavcan/include/uavcan/node/service_server.hpp +++ b/libuavcan/include/uavcan/node/service_server.hpp @@ -18,7 +18,26 @@ namespace uavcan { - +/** + * Use this class to implement UAVCAN service servers. + * + * @tparam DataType_ Service data type. + * + * @tparam Callback_ Service calls will be delivered through the callback of this type, and service + * response will be returned via the output parameter of the callback. Note that + * the reference to service response data struct passed to the callback always points + * to a default initialized response object. + * Please also refer to @ref ReceivedDataStructure<>. + * In C++11 mode this type defaults to std::function<>. + * In C++03 mode this type defaults to a plain function pointer; use binder to + * call member functions as callbacks. + * + * @tparam NumStaticReceivers Number of statically allocated receiver objects. If there's more service + * clients for this service, extra receivers will be allocated in the memory pool. + * + * @tparam NumStaticBufs Number of statically allocated receiver buffers. If there's more concurrent + * incoming transfers, extra buffers will be allocated in the memory pool. + */ template = UAVCAN_CPP11 typename Callback_ = std::function&, @@ -92,6 +111,10 @@ public: StaticAssert::check(); } + /** + * Starts the server. + * Incoming service requests will be passed to the application via the callback. + */ int start(const Callback& callback) { stop(); @@ -112,6 +135,9 @@ public: return SubscriberType::startAsServiceRequestListener(); } + /** + * Stops the server. + */ using SubscriberType::stop; static MonotonicDuration getDefaultTxTimeout() { return MonotonicDuration::fromMSec(1000); } @@ -121,6 +147,11 @@ public: MonotonicDuration getTxTimeout() const { return publisher_.getTxTimeout(); } void setTxTimeout(MonotonicDuration tx_timeout) { publisher_.setTxTimeout(tx_timeout); } + /** + * Returns the number of failed attempts to decode data structs. Generally, a failed attempt means either: + * - Transient failure in the transport layer. + * - Incompatible data types. + */ uint32_t getRequestFailureCount() const { return SubscriberType::getFailureCount(); } uint32_t getResponseFailureCount() const { return response_failure_count_; } }; diff --git a/libuavcan/include/uavcan/node/subscriber.hpp b/libuavcan/include/uavcan/node/subscriber.hpp index 98394b53fa..a644494e4a 100644 --- a/libuavcan/include/uavcan/node/subscriber.hpp +++ b/libuavcan/include/uavcan/node/subscriber.hpp @@ -18,7 +18,28 @@ namespace uavcan { - +/** + * Use this class to subscribe to a message. + * + * @tparam DataType_ Message data type. + * + * @tparam Callback_ Type of the callback that will be used to deliver received messages + * into the application. Type of the argument of the callback can be either: + * - DataType_& + * - const DataType_& + * - ReceivedDataStructure& + * - const ReceivedDataStructure& + * For the first two options, @ref ReceivedDataStructure<> will be casted implicitly. + * In C++11 mode this type defaults to std::function<>. + * In C++03 mode this type defaults to a plain function pointer; use binder to + * call member functions as callbacks. + * + * @tparam NumStaticReceivers Number of statically allocated receiver objects. If there's more publishers + * of this message, extra receivers will be allocated in the memory pool. + * + * @tparam NumStaticBufs Number of statically allocated receiver buffers. If there's more concurrent + * incoming transfers, extra buffers will be allocated in the memory pool. + */ template = UAVCAN_CPP11 typename Callback_ = std::function&)>, @@ -70,6 +91,11 @@ public: StaticAssert::check(); } + /** + * Begin receiving messages. + * Each message will be passed to the application via the callback. + * Returns negative error code. + */ int start(const Callback& callback) { stop(); diff --git a/libuavcan/include/uavcan/node/timer.hpp b/libuavcan/include/uavcan/node/timer.hpp index 1ba5c599b8..cf638d8e96 100644 --- a/libuavcan/include/uavcan/node/timer.hpp +++ b/libuavcan/include/uavcan/node/timer.hpp @@ -25,10 +25,13 @@ namespace uavcan class UAVCAN_EXPORT TimerBase; +/** + * Objects of this type will be supplied into timer callbacks. + */ struct UAVCAN_EXPORT TimerEvent { - MonotonicTime scheduled_time; - MonotonicTime real_time; + MonotonicTime scheduled_time; ///< Time when the timer callback was expected to be invoked + MonotonicTime real_time; ///< True time when the timer callback was invoked TimerEvent(MonotonicTime arg_scheduled_time, MonotonicTime arg_real_time) : scheduled_time(arg_scheduled_time) @@ -36,7 +39,9 @@ struct UAVCAN_EXPORT TimerEvent { } }; - +/** + * Inherit this class if you need a timer callback method in your class. + */ class UAVCAN_EXPORT TimerBase : private DeadlineHandler { MonotonicDuration period_; @@ -54,16 +59,35 @@ public: , period_(MonotonicDuration::getInfinite()) { } + /** + * Various ways to start the timer - periodically or once. + */ void startOneShotWithDeadline(MonotonicTime deadline); void startOneShotWithDelay(MonotonicDuration delay); void startPeriodic(MonotonicDuration period); + /** + * Returns period if the timer is in periodic mode. + * Returns infinite duration if the timer is in one-shot mode or stopped. + */ MonotonicDuration getPeriod() const { return period_; } + /** + * Implement this method in your class to receive callbacks. + */ virtual void handleTimerEvent(const TimerEvent& event) = 0; }; - +/** + * Wrapper over TimerBase that forwards callbacks into arbitrary handlers, like + * functor objects, member functions or static functions. + * + * Callback must be set before the first event; otherwise the event will generate a fatal error. + * + * Also take a look at @ref MethodBinder<>, which may come useful if C++11 features are not available. + * + * @tparam Callback_ Callback type. Shall accept const reference to TimerEvent as its argument. + */ template class UAVCAN_EXPORT TimerEventForwarder : public TimerBase { @@ -96,6 +120,10 @@ public: , callback_(callback) { } + /** + * Get/set the callback object. + * Callback must be set before the first event; otherwise the event will generate a fatal error. + */ const Callback& getCallback() const { return callback_; } void setCallback(const Callback& callback) { callback_ = callback; } }; @@ -103,6 +131,10 @@ public: #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 +/** + * Use this timer in C++11 mode. + * Callback type is std::function<>. + */ typedef TimerEventForwarder > Timer; #endif diff --git a/libuavcan/include/uavcan/protocol/data_type_info_provider.hpp b/libuavcan/include/uavcan/protocol/data_type_info_provider.hpp index e633818b63..568c9ecf3a 100644 --- a/libuavcan/include/uavcan/protocol/data_type_info_provider.hpp +++ b/libuavcan/include/uavcan/protocol/data_type_info_provider.hpp @@ -12,7 +12,11 @@ namespace uavcan { - +/** + * This class implements the standard services for data type introspection. + * Once started it does not require any attention from the application. + * The user does not need to deal with it directly - it's started by the node class. + */ class UAVCAN_EXPORT DataTypeInfoProvider : Noncopyable { typedef MethodBinder= severity level of the logger. + * + * The message will be reported into the external log sink if the external sink is + * installed and the severity level of the message is >= severity level of the external sink. + * + * Returns negative error code. + */ int log(const protocol::debug::LogMessage& message); + /** + * Severity filter for UAVCAN broadcasting. + * Log message will be broadcasted via the UAVCAN network only if its severity is >= getLevel(). + * This does not affect the external sink. + * Default level is ERROR. + */ LogLevel getLevel() const { return level_; } void setLevel(LogLevel level) { level_ = level; } + /** + * External log sink allows the application to install a hook on the logger output. + * This can be used for application-wide logging. + * Null pointer means that there's no log sink (can be used to remove it). + * By default there's no log sink. + */ ILogSink* getExternalSink() const { return external_sink_; } void setExternalSink(ILogSink* sink) { external_sink_ = sink; } + /** + * Log message broadcast transmission timeout. + * The default value should be acceptable for any use case. + */ MonotonicDuration getTxTimeout() const { return logmsg_pub_.getTxTimeout(); } void setTxTimeout(MonotonicDuration val) { logmsg_pub_.setTxTimeout(val); } + /** + * Helper methods for various severity levels and with formatting support. + * These methods build a formatted log message and pass it into the method @ref log(). + * + * Format string usage is a bit unusual: use "%*" for any argument type, use "%%" to print a percent character. + * No other formating options are supported. Insufficient/extra arguments are ignored. + * + * Example format string: + * "What do you get if you %* %* by %*? %*. Extra arguments: %* %* %%" + * ...with the following arguments: + * "multiply", 6, 9.0F 4.2e1 + * ...will likely produce this (floating point representation is platform dependent): + * "What do you get if you multiply 6 by 9.000000? 42.000000. Extra arguments: %* %* %" + * + * Formatting is not supported in C++03 mode. + * @{ + */ #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 template @@ -129,6 +199,9 @@ public: } #endif + /** + * @} + */ }; #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 diff --git a/libuavcan/include/uavcan/protocol/network_compat_checker.hpp b/libuavcan/include/uavcan/protocol/network_compat_checker.hpp index 4107c15c0d..2a5799e3bc 100644 --- a/libuavcan/include/uavcan/protocol/network_compat_checker.hpp +++ b/libuavcan/include/uavcan/protocol/network_compat_checker.hpp @@ -16,19 +16,25 @@ namespace uavcan struct UAVCAN_EXPORT NetworkCompatibilityCheckResult { - NodeID conflicting_node; - uint8_t num_failed_nodes; + NodeID conflicting_node; ///< First detected conflicting node + uint8_t num_failed_nodes; ///< Number of nodes that did not respond to service requests (probably not supporting) NetworkCompatibilityCheckResult() : num_failed_nodes(0) { } + /** + * Quick check if the network compatibility check did not discover any problems. + */ bool isOk() const { return !conflicting_node.isValid(); } }; /** + * Performs Network Compatibility Check. Please read the specs. + * * This class does not issue GlobalDiscoveryRequest, assuming that it was done already by the caller. - * Instantiated object can execute() only once. Objects of this class are intended for stack allocation. + * Instantiated object can @ref execute() only once. + * Objects of this class are intended for stack allocation. */ class UAVCAN_EXPORT NetworkCompatibilityChecker : Noncopyable { @@ -72,10 +78,28 @@ public: , last_cats_request_ok_(false) { } + /** + * Run the check. + * Beware: this method may block for a several seconds! + * + * If this method has been executed successfully, use @ref getResult() to get the actual check result. + * + * This method can be executed only once on a given instance of this class (shall be + * destroyed and reconstructed from scratch). + * + * Returns negative error code. + */ int execute(); + /** + * This method can return a meaningful result only if @ref execute() has been executed successfully once. + */ const NetworkCompatibilityCheckResult& getResult() const { return result_; } + /** + * Convenience method. Should be called immediately before @ref execute(). + * Returns negative error code. + */ static int publishGlobalDiscoveryRequest(INode& node); }; diff --git a/libuavcan/include/uavcan/protocol/node_status_monitor.hpp b/libuavcan/include/uavcan/protocol/node_status_monitor.hpp index d553d2c4bd..84f86f15e4 100644 --- a/libuavcan/include/uavcan/protocol/node_status_monitor.hpp +++ b/libuavcan/include/uavcan/protocol/node_status_monitor.hpp @@ -11,7 +11,10 @@ namespace uavcan { - +/** + * This class implements the core functionality of a network monitor. + * It can be extended by inheritance to add more complex logic, or used directly as is. + */ class UAVCAN_EXPORT NodeStatusMonitor : protected TimerBase { public: @@ -67,6 +70,8 @@ private: protected: /** * Called when a node becomes online, changes status or goes offline. + * Refer to uavcan.protocol.NodeStatus for the offline timeout value. + * Overriding is not required. */ virtual void handleNodeStatusChange(const NodeStatusChangeEvent& event) { @@ -74,7 +79,9 @@ protected: } /** - * Called for every received message uavcan.protocol.NodeStatus after handleNodeStatusChange(). + * Called for every received message uavcan.protocol.NodeStatus after handleNodeStatusChange(), even + * if the status code did not change. + * Overriding is not required. */ virtual void handleNodeStatusMessage(const ReceivedDataStructure& msg) { @@ -89,12 +96,28 @@ public: virtual ~NodeStatusMonitor() { } + /** + * Starts the monitor. + * Destroy the object to stop it. + * Returns negative error code. + */ int start(); + /** + * Make the node unknown. + */ void forgetNode(NodeID node_id); + /** + * Returns status of a given node. + * Unknown nodes are considered offline. + */ NodeStatus getNodeStatus(NodeID node_id) const; + /** + * This helper method allows to quickly estimate the overall network health. + * Status of the local node is not considered. + */ NodeID findNodeWithWorstStatus() const; }; diff --git a/libuavcan/include/uavcan/protocol/node_status_provider.hpp b/libuavcan/include/uavcan/protocol/node_status_provider.hpp index ff950ed634..92f48bdcc4 100644 --- a/libuavcan/include/uavcan/protocol/node_status_provider.hpp +++ b/libuavcan/include/uavcan/protocol/node_status_provider.hpp @@ -16,7 +16,10 @@ namespace uavcan { - +/** + * Provides the status and basic information about this node to other network participants. + * Usually the application does not need to deal with this class directly - it's instantiated by the node class. + */ class UAVCAN_EXPORT NodeStatusProvider : private TimerBase { typedef MethodBinder @@ -64,10 +67,21 @@ public: node_status_pub_.setTxTimeout(MonotonicDuration::fromMSec(protocol::NodeStatus::PUBLICATION_PERIOD_MS - 10)); } + /** + * Starts the provider and immediately broadcasts uavcan.protocol.NodeStatus. + * Returns negative error code. + */ int startAndPublish(); + /** + * Publish the message uavcan.protocol.NodeStatus right now, out of schedule. + * Returns negative error code. + */ int forcePublish() { return publish(); } + /** + * Local node status code control. + */ uint8_t getStatusCode() const { return node_info_.status.status_code; } void setStatusCode(uint8_t code); void setStatusOk() { setStatusCode(protocol::NodeStatus::STATUS_OK); } @@ -76,9 +90,18 @@ public: void setStatusCritical() { setStatusCode(protocol::NodeStatus::STATUS_CRITICAL); } void setStatusOffline() { setStatusCode(protocol::NodeStatus::STATUS_OFFLINE); } + /** + * Local node name control. + * Can be set only once before the provider is started. + * The provider will refuse to start if the node name is not set. + */ const typename protocol::GetNodeInfo::Response::FieldTypes::name& getName() const { return node_info_.name; } void setName(const char* name); + /** + * Node version information. + * Can be set only once before the provider is started. + */ const protocol::SoftwareVersion& getSoftwareVersion() const { return node_info_.software_version; } const protocol::HardwareVersion& getHardwareVersion() const { return node_info_.hardware_version; } void setSoftwareVersion(const protocol::SoftwareVersion& version); diff --git a/libuavcan/include/uavcan/protocol/panic_broadcaster.hpp b/libuavcan/include/uavcan/protocol/panic_broadcaster.hpp index d23c4116d6..0fe5b9fca4 100644 --- a/libuavcan/include/uavcan/protocol/panic_broadcaster.hpp +++ b/libuavcan/include/uavcan/protocol/panic_broadcaster.hpp @@ -10,7 +10,9 @@ namespace uavcan { - +/** + * Helper for broadcasting the message uavcan.protocol.Panic. + */ class UAVCAN_EXPORT PanicBroadcaster : private TimerBase { Publisher pub_; @@ -28,8 +30,15 @@ public: pub_.setTxTimeout(MonotonicDuration::fromMSec(protocol::Panic::BROADCASTING_INTERVAL_MS - 10)); } + /** + * Begin broadcasting at the standard interval. + * This method does not block and can't fail. + */ void panic(const char* short_reason); + /** + * Stop broadcasting immediately. + */ void dontPanic(); // Where's my towel bool isPanicking() const; diff --git a/libuavcan/include/uavcan/protocol/panic_listener.hpp b/libuavcan/include/uavcan/protocol/panic_listener.hpp index e00a797d9d..00c8f30e4b 100644 --- a/libuavcan/include/uavcan/protocol/panic_listener.hpp +++ b/libuavcan/include/uavcan/protocol/panic_listener.hpp @@ -22,11 +22,13 @@ namespace uavcan { /** - * Callback prototype: - * void (const ReceivedDataStructure&) - * Or: - * void (const protocol::Panic&) + * This class implements proper panic detector. + * Refer to uavcan.protocol.Panic for details. * The listener can be stopped from the callback. + * + * @tparam Callback Possible callback prototypes: + * void (const ReceivedDataStructure&) + * void (const protocol::Panic&) */ template < #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 @@ -95,6 +97,11 @@ public: , num_subsequent_msgs_(0) { } + /** + * Start the listener. + * Once started it does not require further attention. + * Returns negative error code. + */ int start(const Callback& callback) { stop(); diff --git a/libuavcan/include/uavcan/protocol/param_server.hpp b/libuavcan/include/uavcan/protocol/param_server.hpp index 03b91b1df0..ad82f4f57a 100644 --- a/libuavcan/include/uavcan/protocol/param_server.hpp +++ b/libuavcan/include/uavcan/protocol/param_server.hpp @@ -11,7 +11,10 @@ namespace uavcan { - +/** + * Implement this interface in the application to support the standard remote reconfiguration services. + * Refer to @ref ParamServer. + */ class UAVCAN_EXPORT IParamManager { public: @@ -62,7 +65,10 @@ public: virtual int eraseAllParams() = 0; }; - +/** + * Convenience class for supporting the standard configuration services. + * Highly recommended to use. + */ class UAVCAN_EXPORT ParamServer { typedef MethodBinder namespace uavcan diff --git a/libuavcan/include/uavcan/time.hpp b/libuavcan/include/uavcan/time.hpp index a7958e5050..0fb1645c00 100644 --- a/libuavcan/include/uavcan/time.hpp +++ b/libuavcan/include/uavcan/time.hpp @@ -83,9 +83,9 @@ public: } static const unsigned StringBufSize = 32; - void toString(char buf[StringBufSize]) const; + void toString(char buf[StringBufSize]) const; ///< Prints time in seconds with microsecond resolution #if UAVCAN_TOSTRING - std::string toString() const; + std::string toString() const; ///< Prints time in seconds with microsecond resolution #endif }; @@ -169,9 +169,9 @@ public: } static const unsigned StringBufSize = 32; - void toString(char buf[StringBufSize]) const; + void toString(char buf[StringBufSize]) const; ///< Prints time in seconds with microsecond resolution #if UAVCAN_TOSTRING - std::string toString() const; + std::string toString() const; ///< Prints time in seconds with microsecond resolution #endif }; @@ -187,7 +187,7 @@ class UAVCAN_EXPORT MonotonicTime : public TimeBase { }; -class UAVCAN_EXPORT UtcTime : public TimeBase +class UAVCAN_EXPORT UtcTime : public TimeBase /// Implicitly convertible to/from uavcan.Timestamp { public: UtcTime() { } diff --git a/libuavcan/include/uavcan/transport/dispatcher.hpp b/libuavcan/include/uavcan/transport/dispatcher.hpp index 07054754e5..50cc703ca3 100644 --- a/libuavcan/include/uavcan/transport/dispatcher.hpp +++ b/libuavcan/include/uavcan/transport/dispatcher.hpp @@ -19,6 +19,9 @@ namespace uavcan class UAVCAN_EXPORT Dispatcher; +/** + * Inherit this class to receive notifications about all TX CAN frames that were transmitted with the loopback flag. + */ class UAVCAN_EXPORT LoopbackFrameListenerBase : public LinkedListNode, Noncopyable { Dispatcher& dispatcher_; @@ -54,7 +57,9 @@ public: void invokeListeners(RxFrame& frame); }; - +/** + * This class performs low-level CAN frame routing. + */ class UAVCAN_EXPORT Dispatcher : Noncopyable { CanIOManager canio_; diff --git a/libuavcan/include/uavcan/transport/frame.hpp b/libuavcan/include/uavcan/transport/frame.hpp index ab6e7607de..ea43e8c2b0 100644 --- a/libuavcan/include/uavcan/transport/frame.hpp +++ b/libuavcan/include/uavcan/transport/frame.hpp @@ -53,6 +53,9 @@ public: UAVCAN_ASSERT(frame_index <= MaxIndex); } + /** + * Max payload length depends on the transfer type and frame index. + */ int getMaxPayloadLen() const; int setPayload(const uint8_t* data, unsigned len); @@ -107,7 +110,14 @@ public: bool parse(const CanRxFrame& can_frame); + /** + * Can't be zero. + */ MonotonicTime getMonotonicTimestamp() const { return ts_mono_; } + + /** + * Can be zero if not supported by the platform driver. + */ UtcTime getUtcTimestamp() const { return ts_utc_; } uint8_t getIfaceIndex() const { return iface_index_; } diff --git a/libuavcan/include/uavcan/transport/outgoing_transfer_registry.hpp b/libuavcan/include/uavcan/transport/outgoing_transfer_registry.hpp index da6d0a1619..16236cb727 100644 --- a/libuavcan/include/uavcan/transport/outgoing_transfer_registry.hpp +++ b/libuavcan/include/uavcan/transport/outgoing_transfer_registry.hpp @@ -57,7 +57,11 @@ public: }; UAVCAN_PACKED_END - +/** + * Outgoing transfer registry keeps track of Transfer ID values for all currently existing local transfer senders. + * If a local transfer sender was inactive for a sufficiently long time, the outgoing transfer registry will + * remove the respective Transfer ID tracking object. + */ class UAVCAN_EXPORT IOutgoingTransferRegistry { public: diff --git a/libuavcan/include/uavcan/transport/transfer.hpp b/libuavcan/include/uavcan/transport/transfer.hpp index 76f0ac6257..9041d0a0a6 100644 --- a/libuavcan/include/uavcan/transport/transfer.hpp +++ b/libuavcan/include/uavcan/transport/transfer.hpp @@ -11,7 +11,7 @@ namespace uavcan { -static const unsigned MaxTransferPayloadLen = 439; ///< According to the RFC +static const unsigned MaxTransferPayloadLen = 439; ///< According to the specification. static const unsigned MaxSingleFrameTransferPayloadLen = 7; diff --git a/libuavcan/include/uavcan/transport/transfer_listener.hpp b/libuavcan/include/uavcan/transport/transfer_listener.hpp index e6f8fed42f..2965415735 100644 --- a/libuavcan/include/uavcan/transport/transfer_listener.hpp +++ b/libuavcan/include/uavcan/transport/transfer_listener.hpp @@ -83,7 +83,7 @@ public: }; /** - * Internal, refer to transport dispatcher. + * Internal, refer to the transport dispatcher class. */ class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode, Noncopyable { diff --git a/libuavcan/include/uavcan/util/lazy_constructor.hpp b/libuavcan/include/uavcan/util/lazy_constructor.hpp index bea0b4f7ac..8392d5609e 100644 --- a/libuavcan/include/uavcan/util/lazy_constructor.hpp +++ b/libuavcan/include/uavcan/util/lazy_constructor.hpp @@ -15,7 +15,13 @@ namespace uavcan { - +/** + * This class allows to postpone the object contruction. + * It statically allocates a pool of memory of just enough size to fit the object being constructed. + * Later call to construct<>() calls the constructor of the object. + * The object will be destroyed automatically when the container class destructor is called. + * The memory pool is aligned at the size of the largest primitive type (long double or long long int). + */ template class UAVCAN_EXPORT LazyConstructor { diff --git a/libuavcan/include/uavcan/util/linked_list.hpp b/libuavcan/include/uavcan/util/linked_list.hpp index e5d8391e94..efdee41302 100644 --- a/libuavcan/include/uavcan/util/linked_list.hpp +++ b/libuavcan/include/uavcan/util/linked_list.hpp @@ -51,17 +51,27 @@ public: T* get() const { return root_; } bool isEmpty() const { return get() == NULL; } + /** + * Complexity: O(N) + */ unsigned getLength() const; + /** + * Complexity: O(N) (calls remove()) + */ void insert(T* node); /** - * Inserts node A immediately before the node B where + * Inserts the node immediately before the node B where * predicate(B) -> true. + * Complexity: O(2N) (calls remove()) */ template void insertBefore(T* node, Predicate predicate); + /** + * Complexity: O(N) + */ void remove(const T* node); }; diff --git a/libuavcan/include/uavcan/util/map.hpp b/libuavcan/include/uavcan/util/map.hpp index 09853ea91c..323e1c57e2 100644 --- a/libuavcan/include/uavcan/util/map.hpp +++ b/libuavcan/include/uavcan/util/map.hpp @@ -15,6 +15,14 @@ namespace uavcan { /** * Slow but memory efficient KV container. + * + * KV pairs can be allocated in a static buffer or in the node's memory pool if the static buffer is exhausted. + * When a KV pair is deleted from the static buffer, one pair from the memory pool will be moved in the free + * slot of the static buffer, so the use of the memory pool is minimized. + * + * Please be aware that this container does not perform any speed optimizations to minimize memory footprint, + * so the complexity of most operations is O(N). + * * Type requirements: * Both key and value must be copyable, assignable and default constructible. * Key must implement a comparison operator. @@ -124,21 +132,34 @@ protected: ~MapBase() { } public: + /** + * Returns null pointer if there's no such entry. + */ Value* access(const Key& key); - /// If entry with the same key already exists, it will be replaced + /** + * If entry with the same key already exists, it will be replaced + */ Value* insert(const Key& key, const Value& value); + /** + * Does nothing if there's no such entry. + */ void remove(const Key& key); /** - * Remove entries where predicate returns true. + * Removes entries where the predicate returns true. * Predicate prototype: * bool (const Key& key, const Value& value) */ template void removeWhere(Predicate predicate); + /** + * Returns first entry where the predicate returns true. + * Predicate prototype: + * bool (const Key& key, const Value& value) + */ template const Key* findFirstKey(Predicate predicate) const; diff --git a/libuavcan/include/uavcan/util/method_binder.hpp b/libuavcan/include/uavcan/util/method_binder.hpp index 9582a70cc1..ce14f663df 100644 --- a/libuavcan/include/uavcan/util/method_binder.hpp +++ b/libuavcan/include/uavcan/util/method_binder.hpp @@ -10,7 +10,11 @@ namespace uavcan { - +/** + * Use this to call member functions as callbacks in C++03 mode. + * + * In C++11 or newer you don't need it because you can use std::function<>/std::bind<> instead. + */ template class UAVCAN_EXPORT MethodBinder { @@ -36,17 +40,26 @@ public: , fun_(f) { } + /** + * Returns true if the binder is initialized (doesn't contain null pointers). + */ operator bool() const { return try_implicit_cast(obj_, true) && try_implicit_cast(fun_, true); } + /** + * Will raise a fatal error if either method pointer or object pointer are null. + */ void operator()() { validateBeforeCall(); (obj_->*fun_)(); } + /** + * Will raise a fatal error if either method pointer or object pointer are null. + */ template void operator()(Par1& p1) { @@ -54,6 +67,9 @@ public: (obj_->*fun_)(p1); } + /** + * Will raise a fatal error if either method pointer or object pointer are null. + */ template void operator()(Par1& p1, Par2& p2) { diff --git a/libuavcan/include/uavcan/util/placement_new.hpp b/libuavcan/include/uavcan/util/placement_new.hpp index 47ef09627b..e65c001308 100644 --- a/libuavcan/include/uavcan/util/placement_new.hpp +++ b/libuavcan/include/uavcan/util/placement_new.hpp @@ -7,6 +7,11 @@ #include #include +/* + * Some embedded C++ implementations don't implement the placement new operator. + * Define UAVCAN_IMPLEMENT_PLACEMENT_NEW to apply this workaround. + */ + #ifndef UAVCAN_IMPLEMENT_PLACEMENT_NEW # error UAVCAN_IMPLEMENT_PLACEMENT_NEW #endif diff --git a/libuavcan/include/uavcan/util/templates.hpp b/libuavcan/include/uavcan/util/templates.hpp index dfefe14227..2c7ecdb6d2 100644 --- a/libuavcan/include/uavcan/util/templates.hpp +++ b/libuavcan/include/uavcan/util/templates.hpp @@ -63,14 +63,18 @@ struct UAVCAN_EXPORT EnableIf typedef T Type; }; - +/** + * Lightweight type categorization. + */ template struct UAVCAN_EXPORT EnableIfType { typedef R Type; }; - +/** + * Compile-time type selection (Alexandrescu) + */ template struct UAVCAN_EXPORT Select; @@ -111,7 +115,11 @@ public: enum { Result = sizeof(True_) == sizeof(IsImplicitlyConvertibleFromTo::test(returner())) }; }; - +/** + * try_implicit_cast<>(From) + * try_implicit_cast<>(From, To) + * @{ + */ template struct UAVCAN_EXPORT TryImplicitCastImpl { @@ -119,6 +127,10 @@ struct UAVCAN_EXPORT TryImplicitCastImpl static To impl(const From&, const To& default_, FalseType) { return default_; } }; +/** + * If possible, performs an implicit cast from the type From to the type To. + * If the cast is not possible, returns default_ of type To. + */ template UAVCAN_EXPORT To try_implicit_cast(const From& from, const To& default_) @@ -127,6 +139,10 @@ To try_implicit_cast(const From& from, const To& default_) BooleanType::Result>()); } +/** + * If possible, performs an implicit cast from the type From to the type To. + * If the cast is not possible, returns a default constructed object of the type To. + */ template UAVCAN_EXPORT To try_implicit_cast(const From& from) @@ -134,9 +150,13 @@ To try_implicit_cast(const From& from) return TryImplicitCastImpl::impl(from, To(), BooleanType::Result>()); } +/** + * @} + */ /** - * Some arithmetics + * Compile time square root for integers. + * Useful for operations on square matrices. */ template struct UAVCAN_EXPORT CompileTimeIntSqrt; template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<4> { enum { Result = 2 }; };