INode class. Publisher, Subscriber, ServiceServer, ServiceClient now accept INode in constructor instead of the bunch of independent params. Self NodeID now being configured via setNodeID() method instead of constructor param

This commit is contained in:
Pavel Kirienko 2014-03-14 19:54:27 +04:00
parent 15cbf96378
commit 613efa49b9
22 changed files with 211 additions and 181 deletions

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
*/
#pragma once
#include <uavcan/node/scheduler.hpp>
#include <uavcan/node/marshal_buffer.hpp>
namespace uavcan
{
class INode
{
public:
virtual ~INode() { }
virtual IAllocator& getAllocator() = 0;
virtual Scheduler& getScheduler() = 0;
virtual const Scheduler& getScheduler() const = 0;
virtual IMarshalBufferProvider& getMarshalBufferProvider() = 0;
Dispatcher& getDispatcher() { return getScheduler().getDispatcher(); }
const Dispatcher& getDispatcher() const { return getScheduler().getDispatcher(); }
ISystemClock& getSystemClock() { return getScheduler().getSystemClock(); }
MonotonicTime getMonotonicTime() const { return getScheduler().getMonotonicTime(); }
UtcTime getUtcTime() const { return getScheduler().getUtcTime(); }
NodeID getNodeID() const { return getScheduler().getDispatcher().getNodeID(); }
bool setNodeID(NodeID nid)
{
return getScheduler().getDispatcher().setNodeID(nid);
}
int spin(MonotonicTime deadline)
{
return getScheduler().spin(deadline);
}
int spin(MonotonicDuration duration)
{
return getScheduler().spin(getMonotonicTime() + duration);
}
};
}

View File

@ -4,9 +4,8 @@
#pragma once
#include <uavcan/node/scheduler.hpp>
#include <uavcan/node/abstract_node.hpp>
#include <uavcan/data_type.hpp>
#include <uavcan/node/marshal_buffer.hpp>
#include <uavcan/node/global_data_type_registry.hpp>
#include <uavcan/util/lazy_constructor.hpp>
#include <uavcan/debug.hpp>
@ -30,8 +29,7 @@ class GenericPublisher
const MonotonicDuration max_transfer_interval_; // TODO: memory usage can be reduced
MonotonicDuration tx_timeout_;
Scheduler& scheduler_;
IMarshalBufferProvider& buffer_provider_;
INode& node_;
LazyConstructor<TransferSender> sender_;
bool checkInit()
@ -50,15 +48,15 @@ class GenericPublisher
return false;
}
sender_.template construct<Dispatcher&, const DataTypeDescriptor&, CanTxQueue::Qos, MonotonicDuration>
(scheduler_.getDispatcher(), *descr, CanTxQueue::Qos(Qos), max_transfer_interval_);
(node_.getDispatcher(), *descr, CanTxQueue::Qos(Qos), max_transfer_interval_);
return true;
}
MonotonicTime getTxDeadline() const { return scheduler_.getMonotonicTimestamp() + tx_timeout_; }
MonotonicTime getTxDeadline() const { return node_.getMonotonicTime() + tx_timeout_; }
IMarshalBuffer* getBuffer()
{
return buffer_provider_.getBuffer(BitLenToByteLen<DataStruct::MaxBitLen>::Result);
return node_.getMarshalBufferProvider().getBuffer(BitLenToByteLen<DataStruct::MaxBitLen>::Result);
}
int genericPublish(const DataStruct& message, TransferType transfer_type, NodeID dst_node_id,
@ -94,12 +92,11 @@ class GenericPublisher
}
public:
GenericPublisher(Scheduler& scheduler, IMarshalBufferProvider& buffer_provider, MonotonicDuration tx_timeout,
GenericPublisher(INode& node, MonotonicDuration tx_timeout,
MonotonicDuration max_transfer_interval = TransferSender::getDefaultMaxTransferInterval())
: max_transfer_interval_(max_transfer_interval)
, tx_timeout_(tx_timeout)
, scheduler_(scheduler)
, buffer_provider_(buffer_provider)
, node_(node)
{
setTxTimeout(tx_timeout);
#if UAVCAN_DEBUG
@ -132,7 +129,7 @@ public:
tx_timeout_ = tx_timeout;
}
Scheduler& getScheduler() const { return scheduler_; }
INode& getNode() const { return node_; }
};
}

View File

