def test_dfs_trace_filter(self): pta = PTA(["IDLE"]) pta.add_transition("UNINITIALIZED", "IDLE", "init") pta.add_transition("IDLE", "IDLE", "set1") pta.add_transition("IDLE", "IDLE", "set2") self.assertEqual( sorted( dfs_tran_to_name( pta.dfs( 2, trace_filter=[ ["init", "set1", "set2"], ["init", "set2", "set1"], ], ), False, )), [["init", "set1", "set2"], ["init", "set2", "set1"]], ) self.assertEqual( sorted( dfs_tran_to_name( pta.dfs(2, trace_filter=[["init", "set1", "$"], ["init", "set2", "$"]]), False, )), [["init", "set1"], ["init", "set2"]], )
def test_shrink(self): pta = PTA.from_yaml(example_yaml_3) pta.shrink_argument_values() self.assertEqual(pta.transitions[0].name, "setAutoAck") self.assertEqual(pta.transitions[1].name, "setPALevel") self.assertEqual(pta.transitions[2].name, "setRetries") self.assertEqual(pta.transitions[3].name, "setup") self.assertEqual(pta.transitions[4].name, "setup") self.assertEqual(pta.transitions[5].name, "write") self.assertEqual(pta.transitions[0].argument_values, [[0, 1]]) self.assertEqual( pta.transitions[1].argument_values, [["Nrf24l01::RF24_PA_MIN", "Nrf24l01::RF24_PA_MAX"]], ) self.assertEqual(pta.transitions[2].argument_values, [[0, 15], [0, 15]]) self.assertEqual( pta.transitions[5].argument_values, [ [ '"foo"', '"foo"', '"foofoofoo"', '"foofoofoo"', '"123456789012345678901234567890"', '"123456789012345678901234567890"', ], [3, 3, 9, 9, 30, 30], [0, 1, 0, 1, 0, 1], [1, 1, 1, 1, 1, 1], ], )
def test_statetransition_immediate(self): pta = PTA.from_json(example_json_1) pta.set_random_energy_model() pta.state["IDLE"].power.value = 9 cg = get_simulated_accountingmethod( "static_statetransition_immediate")(pta, 1000000, "uint8_t", "uint8_t", "uint8_t", "uint8_t") cg.current_state = pta.state["IDLE"] cg.sleep(7) self.assertEqual(cg.get_energy(), 9 * 7) pta.transitions[1].energy.value = 123 cg.pass_transition(pta.transitions[1]) self.assertEqual(cg.get_energy(), 9 * 7 + 123) cg.pass_transition(pta.transitions[1]) self.assertEqual(cg.get_energy(), (9 * 7 + 123 + 123) % 256) cg = get_simulated_accountingmethod( "static_statetransition_immediate")(pta, 100000, "uint8_t", "uint8_t", "uint8_t", "uint8_t") cg.current_state = pta.state["IDLE"] cg.sleep(7) self.assertEqual(cg.get_energy(), 0) cg.sleep(15) self.assertEqual(cg.get_energy(), 90) cg.sleep(90) self.assertEqual(cg.get_energy(), 900 % 256) cg = get_simulated_accountingmethod( "static_statetransition_immediate")(pta, 100000, "uint8_t", "uint8_t", "uint8_t", "uint16_t") cg.current_state = pta.state["IDLE"] cg.sleep(7) self.assertEqual(cg.get_energy(), 0) cg.sleep(15) self.assertEqual(cg.get_energy(), 90) cg.sleep(90) self.assertEqual(cg.get_energy(), 900) pta.state["IDLE"].power.value = 9 # -> 90 uW pta.transitions[1].energy.value = 1 # -> 100 pJ cg = get_simulated_accountingmethod( "static_statetransition_immediate")(pta, 1000000, "uint8_t", "uint8_t", "uint8_t", "uint8_t", 1e-5, 1e-5, 1e-10) cg.current_state = pta.state["IDLE"] cg.sleep(10) # 10 us self.assertEqual(cg.get_energy(), 90 * 10) cg.pass_transition(pta.transitions[1]) self.assertAlmostEqual(cg.get_energy(), 90 * 10 + 100, places=0) cg.pass_transition(pta.transitions[1]) self.assertAlmostEqual(cg.get_energy(), 90 * 10 + 100 + 100, places=0)
def test_from_json(self): pta = PTA.from_json(example_json_1) self.assertEqual(pta.parameters, ["datarate", "txbytes", "txpower"]) self.assertEqual(pta.state["UNINITIALIZED"].name, "UNINITIALIZED") self.assertEqual(pta.state["IDLE"].name, "IDLE") self.assertEqual(pta.state["TX"].name, "TX") self.assertEqual(len(pta.transitions), 5) self.assertEqual(pta.transitions[0].name, "init") self.assertEqual(pta.transitions[1].name, "init") self.assertEqual(pta.transitions[2].name, "setTxPower") self.assertEqual(pta.transitions[3].name, "send") self.assertEqual(pta.transitions[4].name, "txComplete")
def test_state_immediate(self): pta = PTA.from_json(example_json_1) pta.set_random_energy_model() pta.state["IDLE"].power.value = 9 cg = get_simulated_accountingmethod("static_state_immediate")( pta, 1000000, "uint8_t", "uint8_t", "uint8_t", "uint8_t") cg.current_state = pta.state["IDLE"] cg.sleep(7) self.assertEqual(cg.get_energy(), 9 * 7) pta.transitions[1].energy.value = 123 cg.pass_transition(pta.transitions[1]) self.assertEqual(cg.get_energy(), 9 * 7) cg.pass_transition(pta.transitions[1]) self.assertEqual(cg.get_energy(), 9 * 7)
def test_get_X_expensive_state(self): pta = PTA.from_json(example_json_1) self.assertEqual(pta.get_least_expensive_state(), pta.state["IDLE"]) self.assertEqual(pta.get_most_expensive_state(), pta.state["TX"]) # self.assertAlmostEqual(pta.min_duration_until_energy_overflow(), (2**32 - 1) * 1e-12 / 10e-3, places=9) # self.assertAlmostEqual(pta.min_duration_until_energy_overflow(energy_granularity=1e-9), (2**32 - 1) * 1e-9 / 10e-3, places=9) self.assertAlmostEqual( pta.max_duration_until_energy_overflow(), (2**32 - 1) * 1e-12 / 5e-6, places=9, ) self.assertAlmostEqual( pta.max_duration_until_energy_overflow(energy_granularity=1e-9), (2**32 - 1) * 1e-9 / 5e-6, places=9, )
def test_from_json_dfs_arg(self): pta = PTA.from_json(example_json_1) self.assertEqual( sorted(dfs_tran_to_name(pta.dfs(1), False)), [["init", "init"], ["init", "send"], ["init", "setTxPower"]], ) self.assertEqual( sorted(dfs_tran_to_name(pta.dfs(1, with_arguments=True), True)), [ [("init", ()), ("init", ())], [("init", ()), ("send", ('"foo"', 3))], [("init", ()), ("send", ('"hodor"', 5))], [("init", ()), ("setTxPower", (10, ))], [("init", ()), ("setTxPower", (20, ))], [("init", ()), ("setTxPower", (30, ))], ], )
def test_from_json_function(self): pta = PTA.from_json(example_json_1) self.assertEqual( pta.state["TX"].get_energy(1000, { "datarate": 10, "txbytes": 6, "txpower": 10 }), 1000 * (10000 + 2 * 10), ) self.assertEqual( pta.transitions[4].get_timeout({ "datarate": 10, "txbytes": 6, "txpower": 10 }), 500 + 16 * 6, )
def test_normalization(self): pta = PTA.from_yaml(example_yaml_2) no_param = {"datarate": None, "txbytes": None, "txpower": None} param_tx3 = {"datarate": None, "txbytes": 3, "txpower": None} param_tx6 = {"datarate": None, "txbytes": 6, "txpower": None} param_txp10 = {"datarate": None, "txbytes": None, "txpower": -6} param_txp20 = {"datarate": None, "txbytes": None, "txpower": 4} param_txp30 = {"datarate": None, "txbytes": None, "txpower": 14} self.assertEqual( sorted( dfs_tran_to_name( pta.dfs(1, with_arguments=True, with_parameters=True), True, True)), [ [("init", (), no_param), ("init", (), no_param)], [("init", (), no_param), ("send", ("FOO", ), param_tx3)], [("init", (), no_param), ("send", ("LONGER", ), param_tx6)], [("init", (), no_param), ("setTxPower", (10, ), param_txp10)], [("init", (), no_param), ("setTxPower", (20, ), param_txp20)], [("init", (), no_param), ("setTxPower", (30, ), param_txp30)], ], )
def test_from_yaml_dfs_param(self): pta = PTA.from_yaml(example_yaml_1) no_param = {"datarate": None, "txbytes": None, "txpower": None} param_tx3 = {"datarate": None, "txbytes": 3, "txpower": None} param_tx5 = {"datarate": None, "txbytes": 5, "txpower": None} param_txp10 = {"datarate": None, "txbytes": None, "txpower": 10} param_txp20 = {"datarate": None, "txbytes": None, "txpower": 20} param_txp30 = {"datarate": None, "txbytes": None, "txpower": 30} self.assertEqual( sorted( dfs_tran_to_name( pta.dfs(1, with_arguments=True, with_parameters=True), True, True)), [ [("init", (), no_param), ("init", (), no_param)], [("init", (), no_param), ("send", ('"foo"', 3), param_tx3)], [("init", (), no_param), ("send", ('"hodor"', 5), param_tx5)], [("init", (), no_param), ("setTxPower", (10, ), param_txp10)], [("init", (), no_param), ("setTxPower", (20, ), param_txp20)], [("init", (), no_param), ("setTxPower", (30, ), param_txp30)], ], )
def test_simulation_set_param(self): pta = PTA(parameters=["txpower", "length"]) pta.add_state("IDLE", power=5) pta.add_state("TX", power=100) pta.add_transition( "UNINITIALIZED", "IDLE", "init", energy=500000, duration=50000, set_param={"txpower": 10}, ) trace = [["init"]] expected_energy = 500000 expected_duration = 50000 result = pta.simulate(trace) self.assertAlmostEqual(result.energy, expected_energy * 1e-12, places=12) self.assertAlmostEqual(result.duration, expected_duration * 1e-6, places=6) self.assertEqual(result.end_state.name, "IDLE") self.assertEqual(result.parameters, {"txpower": 10, "length": None})
def benchmark_from_runs( pta: PTA, runs: list, harness: OnboardTimerHarness, benchmark_id: int = 0, dummy=False, repeat=0, ) -> io.StringIO: outbuf = io.StringIO() outbuf.write(target.app_header()) if dummy: outbuf.write('#include "driver/dummy.h"\n') elif "includes" in pta.codegen: for include in pta.codegen["includes"]: outbuf.write('#include "{}"\n'.format(include)) outbuf.write(harness.global_code()) outbuf.write(target.app_function_start()) # There is a race condition between flashing the code and starting the UART log. # When starting the log before flashing, output from a previous benchmark may cause bogus data to be added. # When flashing first and then starting the log, the first log lines may be lost. # To work around this, we flash first, then start the log, and use this delay statement to ensure that no output is lost. # This is also useful to faciliate MIMOSA calibration after flashing # For MIMOSA, the DUT is disconnected from power during calibration, so # it must be set up after the calibration delay. # For energytrace, the device is connected to VCC and set up before # the initialization delay to -- this puts it into a well-defined state and # decreases pre-sync power consumption if "energytrace" not in opt: if "mimosa" in opt: outbuf.write(target.app_delay(12000)) else: outbuf.write(target.app_delay(2000)) # Output some newlines to ensure the parser can determine the start of the first real output line outbuf.write(target.app_newlines()) if "setup" in pta.codegen: for call in pta.codegen["setup"]: outbuf.write(call) if "energytrace" in opt: outbuf.write("for (unsigned char j = 0; j < 10; j++) {\n") outbuf.write(target.app_sleep(250)) outbuf.write("}\n") # Output some newlines to ensure the parser can determine the start of the first real output line outbuf.write(target.app_newlines()) if repeat: outbuf.write("unsigned char i = 0;\n") outbuf.write("while (i++ < {}) {{\n".format(repeat)) else: outbuf.write("while (1) {\n") outbuf.write(harness.start_benchmark()) class_prefix = "" if "instance" in opt: class_prefix = "{}.".format(opt["instance"]) elif "instance" in pta.codegen: class_prefix = "{}.".format(pta.codegen["instance"]) num_transitions = 0 num_traces = 0 for run in runs: outbuf.write(harness.start_run()) harness.start_trace() param = pta.get_initial_param_dict() for transition, arguments, parameter in run: num_transitions += 1 harness.append_transition(transition.name, param, arguments) harness.append_state(transition.destination.name, parameter.copy()) outbuf.write("// {} -> {}\n".format(transition.origin.name, transition.destination.name)) if transition.is_interrupt: outbuf.write("// wait for {} interrupt\n".format( transition.name)) transition_code = "// TODO add startTransition / stopTransition calls to interrupt routine" else: transition_code = "{}{}({});".format( class_prefix, transition.name, ", ".join(map(str, arguments))) outbuf.write( harness.pass_transition( pta.get_transition_id(transition), transition_code, transition=transition, )) param = parameter outbuf.write("// current parameters: {}\n".format(", ".join( map(lambda kv: "{}={}".format(*kv), param.items())))) if "delay_after_ms" in transition.codegen: if "energytrace" in opt: outbuf.write( target.app_sleep( transition.codegen["delay_after_ms"], f"{transition.destination.name} -- delay mandated by codegen.delay_after_ms", )) else: outbuf.write( target.app_delay( transition.codegen["delay_after_ms"], f"{transition.destination.name} -- delay mandated by codegen.delay_after_ms", )) elif opt["sleep"]: if "energytrace" in opt: outbuf.write(f"// -> {transition.destination.name}\n") outbuf.write(target.sleep_ms(opt["sleep"])) else: outbuf.write(f"// -> {transition.destination.name}\n") outbuf.write(target.app_delay(opt["sleep"])) outbuf.write(harness.stop_run(num_traces)) if dummy: outbuf.write( 'kout << "[Energy] " << {}getEnergy() << endl;\n'.format( class_prefix)) outbuf.write("\n") num_traces += 1 outbuf.write(harness.stop_benchmark()) outbuf.write("}\n") # Ensure logging can be terminated after the specified number of measurements outbuf.write(harness.start_benchmark()) outbuf.write(target.app_function_end()) return outbuf
#!/usr/bin/env python3 from dfatool.aspectc import Repo from dfatool.codegen import MultipassDriver from dfatool.automata import PTA import yaml with open("../multipass/model/driver/nrf24l01.dfa", "r") as f: driver_definition = yaml.safe_load(f) pta = PTA.from_yaml(driver_definition) repo = Repo("../multipass/build/repo.acp") enum = dict() if "dummygen" in driver_definition and "enum" in driver_definition["dummygen"]: enum = driver_definition["dummygen"]["enum"] drv = MultipassDriver("Nrf24l01", pta, repo.class_by_name["Nrf24l01"], enum=enum) with open("../multipass/src/driver/dummy.cc", "w") as f: f.write(drv.impl) with open("../multipass/include/driver/dummy.h", "w") as f: f.write(drv.header)
if result.energy_mae: print(u" ± {} / {:.0f}%".format( human_readable(result.energy_mae, "J"), result.energy_mape)) print(" Mean Power: " + human_readable(result.mean_power, "W")) print("") prev_state = result.end_state prev_param = result.parameters return ret for i in range(len(args) // 2): ptafile, raw_word = args[i * 2], args[i * 2 + 1] ptafiles.append(ptafile) pta = PTA.from_file(ptafile) timedword = TimedSequence(raw_word) print("Input: {}\n".format(timedword)) loops[ptafile] = simulate_word(timedword) for loop_name in sorted(loop_names): result_set = list() total_power = 0 for ptafile in sorted(ptafiles): if loop_name in loops[ptafile]: result_set.append(loops[ptafile][loop_name]) total_power += loops[ptafile][loop_name].mean_power print("{}: total mean power is {}".format(loop_name, human_readable(total_power, "W"))) for i, result in enumerate(result_set):
def main(filename): pta = PTA.from_file(filename) print(pta.to_dot())
def test_dfs_objects(self): pta = PTA(["IDLE", "TX"]) pta.add_transition("UNINITIALIZED", "IDLE", "init") pta.add_transition("IDLE", "TX", "send") pta.add_transition("TX", "IDLE", "txComplete") traces = list(pta.dfs(2)) self.assertEqual(len(traces), 1) trace = traces[0] self.assertEqual(len(trace), 3) self.assertEqual(trace[0][0].name, "init") self.assertEqual(trace[1][0].name, "send") self.assertEqual(trace[2][0].name, "txComplete") self.assertEqual(pta.get_transition_id(trace[0][0]), 0) self.assertEqual(pta.get_transition_id(trace[1][0]), 1) self.assertEqual(pta.get_transition_id(trace[2][0]), 2)
def test_dfs_accepting(self): pta = PTA(["IDLE", "TX"], accepting_states=["IDLE"]) pta.add_transition("UNINITIALIZED", "IDLE", "init") pta.add_transition("IDLE", "TX", "send") pta.add_transition("TX", "IDLE", "txComplete") self.assertEqual(dfs_tran_to_name(pta.dfs(0), False), [["init"]]) self.assertEqual(dfs_tran_to_name(pta.dfs(1), False), []) self.assertEqual(dfs_tran_to_name(pta.dfs(2), False), [["init", "send", "txComplete"]]) self.assertEqual(dfs_tran_to_name(pta.dfs(3), False), [])
def test_simulation(self): pta = PTA() pta.add_state("IDLE", power=5) pta.add_state("TX", power=100) pta.add_transition("UNINITIALIZED", "IDLE", "init", duration=50000) pta.add_transition("IDLE", "TX", "send", energy=3, duration=10) pta.add_transition("TX", "IDLE", "txComplete", timeout=2000, is_interrupt=True) trace = [ ["init"], [None, 10000000], ["send", "foo", 3], [None, 5000000], ["send", "foo", 3], ] expected_energy = 5.0 * 10000000 + 3 + 100 * 2000 + 5 * 5000000 + 3 + 100 * 2000 expected_duration = 50000 + 10000000 + 10 + 2000 + 5000000 + 10 + 2000 result = pta.simulate(trace) self.assertAlmostEqual(result.energy, expected_energy * 1e-12, places=12) self.assertAlmostEqual(result.duration, expected_duration * 1e-6, places=6) self.assertEqual(result.end_state.name, "IDLE") self.assertEqual(result.parameters, {})
def test_dfs_with_sleep(self): pta = PTA(["IDLE", "TX"]) pta.add_transition("UNINITIALIZED", "IDLE", "init") pta.add_transition("IDLE", "TX", "send") pta.add_transition("TX", "IDLE", "txComplete") traces = list(pta.dfs(2, sleep=10)) self.assertEqual(len(traces), 1) trace = traces[0] self.assertEqual(len(trace), 6) self.assertIsNone(trace[0][0]) self.assertEqual(trace[1][0].name, "init") self.assertIsNone(trace[2][0]) self.assertEqual(trace[3][0].name, "send") self.assertIsNone(trace[4][0]) self.assertEqual(trace[5][0].name, "txComplete") self.assertEqual(pta.get_transition_id(trace[1][0]), 0) self.assertEqual(pta.get_transition_id(trace[3][0]), 1) self.assertEqual(pta.get_transition_id(trace[5][0]), 2)
show_models = args.show_models show_quality = args.show_quality if args.filter_param: args.filter_param = list( map(lambda x: x.split("="), args.filter_param.split(",")) ) else: args.filter_param = list() if args.with_safe_functions is not None: safe_functions_enabled = True if args.hwmodel: pta = PTA.from_file(args.hwmodel) raw_data = RawData( args.measurement, with_traces=( args.export_traces is not None or args.plot_traces is not None or args.with_substates is not None ), skip_cache=args.no_cache, ) if args.info: print(" ".join(raw_data.filenames) + ":") data_source = "???" if raw_data.ptalog:
def test_simulation_arg_function(self): pta = PTA(parameters=["txpower", "length"]) pta.add_state("IDLE", power=5) pta.add_state("TX", power=100) pta.add_transition("UNINITIALIZED", "IDLE", "init", energy=500000, duration=50000) pta.add_transition( "IDLE", "IDLE", "setTxPower", energy=10000, duration=120, param_update_function=lambda param, arg: { **param, "txpower": arg[0] }, ) pta.add_transition( "IDLE", "TX", "send", energy=AnalyticFunction( 3, "regression_arg(0) + regression_arg(1) * function_arg(1)", ["txpower", "length"], regression_args=[3.0, 5], num_args=2, ), duration=AnalyticFunction( 10, "regression_arg(0) + regression_arg(1) * function_arg(1)", ["txpower", "length"], regression_args=[48, 8], num_args=2, ), ) pta.add_transition("TX", "IDLE", "txComplete", timeout=2000, is_interrupt=True) trace = [["init"], ["setTxPower", 10], ["send", "foo", 3]] expected_energy = 500000 + 10000 + (3 + 5 * 3) + (2000 * 100) expected_duration = 50000 + 120 + (48 + 8 * 3) + 2000 result = pta.simulate(trace) self.assertAlmostEqual(result.energy, expected_energy * 1e-12, places=12) self.assertAlmostEqual(result.duration, expected_duration * 1e-6, places=6) self.assertEqual(result.end_state.name, "IDLE") self.assertEqual(result.parameters, {"txpower": 10, "length": None}) pta = PTA(parameters=["txpower", "length"]) pta.add_state("IDLE", power=5) pta.add_state("TX", power=100) pta.add_transition("UNINITIALIZED", "IDLE", "init", energy=500000, duration=50000) pta.add_transition( "IDLE", "IDLE", "setTxPower", energy=10000, duration=120, param_update_function=lambda param, arg: { **param, "txpower": arg[0] }, ) pta.add_transition( "IDLE", "TX", "send", energy=AnalyticFunction( 3, "regression_arg(0) + regression_arg(1) * function_arg(1)", ["txpower", "length"], regression_args=[3, 5], num_args=2, ), duration=AnalyticFunction( 10, "regression_arg(0) + regression_arg(1) * function_arg(1)", ["txpower", "length"], regression_args=[48, 8], num_args=2, ), ) pta.add_transition("TX", "IDLE", "txComplete", timeout=2000, is_interrupt=True) trace = [["init"], ["setTxPower", 10], ["send", "foobar", 6]] expected_energy = 500000 + 10000 + (3 + 5 * 6) + (2000 * 100) expected_duration = 50000 + 120 + (48 + 8 * 6) + 2000 result = pta.simulate(trace) self.assertAlmostEqual(result.energy, expected_energy * 1e-12, places=12) self.assertAlmostEqual(result.duration, expected_duration * 1e-6, places=6) self.assertEqual(result.end_state.name, "IDLE") self.assertEqual(result.parameters, {"txpower": 10, "length": None})
if "trace-filter" in opt: trace_filter = [] for trace in opt["trace-filter"].split(): trace_filter.append(trace.split(",")) opt["trace-filter"] = trace_filter else: opt["trace-filter"] = None except getopt.GetoptError as err: print(err) sys.exit(2) modelfile = args[0] pta = PTA.from_file(modelfile) enum = dict() if ".json" not in modelfile: with open(modelfile, "r") as f: driver_definition = yaml.safe_load(f) if "dummygen" in driver_definition and "enum" in driver_definition[ "dummygen"]: enum = driver_definition["dummygen"]["enum"] pta.set_random_energy_model() runs = list( pta.dfs( opt["depth"], with_arguments=True,
def test_simulation_param_function(self): pta = PTA(parameters=["length", "txpower"]) pta.add_state("IDLE", power=5) pta.add_state( "TX", power=AnalyticFunction( 100, "regression_arg(0) + regression_arg(1) * parameter(txpower)", ["length", "txpower"], regression_args=[1000, 2], ), ) pta.add_transition("UNINITIALIZED", "IDLE", "init", energy=500000, duration=50000) pta.add_transition( "IDLE", "IDLE", "setTxPower", energy=10000, duration=120, param_update_function=lambda param, arg: { **param, "txpower": arg[0] }, ) pta.add_transition( "IDLE", "TX", "send", energy=AnalyticFunction( 3, "regression_arg(0) + regression_arg(1) * function_arg(1)", ["length", "txpower"], regression_args=[3, 5], num_args=2, ), duration=10, param_update_function=lambda param, arg: { **param, "length": arg[1] }, ) pta.add_transition( "TX", "IDLE", "txComplete", is_interrupt=True, timeout=AnalyticFunction( 2000, "regression_arg(0) + regression_arg(1) * parameter(length)", ["length", "txpower"], regression_args=[500, 16], ), ) trace = [["init"], ["setTxPower", 10], ["send", "foo", 3]] expected_energy = (500000 + 10000 + (3 + 5 * 3) + (1000 + 2 * 10) * (500 + 16 * 3)) expected_duration = 50000 + 120 + 10 + (500 + 16 * 3) result = pta.simulate(trace) self.assertAlmostEqual(result.energy, expected_energy * 1e-12, places=12) self.assertAlmostEqual(result.duration, expected_duration * 1e-6, places=6) self.assertEqual(result.end_state.name, "IDLE") self.assertEqual(result.parameters, {"txpower": 10, "length": 3})
def test_simulation_arg_to_param_map(self): pta = PTA(parameters=["txpower", "length"]) pta.add_state("IDLE", power=5) pta.add_state("TX", power=100) pta.add_transition("UNINITIALIZED", "IDLE", "init", energy=500000, duration=50000) pta.add_transition( "IDLE", "IDLE", "setTxPower", energy=10000, duration=120, arg_to_param_map={0: "txpower"}, ) pta.add_transition("IDLE", "TX", "send", energy=3, duration=10) pta.add_transition("TX", "IDLE", "txComplete", timeout=2000, is_interrupt=True) trace = [["init"], ["setTxPower", 10]] expected_energy = 510000 expected_duration = 50120 result = pta.simulate(trace) self.assertAlmostEqual(result.energy, expected_energy * 1e-12, places=12) self.assertAlmostEqual(result.duration, expected_duration * 1e-6, places=6) self.assertEqual(result.end_state.name, "IDLE") self.assertEqual(result.parameters, {"txpower": 10, "length": None})
def test_bfs(self): pta = PTA(["IDLE", "TX"]) pta.add_transition("UNINITIALIZED", "IDLE", "init") pta.add_transition("IDLE", "TX", "send") pta.add_transition("TX", "IDLE", "txComplete") self.assertEqual(dfs_tran_to_name(pta.bfs(0), False), [["init"]]) self.assertEqual(dfs_tran_to_name(pta.bfs(1), False), [["init"], ["init", "send"]]) self.assertEqual( dfs_tran_to_name(pta.bfs(2), False), [["init"], ["init", "send"], ["init", "send", "txComplete"]], ) self.assertEqual( dfs_tran_to_name(pta.bfs(3), False), [ ["init"], ["init", "send"], ["init", "send", "txComplete"], ["init", "send", "txComplete", "send"], ], ) pta = PTA(["IDLE"]) pta.add_transition("UNINITIALIZED", "IDLE", "init") pta.add_transition("IDLE", "IDLE", "set1") pta.add_transition("IDLE", "IDLE", "set2") self.assertEqual(dfs_tran_to_name(pta.bfs(0), False), [["init"]]) self.assertEqual( sorted(dfs_tran_to_name(pta.bfs(1), False)), [["init"], ["init", "set1"], ["init", "set2"]], ) self.assertEqual( sorted(dfs_tran_to_name(pta.bfs(2), False)), [ ["init"], ["init", "set1"], ["init", "set1", "set1"], ["init", "set1", "set2"], ["init", "set2"], ["init", "set2", "set1"], ["init", "set2", "set2"], ], )