def test_every_block_compilation(parser): """Make sure we can compile a simple every block.""" parser.parse_file(get_path(u'basic_every_1min.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) assert len(sg.nodes) == 7 sg.load_constants() # Now make sure it produces the right output counter15 = log.create_walker(DataStreamSelector.FromString('counter 15')) counter16 = log.create_walker(DataStreamSelector.FromString('counter 16')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 120 seconds') sim.run() assert counter15.count() == 2 assert counter16.count() == 2
def test_on_block(parser): """Make sure on count(stream), on value(stream) and on stream work.""" parser.parse_file(get_path(u'basic_on.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() counter1 = log.create_walker(DataStreamSelector.FromString('counter 1')) counter2 = log.create_walker(DataStreamSelector.FromString('counter 2')) counter3 = log.create_walker(DataStreamSelector.FromString('counter 3')) sim = SensorGraphSimulator(sg) sim.step(DataStream.FromString('input 1'), 8) assert counter1.count() == 0 assert counter2.count() == 0 assert counter3.count() == 0 for i in range(0, 10): sim.step(DataStream.FromString('input 1'), 5) assert counter1.count() == 10 assert counter2.count() == 5 assert counter3.count() == 5
def test_seek_walker(): """Make sure we can seek a walker can count with an offset.""" model = DeviceModel() log = SensorLog(model=model) stream = DataStream.FromString('buffered 1') reading = IOTileReading(stream.encode(), 0, 1) log.push(stream, reading) log.push(stream, reading) log.push(DataStream.FromString('buffered 2'), reading) log.push(stream, reading) walk = log.create_walker(DataStreamSelector.FromString('buffered 1'), skip_all=False) assert walk.offset == 0 assert walk.count() == 3 walk.seek(1) assert walk.offset == 1 assert walk.count() == 2 # Make sure we can seek to a position corresponding to another stream walk.seek(2) assert walk.offset == 2 assert walk.count() == 1 # Make sure we can find a reading by reading ID walk = log.create_walker(DataStreamSelector.FromString('output 1'), skip_all=False) output1 = DataStream.FromString('output 1') output2 = DataStream.FromString('output 2') log.push(output1, IOTileReading(0, 0, 1, reading_id=1)) log.push(output1, IOTileReading(0, 0, 1, reading_id=2)) log.push(output2, IOTileReading(0, 0, 1, reading_id=3)) log.push(output1, IOTileReading(0, 0, 1, reading_id=4)) exact = walk.seek(2, target='id') assert exact is True assert walk.count() == 2 assert walk.offset == 1 exact = walk.seek(3, target='id') assert exact is False assert walk.count() == 1 assert walk.offset == 2 # Verify exceptions thrown by seek() with pytest.raises(UnresolvedIdentifierError): walk.seek(5, target='id') with pytest.raises(UnresolvedIdentifierError): walk.seek(5, target=u'id') with pytest.raises(UnresolvedIdentifierError): walk.seek(5, target='offset') with pytest.raises(ArgumentError): walk.seek(2, target="unsupported")
def test_selector_parsing(): """Make sure we can parse DataStreamSelector strings.""" # Make sure parsing stream type works stream = DataStreamSelector.FromString('buffered 1') assert stream.match_type == DataStream.BufferedType stream = DataStreamSelector.FromString(u'buffered 1') assert stream.match_type == DataStream.BufferedType stream = DataStreamSelector.FromString('unbuffered 1') assert stream.match_type == DataStream.UnbufferedType stream = DataStreamSelector.FromString(u'unbuffered 1') assert stream.match_type == DataStream.UnbufferedType stream = DataStreamSelector.FromString('counter 1') assert stream.match_type == DataStream.CounterType stream = DataStreamSelector.FromString(u'counter 1') assert stream.match_type == DataStream.CounterType stream = DataStreamSelector.FromString('constant 1') assert stream.match_type == DataStream.ConstantType stream = DataStreamSelector.FromString(u'constant 1') assert stream.match_type == DataStream.ConstantType stream = DataStreamSelector.FromString('output 1') assert stream.match_type == DataStream.OutputType stream = DataStreamSelector.FromString(u'output 1') assert stream.match_type == DataStream.OutputType
def test_copy_statement(parser): """Make sure we can copy data using copy.""" parser.parse_file(get_path(u'basic_copy.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() output1 = log.create_walker(DataStreamSelector.FromString('output 1')) output2 = log.create_walker(DataStreamSelector.FromString('output 2')) output3 = log.create_walker(DataStreamSelector.FromString('output 3')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 60 seconds') sim.run() assert output1.count() == 1 assert output2.count() == 1 assert output3.count() == 1 val1 = output1.pop() val2 = output2.pop() val3 = output3.pop() assert val1.value == 0 assert val2.value == 60 assert val3.value == 1
def test_every_block_with_buffering(parser): """Make sure we can compile and simulate an every block with buffered data.""" parser.parse_file(get_path(u'basic_output.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) assert len(sg.nodes) == 7 sg.load_constants() # Now make sure it produces the right output output1 = log.create_walker(DataStreamSelector.FromString('output 1')) buffered1 = log.create_walker(DataStreamSelector.FromString('buffered 1')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 120 seconds') sim.run() assert output1.count() == 12 assert buffered1.count() == 12
def test_every_block_splitting(parser): """Make sure we can split nodes in an every block.""" parser.parse_file(get_path(u'basic_every_split.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) assert len(sg.nodes) == 10 # Now make sure it produces the right output counter15 = log.create_walker(DataStreamSelector.FromString('counter 15')) counter16 = log.create_walker(DataStreamSelector.FromString('counter 16')) counter17 = log.create_walker(DataStreamSelector.FromString('counter 16')) counter18 = log.create_walker(DataStreamSelector.FromString('counter 16')) sg.load_constants() sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 120 seconds') sim.run() sg.load_constants() print([str(x) for x in log._last_values.keys()]) assert counter15.count() == 2 assert counter16.count() == 2 assert counter17.count() == 2 assert counter18.count() == 2
def test_root_buffering(parser): """Make sure that nodes with two inputs where only one of the inputs is a root node gets an unbuffered node in between. Furthermore, check that after topographic sorting, the root nodes are all at the top.""" parser.parse_file(get_path(u'basic_root_buffering.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) assert len(sg.nodes) == 21 #This check is to ensure that all root (input) nodes at the beginning after sorting. root_node_section_passed = False for node in sg.nodes: if not root_node_section_passed: if 'input' not in str(node): root_node_section_passed = True else: assert 'input' not in str(node) # Now make sure it produces the right output output11 = log.create_walker(DataStreamSelector.FromString('output 11')) output12 = log.create_walker(DataStreamSelector.FromString('output 12')) output13 = log.create_walker(DataStreamSelector.FromString('output 13')) output14 = log.create_walker(DataStreamSelector.FromString('output 14')) output15 = log.create_walker(DataStreamSelector.FromString('output 15')) sg.load_constants() sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 20 minutes') sim.stimulus("1 minute: input 1 = 1") sim.stimulus("1 minute: input 2 = 1") sim.stimulus("11 minute: input 1 = 2") sim.run() sg.load_constants() print([str(x) for x in log._last_values.keys()]) assert output11.count() == 2 assert output12.count() == 2 assert output13.count() == 2 assert output14.count() == 2 assert output15.count() == 1
def test_copy_count_statement(parser): """Make sure we can copy data count using copy count.""" parser.parse_file(get_path(u'count.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() output = log.create_walker(DataStreamSelector.FromString('output 1')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 3 seconds') sim.step(user_connected, 8) # Simulates a connected user sim.run() print(output) assert output.count() == 1 print(output)
def test_copy_constant_statement(parser): """Make sure we can copy constant values.""" parser.parse_file(get_path(u'basic_copy_constant.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() output1 = log.create_walker(DataStreamSelector.FromString('output 1')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 10 seconds') sim.run() assert output1.count() == 1 assert output1.pop().value == 15 sim.step(DataStream.FromString('input 1'), 10) assert output1.count() == 1 assert output1.pop().value == 0x10
def test_on_block_dual(parser): """Make sure on with two conditions works.""" parser.parse_file(get_path(u'basic_on_dual.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() counter1 = log.create_walker(DataStreamSelector.FromString('counter 1')) sim = SensorGraphSimulator(sg) sim.step(DataStream.FromString('input 1'), 5) assert counter1.count() == 0 sim.step(DataStream.FromString('input 2'), 1) for _i in range(0, 10): sim.step(DataStream.FromString('input 1'), 5) assert counter1.count() == 11 sim.step(DataStream.FromString('input 2'), 0) for _i in range(0, 10): sim.step(DataStream.FromString('input 1'), 5) assert counter1.count() == 11
def test_when_block_clock(parser): """Make sure we can compile when blocks (without identifiers).""" parser.parse_file(get_path(u'basic_when.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() assert sg.get_tick('fast') == 1 # Now make sure it produces the right output counter15 = log.create_walker(DataStreamSelector.FromString('counter 15')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 60 seconds') sim.run() assert counter15.count() == 0 sim.step(DataStream.FromString('system input 1025'), 8) assert counter15.count() == 1 counter15.skip_all() sim.run() assert counter15.count() == 60 counter15.skip_all() sim.step(DataStream.FromString('system input 1026'), 8) sim.run() assert counter15.count() == 0
def test_counter_walker(): """Make sure counter walkers work correctly.""" model = DeviceModel() log = SensorLog(model=model) walk = log.create_walker(DataStreamSelector.FromString('counter 1')) stream = DataStream.FromString('counter 1') reading = IOTileReading(0, 1, 1) assert walk.count() == 0 log.push(stream, IOTileReading(0, 1, 1)) assert walk.count() == 1 assert walk.peek().value == 1 log.push(stream, IOTileReading(0, 1, 3)) assert walk.count() == 2 assert walk.peek().value == 3 val = walk.pop() assert walk.count() == 1 assert val.value == 3 val = walk.pop() assert walk.count() == 0 assert val.value == 3 with pytest.raises(StreamEmptyError): walk.pop()
def test_storage_streaming_walkers(): """Make sure the storage and streaming walkers work simultaneously.""" model = DeviceModel() log = SensorLog(model=model) storage_walk = log.create_walker(DataStreamSelector.FromString('buffered 1')) output_walk = log.create_walker(DataStreamSelector.FromString('output 1')) storage1 = DataStream.FromString('buffered 1') storage2 = DataStream.FromString('buffered 2') output1 = DataStream.FromString('output 1') output2 = DataStream.FromString('output 2') assert storage_walk.offset == 0 assert output_walk.offset == 0 for i in range(0, 5000): reading = IOTileReading(0, 0, i) log.push(storage1, reading) log.push(storage2, reading) log.push(output1, reading) log.push(output2, reading) assert storage_walk.count() == (i + 1) assert output_walk.count() == (i + 1) assert storage_walk.offset == 0 assert output_walk.offset == 0 for i in range(0, 5000): reading1 = storage_walk.pop() reading2 = output_walk.pop() assert reading1.value == i assert reading1.stream == storage1.encode() assert reading2.value == i assert reading2.stream == output1.encode() assert storage_walk.offset == (2 * i) + 1 assert output_walk.offset == (2* i) + 1 log.clear() assert storage_walk.count() == 0 assert storage_walk.offset == 0 assert output_walk.count() == 0 assert output_walk.offset == 0
def test_encoding(): """Test data stream and selector encoding.""" sel = DataStreamSelector.FromString(u'all system output') assert sel.encode() == 0x5FFF sel = DataStreamSelector.FromString(u'all user output') assert sel.encode() == 0x57FF sel = DataStreamSelector.FromString(u'all output') assert sel.encode() == 0xD7FF sel = DataStreamSelector.FromString(u'all combined output') assert sel.encode() == 0xDFFF stream = DataStream.FromString('output 1') assert stream.encode() == 0x5001 stream = DataStream.FromString('unbuffered 10') assert stream.encode() == 0x100a
def test_matching(): """Test selector stream matching.""" sel = DataStreamSelector.FromString(u'all system buffered') assert sel.matches(DataStream.FromString('system buffered 1')) assert not sel.matches(DataStream.FromString('buffered 1')) assert not sel.matches(DataStream.FromString('counter 1')) sel = DataStreamSelector.FromString(u'all user outputs') assert sel.matches(DataStream.FromString('output 1')) assert not sel.matches(DataStream.FromString('system output 1')) assert not sel.matches(DataStream.FromString('counter 1')) sel = DataStreamSelector.FromString(u'all combined outputs') assert sel.matches(DataStream.FromString('output 1')) assert sel.matches(DataStream.FromString('system output 1')) assert not sel.matches(DataStream.FromString('counter 1')) sel = DataStreamSelector.FromString(u'all outputs') assert sel.matches(DataStream.FromString('output 1')) assert sel.matches(DataStream.FromString('system output 1024')) assert not sel.matches(DataStream.FromString('system output 1')) assert not sel.matches(DataStream.FromString('counter 1'))
def test_subtract_statement(parser): """Make sure we can copy data using subtract.""" parser.parse_file(get_path(u'basic_subtract.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() output1 = log.create_walker(DataStreamSelector.FromString('unbuffered 1')) output2 = log.create_walker(DataStreamSelector.FromString('unbuffered 2')) output3 = log.create_walker(DataStreamSelector.FromString('unbuffered 3')) sg.process_input(DataStream.FromString('input 1'), IOTileReading(0, 0, 15), None) sg.process_input(DataStream.FromString('input 2'), IOTileReading(0, 0, 20), None) sg.process_input(DataStream.FromString('input 3'), IOTileReading(0, 0, 25), None) assert output1.count() == 1 assert output2.count() == 1 assert output3.count() == 1 val1 = output1.pop() val2 = output2.pop() val3 = output3.pop() assert val1.value == 5 assert val2.value == 10 assert val3.value == 25
def test_selector_from_encoded(): """Make sure we can create a selector from an encoded value.""" sel = DataStreamSelector.FromEncoded(0x5FFF) assert str(sel) == 'all system outputs' sel = DataStreamSelector.FromEncoded(0xD7FF) assert str(sel) == 'all outputs' sel = DataStreamSelector.FromEncoded(0x100a) assert str(sel) == 'unbuffered 10' assert str( DataStreamSelector.FromEncoded( DataStreamSelector.FromString( 'all combined output').encode())) == 'all combined outputs'
def test_walker_at_beginning(): """Make sure we can start a walker at the beginning of a stream.""" model = DeviceModel() log = SensorLog(model=model) stream = DataStream.FromString('buffered 1') reading = IOTileReading(stream.encode(), 0, 1) log.push(stream, reading) log.push(stream, reading) log.push(DataStream.FromString('buffered 2'), reading) walk = log.create_walker(DataStreamSelector.FromString('buffered 1'), skip_all=False) assert walk.offset == 0 assert walk.count() == 2
def test_stream_selector_id_parsing(): """Make sure we can parse stream ids.""" stream = DataStreamSelector.FromString('buffered 1') assert stream.match_id == 1 assert stream.match_spec == DataStreamSelector.MatchUserOnly stream = DataStreamSelector.FromString('buffered 0x100') assert stream.match_id == 0x100 assert stream.match_spec == DataStreamSelector.MatchUserOnly stream = DataStreamSelector.FromString(u'buffered 1') assert stream.match_id == 1 assert stream.match_spec == DataStreamSelector.MatchUserOnly stream = DataStreamSelector.FromString(u'buffered 0x100') assert stream.match_id == 0x100 assert stream.match_spec == DataStreamSelector.MatchUserOnly stream = DataStreamSelector.FromString(u'system buffered 0x100') assert stream.match_id == 0x100 assert stream.match_spec == DataStreamSelector.MatchSystemOnly stream = DataStreamSelector.FromString(u'all buffered') assert stream.match_id is None assert stream.match_spec == DataStreamSelector.MatchUserAndBreaks stream = DataStreamSelector.FromString(u'all user buffered') assert stream.match_id is None assert stream.match_spec == DataStreamSelector.MatchUserOnly stream = DataStreamSelector.FromString(u'all combined buffered') assert stream.match_id is None assert stream.match_spec == DataStreamSelector.MatchCombined stream = DataStreamSelector.FromString(u'all system buffered') assert stream.match_id is None assert stream.match_spec == DataStreamSelector.MatchSystemOnly
def test_constant_walker(): """Make sure constant walkers can be read any number of times.""" model = DeviceModel() log = SensorLog(model=model) walk = log.create_walker(DataStreamSelector.FromString('constant 1')) stream = DataStream.FromString('constant 1') reading = IOTileReading(0, 1, 1) log.push(stream, reading) assert walk.count() == 0xFFFFFFFF log.push(stream, reading) assert walk.count() == 0xFFFFFFFF val = walk.pop() assert walk.count() == 0xFFFFFFFF val = walk.pop() assert walk.count() == 0xFFFFFFFF
def test_storage_walker(): """Make sure the storage walker works.""" model = DeviceModel() log = SensorLog(model=model) walk = log.create_walker(DataStreamSelector.FromString('buffered 1')) stream = DataStream.FromString('buffered 1') storage_size = model.get('max_storage_buffer') erase_size = model.get('buffer_erase_size') for i in range(0, storage_size): reading = IOTileReading(0, stream.encode(), i) log.push(stream, reading) assert walk.count() == (i + 1) # Make sure the overwrite happens correctly old_count = walk.count() reading = IOTileReading(0, stream.encode(), storage_size) log.push(stream, reading) assert walk.count() == (old_count - erase_size + 1)
def test_latch_block(parser): """Make sure that we can compile and run latch blocks.""" parser.parse_file(get_path(u'basic_latch.sgf')) model = DeviceModel() parser.compile(model=model) sg = parser.sensor_graph log = sg.sensor_log for x in sg.dump_nodes(): print(x) sg.load_constants() assert sg.get_tick('fast') == 1 # Now make sure it produces the right output counter15 = log.create_walker(DataStreamSelector.FromString('counter 15')) sim = SensorGraphSimulator(sg) sim.stop_condition('run_time 60 seconds') sim.run() assert counter15.count() == 0 sim.step(DataStream.FromString('input 10'), 1) assert log.inspect_last(DataStream.FromString('constant 1')).value == 1 assert log.inspect_last(DataStream.FromString('constant 1024')).value == 1 counter15.skip_all() sim.run() assert counter15.count() == 60 counter15.skip_all() sim.step(DataStream.FromString('input 10'), 0) sim.run() assert counter15.count() == 0
def test_unbuffered_walker(): """Make sure unbuffered walkers hold only 1 reading.""" model = DeviceModel() log = SensorLog(model=model) walk = log.create_walker(DataStreamSelector.FromString('unbuffered 1')) stream = DataStream.FromString('unbuffered 1') assert walk.count() == 0 log.push(stream, IOTileReading(0, 1, 1)) assert walk.count() == 1 assert walk.peek().value == 1 log.push(stream, IOTileReading(0, 1, 3)) assert walk.count() == 1 assert walk.peek().value == 3 val = walk.pop() assert walk.count() == 0 assert val.value == 3 with pytest.raises(StreamEmptyError): walk.pop()
def test_buffered_pluralization(): """Make sure we don't incorrectly pluralize buffered streams.""" sel = DataStreamSelector.FromString('all buffered') assert str(sel) == 'all buffered'
def main(argv=None): """Main entry point for iotile sensorgraph simulator. This is the iotile-sgrun command line program. It takes an optional set of command line parameters to allow for testing. Args: argv (list of str): An optional set of command line parameters. If not passed, these are taken from sys.argv. """ if argv is None: argv = sys.argv[1:] try: executor = None parser = build_args() args = parser.parse_args(args=argv) model = DeviceModel() parser = SensorGraphFileParser() parser.parse_file(args.sensor_graph) parser.compile(model) if not args.disable_optimizer: opt = SensorGraphOptimizer() opt.optimize(parser.sensor_graph, model=model) graph = parser.sensor_graph sim = SensorGraphSimulator(graph) for stop in args.stop: sim.stop_condition(stop) for watch in args.watch: watch_sel = DataStreamSelector.FromString(watch) graph.sensor_log.watch(watch_sel, watch_printer) # If we are semihosting, create the appropriate executor connected to the device if args.semihost_device is not None: executor = SemihostedRPCExecutor(args.port, args.semihost_device) sim.rpc_executor = executor for mock in args.mock_rpc: slot, rpc_id, value = process_mock_rpc(mock) sim.rpc_executor.mock(slot, rpc_id, value) for stim in args.stimulus: sim.stimulus(stim) graph.load_constants() if args.trace is not None: sim.record_trace() try: if args.connected: sim.step(user_connected, 8) sim.run(accelerated=not args.realtime) except KeyboardInterrupt: pass if args.trace is not None: sim.trace.save(args.trace) finally: if executor is not None: executor.hw.close() return 0
def run(self, sensor_graph, model): """Run this optimization pass on the sensor graph If necessary, information on the device model being targeted can be found in the associated model argument. Args: sensor_graph (SensorGraph): The sensor graph to optimize model (DeviceModel): The device model we're using """ # Try to remove a node whose operation is copy_latest_a # It inherently does nothing, so it can be removed if: # 1. There is only one input triggering it # 2. The input is from another node (i.e. not a global sg input) # 3. The type of the input is the same as the type of the output # 4. There are enough output links in the input node to # handle all of the downstream connections. Note that we will # reclaim one free output when we do the replacement. # If there are multiple nodes that write to this input, all # must have an available output. # 5. The stream is not a sensor graph output # 6. The trigger conditions for both inputs and outputs are either # count based or always or value based with the same value. # # For each node, check if 1-6 are valid so we can remove it found_node = None found_inputs = None found_outputs = None for node, inputs, outputs in sensor_graph.iterate_bfs(): if node.func_name != u'copy_latest_a': continue # Check 1 if node.num_inputs != 1: continue # Check 2 if len(inputs) == 0: continue can_combine = True for curr_input in inputs: # Check 3 if curr_input.stream.stream_type != node.stream.stream_type: can_combine = False break # Check 4 (keep in mind we free up one output when we do the swap) if (curr_input.free_outputs + 1) < len(outputs): can_combine = False break if not can_combine: continue # Check 5 if sensor_graph.is_output(node.stream): continue # Check 6 for out in outputs: i = out.find_input(node.stream) _, trigger = out.inputs[i] # We can't merge things that could result in producing # multiple readings at a time since then combining the # trigger might change what number of outputs are # produced since: # trigger every 600 copy_latest then trigger every 1 copy_all # would produce one reading every 600 ticks. # # but: # trigger every 1 copy_latest then trigger every 600 copy_all # would produce 600 readings one every 600 ticks. if out.func_name == u'copy_all_a': can_combine = False break if not self._can_combine(node.inputs[0][1], trigger): can_combine = False break if not can_combine: continue found_node = node found_inputs = inputs found_outputs = outputs break if found_node is None: return False sensor_graph.nodes.remove(found_node) for input_node in found_inputs: input_node.outputs.remove(found_node) for output in found_outputs: i = output.find_input(found_node.stream) old_walker, old_trigger = output.inputs[i] new_trigger = self._try_combine(found_node.inputs[0][1], old_trigger) new_walker = sensor_graph.sensor_log.create_walker( DataStreamSelector.FromString( str(found_node.inputs[0][0].selector))) sensor_graph.sensor_log.destroy_walker(old_walker) output.inputs[i] = (new_walker, new_trigger) for input_node in found_inputs: input_node.connect_output(output) if found_node in sensor_graph.roots: sensor_graph.roots.remove(found_node) sensor_graph.sensor_log.destroy_walker(found_node.inputs[0][0]) return True
def test_language_constructs(): """Make sure the basic sensor graph language constructs work.""" # Create the parser language.get_language() # Test time interval parsing parsed = language.time_interval.parseString('1 day') assert parsed.asList()[0] == 60*60*24 # Test block id parsing parsed = language.block_id.parseString('every 1 day') assert parsed.asList()[0][1][0] == 60*60*24 # Test block parsing parsed = language.block_bnf.parseString('every 1 day {}') assert parsed.asList()[0][0][1][0] == 60*60*24 # Test stream parsing parsed = language.stream.parseString('output 1') assert isinstance(parsed.asList()[0], DataStream) # Test call_rpc statement parsed = language.callrpc_stmt.parseString(u'call 0x4001 on slot 1 => output 1;') assert parsed.asList()[0][0] == 0x4001 # Test block with statement parsing parsed = language.block_bnf.parseString(u'every 1 day { call 0x5001 on slot 2 => output 1; }') assert parsed.asList()[0][0][1][0] == 60*60*24 # Test parsing stream_trigger parsed = language.stream_trigger.parseString(u'value(input 2) == 10') assert parsed[0].getName() == u'stream_trigger' parsed = language.stream_trigger.parseString(u'count(output 1) <= 10') assert parsed[0].getName() == u'stream_trigger' # Test parsing on block with identifier parsed = language.block_bnf.parseString(u'on test_identifier {}') print(parsed) assert parsed[0][0][1][0][0].getName() == u'identifier' assert parsed[0][0][1][0][0][0] == u'test_identifier' parsed = language.block_bnf.parseString(u'on value(input 2) >= 5 {}') assert parsed[0][0][1][0][0].getName() == u'stream_trigger' assert parsed[0][0][1][0][0][0] == u'value' assert parsed[0][0][1][0][0][1] == DataStream.FromString('input 2') assert parsed[0][0][1][0][0][2] == u'>=' assert parsed[0][0][1][0][0][3] == 5 # Test parsing on block with 2 conditions parsed = language.block_bnf.parseString(u'on test_identifier and hello_id {}') assert parsed[0][0][1][0][0].getName() == u'identifier' assert parsed[0][0][1][0][0][0] == u'test_identifier' assert parsed[0][0][1][2][0].getName() == u'identifier' assert parsed[0][0][1][2][0][0] == u'hello_id' assert parsed[0][0][1][1] == u'and' parsed = language.block_bnf.parseString(u'on test_identifier or value(constant 1) == 2 {}') assert parsed[0][0][1][0][0].getName() == u'identifier' assert parsed[0][0][1][0][0][0] == u'test_identifier' assert parsed[0][0][1][1] == u'or' # Test parsing subtract statements parsed = language.subtract_stmt.parseString(u"subtract constant 1 => unbuffered 2, default 10;") assert parsed[0].getName() == 'subtract_statement' assert parsed[0][0] == DataStream.FromString('constant 1') assert parsed[0][1] == DataStream.FromString('unbuffered 2') assert parsed[0]['default'] == 10 parsed = language.subtract_stmt.parseString(u"subtract constant 1 => unbuffered 2;") assert parsed[0].getName() == 'subtract_statement' assert parsed[0][0] == DataStream.FromString('constant 1') assert parsed[0][1] == DataStream.FromString('unbuffered 2') # Test parser streamer statements parsed = language.streamer_stmt.parseString(u'manual streamer on output 1;') assert parsed[0]['selector'] == DataStreamSelector.FromString('output 1') parsed = language.streamer_stmt.parseString(u'manual streamer on all system outputs;') assert parsed[0]['selector'] == DataStreamSelector.FromString('all system outputs') parsed = language.streamer_stmt.parseString(u'manual signed streamer on output 1 to slot 1;') assert parsed[0]['selector'] == DataStreamSelector.FromString('output 1') assert parsed[0]['explicit_tile'] == SlotIdentifier.FromString('slot 1') assert parsed[0]['security'] == u'signed' parsed = language.streamer_stmt.parseString(u'manual broadcast streamer on output 1 to slot 1;') assert parsed[0]['selector'] == DataStreamSelector.FromString('output 1') assert parsed[0]['explicit_tile'] == SlotIdentifier.FromString('slot 1') assert parsed[0]['broadcast'] == u'broadcast' # Test parsing copy statements parsed = language.simple_statement.parseString(u'copy unbuffered 1 => unbuffered 2;') assert parsed[0]['explicit_input'][0] == DataStream.FromString('unbuffered 1') parsed = language.simple_statement.parseString(u'copy 15 => unbuffered 2;') assert parsed[0]['constant_input'] == 15 parsed = language.simple_statement.parseString(u'copy 0x20 => unbuffered 2;') assert parsed[0]['constant_input'] == 0x20
def test_dump_restore(): """Make sure we can properly dump and restore a SensorLog.""" model = DeviceModel() log = SensorLog(model=model) storage = DataStream.FromString('buffered 1') output = DataStream.FromString('output 1') reading = IOTileReading(0, 0, 1) for _i in range(0, 25): log.push(storage, reading) for _i in range(0, 20): log.push(output, reading) out1 = log.create_walker(DataStreamSelector.FromString('output 1'), skip_all=False) store1 = log.create_walker(DataStreamSelector.FromString('buffered 1'), skip_all=False) count1 = log.create_walker(DataStreamSelector.FromString('counter 1')) const1 = log.create_walker(DataStreamSelector.FromString('constant 1')) unbuf1 = log.create_walker(DataStreamSelector.FromString('unbuffered 1')) log.push(DataStream.FromString('counter 1'), reading) log.push(DataStream.FromString('counter 1'), reading) log.push(DataStream.FromString('constant 1'), reading) log.push(DataStream.FromString('unbuffered 1'), reading) state = log.dump() log.clear() log.destroy_all_walkers() out1 = log.create_walker(DataStreamSelector.FromString('output 1'), skip_all=False) store1 = log.create_walker(DataStreamSelector.FromString('buffered 1'), skip_all=False) count1 = log.create_walker(DataStreamSelector.FromString('counter 1')) const1 = log.create_walker(DataStreamSelector.FromString('constant 1')) unbuf1 = log.create_walker(DataStreamSelector.FromString('unbuffered 1')) log.restore(state) assert store1.count() == 25 assert out1.count() == 20 assert count1.count() == 2 assert const1.count() == 0xFFFFFFFF assert unbuf1.count() == 1 # Test permissive and non-permissive restores _unbuf2 = log.create_walker(DataStreamSelector.FromString('unbuffered 2')) with pytest.raises(ArgumentError): log.restore(state) log.clear() log.restore(state, permissive=True) assert store1.count() == 25 assert out1.count() == 20 assert count1.count() == 2 assert const1.count() == 0xFFFFFFFF assert unbuf1.count() == 1 # Test restoring a stream walker log.clear() log.destroy_all_walkers() walk = log.create_walker(DataStreamSelector.FromString(str(storage))) for _i in range(0, 25): log.push(storage, reading) assert walk.count() == 25 dump = walk.dump() log.destroy_all_walkers() walk2 = log.restore_walker(dump) assert walk2.count() == 25