@ -4,7 +4,7 @@
#pragma once
#include <uavcan/node/scheduler.hpp>
#include <uavcan/node/abstract_node.hpp>
#include <uavcan/data_type.hpp>
#include <uavcan/node/global_data_type_registry.hpp>
#include <uavcan/util/compile_time.hpp>
@ -107,8 +107,7 @@ class GenericSubscriber : Noncopyable
using ReceivedDataStructure<DataStruct>::setTransfer;
};
Scheduler& scheduler_;
IAllocator& allocator_;
INode& node_;
LazyConstructor<TransferForwarder> forwarder_;
ReceivedDataStructureSpec message_;
uint32_t failure_count_;
@ -128,7 +127,8 @@ class GenericSubscriber : Noncopyable
UAVCAN_TRACE("GenericSubscriber", "Type [%s] is not registered", DataSpec::getDataTypeFullName());
return false;
}
forwarder_.template construct<SelfType&, const DataTypeDescriptor&, IAllocator&>(*this, *descr, allocator_);
forwarder_.template construct<SelfType&, const DataTypeDescriptor&, IAllocator&>
(*this, *descr, node_.getAllocator());
return true;
}
@ -170,7 +170,7 @@ class GenericSubscriber : Noncopyable
return -1;
}
if (!(scheduler_.getDispatcher().*registration_method)(forwarder_))
if (!(node_.getDispatcher().*registration_method)(forwarder_))
{
UAVCAN_TRACE("GenericSubscriber", "Failed to register transfer listener [%s]",
DataSpec::getDataTypeFullName());
@ -180,9 +180,8 @@ class GenericSubscriber : Noncopyable
}
protected:
GenericSubscriber(Scheduler& scheduler, IAllocator& allocator)
: scheduler_(scheduler)
, allocator_(allocator)
explicit GenericSubscriber(INode& node)
: node_(node)
, failure_count_(0)
{ }
@ -209,9 +208,9 @@ protected:
{
if (forwarder_)
{
scheduler_.getDispatcher().unregisterMessageListener(forwarder_);
scheduler_.getDispatcher().unregisterServiceRequestListener(forwarder_);
scheduler_.getDispatcher().unregisterServiceResponseListener(forwarder_);
node_.getDispatcher().unregisterMessageListener(forwarder_);
node_.getDispatcher().unregisterServiceRequestListener(forwarder_);
node_.getDispatcher().unregisterServiceResponseListener(forwarder_);
}
}
@ -222,7 +221,7 @@ protected:
ReceivedDataStructure<DataStruct>& getReceivedStructStorage() { return message_; }
public:
Scheduler& getScheduler() const { return scheduler_; }
INode& getNode() const { return node_; }
};
}

View File

@ -17,10 +17,9 @@ class Publisher : protected GenericPublisher<DataType_, DataType_>
public:
typedef DataType_ DataType;
Publisher(Scheduler& scheduler, IMarshalBufferProvider& buffer_provider,
MonotonicDuration tx_timeout = getDefaultTxTimeout(),
MonotonicDuration max_transfer_interval = TransferSender::getDefaultMaxTransferInterval())
: BaseType(scheduler, buffer_provider, tx_timeout, max_transfer_interval)
explicit Publisher(INode& node, MonotonicDuration tx_timeout = getDefaultTxTimeout(),
MonotonicDuration max_transfer_interval = TransferSender::getDefaultMaxTransferInterval())
: BaseType(node, tx_timeout, max_transfer_interval)
{
#if UAVCAN_DEBUG
assert(getTxTimeout() == tx_timeout); // Making sure default values are OK
@ -49,7 +48,7 @@ public:
using BaseType::getMaxTxTimeout;
using BaseType::getTxTimeout;
using BaseType::setTxTimeout;
using BaseType::getScheduler;
using BaseType::getNode;
};
}

View File

@ -26,7 +26,7 @@ protected:
virtual ~DeadlineHandler() { stop(); }
public:
virtual void handleDeadline(MonotonicTime current_timestamp) = 0;
virtual void handleDeadline(MonotonicTime current) = 0;
void startWithDeadline(MonotonicTime deadline);
void startWithDelay(MonotonicDuration delay);
@ -50,7 +50,7 @@ public:
bool doesExist(const DeadlineHandler* mdh) const;
unsigned int getNumHandlers() const { return handlers_.getLength(); }
MonotonicTime pollAndGetMonotonicTimestamp(ISystemClock& sysclock);
MonotonicTime pollAndGetMonotonicTime(ISystemClock& sysclock);
MonotonicTime getEarliestDeadline() const;
};
@ -75,9 +75,8 @@ class Scheduler : Noncopyable
void pollCleanup(MonotonicTime mono_ts, uint32_t num_frames_processed_with_last_spin);
public:
Scheduler(ICanDriver& can_driver, IAllocator& allocator, ISystemClock& sysclock, IOutgoingTransferRegistry& otr,
NodeID self_node_id)
: dispatcher_(can_driver, allocator, sysclock, otr, self_node_id)
Scheduler(ICanDriver& can_driver, IAllocator& allocator, ISystemClock& sysclock, IOutgoingTransferRegistry& otr)
: dispatcher_(can_driver, allocator, sysclock, otr)
, prev_cleanup_ts_(sysclock.getMonotonic())
, deadline_resolution_(MonotonicDuration::fromMSec(DefaultDeadlineResolutionMs))
, cleanup_period_(MonotonicDuration::fromMSec(DefaultCleanupPeriodMs))
@ -86,11 +85,13 @@ public:
int spin(MonotonicTime deadline);
DeadlineScheduler& getDeadlineScheduler() { return deadline_scheduler_; }
Dispatcher& getDispatcher() { return dispatcher_; }
ISystemClock& getSystemClock() { return dispatcher_.getSystemClock(); }
MonotonicTime getMonotonicTimestamp() const { return dispatcher_.getSystemClock().getMonotonic(); }
UtcTime getUtcTimestamp() const { return dispatcher_.getSystemClock().getUtc(); }
Dispatcher& getDispatcher() { return dispatcher_; }
const Dispatcher& getDispatcher() const { return dispatcher_; }
ISystemClock& getSystemClock() { return dispatcher_.getSystemClock(); }
MonotonicTime getMonotonicTime() const { return dispatcher_.getSystemClock().getMonotonic(); }
UtcTime getUtcTime() const { return dispatcher_.getSystemClock().getUtc(); }
MonotonicDuration getDeadlineResolution() const { return deadline_resolution_; }
void setDeadlineResolution(MonotonicDuration res)

