Руслан Урядинский / libuavcan

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers generic_publisher.hpp Source File

generic_publisher.hpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #ifndef UAVCAN_NODE_GENERIC_PUBLISHER_HPP_INCLUDED
00006 #define UAVCAN_NODE_GENERIC_PUBLISHER_HPP_INCLUDED
00007 
00008 #include <uavcan/error.hpp>
00009 #include <uavcan/node/abstract_node.hpp>
00010 #include <uavcan/data_type.hpp>
00011 #include <uavcan/node/global_data_type_registry.hpp>
00012 #include <uavcan/debug.hpp>
00013 #include <uavcan/transport/transfer_buffer.hpp>
00014 #include <uavcan/transport/transfer_sender.hpp>
00015 #include <uavcan/marshal/scalar_codec.hpp>
00016 #include <uavcan/marshal/types.hpp>
00017 
00018 namespace uavcan
00019 {
00020 
00021 class GenericPublisherBase : Noncopyable
00022 {
00023     TransferSender sender_;
00024     MonotonicDuration tx_timeout_;
00025     INode& node_;
00026 
00027 protected:
00028     GenericPublisherBase(INode& node, MonotonicDuration tx_timeout,
00029                          MonotonicDuration max_transfer_interval)
00030         : sender_(node.getDispatcher(), max_transfer_interval)
00031         , tx_timeout_(tx_timeout)
00032         , node_(node)
00033     {
00034         setTxTimeout(tx_timeout);
00035 #if UAVCAN_DEBUG
00036         UAVCAN_ASSERT(getTxTimeout() == tx_timeout);  // Making sure default values are OK
00037 #endif
00038     }
00039 
00040     ~GenericPublisherBase() { }
00041 
00042     bool isInited() const;
00043 
00044     int doInit(DataTypeKind dtkind, const char* dtname, CanTxQueue::Qos qos);
00045 
00046     MonotonicTime getTxDeadline() const;
00047 
00048     int genericPublish(const StaticTransferBufferImpl& buffer, TransferType transfer_type,
00049                        NodeID dst_node_id, TransferID* tid, MonotonicTime blocking_deadline);
00050 
00051     TransferSender& getTransferSender() { return sender_; }
00052     const TransferSender& getTransferSender() const { return sender_; }
00053 
00054 public:
00055     static MonotonicDuration getMinTxTimeout() { return MonotonicDuration::fromUSec(200); }
00056     static MonotonicDuration getMaxTxTimeout() { return MonotonicDuration::fromMSec(60000); }
00057 
00058     MonotonicDuration getTxTimeout() const { return tx_timeout_; }
00059     void setTxTimeout(MonotonicDuration tx_timeout);
00060 
00061     /**
00062      * By default, attempt to send a transfer from passive mode will result in an error @ref ErrPassive.
00063      * This option allows to enable sending anonymous transfers from passive mode.
00064      */
00065     void allowAnonymousTransfers()
00066     {
00067         sender_.allowAnonymousTransfers();
00068     }
00069 
00070     /**
00071      * Priority of outgoing transfers.
00072      */
00073     TransferPriority getPriority() const { return sender_.getPriority(); }
00074     void setPriority(const TransferPriority prio) { sender_.setPriority(prio); }
00075 
00076     INode& getNode() const { return node_; }
00077 };
00078 
00079 /**
00080  * Generic publisher, suitable for messages and services.
00081  * DataSpec - data type specification class
00082  * DataStruct - instantiable class
00083  */
00084 template <typename DataSpec, typename DataStruct>
00085 class UAVCAN_EXPORT GenericPublisher : public GenericPublisherBase
00086 {
00087     struct ZeroTransferBuffer : public StaticTransferBufferImpl
00088     {
00089         ZeroTransferBuffer() : StaticTransferBufferImpl(UAVCAN_NULLPTR, 0) { }
00090     };
00091 
00092     typedef typename Select<DataStruct::MaxBitLen == 0,
00093                             ZeroTransferBuffer,
00094                             StaticTransferBuffer<BitLenToByteLen<DataStruct::MaxBitLen>::Result> >::Result Buffer;
00095 
00096     enum
00097     {
00098         Qos = (DataTypeKind(DataSpec::DataTypeKind) == DataTypeKindMessage) ?
00099               CanTxQueue::Volatile : CanTxQueue::Persistent
00100     };
00101 
00102     int checkInit();
00103 
00104     int doEncode(const DataStruct& message, ITransferBuffer& buffer) const;
00105 
00106     int genericPublish(const DataStruct& message, TransferType transfer_type, NodeID dst_node_id,
00107                        TransferID* tid, MonotonicTime blocking_deadline);
00108 
00109 public:
00110     /**
00111      * @param max_transfer_interval     Maximum expected time interval between subsequent publications. Leave default.
00112      */
00113     GenericPublisher(INode& node, MonotonicDuration tx_timeout,
00114                      MonotonicDuration max_transfer_interval = TransferSender::getDefaultMaxTransferInterval())
00115         : GenericPublisherBase(node, tx_timeout, max_transfer_interval)
00116     { }
00117 
00118     ~GenericPublisher() { }
00119 
00120     /**
00121      * Init method can be called prior first publication, but it's not necessary
00122      * because the publisher can be automatically initialized ad-hoc.
00123      */
00124     int init()
00125     {
00126         return checkInit();
00127     }
00128 
00129     /**
00130      * This overload allows to set the priority; otherwise it's the same.
00131      */
00132     int init(TransferPriority priority)
00133     {
00134         setPriority(priority);
00135         return checkInit();
00136     }
00137 
00138     int publish(const DataStruct& message, TransferType transfer_type, NodeID dst_node_id,
00139                 MonotonicTime blocking_deadline = MonotonicTime())
00140     {
00141         return genericPublish(message, transfer_type, dst_node_id, UAVCAN_NULLPTR, blocking_deadline);
00142     }
00143 
00144     int publish(const DataStruct& message, TransferType transfer_type, NodeID dst_node_id, TransferID tid,
00145                 MonotonicTime blocking_deadline = MonotonicTime())
00146     {
00147         return genericPublish(message, transfer_type, dst_node_id, &tid, blocking_deadline);
00148     }
00149 };
00150 
00151 // ----------------------------------------------------------------------------
00152 
00153 template <typename DataSpec, typename DataStruct>
00154 int GenericPublisher<DataSpec, DataStruct>::checkInit()
00155 {
00156     if (isInited())
00157     {
00158         return 0;
00159     }
00160     return doInit(DataTypeKind(DataSpec::DataTypeKind), DataSpec::getDataTypeFullName(), CanTxQueue::Qos(Qos));
00161 }
00162 
00163 template <typename DataSpec, typename DataStruct>
00164 int GenericPublisher<DataSpec, DataStruct>::doEncode(const DataStruct& message, ITransferBuffer& buffer) const
00165 {
00166     BitStream bitstream(buffer);
00167     ScalarCodec codec(bitstream);
00168     const int encode_res = DataStruct::encode(message, codec);
00169     if (encode_res <= 0)
00170     {
00171         UAVCAN_ASSERT(0);   // Impossible, internal error
00172         return -ErrInvalidMarshalData;
00173     }
00174     return encode_res;
00175 }
00176 
00177 template <typename DataSpec, typename DataStruct>
00178 int GenericPublisher<DataSpec, DataStruct>::genericPublish(const DataStruct& message, TransferType transfer_type,
00179                                                            NodeID dst_node_id, TransferID* tid,
00180                                                            MonotonicTime blocking_deadline)
00181 {
00182     const int res = checkInit();
00183     if (res < 0)
00184     {
00185         return res;
00186     }
00187 
00188     Buffer buffer;
00189 
00190     const int encode_res = doEncode(message, buffer);
00191     if (encode_res < 0)
00192     {
00193         return encode_res;
00194     }
00195 
00196     return GenericPublisherBase::genericPublish(buffer, transfer_type, dst_node_id, tid, blocking_deadline);
00197 }
00198 
00199 }
00200 
00201 #endif // UAVCAN_NODE_GENERIC_PUBLISHER_HPP_INCLUDED