From 4db65d5f4cf87a5720c7fc088ae8a2fd734aa7e2 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Tue, 16 Jun 2026 15:34:02 +0800 Subject: [PATCH] refactor(bt): migrate bt_hci_to_btsnoop to esp-pylib Replace argparse with rich-click and use esp_pylib.logger for standardized console output and fatal error handling. (cherry picked from commit 3a7896f2c5a3c335be238f912e825543e9c6f72f) Co-authored-by: zhanghaipeng --- tools/bt/bt_hci_to_btsnoop.py | 54 +++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/tools/bt/bt_hci_to_btsnoop.py b/tools/bt/bt_hci_to_btsnoop.py index cb362865316..2279bfc54c3 100644 --- a/tools/bt/bt_hci_to_btsnoop.py +++ b/tools/bt/bt_hci_to_btsnoop.py @@ -1,11 +1,14 @@ -# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 -import argparse import os import re import struct import time +import rich_click as click +from esp_pylib.logger import log +from rich.markup import escape + def create_new_bt_snoop_file(filename: str) -> None: with open(filename, 'wb') as f: @@ -19,9 +22,9 @@ def create_new_bt_snoop_file(filename: str) -> None: def append_hci_to_bt_snoop_file(filename: str, direction: int, data: str, timestamp_us: int) -> None: if os.path.exists(filename): - print(f'Appending to existing file: {filename}') + log.print(f'Appending to existing file: {escape(filename)}') else: - print(f'Creating new file: {filename}') + log.print(f'Creating new file: {escape(filename)}') create_new_bt_snoop_file(filename) data_bytes = bytearray.fromhex(data) with open(filename, 'ab') as f: @@ -39,8 +42,7 @@ def log_data_clean(data: str) -> str: def parse_log(input_path: str, output_tag: str, has_timestamp: bool = True) -> None: if not os.path.exists(input_path): - print(f"Error: The file '{input_path}' does not exist.") - return + log.die(f"The file '{escape(input_path)}' does not exist.") output_dir = './parsed_logs' os.makedirs(output_dir, exist_ok=True) output_file = os.path.join(output_dir, f'parsed_log_{output_tag}.btsnoop.log') @@ -112,28 +114,38 @@ def parse_log(input_path: str, output_tag: str, has_timestamp: bool = True) -> N append_hci_to_bt_snoop_file(output_file, direction, hci_data, timestamp_us) parsed_num += 1 except Exception as e: - print(f'Exception: {e}') + log.warn(f'Exception: {escape(str(e))}') if parsed_num > 0: - print( - f'Parsing completed, parsed_num {parsed_num}, all_line_num {all_line_num}.\nOutput saved to: {output_file}' + log.print( + f'Parsing completed, parsed_num {parsed_num}, all_line_num {all_line_num}.\n' + f'Output saved to: {escape(output_file)}' ) else: - print('No data could be parsed.') + log.warn('No data could be parsed.') + + +@click.command( + context_settings={'help_option_names': ['-h', '--help']}, + help='Parse Bluetooth HCI logs and convert them to BTSnoop format.', +) +@click.option('-p', '--path', required=True, help='Path to the input log file') +@click.option('-o', '--output', required=True, help='Name tag for the output file') +@click.option( + '--has-ts', + is_flag=True, + default=False, + help='Set this if the input file has timestamp information as part of packets (default: False)', +) +def cli(path: str, output: str, has_ts: bool) -> None: + parse_log(path, output, has_timestamp=has_ts) def main() -> None: - parser = argparse.ArgumentParser(description='Log Parsing Tool') - parser.add_argument('-p', '--path', required=True, help='Path to the input log file') - parser.add_argument('-o', '--output', required=True, help='Name tag for the output file') - parser.add_argument( - '--has-ts', - action='store_true', - default=False, - help='Set this if the input file has timestamp information as part of packets (default: False)', - ) - args = parser.parse_args() - parse_log(args.path, args.output, has_timestamp=args.has_ts) + cli() if __name__ == '__main__': + from esp_pylib.excepthook import install_exception_reporting + + install_exception_reporting() main()