View File

@ -73,7 +73,6 @@ private:
typedef GenericSubscriber<DataType, ResponseType, TransferListenerType> SubscriberType;
PublisherType publisher_;
IAllocator& allocator_;
Callback callback_;
MonotonicDuration request_timeout_;
bool pending_;
@ -128,12 +127,10 @@ private:
}
public:
ServiceClient(Scheduler& scheduler, IAllocator& allocator, IMarshalBufferProvider& buffer_provider,
const Callback& callback = Callback())
: SubscriberType(scheduler, allocator)
, DeadlineHandler(scheduler)
, publisher_(scheduler, buffer_provider, getDefaultRequestTimeout())
, allocator_(allocator)
explicit ServiceClient(INode& node, const Callback& callback = Callback())
: SubscriberType(node)
, DeadlineHandler(node.getScheduler())
, publisher_(node, getDefaultRequestTimeout())
, callback_(callback)
, request_timeout_(getDefaultRequestTimeout())
, pending_(false)
@ -177,8 +174,8 @@ public:
*/
const OutgoingTransferRegistryKey otr_key(descr->getID(), TransferTypeServiceRequest, server_node_id);
const MonotonicTime otr_deadline =
SubscriberType::getScheduler().getMonotonicTimestamp() + TransferSender::getDefaultMaxTransferInterval();
TransferID* const otr_tid = SubscriberType::getScheduler().getDispatcher().getOutgoingTransferRegistry()
SubscriberType::getNode().getMonotonicTime() + TransferSender::getDefaultMaxTransferInterval();
TransferID* const otr_tid = SubscriberType::getNode().getDispatcher().getOutgoingTransferRegistry()
.accessOrCreate(otr_key, otr_deadline);
if (!otr_tid)
{

View File

@ -57,9 +57,9 @@ private:
}
public:
ServiceServer(Scheduler& scheduler, IAllocator& allocator, IMarshalBufferProvider& buffer_provider)
: SubscriberType(scheduler, allocator)
, publisher_(scheduler, buffer_provider, getDefaultTxTimeout())
explicit ServiceServer(INode& node)
: SubscriberType(node)
, publisher_(node, getDefaultTxTimeout())
, callback_()
, response_failure_count_(0)
{

View File

@ -36,8 +36,8 @@ class Subscriber : public GenericSubscriber<DataType_, DataType_,
public:
typedef DataType_ DataType;
Subscriber(Scheduler& scheduler, IAllocator& allocator)
: BaseType(scheduler, allocator)
explicit Subscriber(INode& node)
: BaseType(node)
, callback_()
{
StaticAssert<DataTypeKind(DataType::DataTypeKind) == DataTypeKindMessage>::check();

View File

@ -31,7 +31,7 @@ class Timer : private DeadlineHandler
{
MonotonicDuration period_;
void handleDeadline(MonotonicTime current_timestamp);
void handleDeadline(MonotonicTime current);
public:
using DeadlineHandler::stop;

View File

@ -51,17 +51,15 @@ class Dispatcher : Noncopyable
ListenerRegister lsrv_req_;
ListenerRegister lsrv_resp_;
const NodeID self_node_id_;
NodeID self_node_id_;
void handleFrame(const CanRxFrame& can_frame);
public:
Dispatcher(ICanDriver& driver, IAllocator& allocator, ISystemClock& sysclock, IOutgoingTransferRegistry& otr,
NodeID self_node_id)
Dispatcher(ICanDriver& driver, IAllocator& allocator, ISystemClock& sysclock, IOutgoingTransferRegistry& otr)
: canio_(driver, allocator, sysclock)
, sysclock_(sysclock)
, outgoing_transfer_reg_(otr)
, self_node_id_(self_node_id)
{ }
int spin(MonotonicTime deadline);
@ -87,7 +85,8 @@ public:
IOutgoingTransferRegistry& getOutgoingTransferRegistry() { return outgoing_transfer_reg_; }
NodeID getSelfNodeID() const { return self_node_id_; }
NodeID getNodeID() const { return self_node_id_; }
bool setNodeID(NodeID nid);
const ISystemClock& getSystemClock() const { return sysclock_; }
ISystemClock& getSystemClock() { return sysclock_; }

View File

@ -21,7 +21,7 @@ void DeadlineHandler::startWithDeadline(MonotonicTime deadline)
void DeadlineHandler::startWithDelay(MonotonicDuration delay)
{
startWithDeadline(scheduler_.getMonotonicTimestamp() + delay);
startWithDeadline(scheduler_.getMonotonicTime() + delay);
}
void DeadlineHandler::stop()
@ -80,7 +80,7 @@ bool DeadlineScheduler::doesExist(const DeadlineHandler* mdh) const
return false;
}
MonotonicTime DeadlineScheduler::pollAndGetMonotonicTimestamp(ISystemClock& sysclock)
MonotonicTime DeadlineScheduler::pollAndGetMonotonicTime(ISystemClock& sysclock)
{
while (true)
{
@ -117,7 +117,7 @@ MonotonicTime DeadlineScheduler::getEarliestDeadline() const
MonotonicTime Scheduler::computeDispatcherSpinDeadline(MonotonicTime spin_deadline) const
{
const MonotonicTime earliest = std::min(deadline_scheduler_.getEarliestDeadline(), spin_deadline);
const MonotonicTime ts = getMonotonicTimestamp();
const MonotonicTime ts = getMonotonicTime();
if (earliest > ts)
{
if (ts - earliest > deadline_resolution_)
@ -148,7 +148,7 @@ int Scheduler::spin(MonotonicTime deadline)
if (retval < 0)
break;
const MonotonicTime ts = deadline_scheduler_.pollAndGetMonotonicTimestamp(getSystemClock());
const MonotonicTime ts = deadline_scheduler_.pollAndGetMonotonicTime(getSystemClock());
pollCleanup(ts, retval);
if (ts >= deadline)
break;

View File

@ -8,7 +8,7 @@
namespace uavcan
{
void Timer::handleDeadline(MonotonicTime current_timestamp)
void Timer::handleDeadline(MonotonicTime current)
{
assert(!isRunning());
@ -18,7 +18,7 @@ void Timer::handleDeadline(MonotonicTime current_timestamp)
startWithDeadline(scheduled_time + period_);
// Application can re-register the timer with different params, it's OK
handleTimerEvent(TimerEvent(scheduled_time, current_timestamp));
handleTimerEvent(TimerEvent(scheduled_time, current));
}
void Timer::startOneShotWithDeadline(MonotonicTime deadline)

View File

@ -69,7 +69,7 @@ void Dispatcher::handleFrame(const CanRxFrame& can_frame)
}
if ((frame.getDstNodeID() != NodeID::Broadcast) &&
(frame.getDstNodeID() != getSelfNodeID()))
(frame.getDstNodeID() != getNodeID()))
{
return;
}
@ -117,7 +117,7 @@ int Dispatcher::spin(MonotonicTime deadline)
int Dispatcher::send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline,
CanTxQueue::Qos qos)
{
if (frame.getSrcNodeID() != getSelfNodeID())
if (frame.getSrcNodeID() != getNodeID())
{
assert(0);
return -1;
@ -188,4 +188,14 @@ void Dispatcher::unregisterServiceResponseListener(TransferListenerBase* listene
lsrv_resp_.remove(listener);
}
bool Dispatcher::setNodeID(NodeID nid)
{
if (nid.isUnicast() && !self_node_id_.isValid())
{
self_node_id_ = nid;
return true;
}
return false;
}
}

View File

@ -14,7 +14,7 @@ int TransferSender::send(const uint8_t* payload, int payload_len, MonotonicTime
MonotonicTime blocking_deadline, TransferType transfer_type, NodeID dst_node_id,
TransferID tid)
{
Frame frame(data_type_.getID(), transfer_type, dispatcher_.getSelfNodeID(), dst_node_id, 0, tid);
Frame frame(data_type_.getID(), transfer_type, dispatcher_.getNodeID(), dst_node_id, 0, tid);
if (frame.getMaxPayloadLen() >= payload_len) // Single Frame Transfer
{

View File

@ -7,24 +7,16 @@
#include <uavcan/mavlink/Message.hpp>
#include "../clock.hpp"
#include "../transport/can/can.hpp"
#include "test_node.hpp"
TEST(Publisher, Basic)
{
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
SystemClockMock clock_mock(100);
CanDriverMock can_driver(2, clock_mock);
TestNode node(can_driver, clock_mock, 1);
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
uavcan::Scheduler sch(can_driver, poolmgr, clock_mock, out_trans_reg, uavcan::NodeID(1));
uavcan::MarshalBufferProvider<> buffer_provider;
uavcan::Publisher<uavcan::mavlink::Message> publisher(sch, buffer_provider);
uavcan::Publisher<uavcan::mavlink::Message> publisher(node);
std::cout <<
"sizeof(uavcan::Publisher<uavcan::mavlink::Message>): " <<
@ -61,7 +53,7 @@ TEST(Publisher, Basic)
// uint_fast16_t data_type_id, TransferType transfer_type, NodeID src_node_id, NodeID dst_node_id,
// uint_fast8_t frame_index, TransferID transfer_id, bool last_frame = false
uavcan::Frame expected_frame(uavcan::mavlink::Message::DefaultDataTypeID, uavcan::TransferTypeMessageBroadcast,
sch.getDispatcher().getSelfNodeID(), uavcan::NodeID::Broadcast, 0, 0, true);
node.getNodeID(), uavcan::NodeID::Broadcast, 0, 0, true);
expected_frame.setPayload(expected_transfer_payload, 7);
uavcan::CanFrame expected_can_frame;
@ -76,7 +68,7 @@ TEST(Publisher, Basic)
ASSERT_LT(0, publisher.broadcast(msg));
expected_frame = uavcan::Frame(uavcan::mavlink::Message::DefaultDataTypeID, uavcan::TransferTypeMessageBroadcast,
sch.getDispatcher().getSelfNodeID(), uavcan::NodeID::Broadcast, 0, 1, true);
node.getNodeID(), uavcan::NodeID::Broadcast, 0, 1, true);
expected_frame.setPayload(expected_transfer_payload, 7);
ASSERT_TRUE(expected_frame.compile(expected_can_frame));
@ -97,7 +89,7 @@ TEST(Publisher, Basic)
// uint_fast16_t data_type_id, TransferType transfer_type, NodeID src_node_id, NodeID dst_node_id,
// uint_fast8_t frame_index, TransferID transfer_id, bool last_frame = false
uavcan::Frame expected_frame(uavcan::mavlink::Message::DefaultDataTypeID, uavcan::TransferTypeMessageUnicast,
sch.getDispatcher().getSelfNodeID(), uavcan::NodeID(0x44), 0, 0, true);
node.getNodeID(), uavcan::NodeID(0x44), 0, 0, true);
expected_frame.setPayload(expected_transfer_payload, 7);
uavcan::CanFrame expected_can_frame;

View File

@ -33,7 +33,8 @@ TEST(Scheduler, Timers)
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
uavcan::Scheduler sch(can_driver, poolmgr, clock_driver, out_trans_reg, uavcan::NodeID(1));
uavcan::Scheduler sch(can_driver, poolmgr, clock_driver, out_trans_reg);
sch.getDispatcher().setNodeID(1);
/*
* Registration

View File

@ -12,6 +12,7 @@
#include <queue>
#include "../clock.hpp"
#include "../transport/can/can.hpp"
#include "test_node.hpp"
template <typename DataType>
@ -53,29 +54,6 @@ static void stringServiceServerCallback(const uavcan::ReceivedDataStructure<root
}
struct MakeshiftNode : uavcan::Noncopyable
{
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
SystemClockDriver clock_driver;
uavcan::MarshalBufferProvider<> buffer_provider;
uavcan::OutgoingTransferRegistry<8> otr;
uavcan::Scheduler scheduler;
MakeshiftNode(uavcan::ICanDriver& can_driver, uavcan::NodeID self_node_id)
: otr(poolmgr)
, scheduler(can_driver, poolmgr, clock_driver, otr, self_node_id)
{
poolmgr.addPool(&pool);
}
void spin(uavcan::MonotonicDuration duration)
{
scheduler.spin(clock_driver.getMonotonic() + duration);
}
};
struct PairableCanDriver : public uavcan::ICanDriver, public uavcan::ICanIface
{
uavcan::ISystemClock& clock;
@ -144,18 +122,16 @@ struct PairableCanDriver : public uavcan::ICanDriver, public uavcan::ICanIface
TEST(ServiceClient, Basic)
{
SystemClockDriver clock;
PairableCanDriver can_a(clock), can_b(clock);
can_a.linkTogether(&can_b);
MakeshiftNode node_a(can_a, 1), node_b(can_b, 2);
TestNode node_a(can_a, clock, 1), node_b(can_b, clock, 2);
// Type registration
uavcan::GlobalDataTypeRegistry::instance().reset();
uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator;
// Server
uavcan::ServiceServer<root_ns_a::StringService> server(node_a.scheduler, node_a.poolmgr, node_a.buffer_provider);
uavcan::ServiceServer<root_ns_a::StringService> server(node_a);
ASSERT_EQ(1, server.start(stringServiceServerCallback));
{
@ -165,17 +141,17 @@ TEST(ServiceClient, Basic)
typename ServiceCallResultHandler<root_ns_a::StringService>::Binder > ClientType;
ServiceCallResultHandler<root_ns_a::StringService> handler;
ClientType client1(node_b.scheduler, node_b.poolmgr, node_b.buffer_provider);
ClientType client2(node_b.scheduler, node_b.poolmgr, node_b.buffer_provider);
ClientType client3(node_b.scheduler, node_b.poolmgr, node_b.buffer_provider);
ClientType client1(node_b);
ClientType client2(node_b);
ClientType client3(node_b);
client1.setCallback(handler.bind());
client2.setCallback(client1.getCallback());
client3.setCallback(client1.getCallback());
client3.setRequestTimeout(uavcan::MonotonicDuration::fromMSec(100));
ASSERT_EQ(1, node_a.scheduler.getDispatcher().getNumServiceRequestListeners());
ASSERT_EQ(0, node_b.scheduler.getDispatcher().getNumServiceResponseListeners()); // NOT listening!
ASSERT_EQ(1, node_a.getDispatcher().getNumServiceRequestListeners());
ASSERT_EQ(0, node_b.getDispatcher().getNumServiceResponseListeners()); // NOT listening!
root_ns_a::StringService::Request request;
request.string_request = "Hello world";
@ -184,7 +160,7 @@ TEST(ServiceClient, Basic)
ASSERT_LT(0, client2.call(1, request)); // OK
ASSERT_LT(0, client3.call(99, request)); // Will timeout!
ASSERT_EQ(3, node_b.scheduler.getDispatcher().getNumServiceResponseListeners()); // Listening now!
ASSERT_EQ(3, node_b.getDispatcher().getNumServiceResponseListeners()); // Listening now!
ASSERT_TRUE(client1.isPending());
ASSERT_TRUE(client2.isPending());
@ -193,7 +169,7 @@ TEST(ServiceClient, Basic)
node_a.spin(uavcan::MonotonicDuration::fromMSec(10));
node_b.spin(uavcan::MonotonicDuration::fromMSec(10));
ASSERT_EQ(1, node_b.scheduler.getDispatcher().getNumServiceResponseListeners()); // Third is still listening!
ASSERT_EQ(1, node_b.getDispatcher().getNumServiceResponseListeners()); // Third is still listening!
ASSERT_FALSE(client1.isPending());
ASSERT_FALSE(client2.isPending());
@ -211,7 +187,7 @@ TEST(ServiceClient, Basic)
ASSERT_FALSE(client2.isPending());
ASSERT_FALSE(client3.isPending());
ASSERT_EQ(0, node_b.scheduler.getDispatcher().getNumServiceResponseListeners()); // Third has timed out :(
ASSERT_EQ(0, node_b.getDispatcher().getNumServiceResponseListeners()); // Third has timed out :(
// Validating
ASSERT_TRUE(handler.match(ResultType::ErrorTimeout, 99, root_ns_a::StringService::Response()));
@ -219,11 +195,11 @@ TEST(ServiceClient, Basic)
// Stray request
ASSERT_LT(0, client3.call(99, request)); // Will timeout!
ASSERT_TRUE(client3.isPending());
ASSERT_EQ(1, node_b.scheduler.getDispatcher().getNumServiceResponseListeners());
ASSERT_EQ(1, node_b.getDispatcher().getNumServiceResponseListeners());
}
// All destroyed - nobody listening
ASSERT_EQ(0, node_b.scheduler.getDispatcher().getNumServiceResponseListeners());
ASSERT_EQ(0, node_b.getDispatcher().getNumServiceResponseListeners());
}

View File

@ -8,6 +8,7 @@
#include <root_ns_a/StringService.hpp>
#include "../clock.hpp"
#include "../transport/can/can.hpp"
#include "test_node.hpp"
struct ServerImpl
@ -36,30 +37,22 @@ struct ServerImpl
TEST(ServiceServer, Basic)
{
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
// Manual type registration - we can't rely on the GDTR state
uavcan::GlobalDataTypeRegistry::instance().reset();
uavcan::DefaultDataTypeRegistrator<root_ns_a::StringService> _registrator;
SystemClockDriver clock_driver;
CanDriverMock can_driver(1, clock_driver);
uavcan::MarshalBufferProvider<> buffer_provider;
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
uavcan::Scheduler sch(can_driver, poolmgr, clock_driver, out_trans_reg, uavcan::NodeID(1));
TestNode node(can_driver, clock_driver, 1);
ServerImpl impl("456");
{
uavcan::ServiceServer<root_ns_a::StringService, ServerImpl::Binder> server(sch, poolmgr, buffer_provider);
uavcan::ServiceServer<root_ns_a::StringService, ServerImpl::Binder> server(node);
ASSERT_EQ(0, sch.getDispatcher().getNumServiceRequestListeners());
ASSERT_EQ(0, node.getDispatcher().getNumServiceRequestListeners());
server.start(impl.bind());
ASSERT_EQ(1, sch.getDispatcher().getNumServiceRequestListeners());
ASSERT_EQ(1, node.getDispatcher().getNumServiceRequestListeners());
/*
* Request frames
@ -78,7 +71,7 @@ TEST(ServiceServer, Basic)
can_driver.ifaces[0].pushRx(rx_frame);
}
sch.spin(clock_driver.getMonotonic() + uavcan::MonotonicDuration::fromUSec(10000));
node.spin(clock_driver.getMonotonic() + uavcan::MonotonicDuration::fromUSec(10000));
/*
* Responses (MFT)
@ -113,7 +106,7 @@ TEST(ServiceServer, Basic)
ASSERT_EQ(0, server.getRequestFailureCount());
ASSERT_EQ(0, server.getResponseFailureCount());
ASSERT_EQ(1, sch.getDispatcher().getNumServiceRequestListeners());
ASSERT_EQ(1, node.getDispatcher().getNumServiceRequestListeners());
}
ASSERT_EQ(0, sch.getDispatcher().getNumServiceRequestListeners());
ASSERT_EQ(0, node.getDispatcher().getNumServiceRequestListeners());
}

View File

@ -9,6 +9,7 @@
#include <root_ns_a/EmptyMessage.hpp>
#include "../clock.hpp"
#include "../transport/can/can.hpp"
#include "test_node.hpp"
template <typename DataType>
@ -59,27 +60,20 @@ struct SubscriptionListener
TEST(Subscriber, Basic)
{
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
// Manual type registration - we can't rely on the GDTR state
uavcan::GlobalDataTypeRegistry::instance().reset();
uavcan::DefaultDataTypeRegistrator<uavcan::mavlink::Message> _registrator;
SystemClockDriver clock_driver;
CanDriverMock can_driver(2, clock_driver);
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
uavcan::Scheduler sch(can_driver, poolmgr, clock_driver, out_trans_reg, uavcan::NodeID(1));
TestNode node(can_driver, clock_driver, 1);
typedef SubscriptionListener<uavcan::mavlink::Message> Listener;
uavcan::Subscriber<uavcan::mavlink::Message, Listener::ExtendedBinder> sub_extended(sch, poolmgr);
uavcan::Subscriber<uavcan::mavlink::Message, Listener::ExtendedBinder> sub_extended2(sch, poolmgr); // Not used
uavcan::Subscriber<uavcan::mavlink::Message, Listener::SimpleBinder> sub_simple(sch, poolmgr);
uavcan::Subscriber<uavcan::mavlink::Message, Listener::SimpleBinder> sub_simple2(sch, poolmgr); // Not used
uavcan::Subscriber<uavcan::mavlink::Message, Listener::ExtendedBinder> sub_extended(node);
uavcan::Subscriber<uavcan::mavlink::Message, Listener::ExtendedBinder> sub_extended2(node); // Not used
uavcan::Subscriber<uavcan::mavlink::Message, Listener::SimpleBinder> sub_simple(node);
uavcan::Subscriber<uavcan::mavlink::Message, Listener::SimpleBinder> sub_simple2(node); // Not used
std::cout <<
"sizeof(uavcan::Subscriber<uavcan::mavlink::Message, Listener::ExtendedBinder>): " <<
@ -115,7 +109,7 @@ TEST(Subscriber, Basic)
{
uavcan::TransferType tt = (i & 1) ? uavcan::TransferTypeMessageUnicast : uavcan::TransferTypeMessageBroadcast;
uavcan::NodeID dni = (tt == uavcan::TransferTypeMessageBroadcast) ?
uavcan::NodeID::Broadcast : sch.getDispatcher().getSelfNodeID();
uavcan::NodeID::Broadcast : node.getDispatcher().getNodeID();
// uint_fast16_t data_type_id, TransferType transfer_type, NodeID src_node_id, NodeID dst_node_id,
// uint_fast8_t frame_index, TransferID transfer_id, bool last_frame
uavcan::Frame frame(uavcan::mavlink::Message::DefaultDataTypeID, tt, uavcan::NodeID(i + 100), dni, 0, i, true);
@ -127,19 +121,19 @@ TEST(Subscriber, Basic)
/*
* Reception
*/
ASSERT_EQ(0, sch.getDispatcher().getNumMessageListeners());
ASSERT_EQ(0, node.getDispatcher().getNumMessageListeners());
ASSERT_EQ(1, sub_extended.start(listener.bindExtended()));
ASSERT_EQ(1, sub_extended2.start(listener.bindExtended()));
ASSERT_EQ(1, sub_simple.start(listener.bindSimple()));
ASSERT_EQ(1, sub_simple2.start(listener.bindSimple()));
ASSERT_EQ(4, sch.getDispatcher().getNumMessageListeners());
ASSERT_EQ(4, node.getDispatcher().getNumMessageListeners());
sub_extended2.stop(); // These are not used - making sure they aren't receiving anything
sub_simple2.stop();
ASSERT_EQ(2, sch.getDispatcher().getNumMessageListeners());
ASSERT_EQ(2, node.getDispatcher().getNumMessageListeners());
for (unsigned int i = 0; i < rx_frames.size(); i++)
{
@ -147,7 +141,7 @@ TEST(Subscriber, Basic)
can_driver.ifaces[1].pushRx(rx_frames[i]);
}
ASSERT_LE(0, sch.spin(clock_driver.getMonotonic() + durMono(10000)));
ASSERT_LE(0, node.spin(clock_driver.getMonotonic() + durMono(10000)));
/*
* Validation
@ -175,14 +169,14 @@ TEST(Subscriber, Basic)
/*
* Unregistration
*/
ASSERT_EQ(2, sch.getDispatcher().getNumMessageListeners());
ASSERT_EQ(2, node.getDispatcher().getNumMessageListeners());
sub_extended.stop();
sub_extended2.stop();
sub_simple.stop();
sub_simple2.stop();
ASSERT_EQ(0, sch.getDispatcher().getNumMessageListeners());
ASSERT_EQ(0, node.getDispatcher().getNumMessageListeners());
}
@ -194,26 +188,19 @@ static void panickingSink(const uavcan::ReceivedDataStructure<uavcan::mavlink::M
TEST(Subscriber, FailureCount)
{
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
// Manual type registration - we can't rely on the GDTR state
uavcan::GlobalDataTypeRegistry::instance().reset();
uavcan::DefaultDataTypeRegistrator<uavcan::mavlink::Message> _registrator;
SystemClockDriver clock_driver;
CanDriverMock can_driver(2, clock_driver);
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
uavcan::Scheduler sch(can_driver, poolmgr, clock_driver, out_trans_reg, uavcan::NodeID(1));
TestNode node(can_driver, clock_driver, 1);
{
uavcan::Subscriber<uavcan::mavlink::Message> sub(sch, poolmgr);
ASSERT_EQ(0, sch.getDispatcher().getNumMessageListeners());
uavcan::Subscriber<uavcan::mavlink::Message> sub(node);
ASSERT_EQ(0, node.getDispatcher().getNumMessageListeners());
sub.start(panickingSink);
ASSERT_EQ(1, sch.getDispatcher().getNumMessageListeners());
ASSERT_EQ(1, node.getDispatcher().getNumMessageListeners());
ASSERT_EQ(0, sub.getFailureCount());
@ -229,36 +216,29 @@ TEST(Subscriber, FailureCount)
can_driver.ifaces[1].pushRx(rx_frame);
}
ASSERT_LE(0, sch.spin(clock_driver.getMonotonic() + durMono(10000)));
ASSERT_LE(0, node.spin(clock_driver.getMonotonic() + durMono(10000)));
ASSERT_EQ(4, sub.getFailureCount());
ASSERT_EQ(1, sch.getDispatcher().getNumMessageListeners()); // Still there
ASSERT_EQ(1, node.getDispatcher().getNumMessageListeners()); // Still there
}
ASSERT_EQ(0, sch.getDispatcher().getNumMessageListeners()); // Removed
ASSERT_EQ(0, node.getDispatcher().getNumMessageListeners()); // Removed
}
TEST(Subscriber, SingleFrameTransfer)
{
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
// Manual type registration - we can't rely on the GDTR state
uavcan::GlobalDataTypeRegistry::instance().reset();
uavcan::DefaultDataTypeRegistrator<root_ns_a::EmptyMessage> _registrator;
SystemClockDriver clock_driver;
CanDriverMock can_driver(2, clock_driver);
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
uavcan::Scheduler sch(can_driver, poolmgr, clock_driver, out_trans_reg, uavcan::NodeID(1));
TestNode node(can_driver, clock_driver, 1);
typedef SubscriptionListener<root_ns_a::EmptyMessage> Listener;
uavcan::Subscriber<root_ns_a::EmptyMessage, Listener::SimpleBinder> sub(sch, poolmgr);
uavcan::Subscriber<root_ns_a::EmptyMessage, Listener::SimpleBinder> sub(node);
std::cout <<
"sizeof(uavcan::Subscriber<root_ns_a::EmptyMessage, Listener::SimpleBinder>): " <<
@ -280,7 +260,7 @@ TEST(Subscriber, SingleFrameTransfer)
can_driver.ifaces[1].pushRx(rx_frame);
}
ASSERT_LE(0, sch.spin(clock_driver.getMonotonic() + durMono(10000)));
ASSERT_LE(0, node.spin(clock_driver.getMonotonic() + durMono(10000)));
ASSERT_EQ(0, sub.getFailureCount());

View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
*/
#pragma once
#include <uavcan/node/abstract_node.hpp>
#include <uavcan/util/lazy_constructor.hpp>
struct TestNode : public uavcan::INode
{
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
uavcan::PoolManager<1> poolmgr;
uavcan::MarshalBufferProvider<> buffer_provider;
uavcan::OutgoingTransferRegistry<8> otr;
uavcan::Scheduler scheduler;
TestNode(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock_driver, uavcan::NodeID self_node_id)
: otr(poolmgr)
, scheduler(can_driver, poolmgr, clock_driver, otr)
{
poolmgr.addPool(&pool);
setNodeID(self_node_id);
}
uavcan::PoolManager<1>& getAllocator() { return poolmgr; }
uavcan::Scheduler& getScheduler() { return scheduler; }
const uavcan::Scheduler& getScheduler() const { return scheduler; }
uavcan::IMarshalBufferProvider& getMarshalBufferProvider() { return buffer_provider; }
};

View File

@ -43,7 +43,10 @@ TEST(Dispatcher, Reception)
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg, SELF_NODE_ID);
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
ASSERT_FALSE(dispatcher.setNodeID(SELF_NODE_ID));
ASSERT_EQ(SELF_NODE_ID, dispatcher.getNodeID());
DispatcherTransferEmulator emulator(driver, SELF_NODE_ID);
@ -192,7 +195,9 @@ TEST(Dispatcher, Transmission)
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg, SELF_NODE_ID);
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
ASSERT_FALSE(dispatcher.setNodeID(SELF_NODE_ID));
/*
* Transmission
@ -229,7 +234,9 @@ TEST(Dispatcher, Spin)
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg, SELF_NODE_ID);
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
ASSERT_FALSE(dispatcher.setNodeID(SELF_NODE_ID));
clockmock.monotonic_auto_advance = 100;

View File

@ -39,8 +39,10 @@ TEST(TransferSender, Basic)
static const uavcan::NodeID TX_NODE_ID(64);
static const uavcan::NodeID RX_NODE_ID(65);
uavcan::Dispatcher dispatcher_tx(driver, poolmgr, clockmock, out_trans_reg, TX_NODE_ID);
uavcan::Dispatcher dispatcher_rx(driver, poolmgr, clockmock, out_trans_reg, RX_NODE_ID);
uavcan::Dispatcher dispatcher_tx(driver, poolmgr, clockmock, out_trans_reg);
uavcan::Dispatcher dispatcher_rx(driver, poolmgr, clockmock, out_trans_reg);
ASSERT_TRUE(dispatcher_tx.setNodeID(TX_NODE_ID));
ASSERT_TRUE(dispatcher_rx.setNodeID(RX_NODE_ID));
/*
* Test environment