libuav original
Dependents: UAVCAN UAVCAN_Subscriber
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
Generated on Tue Jul 12 2022 17:17:34 by 1.7.2