Esempio n. 1
0
    def connect(self, client_id):
        """Connect to AWS IOT with the given client_id

        Args:
            client_id (string): The client ID passed to the MQTT message broker
        """

        if self.client is not None:
            raise InternalError("Connect called on an alreaded connected MQTT client")

        client = AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient(client_id, useWebsocket=self.websockets)

        if self.websockets:
            client.configureEndpoint(self.endpoint, 443)
            client.configureCredentials(self.root)

            if self.iam_session is None:
                client.configureIAMCredentials(self.iam_key, self.iam_secret)
            else:
                client.configureIAMCredentials(self.iam_key, self.iam_secret, self.iam_session)
        else:
            client.configureEndpoint(self.endpoint, 8883)
            client.configureCredentials(self.root, self.key, self.cert)

        client.configureOfflinePublishQueueing(0)

        try:
            client.connect()
            self.client = client
        except operationError as exc:
            raise InternalError("Could not connect to AWS IOT", message=exc.message)

        self.sequencer.reset()
Esempio n. 2
0
    def call_rpc(self, rpc_id, payload=bytes()):
        """Call an RPC by its ID.

        Args:
            rpc_id (int): The number of the RPC
            payload (bytes): A byte string of payload parameters up to 20 bytes

        Returns:
            str: The response payload from the RPC
        """

        # If we define the RPC locally, call that one.  We use this for reporting
        # our status
        if super(ServiceDelegateTile, self).has_rpc(rpc_id):
            return super(ServiceDelegateTile, self).call_rpc(rpc_id, payload)

        # FIXME: We set the timeout here to a very large number since we don't
        # know what an appropriate timeout is and don't want to restrict the
        # run time of RPCs that could be long running.  The caller of the RPC
        # through the tile will know what an appropriate timeout is for the
        # RPC that they are trying to call.
        resp = self._client.send_rpc(self._service,
                                     rpc_id,
                                     payload,
                                     timeout=120.0)
        result = resp['result']

        if result == 'success':
            return resp['response']
        elif result == 'service_not_found':
            raise TileNotFoundError("Could not find service by name",
                                    name=self._service)
        elif result == 'rpc_not_found':
            raise RPCNotFoundError("Could not find RPC on service",
                                   name=self._service,
                                   rpc_id=rpc_id)
        elif result == 'invalid_arguments':
            raise RPCInvalidArgumentsError("Invalid arguments to RPC",
                                           name=self._service,
                                           rpc_id=rpc_id)
        elif result == 'invalid_response':
            raise RPCInvalidReturnValueError("Invalid response from RPC",
                                             name=self._service,
                                             rpc_id=rpc_id)
        elif result == 'execution_exception':
            raise InternalError("Exception raised during processing RPC",
                                name=self._service,
                                rpc_id=rpc_id)
        else:
            raise InternalError("Unknown response received from delegated RPC",
                                name=self._service,
                                rpc_id=rpc_id,
                                result=result)
Esempio n. 3
0
    def _load_architectures(self, family):
        """
        Load in all of the architectural overlays for this family.  An architecture adds configuration
        information that is used to build a common set of source code for a particular hardware and sitation.
        They are stackable so that you can specify a chip and a configuration for that chip, for example.
        """

        if "architectures" not in family:
            raise InternalError("required architectures key not in build_settings.json for desired family")

        for key, val in viewitems(family['architectures']):
            if not isinstance(val, dict):
                raise InternalError("All entries under chip_settings must be dictionaries")

            self.archs[key] = deepcopy(val)
Esempio n. 4
0
    def stop(self):
        """Synchronously stop the background loop from outside.

        This method will block until the background loop is completely stopped
        so it cannot be called from inside the loop itself.

        This method is safe to call multiple times.  If the loop is not
        currently running it will return without doing anything.
        """

        if not self.loop:
            return

        if self.inside_loop():
            raise InternalError(
                "BackgroundEventLoop.stop() called from inside event loop; "
                "would have deadlocked.")

        try:
            self.run_coroutine(self._stop_internal())
            self.thread.join()

            if self._pool is not None:
                self._pool.shutdown(wait=True)
        except:
            self._logger.exception("Error stopping BackgroundEventLoop")
            raise
        finally:
            self.thread = None
            self.loop = None
            self._pool = None
            self.tasks = set()
