Exemplo n.º 1
0
    def __init__(self, emulator, model):
        super(SensorLogSubsystem, self).__init__(emulator)

        self.engine = InMemoryStorageEngine(model=model)
        self.storage = SensorLog(self.engine, model=model, id_assigner=lambda x, y: self.allocate_id())
        self.dump_walker = None
        self.next_id = 1
        self._logger = logging.getLogger(__name__)
Exemplo n.º 2
0
def callrpc_sg():
    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    sg.add_node(
        '(system input 2 always && constant 1 always) => unbuffered 2 using call_rpc'
    )
    log.push(DataStream.FromString('constant 1'),
             IOTileReading(0, 0, 0x000a8000))

    return sg
Exemplo n.º 3
0
def test_stream_allocation():
    """Make sure we can allocate DataStreams."""

    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    # TODO Finish this function
    alloc = StreamAllocator(sg, model=model)

    stream1 = alloc.allocate_stream(DataStream.ConstantType)
    assert len(sg.nodes) == 0

    stream2 = alloc.attach_stream(stream1)
    assert len(sg.nodes) == 0

    stream3 = alloc.attach_stream(stream1)
    assert len(sg.nodes) == 0

    stream4 = alloc.attach_stream(stream1)
    assert len(sg.nodes) == 0

    stream5 = alloc.attach_stream(stream1)
    assert len(sg.nodes) == 1

    assert stream1 == stream2
    assert stream2 == stream3
    assert stream4 == stream1
    assert stream5 != stream1
Exemplo n.º 4
0
    def compile(self, model):
        """Compile this file into a SensorGraph.

        You must have preivously called parse_file to parse a
        sensor graph file into statements that are then executed
        by this command to build a sensor graph.

        The results are stored in self.sensor_graph and can be
        inspected before running optimization passes.

        Args:
            model (DeviceModel): The device model that we should compile
                this sensor graph for.
        """

        log = SensorLog(InMemoryStorageEngine(model), model)
        self.sensor_graph = SensorGraph(log, model)

        allocator = StreamAllocator(self.sensor_graph, model)

        self._scope_stack = []

        # Create a root scope
        root = RootScope(self.sensor_graph, allocator)
        self._scope_stack.append(root)

        for statement in self.statements:
            statement.execute(self.sensor_graph, self._scope_stack)

        self.sensor_graph.initialize_remaining_constants()
        self.sensor_graph.sort_nodes()
Exemplo n.º 5
0
def basic_sg():
    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    sg.add_node('(system input 2 always) => unbuffered 1 using copy_all_a')

    return sg
Exemplo n.º 6
0
def usertick_sg():
    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    sg.add_node('(system input 3 always) => counter 1 using copy_latest_a')
    sg.add_config(SlotIdentifier.FromString('controller'),
                  config_fast_tick_secs, 'uint32_t', 2)

    return sg
Exemplo n.º 7
0
def test_string_generation():
    """Make sure we can print nodes."""

    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    sg.add_node(
        '(input 1 always && input 2 when count >= 1) => buffered node 1 using copy_all_a'
    )
    assert str(
        sg.nodes[-1]
    ) == u'(input 1 always && input 2 when count >= 1) => buffered 1 using copy_all_a'

    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)
    sg.add_node(
        '(input 1 when value < 0x10) => buffered node 1 using copy_all_a')
    assert str(sg.nodes[-1]
               ) == u'(input 1 when value < 16) => buffered 1 using copy_all_a'
Exemplo n.º 8
0
def test_usertick():
    """Make sure we properly can set the user tick input."""

    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    assert sg.get_tick('fast') == 0

    sg.add_config(SlotIdentifier.FromString('controller'), config_fast_tick_secs, 'uint32_t', 1)
    assert sg.get_tick('fast') == 1
Exemplo n.º 9
0
def tick2_sg():
    """A sensorgrah that listens to tick1."""

    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    sg.add_node('(system input 6 always) => counter 1 using copy_latest_a')
    sg.add_config(SlotIdentifier.FromString('controller'), config_tick2_secs,
                  'uint32_t', 2)

    return sg
Exemplo n.º 10
0
def test_basic_sensorgraph():
    """Make sure we can parse, load and run a basic sensor graph."""

    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    sg.add_node('(input 1 always && input 2 when count >= 1) => unbuffered 1 using copy_all_a')
    sg.process_input(DataStream.FromString('input 1'), IOTileReading(0, 1, 1), rpc_executor=None)
    sg.process_input(DataStream.FromString('input 2'), IOTileReading(0, 1, 1), rpc_executor=None)

    assert sg.sensor_log.inspect_last(DataStream.FromString('unbuffered 1')).value == 1
