xref: /aosp_15_r20/external/pigweed/pw_system/py/pw_system/device_sim.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2024 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Launch a simulated device subprocess under pw_console."""
15
16import argparse
17from pathlib import Path
18import subprocess
19import sys
20from types import ModuleType
21
22from pw_system.console import console, get_parser
23from pw_system.device_connection import DeviceConnection
24
25
26def _parse_args() -> tuple[argparse.Namespace, list[str]]:
27    parser = argparse.ArgumentParser(description=__doc__)
28    parser.add_argument(
29        '--sim-binary',
30        type=Path,
31        help='Path to a simulated device binary to run on the host',
32    )
33    return parser.parse_known_args()
34
35
36def launch_sim(
37    sim_binary: Path,
38    remaining_args: list[str],
39    compiled_protos: list[ModuleType] | None = None,
40    device_connection: DeviceConnection | None = None,
41) -> int:
42    """Launches a host-device-sim binary, and attaches a console to it."""
43    if '-s' not in remaining_args and '--socket-addr' not in remaining_args:
44        remaining_args.extend(['--socket-addr', 'default'])
45
46    # Pass the remaining arguments on to pw_system console.
47    console_args = get_parser().parse_args(remaining_args)
48
49    sim_process = subprocess.Popen(
50        sim_binary,
51        stdin=subprocess.DEVNULL,
52        stdout=subprocess.DEVNULL,
53        stderr=subprocess.STDOUT,
54    )
55
56    try:
57        retval = console(
58            **vars(console_args),
59            compiled_protos=compiled_protos,
60            device_connection=device_connection,
61        )
62    finally:
63        sim_process.terminate()
64
65    return retval
66
67
68def main(
69    compiled_protos: list[ModuleType] | None = None,
70    device_connection: DeviceConnection | None = None,
71) -> int:
72    sim_args, remaining_args = _parse_args()
73    return launch_sim(
74        **vars(sim_args),
75        remaining_args=remaining_args,
76        compiled_protos=compiled_protos,
77        device_connection=device_connection,
78    )
79
80
81# TODO(b/353327855): Deprecated function, remove when no longer used.
82def main_with_compiled_protos(
83    compiled_protos: list[ModuleType] | None = None,
84    device_connection: DeviceConnection | None = None,
85) -> int:
86    return main(
87        compiled_protos=compiled_protos,
88        device_connection=device_connection,
89    )
90
91
92if __name__ == '__main__':
93    sys.exit(main())
94