uc_dispatcher.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
6 #include <uavcan/debug.hpp>
7 #include <cassert>
8 
9 namespace uavcan
10 {
11 #if !UAVCAN_TINY
12 /*
13  * LoopbackFrameListenerBase
14  */
16 {
18 }
19 
21 {
23 }
24 
26 {
28 }
29 
30 /*
31  * LoopbackFrameListenerRegistry
32  */
34 {
35  UAVCAN_ASSERT(listener);
36  listeners_.insert(listener);
37 }
38 
40 {
41  UAVCAN_ASSERT(listener);
42  listeners_.remove(listener);
43 }
44 
46 {
47  UAVCAN_ASSERT(listener);
48  const LoopbackFrameListenerBase* p = listeners_.get();
49  while (p)
50  {
51  if (p == listener)
52  {
53  return true;
54  }
55  p = p->getNextListNode();
56  }
57  return false;
58 }
59 
61 {
62  LoopbackFrameListenerBase* p = listeners_.get();
63  while (p)
64  {
65  LoopbackFrameListenerBase* const next = p->getNextListNode();
66  p->handleLoopbackFrame(frame); // p may be modified
67  p = next;
68  }
69 }
70 #endif
71 
72 /*
73  * Dispatcher::ListenerRegister
74  */
76 {
77  if (mode == UniqueListener)
78  {
79  TransferListener* p = list_.get();
80  while (p)
81  {
82  if (p->getDataTypeDescriptor().getID() == listener->getDataTypeDescriptor().getID())
83  {
84  return false;
85  }
86  p = p->getNextListNode();
87  }
88  }
89  // Objective is to arrange entries by Data Type ID in ascending order from root.
90  list_.insertBefore(listener, DataTypeIDInsertionComparator(listener->getDataTypeDescriptor().getID()));
91  return true;
92 }
93 
95 {
96  list_.remove(listener);
97 }
98 
100 {
101  TransferListener* p = list_.get();
102  while (p)
103  {
104  if (p->getDataTypeDescriptor().getID() == dtid)
105  {
106  return true;
107  }
108  p = p->getNextListNode();
109  }
110  return false;
111 }
112 
114 {
115  TransferListener* p = list_.get();
116  while (p)
117  {
118  TransferListener* const next = p->getNextListNode();
119  p->cleanup(ts); // p may be modified
120  p = next;
121  }
122 }
123 
125 {
126  TransferListener* p = list_.get();
127  while (p)
128  {
129  TransferListener* const next = p->getNextListNode();
130  if (p->getDataTypeDescriptor().getID() == frame.getDataTypeID())
131  {
132  p->handleFrame(frame); // p may be modified
133  }
134  else if (p->getDataTypeDescriptor().getID() < frame.getDataTypeID()) // Listeners are ordered by data type id!
135  {
136  break;
137  }
138  else
139  {
140  ; // Nothing to do with this one
141  }
142  p = next;
143  }
144 }
145 
146 /*
147  * Dispatcher
148  */
149 void Dispatcher::handleFrame(const CanRxFrame& can_frame)
150 {
151  RxFrame frame;
152  if (!frame.parse(can_frame))
153  {
154  // This is not counted as a transport error
155  UAVCAN_TRACE("Dispatcher", "Invalid CAN frame received: %s", can_frame.toString().c_str());
156  return;
157  }
158 
159  if ((frame.getDstNodeID() != NodeID::Broadcast) &&
160  (frame.getDstNodeID() != getNodeID()))
161  {
162  return;
163  }
164 
165  switch (frame.getTransferType())
166  {
168  {
169  lmsg_.handleFrame(frame);
170  break;
171  }
173  {
174  lsrv_req_.handleFrame(frame);
175  break;
176  }
178  {
179  lsrv_resp_.handleFrame(frame);
180  break;
181  }
182  default:
183  {
184  UAVCAN_ASSERT(0);
185  break;
186  }
187  }
188 }
189 
190 #if UAVCAN_TINY
192 {
193 }
194 
196 {
197 }
198 #else
200 {
201  RxFrame frame;
202  if (!frame.parse(can_frame))
203  {
204  UAVCAN_TRACE("Dispatcher", "Invalid loopback CAN frame: %s", can_frame.toString().c_str());
205  UAVCAN_ASSERT(0); // No way!
206  return;
207  }
208  UAVCAN_ASSERT(frame.getSrcNodeID() == getNodeID());
209  loopback_listeners_.invokeListeners(frame);
210 }
211 
213 {
214  if (rx_listener_ != UAVCAN_NULLPTR)
215  {
216  rx_listener_->handleRxFrame(can_frame, flags);
217  }
218 }
219 #endif
220 
222 {
223  int num_frames_processed = 0;
224  do
225  {
226  CanIOFlags flags = 0;
228  const int res = canio_.receive(frame, deadline, flags);
229  if (res < 0)
230  {
231  return res;
232  }
233  if (res > 0)
234  {
235  if (flags & CanIOFlagLoopback)
236  {
237  handleLoopbackFrame(frame);
238  }
239  else
240  {
241  num_frames_processed++;
242  handleFrame(frame);
243  }
244  notifyRxFrameListener(frame, flags);
245  }
246  }
247  while (sysclock_.getMonotonic() < deadline);
248 
249  return num_frames_processed;
250 }
251 
253 {
254  int num_frames_processed = 0;
255 
256  while (true)
257  {
258  CanIOFlags flags = 0;
260  const int res = canio_.receive(frame, MonotonicTime(), flags);
261  if (res < 0)
262  {
263  return res;
264  }
265  else if (res > 0)
266  {
267  if (flags & CanIOFlagLoopback)
268  {
269  handleLoopbackFrame(frame);
270  }
271  else
272  {
273  num_frames_processed++;
274  handleFrame(frame);
275  }
276  notifyRxFrameListener(frame, flags);
277  }
278  else
279  {
280  break; // No frames left
281  }
282  }
283 
284  return num_frames_processed;
285 }
286 
287 int Dispatcher::send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline,
288  CanIOFlags flags, uint8_t iface_mask)
289 {
290  if (frame.getSrcNodeID() != getNodeID())
291  {
292  UAVCAN_ASSERT(0);
293  return -ErrLogic;
294  }
295 
296  CanFrame can_frame;
297  if (!frame.compile(can_frame))
298  {
299  UAVCAN_TRACE("Dispatcher", "Unable to send: frame is malformed: %s", frame.toString().c_str());
300  UAVCAN_ASSERT(0);
301  return -ErrLogic;
302  }
303  return canio_.send(can_frame, tx_deadline, blocking_deadline, iface_mask, flags);
304 }
305 
307 {
308  outgoing_transfer_reg_.cleanup(ts);
309  lmsg_.cleanup(ts);
310  lsrv_req_.cleanup(ts);
311  lsrv_resp_.cleanup(ts);
312 }
313 
315 {
317  {
318  UAVCAN_ASSERT(0);
319  return false;
320  }
321  return lmsg_.add(listener, ListenerRegistry::ManyListeners); // Multiple subscribers are OK
322 }
323 
325 {
327  {
328  UAVCAN_ASSERT(0);
329  return false;
330  }
331  return lsrv_req_.add(listener, ListenerRegistry::UniqueListener); // Only one server per data type
332 }
333 
335 {
337  {
338  UAVCAN_ASSERT(0);
339  return false;
340  }
341  return lsrv_resp_.add(listener, ListenerRegistry::ManyListeners); // Multiple callers may call same srv
342 }
343 
345 {
346  lmsg_.remove(listener);
347 }
348 
350 {
351  lsrv_req_.remove(listener);
352 }
353 
355 {
356  lsrv_resp_.remove(listener);
357 }
358 
360 {
361  return lmsg_.exists(dtid);
362 }
363 
365 {
366  return outgoing_transfer_reg_.exists(dtid, TransferTypeMessageBroadcast);
367 }
368 
370 {
371  return lsrv_req_.exists(dtid);
372 }
373 
375 {
376  if (!self_node_id_is_set_)
377  {
378  self_node_id_ = nid;
379  self_node_id_is_set_ = true;
380  return true;
381  }
382  return false;
383 }
384 
385 }
void handleFrame(const CanRxFrame &can_frame)
LoopbackFrameListenerRegistry & getLoopbackFrameListenerRegistry()
Definition: dispatcher.hpp:207
std::uint8_t uint8_t
Definition: std.hpp:24
TransferType getTransferType() const
Definition: frame.hpp:75
bool doesExist(const LoopbackFrameListenerBase *listener) const
void notifyRxFrameListener(const CanRxFrame &can_frame, CanIOFlags flags)
const DataTypeDescriptor & getDataTypeDescriptor() const
int send(const Frame &frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, CanIOFlags flags, uint8_t iface_mask)
bool registerServiceRequestListener(TransferListener *listener)
static const NodeID Broadcast
Definition: transfer.hpp:122
bool hasSubscriber(DataTypeID dtid) const
DataTypeID getDataTypeID() const
Definition: frame.hpp:76
int spin(MonotonicTime deadline)
void unregisterServiceRequestListener(TransferListener *listener)
bool hasPublisher(DataTypeID dtid) const
void add(LoopbackFrameListenerBase *listener)
NodeID getDstNodeID() const
Definition: frame.hpp:78
bool hasServer(DataTypeID dtid) const
DataTypeKind getKind() const
Definition: data_type.hpp:158
void remove(TransferListener *listener)
T * getNextListNode() const
Definition: linked_list.hpp:32
void unregisterServiceResponseListener(TransferListener *listener)
void remove(LoopbackFrameListenerBase *listener)
void cleanup(MonotonicTime ts)
void unregisterMessageListener(TransferListener *listener)
virtual void handleFrame(const RxFrame &frame)
NodeID getSrcNodeID() const
Definition: frame.hpp:77
virtual void handleLoopbackFrame(const RxFrame &frame)=0
void handleFrame(const RxFrame &frame)
bool registerMessageListener(TransferListener *listener)
DataTypeID getID() const
Definition: data_type.hpp:159
bool compile(CanFrame &can_frame) const
Definition: uc_frame.cpp:112
bool registerServiceResponseListener(TransferListener *listener)
void cleanup(MonotonicTime ts)
bool setNodeID(NodeID nid)
bool parse(const CanRxFrame &can_frame)
Definition: uc_frame.cpp:304
uavcan::CanFrame frame
Definition: can.cpp:78
void handleLoopbackFrame(const CanRxFrame &can_frame)
static const CanIOFlags CanIOFlagLoopback
bool add(TransferListener *listener, Mode mode)
bool exists(DataTypeID dtid) const


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