generic_subscriber.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #ifndef UAVCAN_NODE_GENERIC_SUBSCRIBER_HPP_INCLUDED
6 #define UAVCAN_NODE_GENERIC_SUBSCRIBER_HPP_INCLUDED
7 
8 #include <uavcan/error.hpp>
10 #include <uavcan/data_type.hpp>
14 #include <uavcan/debug.hpp>
17 #include <uavcan/marshal/types.hpp>
18 
19 namespace uavcan
20 {
38 template <typename DataType_>
40 {
42 
43  template <typename Ret, Ret(IncomingTransfer::*Fun) () const>
44  Ret safeget() const
45  {
46  if (_transfer_ == UAVCAN_NULLPTR)
47  {
48  return Ret();
49  }
50  return (_transfer_->*Fun)();
51  }
52 
53 protected:
55  : _transfer_(UAVCAN_NULLPTR)
56  { }
57 
59  : _transfer_(arg_transfer)
60  {
61  UAVCAN_ASSERT(arg_transfer != UAVCAN_NULLPTR);
62  }
63 
64 public:
65  typedef DataType_ DataType;
66 
68  {
69  return safeget<MonotonicTime, &IncomingTransfer::getMonotonicTimestamp>();
70  }
71  UtcTime getUtcTimestamp() const { return safeget<UtcTime, &IncomingTransfer::getUtcTimestamp>(); }
72  TransferPriority getPriority() const { return safeget<TransferPriority, &IncomingTransfer::getPriority>(); }
73  TransferType getTransferType() const { return safeget<TransferType, &IncomingTransfer::getTransferType>(); }
74  TransferID getTransferID() const { return safeget<TransferID, &IncomingTransfer::getTransferID>(); }
75  NodeID getSrcNodeID() const { return safeget<NodeID, &IncomingTransfer::getSrcNodeID>(); }
76  uint8_t getIfaceIndex() const { return safeget<uint8_t, &IncomingTransfer::getIfaceIndex>(); }
77  bool isAnonymousTransfer() const { return safeget<bool, &IncomingTransfer::isAnonymousTransfer>(); }
78 };
79 
84 template <typename Stream, typename DataType>
85 static Stream& operator<<(Stream& s, const ReceivedDataStructure<DataType>& rds)
86 {
87  s << "# Received struct ts_m=" << rds.getMonotonicTimestamp()
88  << " ts_utc=" << rds.getUtcTimestamp()
89  << " snid=" << int(rds.getSrcNodeID().get()) << "\n";
90  s << static_cast<const DataType&>(rds);
91  return s;
92 }
93 
94 
96 {
97 protected:
100 
102  : node_(node)
103  , failure_count_(0)
104  { }
105 
107 
108  int genericStart(TransferListener* listener, bool (Dispatcher::*registration_method)(TransferListener*));
109 
110  void stop(TransferListener* listener);
111 
112 public:
118  uint32_t getFailureCount() const { return failure_count_; }
119 
120  INode& getNode() const { return node_; }
121 };
122 
127 template <typename DataSpec, typename DataStruct, typename TransferListenerType>
129 {
131 
132  // We need to break the inheritance chain here to implement lazy initialization
133  class TransferForwarder : public TransferListenerType
134  {
135  SelfType& obj_;
136 
138  {
139  obj_.handleIncomingTransfer(transfer);
140  }
141 
142  public:
143  TransferForwarder(SelfType& obj,
144  const DataTypeDescriptor& data_type,
145  uint16_t max_buffer_size,
146  IPoolAllocator& allocator) :
147  TransferListenerType(obj.node_.getDispatcher().getTransferPerfCounter(),
148  data_type,
149  max_buffer_size,
150  allocator),
151  obj_(obj)
152  { }
153  };
154 
156 
157  int checkInit();
158 
159  void handleIncomingTransfer(IncomingTransfer& transfer);
160 
161  int genericStart(bool (Dispatcher::*registration_method)(TransferListener*));
162 
163 protected:
165  {
167 
169  ReceivedDataStructure<DataStruct>(arg_transfer)
170  { }
171  };
172 
174  { }
175 
176  virtual ~GenericSubscriber() { stop(); }
177 
178  virtual void handleReceivedDataStruct(ReceivedDataStructure<DataStruct>&) = 0;
179 
181  {
182  UAVCAN_TRACE("GenericSubscriber", "Start as message listener; dtname=%s", DataSpec::getDataTypeFullName());
183  return genericStart(&Dispatcher::registerMessageListener);
184  }
185 
187  {
188  UAVCAN_TRACE("GenericSubscriber", "Start as service request listener; dtname=%s",
189  DataSpec::getDataTypeFullName());
190  return genericStart(&Dispatcher::registerServiceRequestListener);
191  }
192 
194  {
195  UAVCAN_TRACE("GenericSubscriber", "Start as service response listener; dtname=%s",
196  DataSpec::getDataTypeFullName());
197  return genericStart(&Dispatcher::registerServiceResponseListener);
198  }
199 
205  {
206  forwarder_->allowAnonymousTransfers();
207  }
208 
213  void stop()
214  {
215  UAVCAN_TRACE("GenericSubscriber", "Stop; dtname=%s", DataSpec::getDataTypeFullName());
216  GenericSubscriberBase::stop(forwarder_);
217  }
218 
219  TransferListenerType* getTransferListener() { return forwarder_; }
220 };
221 
222 // ----------------------------------------------------------------------------
223 
224 /*
225  * GenericSubscriber
226  */
227 template <typename DataSpec, typename DataStruct, typename TransferListenerType>
229 {
230  if (forwarder_)
231  {
232  return 0;
233  }
234 
236  const DataTypeDescriptor* const descr =
237  GlobalDataTypeRegistry::instance().find(DataTypeKind(DataSpec::DataTypeKind), DataSpec::getDataTypeFullName());
238  if (descr == UAVCAN_NULLPTR)
239  {
240  UAVCAN_TRACE("GenericSubscriber", "Type [%s] is not registered", DataSpec::getDataTypeFullName());
241  return -ErrUnknownDataType;
242  }
243 
244  static const uint16_t MaxBufferSize = BitLenToByteLen<DataStruct::MaxBitLen>::Result;
245 
246  forwarder_.template construct<SelfType&, const DataTypeDescriptor&, uint16_t, IPoolAllocator&>
247  (*this, *descr, MaxBufferSize, node_.getAllocator());
248 
249  return 0;
250 }
251 
252 template <typename DataSpec, typename DataStruct, typename TransferListenerType>
254 {
255  ReceivedDataStructureSpec rx_struct(&transfer);
256 
257  /*
258  * Decoding into the temporary storage
259  */
260  BitStream bitstream(transfer);
261  ScalarCodec codec(bitstream);
262 
263  const int decode_res = DataStruct::decode(rx_struct, codec);
264 
265  // We don't need the data anymore, the memory can be reused from the callback:
266  transfer.release();
267 
268  if (decode_res <= 0)
269  {
270  UAVCAN_TRACE("GenericSubscriber", "Unable to decode the message [%i] [%s]",
271  decode_res, DataSpec::getDataTypeFullName());
272  failure_count_++;
273  node_.getDispatcher().getTransferPerfCounter().addError();
274  return;
275  }
276 
277  /*
278  * Invoking the callback
279  */
280  handleReceivedDataStruct(rx_struct);
281 }
282 
283 template <typename DataSpec, typename DataStruct, typename TransferListenerType>
285 genericStart(bool (Dispatcher::*registration_method)(TransferListener*))
286 {
287  const int res = checkInit();
288  if (res < 0)
289  {
290  UAVCAN_TRACE("GenericSubscriber", "Initialization failure [%s]", DataSpec::getDataTypeFullName());
291  return res;
292  }
293  return GenericSubscriberBase::genericStart(forwarder_, registration_method);
294 }
295 
296 
297 }
298 
299 #endif // UAVCAN_NODE_GENERIC_SUBSCRIBER_HPP_INCLUDED
std::uint8_t uint8_t
Definition: std.hpp:24
DataTypeKind
Definition: data_type.hpp:19
bool registerServiceRequestListener(TransferListener *listener)
const DataTypeDescriptor * find(const char *name) const
GenericSubscriber< DataSpec, DataStruct, TransferListenerType > SelfType
void handleIncomingTransfer(IncomingTransfer &transfer)
TransferForwarder(SelfType &obj, const DataTypeDescriptor &data_type, uint16_t max_buffer_size, IPoolAllocator &allocator)
Implicitly convertible to/from uavcan.Timestamp.
Definition: time.hpp:191
std::uint32_t uint32_t
Definition: std.hpp:26
ReceivedDataStructureSpec(const IncomingTransfer *arg_transfer)
void handleIncomingTransfer(IncomingTransfer &transfer)
bool registerMessageListener(TransferListener *listener)
TransferType
Definition: transfer.hpp:18
MonotonicTime getMonotonicTimestamp() const
bool registerServiceResponseListener(TransferListener *listener)
ReceivedDataStructure(const IncomingTransfer *arg_transfer)
static GlobalDataTypeRegistry & instance()
void stop(TransferListener *listener)
int genericStart(bool(Dispatcher::*registration_method)(TransferListener *))
std::uint16_t uint16_t
Definition: std.hpp:25
LazyConstructor< TransferForwarder > forwarder_
int genericStart(TransferListener *listener, bool(Dispatcher::*registration_method)(TransferListener *))
TransferListenerType * getTransferListener()
const IncomingTransfer *const _transfer_
Such weird name is necessary to avoid clashing with DataType fields.
TransferPriority getPriority() const
int
Definition: libstubs.cpp:120
TransferType getTransferType() const


uavcan_communicator
Author(s):
autogenerated on Wed Jan 11 2023 03:59:39