libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dispatcher.hpp Source File

dispatcher.hpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #ifndef UAVCAN_TRANSPORT_DISPATCHER_HPP_INCLUDED
00006 #define UAVCAN_TRANSPORT_DISPATCHER_HPP_INCLUDED
00007 
00008 #include <cassert>
00009 #include <uavcan/error.hpp>
00010 #include <uavcan/std.hpp>
00011 #include <uavcan/build_config.hpp>
00012 #include <uavcan/transport/perf_counter.hpp>
00013 #include <uavcan/transport/transfer_listener.hpp>
00014 #include <uavcan/transport/outgoing_transfer_registry.hpp>
00015 #include <uavcan/transport/can_io.hpp>
00016 #include <uavcan/util/linked_list.hpp>
00017 
00018 namespace uavcan
00019 {
00020 
00021 class UAVCAN_EXPORT Dispatcher;
00022 
00023 #if !UAVCAN_TINY
00024 /**
00025  * Inherit this class to receive notifications about all TX CAN frames that were transmitted with the loopback flag.
00026  */
00027 class UAVCAN_EXPORT LoopbackFrameListenerBase : public LinkedListNode<LoopbackFrameListenerBase>
00028 {
00029     Dispatcher& dispatcher_;
00030 
00031 protected:
00032     explicit LoopbackFrameListenerBase(Dispatcher& dispatcher)
00033         : dispatcher_(dispatcher)
00034     { }
00035 
00036     virtual ~LoopbackFrameListenerBase() { stopListening(); }
00037 
00038     void startListening();
00039     void stopListening();
00040     bool isListening() const;
00041 
00042     Dispatcher& getDispatcher() { return dispatcher_; }
00043 
00044 public:
00045     virtual void handleLoopbackFrame(const RxFrame& frame) = 0;
00046 };
00047 
00048 
00049 class UAVCAN_EXPORT LoopbackFrameListenerRegistry : Noncopyable
00050 {
00051     LinkedListRoot<LoopbackFrameListenerBase>  listeners_;
00052 
00053 public:
00054     void add(LoopbackFrameListenerBase* listener);
00055     void remove(LoopbackFrameListenerBase* listener);
00056     bool doesExist(const LoopbackFrameListenerBase* listener) const;
00057     unsigned getNumListeners() const { return listeners_.getLength(); }
00058 
00059     void invokeListeners(RxFrame& frame);
00060 };
00061 
00062 /**
00063  * Implement this interface to receive notifications about all incoming CAN frames, including loopback.
00064  */
00065 class UAVCAN_EXPORT IRxFrameListener
00066 {
00067 public:
00068     virtual ~IRxFrameListener() { }
00069 
00070     /**
00071      * Make sure to filter out loopback frames if they are not wanted.
00072      */
00073     virtual void handleRxFrame(const CanRxFrame& frame, CanIOFlags flags) = 0;
00074 };
00075 #endif
00076 
00077 /**
00078  * This class performs low-level CAN frame routing.
00079  */
00080 class UAVCAN_EXPORT Dispatcher : Noncopyable
00081 {
00082     CanIOManager canio_;
00083     ISystemClock& sysclock_;
00084     OutgoingTransferRegistry outgoing_transfer_reg_;
00085     TransferPerfCounter perf_;
00086 
00087     class ListenerRegistry
00088     {
00089         LinkedListRoot<TransferListener>  list_;
00090 
00091         class DataTypeIDInsertionComparator
00092         {
00093             const DataTypeID id_;
00094         public:
00095             explicit DataTypeIDInsertionComparator(DataTypeID id) : id_(id) { }
00096             bool operator()(const TransferListener* listener) const
00097             {
00098                 UAVCAN_ASSERT(listener);
00099                 return id_ > listener->getDataTypeDescriptor().getID();
00100             }
00101         };
00102 
00103     public:
00104         enum Mode { UniqueListener, ManyListeners };
00105 
00106         bool add(TransferListener* listener, Mode mode);
00107         void remove(TransferListener* listener);
00108         bool exists(DataTypeID dtid) const;
00109         void cleanup(MonotonicTime ts);
00110         void handleFrame(const RxFrame& frame);
00111 
00112         unsigned getNumEntries() const { return list_.getLength(); }
00113 
00114         const LinkedListRoot<TransferListener> & getList() const { return list_; }
00115     };
00116 
00117     ListenerRegistry lmsg_;
00118     ListenerRegistry lsrv_req_;
00119     ListenerRegistry lsrv_resp_;
00120 
00121 #if !UAVCAN_TINY
00122     LoopbackFrameListenerRegistry loopback_listeners_;
00123     IRxFrameListener* rx_listener_;
00124 #endif
00125 
00126     NodeID self_node_id_;
00127     bool self_node_id_is_set_;
00128 
00129     void handleFrame(const CanRxFrame& can_frame);
00130 
00131     void handleLoopbackFrame(const CanRxFrame& can_frame);
00132 
00133     void notifyRxFrameListener(const CanRxFrame& can_frame, CanIOFlags flags);
00134 
00135 public:
00136     Dispatcher(ICanDriver& driver, IPoolAllocator& allocator, ISystemClock& sysclock)
00137         : canio_(driver, allocator, sysclock)
00138         , sysclock_(sysclock)
00139         , outgoing_transfer_reg_(allocator)
00140 #if !UAVCAN_TINY
00141         , rx_listener_(UAVCAN_NULLPTR)
00142 #endif
00143         , self_node_id_(NodeID::Broadcast)  // Default
00144         , self_node_id_is_set_(false)
00145     { }
00146 
00147     /**
00148      * This version returns strictly when the deadline is reached.
00149      */
00150     int spin(MonotonicTime deadline);
00151 
00152     /**
00153      * This version does not return until all available frames are processed.
00154      */
00155     int spinOnce();
00156 
00157     /**
00158      * Refer to CanIOManager::send() for the parameter description
00159      */
00160     int send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, CanTxQueue::Qos qos,
00161              CanIOFlags flags, uint8_t iface_mask);
00162 
00163     void cleanup(MonotonicTime ts);
00164 
00165     bool registerMessageListener(TransferListener* listener);
00166     bool registerServiceRequestListener(TransferListener* listener);
00167     bool registerServiceResponseListener(TransferListener* listener);
00168 
00169     void unregisterMessageListener(TransferListener* listener);
00170     void unregisterServiceRequestListener(TransferListener* listener);
00171     void unregisterServiceResponseListener(TransferListener* listener);
00172 
00173     bool hasSubscriber(DataTypeID dtid) const;
00174     bool hasPublisher(DataTypeID dtid) const;
00175     bool hasServer(DataTypeID dtid) const;
00176 
00177     unsigned getNumMessageListeners()         const { return lmsg_.getNumEntries(); }
00178     unsigned getNumServiceRequestListeners()  const { return lsrv_req_.getNumEntries(); }
00179     unsigned getNumServiceResponseListeners() const { return lsrv_resp_.getNumEntries(); }
00180 
00181     /**
00182      * These methods can be used to retreive lists of messages, service requests and service responses the
00183      * dispatcher is currently listening to.
00184      * Note that the list of service response listeners is very volatile, because a response listener will be
00185      * removed from this list as soon as the corresponding service call is complete.
00186      * @{
00187      */
00188     const LinkedListRoot<TransferListener> & getListOfMessageListeners() const
00189     {
00190         return lmsg_.getList();
00191     }
00192     const LinkedListRoot<TransferListener> & getListOfServiceRequestListeners() const
00193     {
00194         return lsrv_req_.getList();
00195     }
00196     const LinkedListRoot<TransferListener>& getListOfServiceResponseListeners() const
00197     {
00198         return lsrv_resp_.getList();
00199     }
00200     /**
00201      * @}
00202      */
00203 
00204     OutgoingTransferRegistry& getOutgoingTransferRegistry() { return outgoing_transfer_reg_; }
00205 
00206 #if !UAVCAN_TINY
00207     LoopbackFrameListenerRegistry& getLoopbackFrameListenerRegistry() { return loopback_listeners_; }
00208 
00209     IRxFrameListener* getRxFrameListener() const { return rx_listener_; }
00210     void removeRxFrameListener() { rx_listener_ = UAVCAN_NULLPTR; }
00211     void installRxFrameListener(IRxFrameListener* listener)
00212     {
00213         UAVCAN_ASSERT(listener != UAVCAN_NULLPTR);
00214         rx_listener_ = listener;
00215     }
00216 #endif
00217 
00218     /**
00219      * Node ID can be set only once.
00220      * Non-unicast Node ID puts the node into passive mode.
00221      */
00222     NodeID getNodeID() const { return self_node_id_; }
00223     bool setNodeID(NodeID nid);
00224 
00225     /**
00226      * Refer to the specs to learn more about passive mode.
00227      */
00228     bool isPassiveMode() const { return !getNodeID().isUnicast(); }
00229 
00230     const ISystemClock& getSystemClock() const { return sysclock_; }
00231     ISystemClock& getSystemClock() { return sysclock_; }
00232 
00233     const CanIOManager& getCanIOManager() const { return canio_; }
00234     CanIOManager& getCanIOManager() { return canio_; }
00235 
00236     const TransferPerfCounter& getTransferPerfCounter() const { return perf_; }
00237     TransferPerfCounter& getTransferPerfCounter() { return perf_; }
00238 };
00239 
00240 }
00241 
00242 #endif // UAVCAN_TRANSPORT_DISPATCHER_HPP_INCLUDED