示例#1
0
    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))
示例#2
0
    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)
示例#3
0
    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))
示例#4
0
    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()
示例#5
0
    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))
示例#6
0
    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)
示例#7
0
    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
示例#8
0
    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]
示例#9
0
    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))
示例#10
0
    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))
示例#11
0
    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))
示例#12
0
    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()