libuavcan documentation

This commit is contained in:
Pavel Kirienko
2014-07-14 22:22:18 +04:00
parent ee4c191684
commit e5ca1f7379
47 changed files with 1102 additions and 132 deletions
@@ -10,7 +10,11 @@
namespace uavcan
{
/**
* This is the abstract node class. If you're going to implement your own node class for your application,
* please inherit this class so it can be used with default publisher, subscriber, server, etc. classes.
* Normally you don't need to use directly though - please refer to the class Node<>.
*/
class UAVCAN_EXPORT INode
{
public:
@@ -28,19 +32,44 @@ public:
MonotonicTime getMonotonicTime() const { return getScheduler().getMonotonicTime(); }
UtcTime getUtcTime() const { return getScheduler().getUtcTime(); }
/**
* Returns the Node ID of this node.
* If Node ID was not set yet, an invalid value will be returned.
*/
NodeID getNodeID() const { return getScheduler().getDispatcher().getNodeID(); }
/**
* Sets the Node ID of this node.
* Node ID can be assigned only once. This method returns true if the Node ID was successfully assigned, otherwise
* it returns false (e.g. the argument does not represent a valid Node ID, or it was already assigned earlier).
* As long as a valid Node ID is not set, the node will remain in passive mode.
*/
bool setNodeID(NodeID nid)
{
return getScheduler().getDispatcher().setNodeID(nid);
}
/**
* Whether the node is in passive mode, i.e. can't transmit anything to the bus.
* Please read the specs to learn more.
*/
bool isPassiveMode() const { return getScheduler().getDispatcher().isPassiveMode(); }
/**
* Same as @ref spin(MonotonicDuration), but the deadline is specified as an absolute time value
* rather than duration.
*/
int spin(MonotonicTime deadline)
{
return getScheduler().spin(deadline);
}
/**
* Runs the node.
* Normally your application should not block anywhere else.
* Block inside this method forever or call it periodically.
* This method returns 0 if no errors occurred, or a negative error code if something failed (see error.hpp).
*/
int spin(MonotonicDuration duration)
{
return getScheduler().spin(getMonotonicTime() + duration);
@@ -84,6 +84,9 @@ class UAVCAN_EXPORT GenericPublisher : public GenericPublisherBase
TransferID* tid, MonotonicTime blocking_deadline);
public:
/**
* @param max_transfer_interval Maximum expected time interval between subsequent publications. Leave default.
*/
GenericPublisher(INode& node, MonotonicDuration tx_timeout,
MonotonicDuration max_transfer_interval = TransferSender::getDefaultMaxTransferInterval())
: GenericPublisherBase(node, tx_timeout, max_transfer_interval)
@@ -91,6 +94,10 @@ public:
~GenericPublisher() { }
/**
* Init method can be called prior first publication, but it's not necessary
* because the publisher can be automatically initialized ad-hoc.
*/
int init()
{
return checkInit();
@@ -17,7 +17,18 @@
namespace uavcan
{
/**
* This class extends the data structure with extra information obtained from the transport layer,
* such as Source Node ID, timestamps, Transfer ID, index of the interface this transfer was picked up from, etc.
*
* PLEASE NOTE that since this class inherits the data structure type, subscription callbacks can accept either
* object of this class or the data structure type directly if the extra information is not needed.
*
* For example, both of these callbacks can be used with the same data structure 'Foo':
* void first(const ReceivedDataStructure<Foo>& msg);
* void second(const Foo& msg);
* In the latter case, an implicit cast will happen before the callback is invoked.
*/
template <typename DataType_>
class UAVCAN_EXPORT ReceivedDataStructure : public DataType_
{
@@ -57,6 +68,10 @@ public:
uint8_t getIfaceIndex() const { return safeget<uint8_t, &IncomingTransfer::getIfaceIndex>(); }
};
/**
* This operator neatly prints the data structure prepended with extra data from the transport layer.
* The extra data will be represented as YAML comment.
*/
template <typename Stream, typename DataType>
static Stream& operator<<(Stream& s, const ReceivedDataStructure<DataType>& rds)
{
@@ -86,12 +101,19 @@ protected:
void stop(TransferListenerBase* listener);
public:
/**
* Returns the number of failed attempts to decode received message. Generally, a failed attempt means either:
* - Transient failure in the transport layer.
* - Incompatible data types.
*/
uint32_t getFailureCount() const { return failure_count_; }
INode& getNode() const { return node_; }
};
/**
* This helper class does some compile-time magic on the transport layer machinery. For authorized personnel only.
*/
template <typename DataStruct_, unsigned NumStaticReceivers_, unsigned NumStaticBufs_>
class UAVCAN_EXPORT TransferListenerInstantiationHelper
{
@@ -173,6 +195,10 @@ protected:
return genericStart(&Dispatcher::registerServiceResponseListener);
}
/**
* Terminate the subscription.
* Dispatcher core will remove this instance from the subscribers list.
*/
void stop()
{
GenericSubscriberBase::stop(forwarder_);
@@ -180,6 +206,10 @@ protected:
TransferListenerType* getTransferListener() { return forwarder_; }
/**
* Returns the mutable reference to the temporary storage for decoded received messages.
* Reference to this storage is used as a parameter for subscription callbacks.
*/
ReceivedDataStructure<DataStruct>& getReceivedStructStorage() { return message_; }
};
@@ -17,9 +17,26 @@
namespace uavcan
{
/**
* Bit mask where bit at index X is set if there's a Data Type with ID X.
*/
typedef BitSet<DataTypeID::Max + 1> DataTypeIDMask;
/**
* This singleton is shared among all existing node instances. It is instantiated automatically
* when the C++ runtime executes contstructors before main().
*
* Its purpose is to keep the list of all UAVCAN data types known and used by this application.
*
* Also, the mapping between Data Type name and its Data Type ID is also stored in this singleton.
* UAVCAN data types with default Data Type ID that are autogenerated by the libuavcan DSDL compiler
* are registered automatically before main() (refer to the generated headers to see how exactly).
* Data types that don't have a default Data Type ID must be registered manually using the methods
* of this class (read the method documentation).
*
* Attempt to use a data type that was not registered with this singleton (e.g. publish, subscribe,
* perform a service call etc.) will fail with an error code @ref ErrUnknownDataType.
*/
class UAVCAN_EXPORT GlobalDataTypeRegistry : Noncopyable
{
struct Entry : public LinkedListNode<Entry>
@@ -49,12 +66,15 @@ class UAVCAN_EXPORT GlobalDataTypeRegistry : Noncopyable
};
public:
/**
* Result of data type registration
*/
enum RegistResult
{
RegistResultOk,
RegistResultCollision,
RegistResultInvalidParams,
RegistResultFrozen
RegistResultOk, ///< Success, data type is now registered and can be used.
RegistResultCollision, ///< Data type name or ID is not unique.
RegistResultInvalidParams, ///< Invalid input parameters.
RegistResultFrozen ///< Data Type Registery has been frozen and can't be modified anymore.
};
private:
@@ -71,24 +91,85 @@ private:
RegistResult registImpl(Entry* dtd);
public:
/**
* Returns the reference to the singleton.
*/
static GlobalDataTypeRegistry& instance();
/// Last call wins
/**
* Register a data type 'Type' with ID 'id'.
* If this data type was registered earlier, its old registration will be overridden.
* This method will fail if the data type registry is frozen.
*
* @tparam Type Autogenerated UAVCAN data type to register. Data types are generated by the
* libuavcan DSDL compiler from DSDL definitions.
*
* @param id Data Type ID for this data type.
*/
template <typename Type>
RegistResult regist(DataTypeID id);
/// Further calls to regist<>() will fail
/**
* Data Type registry needs to be frozen before a node instance can use it in
* order to prevent accidental change in data type configuration on a running
* node.
*
* This method will be called automatically by the node during start up, so
* the user does not need to call it from the application manually. Subsequent
* calls will not have any effect.
*
* Once frozen, data type registry can't be unfrozen.
*/
void freeze();
bool isFrozen() const { return frozen_; }
/**
* Finds data type descriptor by full data type name, e.g. "uavcan.protocol.NodeStatus".
* Returns null pointer if the data type with this name is not registered.
* @param kind Data Type Kind - message or service
* @param name Full data type name
* @return Descriptor for this data type or null pointer if not found
*/
const DataTypeDescriptor* find(DataTypeKind kind, const char* name) const;
/**
* Finds data type descriptor by data type ID.
* Returns null pointer if the data type with this ID is not registered.
* @param kind Data Type Kind - message or service
* @param dtid Data Type ID
* @return Descriptor for this data type or null pointer if not found
*/
const DataTypeDescriptor* find(DataTypeKind kind, DataTypeID dtid) const;
/**
* Computes Aggregate Signature for all known data types selected by the mask.
* Please read the DSDL specification.
* @param[in] kind Data Type Kind - messages or services.
* @param[inout] inout_id_mask Data types to compute aggregate signature for; bits at
* the positions of unknown data types will be cleared.
* @return Computed data type signature.
*/
DataTypeSignature computeAggregateSignature(DataTypeKind kind, DataTypeIDMask& inout_id_mask) const;
/**
* Sets the mask so that only bits corresponding to known data types will be set.
* In other words:
* for data_type_id := [0, 1023]
* mask[data_type_id] := data_type_exists(data_type_id)
*
* @param[in] kind Data Type Kind - messages or services.
* @param[out] mask Output mask of known data types.
*/
void getDataTypeIDMask(DataTypeKind kind, DataTypeIDMask& mask) const;
/**
* Returns the number of registered message types.
*/
unsigned getNumMessageTypes() const { return msgs_.getLength(); }
/**
* Returns the number of registered service types.
*/
unsigned getNumServiceTypes() const { return srvs_.getLength(); }
#if UAVCAN_DEBUG
@@ -110,7 +191,14 @@ public:
#endif
};
/**
* This class is used by autogenerated data types to register with the
* data type registry automatically before main() is called. Note that
* if a generated data type header file is not included by any translation
* unit of the application, the data type will not be registered.
*
* Data type needs to have a default ID to be registrable by this class.
*/
template <typename Type>
struct UAVCAN_EXPORT DefaultDataTypeRegistrator
{
@@ -10,7 +10,9 @@
namespace uavcan
{
/**
* Abstract temporary buffer for data marshalling.
*/
class UAVCAN_EXPORT IMarshalBuffer : public ITransferBuffer
{
public:
@@ -18,15 +20,31 @@ public:
virtual unsigned getDataLength() const = 0;
};
/**
* Abstract provider of abstract buffer for data marshalling.
*/
class UAVCAN_EXPORT IMarshalBufferProvider
{
public:
virtual ~IMarshalBufferProvider() { }
/**
* Returns pointer to abstract buffer for data marshalling,
* but does not transfer ownership.
* If the requested buffer size is larger than available,
* null pointer will be returned.
* @param size Maximum buffer size needed for marshaling.
* @return Pointer to the buffer, or null pointer if
* the requested size is too large.
*/
virtual IMarshalBuffer* getBuffer(unsigned size) = 0;
};
/**
* Default implementation of marshal buffer provider.
* This implementation provides the buffer large enough to
* serialize any UAVCAN data structure.
*/
template <unsigned MaxSize_ = MaxTransferPayloadLen>
class UAVCAN_EXPORT MarshalBufferProvider : public IMarshalBufferProvider
{
+63 -7
View File
@@ -28,7 +28,31 @@
namespace uavcan
{
/**
* This is the top-level node API.
* A custom node class can be implemented if needed, in which case it shall inherit INode.
*
* @tparam MemPoolSize_ Size of memory pool for this node, in bytes.
* Minimum recommended size is 4K * (number of CAN ifaces + 1).
* For simple nodes this number can be reduced.
* For high-traffic nodes the recommended minimum is
* like 16K * (number of CAN ifaces + 1).
*
* @tparam OutgoingTransferRegistryStaticEntries Number of statically allocated objects
* to track Transfer ID for outgoing transfers.
* Normally it should be equal to expected number of
* publishers and service callers, but it's not necessary.
* Additional objects for Transfer ID tracking will
* be allocated in the memory pool if needed.
* Default value is acceptable for any use case.
*
* @tparam OutgoingTransferMaxPayloadLen Maximum outgoing transfer payload length.
* It's pointless to make this value larger than
* @ref MaxTransferPayloadLen, which is default.
* Note that in tiny mode the default value is actually
* smaller than @ref MaxTransferPayloadLen (may cause
* run-time failures).
*/
template <std::size_t MemPoolSize_,
#if UAVCAN_TINY
unsigned OutgoingTransferRegistryStaticEntries = 0,
@@ -114,42 +138,68 @@ public:
bool isStarted() const { return started_; }
/**
* Starts the node and publishes uavcan.protocol.NodeStatus immediately.
* Does not so anything if the node is already started.
* Once started, the node can't stop.
* If the node failed to start up, it's recommended to destroy the current node instance and start over.
* Returns negative error code.
*/
int start();
#if !UAVCAN_TINY
/**
* Please read the specs to learn about Network Compatibility Check.
* Returns negative error code.
* @param[out] result Check result (output).
*/
int checkNetworkCompatibility(NetworkCompatibilityCheckResult& result);
#endif
/*
* Initialization methods
/**
* Sets the node name, e.g. "com.example.product_name". The node name can be set only once.
* Must be executed before the node is started, otherwise the node will refuse to start up.
*/
void setName(const char* name) { proto_nsp_.setName(name); }
/**
* Status code helpers.
*/
void setStatusOk() { proto_nsp_.setStatusOk(); }
void setStatusInitializing() { proto_nsp_.setStatusInitializing(); }
void setStatusWarning() { proto_nsp_.setStatusWarning(); }
void setStatusCritical() { proto_nsp_.setStatusCritical(); }
/**
* Sets the status OFFLINE and publishes it immediately.
*/
void setStatusOffline()
{
proto_nsp_.setStatusOffline();
(void)proto_nsp_.forcePublish();
}
/**
* Sets the node version information.
*/
void setSoftwareVersion(const protocol::SoftwareVersion& version) { proto_nsp_.setSoftwareVersion(version); }
void setHardwareVersion(const protocol::HardwareVersion& version) { proto_nsp_.setHardwareVersion(version); }
NodeStatusProvider& getNodeStatusProvider() { return proto_nsp_; }
#if !UAVCAN_TINY
/*
* Restart handler
/**
* Restart handler can be installed to handle external node restart requests (highly recommended).
*/
void setRestartRequestHandler(IRestartRequestHandler* handler) { proto_rrs_.setHandler(handler); }
RestartRequestServer& getRestartRequestServer() { return proto_rrs_; }
/*
* Logging
/**
* Node logging.
* Logging calls are passed directly into the @ref Logger instance.
* Type safe log formatting is supported only in C++11 mode.
* @{
*/
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
@@ -185,7 +235,13 @@ public:
void logError(const char* source, const char* text) { (void)proto_logger_.logError(source, text); }
#endif
/**
* @}
*/
/**
* Use this method to configure logging.
*/
Logger& getLogger() { return proto_logger_; }
#endif // UAVCAN_TINY
+38 -2
View File
@@ -8,15 +8,32 @@
namespace uavcan
{
/**
* Use this class to publish messages to the bus (broadcast, unicast, or both).
*
* @tparam DataType_ Message data type
*/
template <typename DataType_>
class UAVCAN_EXPORT Publisher : protected GenericPublisher<DataType_, DataType_>
{
typedef GenericPublisher<DataType_, DataType_> BaseType;
public:
typedef DataType_ DataType;
typedef DataType_ DataType; ///< Message data type
/**
* @param node Node instance this publisher will be registered with.
*
* @param tx_timeout If CAN frames of this message are not delivered to the bus
* in this amount of time, they will be discarded. Default value
* is good enough for rather high-frequency, high-priority messages.
*
* @param max_transfer_interval Maximum expected transfer interval. It's absolutely safe
* to leave default value here. It just defines how soon the
* Transfer ID tracking objects associated with this message type
* will be garbage collected by the library if it's no longer
* being published.
*/
explicit Publisher(INode& node, MonotonicDuration tx_timeout = getDefaultTxTimeout(),
MonotonicDuration max_transfer_interval = TransferSender::getDefaultMaxTransferInterval())
: BaseType(node, tx_timeout, max_transfer_interval)
@@ -27,16 +44,30 @@ public:
StaticAssert<DataTypeKind(DataType::DataTypeKind) == DataTypeKindMessage>::check();
}
/**
* Broadcast the message.
* Returns negative error code.
*/
int broadcast(const DataType& message)
{
return BaseType::publish(message, TransferTypeMessageBroadcast, NodeID::Broadcast);
}
/**
* Warning: You probably don't want to use this method; it's for advanced use cases like
* e.g. network time synchronization. Use the overloaded method with fewer arguments instead.
* This overload allows to explicitly specify Transfer ID.
* Returns negative error code.
*/
int broadcast(const DataType& message, TransferID tid)
{
return BaseType::publish(message, TransferTypeMessageBroadcast, NodeID::Broadcast, tid);
}
/**
* Unicast the message to the specified destination Node ID.
* Returns negative error code.
*/
int unicast(const DataType& message, NodeID dst_node_id)
{
if (!dst_node_id.isUnicast())
@@ -49,7 +80,12 @@ public:
static MonotonicDuration getDefaultTxTimeout() { return MonotonicDuration::fromMSec(10); }
/**
* Init method can be called prior first publication, but it's not necessary
* because the publisher can be automatically initialized ad-hoc.
*/
using BaseType::init;
using BaseType::getTransferSender;
using BaseType::getMinTxTimeout;
using BaseType::getMaxTxTimeout;
+17 -1
View File
@@ -55,7 +55,9 @@ public:
MonotonicTime getEarliestDeadline() const;
};
/**
* This class distributes processing time between library components (IO handling, deadline callbacks, ...).
*/
class UAVCAN_EXPORT Scheduler : Noncopyable
{
enum { DefaultDeadlineResolutionMs = 5 };
@@ -85,6 +87,10 @@ public:
, inside_spin_(false)
{ }
/**
* Spin until the deadline, or until some error occurs.
* Returns negative error code.
*/
int spin(MonotonicTime deadline);
DeadlineScheduler& getDeadlineScheduler() { return deadline_scheduler_; }
@@ -96,6 +102,10 @@ public:
MonotonicTime getMonotonicTime() const { return dispatcher_.getSystemClock().getMonotonic(); }
UtcTime getUtcTime() const { return dispatcher_.getSystemClock().getUtc(); }
/**
* Worst case deadline callback resolution.
* Higher resolution increases CPU usage.
*/
MonotonicDuration getDeadlineResolution() const { return deadline_resolution_; }
void setDeadlineResolution(MonotonicDuration res)
{
@@ -104,6 +114,12 @@ public:
deadline_resolution_ = res;
}
/**
* How often the scheduler will run cleanup (listeners, outgoing transfer registry, ...).
* Cleanup execution time grows linearly with number of listeners and number of items
* in the Outgoing Transfer ID registry.
* Lower period increases CPU usage.
*/
MonotonicDuration getCleanupPeriod() const { return cleanup_period_; }
void setCleanupPeriod(MonotonicDuration period)
{
@@ -27,7 +27,10 @@ public:
typedef ServiceResponseTransferListener<DataTypeMaxByteLen> Type;
};
/**
* Object of this type will be returned to the application as a result of service call.
* Note that application ALWAYS gets this result, even when it times out or fails because of some other reason.
*/
template <typename DataType>
struct UAVCAN_EXPORT ServiceCallResult
{
@@ -35,9 +38,9 @@ struct UAVCAN_EXPORT ServiceCallResult
enum Status { Success, ErrorTimeout };
const Status status;
NodeID server_node_id;
ResponseFieldType& response; ///< Either response contents or unspecified response structure
const Status status; ///< Whether successful or not. Failure to decode the response causes timeout.
NodeID server_node_id; ///< Node ID of the server this call was addressed to.
ResponseFieldType& response; ///< Returned data structure. Undefined if the service call has failed.
ServiceCallResult(Status arg_status, NodeID arg_server_node_id, ResponseFieldType& arg_response)
: status(arg_status)
@@ -48,9 +51,16 @@ struct UAVCAN_EXPORT ServiceCallResult
UAVCAN_ASSERT((status == Success) || (status == ErrorTimeout));
}
/**
* Shortcut to quickly check whether the call was successful.
*/
bool isSuccessful() const { return status == Success; }
};
/**
* This operator neatly prints the service call result prepended with extra data like Server Node ID.
* The extra data will be represented as YAML comment.
*/
template <typename Stream, typename DataType>
static Stream& operator<<(Stream& s, const ServiceCallResult<DataType>& scr)
{
@@ -68,7 +78,9 @@ static Stream& operator<<(Stream& s, const ServiceCallResult<DataType>& scr)
return s;
}
/**
* Do not use directly.
*/
class ServiceClientBase : protected DeadlineHandler
{
protected:
@@ -86,16 +98,34 @@ protected:
int prepareToCall(INode& node, const char* dtname, NodeID server_node_id, TransferID& out_transfer_id);
public:
/**
* Returns true if the service call is currently in progress.
*/
bool isPending() const { return pending_; }
/**
* It's not recommended to override default timeouts.
*/
static MonotonicDuration getDefaultRequestTimeout() { return MonotonicDuration::fromMSec(1000); }
static MonotonicDuration getMinRequestTimeout() { return MonotonicDuration::fromMSec(10); }
static MonotonicDuration getMaxRequestTimeout() { return MonotonicDuration::fromMSec(60000); }
/**
* Returns the service response waiting deadline, if pending.
*/
using DeadlineHandler::getDeadline;
};
/**
* Use this class to invoke services on remote nodes.
*
* @tparam DataType_ Service data type.
*
* @tparam Callback_ Service response will be delivered through the callback of this type.
* In C++11 mode this type defaults to std::function<>.
* In C++03 mode this type defaults to a plain function pointer; use binder to
* call member functions as callbacks.
*/
template <typename DataType_,
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
typename Callback_ = std::function<void (const ServiceCallResult<DataType_>&)>
@@ -133,6 +163,10 @@ private:
virtual void handleDeadline(MonotonicTime);
public:
/**
* @param node Node instance this client will be registered with.
* @param callback Callback instance. Optional, can be assigned later.
*/
explicit ServiceClient(INode& node, const Callback& callback = Callback())
: SubscriberType(node)
, ServiceClientBase(node)
@@ -147,23 +181,53 @@ public:
virtual ~ServiceClient() { cancel(); }
/**
* Shall be called before first use.
* Returns negative error code.
*/
int init()
{
return publisher_.init();
}
/**
* Performs non-blocking service call.
* This method transmits the service request and returns immediately.
*
* Service response will be delivered into the application via the callback.
* Note that the callback will ALWAYS be called even if the service call has timed out; the
* actual result of the call (success/failure) will be passed to the callback as well.
*
* If this client instance is already pending service response, it will be cancelled and the new
* call will be performed.
*
* Returns negative error code.
*/
int call(NodeID server_node_id, const RequestType& request);
/**
* Cancel the pending service call.
* Does nothing if it is not pending.
*/
void cancel();
/**
* Service response callback must be set prior service call.
*/
const Callback& getCallback() const { return callback_; }
void setCallback(const Callback& cb) { callback_ = cb; }
/**
* Returns the number of failed attempts to decode received response. Generally, a failed attempt means either:
* - Transient failure in the transport layer.
* - Incompatible data types.
*/
uint32_t getResponseFailureCount() const { return SubscriberType::getFailureCount(); }
/*
* Request timeouts
* There is no such config as TX timeout - TX timeouts are configured automagically according to request timeouts
/**
* Request timeouts.
* There is no such config as TX timeout - TX timeouts are configured automagically according to request timeouts.
* Not recommended to change.
*/
MonotonicDuration getRequestTimeout() const { return request_timeout_; }
void setRequestTimeout(MonotonicDuration timeout)
@@ -18,7 +18,26 @@
namespace uavcan
{
/**
* Use this class to implement UAVCAN service servers.
*
* @tparam DataType_ Service data type.
*
* @tparam Callback_ Service calls will be delivered through the callback of this type, and service
* response will be returned via the output parameter of the callback. Note that
* the reference to service response data struct passed to the callback always points
* to a default initialized response object.
* Please also refer to @ref ReceivedDataStructure<>.
* In C++11 mode this type defaults to std::function<>.
* In C++03 mode this type defaults to a plain function pointer; use binder to
* call member functions as callbacks.
*
* @tparam NumStaticReceivers Number of statically allocated receiver objects. If there's more service
* clients for this service, extra receivers will be allocated in the memory pool.
*
* @tparam NumStaticBufs Number of statically allocated receiver buffers. If there's more concurrent
* incoming transfers, extra buffers will be allocated in the memory pool.
*/
template <typename DataType_,
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
typename Callback_ = std::function<void (const ReceivedDataStructure<typename DataType_::Request>&,
@@ -92,6 +111,10 @@ public:
StaticAssert<DataTypeKind(DataType::DataTypeKind) == DataTypeKindService>::check();
}
/**
* Starts the server.
* Incoming service requests will be passed to the application via the callback.
*/
int start(const Callback& callback)
{
stop();
@@ -112,6 +135,9 @@ public:
return SubscriberType::startAsServiceRequestListener();
}
/**
* Stops the server.
*/
using SubscriberType::stop;
static MonotonicDuration getDefaultTxTimeout() { return MonotonicDuration::fromMSec(1000); }
@@ -121,6 +147,11 @@ public:
MonotonicDuration getTxTimeout() const { return publisher_.getTxTimeout(); }
void setTxTimeout(MonotonicDuration tx_timeout) { publisher_.setTxTimeout(tx_timeout); }
/**
* Returns the number of failed attempts to decode data structs. Generally, a failed attempt means either:
* - Transient failure in the transport layer.
* - Incompatible data types.
*/
uint32_t getRequestFailureCount() const { return SubscriberType::getFailureCount(); }
uint32_t getResponseFailureCount() const { return response_failure_count_; }
};
+27 -1
View File
@@ -18,7 +18,28 @@
namespace uavcan
{
/**
* Use this class to subscribe to a message.
*
* @tparam DataType_ Message data type.
*
* @tparam Callback_ Type of the callback that will be used to deliver received messages
* into the application. Type of the argument of the callback can be either:
* - DataType_&
* - const DataType_&
* - ReceivedDataStructure<DataType_>&
* - const ReceivedDataStructure<DataType_>&
* For the first two options, @ref ReceivedDataStructure<> will be casted implicitly.
* In C++11 mode this type defaults to std::function<>.
* In C++03 mode this type defaults to a plain function pointer; use binder to
* call member functions as callbacks.
*
* @tparam NumStaticReceivers Number of statically allocated receiver objects. If there's more publishers
* of this message, extra receivers will be allocated in the memory pool.
*
* @tparam NumStaticBufs Number of statically allocated receiver buffers. If there's more concurrent
* incoming transfers, extra buffers will be allocated in the memory pool.
*/
template <typename DataType_,
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
typename Callback_ = std::function<void (const ReceivedDataStructure<DataType_>&)>,
@@ -70,6 +91,11 @@ public:
StaticAssert<DataTypeKind(DataType::DataTypeKind) == DataTypeKindMessage>::check();
}
/**
* Begin receiving messages.
* Each message will be passed to the application via the callback.
* Returns negative error code.
*/
int start(const Callback& callback)
{
stop();
+36 -4
View File
@@ -25,10 +25,13 @@ namespace uavcan
class UAVCAN_EXPORT TimerBase;
/**
* Objects of this type will be supplied into timer callbacks.
*/
struct UAVCAN_EXPORT TimerEvent
{
MonotonicTime scheduled_time;
MonotonicTime real_time;
MonotonicTime scheduled_time; ///< Time when the timer callback was expected to be invoked
MonotonicTime real_time; ///< True time when the timer callback was invoked
TimerEvent(MonotonicTime arg_scheduled_time, MonotonicTime arg_real_time)
: scheduled_time(arg_scheduled_time)
@@ -36,7 +39,9 @@ struct UAVCAN_EXPORT TimerEvent
{ }
};
/**
* Inherit this class if you need a timer callback method in your class.
*/
class UAVCAN_EXPORT TimerBase : private DeadlineHandler
{
MonotonicDuration period_;
@@ -54,16 +59,35 @@ public:
, period_(MonotonicDuration::getInfinite())
{ }
/**
* Various ways to start the timer - periodically or once.
*/
void startOneShotWithDeadline(MonotonicTime deadline);
void startOneShotWithDelay(MonotonicDuration delay);
void startPeriodic(MonotonicDuration period);
/**
* Returns period if the timer is in periodic mode.
* Returns infinite duration if the timer is in one-shot mode or stopped.
*/
MonotonicDuration getPeriod() const { return period_; }
/**
* Implement this method in your class to receive callbacks.
*/
virtual void handleTimerEvent(const TimerEvent& event) = 0;
};
/**
* Wrapper over TimerBase that forwards callbacks into arbitrary handlers, like
* functor objects, member functions or static functions.
*
* Callback must be set before the first event; otherwise the event will generate a fatal error.
*
* Also take a look at @ref MethodBinder<>, which may come useful if C++11 features are not available.
*
* @tparam Callback_ Callback type. Shall accept const reference to TimerEvent as its argument.
*/
template <typename Callback_>
class UAVCAN_EXPORT TimerEventForwarder : public TimerBase
{
@@ -96,6 +120,10 @@ public:
, callback_(callback)
{ }
/**
* Get/set the callback object.
* Callback must be set before the first event; otherwise the event will generate a fatal error.
*/
const Callback& getCallback() const { return callback_; }
void setCallback(const Callback& callback) { callback_ = callback; }
};
@@ -103,6 +131,10 @@ public:
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
/**
* Use this timer in C++11 mode.
* Callback type is std::function<>.
*/
typedef TimerEventForwarder<std::function<void (const TimerEvent& event)> > Timer;
#endif