mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-04-28 19:14:07 +08:00
PanicListener
This commit is contained in:
parent
5cc74bf872
commit
3829506368
101
libuavcan/include/uavcan/protocol/panic_listener.hpp
Normal file
101
libuavcan/include/uavcan/protocol/panic_listener.hpp
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <uavcan/node/subscriber.hpp>
|
||||
#include <uavcan/util/method_binder.hpp>
|
||||
#include <uavcan/protocol/Panic.hpp>
|
||||
|
||||
namespace uavcan
|
||||
{
|
||||
/**
|
||||
* Callback prototype:
|
||||
* void (const ReceivedDataStructure<protocol::Panic>&)
|
||||
* Or:
|
||||
* void (const protocol::Panic&)
|
||||
* The listener can be stopped from the callback.
|
||||
*/
|
||||
template <typename Callback = void(*)(const protocol::Panic&)>
|
||||
class PanicListener : Noncopyable
|
||||
{
|
||||
typedef MethodBinder<PanicListener*, void(PanicListener::*)(const ReceivedDataStructure<protocol::Panic>&)>
|
||||
PanicMsgCallback;
|
||||
|
||||
Subscriber<protocol::Panic, PanicMsgCallback> sub_;
|
||||
MonotonicTime prev_msg_timestamp_;
|
||||
Callback callback_;
|
||||
uint8_t num_subsequent_msgs_;
|
||||
|
||||
void invokeCallback(const ReceivedDataStructure<protocol::Panic>& msg)
|
||||
{
|
||||
if (try_implicit_cast<bool>(callback_, true))
|
||||
{
|
||||
callback_(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0); // This is a logic error because normally we shouldn't start with an invalid callback
|
||||
sub_.getNode().registerInternalFailure("PanicListener invalid callback");
|
||||
}
|
||||
}
|
||||
|
||||
void handleMsg(const ReceivedDataStructure<protocol::Panic>& msg)
|
||||
{
|
||||
UAVCAN_TRACE("PanicListener", "Received panic from snid=%i reason=%s",
|
||||
int(msg.getSrcNodeID().get()), msg.reason_text.c_str());
|
||||
if (prev_msg_timestamp_.isZero())
|
||||
{
|
||||
num_subsequent_msgs_ = 1;
|
||||
prev_msg_timestamp_ = msg.getMonotonicTimestamp();
|
||||
}
|
||||
else
|
||||
{
|
||||
const MonotonicDuration diff = msg.getMonotonicTimestamp() - prev_msg_timestamp_;
|
||||
assert(diff.isPositive() || diff.isZero());
|
||||
if (diff.toMSec() > protocol::Panic::MAX_INTERVAL_MS)
|
||||
{
|
||||
num_subsequent_msgs_ = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
num_subsequent_msgs_++;
|
||||
}
|
||||
prev_msg_timestamp_ = msg.getMonotonicTimestamp();
|
||||
if (num_subsequent_msgs_ >= protocol::Panic::MIN_MESSAGES)
|
||||
{
|
||||
num_subsequent_msgs_ = protocol::Panic::MIN_MESSAGES;
|
||||
invokeCallback(msg); // The application can stop us from the callback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
PanicListener(INode& node)
|
||||
: sub_(node)
|
||||
, callback_()
|
||||
, num_subsequent_msgs_(0)
|
||||
{ }
|
||||
|
||||
int start(const Callback& callback)
|
||||
{
|
||||
stop();
|
||||
if (!try_implicit_cast<bool>(callback, true))
|
||||
{
|
||||
UAVCAN_TRACE("PanicListener", "Invalid callback");
|
||||
return -1;
|
||||
}
|
||||
callback_ = callback;
|
||||
return sub_.start(PanicMsgCallback(this, &PanicListener::handleMsg));
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
sub_.stop();
|
||||
num_subsequent_msgs_ = 0;
|
||||
prev_msg_timestamp_ = MonotonicTime();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
52
libuavcan/test/protocol/panic_listener.cpp
Normal file
52
libuavcan/test/protocol/panic_listener.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/protocol/panic_listener.hpp>
|
||||
#include <uavcan/protocol/panic_broadcaster.hpp>
|
||||
#include "helpers.hpp"
|
||||
|
||||
|
||||
struct PanicHandler
|
||||
{
|
||||
uavcan::protocol::Panic msg;
|
||||
|
||||
PanicHandler() : msg() { }
|
||||
|
||||
void handle(const uavcan::protocol::Panic& msg)
|
||||
{
|
||||
std::cout << msg << std::endl;
|
||||
this->msg = msg;
|
||||
}
|
||||
|
||||
typedef uavcan::MethodBinder<PanicHandler*, void (PanicHandler::*)(const uavcan::protocol::Panic& msg)> Binder;
|
||||
|
||||
Binder bind() { return Binder(this, &PanicHandler::handle); }
|
||||
};
|
||||
|
||||
|
||||
TEST(PanicListener, Basic)
|
||||
{
|
||||
InterlinkedTestNodes nodes;
|
||||
|
||||
uavcan::PanicListener<PanicHandler::Binder> pl(nodes.a);
|
||||
uavcan::PanicBroadcaster pbr(nodes.b);
|
||||
PanicHandler handler;
|
||||
ASSERT_LE(0, pl.start(handler.bind()));
|
||||
|
||||
pbr.panic("PANIC!!!");
|
||||
ASSERT_TRUE(handler.msg == uavcan::protocol::Panic()); // One message published, panic is not registered yet
|
||||
|
||||
pbr.dontPanic();
|
||||
ASSERT_FALSE(pbr.isPanicking());
|
||||
std::cout << "Not panicking" << std::endl;
|
||||
|
||||
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1000)); // Will reset
|
||||
ASSERT_TRUE(handler.msg == uavcan::protocol::Panic());
|
||||
|
||||
pbr.panic("PANIC2!!!"); // Message text doesn't matter
|
||||
ASSERT_TRUE(pbr.isPanicking());
|
||||
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(1000));
|
||||
ASSERT_STREQ("PANIC2!", handler.msg.reason_text.c_str()); // Registered, only 7 chars preserved
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user