def _execute(self): result = self.on_request() # on_request generally wouldn't return anything, but if it's a # coroutine and it yields then we'll get a future back (the value # of which is irrelevant). Wait for the future to ensure the handler # has populated all the response fields. # FIXME #if tornado.concurrent.is_future(result): # result = yield result # Send the response transfer transfer = transport.Transfer( payload=self.response, source_node_id=self.node.node_id, dest_node_id=self.transfer.source_node_id, transfer_id=self.transfer.transfer_id, transfer_priority=self.transfer.transfer_priority, service_not_message=True, request_not_response=False ) for frame in transfer.to_frames(datatype_crc=self.request.type.base_crc): self.node.can.send(frame.message_id, frame.to_bytes(), extended=True) logging.info( "ServiceHandler._execute(dest_node_id={0:d}): sent {1!r}".format( self.transfer.source_node_id, self.response))
def _recv_frame(self, raw_frame): if not raw_frame.extended: return frame = transport.Frame(raw_frame.id, raw_frame.data, raw_frame.ts_monotonic, raw_frame.ts_real) transfer_frames = self._transfer_manager.receive_frame(frame) if not transfer_frames: return transfer = transport.Transfer() transfer.from_frames(transfer_frames) self._transfer_hook_dispatcher.call_hooks( self._transfer_hook_dispatcher.TRANSFER_DIRECTION_INCOMING, transfer) if (transfer.service_not_message and not transfer.request_not_response) and \ transfer.dest_node_id == self._node_id: # This is a reply to a request we sent. Look up the original request and call the appropriate callback requests = self._outstanding_requests.keys() for key in requests: if transfer.is_response_to(self._outstanding_requests[key]): # Call the request's callback and remove it from the active list event = TransferEvent(transfer, self, 'response') self._outstanding_request_callbacks[key](event) del self._outstanding_requests[key] del self._outstanding_request_callbacks[key] break elif not transfer.service_not_message or transfer.dest_node_id == self._node_id: # This is a request or a broadcast; look up the appropriate handler by data type ID self._handler_dispatcher.call_handlers(transfer)
def request(self, payload, dest_node_id, callback, priority=None, timeout=None): self._throw_if_anonymous() # Preparing the transfer transfer_id = self._next_transfer_id( (get_uavcan_data_type(payload).default_dtid, dest_node_id)) transfer = transport.Transfer(payload=payload, source_node_id=self._node_id, dest_node_id=dest_node_id, transfer_id=transfer_id, transfer_priority=priority or DEFAULT_TRANSFER_PRIORITY, service_not_message=True, request_not_response=True) # Calling hooks self._transfer_hook_dispatcher.call_hooks( self._transfer_hook_dispatcher.TRANSFER_DIRECTION_OUTGOING, transfer) # Sending the transfer for frame in transfer.to_frames(): self._can_driver.send(frame.message_id, frame.bytes, extended=True) # Registering a callback that will be invoked if there was no response after 'timeout' seconds def on_timeout(): try: del self._outstanding_requests[transfer.key] except KeyError: pass try: del self._outstanding_request_callbacks[transfer.key] except KeyError: pass callback(None) timeout = timeout or DEFAULT_SERVICE_TIMEOUT timeout_caller_handle = self.defer(timeout, on_timeout) # This wrapper will automatically cancel the timeout callback if there was a response def timeout_cancelling_wrapper(event): timeout_caller_handle.try_remove() callback(event) # Registering the pending request using the wrapper above instead of the callback self._outstanding_requests[transfer.key] = transfer self._outstanding_request_callbacks[ transfer.key] = timeout_cancelling_wrapper logger.debug("Node.request(dest_node_id={0:d}): sent {1!r}".format( dest_node_id, payload))
def _recv_frame(self, dev, message): frame_id, frame_data, ext_id = message if not ext_id: return frame = transport.Frame(frame_id, frame_data) # logging.debug("Node._recv_frame(): got {0!s}".format(frame)) transfer_frames = self.transfer_manager.receive_frame(frame) if not transfer_frames: return transfer = transport.Transfer() transfer.from_frames(transfer_frames) logging.debug("Node._recv_frame(): received {0!r}".format(transfer)) # If it's a node info request, keep track of the status of each node if transfer.payload.type == uavcan.protocol.NodeStatus: self.node_info[transfer.source_node_id] = { "uptime": transfer.payload.uptime_sec, "health": transfer.payload.health, "mode": transfer.payload.mode, "sub_mode": transfer.payload.sub_mode, "vendor_specific_status_code": transfer.payload.vendor_specific_status_code, "timestamp": time.time() } if (transfer.service_not_message and not transfer.request_not_response) and \ transfer.dest_node_id == self.node_id: # This is a reply to a request we sent. Look up the original # request and call the appropriate callback requests = self.outstanding_requests.keys() for key in requests: if transfer.is_response_to(self.outstanding_requests[key]): # Call the request's callback and remove it from the # active list self.outstanding_request_callbacks[key](transfer.payload, transfer) del self.outstanding_requests[key] del self.outstanding_request_callbacks[key] del self.outstanding_request_timestamps[key] del self.outstanding_request_retries[key] break elif not transfer.service_not_message or \ transfer.dest_node_id == self.node_id: # This is a request, a unicast or a broadcast; look up the # appropriate handler by data type ID for handler in self.handlers: if handler[0] == transfer.payload.type: kwargs = handler[2] if len(handler) == 3 else {} h = handler[1](transfer.payload, transfer, self, **kwargs) h._execute()
def send_message(self, payload): transfer_id = self._next_transfer_id(payload.type.default_dtid) transfer = transport.Transfer(payload=payload, source_node_id=self.node_id, transfer_id=transfer_id, service_not_message=False) for frame in transfer.to_frames(): self.can.send(frame.message_id, frame.bytes, extended=True) logging.debug("Node.send_message(): sent {0!r}".format(payload))
def broadcast(self, payload, priority=None): self._throw_if_anonymous() transfer_id = self._next_transfer_id(get_uavcan_data_type(payload).default_dtid) transfer = transport.Transfer(payload=payload, source_node_id=self._node_id, transfer_id=transfer_id, transfer_priority=priority or DEFAULT_TRANSFER_PRIORITY, service_not_message=False) self._transfer_hook_dispatcher.call_hooks(self._transfer_hook_dispatcher.TRANSFER_DIRECTION_OUTGOING, transfer) for frame in transfer.to_frames(): self._can_driver.send(frame.message_id, frame.bytes, extended=True)
def handle_raw_frame(self, raw_frame, handle_transfer=True): frame = transport.Frame(raw_frame.id, raw_frame.data, raw_frame.ts_monotonic, raw_frame.ts_real) transfer_frames = self._transfer_manager.receive_frame(frame) if not transfer_frames: return transfer = transport.Transfer() transfer.from_frames(transfer_frames) if handle_transfer: self.handle_transfer(transfer) return None else: return transfer
def setUp(self): msg = uavcan.protocol.debug.KeyValue() msg.key = 'foo' msg.value = 42 transfer = transport.Transfer( payload=msg, source_node_id=42, transfer_id=10, transfer_priority=DEFAULT_TRANSFER_PRIORITY, service_not_message=False) self.frames = [ CANFrame(can_id=f.message_id, data=f.bytes, extended=True) for f in transfer.to_frames() ] self.driver = Mock() self.driver.receive.side_effect = self.frames + [None]
def _execute(self): result = self.on_request() # Send the response transfer transfer = transport.Transfer( payload=self.response, source_node_id=self.node.node_id, dest_node_id=self.transfer.source_node_id, transfer_id=self.transfer.transfer_id, transfer_priority=self.transfer.transfer_priority, service_not_message=True, request_not_response=False) for frame in transfer.to_frames(): self.node.can.send(frame.message_id, frame.bytes, extended=True) logging.debug( "ServiceHandler._execute(dest_node_id={0:d}): sent {1!r}".format( self.transfer.source_node_id, self.response))
def respond(self, payload, dest_node_id, transfer_id, priority): self._throw_if_anonymous() transfer = transport.Transfer( payload=payload, source_node_id=self._node_id, dest_node_id=dest_node_id, transfer_id=transfer_id, transfer_priority=priority, service_not_message=True, request_not_response=False ) self._transfer_hook_dispatcher.call_hooks(self._transfer_hook_dispatcher.TRANSFER_DIRECTION_OUTGOING, transfer) for frame in transfer.to_frames(): self._can_driver.send(frame.message_id, frame.bytes, extended=True) logger.debug("Node.respond(dest_node_id={0:d}, transfer_id={0:d}, priority={0:d}): sent {1!r}" .format(dest_node_id, transfer_id, priority, payload))
def send_request(self, payload, dest_node_id=None, callback=None): transfer_id = self._next_transfer_id((payload.type.default_dtid, dest_node_id)) transfer = transport.Transfer( payload=payload, source_node_id=self.node_id, dest_node_id=dest_node_id, transfer_id=transfer_id, service_not_message=True, request_not_response=True) for frame in transfer.to_frames(datatype_crc=payload.type.base_crc): self.can.send(frame.message_id, frame.to_bytes(), extended=True) self.outstanding_requests[transfer.key] = transfer self.outstanding_request_callbacks[transfer.key] = callback self.outstanding_request_timestamps[transfer.key] = time.time() logging.info( "Node.send_request(dest_node_id={0:d}): sent {1!r}".format( dest_node_id, payload))
def _recv_frame(self, dev, message): frame_id, frame_data, ext_id = message if not ext_id: return frame = transport.Frame(frame_id, frame_data) # logging.debug("Node._recv_frame(): got {0!s}".format(frame)) transfer_frames = self.transfer_manager.receive_frame(frame) if not transfer_frames: return dtid = transfer_frames[0].data_type_id if transfer_frames[0].transfer_priority == \ transport.TransferPriority.SERVICE: kind = dsdl.parser.CompoundType.KIND_SERVICE else: kind = dsdl.parser.CompoundType.KIND_MESSAGE datatype = uavcan.DATATYPES.get((dtid, kind)) if not datatype: logging.debug(("Node._recv_frame(): unrecognised data type " + "ID {0:d} for kind {1:d}").format(dtid, kind)) return transfer = transport.Transfer() transfer.from_frames(transfer_frames, datatype_crc=datatype.base_crc) if transfer.is_message(): payload = datatype() # Broadcast or unicast elif transfer.is_request(): payload = datatype(mode="request") else: # transfer.is_response() payload = datatype(mode="response") payload.unpack(transport.bits_from_bytes(transfer.payload)) logging.info("Node._recv_frame(): received {0!r}".format(payload)) # If it's a node info request, keep track of the status of each node if payload.type == uavcan.protocol.NodeStatus: self.node_info[transfer.source_node_id] = { "uptime": payload.uptime_sec, "status": payload.status_code, "timestamp": time.time() } if transfer.is_response() and transfer.dest_node_id == self.node_id: # This is a reply to a request we sent. Look up the original # request and call the appropriate callback requests = self.outstanding_requests.keys() for key in requests: if transfer.is_response_to(self.outstanding_requests[key]): # Call the request's callback and remove it from the # active list if key in self.outstanding_request_callbacks: self.outstanding_request_callbacks[key]((payload, transfer)) del self.outstanding_request_callbacks[key] del self.outstanding_requests[key] del self.outstanding_request_timestamps[key] break elif transfer.is_broadcast() or transfer.dest_node_id == self.node_id: # This is a request, a unicast or a broadcast; look up the # appropriate handler by data type ID for handler in self.handlers: if handler[0] == datatype: kwargs = handler[2] if len(handler) == 3 else {} h = handler[1](payload, transfer, self, **kwargs) h._execute()