node.py
Go to the documentation of this file.
1 #
2 # Copyright (C) 2014-2015 UAVCAN Development Team <uavcan.org>
3 #
4 # This software is distributed under the terms of the MIT License.
5 #
6 # Author: Ben Dyer <ben_dyer@mac.com>
7 # Pavel Kirienko <pavel.kirienko@zubax.com>
8 #
9 
10 from __future__ import division, absolute_import, print_function, unicode_literals
11 import time
12 import collections
13 import sched
14 import sys
15 import inspect
16 from logging import getLogger
17 
18 import pyuavcan_v0
19 import pyuavcan_v0.driver as driver
20 import pyuavcan_v0.transport as transport
21 from pyuavcan_v0.transport import get_uavcan_data_type
22 from pyuavcan_v0 import UAVCANException
23 
24 
25 DEFAULT_NODE_STATUS_INTERVAL = 1.0
26 DEFAULT_SERVICE_TIMEOUT = 1.0
27 DEFAULT_TRANSFER_PRIORITY = 20
28 
29 
30 logger = getLogger(__name__)
31 
32 
33 class Scheduler(object):
34  """This class implements a simple non-blocking event scheduler.
35  It supports one-shot and periodic events.
36  """
37 
38  def __init__(self):
39  if sys.version_info[0] > 2:
40  # Nice and easy.
41  self._scheduler = sched.scheduler()
42  # The documentation says that run() returns the next deadline,
43  # but it's not true - it returns the remaining time.
44  self._run_scheduler = lambda: self._scheduler.run(blocking=False) + self._scheduler.timefunc()
45  else:
46  # Nightmare inducing hacks
47  class SayNoToBlockingSchedulingException(pyuavcan_v0.UAVCANException):
48  pass
49 
50  def delayfunc_impostor(duration):
51  if duration > 0:
52  raise SayNoToBlockingSchedulingException('No!')
53 
54  self._scheduler = sched.scheduler(time.monotonic, delayfunc_impostor)
55 
56  def run_scheduler():
57  try:
58  self._scheduler.run()
59  except SayNoToBlockingSchedulingException:
60  q = self._scheduler.queue
61  return q[0][0] if q else None
62 
63  self._run_scheduler = run_scheduler
64 
65  def _make_sched_handle(self, get_event):
66  class EventHandle(object):
67  @staticmethod
68  def remove():
69  self._scheduler.cancel(get_event())
70 
71  @staticmethod
72  def try_remove():
73  try:
74  self._scheduler.cancel(get_event())
75  return True
76  except ValueError:
77  return False
78 
79  return EventHandle()
80 
82  return self._run_scheduler()
83 
84  def defer(self, timeout_seconds, callback):
85  """This method allows to invoke the callback with specified arguments once the specified amount of time.
86  :returns: EventHandle object. Call .remove() on it to cancel the event.
87  """
88  priority = 1
89  event = self._scheduler.enter(timeout_seconds, priority, callback, ())
90  return self._make_sched_handle(lambda: event)
91 
92  def periodic(self, period_seconds, callback):
93  """This method allows to invoke the callback periodically, with specified time intervals.
94  Note that the scheduler features zero phase drift.
95  :returns: EventHandle object. Call .remove() on it to cancel the event.
96  """
97  priority = 0
98 
99  def caller(scheduled_deadline):
100  # Event MUST be re-registered first in order to ensure that it can be cancelled from the callback
101  scheduled_deadline += period_seconds
102  event_holder[0] = self._scheduler.enterabs(scheduled_deadline, priority, caller, (scheduled_deadline,))
103  callback()
104 
105  first_deadline = self._scheduler.timefunc() + period_seconds
106  event_holder = [self._scheduler.enterabs(first_deadline, priority, caller, (first_deadline,))]
107  return self._make_sched_handle(lambda: event_holder[0])
108 
110  """Returns true if there is at least one pending event in the queue.
111  """
112  return not self._scheduler.empty()
113 
114 
115 class TransferEvent(object):
116  def __init__(self, transfer, node, payload_attr_name):
117  setattr(self, payload_attr_name, transfer.payload)
118  self.transfer = transfer
119  self.node = node
120 
121  def __str__(self):
122  return str(self.transfer)
123 
124  def __repr__(self):
125  return repr(self.transfer)
126 
127 
129  def __init__(self, remover):
130  self._remover = remover
131 
132  def remove(self):
133  self._remover()
134 
135  def try_remove(self):
136  try:
137  self._remover()
138  return True
139  except ValueError:
140  return False
141 
142 
143 class HandlerDispatcher(object):
144  def __init__(self, node, catch_exceptions):
145  self._handlers = [] # type, callable
146  self._node = node
147  self._catch_exceptions = catch_exceptions
148 
149  def add_handler(self, uavcan_type, handler, **kwargs):
150  service = {
151  uavcan_type.KIND_SERVICE: True,
152  uavcan_type.KIND_MESSAGE: False
153  }[uavcan_type.kind]
154 
155  # If handler is a class, create a wrapper function and register it as a regular callback
156  if inspect.isclass(handler):
157  def class_handler_adapter(event):
158  h = handler(event, **kwargs)
159  if service:
160  h.on_request()
161  return h.response
162  else:
163  h.on_message()
164 
165  return self.add_handler(uavcan_type, class_handler_adapter)
166 
167  # At this point process the handler as a regular callback
168  def call(transfer):
169  event = TransferEvent(transfer, self._node, 'request' if service else 'message')
170  result = handler(event, **kwargs)
171  if service:
172  if result is None:
173  raise UAVCANException('Service request handler did not return a response [%r, %r]' %
174  (uavcan_type, handler))
175  self._node.respond(result,
176  transfer.source_node_id,
177  transfer.transfer_id,
178  transfer.transfer_priority)
179  else:
180  if result is not None:
181  raise UAVCANException('Message request handler did not return None [%r, %r]' %
182  (uavcan_type, handler))
183 
184  entry = uavcan_type, call
185  self._handlers.append(entry)
186  return HandleRemover(lambda: self._handlers.remove(entry))
187 
188  def remove_handlers(self, uavcan_type):
189  self._handlers = list(filter(lambda x: x[0] != uavcan_type, self._handlers))
190 
191  def call_handlers(self, transfer):
192  for uavcan_type, wrapper in self._handlers:
193  if uavcan_type == get_uavcan_data_type(transfer.payload):
194  try:
195  wrapper(transfer)
196  # noinspection PyBroadException
197  except Exception as e:
198  logger.error('Transfer handler exception', exc_info=True)
199  if not self._catch_exceptions:
200  raise e
201 
202 
204  TRANSFER_DIRECTION_INCOMING = 'rx'
205  TRANSFER_DIRECTION_OUTGOING = 'tx'
206 
207  def __init__(self):
208  self._hooks = []
209 
210  def add_hook(self, hook, **kwargs):
211  def proxy(transfer):
212  hook(transfer, **kwargs)
213  self._hooks.append(proxy)
214  return HandleRemover(lambda: self._hooks.remove(proxy))
215 
216  def call_hooks(self, direction, transfer):
217  setattr(transfer, 'direction', direction)
218  for hook in self._hooks:
219  # noinspection PyBroadException
220  try:
221  hook(transfer)
222  except Exception:
223  logger.error('Transfer hook exception', exc_info=True)
224 
225 
227  def __init__(self, can_driver, node_id=None, node_status_interval=None,
228  mode=None, node_info=None, catch_handler_exceptions=True,
229  **_extras):
230  """
231  It is recommended to use make_node() rather than instantiating this type directly.
232 
233  :param can_driver: CAN bus driver object. Calling close() on a node object closes its driver instance.
234 
235  :param node_id: Node ID of the current instance. Defaults to None, which enables passive mode.
236 
237  :param node_status_interval: NodeStatus broadcasting interval. Defaults to DEFAULT_NODE_STATUS_INTERVAL.
238 
239  :param mode: Initial operating mode (INITIALIZATION, OPERATIONAL, etc.); defaults to INITIALIZATION.
240 
241  :param node_info: Structure of type pyuavcan_v0.protocol.GetNodeInfo.Response, responded with when the local
242  node is queried for its node info.
243  :param catch_handler_exceptions: If true, exceptions raised from message
244  handlers will be caught and logged. If
245  False, spin() will raise exceptions
246  raised from callbacks.
247  """
248  super(Node, self).__init__()
249 
250  self._handler_dispatcher = HandlerDispatcher(self, catch_handler_exceptions)
251 
252  self._can_driver = can_driver
253  self._node_id = node_id
254 
258  self._next_transfer_ids = collections.defaultdict(int)
259 
260  self.start_time_monotonic = time.monotonic()
261 
262  # Hooks
264 
265  # NodeStatus publisher
266  self.health = pyuavcan_v0.protocol.NodeStatus().HEALTH_OK # @UndefinedVariable
267  self.mode = pyuavcan_v0.protocol.NodeStatus().MODE_INITIALIZATION if mode is None else mode # @UndefinedVariable
269 
270  node_status_interval = node_status_interval or DEFAULT_NODE_STATUS_INTERVAL
271  self.periodic(node_status_interval, self._send_node_status)
272 
273  # GetNodeInfo server
274  def on_get_node_info(e):
275  logger.debug('GetNodeInfo request from %r', e.transfer.source_node_id)
276  self._fill_node_status(self.node_info.status)
277  return self.node_info
278  self.node_info = node_info or pyuavcan_v0.protocol.GetNodeInfo.Response() # @UndefinedVariable
279  self.add_handler(pyuavcan_v0.protocol.GetNodeInfo, on_get_node_info) # @UndefinedVariable
280 
281  @property
282  def is_anonymous(self):
283  return (self._node_id or 0) == 0
284 
285  @property
286  def node_id(self):
287  return self._node_id
288 
289  @node_id.setter
290  def node_id(self, value):
291  if self.is_anonymous:
292  value = int(value)
293  if not (1 <= value <= 127):
294  raise ValueError('Invalid Node ID [%d]' % value)
295  self._node_id = value
296  else:
297  raise UAVCANException('Node ID can be set only once')
298 
299  @property
300  def can_driver(self):
301  return self._can_driver
302 
303  def _recv_frame(self, raw_frame):
304  if not raw_frame.extended:
305  return
306 
307  frame = transport.Frame(raw_frame.id, raw_frame.data, raw_frame.ts_monotonic, raw_frame.ts_real)
308 
309  transfer_frames = self._transfer_manager.receive_frame(frame)
310  if not transfer_frames:
311  return
312 
313  transfer = transport.Transfer()
314  transfer.from_frames(transfer_frames)
315 
316  self._transfer_hook_dispatcher.call_hooks(self._transfer_hook_dispatcher.TRANSFER_DIRECTION_INCOMING, transfer)
317 
318  if (transfer.service_not_message and not transfer.request_not_response) and \
319  transfer.dest_node_id == self._node_id:
320  # This is a reply to a request we sent. Look up the original request and call the appropriate callback
321  requests = self._outstanding_requests.keys()
322  for key in requests:
323  if transfer.is_response_to(self._outstanding_requests[key]):
324  # Call the request's callback and remove it from the active list
325  event = TransferEvent(transfer, self, 'response')
326  self._outstanding_request_callbacks[key](event)
327  del self._outstanding_requests[key]
328  del self._outstanding_request_callbacks[key]
329  break
330  elif not transfer.service_not_message or transfer.dest_node_id == self._node_id:
331  # This is a request or a broadcast; look up the appropriate handler by data type ID
332  self._handler_dispatcher.call_handlers(transfer)
333 
334  def _next_transfer_id(self, key):
335  transfer_id = self._next_transfer_ids[key]
336  self._next_transfer_ids[key] = (transfer_id + 1) & 0x1F
337  return transfer_id
338 
340  if not self._node_id:
341  raise pyuavcan_v0.UAVCANException('The local node is configured in anonymous mode')
342 
343  def _fill_node_status(self, msg):
344  msg.uptime_sec = int(time.monotonic() - self.start_time_monotonic + 0.5)
345  msg.health = self.health
346  msg.mode = self.mode
347  msg.vendor_specific_status_code = self.vendor_specific_status_code
348 
349  def _send_node_status(self):
350  self._fill_node_status(self.node_info.status)
351  if self._node_id:
352  # TODO: transmit self.node_info.status instead of creating a new object
353  msg = pyuavcan_v0.protocol.NodeStatus() # @UndefinedVariable
354  self._fill_node_status(msg)
355  self.broadcast(msg)
356 
357  def add_transfer_hook(self, hook, **kwargs):
358  """
359  :param hook: Callable hook; expected signature: hook(transfer).
360  :param kwargs: Extra arguments for the hook.
361  :return: A handle object that can be used to unregister the hook by calling remove() on it.
362  """
363  return self._transfer_hook_dispatcher.add_hook(hook, **kwargs)
364 
365  def add_handler(self, uavcan_type, handler, **kwargs):
366  """
367  Adds a handler for the specified data type.
368  :param uavcan_type: DSDL data type. Only transfers of this type will be accepted for this handler.
369  :param handler: The handler. This must be either a callable or a class.
370  :param **kwargs: Extra arguments for the handler.
371  :return: A remover object that can be used to unregister the handler as follows:
372  x = node.add_handler(...)
373  # Remove the handler like this:
374  x.remove()
375  # Or like this:
376  if x.try_remove():
377  print('The handler has been removed successfully')
378  else:
379  print('There is no such handler')
380  """
381  return self._handler_dispatcher.add_handler(uavcan_type, handler, **kwargs)
382 
383  def remove_handlers(self, uavcan_type):
384  """Removes all handlers for the specified DSDL data type.
385  """
386  self._handler_dispatcher.remove_handlers(uavcan_type)
387 
388  def spin(self, timeout=None):
389  """
390  Runs background processes until timeout expires.
391  Note that all processing is implemented in one thread.
392  :param timeout: The method will return once this amount of time expires.
393  If None, the method will never return.
394  If zero, the method will handle only those events that are ready, then return immediately.
395  """
396  if timeout != 0:
397  deadline = (time.monotonic() + timeout) if timeout is not None else sys.float_info.max
398 
399  def execute_once():
400  next_event_at = self._poll_scheduler_and_get_next_deadline()
401  if next_event_at is None:
402  next_event_at = sys.float_info.max
403 
404  read_timeout = min(next_event_at, deadline) - time.monotonic()
405  read_timeout = max(read_timeout, 0)
406  read_timeout = min(read_timeout, 1)
407 
408  frame = self._can_driver.receive(read_timeout)
409  if frame:
410  self._recv_frame(frame)
411 
412  execute_once()
413  while time.monotonic() < deadline:
414  execute_once()
415  else:
416  while True:
417  frame = self._can_driver.receive(0)
418  if frame:
419  self._recv_frame(frame)
420  else:
421  break
423 
424  def request(self, payload, dest_node_id, callback, priority=None, timeout=None):
425  self._throw_if_anonymous()
426 
427  # Preparing the transfer
428  transfer_id = self._next_transfer_id((get_uavcan_data_type(payload).default_dtid, dest_node_id))
429  transfer = transport.Transfer(payload=payload,
430  source_node_id=self._node_id,
431  dest_node_id=dest_node_id,
432  transfer_id=transfer_id,
433  transfer_priority=priority or DEFAULT_TRANSFER_PRIORITY,
434  service_not_message=True,
435  request_not_response=True)
436 
437  # Calling hooks
438  self._transfer_hook_dispatcher.call_hooks(self._transfer_hook_dispatcher.TRANSFER_DIRECTION_OUTGOING, transfer)
439 
440  # Sending the transfer
441  for frame in transfer.to_frames():
442  self._can_driver.send(frame.message_id, frame.bytes, extended=True)
443 
444  # Registering a callback that will be invoked if there was no response after 'timeout' seconds
445  def on_timeout():
446  try:
447  del self._outstanding_requests[transfer.key]
448  except KeyError:
449  pass
450  try:
451  del self._outstanding_request_callbacks[transfer.key]
452  except KeyError:
453  pass
454  callback(None)
455 
456  timeout = timeout or DEFAULT_SERVICE_TIMEOUT
457  timeout_caller_handle = self.defer(timeout, on_timeout)
458 
459  # This wrapper will automatically cancel the timeout callback if there was a response
460  def timeout_cancelling_wrapper(event):
461  timeout_caller_handle.try_remove()
462  callback(event)
463 
464  # Registering the pending request using the wrapper above instead of the callback
465  self._outstanding_requests[transfer.key] = transfer
466  self._outstanding_request_callbacks[transfer.key] = timeout_cancelling_wrapper
467 
468  logger.debug("Node.request(dest_node_id={0:d}): sent {1!r}".format(dest_node_id, payload))
469 
470  def respond(self, payload, dest_node_id, transfer_id, priority):
471  self._throw_if_anonymous()
472 
473  transfer = transport.Transfer(
474  payload=payload,
475  source_node_id=self._node_id,
476  dest_node_id=dest_node_id,
477  transfer_id=transfer_id,
478  transfer_priority=priority,
479  service_not_message=True,
480  request_not_response=False
481  )
482 
483  self._transfer_hook_dispatcher.call_hooks(self._transfer_hook_dispatcher.TRANSFER_DIRECTION_OUTGOING, transfer)
484 
485  for frame in transfer.to_frames():
486  self._can_driver.send(frame.message_id, frame.bytes, extended=True)
487 
488  logger.debug("Node.respond(dest_node_id={0:d}, transfer_id={0:d}, priority={0:d}): sent {1!r}"
489  .format(dest_node_id, transfer_id, priority, payload))
490 
491  def broadcast(self, payload, priority=None):
492  self._throw_if_anonymous()
493 
494  transfer_id = self._next_transfer_id(get_uavcan_data_type(payload).default_dtid)
495  transfer = transport.Transfer(payload=payload,
496  source_node_id=self._node_id,
497  transfer_id=transfer_id,
498  transfer_priority=priority or DEFAULT_TRANSFER_PRIORITY,
499  service_not_message=False)
500 
501  self._transfer_hook_dispatcher.call_hooks(self._transfer_hook_dispatcher.TRANSFER_DIRECTION_OUTGOING, transfer)
502 
503  for frame in transfer.to_frames():
504  self._can_driver.send(frame.message_id, frame.bytes, extended=True)
505 
506  def close(self):
507  self._can_driver.close()
508 
509 
510 def make_node(can_device_name, **kwargs):
511  """Constructs a node instance with specified CAN device.
512  :param can_device_name: CAN device name, e.g. "/dev/ttyACM0", "COM9", "can0".
513  :param kwargs: These arguments will be supplied to the CAN driver factory and to the node constructor.
514  """
515  can = driver.make_driver(can_device_name, **kwargs)
516  return Node(can, **kwargs)
517 
518 
519 class Monitor(object):
520  def __init__(self, event):
521  self.message = event.message
522  self.transfer = event.transfer
523  self.node = event.node
524 
525  def on_message(self):
526  pass
527 
528 
529 class Service(object):
530  def __init__(self, event):
531  self.request = event.request
532  self.transfer = event.transfer
533  self.node = event.node
534  self.response = get_uavcan_data_type(self.request).Response()
535 
536  def on_request(self):
537  pass
pyuavcan_v0.node.Node._next_transfer_id
def _next_transfer_id(self, key)
Definition: node.py:334
pyuavcan_v0.node.HandlerDispatcher.remove_handlers
def remove_handlers(self, uavcan_type)
Definition: node.py:188
pyuavcan_v0.node.Scheduler._poll_scheduler_and_get_next_deadline
def _poll_scheduler_and_get_next_deadline(self)
Definition: node.py:81
pyuavcan_v0.driver
Definition: pyuavcan/pyuavcan_v0/driver/__init__.py:1
pyuavcan_v0.node.Node._send_node_status
def _send_node_status(self)
Definition: node.py:349
pyuavcan_v0.node.Node._fill_node_status
def _fill_node_status(self, msg)
Definition: node.py:343
pyuavcan_v0.node.Node.respond
def respond(self, payload, dest_node_id, transfer_id, priority)
Definition: node.py:470
pyuavcan_v0.node.Node.can_driver
def can_driver(self)
Definition: node.py:300
pyuavcan_v0.node.Node.is_anonymous
def is_anonymous(self)
Definition: node.py:282
pyuavcan_v0.node.HandlerDispatcher._handlers
_handlers
Definition: node.py:145
pyuavcan_v0.node.HandlerDispatcher.call_handlers
def call_handlers(self, transfer)
Definition: node.py:191
pyuavcan_v0.node.Scheduler._make_sched_handle
def _make_sched_handle(self, get_event)
Definition: node.py:65
pyuavcan_v0.node.Monitor.on_message
def on_message(self)
Definition: node.py:525
pyuavcan_v0.node.Monitor.transfer
transfer
Definition: node.py:522
pyuavcan_v0.node.TransferEvent
Definition: node.py:115
pyuavcan_v0.node.TransferHookDispatcher.__init__
def __init__(self)
Definition: node.py:207
pyuavcan_v0.node.Node.node_id
def node_id(self)
Definition: node.py:286
pyuavcan_v0.node.Node.broadcast
def broadcast(self, payload, priority=None)
Definition: node.py:491
pyuavcan_v0.node.Node._can_driver
_can_driver
Definition: node.py:250
pyuavcan_v0.node.Scheduler.periodic
def periodic(self, period_seconds, callback)
Definition: node.py:92
pyuavcan_v0.node.Node.vendor_specific_status_code
vendor_specific_status_code
Definition: node.py:266
pyuavcan_v0.node.make_node
def make_node(can_device_name, **kwargs)
Definition: node.py:510
pyuavcan_v0.node.Node._outstanding_request_callbacks
_outstanding_request_callbacks
Definition: node.py:255
pyuavcan_v0.node.Service.transfer
transfer
Definition: node.py:532
pyuavcan_v0.node.TransferEvent.node
node
Definition: node.py:119
pyuavcan_v0.node.Node
Definition: node.py:226
pyuavcan_v0.node.Node._recv_frame
def _recv_frame(self, raw_frame)
Definition: node.py:303
pyuavcan_v0.node.Node._node_id
_node_id
Definition: node.py:251
libuavcan_dsdl_compiler.str
str
Definition: libuavcan_dsdl_compiler/__init__.py:22
pyuavcan_v0.node.Node._throw_if_anonymous
def _throw_if_anonymous(self)
Definition: node.py:339
pyuavcan_v0.node.TransferHookDispatcher._hooks
_hooks
Definition: node.py:208
pyuavcan_v0.UAVCANException
Definition: pyuavcan/pyuavcan_v0/__init__.py:45
pyuavcan_v0.node.Node.__init__
def __init__(self, can_driver, node_id=None, node_status_interval=None, mode=None, node_info=None, catch_handler_exceptions=True, **_extras)
Definition: node.py:227
pyuavcan_v0.node.Node._next_transfer_ids
_next_transfer_ids
Definition: node.py:256
pyuavcan_v0.node.Monitor.__init__
def __init__(self, event)
Definition: node.py:520
pyuavcan_v0.node.Node._transfer_hook_dispatcher
_transfer_hook_dispatcher
Definition: node.py:261
libuavcan_dsdl_compiler.run
def run(source_dirs, include_dirs, output_dir)
Definition: libuavcan_dsdl_compiler/__init__.py:37
pyuavcan_v0.node.TransferHookDispatcher.call_hooks
def call_hooks(self, direction, transfer)
Definition: node.py:216
pyuavcan_v0.node.Service.request
request
Definition: node.py:531
pyuavcan_v0.node.TransferEvent.__repr__
def __repr__(self)
Definition: node.py:124
pyuavcan_v0.node.HandleRemover.try_remove
def try_remove(self)
Definition: node.py:135
uavcan::max
const UAVCAN_EXPORT T & max(const T &a, const T &b)
Definition: templates.hpp:291
pyuavcan_v0.node.Node._transfer_manager
_transfer_manager
Definition: node.py:253
pyuavcan_v0.transport.TransferManager
Definition: transport.py:843
pyuavcan_v0.node.Service.response
response
Definition: node.py:534
pyuavcan_v0.node.HandleRemover._remover
_remover
Definition: node.py:130
pyuavcan_v0.transport.Transfer
Definition: transport.py:653
pyuavcan_v0.node.HandleRemover
Definition: node.py:128
pyuavcan_v0.node.Service.node
node
Definition: node.py:533
pyuavcan_v0.node.Scheduler
Definition: node.py:33
uavcan::min
const UAVCAN_EXPORT T & min(const T &a, const T &b)
Definition: templates.hpp:281
pyuavcan_v0.node.HandleRemover.__init__
def __init__(self, remover)
Definition: node.py:129
pyuavcan_v0.node.TransferEvent.transfer
transfer
Definition: node.py:118
pyuavcan_v0.node.Scheduler.__init__
def __init__(self)
Definition: node.py:38
pyuavcan_v0.node.Service.__init__
def __init__(self, event)
Definition: node.py:530
pyuavcan_v0.node.Monitor.node
node
Definition: node.py:523
pyuavcan_v0.node.Service.on_request
def on_request(self)
Definition: node.py:536
pyuavcan_v0.transport.get_uavcan_data_type
def get_uavcan_data_type(obj)
Definition: transport.py:42
pyuavcan_v0.node.Node.close
def close(self)
Definition: node.py:506
int
int
Definition: libstubs.cpp:120
pyuavcan_v0.node.HandlerDispatcher._node
_node
Definition: node.py:146
pyuavcan_v0.node.Node.remove_handlers
def remove_handlers(self, uavcan_type)
Definition: node.py:383
pyuavcan_v0.node.Node.spin
def spin(self, timeout=None)
Definition: node.py:388
pyuavcan_v0.node.Node._handler_dispatcher
_handler_dispatcher
Definition: node.py:248
pyuavcan_v0.node.Node._outstanding_requests
_outstanding_requests
Definition: node.py:254
pyuavcan_v0.node.Scheduler._run_scheduler
_run_scheduler
Definition: node.py:44
pyuavcan_v0.node.TransferHookDispatcher.add_hook
def add_hook(self, hook, **kwargs)
Definition: node.py:210
pyuavcan_v0.node.Node.start_time_monotonic
start_time_monotonic
Definition: node.py:258
pyuavcan_v0.node.TransferEvent.__init__
def __init__(self, transfer, node, payload_attr_name)
Definition: node.py:116
pyuavcan_v0.node.Node.request
def request(self, payload, dest_node_id, callback, priority=None, timeout=None)
Definition: node.py:424
pyuavcan_v0.node.Node.mode
mode
Definition: node.py:265
pyuavcan_v0.node.HandleRemover.remove
def remove(self)
Definition: node.py:132
pyuavcan_v0.node.Node.node_info
node_info
Definition: node.py:276
pyuavcan_v0.node.Monitor.message
message
Definition: node.py:521
pyuavcan_v0.node.HandlerDispatcher._catch_exceptions
_catch_exceptions
Definition: node.py:147
pyuavcan_v0.transport
Definition: transport.py:1
pyuavcan_v0.node.Node.health
health
Definition: node.py:264
pyuavcan_v0.node.TransferHookDispatcher
Definition: node.py:203
pyuavcan_v0.node.HandlerDispatcher.__init__
def __init__(self, node, catch_exceptions)
Definition: node.py:144
pyuavcan_v0.transport.Frame
Definition: transport.py:623
pyuavcan_v0.node.Scheduler.has_pending_events
def has_pending_events(self)
Definition: node.py:109
pyuavcan_v0.node.Scheduler._scheduler
_scheduler
Definition: node.py:41
pyuavcan_v0.node.Scheduler.defer
def defer(self, timeout_seconds, callback)
Definition: node.py:84
pyuavcan_v0.node.HandlerDispatcher.add_handler
def add_handler(self, uavcan_type, handler, **kwargs)
Definition: node.py:149
pyuavcan_v0.node.Monitor
Definition: node.py:519
pyuavcan_v0.node.HandlerDispatcher
Definition: node.py:143
pyuavcan_v0.node.Node.add_transfer_hook
def add_transfer_hook(self, hook, **kwargs)
Definition: node.py:357
pyuavcan_v0.node.Node.add_handler
def add_handler(self, uavcan_type, handler, **kwargs)
Definition: node.py:365
pyuavcan_v0.node.TransferEvent.__str__
def __str__(self)
Definition: node.py:121
test.format
format
Definition: dsdl/test.py:6


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:02