Esempio n. 5
0
    def add_subtask(self, subtask):
        """Link a subtask to this parent task.

        This will cause stop() to block until the subtask has also
        finished.  Calling stop will not directly cancel the subtask.
        It is expected that your finalizer for this parent task will
        cancel or otherwise stop the subtask.

        Args:
            subtask (BackgroundTask): Another task that will be stopped
                when this task is stopped.
        """

        if self.stopped:
            raise InternalError(
                "Cannot add a subtask to a parent that is already stopped")

        if not isinstance(subtask, BackgroundTask):
            raise ArgumentError(
                "Subtasks must inherit from BackgroundTask, task={}".format(
                    subtask))

        # pylint:disable=protected-access;It is the same class as us so is equivalent to self access.
        if subtask._loop != self._loop:
            raise ArgumentError(
                "Subtasks must run in the same BackgroundEventLoop as their parent",
                subtask=subtask,
                parent=self)

        self.subtasks.append(subtask)
Esempio n. 6
0
    def create_subtask(self, cor, name=None, stop_timeout=1.0):
        """Create and add a subtask from a coroutine.

        This function will create a BackgroundTask and then
        call self.add_subtask() on it.

        Args:
            cor (coroutine): The coroutine that should be wrapped
                in a background task.
            name (str): An optional name for the task.
            stop_timeout (float): The maximum time to wait for this
                subtask to die after stopping it.

        Returns:
            Backgroundtask: The created subtask.
        """

        if self.stopped:
            raise InternalError(
                "Cannot add a subtask to a parent that is already stopped")

        subtask = BackgroundTask(cor,
                                 name,
                                 loop=self._loop,
                                 stop_timeout=stop_timeout)
        self.add_subtask(subtask)
        return subtask
Esempio n. 7
0
    def verify_calling_thread(self, should_be_emulation, message=None):
        """Verify if the calling thread is or is not the emulation thread.

        This method can be called to make sure that an action is being taken
        in the appropriate context such as not blocking the event loop thread
        or modifying an emulate state outside of the event loop thread.

        If the verification fails an InternalError exception is raised,
        allowing this method to be used to protect other methods from being
        called in a context that could deadlock or cause race conditions.

        Args:
            should_be_emulation (bool): True if this call should be taking place
                on the emulation, thread, False if it must not take place on
                the emulation thread.
            message (str): Optional message to include when raising the exception.
                Otherwise a generic message is used.

        Raises:
            InternalError: When called from the wrong thread.
        """

        if should_be_emulation == self.on_emulation_thread():
            return

        if message is None:
            message = "Operation performed on invalid thread"

        raise InternalError(message)
Esempio n. 8
0
    def associated_stream(self):
        """Return the corresponding output or storage stream for an important system input.

        Certain system inputs are designed as important and automatically
        copied to output streams without requiring any manual interaction.

        This method returns the corresponding stream for an important system
        input.  It will raise an InternalError unlesss the self.important
        property is True.

        Returns:
            DataStream: The corresponding output or storage stream.

        Raises:
            InternalError: If this stream is not marked as an important system input.
        """

        if not self.important:
            raise InternalError("You may only call autocopied_stream on when DataStream.important is True", stream=self)

        if self.stream_id >= DataStream.ImportantSystemStorageStart:
            stream_type = DataStream.BufferedType
        else:
            stream_type = DataStream.OutputType

        return DataStream(stream_type, self.stream_id, True)
Esempio n. 9
0
    def triggered(self, manual=False):
        """Check if this streamer should generate a report.

        Streamers can be triggered automatically whenever they have data
        or they can be triggered manually. This method returns True if the
        streamer is currented triggered.

        A streamer is triggered if it:
          - (has data AND is automatic) OR
          - (has data AND is manually triggered)

        Args:
            manual (bool): Indicate that the streamer has been manually triggered.

        Returns:
            bool: Whether the streamer can generate a report right now.
        """

        if self.walker is None:
            raise InternalError(
                "You can only check if a streamer is triggered if you create it with a SensorLog"
            )

        if not self.automatic and not manual:
            return False

        return self.has_data()
Esempio n. 10
0
    def subscribe(self, topic, callback, ordered=True):
        """Subscribe to future messages in the given topic

        The contents of topic should be in the format created by self.publish with a
        sequence number of message type encoded as a json string.

        Wildcard topics containing + and # are allowed and

        Args:
            topic (string): The MQTT topic to subscribe to
            callback (callable): The callback to call when a new mesage is received
                The signature of callback should be callback(sequence, topic, type, message)
            ordered (bool): Whether messages on this topic have a sequence number that must
                be checked and queued to ensure that packets are received in order
        """

        if '+' in topic or '#' in topic:
            regex = re.compile(topic.replace('+', '[^/]+').replace('#', '.*'))
            self.wildcard_queues.append((topic, regex, callback, ordered))
        else:
            self.queues[topic] = PacketQueue(0, callback, ordered)

        try:
            self.client.subscribe(topic, 1, self._on_receive)
        except operationError as exc:
            raise InternalError("Could not subscribe to topic", topic=topic, message=exc.message)
