CAN HW filters are added using map container

This commit is contained in:
ilia-sheremet
2015-06-26 14:35:53 +02:00
parent bad7123b7d
commit 573b268457
43 changed files with 953 additions and 782 deletions
@@ -33,19 +33,11 @@ ${line}
#undef ${a.name} #undef ${a.name}
% endfor % endfor
#ifndef UAVCAN_PACK_STRUCTS
# error UAVCAN_PACK_STRUCTS
#endif
% for nsc in t.cpp_namespace_components: % for nsc in t.cpp_namespace_components:
namespace ${nsc} namespace ${nsc}
{ {
% endfor % endfor
#if UAVCAN_PACK_STRUCTS
UAVCAN_PACKED_BEGIN
#endif
% if t.kind != t.KIND_SERVICE: % if t.kind != t.KIND_SERVICE:
template <int _tmpl> template <int _tmpl>
% endif % endif
@@ -178,10 +170,6 @@ private:
% endif % endif
}; };
#if UAVCAN_PACK_STRUCTS
UAVCAN_PACKED_END
#endif
/* /*
* Out of line struct method definitions * Out of line struct method definitions
*/ */
+29 -15
View File
@@ -82,21 +82,6 @@
# endif # endif
#endif #endif
/**
* Struct layout control.
* 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
#endif
#ifndef UAVCAN_PACKED_BEGIN
# define UAVCAN_PACKED_BEGIN
#endif
#ifndef UAVCAN_PACKED_END
# define UAVCAN_PACKED_END
#endif
/** /**
* Declaration visibility * Declaration visibility
* http://gcc.gnu.org/wiki/Visibility * http://gcc.gnu.org/wiki/Visibility
@@ -228,6 +213,35 @@ static const unsigned FloatComparisonEpsilonMult = UAVCAN_FLOAT_COMPARISON_EPSIL
static const unsigned FloatComparisonEpsilonMult = 10; static const unsigned FloatComparisonEpsilonMult = 10;
#endif #endif
/**
* Maximum number of CAN acceptance filters available on the platform
*/
#ifdef UAVCAN_MAX_CAN_ACCEPTANCE_FILTERS
/// Explicitly specified by the user.
static const unsigned MaxCanAcceptanceFilters = UAVCAN_MAX_CAN_ACCEPTANCE_FILTERS;
#else
/// Default that should be OK for any platform.
static const unsigned MaxCanAcceptanceFilters = 32;
#endif
/**
* This constant defines how many receiver objects will be statically pre-allocated by classes that listen to messages
* of type uavcan.protocol.NodeStatus from other nodes. If the number of publishers exceeds this value, extra
* listeners will be allocated in the dynamic memory (one block per listener).
*
* The default value is safe to use in any application (since extra memory can always be retrieved from the pool).
* Applications that are extremely memory sensitive and are not expected to operate in large networks can override
* the default with a lower value.
*
* Note that nodes that aren't using classes that monitor the network (e.g. NodeStatusMonitor, dynamic node ID
* allocation servers) do not depend on this configuration parameter in any way.
*/
#ifdef UAVCAN_MAX_NETWORK_SIZE_HINT
static const unsigned MaxNetworkSizeHint = UAVCAN_MAX_NETWORK_SIZE_HINT;
#else
static const unsigned MaxNetworkSizeHint = 64; ///< Rest will go into the dynamic memory
#endif
} }
#endif // UAVCAN_BUILD_CONFIG_HPP_INCLUDED #endif // UAVCAN_BUILD_CONFIG_HPP_INCLUDED
+10 -10
View File
@@ -131,24 +131,24 @@ public:
*/ */
class UAVCAN_EXPORT DataTypeDescriptor class UAVCAN_EXPORT DataTypeDescriptor
{ {
DataTypeKind kind_;
DataTypeID id_;
DataTypeSignature signature_; DataTypeSignature signature_;
const char* full_name_; const char* full_name_;
DataTypeKind kind_;
DataTypeID id_;
public: public:
static const unsigned MaxFullNameLen = 80; static const unsigned MaxFullNameLen = 80;
DataTypeDescriptor() DataTypeDescriptor() :
: kind_(DataTypeKind(0)) full_name_(""),
, full_name_("") kind_(DataTypeKind(0))
{ } { }
DataTypeDescriptor(DataTypeKind kind, DataTypeID id, const DataTypeSignature& signature, const char* name) DataTypeDescriptor(DataTypeKind kind, DataTypeID id, const DataTypeSignature& signature, const char* name) :
: kind_(kind) signature_(signature),
, id_(id) full_name_(name),
, signature_(signature) kind_(kind),
, full_name_(name) id_(id)
{ {
UAVCAN_ASSERT(kind < NumDataTypeKinds); UAVCAN_ASSERT(kind < NumDataTypeKinds);
UAVCAN_ASSERT(name); UAVCAN_ASSERT(name);
+19 -16
View File
@@ -16,7 +16,6 @@ namespace uavcan
/** /**
* Raw CAN frame, as passed to/from the CAN driver. * Raw CAN frame, as passed to/from the CAN driver.
*/ */
UAVCAN_PACKED_BEGIN
struct UAVCAN_EXPORT CanFrame struct UAVCAN_EXPORT CanFrame
{ {
static const uint32_t MaskStdID = 0x000007FFU; static const uint32_t MaskStdID = 0x000007FFU;
@@ -31,16 +30,16 @@ struct UAVCAN_EXPORT CanFrame
uint8_t data[MaxDataLen]; uint8_t data[MaxDataLen];
uint8_t dlc; ///< Data Length Code uint8_t dlc; ///< Data Length Code
CanFrame() CanFrame() :
: id(0) id(0),
, dlc(0) dlc(0)
{ {
fill(data, data + MaxDataLen, uint8_t(0)); fill(data, data + MaxDataLen, uint8_t(0));
} }
CanFrame(uint32_t can_id, const uint8_t* can_data, uint8_t data_len) CanFrame(uint32_t can_id, const uint8_t* can_data, uint8_t data_len) :
: id(can_id) id(can_id),
, dlc((data_len > MaxDataLen) ? MaxDataLen : data_len) dlc((data_len > MaxDataLen) ? MaxDataLen : data_len)
{ {
UAVCAN_ASSERT(can_data != NULL); UAVCAN_ASSERT(can_data != NULL);
UAVCAN_ASSERT(data_len == dlc); UAVCAN_ASSERT(data_len == dlc);
@@ -63,7 +62,9 @@ struct UAVCAN_EXPORT CanFrame
StrTight, ///< Minimum string length (default) StrTight, ///< Minimum string length (default)
StrAligned ///< Fixed formatting for any frame StrAligned ///< Fixed formatting for any frame
}; };
std::string toString(StringRepresentation mode = StrTight) const; std::string toString(StringRepresentation mode = StrTight) const;
#endif #endif
/** /**
@@ -74,7 +75,6 @@ struct UAVCAN_EXPORT CanFrame
bool priorityHigherThan(const CanFrame& rhs) const; bool priorityHigherThan(const CanFrame& rhs) const;
bool priorityLowerThan(const CanFrame& rhs) const { return rhs.priorityHigherThan(*this); } bool priorityLowerThan(const CanFrame& rhs) const { return rhs.priorityHigherThan(*this); }
}; };
UAVCAN_PACKED_END
/** /**
* CAN hardware filter config struct. * CAN hardware filter config struct.
@@ -86,15 +86,14 @@ struct UAVCAN_EXPORT CanFilterConfig
uint32_t id; uint32_t id;
uint32_t mask; uint32_t mask;
//bool operator == (const CanFilterConfig&) const;
bool operator==(const CanFilterConfig& rhs) const bool operator==(const CanFilterConfig& rhs) const
{ {
return rhs.id == id && rhs.mask == mask; return rhs.id == id && rhs.mask == mask;
} }
CanFilterConfig() CanFilterConfig() :
: id(0) id(0),
, mask(0) mask(0)
{ } { }
}; };
@@ -107,9 +106,9 @@ struct UAVCAN_EXPORT CanSelectMasks
uint8_t read; uint8_t read;
uint8_t write; uint8_t write;
CanSelectMasks() CanSelectMasks() :
: read(0) read(0),
, write(0) write(0)
{ } { }
}; };
@@ -178,7 +177,11 @@ public:
* Returns an 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; virtual ICanIface* getIface(uint8_t iface_index) = 0;
virtual const ICanIface* getIface(uint8_t iface_index) const = 0;
virtual const ICanIface* getIface(uint8_t iface_index) const
{
return const_cast<ICanDriver*>(this)->getIface(iface_index);
}
/** /**
* Total number of available CAN interfaces. * Total number of available CAN interfaces.
+47 -179
View File
@@ -26,55 +26,13 @@ public:
virtual void* allocate(std::size_t size) = 0; virtual void* allocate(std::size_t size) = 0;
virtual void deallocate(const void* ptr) = 0; virtual void deallocate(const void* ptr) = 0;
virtual bool isInPool(const void* ptr) const = 0; virtual uint16_t getNumBlocks() const = 0;
virtual std::size_t getBlockSize() const = 0;
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
{
IPoolAllocator* pools_[MaxPools];
static int qsortComparePoolAllocators(const void* raw_a, const void* raw_b)
{
const IPoolAllocator* const a = *static_cast<const IPoolAllocator* const*>(raw_a);
const IPoolAllocator* const b = *static_cast<const IPoolAllocator* const*>(raw_b);
const std::size_t a_size = a ? a->getBlockSize() : NumericTraits<std::size_t>::max();
const std::size_t b_size = b ? b->getBlockSize() : NumericTraits<std::size_t>::max();
if (a_size != b_size)
{
return (a_size > b_size) ? 1 : -1;
}
return 0;
}
public:
PoolManager()
{
(void)std::memset(pools_, 0, sizeof(pools_));
}
bool addPool(IPoolAllocator* pool);
virtual void* allocate(std::size_t size);
virtual void deallocate(const void* ptr);
virtual bool isInPool(const void* ptr) const;
virtual std::size_t getBlockSize() const;
virtual std::size_t getNumBlocks() const;
}; };
/** /**
* Classic implementation of a pool allocator (Meyers). * Classic implementation of a pool allocator (Meyers).
*/ */
template <std::size_t PoolSize, std::size_t BlockSize> template <std::size_t PoolSize, uint8_t BlockSize>
class UAVCAN_EXPORT PoolAllocator : public IPoolAllocator, Noncopyable class UAVCAN_EXPORT PoolAllocator : public IPoolAllocator, Noncopyable
{ {
union Node union Node
@@ -92,21 +50,29 @@ class UAVCAN_EXPORT PoolAllocator : public IPoolAllocator, Noncopyable
Node _aligner3; Node _aligner3;
} pool_; } pool_;
uint16_t used_;
uint16_t max_used_;
public: public:
static const unsigned NumBlocks = unsigned(PoolSize / BlockSize); static const uint16_t NumBlocks = PoolSize / BlockSize;
PoolAllocator(); PoolAllocator();
virtual void* allocate(std::size_t size); virtual void* allocate(std::size_t size);
virtual void deallocate(const void* ptr); virtual void deallocate(const void* ptr);
virtual bool isInPool(const void* ptr) const; virtual uint16_t getNumBlocks() const { return NumBlocks; }
virtual std::size_t getBlockSize() const { return BlockSize; } /**
virtual std::size_t getNumBlocks() const { return NumBlocks; } * Return the number of blocks that are currently allocated/unallocated.
*/
uint16_t getNumUsedBlocks() const { return used_; }
uint16_t getNumFreeBlocks() const { return static_cast<uint16_t>(NumBlocks - used_); }
unsigned getNumFreeBlocks() const; /**
unsigned getNumUsedBlocks() const { return NumBlocks - getNumFreeBlocks(); } * Returns the maximum number of blocks that were ever allocated at the same time.
*/
uint16_t getPeakNumUsedBlocks() const { return max_used_; }
}; };
/** /**
@@ -115,13 +81,13 @@ public:
class LimitedPoolAllocator : public IPoolAllocator class LimitedPoolAllocator : public IPoolAllocator
{ {
IPoolAllocator& allocator_; IPoolAllocator& allocator_;
const std::size_t max_blocks_; const uint16_t max_blocks_;
std::size_t used_blocks_; uint16_t used_blocks_;
public: public:
LimitedPoolAllocator(IPoolAllocator& allocator, std::size_t max_blocks) LimitedPoolAllocator(IPoolAllocator& allocator, std::size_t max_blocks)
: allocator_(allocator) : allocator_(allocator)
, max_blocks_(max_blocks) , max_blocks_(static_cast<uint16_t>(min<std::size_t>(max_blocks, 0xFFFFU)))
, used_blocks_(0) , used_blocks_(0)
{ {
UAVCAN_ASSERT(max_blocks_ > 0); UAVCAN_ASSERT(max_blocks_ > 0);
@@ -130,118 +96,26 @@ public:
virtual void* allocate(std::size_t size); virtual void* allocate(std::size_t size);
virtual void deallocate(const void* ptr); virtual void deallocate(const void* ptr);
virtual bool isInPool(const void* ptr) const; virtual uint16_t getNumBlocks() const;
virtual std::size_t getBlockSize() const;
virtual std::size_t getNumBlocks() const;
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/*
* PoolManager<>
*/
template <unsigned MaxPools>
bool PoolManager<MaxPools>::addPool(IPoolAllocator* pool)
{
UAVCAN_ASSERT(pool);
bool retval = false;
for (unsigned i = 0; i < MaxPools; i++)
{
UAVCAN_ASSERT(pools_[i] != pool);
if (pools_[i] == NULL || pools_[i] == pool)
{
pools_[i] = pool;
retval = true;
break;
}
}
// We need to keep the pools in order, so that smallest blocks go first
qsort(pools_, MaxPools, sizeof(IPoolAllocator*), &PoolManager::qsortComparePoolAllocators);
return retval;
}
template <unsigned MaxPools>
void* PoolManager<MaxPools>::allocate(std::size_t size)
{
for (unsigned i = 0; i < MaxPools; i++)
{
if (pools_[i] == NULL)
{
break;
}
void* const pmem = pools_[i]->allocate(size);
if (pmem != NULL)
{
return pmem;
}
}
return NULL;
}
template <unsigned MaxPools>
void PoolManager<MaxPools>::deallocate(const void* ptr)
{
for (unsigned i = 0; i < MaxPools; i++)
{
if (pools_[i] == NULL)
{
UAVCAN_ASSERT(0);
break;
}
if (pools_[i]->isInPool(ptr))
{
pools_[i]->deallocate(ptr);
break;
}
}
}
template <unsigned MaxPools>
bool PoolManager<MaxPools>::isInPool(const void* ptr) const
{
for (unsigned i = 0; i < MaxPools; i++)
{
if (pools_[i] == NULL)
{
break;
}
if (pools_[i]->isInPool(ptr))
{
return true;
}
}
return false;
}
template <unsigned MaxPools>
std::size_t PoolManager<MaxPools>::getBlockSize() const
{
return 0;
}
template <unsigned MaxPools>
std::size_t PoolManager<MaxPools>::getNumBlocks() const
{
std::size_t ret = 0;
for (unsigned i = 0; i < MaxPools; i++)
{
if (pools_[i] == NULL)
{
break;
}
ret += pools_[i]->getNumBlocks();
}
return ret;
}
/* /*
* PoolAllocator<> * PoolAllocator<>
*/ */
template <std::size_t PoolSize, std::size_t BlockSize> template <std::size_t PoolSize, uint8_t BlockSize>
PoolAllocator<PoolSize, BlockSize>::PoolAllocator() const uint16_t PoolAllocator<PoolSize, BlockSize>::NumBlocks;
: free_list_(reinterpret_cast<Node*>(pool_.bytes))
template <std::size_t PoolSize, uint8_t BlockSize>
PoolAllocator<PoolSize, BlockSize>::PoolAllocator() :
free_list_(reinterpret_cast<Node*>(pool_.bytes)),
used_(0),
max_used_(0)
{ {
// The limit is imposed by the width of the pool usage tracking variables.
StaticAssert<((PoolSize / BlockSize) <= 0xFFFFU)>::check();
(void)std::memset(pool_.bytes, 0, PoolSize); (void)std::memset(pool_.bytes, 0, PoolSize);
for (unsigned i = 0; (i + 1) < (NumBlocks - 1 + 1); i++) // -Werror=type-limits for (unsigned i = 0; (i + 1) < (NumBlocks - 1 + 1); i++) // -Werror=type-limits
{ {
@@ -251,49 +125,43 @@ PoolAllocator<PoolSize, BlockSize>::PoolAllocator()
free_list_[NumBlocks - 1].next = NULL; free_list_[NumBlocks - 1].next = NULL;
} }
template <std::size_t PoolSize, std::size_t BlockSize> template <std::size_t PoolSize, uint8_t BlockSize>
void* PoolAllocator<PoolSize, BlockSize>::allocate(std::size_t size) void* PoolAllocator<PoolSize, BlockSize>::allocate(std::size_t size)
{ {
if (free_list_ == NULL || size > BlockSize) if (free_list_ == NULL || size > BlockSize)
{ {
return NULL; return NULL;
} }
void* pmem = free_list_; void* pmem = free_list_;
free_list_ = free_list_->next; free_list_ = free_list_->next;
// Statistics
UAVCAN_ASSERT(used_ < NumBlocks);
used_++;
if (used_ > max_used_)
{
max_used_ = used_;
}
return pmem; return pmem;
} }
template <std::size_t PoolSize, std::size_t BlockSize> template <std::size_t PoolSize, uint8_t BlockSize>
void PoolAllocator<PoolSize, BlockSize>::deallocate(const void* ptr) void PoolAllocator<PoolSize, BlockSize>::deallocate(const void* ptr)
{ {
if (ptr == NULL) if (ptr == NULL)
{ {
return; return;
} }
Node* p = static_cast<Node*>(const_cast<void*>(ptr)); Node* p = static_cast<Node*>(const_cast<void*>(ptr));
p->next = free_list_; p->next = free_list_;
free_list_ = p; free_list_ = p;
}
template <std::size_t PoolSize, std::size_t BlockSize> // Statistics
bool PoolAllocator<PoolSize, BlockSize>::isInPool(const void* ptr) const UAVCAN_ASSERT(used_ > 0);
{ used_--;
return ptr >= pool_.bytes &&
ptr < (pool_.bytes + PoolSize);
}
template <std::size_t PoolSize, std::size_t BlockSize>
unsigned PoolAllocator<PoolSize, BlockSize>::getNumFreeBlocks() const
{
unsigned num = 0;
Node* p = free_list_;
while (p)
{
num++;
UAVCAN_ASSERT(num <= NumBlocks);
p = p->next;
}
return num;
} }
} }
@@ -42,12 +42,12 @@ class Server : IAllocationRequestHandler
*/ */
bool isNodeIDTaken(const NodeID node_id) const bool isNodeIDTaken(const NodeID node_id) const
{ {
return storage_.findByNodeID(node_id) != NULL; return storage_.isNodeIDOccupied(node_id);
} }
void tryPublishAllocationResult(const Storage::Entry& entry) void tryPublishAllocationResult(const NodeID node_id, const UniqueID& unique_id)
{ {
const int res = allocation_request_manager_.broadcastAllocationResponse(entry.unique_id, entry.node_id); const int res = allocation_request_manager_.broadcastAllocationResponse(unique_id, node_id);
if (res < 0) if (res < 0)
{ {
tracer_.onEvent(TraceError, res); tracer_.onEvent(TraceError, res);
@@ -65,10 +65,10 @@ class Server : IAllocationRequestHandler
virtual void handleAllocationRequest(const UniqueID& unique_id, const NodeID preferred_node_id) virtual void handleAllocationRequest(const UniqueID& unique_id, const NodeID preferred_node_id)
{ {
const Storage::Entry* const e = storage_.findByUniqueID(unique_id); const NodeID existing_node_id = storage_.getNodeIDForUniqueID(unique_id);
if (e != NULL) if (existing_node_id.isValid())
{ {
tryPublishAllocationResult(*e); tryPublishAllocationResult(existing_node_id, unique_id);
} }
else else
{ {
@@ -80,7 +80,7 @@ class Server : IAllocationRequestHandler
const int res = storage_.add(allocated_node_id, unique_id); const int res = storage_.add(allocated_node_id, unique_id);
if (res >= 0) if (res >= 0)
{ {
tryPublishAllocationResult(Storage::Entry(allocated_node_id, unique_id)); tryPublishAllocationResult(allocated_node_id, unique_id);
} }
else else
{ {
@@ -105,12 +105,12 @@ class Server : IAllocationRequestHandler
virtual NodeAwareness checkNodeAwareness(NodeID node_id) const virtual NodeAwareness checkNodeAwareness(NodeID node_id) const
{ {
return (storage_.findByNodeID(node_id) == NULL) ? NodeAwarenessUnknown : NodeAwarenessKnownAndCommitted; return storage_.isNodeIDOccupied(node_id) ? NodeAwarenessKnownAndCommitted : NodeAwarenessUnknown;
} }
virtual void handleNewNodeDiscovery(const UniqueID* unique_id_or_null, NodeID node_id) virtual void handleNewNodeDiscovery(const UniqueID* unique_id_or_null, NodeID node_id)
{ {
if (storage_.findByNodeID(node_id) != NULL) if (storage_.isNodeIDOccupied(node_id))
{ {
UAVCAN_ASSERT(0); // Such node is already known, the class that called this method should have known that UAVCAN_ASSERT(0); // Such node is already known, the class that called this method should have known that
return; return;
@@ -152,25 +152,15 @@ public:
own_unique_id_ = own_unique_id; own_unique_id_ = own_unique_id;
{ {
const Storage::Entry* e = storage_.findByNodeID(node_.getNodeID()); const NodeID stored_own_node_id = storage_.getNodeIDForUniqueID(own_unique_id_);
if (e != NULL) if (stored_own_node_id.isValid())
{ {
if (e->unique_id != own_unique_id_) if (stored_own_node_id != node_.getNodeID())
{ {
return -ErrInvalidConfiguration; return -ErrInvalidConfiguration;
} }
} }
else
e = storage_.findByUniqueID(own_unique_id_);
if (e != NULL)
{
if (e->node_id != node_.getNodeID())
{
return -ErrInvalidConfiguration;
}
}
if (e == NULL)
{ {
res = storage_.add(node_.getNodeID(), own_unique_id_); res = storage_.add(node_.getNodeID(), own_unique_id_);
if (res < 0) if (res < 0)
@@ -198,7 +188,7 @@ public:
return 0; return 0;
} }
Storage::Size getNumAllocations() const { return storage_.getSize(); } uint8_t getNumAllocations() const { return storage_.getSize(); }
}; };
} }
@@ -9,6 +9,7 @@
#include <uavcan/debug.hpp> #include <uavcan/debug.hpp>
#include <uavcan/protocol/dynamic_node_id_server/storage_marshaller.hpp> #include <uavcan/protocol/dynamic_node_id_server/storage_marshaller.hpp>
#include <uavcan/protocol/dynamic_node_id_server/event.hpp> #include <uavcan/protocol/dynamic_node_id_server/event.hpp>
#include <uavcan/util/bitset.hpp>
namespace uavcan namespace uavcan
{ {
@@ -22,148 +23,59 @@ namespace centralized
*/ */
class Storage class Storage
{ {
public: typedef BitSet<NodeID::Max + 1> OccupationMask;
typedef uint8_t Size; typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeStatic,
BitLenToByteLen<NodeID::Max + 1>::Result>
OccupationMaskArray;
enum { Capacity = NodeID::Max };
struct Entry
{
UniqueID unique_id;
NodeID node_id;
Entry() { }
Entry(const NodeID nid, const UniqueID& uid)
: unique_id(uid)
, node_id(nid)
{ }
bool operator==(const Entry& rhs) const
{
return unique_id == rhs.unique_id &&
node_id == rhs.node_id;
}
};
private:
IStorageBackend& storage_; IStorageBackend& storage_;
Entry entries_[Capacity]; OccupationMask occupation_mask_;
Size size_;
static IStorageBackend::String getSizeKey() { return "size"; } static IStorageBackend::String getOccupationMaskKey() { return "occupation_mask"; }
static IStorageBackend::String makeEntryKey(Size index, const char* postfix) static OccupationMask maskFromArray(const OccupationMaskArray& array)
{ {
IStorageBackend::String str; OccupationMask mask;
// "0_foobar" for (uint8_t byte = 0; byte < array.size(); byte++)
str.appendFormatted("%d", int(index)); {
str += "_"; for (uint8_t bit = 0; bit < 8; bit++)
str += postfix; {
return str; mask[byte * 8U + bit] = (array[byte] & (1U << bit)) != 0;
}
}
return mask;
} }
int readEntryFromStorage(Size index, Entry& out_entry) static OccupationMaskArray maskToArray(const OccupationMask& mask)
{ {
const StorageMarshaller io(storage_); OccupationMaskArray array;
for (uint8_t byte = 0; byte < array.size(); byte++)
// Unique ID
if (io.get(makeEntryKey(index, "unique_id"), out_entry.unique_id) < 0)
{ {
return -ErrFailure; for (uint8_t bit = 0; bit < 8; bit++)
{
if (mask[byte * 8U + bit])
{
array[byte] |= static_cast<uint8_t>(1U << bit);
}
}
} }
return array;
// Node ID
uint32_t node_id = 0;
if (io.get(makeEntryKey(index, "node_id"), node_id) < 0)
{
return -ErrFailure;
}
if (node_id > NodeID::Max || node_id == 0)
{
return -ErrFailure;
}
out_entry.node_id = NodeID(static_cast<uint8_t>(node_id));
return 0;
}
int writeEntryToStorage(Size index, const Entry& entry)
{
Entry temp = entry;
StorageMarshaller io(storage_);
// Unique ID
if (io.setAndGetBack(makeEntryKey(index, "unique_id"), temp.unique_id) < 0)
{
return -ErrFailure;
}
// Node ID
uint32_t node_id = entry.node_id.get();
if (io.setAndGetBack(makeEntryKey(index, "node_id"), node_id) < 0)
{
return -ErrFailure;
}
temp.node_id = NodeID(static_cast<uint8_t>(node_id));
return (temp == entry) ? 0 : -ErrFailure;
} }
public: public:
Storage(IStorageBackend& storage) Storage(IStorageBackend& storage) :
: storage_(storage) storage_(storage)
, size_(0)
{ } { }
/** /**
* This method reads all entries from the storage. * This method reads only the occupation mask from the storage.
*/ */
int init() int init()
{ {
StorageMarshaller io(storage_); StorageMarshaller io(storage_);
OccupationMaskArray array;
// Reading size io.get(getOccupationMaskKey(), array);
size_ = 0; occupation_mask_ = maskFromArray(array);
{
uint32_t value = 0;
if (io.get(getSizeKey(), value) < 0)
{
if (storage_.get(getSizeKey()).empty())
{
int res = io.setAndGetBack(getSizeKey(), value);
if (res < 0)
{
return res;
}
return (value == 0) ? 0 : -ErrFailure;
}
else
{
// There's some data in the storage, but it cannot be parsed - reporting an error
return -ErrFailure;
}
}
if (value > Capacity)
{
return -ErrFailure;
}
size_ = Size(value);
}
// Restoring entries
for (Size index = 0; index < size_; index++)
{
const int result = readEntryFromStorage(index, entries_[index]);
if (result < 0)
{
return result;
}
}
return 0; return 0;
} }
@@ -173,77 +85,62 @@ public:
*/ */
int add(const NodeID node_id, const UniqueID& unique_id) int add(const NodeID node_id, const UniqueID& unique_id)
{ {
if (size_ == Capacity)
{
return -ErrLogic;
}
if (!node_id.isUnicast()) if (!node_id.isUnicast())
{ {
return -ErrInvalidParam; return -ErrInvalidParam;
} }
Entry entry; StorageMarshaller io(storage_);
entry.node_id = node_id;
entry.unique_id = unique_id;
// If next operations fail, we'll get a dangling entry, but it's absolutely OK. // If next operations fail, we'll get a dangling entry, but it's absolutely OK.
int res = writeEntryToStorage(size_, entry);
if (res < 0)
{ {
return res; uint32_t node_id_int = node_id.get();
int res = io.setAndGetBack(StorageMarshaller::convertUniqueIDToHex(unique_id), node_id_int);
if (res < 0)
{
return res;
}
if (node_id_int != node_id.get())
{
return -ErrFailure;
}
} }
// Updating the size // Updating the mask in the storage
StorageMarshaller io(storage_); OccupationMask new_occupation_mask = occupation_mask_;
uint32_t new_size_index = size_ + 1U; new_occupation_mask[node_id.get()] = true;
res = io.setAndGetBack(getSizeKey(), new_size_index); OccupationMaskArray occupation_array = maskToArray(new_occupation_mask);
int res = io.setAndGetBack(getOccupationMaskKey(), occupation_array);
if (res < 0) if (res < 0)
{ {
return res; return res;
} }
if (new_size_index != size_ + 1U) if (occupation_array != maskToArray(new_occupation_mask))
{ {
return -ErrFailure; return -ErrFailure;
} }
entries_[size_] = entry; // Updating the cached mask only if the storage was updated successfully
size_++; occupation_mask_ = new_occupation_mask;
return 0; return 0;
} }
/** /**
* Returns nullptr if there's no such entry. * Returns an invalid node ID if there's no such allocation.
*/ */
const Entry* findByNodeID(const NodeID node_id) const NodeID getNodeIDForUniqueID(const UniqueID& unique_id) const
{ {
for (Size i = 0; i < size_; i++) StorageMarshaller io(storage_);
{ uint32_t node_id = 0;
if (entries_[i].node_id == node_id) io.get(StorageMarshaller::convertUniqueIDToHex(unique_id), node_id);
{ return (node_id > 0 && node_id <= NodeID::Max) ? NodeID(static_cast<uint8_t>(node_id)) : NodeID();
return &entries_[i];
}
}
return NULL;
} }
/** bool isNodeIDOccupied(NodeID node_id) const { return occupation_mask_[node_id.get()]; }
* Returns nullptr if there's no such entry.
*/
const Entry* findByUniqueID(const UniqueID& unique_id) const
{
for (Size i = 0; i < size_; i++)
{
if (entries_[i].unique_id == unique_id)
{
return &entries_[i];
}
}
return NULL;
}
Size getSize() const { return size_; } uint8_t getSize() const { return static_cast<uint8_t>(occupation_mask_.count()); }
}; };
} }
@@ -94,8 +94,6 @@ class NodeDiscoverer : TimerBase
enum { TimerPollIntervalMs = 170 }; // ~ ceil(500 ms service timeout / 3) enum { TimerPollIntervalMs = 170 }; // ~ ceil(500 ms service timeout / 3)
enum { NumNodeStatusStaticReceivers = 64 };
/* /*
* States * States
*/ */
@@ -106,7 +104,7 @@ class NodeDiscoverer : TimerBase
NodeMap node_map_; ///< Will not work in UAVCAN_TINY NodeMap node_map_; ///< Will not work in UAVCAN_TINY
ServiceClient<protocol::GetNodeInfo, GetNodeInfoResponseCallback> get_node_info_client_; ServiceClient<protocol::GetNodeInfo, GetNodeInfoResponseCallback> get_node_info_client_;
Subscriber<protocol::NodeStatus, NodeStatusCallback, NumNodeStatusStaticReceivers, 0> node_status_sub_; Subscriber<protocol::NodeStatus, NodeStatusCallback, MaxNetworkSizeHint, 0> node_status_sub_;
/* /*
* Methods * Methods
@@ -38,6 +38,20 @@ public:
: storage_(storage) : storage_(storage)
{ } { }
/**
* Turns a unique ID into a hex string that can be used as a key or as a value.
*/
static IStorageBackend::String convertUniqueIDToHex(const UniqueID& key)
{
IStorageBackend::String serialized;
for (uint8_t i = 0; i < UniqueID::MaxSize; i++)
{
serialized.appendFormatted("%02x", key.at(i));
}
UAVCAN_ASSERT(serialized.size() == UniqueID::MaxSize * 2);
return serialized;
}
/** /**
* These methods set the value and then immediately read it back. * These methods set the value and then immediately read it back.
* 1. Serialize the value. * 1. Serialize the value.
@@ -58,12 +72,7 @@ public:
int setAndGetBack(const IStorageBackend::String& key, UniqueID& inout_value) int setAndGetBack(const IStorageBackend::String& key, UniqueID& inout_value)
{ {
IStorageBackend::String serialized; const IStorageBackend::String serialized = convertUniqueIDToHex(inout_value);
for (uint8_t i = 0; i < UniqueID::MaxSize; i++)
{
serialized.appendFormatted("%02x", inout_value.at(i));
}
UAVCAN_ASSERT(serialized.size() == UniqueID::MaxSize * 2);
UAVCAN_TRACE("StorageMarshaller", "Set %s = %s", key.c_str(), serialized.c_str()); UAVCAN_TRACE("StorageMarshaller", "Set %s = %s", key.c_str(), serialized.c_str());
storage_.set(key, serialized); storage_.set(key, serialized);
@@ -365,6 +365,22 @@ public:
return 0; return 0;
} }
/**
* This method forces the class to re-request uavcan.protocol.GetNodeInfo from all nodes as if they
* have just appeared in the network.
*/
void invalidateAll()
{
NodeStatusMonitor::forgetAllNodes();
get_node_info_client_.cancelAllCalls();
for (unsigned i = 0; i < (sizeof(entries_) / sizeof(entries_[0])); i++)
{
entries_[i] = Entry();
}
// It is not necessary to reset the last picked node index
}
/** /**
* Adds one listener. Does nothing if such listener already exists. * Adds one listener. Does nothing if such listener already exists.
* May return -ErrMemory if there's no space to add the listener. * May return -ErrMemory if there's no space to add the listener.
@@ -51,12 +51,7 @@ private:
typedef MethodBinder<NodeStatusMonitor*, void (NodeStatusMonitor::*)(const TimerEvent&)> TimerCallback; typedef MethodBinder<NodeStatusMonitor*, void (NodeStatusMonitor::*)(const TimerEvent&)> TimerCallback;
/* Subscriber<protocol::NodeStatus, NodeStatusCallback, MaxNetworkSizeHint, 0> sub_;
* We'll be able to handle this many nodes in the network without any dynamic memory.
*/
enum { NumStaticReceivers = 64 };
Subscriber<protocol::NodeStatus, NodeStatusCallback, NumStaticReceivers, 0> sub_;
TimerEventForwarder<TimerCallback> timer_; TimerEventForwarder<TimerCallback> timer_;
@@ -200,6 +195,17 @@ public:
} }
} }
/**
* Make all nodes unknown.
*/
void forgetAllNodes()
{
for (unsigned i = 0; i < (sizeof(entries_) / sizeof(entries_[0])); i++)
{
entries_[i] = Entry();
}
}
/** /**
* Returns status of a given node. * Returns status of a given node.
* Unknown nodes are considered offline. * Unknown nodes are considered offline.
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>,
* Ilia Sheremet <illia.sheremet@gmail.com>
*/
#ifndef UAVCAN_ACCEPTANCE_FILTER_CONFIGURATOR_HPP_INCLUDED
#define UAVCAN_ACCEPTANCE_FILTER_CONFIGURATOR_HPP_INCLUDED
#include <cassert>
#include <uavcan/data_type.hpp>
#include <uavcan/error.hpp>
#include <uavcan/transport/dispatcher.hpp>
#include <uavcan/node/abstract_node.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/util/multiset.hpp>
namespace uavcan
{
/**
* This class configures hardware acceptance filters (if this feature is present on the particular CAN driver) to
* preclude reception of irrelevant CAN frames on the hardware level.
*
* Configuration starts by creating an object of class @ref CanAcceptanceFilterConfigurator on the stack.
* Through the method configureFilters() it determines the number of available HW filters and the number
* of listeners. In case the number of listeners is higher than the number of available HW filters, the function
* automatically merges configs in the most efficient way until their number is reduced to the number of
* available HW filters. Subsequently obtained configurations are then loaded into the CAN driver.
*
* The maximum number of CAN acceptance filters is predefined in uavcan/build_config.hpp through a constant
* @ref MaxCanAcceptanceFilters. The algorithm doesn't allow to have higher number of HW filters configurations than
* defined by MaxCanAcceptanceFilters. You can change this value according to the number specified in your CAN driver
* datasheet.
*/
class CanAcceptanceFilterConfigurator
{
/**
* Below constants based on UAVCAN transport layer specification. Masks and ID's depends on message Priority,
* TypeID, TransferID (RequestNotResponse - for service types, BroadcastNotUnicast - for message types).
* For more details refer to uavcan.org/CAN_bus_transport_layer_specification.
* For clarity let's represent "i" as Data Type ID
* DefaultFilterMsgMask = 00111111111110000000000000000
* DefaultFilterMsgID = 00iiiiiiiiiii0000000000000000, no need to explicitly define, since MsgID initialized as 0.
* DefaultFilterServiceRequestMask = 11111111111100000000000000000
* DefaultFilterServiceRequestID = 101iiiiiiiii00000000000000000
* ServiceRespFrameMask = 11100000000000000000000000000
* ServiceRespFrameID = 10000000000000000000000000000, all Service Response Frames are accepted by HW filters.
*/
static const unsigned DefaultFilterMsgMask = 0x7FF0000;
static const unsigned DefaultFilterServiceRequestID = 0x14000000;
static const unsigned DefaultFilterServiceRequestMask = 0x1FFE0000;
static const unsigned ServiceRespFrameID = 0x10000000;
static const unsigned ServiceRespFrameMask = 0x1C000000;
typedef uavcan::Multiset<CanFilterConfig, 1> MultisetConfigContainer;
static CanFilterConfig mergeFilters(CanFilterConfig &a_, CanFilterConfig &b_);
static uint8_t countBits(uint32_t n_);
uint16_t getNumFilters() const;
/**
* Fills the multiset_configs_ to proceed it with computeConfiguration()
*/
int16_t loadInputConfiguration();
/**
* This method merges several listeners's filter configurations by predetermined algorithm
* if number of available hardware acceptance filters less than number of listeners
*/
int16_t computeConfiguration();
/**
* This method loads the configuration computed with computeConfiguration() to the CAN driver.
*/
int16_t applyConfiguration();
INode& node_; //< Node reference is needed for access to ICanDriver and Dispatcher
MultisetConfigContainer multiset_configs_;
public:
explicit CanAcceptanceFilterConfigurator(INode& node)
: node_(node)
, multiset_configs_(node.getAllocator())
{ }
/**
* This method invokes loadInputConfiguration(), computeConfiguration() and applyConfiguration() consequently, so that
* optimal acceptance filter configuration will be computed and loaded through CanDriver::configureFilters()
* @return 0 = success, negative for error.
*/
int configureFilters();
/**
* Returns the configuration computed with computeConfiguration().
* If computeConfiguration() has not been called yet, an empty configuration will be returned.
*/
const MultisetConfigContainer& getConfiguration() const
{
return multiset_configs_;
}
};
}
#endif // UAVCAN_BUILD_CONFIG_HPP_INCLUDED
@@ -16,7 +16,6 @@
namespace uavcan namespace uavcan
{ {
UAVCAN_PACKED_BEGIN
class UAVCAN_EXPORT OutgoingTransferRegistryKey class UAVCAN_EXPORT OutgoingTransferRegistryKey
{ {
DataTypeID data_type_id_; DataTypeID data_type_id_;
@@ -56,7 +55,6 @@ public:
std::string toString() const; std::string toString() const;
#endif #endif
}; };
UAVCAN_PACKED_END
/** /**
* Outgoing transfer registry keeps track of Transfer ID values for all currently existing local transfer senders. * Outgoing transfer registry keeps track of Transfer ID values for all currently existing local transfer senders.
@@ -76,13 +74,11 @@ public:
template <int NumStaticEntries> template <int NumStaticEntries>
class UAVCAN_EXPORT OutgoingTransferRegistry : public IOutgoingTransferRegistry, Noncopyable class UAVCAN_EXPORT OutgoingTransferRegistry : public IOutgoingTransferRegistry, Noncopyable
{ {
UAVCAN_PACKED_BEGIN
struct Value struct Value
{ {
MonotonicTime deadline; MonotonicTime deadline;
TransferID tid; TransferID tid;
}; };
UAVCAN_PACKED_END
class DeadlineExpiredPredicate class DeadlineExpiredPredicate
{ {
@@ -16,7 +16,6 @@
namespace uavcan namespace uavcan
{ {
UAVCAN_PACKED_BEGIN
/** /**
* Internal for TransferBufferManager * Internal for TransferBufferManager
*/ */
@@ -136,7 +135,6 @@ public:
virtual int read(unsigned offset, uint8_t* data, unsigned len) const; virtual int read(unsigned offset, uint8_t* data, unsigned len) const;
virtual int write(unsigned offset, const uint8_t* data, unsigned len); virtual int write(unsigned offset, const uint8_t* data, unsigned len);
}; };
UAVCAN_PACKED_END
/** /**
* Standalone static buffer * Standalone static buffer
@@ -13,37 +13,46 @@
namespace uavcan namespace uavcan
{ {
UAVCAN_PACKED_BEGIN
class UAVCAN_EXPORT TransferReceiver class UAVCAN_EXPORT TransferReceiver
{ {
public: public:
enum ResultCode { ResultNotComplete, ResultComplete, ResultSingleFrame }; enum ResultCode { ResultNotComplete, ResultComplete, ResultSingleFrame };
static const uint32_t MinTransferIntervalUSec = 1 * 1000UL; static const uint16_t MinTransferIntervalMSec = 1;
static const uint32_t MaxTransferIntervalUSec = 10 * 1000 * 1000UL; static const uint16_t MaxTransferIntervalMSec = 0xFFFF;
static const uint32_t DefaultTransferIntervalUSec = 1 * 1000 * 1000UL; static const uint16_t DefaultTransferIntervalMSec = 1000;
static MonotonicDuration getDefaultTransferInterval() static MonotonicDuration getDefaultTransferInterval()
{ {
return MonotonicDuration::fromUSec(DefaultTransferIntervalUSec); return MonotonicDuration::fromMSec(DefaultTransferIntervalMSec);
} }
static MonotonicDuration getMinTransferInterval() { return MonotonicDuration::fromUSec(MinTransferIntervalUSec); } static MonotonicDuration getMinTransferInterval() { return MonotonicDuration::fromMSec(MinTransferIntervalMSec); }
static MonotonicDuration getMaxTransferInterval() { return MonotonicDuration::fromUSec(MaxTransferIntervalUSec); } static MonotonicDuration getMaxTransferInterval() { return MonotonicDuration::fromMSec(MaxTransferIntervalMSec); }
private: private:
enum TidRelation { TidSame, TidRepeat, TidFuture }; enum TidRelation { TidSame, TidRepeat, TidFuture };
static const uint8_t IfaceIndexNotSet = 0xFF;
enum { IfaceIndexNotSet = MaxCanIfaces };
enum { BufferWritePosMask = 4095 };
enum { ErrorCntMask = 15 };
enum { IfaceIndexMask = MaxCanIfaces };
MonotonicTime prev_transfer_ts_; MonotonicTime prev_transfer_ts_;
MonotonicTime this_transfer_ts_; MonotonicTime this_transfer_ts_;
UtcTime first_frame_ts_; UtcTime first_frame_ts_;
uint32_t transfer_interval_usec_; uint16_t transfer_interval_msec_;
uint16_t this_transfer_crc_; uint16_t this_transfer_crc_;
uint16_t buffer_write_pos_;
TransferID tid_; // 2 byte aligned bitfields:
uint8_t iface_index_; uint16_t buffer_write_pos_ : 12;
uint8_t next_frame_index_; mutable uint16_t error_cnt_ : 4;
mutable uint8_t error_cnt_;
TransferID tid_; // 1 byte field
// 1 byte aligned bitfields:
uint8_t next_frame_index_ : 6;
uint8_t iface_index_ : 2;
bool isInitialized() const { return iface_index_ != IfaceIndexNotSet; } bool isInitialized() const { return iface_index_ != IfaceIndexNotSet; }
@@ -59,14 +68,18 @@ private:
ResultCode receive(const RxFrame& frame, TransferBufferAccessor& tba); ResultCode receive(const RxFrame& frame, TransferBufferAccessor& tba);
public: public:
TransferReceiver() TransferReceiver() :
: transfer_interval_usec_(DefaultTransferIntervalUSec) transfer_interval_msec_(DefaultTransferIntervalMSec),
, this_transfer_crc_(0) this_transfer_crc_(0),
, buffer_write_pos_(0) buffer_write_pos_(0),
, iface_index_(IfaceIndexNotSet) error_cnt_(0),
, next_frame_index_(0) next_frame_index_(0),
, error_cnt_(0) iface_index_(IfaceIndexNotSet)
{ } {
#if UAVCAN_DEBUG
StaticAssert<sizeof(TransferReceiver) == 32>::check();
#endif
}
bool isTimedOut(MonotonicTime current_ts) const; bool isTimedOut(MonotonicTime current_ts) const;
@@ -79,9 +92,8 @@ public:
uint16_t getLastTransferCrc() const { return this_transfer_crc_; } uint16_t getLastTransferCrc() const { return this_transfer_crc_; }
MonotonicDuration getInterval() const { return MonotonicDuration::fromUSec(transfer_interval_usec_); } MonotonicDuration getInterval() const { return MonotonicDuration::fromMSec(transfer_interval_msec_); }
}; };
UAVCAN_PACKED_END
} }
+8 -9
View File
@@ -36,22 +36,22 @@ class UAVCAN_EXPORT MapBase : Noncopyable
{ {
template <typename, typename, unsigned> friend class Map; template <typename, typename, unsigned> friend class Map;
UAVCAN_PACKED_BEGIN
public: public:
struct KVPair struct KVPair
{ {
Value value; // Key and value are swapped because this may allow to reduce padding (depending on types)
Key key; Key key;
Value value;
KVPair() KVPair() :
: key() value(),
, value() key()
{ } { }
KVPair(const Key& arg_key, const Value& arg_value) KVPair(const Key& arg_key, const Value& arg_value) :
: key(arg_key) value(arg_value),
, value(arg_value) key(arg_key)
{ } { }
bool match(const Key& rhs) const { return rhs == key; } bool match(const Key& rhs) const { return rhs == key; }
}; };
@@ -99,7 +99,6 @@ private:
return NULL; return NULL;
} }
}; };
UAVCAN_PACKED_END
LinkedListRoot<KVGroup> list_; LinkedListRoot<KVGroup> list_;
IPoolAllocator& allocator_; IPoolAllocator& allocator_;
+1 -1
View File
@@ -132,7 +132,7 @@ MonotonicTime Scheduler::computeDispatcherSpinDeadline(MonotonicTime spin_deadli
const MonotonicTime ts = getMonotonicTime(); const MonotonicTime ts = getMonotonicTime();
if (earliest > ts) if (earliest > ts)
{ {
if (ts - earliest > deadline_resolution_) if (earliest - ts > deadline_resolution_)
{ {
return ts + deadline_resolution_; return ts + deadline_resolution_;
} }
@@ -0,0 +1,228 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>,
* Ilia Sheremet <illia.sheremet@gmail.com>
*/
#include <uavcan/transport/can_acceptance_filter_configurator.hpp>
#include <cassert>
namespace uavcan
{
const unsigned CanAcceptanceFilterConfigurator::DefaultFilterMsgMask;
const unsigned CanAcceptanceFilterConfigurator::DefaultFilterServiceRequestID;
const unsigned CanAcceptanceFilterConfigurator::DefaultFilterServiceRequestMask;
const unsigned CanAcceptanceFilterConfigurator::ServiceRespFrameID;
const unsigned CanAcceptanceFilterConfigurator::ServiceRespFrameMask;
int16_t CanAcceptanceFilterConfigurator::loadInputConfiguration()
{
multiset_configs_.clear();
CanFilterConfig service_resp_cfg;
service_resp_cfg.id = ServiceRespFrameID;
service_resp_cfg.mask = ServiceRespFrameMask;
if (multiset_configs_.emplace(service_resp_cfg) == NULL)
{
return -ErrMemory;
}
const TransferListenerBase* p = node_.getDispatcher().getListOfMessageListeners().get();
while (p)
{
CanFilterConfig cfg;
cfg.id = static_cast<uint32_t>(p->getDataTypeDescriptor().getID().get()) << 16;
cfg.id |= static_cast<uint32_t>(p->getDataTypeDescriptor().getKind()) << 8;
cfg.mask = DefaultFilterMsgMask;
if (multiset_configs_.emplace(cfg) == NULL)
{
return -ErrMemory;
}
p = p->getNextListNode();
}
const TransferListenerBase* p1 = node_.getDispatcher().getListOfServiceRequestListeners().get();
while (p1)
{
CanFilterConfig cfg;
cfg.id = DefaultFilterServiceRequestID;
cfg.id |= static_cast<uint32_t>(p1->getDataTypeDescriptor().getID().get()) << 17;
cfg.mask = DefaultFilterServiceRequestMask;
if (multiset_configs_.emplace(cfg) == NULL)
{
return -ErrMemory;
}
p1 = p1->getNextListNode();
}
if (multiset_configs_.getSize() == 0)
{
return -ErrLogic;
}
#if UAVCAN_DEBUG
for (uint16_t i = 0; i < multiset_configs_.getSize(); i++)
{
UAVCAN_TRACE("CanAcceptanceFilterConfigurator::loadInputConfiguration()", "cfg.ID [%u] = %d", i,
multiset_configs_.getByIndex(i)->id);
UAVCAN_TRACE("CanAcceptanceFilterConfigurator::loadInputConfiguration()", "cfg.MK [%u] = %d", i,
multiset_configs_.getByIndex(i)->mask);
}
#endif
return 0;
}
int16_t CanAcceptanceFilterConfigurator::computeConfiguration()
{
const uint16_t acceptance_filters_number = getNumFilters();
UAVCAN_ASSERT(multiset_configs_.getSize() != 0);
while (acceptance_filters_number < multiset_configs_.getSize())
{
uint16_t i_rank = 0, j_rank = 0;
uint8_t best_rank = 0;
const uint16_t multiset_array_size = static_cast<uint16_t>(multiset_configs_.getSize());
for (uint16_t i_ind = 0; i_ind < multiset_array_size - 1; i_ind++)
{
for (uint16_t j_ind = static_cast<uint8_t>(i_ind + 1); j_ind < multiset_array_size; j_ind++)
{
CanFilterConfig temp_config = mergeFilters(*multiset_configs_.getByIndex(i_ind),
*multiset_configs_.getByIndex(j_ind));
uint8_t rank = countBits(temp_config.mask);
if (rank > best_rank)
{
best_rank = rank;
i_rank = i_ind;
j_rank = j_ind;
}
}
}
*multiset_configs_.getByIndex(j_rank) = mergeFilters(*multiset_configs_.getByIndex(i_rank),
*multiset_configs_.getByIndex(j_rank));
multiset_configs_.removeFirst(*multiset_configs_.getByIndex(i_rank));
}
UAVCAN_ASSERT(acceptance_filters_number >= multiset_configs_.getSize());
return 0;
}
int16_t CanAcceptanceFilterConfigurator::applyConfiguration(void)
{
CanFilterConfig filter_conf_array[MaxCanAcceptanceFilters];
const unsigned int filter_array_size = multiset_configs_.getSize();
if (filter_array_size > MaxCanAcceptanceFilters)
{
UAVCAN_ASSERT(0);
return -ErrLogic;
}
for (uint16_t i = 0; i < filter_array_size; i++)
{
CanFilterConfig temp_filter_config = *multiset_configs_.getByIndex(i);
filter_conf_array[i] = temp_filter_config;
}
ICanDriver& can_driver = node_.getDispatcher().getCanIOManager().getCanDriver();
for (uint8_t i = 0; i < node_.getDispatcher().getCanIOManager().getNumIfaces(); i++)
{
ICanIface* iface = can_driver.getIface(i);
if (iface == NULL)
{
return -ErrDriver;
}
int16_t num = iface->configureFilters(reinterpret_cast<CanFilterConfig*>(&filter_conf_array),
static_cast<uint16_t>(filter_array_size));
if (num < 0)
{
return -ErrDriver;
}
}
return 0;
}
int CanAcceptanceFilterConfigurator::configureFilters()
{
if (getNumFilters() == 0)
{
UAVCAN_TRACE("CanAcceptanceFilter", "No HW filters available");
return -ErrDriver;
}
int16_t fill_array_error = loadInputConfiguration();
if (fill_array_error != 0)
{
UAVCAN_TRACE("CanAcceptanceFilter::loadInputConfiguration", "Failed to execute loadInputConfiguration()");
return fill_array_error;
}
int16_t compute_configuration_error = computeConfiguration();
if (compute_configuration_error != 0)
{
UAVCAN_TRACE("CanAcceptanceFilter", "Failed to compute optimal acceptance fliter's configuration");
return compute_configuration_error;
}
if (applyConfiguration() != 0)
{
UAVCAN_TRACE("CanAcceptanceFilter", "Failed to apply HW filter configuration");
return -ErrDriver;
}
return 0;
}
uint16_t CanAcceptanceFilterConfigurator::getNumFilters() const
{
static const uint16_t InvalidOut = 0xFFFF;
uint16_t out = InvalidOut;
ICanDriver& can_driver = node_.getDispatcher().getCanIOManager().getCanDriver();
for (uint8_t i = 0; i < node_.getDispatcher().getCanIOManager().getNumIfaces(); i++)
{
const ICanIface* iface = can_driver.getIface(i);
if (iface == NULL)
{
UAVCAN_ASSERT(0);
out = 0;
break;
}
const uint16_t num = iface->getNumFilters();
out = min(out, num);
if (out > MaxCanAcceptanceFilters)
{
out = MaxCanAcceptanceFilters;
}
}
return (out == InvalidOut) ? 0 : out;
}
CanFilterConfig CanAcceptanceFilterConfigurator::mergeFilters(CanFilterConfig &a_, CanFilterConfig &b_)
{
CanFilterConfig temp_arr;
temp_arr.mask = a_.mask & b_.mask & ~(a_.id ^ b_.id);
temp_arr.id = a_.id & temp_arr.mask;
return temp_arr;
}
uint8_t CanAcceptanceFilterConfigurator::countBits(uint32_t n_)
{
uint8_t c_; // c accumulates the total bits set in v
for (c_ = 0; n_; c_++)
{
n_ &= n_ - 1; // clear the least significant bit set
}
return c_;
}
}
@@ -11,21 +11,13 @@
namespace uavcan namespace uavcan
{ {
const uint32_t TransferReceiver::MinTransferIntervalUSec; const uint16_t TransferReceiver::MinTransferIntervalMSec;
const uint32_t TransferReceiver::MaxTransferIntervalUSec; const uint16_t TransferReceiver::MaxTransferIntervalMSec;
const uint32_t TransferReceiver::DefaultTransferIntervalUSec; const uint16_t TransferReceiver::DefaultTransferIntervalMSec;
const uint8_t TransferReceiver::IfaceIndexNotSet;
void TransferReceiver::registerError() const void TransferReceiver::registerError() const
{ {
if (error_cnt_ < 0xFF) error_cnt_ = static_cast<uint8_t>(error_cnt_ + 1) & ErrorCntMask;
{
error_cnt_ = static_cast<uint8_t>(error_cnt_ + 1);
}
else
{
UAVCAN_ASSERT(0);
}
} }
TransferReceiver::TidRelation TransferReceiver::getTidRelation(const RxFrame& frame) const TransferReceiver::TidRelation TransferReceiver::getTidRelation(const RxFrame& frame) const
@@ -51,10 +43,10 @@ void TransferReceiver::updateTransferTimings()
if ((!prev_prev_ts.isZero()) && (!prev_transfer_ts_.isZero()) && (prev_transfer_ts_ >= prev_prev_ts)) if ((!prev_prev_ts.isZero()) && (!prev_transfer_ts_.isZero()) && (prev_transfer_ts_ >= prev_prev_ts))
{ {
uint64_t interval_usec = uint64_t((prev_transfer_ts_ - prev_prev_ts).toUSec()); uint64_t interval_msec = uint64_t((prev_transfer_ts_ - prev_prev_ts).toMSec());
interval_usec = min(interval_usec, uint64_t(MaxTransferIntervalUSec)); interval_msec = min(interval_msec, uint64_t(MaxTransferIntervalMSec));
interval_usec = max(interval_usec, uint64_t(MinTransferIntervalUSec)); interval_msec = max(interval_msec, uint64_t(MinTransferIntervalMSec));
transfer_interval_usec_ = static_cast<uint32_t>((uint64_t(transfer_interval_usec_) * 7 + interval_usec) / 8); transfer_interval_msec_ = static_cast<uint16_t>((uint64_t(transfer_interval_msec_) * 7U + interval_msec) / 8U);
} }
} }
@@ -118,7 +110,7 @@ bool TransferReceiver::writePayload(const RxFrame& frame, ITransferBuffer& buf)
const bool success = res == static_cast<int>(effective_payload_len); const bool success = res == static_cast<int>(effective_payload_len);
if (success) if (success)
{ {
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + effective_payload_len); buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + effective_payload_len) & BufferWritePosMask;
} }
return success; return success;
} }
@@ -128,7 +120,7 @@ bool TransferReceiver::writePayload(const RxFrame& frame, ITransferBuffer& buf)
const bool success = res == static_cast<int>(payload_len); const bool success = res == static_cast<int>(payload_len);
if (success) if (success)
{ {
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + payload_len); buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + payload_len) & BufferWritePosMask;
} }
return success; return success;
} }
@@ -186,12 +178,12 @@ TransferReceiver::ResultCode TransferReceiver::receive(const RxFrame& frame, Tra
bool TransferReceiver::isTimedOut(MonotonicTime current_ts) const bool TransferReceiver::isTimedOut(MonotonicTime current_ts) const
{ {
static const int64_t INTERVAL_MULT = (1 << TransferID::BitLen) / 2 + 1; static const int64_t IntervalMult = (1 << TransferID::BitLen) / 2 + 1;
if (current_ts <= this_transfer_ts_) if (current_ts <= this_transfer_ts_)
{ {
return false; return false;
} }
return (current_ts - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_usec_) * INTERVAL_MULT); return (current_ts - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_msec_) * 1000 * IntervalMult);
} }
TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, TransferBufferAccessor& tba) TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, TransferBufferAccessor& tba)
@@ -209,7 +201,7 @@ TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, Tr
const bool first_fame = frame.isFirst(); const bool first_fame = frame.isFirst();
const TidRelation tid_rel = getTidRelation(frame); const TidRelation tid_rel = getTidRelation(frame);
const bool iface_timed_out = const bool iface_timed_out =
(frame.getMonotonicTimestamp() - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_usec_) * 2); (frame.getMonotonicTimestamp() - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_msec_) * 1000 * 2);
// FSM, the hard way // FSM, the hard way
const bool need_restart = const bool need_restart =
@@ -230,7 +222,7 @@ TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, Tr
int(not_initialized), int(iface_timed_out), int(receiver_timed_out), int(same_iface), int(not_initialized), int(iface_timed_out), int(receiver_timed_out), int(same_iface),
int(first_fame), int(tid_rel), frame.toString().c_str()); int(first_fame), int(tid_rel), frame.toString().c_str());
tba.remove(); tba.remove();
iface_index_ = frame.getIfaceIndex(); iface_index_ = frame.getIfaceIndex() & IfaceIndexMask;
tid_ = frame.getTransferID(); tid_ = frame.getTransferID();
next_frame_index_ = 0; next_frame_index_ = 0;
buffer_write_pos_ = 0; buffer_write_pos_ = 0;
+1 -11
View File
@@ -33,17 +33,7 @@ void LimitedPoolAllocator::deallocate(const void* ptr)
} }
} }
bool LimitedPoolAllocator::isInPool(const void* ptr) const uint16_t LimitedPoolAllocator::getNumBlocks() const
{
return allocator_.isInPool(ptr);
}
std::size_t LimitedPoolAllocator::getBlockSize() const
{
return allocator_.getBlockSize();
}
std::size_t LimitedPoolAllocator::getNumBlocks() const
{ {
return min(max_blocks_, allocator_.getNumBlocks()); return min(max_blocks_, allocator_.getNumBlocks());
} }
+23 -71
View File
@@ -8,91 +8,40 @@
TEST(DynamicMemory, Basic) TEST(DynamicMemory, Basic)
{ {
uavcan::PoolAllocator<128, 32> pool32; uavcan::PoolAllocator<128, 32> pool32;
uavcan::PoolAllocator<256, 64> pool64;
uavcan::PoolAllocator<512, 128> pool128;
EXPECT_EQ(4, pool32.getNumFreeBlocks()); EXPECT_EQ(4, pool32.getNumFreeBlocks());
EXPECT_EQ(4, pool64.getNumFreeBlocks()); EXPECT_EQ(0, pool32.getPeakNumUsedBlocks());
EXPECT_EQ(4, pool128.getNumFreeBlocks()); const void* ptr1 = pool32.allocate(16);
ASSERT_TRUE(ptr1);
uavcan::PoolManager<2> poolmgr;
EXPECT_TRUE(poolmgr.addPool(&pool64)); // Order of insertion shall not matter
EXPECT_TRUE(poolmgr.addPool(&pool32));
EXPECT_FALSE(poolmgr.addPool(&pool128));
EXPECT_EQ(4 * 2, poolmgr.getNumBlocks());
const void* ptr1 = poolmgr.allocate(16);
EXPECT_TRUE(ptr1);
const void* ptr2 = poolmgr.allocate(32);
EXPECT_TRUE(ptr2);
const void* ptr3 = poolmgr.allocate(64);
EXPECT_TRUE(ptr3);
EXPECT_FALSE(poolmgr.allocate(120));
EXPECT_EQ(2, pool32.getNumUsedBlocks());
EXPECT_EQ(1, pool64.getNumUsedBlocks());
EXPECT_EQ(0, pool128.getNumUsedBlocks());
poolmgr.deallocate(ptr1);
EXPECT_EQ(1, pool32.getNumUsedBlocks()); EXPECT_EQ(1, pool32.getNumUsedBlocks());
poolmgr.deallocate(ptr2); EXPECT_FALSE(pool32.allocate(120));
EXPECT_EQ(1, pool32.getNumUsedBlocks());
pool32.deallocate(ptr1);
EXPECT_EQ(0, pool32.getNumUsedBlocks()); EXPECT_EQ(0, pool32.getNumUsedBlocks());
EXPECT_EQ(1, pool64.getNumUsedBlocks()); EXPECT_EQ(1, pool32.getPeakNumUsedBlocks());
poolmgr.deallocate(ptr3);
EXPECT_EQ(0, pool64.getNumUsedBlocks());
EXPECT_EQ(0, pool128.getNumUsedBlocks());
} }
TEST(DynamicMemory, OutOfMemory) TEST(DynamicMemory, OutOfMemory)
{ {
uavcan::PoolAllocator<64, 32> pool32; uavcan::PoolAllocator<64, 32> pool32;
uavcan::PoolAllocator<128, 64> pool64;
EXPECT_EQ(2, pool32.getNumFreeBlocks()); EXPECT_EQ(2, pool32.getNumFreeBlocks());
EXPECT_EQ(2, pool64.getNumFreeBlocks()); EXPECT_EQ(0, pool32.getNumUsedBlocks());
EXPECT_EQ(0, pool32.getPeakNumUsedBlocks());
uavcan::PoolManager<4> poolmgr; const void* ptr1 = pool32.allocate(32);
EXPECT_TRUE(poolmgr.addPool(&pool64)); ASSERT_TRUE(ptr1);
EXPECT_TRUE(poolmgr.addPool(&pool32)); EXPECT_EQ(1, pool32.getNumUsedBlocks());
EXPECT_EQ(1, pool32.getPeakNumUsedBlocks());
const void* ptr1 = poolmgr.allocate(32);
EXPECT_TRUE(ptr1);
EXPECT_TRUE(pool32.isInPool(ptr1));
EXPECT_FALSE(pool64.isInPool(ptr1));
const void* ptr2 = poolmgr.allocate(32);
EXPECT_TRUE(ptr2);
EXPECT_TRUE(pool32.isInPool(ptr2));
EXPECT_FALSE(pool64.isInPool(ptr2));
const void* ptr3 = poolmgr.allocate(32);
EXPECT_TRUE(ptr3);
EXPECT_FALSE(pool32.isInPool(ptr3));
EXPECT_TRUE(pool64.isInPool(ptr3)); // One block went to the next pool
const void* ptr2 = pool32.allocate(32);
ASSERT_TRUE(ptr2);
EXPECT_EQ(2, pool32.getNumUsedBlocks()); EXPECT_EQ(2, pool32.getNumUsedBlocks());
EXPECT_EQ(1, pool64.getNumUsedBlocks()); EXPECT_EQ(2, pool32.getPeakNumUsedBlocks());
poolmgr.deallocate(ptr2); ASSERT_FALSE(pool32.allocate(32)); // No free blocks left --> NULL
EXPECT_EQ(1, pool32.getNumUsedBlocks()); EXPECT_EQ(2, pool32.getNumUsedBlocks());
EXPECT_EQ(1, pool64.getNumUsedBlocks()); EXPECT_EQ(0, pool32.getNumFreeBlocks());
EXPECT_EQ(2, pool32.getPeakNumUsedBlocks());
const void* ptr4 = poolmgr.allocate(64);
EXPECT_TRUE(ptr4);
EXPECT_EQ(1, pool32.getNumUsedBlocks());
EXPECT_EQ(2, pool64.getNumUsedBlocks()); // Top pool is 100% used
EXPECT_FALSE(poolmgr.allocate(64)); // No free blocks left --> NULL
EXPECT_EQ(1, pool32.getNumUsedBlocks());
EXPECT_EQ(2, pool64.getNumUsedBlocks());
poolmgr.deallocate(ptr3); // This was small chunk allocated in big pool
EXPECT_EQ(1, pool32.getNumUsedBlocks());
EXPECT_EQ(1, pool64.getNumUsedBlocks()); // Make sure it was properly deallocated
} }
TEST(DynamicMemory, LimitedPoolAllocator) TEST(DynamicMemory, LimitedPoolAllocator)
@@ -101,6 +50,7 @@ TEST(DynamicMemory, LimitedPoolAllocator)
uavcan::LimitedPoolAllocator lim(pool32, 2); uavcan::LimitedPoolAllocator lim(pool32, 2);
EXPECT_EQ(2, lim.getNumBlocks()); EXPECT_EQ(2, lim.getNumBlocks());
EXPECT_EQ(0, pool32.getPeakNumUsedBlocks());
const void* ptr1 = lim.allocate(1); const void* ptr1 = lim.allocate(1);
const void* ptr2 = lim.allocate(1); const void* ptr2 = lim.allocate(1);
@@ -119,4 +69,6 @@ TEST(DynamicMemory, LimitedPoolAllocator)
EXPECT_TRUE(ptr4); EXPECT_TRUE(ptr4);
EXPECT_TRUE(ptr5); EXPECT_TRUE(ptr5);
EXPECT_FALSE(ptr6); EXPECT_FALSE(ptr6);
EXPECT_EQ(2, pool32.getPeakNumUsedBlocks());
} }
+3 -14
View File
@@ -20,17 +20,15 @@
struct TestNode : public uavcan::INode struct TestNode : public uavcan::INode
{ {
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 100, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 100, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
uavcan::OutgoingTransferRegistry<8> otr; uavcan::OutgoingTransferRegistry<8> otr;
uavcan::Scheduler scheduler; uavcan::Scheduler scheduler;
uint64_t internal_failure_count; uint64_t internal_failure_count;
TestNode(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock_driver, uavcan::NodeID self_node_id) TestNode(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock_driver, uavcan::NodeID self_node_id)
: otr(poolmgr) : otr(pool)
, scheduler(can_driver, poolmgr, clock_driver, otr) , scheduler(can_driver, pool, clock_driver, otr)
, internal_failure_count(0) , internal_failure_count(0)
{ {
poolmgr.addPool(&pool);
setNodeID(self_node_id); setNodeID(self_node_id);
} }
@@ -40,7 +38,7 @@ struct TestNode : public uavcan::INode
internal_failure_count++; internal_failure_count++;
} }
virtual uavcan::PoolManager<1>& getAllocator() { return poolmgr; } virtual uavcan::IPoolAllocator& getAllocator() { return pool; }
virtual uavcan::Scheduler& getScheduler() { return scheduler; } virtual uavcan::Scheduler& getScheduler() { return scheduler; }
virtual const uavcan::Scheduler& getScheduler() const { return scheduler; } virtual const uavcan::Scheduler& getScheduler() const { return scheduler; }
}; };
@@ -75,15 +73,6 @@ struct PairableCanDriver : public uavcan::ICanDriver, public uavcan::ICanIface
return NULL; return NULL;
} }
virtual const uavcan::ICanIface* getIface(uavcan::uint8_t iface_index) const
{
if (iface_index == 0)
{
return this;
}
return NULL;
}
virtual uavcan::uint8_t getNumIfaces() const { return 1; } virtual uavcan::uint8_t getNumIfaces() const { return 1; }
virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks, uavcan::MonotonicTime blocking_deadline) virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks, uavcan::MonotonicTime blocking_deadline)
@@ -11,6 +11,7 @@
TEST(dynamic_node_id_server_centralized_Storage, Initialization) TEST(dynamic_node_id_server_centralized_Storage, Initialization)
{ {
using namespace uavcan::dynamic_node_id_server::centralized; using namespace uavcan::dynamic_node_id_server::centralized;
using namespace uavcan::dynamic_node_id_server;
// No data in the storage - initializing empty // No data in the storage - initializing empty
{ {
@@ -20,95 +21,51 @@ TEST(dynamic_node_id_server_centralized_Storage, Initialization)
ASSERT_EQ(0, storage.getNumKeys()); ASSERT_EQ(0, storage.getNumKeys());
ASSERT_LE(0, stor.init()); ASSERT_LE(0, stor.init());
ASSERT_EQ(1, storage.getNumKeys()); ASSERT_EQ(0, storage.getNumKeys());
ASSERT_EQ(0, stor.getSize()); ASSERT_EQ(0, stor.getSize());
ASSERT_FALSE(stor.findByNodeID(1)); ASSERT_FALSE(stor.isNodeIDOccupied(1));
ASSERT_FALSE(stor.findByNodeID(0)); ASSERT_FALSE(stor.isNodeIDOccupied(0));
}
// Nonempty storage, one item
{
MemoryStorageBackend storage;
Storage stor(storage);
storage.set("size", "1");
ASSERT_EQ(-uavcan::ErrFailure, stor.init()); // Expected one entry, none found
ASSERT_EQ(1, storage.getNumKeys());
storage.set("0_unique_id", "00000000000000000000000000000000");
storage.set("0_node_id", "0");
ASSERT_EQ(-uavcan::ErrFailure, stor.init()); // Invalid entry - zero Node ID
storage.set("0_node_id", "1");
ASSERT_LE(0, stor.init()); // OK now
ASSERT_EQ(3, storage.getNumKeys());
ASSERT_EQ(1, stor.getSize());
ASSERT_TRUE(stor.findByNodeID(1));
ASSERT_FALSE(stor.findByNodeID(0));
}
// Nonempty storage, broken data
{
MemoryStorageBackend storage;
Storage stor(storage);
storage.set("size", "foobar");
ASSERT_EQ(-uavcan::ErrFailure, stor.init()); // Bad value
storage.set("size", "128");
ASSERT_EQ(-uavcan::ErrFailure, stor.init()); // Bad value
storage.set("size", "1");
ASSERT_EQ(-uavcan::ErrFailure, stor.init()); // No items
ASSERT_EQ(1, storage.getNumKeys());
storage.set("0_unique_id", "00000000000000000000000000000000");
storage.set("0_node_id", "128"); // Bad value (127 max)
ASSERT_EQ(-uavcan::ErrFailure, stor.init()); // Failed
storage.set("0_node_id", "127");
ASSERT_LE(0, stor.init()); // OK now
ASSERT_EQ(1, stor.getSize());
ASSERT_TRUE(stor.findByNodeID(127));
ASSERT_FALSE(stor.findByNodeID(0));
ASSERT_EQ(3, storage.getNumKeys());
} }
// Nonempty storage, many items // Nonempty storage, many items
{ {
MemoryStorageBackend storage; MemoryStorageBackend storage;
Storage stor(storage); Storage stor(storage);
storage.set("size", "2"); storage.set("occupation_mask", "0e000000000000000000000000000000"); // node ID 1, 2, 3
storage.set("0_unique_id", "00000000000000000000000000000000"); ASSERT_LE(0, stor.init()); // OK
storage.set("0_node_id", "1");
storage.set("1_unique_id", "0123456789abcdef0123456789abcdef");
storage.set("1_node_id", "127");
ASSERT_LE(0, stor.init()); // OK now ASSERT_EQ(1, storage.getNumKeys());
ASSERT_EQ(5, storage.getNumKeys()); ASSERT_EQ(3, stor.getSize());
ASSERT_EQ(2, stor.getSize());
ASSERT_TRUE(stor.findByNodeID(1)); ASSERT_TRUE(stor.isNodeIDOccupied(1));
ASSERT_TRUE(stor.findByNodeID(127)); ASSERT_TRUE(stor.isNodeIDOccupied(2));
ASSERT_FALSE(stor.findByNodeID(0)); ASSERT_TRUE(stor.isNodeIDOccupied(3));
ASSERT_FALSE(stor.isNodeIDOccupied(0));
ASSERT_FALSE(stor.isNodeIDOccupied(4));
uavcan::protocol::dynamic_node_id::server::Entry::FieldTypes::unique_id uid; UniqueID uid_1;
uid[0] = 0x01; uid_1[0] = 1;
uid[1] = 0x23;
uid[2] = 0x45;
uid[3] = 0x67;
uid[4] = 0x89;
uid[5] = 0xab;
uid[6] = 0xcd;
uid[7] = 0xef;
uavcan::copy(uid.begin(), uid.begin() + 8, uid.begin() + 8);
ASSERT_TRUE(stor.findByUniqueID(uid)); UniqueID uid_2;
ASSERT_EQ(127, stor.findByUniqueID(uid)->node_id.get()); uid_2[0] = 2;
ASSERT_EQ(uid, stor.findByNodeID(127)->unique_id);
UniqueID uid_3;
uid_3[0] = 3;
ASSERT_FALSE(stor.getNodeIDForUniqueID(uid_1).isValid());
ASSERT_FALSE(stor.getNodeIDForUniqueID(uid_2).isValid());
ASSERT_FALSE(stor.getNodeIDForUniqueID(uid_3).isValid());
ASSERT_FALSE(stor.isNodeIDOccupied(127));
storage.set("01000000000000000000000000000000", "1");
storage.set("02000000000000000000000000000000", "2");
storage.set("03000000000000000000000000000000", "3");
ASSERT_EQ(1, stor.getNodeIDForUniqueID(uid_1).get());
ASSERT_EQ(2, stor.getNodeIDForUniqueID(uid_2).get());
ASSERT_EQ(3, stor.getNodeIDForUniqueID(uid_3).get());
ASSERT_FALSE(stor.isNodeIDOccupied(127));
} }
} }
@@ -123,21 +80,19 @@ TEST(dynamic_node_id_server_centralized_Storage, Basic)
ASSERT_EQ(0, storage.getNumKeys()); ASSERT_EQ(0, storage.getNumKeys());
ASSERT_LE(0, stor.init()); ASSERT_LE(0, stor.init());
storage.print(); storage.print();
ASSERT_EQ(1, storage.getNumKeys()); ASSERT_EQ(0, storage.getNumKeys());
/* /*
* Adding one entry to the log, making sure it appears in the storage * Adding one entry to the log, making sure it appears in the storage
*/ */
Storage::Entry entry; uavcan::dynamic_node_id_server::UniqueID unique_id;
entry.node_id = 1; unique_id[0] = 1;
entry.unique_id[0] = 1; ASSERT_LE(0, stor.add(1, unique_id));
ASSERT_LE(0, stor.add(entry.node_id, entry.unique_id));
ASSERT_EQ("1", storage.get("size")); ASSERT_EQ("02000000000000000000000000000000", storage.get("occupation_mask"));
ASSERT_EQ("01000000000000000000000000000000", storage.get("0_unique_id")); ASSERT_EQ("1", storage.get("01000000000000000000000000000000"));
ASSERT_EQ("1", storage.get("0_node_id"));
ASSERT_EQ(3, storage.getNumKeys()); ASSERT_EQ(2, storage.getNumKeys());
ASSERT_EQ(1, stor.getSize()); ASSERT_EQ(1, stor.getSize());
/* /*
@@ -145,30 +100,31 @@ TEST(dynamic_node_id_server_centralized_Storage, Basic)
*/ */
storage.failOnSetCalls(true); storage.failOnSetCalls(true);
ASSERT_EQ(3, storage.getNumKeys()); ASSERT_EQ(2, storage.getNumKeys());
entry.node_id = 2; unique_id[0] = 2;
entry.unique_id[0] = 2; ASSERT_GT(0, stor.add(2, unique_id));
ASSERT_GT(0, stor.add(entry.node_id, entry.unique_id));
ASSERT_EQ(3, storage.getNumKeys()); // No new entries, we failed ASSERT_EQ(2, storage.getNumKeys()); // No new entries, we failed
ASSERT_EQ(1, stor.getSize()); ASSERT_EQ(1, stor.getSize());
/* /*
* Making sure add() fails when the log is full * Adding a lot of entries
*/ */
storage.failOnSetCalls(false); storage.failOnSetCalls(false);
while (stor.getSize() < stor.Capacity) uavcan::NodeID node_id(2);
while (stor.getSize() < 127)
{ {
ASSERT_LE(0, stor.add(entry.node_id, entry.unique_id)); ASSERT_LE(0, stor.add(node_id, unique_id));
entry.node_id = uint8_t(uavcan::min(entry.node_id.get() + 1U, 127U)); ASSERT_TRUE(stor.getNodeIDForUniqueID(unique_id).isValid());
entry.unique_id[0] = uint8_t(entry.unique_id[0] + 1U); ASSERT_TRUE(stor.isNodeIDOccupied(node_id));
node_id = uint8_t(uavcan::min(node_id.get() + 1U, 127U));
unique_id[0] = uint8_t(unique_id[0] + 1U);
} }
ASSERT_GT(0, stor.add(123, entry.unique_id)); // Failing because full
storage.print(); storage.print();
} }
@@ -203,6 +203,26 @@ TEST(NodeInfoRetriever, Basic)
EXPECT_EQ(13, listener.status_message_cnt); EXPECT_EQ(13, listener.status_message_cnt);
EXPECT_EQ(7, listener.status_change_cnt); // node 2 online/offline + 2 test nodes above online/offline + 1 EXPECT_EQ(7, listener.status_change_cnt); // node 2 online/offline + 2 test nodes above online/offline + 1
EXPECT_EQ(3, listener.info_unavailable_cnt); EXPECT_EQ(3, listener.info_unavailable_cnt);
/*
* Forcing the class to forget everything
*/
std::cout << "Invalidation" << std::endl;
retr.invalidateAll();
ASSERT_FALSE(retr.isRetrievingInProgress());
ASSERT_EQ(0, retr.getNumPendingRequests());
tid.increment();
publishNodeStatus(nodes.can_a, uavcan::NodeID(10), 0, 60, tid);
publishNodeStatus(nodes.can_a, uavcan::NodeID(11), 0, 60, tid);
publishNodeStatus(nodes.can_a, uavcan::NodeID(12), 0, 60, tid);
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(200));
ASSERT_TRUE(retr.isRetrievingInProgress());
ASSERT_EQ(3, retr.getNumPendingRequests());
} }
-1
View File
@@ -232,7 +232,6 @@ public:
} }
virtual uavcan::ICanIface* getIface(uavcan::uint8_t iface_index) { return &ifaces.at(iface_index); } virtual uavcan::ICanIface* getIface(uavcan::uint8_t iface_index) { return &ifaces.at(iface_index); }
virtual const uavcan::ICanIface* getIface(uavcan::uint8_t iface_index) const { return &ifaces.at(iface_index); }
virtual uavcan::uint8_t getNumIfaces() const { return uavcan::uint8_t(ifaces.size()); } virtual uavcan::uint8_t getNumIfaces() const { return uavcan::uint8_t(ifaces.size()); }
}; };
+3 -9
View File
@@ -23,15 +23,13 @@ TEST(CanIOManager, Reception)
{ {
// Memory // Memory
uavcan::PoolAllocator<sizeof(uavcan::CanTxQueue::Entry) * 4, sizeof(uavcan::CanTxQueue::Entry)> pool; uavcan::PoolAllocator<sizeof(uavcan::CanTxQueue::Entry) * 4, sizeof(uavcan::CanTxQueue::Entry)> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
// Platform interface // Platform interface
SystemClockMock clockmock; SystemClockMock clockmock;
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
// IO Manager // IO Manager
uavcan::CanIOManager iomgr(driver, poolmgr, clockmock); uavcan::CanIOManager iomgr(driver, pool, clockmock);
ASSERT_EQ(2, iomgr.getNumIfaces()); ASSERT_EQ(2, iomgr.getNumIfaces());
/* /*
@@ -120,15 +118,13 @@ TEST(CanIOManager, Transmission)
// Memory // Memory
uavcan::PoolAllocator<sizeof(CanTxQueue::Entry) * 4, sizeof(CanTxQueue::Entry)> pool; uavcan::PoolAllocator<sizeof(CanTxQueue::Entry) * 4, sizeof(CanTxQueue::Entry)> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
// Platform interface // Platform interface
SystemClockMock clockmock; SystemClockMock clockmock;
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
// IO Manager // IO Manager
CanIOManager iomgr(driver, poolmgr, clockmock, 9999); CanIOManager iomgr(driver, pool, clockmock, 9999);
ASSERT_EQ(2, iomgr.getNumIfaces()); ASSERT_EQ(2, iomgr.getNumIfaces());
const int ALL_IFACES_MASK = 3; const int ALL_IFACES_MASK = 3;
@@ -312,15 +308,13 @@ TEST(CanIOManager, Loopback)
// Memory // Memory
uavcan::PoolAllocator<sizeof(CanTxQueue::Entry) * 4, sizeof(CanTxQueue::Entry)> pool; uavcan::PoolAllocator<sizeof(CanTxQueue::Entry) * 4, sizeof(CanTxQueue::Entry)> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
// Platform interface // Platform interface
SystemClockMock clockmock; SystemClockMock clockmock;
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
// IO Manager // IO Manager
CanIOManager iomgr(driver, poolmgr, clockmock); CanIOManager iomgr(driver, pool, clockmock);
ASSERT_EQ(2, iomgr.getNumIfaces()); ASSERT_EQ(2, iomgr.getNumIfaces());
CanFrame fr1; CanFrame fr1;
+1 -3
View File
@@ -68,12 +68,10 @@ TEST(CanTxQueue, TxQueue)
ASSERT_GE(40, sizeof(CanTxQueue::Entry)); // should be true for any platforms, though not required ASSERT_GE(40, sizeof(CanTxQueue::Entry)); // should be true for any platforms, though not required
uavcan::PoolAllocator<40 * 4, 40> pool; uavcan::PoolAllocator<40 * 4, 40> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
SystemClockMock clockmock; SystemClockMock clockmock;
CanTxQueue queue(poolmgr, clockmock, 99999); CanTxQueue queue(pool, clockmock, 99999);
EXPECT_TRUE(queue.isEmpty()); EXPECT_TRUE(queue.isEmpty());
const uavcan::CanIOFlags flags = 0; const uavcan::CanIOFlags flags = 0;
@@ -0,0 +1,157 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>,
* Ilia Sheremet <illia.sheremet@gmail.com>
*/
#include <gtest/gtest.h>
#include <cassert>
#include <uavcan/transport/can_acceptance_filter_configurator.hpp>
#include "../node/test_node.hpp"
#include "uavcan/node/subscriber.hpp"
#include <uavcan/equipment/camera_gimbal/AngularCommand.hpp>
#include <uavcan/equipment/air_data/Sideslip.hpp>
#include <uavcan/equipment/air_data/TrueAirspeed.hpp>
#include <uavcan/equipment/air_data/AngleOfAttack.hpp>
#include <uavcan/equipment/ahrs/AHRS.hpp>
#include <uavcan/equipment/air_data/StaticPressure.hpp>
#include <uavcan/protocol/file/BeginFirmwareUpdate.hpp>
#include <uavcan/node/service_client.hpp>
#include <uavcan/node/service_server.hpp>
#include <iostream>
#include <bitset>
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
template <typename DataType>
struct SubscriptionListener
{
typedef uavcan::ReceivedDataStructure<DataType> ReceivedDataStructure;
struct ReceivedDataStructureCopy
{
uavcan::MonotonicTime ts_monotonic;
uavcan::UtcTime ts_utc;
uavcan::TransferType transfer_type;
uavcan::TransferID transfer_id;
uavcan::NodeID src_node_id;
uavcan::uint8_t iface_index;
DataType msg;
ReceivedDataStructureCopy(const ReceivedDataStructure& s) :
ts_monotonic(s.getMonotonicTimestamp()),
ts_utc(s.getUtcTimestamp()),
transfer_type(s.getTransferType()),
transfer_id(s.getTransferID()),
src_node_id(s.getSrcNodeID()),
iface_index(s.getIfaceIndex()),
msg(s)
{ }
};
std::vector<DataType> simple;
std::vector<ReceivedDataStructureCopy> extended;
void receiveExtended(ReceivedDataStructure& msg)
{
extended.push_back(msg);
}
void receiveSimple(DataType& msg)
{
simple.push_back(msg);
}
typedef SubscriptionListener<DataType> SelfType;
typedef uavcan::MethodBinder<SelfType*, void(SelfType::*) (ReceivedDataStructure&)> ExtendedBinder;
typedef uavcan::MethodBinder<SelfType*, void(SelfType::*) (DataType&)> SimpleBinder;
ExtendedBinder bindExtended() { return ExtendedBinder(this, &SelfType::receiveExtended); }
SimpleBinder bindSimple() { return SimpleBinder(this, &SelfType::receiveSimple); }
};
static void writeServiceServerCallback(
const uavcan::ReceivedDataStructure<uavcan::protocol::file::BeginFirmwareUpdate::Request>& req,
uavcan::protocol::file::BeginFirmwareUpdate::Response& rsp)
{
std::cout << req << std::endl;
rsp.error = rsp.ERROR_UNKNOWN;
}
TEST(CanAcceptanceFilter, Basic_test)
{
uavcan::GlobalDataTypeRegistry::instance().reset();
uavcan::DefaultDataTypeRegistrator<uavcan::equipment::camera_gimbal::AngularCommand> _reg1;
uavcan::DefaultDataTypeRegistrator<uavcan::equipment::air_data::Sideslip> _reg2;
uavcan::DefaultDataTypeRegistrator<uavcan::equipment::air_data::TrueAirspeed> _reg3;
uavcan::DefaultDataTypeRegistrator<uavcan::equipment::air_data::AngleOfAttack> _reg4;
uavcan::DefaultDataTypeRegistrator<uavcan::equipment::ahrs::AHRS> _reg5;
uavcan::DefaultDataTypeRegistrator<uavcan::equipment::air_data::StaticPressure> _reg6;
uavcan::DefaultDataTypeRegistrator<uavcan::protocol::file::BeginFirmwareUpdate> _reg7;
SystemClockDriver clock_driver;
CanDriverMock can_driver(1, clock_driver);
TestNode node(can_driver, clock_driver, 24);
uavcan::Subscriber<uavcan::equipment::camera_gimbal::AngularCommand,
SubscriptionListener<uavcan::equipment::camera_gimbal::AngularCommand>::ExtendedBinder> sub_1(node);
uavcan::Subscriber<uavcan::equipment::air_data::Sideslip,
SubscriptionListener<uavcan::equipment::air_data::Sideslip>::ExtendedBinder> sub_2(node);
uavcan::Subscriber<uavcan::equipment::air_data::TrueAirspeed,
SubscriptionListener<uavcan::equipment::air_data::TrueAirspeed>::ExtendedBinder> sub_3(node);
uavcan::Subscriber<uavcan::equipment::air_data::AngleOfAttack,
SubscriptionListener<uavcan::equipment::air_data::AngleOfAttack>::ExtendedBinder> sub_4(node);
uavcan::Subscriber<uavcan::equipment::ahrs::AHRS,
SubscriptionListener<uavcan::equipment::ahrs::AHRS>::ExtendedBinder> sub_5(node);
uavcan::Subscriber<uavcan::equipment::air_data::StaticPressure,
SubscriptionListener<uavcan::equipment::air_data::StaticPressure>::ExtendedBinder> sub_6(node);
uavcan::Subscriber<uavcan::equipment::air_data::StaticPressure,
SubscriptionListener<uavcan::equipment::air_data::StaticPressure>::ExtendedBinder> sub_6_1(node);
uavcan::ServiceServer<uavcan::protocol::file::BeginFirmwareUpdate> server(node);
SubscriptionListener<uavcan::equipment::camera_gimbal::AngularCommand> listener_1;
SubscriptionListener<uavcan::equipment::air_data::Sideslip> listener_2;
SubscriptionListener<uavcan::equipment::air_data::TrueAirspeed> listener_3;
SubscriptionListener<uavcan::equipment::air_data::AngleOfAttack> listener_4;
SubscriptionListener<uavcan::equipment::ahrs::AHRS> listener_5;
SubscriptionListener<uavcan::equipment::air_data::StaticPressure> listener_6;
sub_1.start(listener_1.bindExtended());
sub_2.start(listener_2.bindExtended());
sub_3.start(listener_3.bindExtended());
sub_4.start(listener_4.bindExtended());
sub_5.start(listener_5.bindExtended());
sub_6.start(listener_6.bindExtended());
sub_6_1.start(listener_6.bindExtended());
server.start(writeServiceServerCallback);
std::cout << "Subscribers are initialized ..." << std::endl;
uavcan::CanAcceptanceFilterConfigurator test_configurator(node);
int configure_filters_assert = test_configurator.configureFilters();
if (configure_filters_assert == 0)
{
std::cout << "Filters are configured ..." << std::endl;
}
const auto& configure_array = test_configurator.getConfiguration();
uint32_t configure_array_size = configure_array.getSize();
ASSERT_EQ(configure_filters_assert, 0);
ASSERT_EQ(configure_array_size, 4);
for (uint16_t i = 0; i<configure_array_size; i++)
{
std::cout << "config.ID [" << i << "]= " << configure_array.getByIndex(i)->id << std::endl;
std::cout << "config.MK [" << i << "]= " << configure_array.getByIndex(i)->mask << std::endl;
}
ASSERT_EQ(configure_array.getByIndex(0)->id, 268435456);
ASSERT_EQ(configure_array.getByIndex(0)->mask, 469762048);
ASSERT_EQ(configure_array.getByIndex(1)->id, 363069440);
ASSERT_EQ(configure_array.getByIndex(1)->mask, 536739840);
ASSERT_EQ(configure_array.getByIndex(2)->id, 16777216);
ASSERT_EQ(configure_array.getByIndex(2)->mask, 124452864);
ASSERT_EQ(configure_array.getByIndex(3)->id, 18874368);
ASSERT_EQ(configure_array.getByIndex(3)->mask, 133169152);
}
#endif
+12 -16
View File
@@ -53,15 +53,13 @@ static const uavcan::NodeID SELF_NODE_ID(64);
TEST(Dispatcher, Reception) TEST(Dispatcher, Reception)
{ {
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
SystemClockMock clockmock(100); SystemClockMock clockmock(100);
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr); uavcan::OutgoingTransferRegistry<8> out_trans_reg(pool);
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg); uavcan::Dispatcher dispatcher(driver, pool, clockmock, out_trans_reg);
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
ASSERT_FALSE(dispatcher.setNodeID(SELF_NODE_ID)); ASSERT_FALSE(dispatcher.setNodeID(SELF_NODE_ID));
ASSERT_EQ(SELF_NODE_ID, dispatcher.getNodeID()); ASSERT_EQ(SELF_NODE_ID, dispatcher.getNodeID());
@@ -93,12 +91,12 @@ TEST(Dispatcher, Reception)
static const int NUM_SUBSCRIBERS = 6; static const int NUM_SUBSCRIBERS = 6;
SubscriberPtr subscribers[NUM_SUBSCRIBERS] = SubscriberPtr subscribers[NUM_SUBSCRIBERS] =
{ {
SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[0], poolmgr)), // msg SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[0], pool)), // msg
SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[0], poolmgr)), // msg // Two similar SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[0], pool)), // msg // Two similar
SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[1], poolmgr)), // msg SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[1], pool)), // msg
SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[2], poolmgr)), // srv SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[2], pool)), // srv
SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[3], poolmgr)), // srv SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[3], pool)), // srv
SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[3], poolmgr)) // srv // Repeat again SubscriberPtr(new Subscriber(dispatcher.getTransferPerfCounter(), TYPES[3], pool)) // srv // Repeat again
}; };
static const std::string DATA[6] = static const std::string DATA[6] =
@@ -259,15 +257,13 @@ TEST(Dispatcher, Reception)
TEST(Dispatcher, Transmission) TEST(Dispatcher, Transmission)
{ {
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
SystemClockMock clockmock(100); SystemClockMock clockmock(100);
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr); uavcan::OutgoingTransferRegistry<8> out_trans_reg(pool);
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg); uavcan::Dispatcher dispatcher(driver, pool, clockmock, out_trans_reg);
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
ASSERT_FALSE(dispatcher.setNodeID(SELF_NODE_ID)); ASSERT_FALSE(dispatcher.setNodeID(SELF_NODE_ID));
@@ -324,7 +320,7 @@ TEST(Dispatcher, Transmission)
TEST(Dispatcher, Spin) TEST(Dispatcher, Spin)
{ {
uavcan::PoolManager<1> poolmgr; NullAllocator poolmgr;
SystemClockMock clockmock(100); SystemClockMock clockmock(100);
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
@@ -370,7 +366,7 @@ struct DispatcherTestLoopbackFrameListener : public uavcan::LoopbackFrameListene
TEST(Dispatcher, Loopback) TEST(Dispatcher, Loopback)
{ {
uavcan::PoolManager<1> poolmgr; NullAllocator poolmgr;
SystemClockMock clockmock(100); SystemClockMock clockmock(100);
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
@@ -6,6 +6,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <uavcan/transport/transfer_listener.hpp> #include <uavcan/transport/transfer_listener.hpp>
#include "../clock.hpp" #include "../clock.hpp"
#include "transfer_test_helpers.hpp"
static uavcan::RxFrame makeFrame() static uavcan::RxFrame makeFrame()
@@ -71,7 +72,7 @@ TEST(MultiFrameIncomingTransfer, Basic)
using uavcan::RxFrame; using uavcan::RxFrame;
using uavcan::MultiFrameIncomingTransfer; using uavcan::MultiFrameIncomingTransfer;
uavcan::PoolManager<1> poolmgr; // We don't need dynamic memory NullAllocator poolmgr; // We don't need dynamic memory
uavcan::TransferBufferManager<256, 1> bufmgr(poolmgr); uavcan::TransferBufferManager<256, 1> bufmgr(poolmgr);
const RxFrame frame = makeFrame(); const RxFrame frame = makeFrame();
@@ -6,12 +6,13 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <uavcan/transport/outgoing_transfer_registry.hpp> #include <uavcan/transport/outgoing_transfer_registry.hpp>
#include "../clock.hpp" #include "../clock.hpp"
#include "transfer_test_helpers.hpp"
TEST(OutgoingTransferRegistry, Basic) TEST(OutgoingTransferRegistry, Basic)
{ {
using uavcan::OutgoingTransferRegistryKey; using uavcan::OutgoingTransferRegistryKey;
uavcan::PoolManager<1> poolmgr; // Empty NullAllocator poolmgr; // Empty
uavcan::OutgoingTransferRegistry<4> otr(poolmgr); uavcan::OutgoingTransferRegistry<4> otr(poolmgr);
otr.cleanup(tsMono(1000)); otr.cleanup(tsMono(1000));
+2 -6
View File
@@ -133,10 +133,8 @@ TEST(DynamicTransferBufferManagerEntry, Basic)
static const int MAX_SIZE = TEST_BUFFER_SIZE; static const int MAX_SIZE = TEST_BUFFER_SIZE;
static const int POOL_BLOCKS = 8; static const int POOL_BLOCKS = 8;
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
DynamicTransferBufferManagerEntry buf(poolmgr, MAX_SIZE); DynamicTransferBufferManagerEntry buf(pool, MAX_SIZE);
uint8_t local_buffer[TEST_BUFFER_SIZE * 2]; uint8_t local_buffer[TEST_BUFFER_SIZE * 2];
const uint8_t* const test_data_ptr = reinterpret_cast<const uint8_t*>(TEST_DATA.c_str()); const uint8_t* const test_data_ptr = reinterpret_cast<const uint8_t*>(TEST_DATA.c_str());
@@ -233,11 +231,9 @@ TEST(TransferBufferManager, Basic)
static const int POOL_BLOCKS = 6; static const int POOL_BLOCKS = 6;
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
typedef TransferBufferManager<MGR_MAX_BUFFER_SIZE, 2> TransferBufferManagerType; typedef TransferBufferManager<MGR_MAX_BUFFER_SIZE, 2> TransferBufferManagerType;
std::auto_ptr<TransferBufferManagerType> mgr(new TransferBufferManagerType(poolmgr)); std::auto_ptr<TransferBufferManagerType> mgr(new TransferBufferManagerType(pool));
// Empty // Empty
ASSERT_FALSE(mgr->access(TransferBufferManagerKey(0, uavcan::TransferTypeMessageUnicast))); ASSERT_FALSE(mgr->access(TransferBufferManagerKey(0, uavcan::TransferTypeMessageUnicast)));
@@ -36,11 +36,9 @@ TEST(TransferListener, BasicMFT)
static const int NUM_POOL_BLOCKS = 12; // This number is just enough to pass the test static const int NUM_POOL_BLOCKS = 12; // This number is just enough to pass the test
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * NUM_POOL_BLOCKS, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * NUM_POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
uavcan::TransferPerfCounter perf; uavcan::TransferPerfCounter perf;
TestListener<256, 1, 1> subscriber(perf, type, poolmgr); TestListener<256, 1, 1> subscriber(perf, type, pool);
/* /*
* Test data * Test data
@@ -97,7 +95,7 @@ TEST(TransferListener, CrcFailure)
{ {
const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A"); const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A");
uavcan::PoolManager<1> poolmgr; // No dynamic memory NullAllocator poolmgr; // No dynamic memory
uavcan::TransferPerfCounter perf; uavcan::TransferPerfCounter perf;
TestListener<256, 2, 2> subscriber(perf, type, poolmgr); // Static buffer only, 2 entries TestListener<256, 2, 2> subscriber(perf, type, poolmgr); // Static buffer only, 2 entries
@@ -140,7 +138,7 @@ TEST(TransferListener, BasicSFT)
{ {
const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A"); const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A");
uavcan::PoolManager<1> poolmgr; // No dynamic memory. At all. NullAllocator poolmgr; // No dynamic memory. At all.
uavcan::TransferPerfCounter perf; uavcan::TransferPerfCounter perf;
TestListener<0, 0, 5> subscriber(perf, type, poolmgr); // Max buf size is 0, i.e. SFT-only TestListener<0, 0, 5> subscriber(perf, type, poolmgr); // Max buf size is 0, i.e. SFT-only
@@ -176,7 +174,7 @@ TEST(TransferListener, Cleanup)
{ {
const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A"); const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A");
uavcan::PoolManager<1> poolmgr; // No dynamic memory NullAllocator poolmgr; // No dynamic memory
uavcan::TransferPerfCounter perf; uavcan::TransferPerfCounter perf;
TestListener<256, 1, 2> subscriber(perf, type, poolmgr); // Static buffer only, 1 entry TestListener<256, 1, 2> subscriber(perf, type, poolmgr); // Static buffer only, 1 entry
@@ -231,7 +229,7 @@ TEST(TransferListener, MaximumTransferLength)
{ {
const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A"); const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A");
uavcan::PoolManager<1> poolmgr; NullAllocator poolmgr;
uavcan::TransferPerfCounter perf; uavcan::TransferPerfCounter perf;
TestListener<uavcan::MaxPossibleTransferPayloadLen * 2, 3, 3> subscriber(perf, type, poolmgr); TestListener<uavcan::MaxPossibleTransferPayloadLen * 2, 3, 3> subscriber(perf, type, poolmgr);
@@ -260,7 +258,7 @@ TEST(TransferListener, AnonymousTransfers)
{ {
const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A"); const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A");
uavcan::PoolManager<1> poolmgr; NullAllocator poolmgr;
uavcan::TransferPerfCounter perf; uavcan::TransferPerfCounter perf;
TestListener<0, 0, 0> subscriber(perf, type, poolmgr); TestListener<0, 0, 0> subscriber(perf, type, poolmgr);
+26 -12
View File
@@ -6,6 +6,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <uavcan/transport/transfer_receiver.hpp> #include <uavcan/transport/transfer_receiver.hpp>
#include "../clock.hpp" #include "../clock.hpp"
#include "transfer_test_helpers.hpp"
/* /*
* Beware! * Beware!
@@ -46,17 +47,16 @@ struct RxFrameGenerator
const uavcan::TransferBufferManagerKey RxFrameGenerator::DEFAULT_KEY(42, uavcan::TransferTypeMessageBroadcast); const uavcan::TransferBufferManagerKey RxFrameGenerator::DEFAULT_KEY(42, uavcan::TransferTypeMessageBroadcast);
template <unsigned BUFSIZE> template <unsigned BufSize>
struct Context struct Context
{ {
uavcan::PoolManager<1> poolmgr; // We don't need dynamic memory for this test NullAllocator pool; // We don't need dynamic memory for this test
uavcan::TransferReceiver receiver; // Must be default constructible and copyable uavcan::TransferReceiver receiver; // Must be default constructible and copyable
uavcan::TransferBufferManager<BUFSIZE, 1> bufmgr; uavcan::TransferBufferManager<BufSize, 1> bufmgr;
Context() Context() : bufmgr(pool)
: bufmgr(poolmgr)
{ {
assert(poolmgr.allocate(1) == NULL); assert(pool.allocate(1) == NULL);
} }
~Context() ~Context()
@@ -144,8 +144,8 @@ TEST(TransferReceiver, Basic)
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "345678abcdefgh")); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "345678abcdefgh"));
ASSERT_EQ(0x789A, rcv.getLastTransferCrc()); ASSERT_EQ(0x789A, rcv.getLastTransferCrc());
ASSERT_GT(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval()); ASSERT_GE(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval());
ASSERT_LT(TransferReceiver::getMinTransferInterval(), rcv.getInterval()); ASSERT_LE(TransferReceiver::getMinTransferInterval(), rcv.getInterval());
ASSERT_EQ(1000, rcv.getLastTransferTimestampMonotonic().toUSec()); ASSERT_EQ(1000, rcv.getLastTransferTimestampMonotonic().toUSec());
ASSERT_FALSE(rcv.isTimedOut(tsMono(1000))); ASSERT_FALSE(rcv.isTimedOut(tsMono(1000)));
ASSERT_FALSE(rcv.isTimedOut(tsMono(5000))); ASSERT_FALSE(rcv.isTimedOut(tsMono(5000)));
@@ -174,33 +174,47 @@ TEST(TransferReceiver, Basic)
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "", 0, true, 4, 3600), bk)); CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "", 0, true, 4, 3600), bk));
ASSERT_EQ(3600, rcv.getLastTransferTimestampMonotonic().toUSec()); ASSERT_EQ(3600, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
/* /*
* Timeouts * Timeouts
*/ */
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 1, 100000), bk)); // Wrong iface - ignored CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 1, 5000), bk)); // Wrong iface - ignored
CHECK_SINGLE_FRAME(rcv.addFrame(gen(1, "qwe", 0, true, 6, 1500000), bk)); // Accepted due to iface timeout CHECK_SINGLE_FRAME(rcv.addFrame(gen(1, "qwe", 0, true, 6, 1500000), bk)); // Accepted due to iface timeout
ASSERT_EQ(1500000, rcv.getLastTransferTimestampMonotonic().toUSec()); ASSERT_EQ(1500000, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "qwe", 0, true, 7, 1500100), bk)); // Ignored - old iface 0 CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "qwe", 0, true, 7, 1500100), bk)); // Ignored - old iface 0
CHECK_SINGLE_FRAME(rcv.addFrame(gen(1, "qwe", 0, true, 7, 1500100), bk)); CHECK_SINGLE_FRAME(rcv.addFrame(gen(1, "qwe", 0, true, 7, 1500100), bk));
ASSERT_EQ(1500100, rcv.getLastTransferTimestampMonotonic().toUSec()); ASSERT_EQ(1500100, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 7, 1500100), bk)); // Old TID CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 7, 1500100), bk)); // Old TID
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 7, 100000000), bk)); // Accepted - global timeout CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 7, 100000000), bk)); // Accepted - global timeout
ASSERT_EQ(100000000, rcv.getLastTransferTimestampMonotonic().toUSec()); ASSERT_EQ(100000000, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 0, 100000100), bk)); CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 0, 100000100), bk));
ASSERT_EQ(100000100, rcv.getLastTransferTimestampMonotonic().toUSec()); ASSERT_EQ(100000100, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
ASSERT_TRUE(rcv.isTimedOut(tsMono(900000000))); ASSERT_TRUE(rcv.isTimedOut(tsMono(900000000)));
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "\x78\x56" "345678", 0, false, 0, 900000000), bk)); // Global timeout CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "\x78\x56" "345678", 0, false, 0, 900000000), bk)); // Global timeout
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "12345678", 0, false, 0, 900000100), bk)); // Wrong iface CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "12345678", 0, false, 0, 900000100), bk)); // Wrong iface
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "qwe", 1, true, 0, 900000200), bk)); // Wrong iface CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "qwe", 1, true, 0, 900000200), bk)); // Wrong iface
CHECK_COMPLETE( rcv.addFrame(gen(1, "qwe", 1, true, 0, 900000200), bk)); CHECK_COMPLETE( rcv.addFrame(gen(1, "qwe", 1, true, 0, 900000200), bk));
ASSERT_EQ(900000000, rcv.getLastTransferTimestampMonotonic().toUSec()); ASSERT_EQ(900000000, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
ASSERT_FALSE(rcv.isTimedOut(tsMono(1000))); ASSERT_FALSE(rcv.isTimedOut(tsMono(1000)));
ASSERT_FALSE(rcv.isTimedOut(tsMono(900000200))); ASSERT_FALSE(rcv.isTimedOut(tsMono(900000300)));
ASSERT_TRUE(rcv.isTimedOut(tsMono(1000 * 1000000))); ASSERT_TRUE(rcv.isTimedOut(tsMono(990000000)));
ASSERT_LT(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval()); ASSERT_LT(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval());
ASSERT_LE(TransferReceiver::getMinTransferInterval(), rcv.getInterval()); ASSERT_LE(TransferReceiver::getMinTransferInterval(), rcv.getInterval());
ASSERT_GE(TransferReceiver::getMaxTransferInterval(), rcv.getInterval()); ASSERT_GE(TransferReceiver::getMaxTransferInterval(), rcv.getInterval());
+3 -3
View File
@@ -29,7 +29,7 @@ static int sendOne(uavcan::TransferSender& sender, const std::string& data,
TEST(TransferSender, Basic) TEST(TransferSender, Basic)
{ {
uavcan::PoolManager<1> poolmgr; NullAllocator poolmgr;
SystemClockMock clockmock(100); SystemClockMock clockmock(100);
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
@@ -185,7 +185,7 @@ struct TransferSenderTestLoopbackFrameListener : public uavcan::LoopbackFrameLis
TEST(TransferSender, Loopback) TEST(TransferSender, Loopback)
{ {
uavcan::PoolManager<1> poolmgr; NullAllocator poolmgr;
SystemClockMock clockmock(100); SystemClockMock clockmock(100);
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
@@ -226,7 +226,7 @@ TEST(TransferSender, Loopback)
TEST(TransferSender, PassiveMode) TEST(TransferSender, PassiveMode)
{ {
uavcan::PoolManager<1> poolmgr; NullAllocator poolmgr;
SystemClockMock clockmock(100); SystemClockMock clockmock(100);
CanDriverMock driver(2, clockmock); CanDriverMock driver(2, clockmock);
@@ -10,10 +10,8 @@
TEST(TransferTestHelpers, Transfer) TEST(TransferTestHelpers, Transfer)
{ {
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
uavcan::TransferBufferManager<128, 1> mgr(poolmgr); uavcan::TransferBufferManager<128, 1> mgr(pool);
uavcan::TransferBufferAccessor tba(mgr, uavcan::TransferBufferManagerKey(0, uavcan::TransferTypeMessageUnicast)); uavcan::TransferBufferAccessor tba(mgr, uavcan::TransferBufferManagerKey(0, uavcan::TransferTypeMessageUnicast));
uavcan::RxFrame frame(uavcan::Frame(123, uavcan::TransferTypeMessageBroadcast, 1, 0, 0, 0, true), uavcan::RxFrame frame(uavcan::Frame(123, uavcan::TransferTypeMessageBroadcast, 1, 0, 0, 0, true),
@@ -323,3 +323,14 @@ public:
template <int SIZE> void send(const Transfer (&transfers)[SIZE]) { send(transfers, SIZE); } template <int SIZE> void send(const Transfer (&transfers)[SIZE]) { send(transfers, SIZE); }
}; };
/**
* Zero allocator - always fails
*/
class NullAllocator : public uavcan::IPoolAllocator
{
public:
virtual void* allocate(std::size_t) { return NULL; }
virtual void deallocate(const void*) { }
virtual uint16_t getNumBlocks() const { return 0; }
};
+3 -9
View File
@@ -45,11 +45,9 @@ TEST(Map, Basic)
static const int POOL_BLOCKS = 3; static const int POOL_BLOCKS = 3;
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
typedef Map<std::string, std::string, 2> MapType; typedef Map<std::string, std::string, 2> MapType;
std::auto_ptr<MapType> map(new MapType(poolmgr)); std::auto_ptr<MapType> map(new MapType(pool));
// Empty // Empty
ASSERT_FALSE(map->access("hi")); ASSERT_FALSE(map->access("hi"));
@@ -208,11 +206,9 @@ TEST(Map, NoStatic)
static const int POOL_BLOCKS = 3; static const int POOL_BLOCKS = 3;
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
typedef Map<std::string, std::string> MapType; typedef Map<std::string, std::string> MapType;
std::auto_ptr<MapType> map(new MapType(poolmgr)); std::auto_ptr<MapType> map(new MapType(pool));
// Empty // Empty
ASSERT_FALSE(map->access("hi")); ASSERT_FALSE(map->access("hi"));
@@ -241,11 +237,9 @@ TEST(Map, PrimitiveKey)
static const int POOL_BLOCKS = 3; static const int POOL_BLOCKS = 3;
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
typedef Map<short, short, 2> MapType; typedef Map<short, short, 2> MapType;
std::auto_ptr<MapType> map(new MapType(poolmgr)); std::auto_ptr<MapType> map(new MapType(pool));
// Empty // Empty
ASSERT_FALSE(map->access(1)); ASSERT_FALSE(map->access(1));
+3 -9
View File
@@ -70,11 +70,9 @@ TEST(Multiset, Basic)
static const int POOL_BLOCKS = 3; static const int POOL_BLOCKS = 3;
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
typedef Multiset<std::string, 2> MultisetType; typedef Multiset<std::string, 2> MultisetType;
std::auto_ptr<MultisetType> mset(new MultisetType(poolmgr)); std::auto_ptr<MultisetType> mset(new MultisetType(pool));
typedef SummationOperator<std::string> StringConcatenationOperator; typedef SummationOperator<std::string> StringConcatenationOperator;
@@ -220,11 +218,9 @@ TEST(Multiset, PrimitiveKey)
static const int POOL_BLOCKS = 3; static const int POOL_BLOCKS = 3;
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
typedef Multiset<int, 2> MultisetType; typedef Multiset<int, 2> MultisetType;
std::auto_ptr<MultisetType> mset(new MultisetType(poolmgr)); std::auto_ptr<MultisetType> mset(new MultisetType(pool));
// Empty // Empty
mset->removeFirst(8); mset->removeFirst(8);
@@ -272,11 +268,9 @@ TEST(Multiset, NoncopyableWithCounter)
static const int POOL_BLOCKS = 3; static const int POOL_BLOCKS = 3;
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool; uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<2> poolmgr;
poolmgr.addPool(&pool);
typedef Multiset<NoncopyableWithCounter, 2> MultisetType; typedef Multiset<NoncopyableWithCounter, 2> MultisetType;
std::auto_ptr<MultisetType> mset(new MultisetType(poolmgr)); std::auto_ptr<MultisetType> mset(new MultisetType(pool));
ASSERT_EQ(0, NoncopyableWithCounter::num_objects); ASSERT_EQ(0, NoncopyableWithCounter::num_objects);
ASSERT_EQ(0, mset->emplace()->value); ASSERT_EQ(0, mset->emplace()->value);
@@ -601,11 +601,6 @@ public:
{ {
return (iface_index >= num_ifaces_) ? nullptr : static_cast<SocketCanIface*>(ifaces_[iface_index]); return (iface_index >= num_ifaces_) ? nullptr : static_cast<SocketCanIface*>(ifaces_[iface_index]);
} }
const SocketCanIface* getIface(std::uint8_t iface_index) const override
{
return (iface_index >= num_ifaces_) ? nullptr : static_cast<const SocketCanIface*>(ifaces_[iface_index]);
}
std::uint8_t getNumIfaces() const override { return num_ifaces_; } std::uint8_t getNumIfaces() const override { return num_ifaces_; }
@@ -61,8 +61,6 @@ public:
virtual uavcan::ICanIface* getIface(uavcan::uint8_t iface_index); virtual uavcan::ICanIface* getIface(uavcan::uint8_t iface_index);
virtual const uavcan::ICanIface* getIface(uavcan::uint8_t iface_index) const;
virtual uavcan::uint8_t getNumIfaces() const; virtual uavcan::uint8_t getNumIfaces() const;
}; };
@@ -114,7 +114,7 @@ $(CPPOBJ): $(OBJDIR)/%.o: %.cpp
$(CPPC) -c $(DEF) $(INC) $(CPPFLAGS) $< -o $@ $(CPPC) -c $(DEF) $(INC) $(CPPFLAGS) $< -o $@
clean: clean:
rm -rf $(BUILDDIR) rm -rf $(BUILDDIR) dsdlc_generated
size: $(ELF) size: $(ELF)
@if [ -f $(ELF) ]; then echo; $(SIZE) $(ELF); echo; fi; @if [ -f $(ELF) ]; then echo; $(SIZE) $(ELF); echo; fi;
@@ -17,7 +17,8 @@ CPPSRC = src/main.cpp src/dummy.cpp
UDEFS = -DUAVCAN_STM32_CHIBIOS=1 \ UDEFS = -DUAVCAN_STM32_CHIBIOS=1 \
-DUAVCAN_STM32_TIMER_NUMBER=6 \ -DUAVCAN_STM32_TIMER_NUMBER=6 \
-DUAVCAN_TINY=1 \ -DUAVCAN_TINY=1 \
-DUAVCAN_STM32_NUM_IFACES=2 -DUAVCAN_STM32_NUM_IFACES=2 \
-DUAVCAN_MEM_POOL_BLOCK_SIZE=48
include ../../../libuavcan/include.mk include ../../../libuavcan/include.mk
CPPSRC += $(LIBUAVCAN_SRC) CPPSRC += $(LIBUAVCAN_SRC)