diff --git a/libuavcan/include/uavcan/protocol/restart_request_server.hpp b/libuavcan/include/uavcan/protocol/restart_request_server.hpp new file mode 100644 index 0000000000..be7d9e8407 --- /dev/null +++ b/libuavcan/include/uavcan/protocol/restart_request_server.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 Pavel Kirienko + */ + +#pragma once + +#include +#include +#include + +namespace uavcan +{ + +class IRestartRequestHandler +{ +public: + virtual ~IRestartRequestHandler() { } + virtual bool handleRestartRequest(NodeID request_source) = 0; +}; + + +class RestartRequestServer : Noncopyable +{ + typedef MethodBinder&, + protocol::RestartNode::Response&) const> RestartNodeCallback; + + ServiceServer srv_; + IRestartRequestHandler* handler_; + + void handleRestartNode(const ReceivedDataStructure& request, + protocol::RestartNode::Response& response) const; + +public: + RestartRequestServer(INode& node) + : srv_(node) + , handler_(NULL) + { } + + IRestartRequestHandler* getHandler() const { return handler_; } + void setHandler(IRestartRequestHandler* handler) { handler_ = handler; } + + int start(); +}; + +} diff --git a/libuavcan/src/protocol/restart_request_server.cpp b/libuavcan/src/protocol/restart_request_server.cpp new file mode 100644 index 0000000000..beb2daa495 --- /dev/null +++ b/libuavcan/src/protocol/restart_request_server.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Pavel Kirienko + */ + +#include +#include + +namespace uavcan +{ + +void RestartRequestServer::handleRestartNode(const ReceivedDataStructure& request, + protocol::RestartNode::Response& response) const +{ + UAVCAN_TRACE("RestartRequestServer", "Request from snid=%i", int(request.getSrcNodeID().get())); + response.ok = false; + if (request.magic_number == protocol::RestartNode::Request::MAGIC_NUMBER) + { + if (handler_) + { + response.ok = handler_->handleRestartRequest(request.getSrcNodeID()); + } + UAVCAN_TRACE("RestartRequestServer", "%s", (response.ok ? "Accepted" : "Rejected")); + } + else + { + UAVCAN_TRACE("RestartRequestServer", "Invalid magic number 0x%llx", + static_cast(request.magic_number)); + } +} + +int RestartRequestServer::start() +{ + return srv_.start(RestartNodeCallback(this, &RestartRequestServer::handleRestartNode)); +} + +} diff --git a/libuavcan/test/protocol/restart_request_server.cpp b/libuavcan/test/protocol/restart_request_server.cpp new file mode 100644 index 0000000000..64fa9c2ceb --- /dev/null +++ b/libuavcan/test/protocol/restart_request_server.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 Pavel Kirienko + */ + +#include +#include +#include "helpers.hpp" + + +struct Handler : public uavcan::IRestartRequestHandler +{ + bool accept; + + bool handleRestartRequest(uavcan::NodeID request_source) + { + std::cout << "Restart request from " << int(request_source.get()) << " will be " + << (accept ? "accepted" : "rejected") << std::endl; + return accept; + } +}; + + +TEST(RestartRequestServer, Basic) +{ + InterlinkedTestNodes nodes; + + uavcan::RestartRequestServer rrs(nodes.a); + + ServiceClientWithCollector rrs_cln(nodes.b); + + uavcan::GlobalDataTypeRegistry::instance().reset(); + uavcan::DefaultDataTypeRegistrator _reg1; + + ASSERT_LE(0, rrs.start()); + + uavcan::protocol::RestartNode::Request request; + request.magic_number = uavcan::protocol::RestartNode::Request::MAGIC_NUMBER; + + /* + * Rejected - handler was not set + */ + ASSERT_LE(0, rrs_cln.call(1, request)); + nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(2)); + + ASSERT_TRUE(rrs_cln.collector.result->isSuccessful()); + ASSERT_FALSE(rrs_cln.collector.result->response.ok); + + /* + * Accepted + */ + Handler handler; + handler.accept = true; + rrs.setHandler(&handler); + + ASSERT_LE(0, rrs_cln.call(1, request)); + nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(2)); + + ASSERT_TRUE(rrs_cln.collector.result->isSuccessful()); + ASSERT_TRUE(rrs_cln.collector.result->response.ok); + + /* + * Rejected by handler + */ + handler.accept = false; + + ASSERT_LE(0, rrs_cln.call(1, request)); + nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(2)); + + ASSERT_TRUE(rrs_cln.collector.result->isSuccessful()); + ASSERT_FALSE(rrs_cln.collector.result->response.ok); + + /* + * Rejected because of invalid magic number + */ + handler.accept = true; + + ASSERT_LE(0, rrs_cln.call(1, uavcan::protocol::RestartNode::Request())); + nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(2)); + + ASSERT_TRUE(rrs_cln.collector.result->isSuccessful()); + ASSERT_FALSE(rrs_cln.collector.result->response.ok); +}