Esempio n. 11
0
    def run_coroutine(self, cor, *args, **kwargs):
        """Run a coroutine to completion and return its result.

        This method may only be called outside of the event loop.
        Attempting to call it from inside the event loop would deadlock
        and will raise InternalError instead.

        Args:
            cor (coroutine): The coroutine that we wish to run in the
                background and wait until it finishes.

        Returns:
            object: Whatever the coroutine cor returns.
        """

        if self.stopping:
            raise LoopStoppingError(
                "Could not launch coroutine because loop is shutting down: %s"
                % cor)

        self.start()

        cor = _instaniate_coroutine(cor, args, kwargs)

        if self.inside_loop():
            raise InternalError(
                "BackgroundEventLoop.run_coroutine called from inside event loop, "
                "would have deadlocked.")

        future = self.launch_coroutine(cor)
        return future.result()
Esempio n. 12
0
    async def connect(self):
        """Connect to this virtual device."""

        if self.connected:
            raise InternalError(
                "connect() was called but someone was already connected")

        await self.open_interface('connected')
Esempio n. 13
0
    def _load_module_targets(self, family):
        if "module_targets" in family:
            for mod, targets in viewitems(family['module_targets']):
                for target in targets:
                    if not self.validate_target(target):
                        raise InternalError("Module %s targets unknown architectures '%s'" % (mod, target))

                self.module_targets[mod] = targets
Esempio n. 14
0
    def __init__(self, emulator, basic=True):
        if not basic:
            raise InternalError(
                "Full stream manager support is not yet implemented")

        self.stream_manager = BasicStreamingSubsystem(
            emulator, self._device, self.sensor_log.allocate_id)
        self._post_config_subsystems.append(self.stream_manager)
Esempio n. 15
0
    def stop(self):
        """Stop running this virtual device."""

        if not self._started:
            raise InternalError(
                "Stop called without start() first being called")

        self._started = False
Esempio n. 16
0
    def start_workers(self):
        """Start running this virtual device including any necessary worker threads."""

        if self._started:
            raise InternalError("The method start() was called twice on a BaseRunnable object.")

        self._started = True

        for worker in self._workers:
            worker.start()
Esempio n. 17
0
    def disconnect(self):
        """Disconnect from AWS IOT message broker
        """

        if self.client is None:
            return

        try:
            self.client.disconnect()
        except operationError as exc:
            raise InternalError("Could not disconnect from AWS IOT", message=exc.message)
Esempio n. 18
0
    def set_result(self, result):
        """Finish this response and set the result."""

        if self.is_finished():
            raise InternalError(
                "set_result called on finished AsynchronousResponse",
                result=self._result,
                exception=self._exception)

        self._result = result
        self.finish()
Esempio n. 19
0
        async def _awaitable_wrapper():

            # FIXME: We set the timeout here to a very large number since we don't
            # know what an appropriate timeout is and don't want to restrict the
            # run time of RPCs that could be long running.  The caller of the RPC
            # through the tile will know what an appropriate timeout is for the
            # RPC that they are trying to call.
            resp = await self._client.send_rpc(self._service,
                                               rpc_id,
                                               payload,
                                               timeout=120.0)
            result = resp['result']

            if result == 'success':
                return resp['response']
            elif result == 'service_not_found':
                raise TileNotFoundError("Could not find service by name",
                                        name=self._service)
            elif result == 'rpc_not_found':
                raise RPCNotFoundError("Could not find RPC on service",
                                       name=self._service,
                                       rpc_id=rpc_id)
            elif result == 'invalid_arguments':
                raise RPCInvalidArgumentsError("Invalid arguments to RPC",
                                               name=self._service,
                                               rpc_id=rpc_id)
            elif result == 'invalid_response':
                raise RPCInvalidReturnValueError("Invalid response from RPC",
                                                 name=self._service,
                                                 rpc_id=rpc_id)
            elif result == 'execution_exception':
                raise InternalError("Exception raised during processing RPC",
                                    name=self._service,
                                    rpc_id=rpc_id)
            else:
                raise InternalError(
                    "Unknown response received from delegated RPC",
                    name=self._service,
                    rpc_id=rpc_id,
                    result=result)
Esempio n. 20
0
    def has_data(self):
        """Check whether there is any data in this streamer.

        Returns:
            bool: Whether there is any available data.
        """

        if self.walker is None:
            raise InternalError(
                "You can only check if a streamer is triggered if you create it with a SensorLog"
            )

        return self.walker.count() > 0
