xref: /aosp_15_r20/external/pigweed/pw_console/embedding.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_console-embedding:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker===============
4*61c4878aSAndroid Build Coastguard WorkerEmbedding Guide
5*61c4878aSAndroid Build Coastguard Worker===============
6*61c4878aSAndroid Build Coastguard Worker.. pigweed-module-subpage::
7*61c4878aSAndroid Build Coastguard Worker   :name: pw_console
8*61c4878aSAndroid Build Coastguard Worker
9*61c4878aSAndroid Build Coastguard Worker-------------
10*61c4878aSAndroid Build Coastguard WorkerUsing embed()
11*61c4878aSAndroid Build Coastguard Worker-------------
12*61c4878aSAndroid Build Coastguard Worker``pw console`` is invoked by calling ``PwConsoleEmbed().embed()`` in your
13*61c4878aSAndroid Build Coastguard Workerown Python script. For a complete example of an embedded device console script see
14*61c4878aSAndroid Build Coastguard Worker:bdg-link-primary-line:`pw_system/py/pw_system/console.py <https://cs.pigweed.dev/pigweed/+/main:pw_system/py/pw_system/console.py>`.
15*61c4878aSAndroid Build Coastguard Worker
16*61c4878aSAndroid Build Coastguard Worker.. automodule:: pw_console.embed
17*61c4878aSAndroid Build Coastguard Worker    :members: PwConsoleEmbed
18*61c4878aSAndroid Build Coastguard Worker    :undoc-members:
19*61c4878aSAndroid Build Coastguard Worker    :show-inheritance:
20*61c4878aSAndroid Build Coastguard Worker
21*61c4878aSAndroid Build Coastguard Worker.. _module-pw_console-embedding-logstore:
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker.. autoclass:: pw_console.log_store.LogStore
24*61c4878aSAndroid Build Coastguard Worker    :members: __init__
25*61c4878aSAndroid Build Coastguard Worker    :undoc-members:
26*61c4878aSAndroid Build Coastguard Worker    :show-inheritance:
27*61c4878aSAndroid Build Coastguard Worker
28*61c4878aSAndroid Build Coastguard Worker.. _module-pw_console-embedding-plugins:
29*61c4878aSAndroid Build Coastguard Worker
30*61c4878aSAndroid Build Coastguard WorkerAdding Plugins
31*61c4878aSAndroid Build Coastguard Worker==============
32*61c4878aSAndroid Build Coastguard WorkerUser plugin instances are created before starting-up and passed to the Pigweed
33*61c4878aSAndroid Build Coastguard WorkerConsole embed instance. Typically, a console is started by creating a
34*61c4878aSAndroid Build Coastguard Worker``PwConsoleEmbed()`` instance, calling customization functions, then calling
35*61c4878aSAndroid Build Coastguard Worker``.embed()`` as shown in `Using embed()`_. Adding plugins functions similarly by
36*61c4878aSAndroid Build Coastguard Workercalling ``add_top_toolbar``, ``add_bottom_toolbar``,
37*61c4878aSAndroid Build Coastguard Worker``add_floating_window_plugin`` or ``add_window_plugin``. For example:
38*61c4878aSAndroid Build Coastguard Worker
39*61c4878aSAndroid Build Coastguard Worker.. code-block:: python
40*61c4878aSAndroid Build Coastguard Worker
41*61c4878aSAndroid Build Coastguard Worker   # Create plugin instances
42*61c4878aSAndroid Build Coastguard Worker   user_toolbar1 = DeviceStatusToolbar(device=client.client.channel(1))
43*61c4878aSAndroid Build Coastguard Worker   user_toolbar2 = BandwithToolbar()
44*61c4878aSAndroid Build Coastguard Worker   user_device_window = CustomWindowPlugin()
45*61c4878aSAndroid Build Coastguard Worker
46*61c4878aSAndroid Build Coastguard Worker   console = PwConsoleEmbed(
47*61c4878aSAndroid Build Coastguard Worker       global_vars=local_variables,
48*61c4878aSAndroid Build Coastguard Worker       loggers={
49*61c4878aSAndroid Build Coastguard Worker           'Device Logs': [logging.getLogger('rpc_device')],
50*61c4878aSAndroid Build Coastguard Worker           'Host Logs': [logging.getLogger()],
51*61c4878aSAndroid Build Coastguard Worker       },
52*61c4878aSAndroid Build Coastguard Worker       ...
53*61c4878aSAndroid Build Coastguard Worker   )
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker   # Add toolbar plugins
56*61c4878aSAndroid Build Coastguard Worker   console.add_top_toolbar(user_toolbar1)
57*61c4878aSAndroid Build Coastguard Worker   console.add_bottom_toolbar(user_toolbar2)
58*61c4878aSAndroid Build Coastguard Worker
59*61c4878aSAndroid Build Coastguard Worker   # Add Window plugins
60*61c4878aSAndroid Build Coastguard Worker   console.add_window_plugin(user_device_window)
61*61c4878aSAndroid Build Coastguard Worker
62*61c4878aSAndroid Build Coastguard Worker   # Start the console
63*61c4878aSAndroid Build Coastguard Worker   console.embed()
64*61c4878aSAndroid Build Coastguard Worker
65*61c4878aSAndroid Build Coastguard Worker-------------------
66*61c4878aSAndroid Build Coastguard WorkerAdding Log Metadata
67*61c4878aSAndroid Build Coastguard Worker-------------------
68*61c4878aSAndroid Build Coastguard Worker``pw_console`` can display log messages in a table with justified columns for
69*61c4878aSAndroid Build Coastguard Workermetadata fields provided by :ref:`module-pw_log_tokenized`.
70*61c4878aSAndroid Build Coastguard Worker
71*61c4878aSAndroid Build Coastguard WorkerIt is also possible to manually add values that should be displayed in columns
72*61c4878aSAndroid Build Coastguard Workerusing the ``extra`` keyword argument when logging from Python. See the `Python's
73*61c4878aSAndroid Build Coastguard Workerlogging documentation`_ for how ``extra`` works. A dict of name, value pairs can
74*61c4878aSAndroid Build Coastguard Workerbe passed in as the ``extra_metadata_fields`` variable. For example, the
75*61c4878aSAndroid Build Coastguard Workerfollowing code will create a log message with two custom columns titled
76*61c4878aSAndroid Build Coastguard Worker``module`` and ``timestamp``.
77*61c4878aSAndroid Build Coastguard Worker
78*61c4878aSAndroid Build Coastguard Worker.. code-block:: python
79*61c4878aSAndroid Build Coastguard Worker
80*61c4878aSAndroid Build Coastguard Worker   import logging
81*61c4878aSAndroid Build Coastguard Worker
82*61c4878aSAndroid Build Coastguard Worker   LOG = logging.getLogger('log_source_1')
83*61c4878aSAndroid Build Coastguard Worker
84*61c4878aSAndroid Build Coastguard Worker   LOG.info(
85*61c4878aSAndroid Build Coastguard Worker       'Hello there!',
86*61c4878aSAndroid Build Coastguard Worker       extra={
87*61c4878aSAndroid Build Coastguard Worker           'extra_metadata_fields': {
88*61c4878aSAndroid Build Coastguard Worker               'module': 'cool',
89*61c4878aSAndroid Build Coastguard Worker               'timestamp': 1.2345,
90*61c4878aSAndroid Build Coastguard Worker           }
91*61c4878aSAndroid Build Coastguard Worker       }
92*61c4878aSAndroid Build Coastguard Worker   )
93*61c4878aSAndroid Build Coastguard Worker
94*61c4878aSAndroid Build Coastguard Worker---------------------
95*61c4878aSAndroid Build Coastguard WorkerDebugging Serial Data
96*61c4878aSAndroid Build Coastguard Worker---------------------
97*61c4878aSAndroid Build Coastguard Worker``pw_console`` is often used to communicate with devices using `pySerial
98*61c4878aSAndroid Build Coastguard Worker<https://pythonhosted.org/pyserial/>`_ or
99*61c4878aSAndroid Build Coastguard Worker``pw_console.socket_client.SocketClient``. To monitor the raw data flowing over
100*61c4878aSAndroid Build Coastguard Workerthe wire, ``pw_console`` provides simple wrappers for pySerial and socket client
101*61c4878aSAndroid Build Coastguard Workerinstances that log data for each read and write call.
102*61c4878aSAndroid Build Coastguard Worker
103*61c4878aSAndroid Build Coastguard WorkerLogging data with PySerial
104*61c4878aSAndroid Build Coastguard Worker==========================
105*61c4878aSAndroid Build Coastguard Worker.. code-block:: python
106*61c4878aSAndroid Build Coastguard Worker
107*61c4878aSAndroid Build Coastguard Worker   # Instead of 'import serial' use this import:
108*61c4878aSAndroid Build Coastguard Worker   from pw_console.pyserial_wrapper import SerialWithLogging
109*61c4878aSAndroid Build Coastguard Worker
110*61c4878aSAndroid Build Coastguard Worker   serial_device = SerialWithLogging('/dev/ttyUSB0', 115200, timeout=1)
111*61c4878aSAndroid Build Coastguard Worker
112*61c4878aSAndroid Build Coastguard WorkerLogging data with sockets
113*61c4878aSAndroid Build Coastguard Worker=========================
114*61c4878aSAndroid Build Coastguard Worker.. code-block:: python
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard Worker   from pw_console.socket_client import SocketClientWithLogging
117*61c4878aSAndroid Build Coastguard Worker
118*61c4878aSAndroid Build Coastguard Worker   # Name resolution with explicit port
119*61c4878aSAndroid Build Coastguard Worker   serial_device = SocketClientWithLogging('localhost:1234')
120*61c4878aSAndroid Build Coastguard Worker   # Name resolution with default port.
121*61c4878aSAndroid Build Coastguard Worker   serial_device = SocketClientWithLogging('pigweed.dev')
122*61c4878aSAndroid Build Coastguard Worker   # Link-local IPv6 address with explicit port.
123*61c4878aSAndroid Build Coastguard Worker   serial_device = SocketClientWithLogging('[fe80::100%enp1s0]:1234')
124*61c4878aSAndroid Build Coastguard Worker   # Link-local IPv6 address with default port.
125*61c4878aSAndroid Build Coastguard Worker   serial_device = SocketClientWithLogging('[fe80::100%enp1s0]')
126*61c4878aSAndroid Build Coastguard Worker   # IPv4 address with port.
127*61c4878aSAndroid Build Coastguard Worker   serial_device = SocketClientWithLogging('1.2.3.4:5678')
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker.. tip::
130*61c4878aSAndroid Build Coastguard Worker   The ``SocketClient`` takes an optional callback called when a disconnect is
131*61c4878aSAndroid Build Coastguard Worker   detected. The ``pw_system`` console provides an example reconnect routine.
132*61c4878aSAndroid Build Coastguard Worker
133*61c4878aSAndroid Build Coastguard WorkerWith the above examples each ``serial_device.read`` and ``write`` call will
134*61c4878aSAndroid Build Coastguard Workercreate a log message to the ``pw_console.serial_debug_logger`` Python
135*61c4878aSAndroid Build Coastguard Workerlogger. This logger can then be included as a log window pane in the
136*61c4878aSAndroid Build Coastguard Worker``PwConsoleEmbed()`` call.
137*61c4878aSAndroid Build Coastguard Worker
138*61c4878aSAndroid Build Coastguard Worker.. code-block:: python
139*61c4878aSAndroid Build Coastguard Worker
140*61c4878aSAndroid Build Coastguard Worker   import logging
141*61c4878aSAndroid Build Coastguard Worker   from pw_console import PwConsoleEmbed
142*61c4878aSAndroid Build Coastguard Worker
143*61c4878aSAndroid Build Coastguard Worker   console = PwConsoleEmbed(
144*61c4878aSAndroid Build Coastguard Worker       global_vars=globals(),
145*61c4878aSAndroid Build Coastguard Worker       local_vars=locals(),
146*61c4878aSAndroid Build Coastguard Worker       loggers={
147*61c4878aSAndroid Build Coastguard Worker           'Host Logs': [
148*61c4878aSAndroid Build Coastguard Worker               # Root Python logger
149*61c4878aSAndroid Build Coastguard Worker               logging.getLogger(''),
150*61c4878aSAndroid Build Coastguard Worker               # Your current Python package logger.
151*61c4878aSAndroid Build Coastguard Worker               logging.getLogger(__package__)
152*61c4878aSAndroid Build Coastguard Worker           ],
153*61c4878aSAndroid Build Coastguard Worker           'Device Logs': [
154*61c4878aSAndroid Build Coastguard Worker               logging.getLogger('usb_gadget')
155*61c4878aSAndroid Build Coastguard Worker           ],
156*61c4878aSAndroid Build Coastguard Worker           'Serial Debug': [
157*61c4878aSAndroid Build Coastguard Worker               # New log window to display serial read and writes
158*61c4878aSAndroid Build Coastguard Worker               logging.getLogger('pw_console.serial_debug_logger')
159*61c4878aSAndroid Build Coastguard Worker           ],
160*61c4878aSAndroid Build Coastguard Worker       },
161*61c4878aSAndroid Build Coastguard Worker       app_title='CoolConsole',
162*61c4878aSAndroid Build Coastguard Worker   )
163*61c4878aSAndroid Build Coastguard Worker   # Then run the console with:
164*61c4878aSAndroid Build Coastguard Worker   console.embed()
165*61c4878aSAndroid Build Coastguard Worker
166*61c4878aSAndroid Build Coastguard Worker.. figure:: images/serial_debug.svg
167*61c4878aSAndroid Build Coastguard Worker  :alt: Serial debug pw_console screenshot.
168*61c4878aSAndroid Build Coastguard Worker
169*61c4878aSAndroid Build Coastguard Worker  Screenshot of issuing an Echo RPC with serial debug logging.
170*61c4878aSAndroid Build Coastguard Worker
171*61c4878aSAndroid Build Coastguard Worker
172*61c4878aSAndroid Build Coastguard Worker.. _Python's logging documentation: https://docs.python.org/3/library/logging.html#logging.Logger.debug
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker.. _module-pw_console-embedding-ipython:
175*61c4878aSAndroid Build Coastguard Worker
176*61c4878aSAndroid Build Coastguard Worker------------------------------
177*61c4878aSAndroid Build Coastguard WorkerEmbeddeding other interpreters
178*61c4878aSAndroid Build Coastguard Worker------------------------------
179*61c4878aSAndroid Build Coastguard WorkerThe Pigweed console is optimized for use with Pigweed, but other embedded Python
180*61c4878aSAndroid Build Coastguard Workerinterpreters may be used to interact with Pigweed devices. Popular options
181*61c4878aSAndroid Build Coastguard Workerinclude `IPython <https://ipython.org/>`_ and `bpython
182*61c4878aSAndroid Build Coastguard Worker<https://bpython-interpreter.org/>`_.
183*61c4878aSAndroid Build Coastguard Worker
184*61c4878aSAndroid Build Coastguard WorkerEmbedding IPython is similar to embedding ``pw_console``. After ``import
185*61c4878aSAndroid Build Coastguard WorkerIPython``, call ``IPython.start_ipython()`` with the set of variables to expose
186*61c4878aSAndroid Build Coastguard Workerin the console. See `Embedding IPython
187*61c4878aSAndroid Build Coastguard Worker<https://ipython.readthedocs.io/en/stable/interactive/reference.html#embedding>`_
188*61c4878aSAndroid Build Coastguard Workerfor details.
189*61c4878aSAndroid Build Coastguard Worker
190*61c4878aSAndroid Build Coastguard Worker.. code-block:: python
191*61c4878aSAndroid Build Coastguard Worker
192*61c4878aSAndroid Build Coastguard Worker   IPython.start_ipython(
193*61c4878aSAndroid Build Coastguard Worker       argv=[],
194*61c4878aSAndroid Build Coastguard Worker       display_banner=False,
195*61c4878aSAndroid Build Coastguard Worker       user_ns=local_variables,
196*61c4878aSAndroid Build Coastguard Worker   )
197*61c4878aSAndroid Build Coastguard Worker   return
198