libuavcan documentation

This commit is contained in:
Pavel Kirienko
2014-07-14 22:22:18 +04:00
parent ee4c191684
commit e5ca1f7379
47 changed files with 1102 additions and 132 deletions
+3 -1
View File
@@ -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_;
+24 -11
View File
@@ -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.
+10 -3
View File
@@ -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 <unsigned MaxPools>
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 <std::size_t PoolSize, std::size_t BlockSize>
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_;
+15 -4
View File
@@ -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))
@@ -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 <unsigned NumComponents_>
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 <typename ComponentIndexType>
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;
+31 -9
View File
@@ -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 <new>.
*/
#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 <typename T>
struct UAVCAN_EXPORT IsDynamicallyAllocatable
{
+96 -17
View File
@@ -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 <typename T, ArrayMode ArrayMode, unsigned MaxSize>
class UAVCAN_EXPORT ArrayImpl : public Select<ArrayMode == ArrayModeDynamic,
@@ -135,6 +138,7 @@ class UAVCAN_EXPORT ArrayImpl : public Select<ArrayMode == ArrayModeDynamic,
public:
enum
{
/// True if the array contents can be interpreted as a 8-bit string (ASCII or UTF8).
IsStringLike = IsIntegerSpec<T>::Result && (T::MaxBitLen == 8 || T::MaxBitLen == 7) &&
(ArrayMode == ArrayModeDynamic)
};
@@ -165,6 +169,10 @@ public:
ArrayImpl() { initialize<ValueType>(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<IsStringLike>::check();
@@ -173,34 +181,53 @@ public:
return reinterpret_cast<const char*>(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 <typename R>
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 <unsigned MaxSize, ArrayMode ArrayMode, CastMode CastMode>
class UAVCAN_EXPORT ArrayImpl<IntegerSpec<1, SignednessUnsigned, CastMode>, 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<MaxSize>::operator[](ArrayBase::validateRange(pos)); }
bool at(SizeType pos) const { return BitSet<MaxSize>::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 <typename T, ArrayMode ArrayMode> class ArrayImpl<T, ArrayMode, 0>;
/**
* 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 <typename T, ArrayMode ArrayMode, unsigned MaxSize_>
class UAVCAN_EXPORT Array : public ArrayImpl<T, ArrayMode, MaxSize_>
{
@@ -446,9 +488,9 @@ class UAVCAN_EXPORT Array : public ArrayImpl<T, ArrayMode, MaxSize_>
}
public:
typedef T RawValueType;
typedef typename StorageType<T>::Type ValueType;
typedef typename Base::SizeType SizeType;
typedef T RawValueType; ///< This may be not the same as the element type.
typedef typename StorageType<T>::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 R>
typename EnableIf<sizeof(((const R*)(0U))->size()) && 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 <typename R> 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<Base::IsStringLike>::check();
@@ -586,6 +646,9 @@ public:
return *this;
}
/**
* Appends another Array<> with the same element type. Mode and max size can be different.
*/
template <uavcan::ArrayMode RhsArrayMode, unsigned RhsMaxSize>
SelfType& operator+=(const Array<T, RhsArrayMode, RhsMaxSize>& 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 <typename A>
void appendFormatted(const char* const format, const A value)
@@ -610,8 +676,8 @@ public:
StaticAssert<Base::IsStringLike>::check();
StaticAssert<IsDynamic>::check();
StaticAssert<sizeof(A() == A(0))>::check(); // This check allows to weed out most non-trivial types
StaticAssert<sizeof(A) <= sizeof(long double)>::check(); // Another stupid check to catch non-trivial types
StaticAssert<sizeof(A() == A(0))>::check(); // This check allows to weed out most compound types
StaticAssert<sizeof(A) <= sizeof(long double)>::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 <typename ScalarType>
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 R>
typename EnableIf<sizeof(((const R*)(0U))->begin()) && 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 <typename ScalarType>
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 R>
typename EnableIf<sizeof(((const R*)(0U))->begin()) && 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<T, ArrayMode, MaxSize>& lhs)
return lhs.operator!=(rhs);
}
/**
* YAML streamer specification for any Array<>
*/
template <typename T, ArrayMode ArrayMode, unsigned MaxSize>
class UAVCAN_EXPORT YamlStreamer<Array<T, ArrayMode, MaxSize> >
{
@@ -893,6 +969,9 @@ class UAVCAN_EXPORT YamlStreamer<Array<T, ArrayMode, MaxSize> >
}
public:
/**
* Prints Array<> into the stream in YAML format.
*/
template <typename Stream>
static void stream(Stream& s, const ArrayType& array, int level)
{
@@ -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;
@@ -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_;
+21 -7
View File
@@ -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 <unsigned long Num>
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 <unsigned long BitLen>
struct BitLenToByteLen
{
enum { Result = (BitLen + 7) / 8 };
};
/**
* Compile-time: Helper for integer and float specialization classes. Returns the platform-specific storage type.
*/
template <typename T, typename Enable = void>
struct StorageType
{
typedef T Type;
};
template <typename T>
struct StorageType<T, typename EnableIfType<typename T::StorageType>::Type>
{
typedef typename T::StorageType Type;
};
/**
* Compile-time: Whether T is a primitive type on this platform.
*/
template <typename T>
class IsPrimitiveType
{
@@ -63,7 +75,9 @@ public:
enum { Result = sizeof(test<T>(0)) == sizeof(Yes) };
};
/**
* Streams a given value into YAML string. Please see the specializations.
*/
template <typename T>
class UAVCAN_EXPORT YamlStreamer;
@@ -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);
@@ -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();
@@ -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<Foo>& msg);
* void second(const Foo& msg);
* In the latter case, an implicit cast will happen before the callback is invoked.
*/
template <typename DataType_>
class UAVCAN_EXPORT ReceivedDataStructure : public DataType_
{
@@ -57,6 +68,10 @@ public:
uint8_t getIfaceIndex() const { return safeget<uint8_t, &IncomingTransfer::getIfaceIndex>(); }
};
/**
* 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 <typename Stream, typename DataType>
static Stream& operator<<(Stream& s, const ReceivedDataStructure<DataType>& 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 <typename DataStruct_, unsigned NumStaticReceivers_, unsigned NumStaticBufs_>
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<DataStruct>& getReceivedStructStorage() { return message_; }
};
@@ -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<DataTypeID::Max + 1> 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<Entry>
@@ -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 <typename Type>
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 <typename Type>
struct UAVCAN_EXPORT DefaultDataTypeRegistrator
{
@@ -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 <unsigned MaxSize_ = MaxTransferPayloadLen>
class UAVCAN_EXPORT MarshalBufferProvider : public IMarshalBufferProvider
{
+63 -7
View File
@@ -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 <std::size_t MemPoolSize_,
#if UAVCAN_TINY
unsigned OutgoingTransferRegistryStaticEntries = 0,
@@ -114,42 +138,68 @@ public:
bool isStarted() const { return started_; }
/**
* Starts the node and publishes uavcan.protocol.NodeStatus immediately.
* Does not so anything if the node is already started.
* Once started, the node can't stop.
* If the node failed to start up, it's recommended to destroy the current node instance and start over.
* Returns negative error code.
*/
int start();
#if !UAVCAN_TINY
/**
* Please read the specs to learn about Network Compatibility Check.
* Returns negative error code.
* @param[out] result Check result (output).
*/
int checkNetworkCompatibility(NetworkCompatibilityCheckResult& result);
#endif
/*
* Initialization methods
/**
* Sets the node name, e.g. "com.example.product_name". The node name can be set only once.
* Must be executed before the node is started, otherwise the node will refuse to start up.
*/
void setName(const char* name) { proto_nsp_.setName(name); }
/**
* Status code helpers.
*/
void setStatusOk() { proto_nsp_.setStatusOk(); }
void setStatusInitializing() { proto_nsp_.setStatusInitializing(); }
void setStatusWarning() { proto_nsp_.setStatusWarning(); }
void setStatusCritical() { proto_nsp_.setStatusCritical(); }
/**
* Sets the status OFFLINE and publishes it immediately.
*/
void setStatusOffline()
{
proto_nsp_.setStatusOffline();
(void)proto_nsp_.forcePublish();
}
/**
* Sets the node version information.
*/
void setSoftwareVersion(const protocol::SoftwareVersion& version) { proto_nsp_.setSoftwareVersion(version); }
void setHardwareVersion(const protocol::HardwareVersion& version) { proto_nsp_.setHardwareVersion(version); }
NodeStatusProvider& getNodeStatusProvider() { return proto_nsp_; }
#if !UAVCAN_TINY
/*
* Restart handler
/**
* Restart handler can be installed to handle external node restart requests (highly recommended).
*/
void setRestartRequestHandler(IRestartRequestHandler* handler) { proto_rrs_.setHandler(handler); }
RestartRequestServer& getRestartRequestServer() { return proto_rrs_; }
/*
* Logging
/**
* Node logging.
* Logging calls are passed directly into the @ref Logger instance.
* Type safe log formatting is supported only in C++11 mode.
* @{
*/
#if UAVCAN_CPP_VERSION >= 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
+38 -2
View File
@@ -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 <typename DataType_>
class UAVCAN_EXPORT Publisher : protected GenericPublisher<DataType_, DataType_>
{
typedef GenericPublisher<DataType_, DataType_> 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<DataTypeKind(DataType::DataTypeKind) == DataTypeKindMessage>::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;
+17 -1
View File
@@ -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)
{
@@ -27,7 +27,10 @@ public:
typedef ServiceResponseTransferListener<DataTypeMaxByteLen> 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 <typename DataType>
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 <typename Stream, typename DataType>
static Stream& operator<<(Stream& s, const ServiceCallResult<DataType>& scr)
{
@@ -68,7 +78,9 @@ static Stream& operator<<(Stream& s, const ServiceCallResult<DataType>& 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 <typename DataType_,
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
typename Callback_ = std::function<void (const ServiceCallResult<DataType_>&)>
@@ -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)
@@ -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 <typename DataType_,
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
typename Callback_ = std::function<void (const ReceivedDataStructure<typename DataType_::Request>&,
@@ -92,6 +111,10 @@ public:
StaticAssert<DataTypeKind(DataType::DataTypeKind) == DataTypeKindService>::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_; }
};
+27 -1
View File
@@ -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<DataType_>&
* - const ReceivedDataStructure<DataType_>&
* 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 <typename DataType_,
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
typename Callback_ = std::function<void (const ReceivedDataStructure<DataType_>&)>,
@@ -70,6 +91,11 @@ public:
StaticAssert<DataTypeKind(DataType::DataTypeKind) == DataTypeKindMessage>::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();
+36 -4
View File
@@ -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 <typename Callback_>
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<std::function<void (const TimerEvent& event)> > Timer;
#endif
@@ -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<DataTypeInfoProvider*,
@@ -13,7 +13,15 @@
namespace uavcan
{
/**
* Please read the specs to learn how the time synchronization works.
*
* No more than one object of this class is allowed per node; otherwise a disaster is bound to happen.
*
* NOTE: In order for this class to work, the platform driver must implement
* CAN bus TX loopback with both UTC and monotonic timestamping.
*
* Ref. M. Gergeleit, H. Streich - "Implementing a Distributed High-Resolution Real-Time Clock using the CAN-Bus"
*
* TODO: Enforce max one master per node
*/
class UAVCAN_EXPORT GlobalTimeSyncMaster : protected LoopbackFrameListenerBase
@@ -57,10 +65,29 @@ public:
, initialized_(false)
{ }
/**
* Merely prepares the class to work, doesn't do anything else.
* Must be called before the master can be used.
* Returns negative error code.
*/
int init();
/**
* Whether the master instance has been initialized.
*/
bool isInitialized() const { return initialized_; }
/**
* Publishes one sync message.
*
* Every call to this method hints the master to publish the next sync message once. Exact time will
* be obtained from the TX loopback timestamp field.
*
* This method shall be called with a proper interval - refer to the time sync message definition
* for min/max interval values.
*
* Returns negative error code.
*/
int publish();
};
@@ -11,6 +11,14 @@
namespace uavcan
{
/**
* Please read the specs to learn how the time synchronization works.
*
* No more than one object of this class is allowed per node; otherwise a disaster is bound to happen.
*
* NOTE: In order for this class to work, the platform driver must implement:
* - CAN bus RX UTC timestamping;
* - Clock adjustment method in the system clock interface @ref ISystemClock::adjustUtc().
*
* Ref. M. Gergeleit, H. Streich - "Implementing a Distributed High-Resolution Real-Time Clock using the CAN-Bus"
* http://modecs.cs.uni-salzburg.at/results/related_documents/CAN_clock.pdf
*/
@@ -50,15 +58,47 @@ public:
, suppressed_(false)
{ }
/**
* Starts the time sync slave. Once started, it works on its own and does not require any
* attention from the application, other than to handle a clock adjustment request occasionally.
* Returns negative error code.
*/
int start();
/**
* Enable or disable the suppressed mode.
*
* In suppressed mode the slave will continue tracking time sync masters in the network, but will not
* perform local clock adjustments. So it's kind of a dry run - all the time sync logic works except
* the local clock will not receive adjustments.
*
* Suppressed mode is useful for nodes that can act as a back-up clock sync masters - as long as the
* node sees a higher priority time sync master in the network, its slave will be NOT suppressed
* in order to sync the local clock with the global master. As soon as all other higher priority
* masters go down, the local node will suppress its time sync slave instance and become a new master.
*
* Suppressed mode is disabled by default.
*/
void suppress(bool suppressed) { suppressed_ = suppressed; }
bool isSuppressed() const { return suppressed_; }
/**
* If the clock sync slave sees any clock sync masters in the network, it is ACTIVE.
* When the last master times out (PUBLISHER_TIMEOUT), the slave will be INACTIVE.
* Note that immediately after start up the slave will be INACTIVE until it finds a master.
* Please read the specs to learn more.
*/
bool isActive() const;
/**
* Node ID of the master the slave is currently locked on.
* Returns an invalid Node ID if there's no active master.
*/
NodeID getMasterNodeID() const;
/**
* Last time when the local clock adjustment was performed.
*/
MonotonicTime getLastAdjustmentTime() const { return last_adjustment_ts_; }
};
+77 -4
View File
@@ -15,7 +15,12 @@
namespace uavcan
{
/**
* External log sink interface.
* External log sink allows the application to install a hook on the logger output.
* This can be used for application-wide logging.
* Please refer to the @ref Logger class docs.
*/
class UAVCAN_EXPORT ILogSink
{
public:
@@ -24,22 +29,38 @@ public:
virtual ~ILogSink() { }
/**
* Logger will not sink messages with level lower than returned by this method.
* Logger will not sink messages with a severity level lower than returned by this method.
* Default level is DEBUG.
*/
virtual LogLevel getLogLevel() const { return protocol::debug::LogLevel::DEBUG; }
/**
* Logger will call this method for every log message with level not less than the current level of this sink.
* Logger will call this method for every log message which severity level
* is not less than the current level of this sink.
*/
virtual void log(const protocol::debug::LogMessage& message) = 0;
};
/**
* Node logging convenience class.
*
* This class is based on the standard UAVCAN message type for logging - uavcan.protocol.debug.LogMessage.
*
* Provides logging methods of different severity; implements two sinks for the log messages:
* - Broadcast via the UAVCAN bus;
* - Sink into the application via @ref ILogSink.
*
* For each sink an individual severity threshold filter can be configured.
*/
class UAVCAN_EXPORT Logger
{
public:
typedef ILogSink::LogLevel LogLevel;
/**
* This value is higher than any valid severity value.
* Use it to completely suppress the output.
*/
static const LogLevel LevelAboveAll = (1 << protocol::debug::LogLevel::FieldTypes::value::BitLen) - 1;
private:
@@ -62,19 +83,68 @@ public:
UAVCAN_ASSERT(getTxTimeout() == MonotonicDuration::fromMSec(DefaultTxTimeoutMs));
}
/**
* Initializes the logger, does not perform any network activity.
* Must be called once before use.
* Returns negative error code.
*/
int init();
/**
* Logs one message. Please consider using helper methods instead of this one.
*
* The message will be broadcasted via the UAVCAN bus if the severity level of the
* message is >= 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 <typename... Args>
@@ -129,6 +199,9 @@ public:
}
#endif
/**
* @}
*/
};
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
@@ -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);
};
@@ -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<protocol::NodeStatus>& 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;
};
@@ -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<NodeStatusProvider*, void (NodeStatusProvider::*)(const protocol::GlobalDiscoveryRequest&)>
@@ -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);
@@ -10,7 +10,9 @@
namespace uavcan
{
/**
* Helper for broadcasting the message uavcan.protocol.Panic.
*/
class UAVCAN_EXPORT PanicBroadcaster : private TimerBase
{
Publisher<protocol::Panic> 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;
@@ -22,11 +22,13 @@
namespace uavcan
{
/**
* Callback prototype:
* void (const ReceivedDataStructure<protocol::Panic>&)
* 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<protocol::Panic>&)
* 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();
@@ -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<ParamServer*, void (ParamServer::*)(const protocol::param::GetSet::Request&,
@@ -89,6 +95,10 @@ public:
, manager_(NULL)
{ }
/**
* Starts the parameter server with given param manager instance.
* Returns negative error code.
*/
int start(IParamManager* manager);
IParamManager* getParamManager() const { return manager_; }
@@ -10,15 +10,29 @@
namespace uavcan
{
/**
* Implement this interface in the application to support the standard node restart service.
*/
class UAVCAN_EXPORT IRestartRequestHandler
{
public:
virtual ~IRestartRequestHandler() { }
/**
* This method shall do either:
* - restart the local node immediately;
* - initiate the restart procedure to complete it asynchronously;
* - reject the restart request and return false.
*
* If the restart requets was accepted, this method shall either return true or don't return at all.
*/
virtual bool handleRestartRequest(NodeID request_source) = 0;
};
/**
* Convenience class for supporting the standard node restart service.
* Highly recommended to use.
*/
class UAVCAN_EXPORT RestartRequestServer : Noncopyable
{
typedef MethodBinder<const RestartRequestServer*,
@@ -37,9 +51,17 @@ public:
, handler_(NULL)
{ }
/**
* Restart request handler configuration.
* All restart requests will be explicitly rejected if there's no handler installed.
*/
IRestartRequestHandler* getHandler() const { return handler_; }
void setHandler(IRestartRequestHandler* handler) { handler_ = handler; }
/**
* Starts the server.
* Returns negative error code.
*/
int start();
};
@@ -10,7 +10,10 @@
namespace uavcan
{
/**
* This class provides statistics about the transport layer performance on the local node.
* The user's application does not deal with this class directly because it's instantiated by the node class.
*/
class UAVCAN_EXPORT TransportStatsProvider : Noncopyable
{
typedef MethodBinder<const TransportStatsProvider*,
@@ -28,6 +31,10 @@ public:
: srv_(node)
{ }
/**
* Once started, this class requires no further attention.
* Returns negative error code.
*/
int start();
};
+3
View File
@@ -31,6 +31,9 @@ typedef std::int64_t int64_t;
#else
/*
* C++03 doesn't define standard integer types, so we pull it from the C library as a workaround.
*/
# include <stdint.h>
namespace uavcan
+5 -5
View File
@@ -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<MonotonicTime, MonotonicDura
*/
class UAVCAN_EXPORT UtcDuration : public DurationBase<UtcDuration> { };
class UAVCAN_EXPORT UtcTime : public TimeBase<UtcTime, UtcDuration>
class UAVCAN_EXPORT UtcTime : public TimeBase<UtcTime, UtcDuration> /// Implicitly convertible to/from uavcan.Timestamp
{
public:
UtcTime() { }
@@ -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<LoopbackFrameListenerBase>, 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_;
@@ -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_; }
@@ -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:
@@ -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;
@@ -83,7 +83,7 @@ public:
};
/**
* Internal, refer to transport dispatcher.
* Internal, refer to the transport dispatcher class.
*/
class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListenerBase>, Noncopyable
{
@@ -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 <typename T>
class UAVCAN_EXPORT LazyConstructor
{
+11 -1
View File
@@ -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 <typename Predicate>
void insertBefore(T* node, Predicate predicate);
/**
* Complexity: O(N)
*/
void remove(const T* node);
};
+23 -2
View File
@@ -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 <typename Predicate>
void removeWhere(Predicate predicate);
/**
* Returns first entry where the predicate returns true.
* Predicate prototype:
* bool (const Key& key, const Value& value)
*/
template <typename Predicate>
const Key* findFirstKey(Predicate predicate) const;
@@ -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 <typename ObjectPtr, typename MemFunPtr>
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<bool>(obj_, true) && try_implicit_cast<bool>(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 <typename Par1>
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 <typename Par1, typename Par2>
void operator()(Par1& p1, Par2& p2)
{
@@ -7,6 +7,11 @@
#include <cstddef>
#include <uavcan/impl_constants.hpp>
/*
* 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
+24 -4
View File
@@ -63,14 +63,18 @@ struct UAVCAN_EXPORT EnableIf<true, T>
typedef T Type;
};
/**
* Lightweight type categorization.
*/
template <typename T, typename R = void>
struct UAVCAN_EXPORT EnableIfType
{
typedef R Type;
};
/**
* Compile-time type selection (Alexandrescu)
*/
template <bool Condition, typename TrueType, typename FalseType>
struct UAVCAN_EXPORT Select;
@@ -111,7 +115,11 @@ public:
enum { Result = sizeof(True_) == sizeof(IsImplicitlyConvertibleFromTo<T1, T2>::test(returner<T1>())) };
};
/**
* try_implicit_cast<>(From)
* try_implicit_cast<>(From, To)
* @{
*/
template <typename From, typename To>
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 <typename To, typename From>
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<IsImplicitlyConvertibleFromTo<From, To>::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 <typename To, typename From>
UAVCAN_EXPORT
To try_implicit_cast(const From& from)
@@ -134,9 +150,13 @@ To try_implicit_cast(const From& from)
return TryImplicitCastImpl<From, To>::impl(from, To(),
BooleanType<IsImplicitlyConvertibleFromTo<From, To>::Result>());
}
/**
* @}
*/
/**
* Some arithmetics
* Compile time square root for integers.
* Useful for operations on square matrices.
*/
template <unsigned Value> struct UAVCAN_EXPORT CompileTimeIntSqrt;
template <> struct UAVCAN_EXPORT CompileTimeIntSqrt<4> { enum { Result = 2 }; };