From a5a43ace56e642f85a1be35396352fc915a24a41 Mon Sep 17 00:00:00 2001 From: rgoliver Date: Mon, 7 Mar 2022 16:33:22 -0500 Subject: [PATCH] RPC: Console improvements. (#15916) - Add chip device toolbar for viewing device info including; VID, PID, SN, Pairing code/discrimator, fabric, node, pair state - Add raw serial logger for debugging serial communication. - Decode EFR32 log lines. - Decode NFR32 log lines. - Decode NXP log lines. - Add raw logger for log streams which are not HDLC encoded. - Add a helper scripts class, which currently just has a script to read the descriptor cluster. --- .../common/pigweed/rpc_console/py/BUILD.gn | 6 +- .../rpc_console/py/chip_rpc/console.py | 136 +++++++++++++++--- .../py/chip_rpc/plugins/__init__.py | 0 .../py/chip_rpc/plugins/device_toolbar.py | 112 +++++++++++++++ .../py/chip_rpc/plugins/helper_scripts.py | 64 +++++++++ 5 files changed, 297 insertions(+), 21 deletions(-) create mode 100644 examples/common/pigweed/rpc_console/py/chip_rpc/plugins/__init__.py create mode 100644 examples/common/pigweed/rpc_console/py/chip_rpc/plugins/device_toolbar.py create mode 100644 examples/common/pigweed/rpc_console/py/chip_rpc/plugins/helper_scripts.py diff --git a/examples/common/pigweed/rpc_console/py/BUILD.gn b/examples/common/pigweed/rpc_console/py/BUILD.gn index 183a32c84f9dde..67c6164eeaf1c4 100644 --- a/examples/common/pigweed/rpc_console/py/BUILD.gn +++ b/examples/common/pigweed/rpc_console/py/BUILD.gn @@ -29,7 +29,11 @@ pw_python_package("chip_rpc") { install_requires = [ "ipython" ] } } - sources = [ "chip_rpc/console.py" ] + sources = [ + "chip_rpc/console.py", + "chip_rpc/plugins/device_toolbar.py", + "chip_rpc/plugins/helper_scripts.py", + ] python_deps = [ "$dir_pw_console/py", "$dir_pw_hdlc/py", diff --git a/examples/common/pigweed/rpc_console/py/chip_rpc/console.py b/examples/common/pigweed/rpc_console/py/chip_rpc/console.py index 50591411c64845..34567bbd19ca64 100644 --- a/examples/common/pigweed/rpc_console/py/chip_rpc/console.py +++ b/examples/common/pigweed/rpc_console/py/chip_rpc/console.py @@ -30,31 +30,35 @@ rpcs - used to invoke RPCs device - the serial device used for communication client - the pw_rpc.Client + scripts - helper scripts for working with chip devices protos - protocol buffer messages indexed by proto package An example RPC command: rpcs.chip.rpc.DeviceCommon.GetDeviceInfo() """ -import json import argparse +from typing import Callable from collections import namedtuple +from inspect import cleandoc import logging -import functools +import re +import socket +from concurrent.futures import ThreadPoolExecutor import sys +import threading from typing import Any, BinaryIO -import socket -from inspect import cleandoc -import serial # type: ignore -import re + +from chip_rpc.plugins.device_toolbar import DeviceToolbar +from chip_rpc.plugins.helper_scripts import HelperScripts import pw_cli.log from pw_console import PwConsoleEmbed from pw_console.__main__ import create_temp_log_file +from pw_console.pyserial_wrapper import SerialWithLogging from pw_hdlc.rpc import HdlcRpcClient, default_channels from pw_rpc import callback_client from pw_rpc.console_tools.console import ClientInfo, flattened_rpc_completions - # Protos from attributes_service import attributes_service_pb2 from button_service import button_service_pb2 @@ -103,6 +107,11 @@ def _parse_args(): default=sys.stdout.buffer, help=('The file to which to write device output (HDLC channel 1); ' 'provide - or omit for stdout.')) + parser.add_argument( + '-r', + '--raw_serial', + action="store_true", + help=('Use raw serial instead of HDLC/RPC')) group.add_argument('-s', '--socket-addr', type=str, @@ -111,12 +120,53 @@ def _parse_args(): return parser.parse_args() -def _start_ipython_terminal(client: HdlcRpcClient) -> None: +def _start_ipython_raw_terminal() -> None: + """Starts an interactive IPython terminal with preset variables. This raw + terminal does not use HDLC and provides no RPC functionality, this is + just a serial log viewer.""" + local_variables = dict( + LOG=_DEVICE_LOG, + ) + + welcome_message = cleandoc(""" + Welcome to the CHIP Console! + + This has been started in raw serial mode, + and all RPC functionality is disabled. + + Press F1 for help. + """) + + interactive_console = PwConsoleEmbed( + global_vars=local_variables, + local_vars=None, + loggers={ + 'Device Logs': [_DEVICE_LOG], + 'Host Logs': [logging.getLogger()], + 'Serial Debug': [logging.getLogger('pw_console.serial_debug_logger')], + }, + repl_startup_message=welcome_message, + help_text=__doc__, + app_title="CHIP Console", + ) + + interactive_console.hide_windows('Host Logs') + interactive_console.hide_windows('Serial Debug') + + # Setup Python logger propagation + interactive_console.setup_python_logging() + # Don't send device logs to the root logger. + _DEVICE_LOG.propagate = False + interactive_console.embed() + + +def _start_ipython_hdlc_terminal(client: HdlcRpcClient) -> None: """Starts an interactive IPython terminal with preset variables.""" local_variables = dict( client=client, channel_client=client.client.channel(1), rpcs=client.client.channel(1).rpcs, + scripts=HelperScripts(client.client.channel(1).rpcs), protos=client.protos.packages, # Include the active pane logger for creating logs in the repl. LOG=_DEVICE_LOG, @@ -132,7 +182,7 @@ def _start_ipython_terminal(client: HdlcRpcClient) -> None: Press F1 for help. Example commands: - rpcs.chip.rpc.DeviceCommon.GetDeviceInfo() + rpcs.chip.rpc.Device.GetDeviceInfo() LOG.warning('Message appears console log window.') """) @@ -143,13 +193,19 @@ def _start_ipython_terminal(client: HdlcRpcClient) -> None: loggers={ 'Device Logs': [_DEVICE_LOG], 'Host Logs': [logging.getLogger()], + 'Serial Debug': [logging.getLogger('pw_console.serial_debug_logger')], }, repl_startup_message=welcome_message, help_text=__doc__, app_title="CHIP Console", ) - interactive_console.hide_windows('Host Logs') + interactive_console.add_sentence_completer(completions) + interactive_console.add_bottom_toolbar( + DeviceToolbar(client.client.channel(1).rpcs)) + + interactive_console.hide_windows('Host Logs') + interactive_console.hide_windows('Serial Debug') # Setup Python logger propagation interactive_console.setup_python_logging() @@ -183,12 +239,32 @@ def write_to_output(data: bytes, unused_output: BinaryIO = sys.stdout.buffer,): log_line = data RegexStruct = namedtuple('RegexStruct', 'platform type regex match_num') - LEVEL_MAPPING = {"I": logging.INFO, "W": logging.WARNING, - "E": logging.ERROR, "F": logging.FATAL, "V": logging.DEBUG, "D": logging.DEBUG} + LEVEL_MAPPING = {"I": logging.INFO, "W": logging.WARNING, "P": logging.INFO, + "E": logging.ERROR, "F": logging.FATAL, "V": logging.DEBUG, "D": logging.DEBUG, + "": logging.INFO, "": logging.DEBUG, "": logging.ERROR, + "": logging.INFO, "": logging.WARNING, + "": logging.ERROR, "": logging.DEBUG} + ESP_CHIP_REGEX = r"(?P[IWEFV]) \((?P