Esempio n. 21
0
    def unsubscribe(self, topic):
        """Unsubscribe from messages on a given topic

        Args:
            topic (string): The MQTT topic to unsubscribe from
        """

        del self.queues[topic]

        try:
            self.client.unsubscribe(topic)
        except operationError as exc:
            raise InternalError("Could not unsubscribe from topic", topic=topic, message=exc.message)
Esempio n. 22
0
    async def initialize(self, timeout=2.0):
        """Launch any background tasks associated with this subsystem.

        This method will synchronously await self.initialized() which makes
        sure that the background tasks start up correctly.
        """

        if self.initialized.is_set():
            raise InternalError("initialize called when already initialized")

        self._emulator.add_task(8, self._reset_vector())

        await asyncio.wait_for(self.initialized.wait(), timeout=timeout)
Esempio n. 23
0
    def set_exception(self, exc_class, exc_info, exc_stack):
        """Set an exception as the result of this operation.

        Args:
            exc_class (object): The exception type """

        if self.is_finished():
            raise InternalError(
                "set_exception called on finished AsynchronousResponse",
                result=self._result,
                exception=self._exception)

        self._exception = (exc_class, exc_info, exc_stack)
        self.finish()
Esempio n. 24
0
    def start(self, channel):
        """Start running this virtual device.

        Args:
            channel (AbstractAsyncDeviceChannel): A channel that can be used by the device
                to push events asynchronously to an attached client.
        """

        if self._started:
            raise InternalError(
                "The method start() was called twice on VirtualIOTileDevice.")

        self._push_channel = channel
        self._started = True
Esempio n. 25
0
    def __init__(self, code, subsystem=None, size="L"):
        super(RPCRuntimeError, self).__init__()

        if size not in ("L", "H"):
            raise InternalError(
                "Unknown size {} in RPCRuntimeError".format(size))

        if subsystem is not None and size == 'H':
            raise InternalError(
                "You cannot combine size=H with a subsystem, subsystem={}".
                format(subsystem))

        if subsystem is not None:
            error = pack_error(subsystem, code)
        else:
            error = code

        self.code = error
        self.subsystem = subsystem
        self.packed_error = error

        print("Packed error: %r" % self.packed_error)
        self.binary_error = struct.pack("<{}".format(size), self.packed_error)
Esempio n. 26
0
    def _load_modules(self, family):
        if "modules" not in family:
            raise InternalError("required modules key not in build_settings.json for desired family")

        for modname in family['modules']:
            overlays = {}
            rawmod = family['modules'][modname]

            if 'overlays' in rawmod:
                overlays = rawmod['overlays']
                del rawmod['overlays']

            mod = ModuleSettings(overlays, rawmod)
            self.modules[modname] = mod
Esempio n. 27
0
    def start(self, channel):
        """Start running this virtual device including any necessary worker threads.

        Args:
            channel (IOTilePushChannel): the channel with a stream and trace
                routine for streaming and tracing data through a VirtualInterface
        """

        if self._started:
            raise InternalError(
                "The method start() was called twice on VirtualIOTileDevice.")

        self._push_channel = channel
        self.start_workers()
Esempio n. 28
0
    def unpause(self):
        """Undo a previous call to pause().

        This method decreases the internal pause request counter.  When the counter
        reaches 0, message processing is allowed again.
        """

        if self._pause_count == 0:
            raise InternalError(
                "Mismatched usage of pause/unpause, unpause called when not paused"
            )

        self._pause_count -= 1
        if self._pause_count == 0 and len(self._messages) > 0:
            self._loop.launch_coroutine(self.process_all)
Esempio n. 29
0
    def _call_rpc(self, address, rpc_id, payload):
        """Call an RPC with the given information and return its response.

        Must raise a hardware error of the appropriate kind if the RPC
        can not be executed correctly.  Otherwise it should return the binary
        response payload received from the RPC.

        Args:
            address (int): The address of the tile we want to call the RPC
                on
            rpc_id (int): The id of the RPC that we want to call
            payload (bytes, bytearray): The data that we want to send as the payload
        """

        raise InternalError("RPCExecutor did not properly override _call_rpc")
Esempio n. 30
0
    def get_current_rpc(self):
        """Get the currently running RPC for asynchronous responses.

        Returns the address and rpc_id of the RPC that is currently being
        dispatched. This information can be saved and passed later to
        finish_async_rpc() to send a response to an asynchronous rpc.

        Returns:
            (address, rpc_id): A tuple with the currently running RPC.
        """

        if self._current_rpc is None:
            raise InternalError("There is no current RPC running")

        return self._current_rpc