libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers service_server.hpp Source File

service_server.hpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #ifndef UAVCAN_NODE_SERVICE_SERVER_HPP_INCLUDED
00006 #define UAVCAN_NODE_SERVICE_SERVER_HPP_INCLUDED
00007 
00008 #include <uavcan/build_config.hpp>
00009 #include <uavcan/node/generic_publisher.hpp>
00010 #include <uavcan/node/generic_subscriber.hpp>
00011 
00012 #if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
00013 # error UAVCAN_CPP_VERSION
00014 #endif
00015 
00016 #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
00017 # include <functional>
00018 #endif
00019 
00020 namespace uavcan
00021 {
00022 /**
00023  * This type can be used in place of the response type in a service server callback to get more advanced control
00024  * of service request processing.
00025  *
00026  * PLEASE NOTE that since this class inherits the response type, service server callbacks can accept either
00027  * object of this class or the response type directly if the extra options are not needed.
00028  *
00029  * For example, both of these callbacks can be used with the same service type 'Foo':
00030  *
00031  *  void first(const ReceivedDataStructure<Foo::Request>& request,
00032  *             ServiceResponseDataStructure<Foo::Response>& response);
00033  *
00034  *  void second(const Foo::Request& request,
00035  *              Foo::Response& response);
00036  *
00037  * In the latter case, an implicit cast will happen before the callback is invoked.
00038  */
00039 template <typename ResponseDataType_>
00040 class ServiceResponseDataStructure : public ResponseDataType_
00041 {
00042     // Fields are weirdly named to avoid name clashing with the inherited data type
00043     bool _enabled_;
00044 
00045 public:
00046     typedef ResponseDataType_ ResponseDataType;
00047 
00048     ServiceResponseDataStructure()
00049         : _enabled_(true)
00050     { }
00051 
00052     /**
00053      * When disabled, the server will not transmit the response transfer.
00054      * By default it is enabled, i.e. response will be sent.
00055      */
00056     void setResponseEnabled(bool x) { _enabled_ = x; }
00057 
00058     /**
00059      * Whether the response will be sent. By default it will.
00060      */
00061     bool isResponseEnabled() const { return _enabled_; }
00062 };
00063 
00064 /**
00065  * Use this class to implement UAVCAN service servers.
00066  *
00067  * Note that the references passed to the callback may point to stack-allocated objects, which means that the
00068  * references get invalidated once the callback returns.
00069  *
00070  * @tparam DataType_        Service data type.
00071  *
00072  * @tparam Callback_        Service calls will be delivered through the callback of this type, and service
00073  *                          response will be returned via the output parameter of the callback. Note that
00074  *                          the reference to service response data struct passed to the callback always points
00075  *                          to a default initialized response object.
00076  *                          Please also refer to @ref ReceivedDataStructure<> and @ref ServiceResponseDataStructure<>.
00077  *                          In C++11 mode this type defaults to std::function<>.
00078  *                          In C++03 mode this type defaults to a plain function pointer; use binder to
00079  *                          call member functions as callbacks.
00080  */
00081 template <typename DataType_,
00082 #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
00083           typename Callback_ = std::function<void (const ReceivedDataStructure<typename DataType_::Request>&,
00084                                                    ServiceResponseDataStructure<typename DataType_::Response>&)>
00085 #else
00086           typename Callback_ = void (*)(const ReceivedDataStructure<typename DataType_::Request>&,
00087                                         ServiceResponseDataStructure<typename DataType_::Response>&)
00088 #endif
00089           >
00090 class UAVCAN_EXPORT ServiceServer
00091     : public GenericSubscriber<DataType_, typename DataType_::Request, TransferListener>
00092 {
00093 public:
00094     typedef DataType_ DataType;
00095     typedef typename DataType::Request RequestType;
00096     typedef typename DataType::Response ResponseType;
00097     typedef Callback_ Callback;
00098 
00099 private:
00100     typedef GenericSubscriber<DataType, RequestType, TransferListener> SubscriberType;
00101     typedef GenericPublisher<DataType, ResponseType> PublisherType;
00102 
00103     PublisherType publisher_;
00104     Callback callback_;
00105     uint32_t response_failure_count_;
00106 
00107     virtual void handleReceivedDataStruct(ReceivedDataStructure<RequestType>& request)
00108     {
00109         UAVCAN_ASSERT(request.getTransferType() == TransferTypeServiceRequest);
00110 
00111         ServiceResponseDataStructure<ResponseType> response;
00112 
00113         if (coerceOrFallback<bool>(callback_, true))
00114         {
00115             UAVCAN_ASSERT(response.isResponseEnabled());  // Enabled by default
00116             callback_(request, response);
00117         }
00118         else
00119         {
00120             handleFatalError("Srv serv clbk");
00121         }
00122 
00123         if (response.isResponseEnabled())
00124         {
00125             publisher_.setPriority(request.getPriority());      // Responding at the same priority.
00126 
00127             const int res = publisher_.publish(response, TransferTypeServiceResponse, request.getSrcNodeID(),
00128                                                request.getTransferID());
00129             if (res < 0)
00130             {
00131                 UAVCAN_TRACE("ServiceServer", "Response publication failure: %i", res);
00132                 publisher_.getNode().getDispatcher().getTransferPerfCounter().addError();
00133                 response_failure_count_++;
00134             }
00135         }
00136         else
00137         {
00138             UAVCAN_TRACE("ServiceServer", "Response was suppressed by the application");
00139         }
00140     }
00141 
00142 public:
00143     explicit ServiceServer(INode& node)
00144         : SubscriberType(node)
00145         , publisher_(node, getDefaultTxTimeout())
00146         , callback_()
00147         , response_failure_count_(0)
00148     {
00149         UAVCAN_ASSERT(getTxTimeout() == getDefaultTxTimeout());  // Making sure it is valid
00150 
00151         StaticAssert<DataTypeKind(DataType::DataTypeKind) == DataTypeKindService>::check();
00152     }
00153 
00154     /**
00155      * Starts the server.
00156      * Incoming service requests will be passed to the application via the callback.
00157      */
00158     int start(const Callback& callback)
00159     {
00160         stop();
00161 
00162         if (!coerceOrFallback<bool>(callback, true))
00163         {
00164             UAVCAN_TRACE("ServiceServer", "Invalid callback");
00165             return -ErrInvalidParam;
00166         }
00167         callback_ = callback;
00168 
00169         const int publisher_res = publisher_.init();
00170         if (publisher_res < 0)
00171         {
00172             UAVCAN_TRACE("ServiceServer", "Publisher initialization failure: %i", publisher_res);
00173             return publisher_res;
00174         }
00175         return SubscriberType::startAsServiceRequestListener();
00176     }
00177 
00178     /**
00179      * Stops the server.
00180      */
00181     using SubscriberType::stop;
00182 
00183     static MonotonicDuration getDefaultTxTimeout() { return MonotonicDuration::fromMSec(1000); }
00184     static MonotonicDuration getMinTxTimeout() { return PublisherType::getMinTxTimeout(); }
00185     static MonotonicDuration getMaxTxTimeout() { return PublisherType::getMaxTxTimeout(); }
00186 
00187     MonotonicDuration getTxTimeout() const { return publisher_.getTxTimeout(); }
00188     void setTxTimeout(MonotonicDuration tx_timeout) { publisher_.setTxTimeout(tx_timeout); }
00189 
00190     /**
00191      * Returns the number of failed attempts to decode data structs. Generally, a failed attempt means either:
00192      * - Transient failure in the transport layer.
00193      * - Incompatible data types.
00194      */
00195     uint32_t getRequestFailureCount() const { return SubscriberType::getFailureCount(); }
00196     uint32_t getResponseFailureCount() const { return response_failure_count_; }
00197 };
00198 
00199 }
00200 
00201 #endif // UAVCAN_NODE_SERVICE_SERVER_HPP_INCLUDED