libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers node.hpp Source File

node.hpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #ifndef UAVCAN_NODE_NODE_HPP_INCLUDED
00006 #define UAVCAN_NODE_NODE_HPP_INCLUDED
00007 
00008 #include <cassert>
00009 #include <uavcan/error.hpp>
00010 #include <uavcan/build_config.hpp>
00011 #include <uavcan/node/abstract_node.hpp>
00012 
00013 // High-level functionality available by default
00014 #include <uavcan/protocol/node_status_provider.hpp>
00015 
00016 #if !UAVCAN_TINY
00017 # include <uavcan/protocol/data_type_info_provider.hpp>
00018 # include <uavcan/protocol/logger.hpp>
00019 # include <uavcan/protocol/restart_request_server.hpp>
00020 # include <uavcan/protocol/transport_stats_provider.hpp>
00021 #endif
00022 
00023 #if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
00024 # error UAVCAN_CPP_VERSION
00025 #endif
00026 
00027 namespace uavcan
00028 {
00029 /**
00030  * This is the top-level node API.
00031  * A custom node class can be implemented if needed, in which case it shall inherit INode.
00032  *
00033  * @tparam MemPoolSize      Size of memory pool for this node, in bytes.
00034  *                          Please refer to the documentation for details.
00035  *                          If this value is zero, the constructor will accept a reference to user-provided allocator.
00036  */
00037 template <std::size_t MemPoolSize = 0>
00038 class UAVCAN_EXPORT Node : public INode
00039 {
00040     typedef typename
00041         Select<(MemPoolSize > 0),
00042                PoolAllocator<MemPoolSize, MemPoolBlockSize>, // If pool size is specified, use default allocator
00043                IPoolAllocator&                               // Otherwise use reference to user-provided allocator
00044               >::Result Allocator;
00045 
00046     Allocator pool_allocator_;
00047     Scheduler scheduler_;
00048 
00049     NodeStatusProvider proto_nsp_;
00050 #if !UAVCAN_TINY
00051     DataTypeInfoProvider proto_dtp_;
00052     Logger proto_logger_;
00053     RestartRequestServer proto_rrs_;
00054     TransportStatsProvider proto_tsp_;
00055 #endif
00056 
00057     uint64_t internal_failure_cnt_;
00058     bool started_;
00059 
00060     void commonInit()
00061     {
00062         internal_failure_cnt_ = 0;
00063         started_ = false;
00064     }
00065 
00066 protected:
00067     virtual void registerInternalFailure(const char* msg)
00068     {
00069         internal_failure_cnt_++;
00070         UAVCAN_TRACE("Node", "Internal failure: %s", msg);
00071 #if UAVCAN_TINY
00072         (void)msg;
00073 #else
00074         (void)getLogger().log(protocol::debug::LogLevel::ERROR, "UAVCAN", msg);
00075 #endif
00076     }
00077 
00078 public:
00079     /**
00080      * This overload is only valid if MemPoolSize > 0.
00081      */
00082     Node(ICanDriver& can_driver,
00083          ISystemClock& system_clock) :
00084         scheduler_(can_driver, pool_allocator_, system_clock),
00085         proto_nsp_(*this)
00086 #if !UAVCAN_TINY
00087         , proto_dtp_(*this)
00088         , proto_logger_(*this)
00089         , proto_rrs_(*this)
00090         , proto_tsp_(*this)
00091 #endif
00092     {
00093         commonInit();
00094     }
00095 
00096     /**
00097      * This overload is only valid if MemPoolSize == 0.
00098      */
00099     Node(ICanDriver& can_driver,
00100          ISystemClock& system_clock,
00101          IPoolAllocator& allocator) :
00102         pool_allocator_(allocator),
00103         scheduler_(can_driver, pool_allocator_, system_clock),
00104         proto_nsp_(*this)
00105 #if !UAVCAN_TINY
00106         , proto_dtp_(*this)
00107         , proto_logger_(*this)
00108         , proto_rrs_(*this)
00109         , proto_tsp_(*this)
00110 #endif
00111     {
00112         commonInit();
00113     }
00114 
00115     virtual typename RemoveReference<Allocator>::Type& getAllocator() { return pool_allocator_; }
00116 
00117     virtual Scheduler& getScheduler() { return scheduler_; }
00118     virtual const Scheduler& getScheduler() const { return scheduler_; }
00119 
00120     int spin(MonotonicTime deadline)
00121     {
00122         if (started_)
00123         {
00124             return INode::spin(deadline);
00125         }
00126         return -ErrNotInited;
00127     }
00128 
00129     int spin(MonotonicDuration duration)
00130     {
00131         if (started_)
00132         {
00133             return INode::spin(duration);
00134         }
00135         return -ErrNotInited;
00136     }
00137 
00138     int spinOnce()
00139     {
00140         if (started_)
00141         {
00142             return INode::spinOnce();
00143         }
00144         return -ErrNotInited;
00145     }
00146 
00147     bool isStarted() const { return started_; }
00148 
00149     uint64_t getInternalFailureCount() const { return internal_failure_cnt_; }
00150 
00151     /**
00152      * Starts the node and publishes uavcan.protocol.NodeStatus immediately.
00153      * Does not so anything if the node is already started.
00154      * Once started, the node can't stop.
00155      * If the node failed to start up, it's recommended to destroy the current node instance and start over.
00156      * Returns negative error code.
00157      * @param node_status_transfer_priority Transfer priority that will be used for outgoing NodeStatus messages.
00158      *                                      Normal priority is used by default.
00159      */
00160     int start(const TransferPriority node_status_transfer_priority = TransferPriority::Default);
00161 
00162     /**
00163      * Gets/sets the node name, e.g. "com.example.product_name". The node name can be set only once.
00164      * The name must be set before the node is started, otherwise the node will refuse to start up.
00165      */
00166     const NodeStatusProvider::NodeName& getName() const { return proto_nsp_.getName(); }
00167     void setName(const NodeStatusProvider::NodeName& name) { proto_nsp_.setName(name); }
00168 
00169     /**
00170      * Node health code helpers.
00171      */
00172     void setHealthOk()           { proto_nsp_.setHealthOk(); }
00173     void setHealthWarning()      { proto_nsp_.setHealthWarning(); }
00174     void setHealthError()        { proto_nsp_.setHealthError(); }
00175     void setHealthCritical()     { proto_nsp_.setHealthCritical(); }
00176 
00177     /**
00178      * Node mode code helpers.
00179      * Note that INITIALIZATION is the default mode; the application has to manually set it to OPERATIONAL.
00180      */
00181     void setModeOperational()    { proto_nsp_.setModeOperational(); }
00182     void setModeInitialization() { proto_nsp_.setModeInitialization(); }
00183     void setModeMaintenance()    { proto_nsp_.setModeMaintenance(); }
00184     void setModeSoftwareUpdate() { proto_nsp_.setModeSoftwareUpdate(); }
00185 
00186     void setModeOfflineAndPublish()
00187     {
00188         proto_nsp_.setModeOffline();
00189         (void)proto_nsp_.forcePublish();
00190     }
00191 
00192     /**
00193      * Updates the vendor-specific status code.
00194      */
00195     void setVendorSpecificStatusCode(NodeStatusProvider::VendorSpecificStatusCode code)
00196     {
00197         proto_nsp_.setVendorSpecificStatusCode(code);
00198     }
00199 
00200     /**
00201      * Gets/sets the node version information.
00202      */
00203     void setSoftwareVersion(const protocol::SoftwareVersion& version) { proto_nsp_.setSoftwareVersion(version); }
00204     void setHardwareVersion(const protocol::HardwareVersion& version) { proto_nsp_.setHardwareVersion(version); }
00205 
00206     const protocol::SoftwareVersion& getSoftwareVersion() const { return proto_nsp_.getSoftwareVersion(); }
00207     const protocol::HardwareVersion& getHardwareVersion() const { return proto_nsp_.getHardwareVersion(); }
00208 
00209     NodeStatusProvider& getNodeStatusProvider() { return proto_nsp_; }
00210 
00211 #if !UAVCAN_TINY
00212     /**
00213      * Restart handler can be installed to handle external node restart requests (highly recommended).
00214      */
00215     void setRestartRequestHandler(IRestartRequestHandler* handler) { proto_rrs_.setHandler(handler); }
00216 
00217     RestartRequestServer& getRestartRequestServer() { return proto_rrs_; }
00218 
00219     /**
00220      * Node logging.
00221      * Logging calls are passed directly into the @ref Logger instance.
00222      * Type safe log formatting is supported only in C++11 mode.
00223      * @{
00224      */
00225 #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
00226 
00227     template <typename... Args>
00228     inline void logDebug(const char* source, const char* format, Args... args)
00229     {
00230         (void)proto_logger_.logDebug(source, format, args...);
00231     }
00232 
00233     template <typename... Args>
00234     inline void logInfo(const char* source, const char* format, Args... args)
00235     {
00236         (void)proto_logger_.logInfo(source, format, args...);
00237     }
00238 
00239     template <typename... Args>
00240     inline void logWarning(const char* source, const char* format, Args... args)
00241     {
00242         (void)proto_logger_.logWarning(source, format, args...);
00243     }
00244 
00245     template <typename... Args>
00246     inline void logError(const char* source, const char* format, Args... args)
00247     {
00248         (void)proto_logger_.logError(source, format, args...);
00249     }
00250 
00251 #else
00252 
00253     void logDebug(const char* source, const char* text)   { (void)proto_logger_.logDebug(source, text); }
00254     void logInfo(const char* source, const char* text)    { (void)proto_logger_.logInfo(source, text); }
00255     void logWarning(const char* source, const char* text) { (void)proto_logger_.logWarning(source, text); }
00256     void logError(const char* source, const char* text)   { (void)proto_logger_.logError(source, text); }
00257 
00258 #endif
00259     /**
00260      * @}
00261      */
00262 
00263     /**
00264      * Use this method to configure logging.
00265      */
00266     Logger& getLogger() { return proto_logger_; }
00267 
00268 #endif  // UAVCAN_TINY
00269 };
00270 
00271 // ----------------------------------------------------------------------------
00272 
00273 template <std::size_t MemPoolSize_>
00274 int Node<MemPoolSize_>::start(const TransferPriority priority)
00275 {
00276     if (started_)
00277     {
00278         return 0;
00279     }
00280     GlobalDataTypeRegistry::instance().freeze();
00281 
00282     int res = 0;
00283     res = proto_nsp_.startAndPublish(priority);
00284     if (res < 0)
00285     {
00286         goto fail;
00287     }
00288 #if !UAVCAN_TINY
00289     res = proto_dtp_.start();
00290     if (res < 0)
00291     {
00292         goto fail;
00293     }
00294     res = proto_logger_.init();
00295     if (res < 0)
00296     {
00297         goto fail;
00298     }
00299     res = proto_rrs_.start();
00300     if (res < 0)
00301     {
00302         goto fail;
00303     }
00304     res = proto_tsp_.start();
00305     if (res < 0)
00306     {
00307         goto fail;
00308     }
00309 #endif
00310     started_ = res >= 0;
00311     return res;
00312 fail:
00313     UAVCAN_ASSERT(res < 0);
00314     return res;
00315 }
00316 
00317 }
00318 
00319 #endif // UAVCAN_NODE_NODE_HPP_INCLUDED