Exemplo n.º 11
0
def test_iteration():
    """Make sure we can iterate over the graph."""

    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    sg.add_node(
        '(input 1 always && input 2 when count >= 1) => unbuffered 1 using copy_all_a'
    )
    sg.add_node(
        '(input 1 always && input 3 when count >= 1) => unbuffered 2 using copy_all_a'
    )
    sg.add_node(
        '(unbuffered 2 always && unbuffered 1 always) => unbuffered 3 using copy_all_a'
    )
    sg.add_node('(unbuffered 1 always) => unbuffered 3 using copy_all_a')

    iterator = sg.iterate_bfs()

    node1, in1, out1 = next(iterator)
    assert str(node1.stream) == u'unbuffered 1'
    assert len(in1) == 0
    assert len(out1) == 2
    assert str(out1[0].stream) == u'unbuffered 3'
    assert str(out1[1].stream) == u'unbuffered 3'

    node1, in1, out1 = next(iterator)
    assert str(node1.stream) == u'unbuffered 2'
    assert len(in1) == 0
    assert len(out1) == 1
    assert str(out1[0].stream) == u'unbuffered 3'

    node1, in1, out1 = next(iterator)
    assert str(node1.stream) == u'unbuffered 3'
    assert len(in1) == 2
    assert len(out1) == 0
    assert str(in1[0].stream) == u'unbuffered 2'
    assert str(in1[1].stream) == u'unbuffered 1'

    node1, in1, out1 = next(iterator)
    assert str(node1.stream) == u'unbuffered 3'
    assert len(in1) == 1
    assert len(out1) == 0
    assert str(in1[0].stream) == u'unbuffered 1'
Exemplo n.º 12
0
def test_triggering_streamers():
    model = DeviceModel()
    log = SensorLog(model=model)
    sg = SensorGraph(log, model=model)

    sg.add_node('(input 1 always) => output 1 using copy_all_a')
    sg.add_node('(input 1 always) => output 2 using copy_all_a')

    sg.add_streamer(parse_string_descriptor('streamer on output 1'))
    sg.add_streamer(
        parse_string_descriptor('manual streamer on output 2 with streamer 0'))

    triggered = sg.check_streamers()
    assert len(triggered) == 0

    sg.process_input(DataStream.FromString('input 1'),
                     IOTileReading(0, 1, 1),
                     rpc_executor=None)
    triggered = sg.check_streamers()
    assert len(triggered) == 2
