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