Exemplo n.º 13
0
class SensorLogSubsystem(ControllerSubsystemBase):
    """Container for raw sensor log state."""
    def __init__(self, emulator, model):
        super(SensorLogSubsystem, self).__init__(emulator)

        self.engine = InMemoryStorageEngine(model=model)
        self.storage = SensorLog(self.engine,
                                 model=model,
                                 id_assigner=lambda x, y: self.allocate_id())
        self.dump_walker = None
        self.next_id = 1
        self._logger = logging.getLogger(__name__)

    def dump(self):
        """Serialize the state of this subsystem into a dict.

        Returns:
            dict: The serialized state
        """

        walker = self.dump_walker
        if walker is not None:
            walker = walker.dump()

        state = {
            'storage': self.storage.dump(),
            'dump_walker': walker,
            'next_id': self.next_id
        }

        return state

    def prepare_for_restore(self):
        """Prepare the SensorLog subsystem for a restore.

        This must be called at the start of the restore to clear all of the
        stream walkers in the SensorLog storage engine, which are then added
        back by the SensorGraph and Streaming subsystems and then restored
        to their previous positions when restore() is called on this subsystem.
        """

        self.storage.destroy_all_walkers()

    def restore(self, state):
        """Restore the state of this subsystem from a prior call to dump().

        Calling restore must be properly sequenced with calls to other
        subsystems that include stream walkers so that their walkers are
        properly restored.

        Args:
            state (dict): The results of a prior call to dump().
        """

        self.storage.restore(state.get('storage'))

        dump_walker = state.get('dump_walker')
        if dump_walker is not None:
            dump_walker = self.storage.restore_walker(dump_walker)

        self.dump_walker = dump_walker
        self.next_id = state.get('next_id', 1)

    def clear(self, timestamp):
        """Clear all data from the RSL.

        This pushes a single reading once we clear everything so that
        we keep track of the highest ID that we have allocated to date.

        This needs the current timestamp to be able to properly timestamp
        the cleared storage reading that it pushes.

        Args:
            timestamp (int): The current timestamp to store with the
                reading.
        """

        self.storage.clear()

        self.push(streams.DATA_CLEARED, timestamp, 1)

    def clear_to_reset(self, config_vars):
        """Clear all volatile information across a reset."""

        self._logger.info("Config vars in sensor log reset: %s", config_vars)
        super(SensorLogSubsystem, self).clear_to_reset(config_vars)

        self.storage.destroy_all_walkers()
        self.dump_walker = None

        if config_vars.get('storage_fillstop', False):
            self._logger.debug("Marking storage log fill/stop")
            self.storage.set_rollover('storage', False)

        if config_vars.get('streaming_fillstop', False):
            self._logger.debug("Marking streaming log fill/stop")
            self.storage.set_rollover('streaming', False)

    def count(self):
        """Count many many readings are persistently stored.

        Returns:
            (int, int): The number of readings in storage and output areas.
        """

        return self.storage.count()

    def allocate_id(self):
        """Get the next unique ID.

        Returns:
            int: A unique reading ID.
        """

        next_id = self.next_id
        self.next_id += 1

        return next_id

    def push(self, stream_id, timestamp, value):
        """Push a value to a stream.

        Args:
            stream_id (int): The stream we want to push to.
            timestamp (int): The raw timestamp of the value we want to
                store.
            value (int): The 32-bit integer value we want to push.
        Returns:
            int: Packed 32-bit error code.
        """

        stream = DataStream.FromEncoded(stream_id)
        reading = IOTileReading(stream_id, timestamp, value)

        try:
            self.storage.push(stream, reading)

            return Error.NO_ERROR
        except StorageFullError:
            return pack_error(ControllerSubsystem.SENSOR_LOG,
                              SensorLogError.RING_BUFFER_FULL)

    def inspect_virtual(self, stream_id):
        """Inspect the last value written into a virtual stream.

        Args:
            stream_id (int): The virtual stream was want to inspect.

        Returns:
            (int, int): An error code and the stream value.
        """

        stream = DataStream.FromEncoded(stream_id)

        if stream.buffered:
            return [
                pack_error(ControllerSubsystem.SENSOR_LOG,
                           SensorLogError.VIRTUAL_STREAM_NOT_FOUND), 0
            ]

        try:
            reading = self.storage.inspect_last(stream, only_allocated=True)
            return [Error.NO_ERROR, reading.value]
        except StreamEmptyError:
            return [Error.NO_ERROR, 0]
        except UnresolvedIdentifierError:
            return [
                pack_error(ControllerSubsystem.SENSOR_LOG,
                           SensorLogError.VIRTUAL_STREAM_NOT_FOUND), 0
            ]

    def dump_begin(self, selector_id):
        """Start dumping a stream.

        Args:
            selector_id (int): The buffered stream we want to dump.

        Returns:
            (int, int, int): Error code, second error code, number of available readings
        """

        if self.dump_walker is not None:
            self.storage.destroy_walker(self.dump_walker)

        selector = DataStreamSelector.FromEncoded(selector_id)
        self.dump_walker = self.storage.create_walker(selector, skip_all=False)

        return Error.NO_ERROR, Error.NO_ERROR, self.dump_walker.count()

    def dump_seek(self, reading_id):
        """Seek the dump streamer to a given ID.

        Returns:
            (int, int, int): Two error codes and the count of remaining readings.

            The first error code covers the seeking process.
            The second error code covers the stream counting process (cannot fail)
            The third item in the tuple is the number of readings left in the stream.
        """

        if self.dump_walker is None:
            return (pack_error(ControllerSubsystem.SENSOR_LOG,
                               SensorLogError.STREAM_WALKER_NOT_INITIALIZED),
                    Error.NO_ERROR, 0)

        try:
            exact = self.dump_walker.seek(reading_id, target='id')
        except UnresolvedIdentifierError:
            return (pack_error(ControllerSubsystem.SENSOR_LOG,
                               SensorLogError.NO_MORE_READINGS),
                    Error.NO_ERROR, 0)

        error = Error.NO_ERROR
        if not exact:
            error = pack_error(ControllerSubsystem.SENSOR_LOG,
                               SensorLogError.ID_FOUND_FOR_ANOTHER_STREAM)

        return (error, error.NO_ERROR, self.dump_walker.count())

    def dump_next(self):
        """Dump the next reading from the stream.

        Returns:
            IOTileReading: The next reading or None if there isn't one
        """

        if self.dump_walker is None:
            return pack_error(ControllerSubsystem.SENSOR_LOG,
                              SensorLogError.STREAM_WALKER_NOT_INITIALIZED)

        try:
            return self.dump_walker.pop()
        except StreamEmptyError:
            return None

    def highest_stored_id(self):
        """Scan through the stored readings and report the highest stored id.

        Returns:
            int: The highest stored id.
        """

        shared = [0]

        def _keep_max(_i, reading):
            if reading.reading_id > shared[0]:
                shared[0] = reading.reading_id

        self.engine.scan_storage('storage', _keep_max)
        self.engine.scan_storage('streaming', _keep_max)

        return shared[0]
Exemplo n.º 14
0
 def __init__(self, model):
     self.engine = InMemoryStorageEngine(model=model)
     self.storage = SensorLog(self.engine, model=model, id_assigner=lambda x, y: self.allocate_id())
     self.dump_walker = None
     self.next_id = 1