Files
zhouli 2c40c19202 fix(basic-demo): add esp32-s3 breadboard support
- add patches for board manager, esp-idf, usb-uac
2026-04-18 18:56:23 +08:00

159 lines
5.3 KiB
Python
Executable File

#!/usr/bin/env python3
#
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
import argparse
import sys
from pathlib import Path
UAC_FILE = 'managed_components/espressif__usb_host_uac/uac_host.c'
C_FILE = 'managed_components/espressif__esp_board_manager/src/esp_board_device.c'
H_FILE = 'managed_components/espressif__esp_board_manager/include/esp_board_device.h'
GEN_BOARD_DEVICE_CONFIG_FILE = 'components/gen_bmgr_codes/gen_board_device_config.c'
UPDATE_CONFIG_FUNCTION = """esp_err_t esp_board_device_update_config(const char *name, const void *config)
{
ESP_BOARD_RETURN_ON_FALSE(name && config, ESP_BOARD_ERR_DEVICE_INVALID_ARG, TAG, "Invalid args");
/* Find device descriptor */
esp_board_device_desc_t *desc = (esp_board_device_desc_t*)esp_board_find_device_desc(name);
ESP_BOARD_RETURN_ON_DEVICE_NOT_FOUND(desc, name, TAG, "Device descriptor %s not found", name);
if (!desc->cfg) {
ESP_LOGW(TAG, "Device %s has no config, force to update", name);
}
desc->cfg = config;
ESP_LOGI(TAG, "Device %s config updated: %p (size: %d)", name, desc->cfg, desc->cfg_size);
return ESP_OK;
}
"""
UPDATE_CONFIG_DECLARATION = 'esp_err_t esp_board_device_update_config(const char *name, const void *config);\n'
UAC_PSRAM_LINE = ' || esp_ptr_in_psram(ptr)\n'
UAC_PSRAM_COMMENTED_LINE = ' // || esp_ptr_in_psram(ptr)\n'
BOARD_DEVICE_ARRAY_CONST_LINE = 'const esp_board_device_desc_t g_esp_board_devices'
BOARD_DEVICE_ARRAY_MUTABLE_LINE = 'esp_board_device_desc_t g_esp_board_devices'
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description='Insert esp_board_device_update_config() into esp_board_manager sources.'
)
parser.add_argument(
'--project-dir',
default='.',
help='Path to the project directory. Defaults to the current directory.',
)
return parser.parse_args()
def fail(message: str) -> None:
raise RuntimeError(message)
def ensure_contains(path: Path, needle: str) -> str:
try:
content = path.read_text(encoding='utf-8')
except FileNotFoundError as exc:
raise RuntimeError(f'Missing file: {path}') from exc
if needle not in content:
fail(f'Expected content not found in {path}: {needle}')
return content
def write_if_changed(path: Path, original: str, updated: str) -> bool:
if updated == original:
return False
path.write_text(updated, encoding='utf-8')
return True
def patch_c_file(path: Path) -> bool:
content = ensure_contains(path, 'esp_board_device_get_handle')
if 'esp_board_device_update_config(' in content:
return False
anchor = """esp_err_t esp_board_device_get_config(const char *name, void **config)
"""
if anchor not in content:
fail(f'Anchor not found in {path}: {anchor.strip()}')
updated = content.replace(anchor, f'{UPDATE_CONFIG_FUNCTION}\n{anchor}', 1)
return write_if_changed(path, content, updated)
def patch_h_file(path: Path) -> bool:
content = ensure_contains(path, 'esp_board_device_get_config')
if 'esp_board_device_update_config(' in content:
return False
anchor = 'esp_err_t esp_board_device_get_config(const char *name, void **config);\n'
if anchor not in content:
fail(f'Anchor not found in {path}: {anchor.strip()}')
updated = content.replace(anchor, f'{anchor}\n{UPDATE_CONFIG_DECLARATION}', 1)
return write_if_changed(path, content, updated)
def patch_uac_file(path: Path) -> bool:
if path.exists() is False:
print(f'File {path} does not exist, skipping patch.')
return False
content = ensure_contains(path, 'ptr_is_writable')
if UAC_PSRAM_COMMENTED_LINE in content:
return False
if UAC_PSRAM_LINE not in content:
fail(f'Target line not found in {path}: {UAC_PSRAM_LINE.strip()}')
updated = content.replace(UAC_PSRAM_LINE, UAC_PSRAM_COMMENTED_LINE, 1)
return write_if_changed(path, content, updated)
def patch_gen_board_device_config_file(path: Path) -> bool:
content = ensure_contains(path, 'g_esp_board_devices')
if BOARD_DEVICE_ARRAY_CONST_LINE not in content:
return False
updated = content.replace(BOARD_DEVICE_ARRAY_CONST_LINE, BOARD_DEVICE_ARRAY_MUTABLE_LINE, 1)
return write_if_changed(path, content, updated)
def main() -> int:
args = parse_args()
project_dir = Path(args.project_dir).resolve()
c_path = project_dir / C_FILE
h_path = project_dir / H_FILE
uac_path = project_dir / UAC_FILE
gen_board_device_config_path = project_dir / GEN_BOARD_DEVICE_CONFIG_FILE
changed_files: list[Path] = []
if patch_c_file(c_path):
changed_files.append(c_path)
if patch_h_file(h_path):
changed_files.append(h_path)
if patch_uac_file(uac_path):
changed_files.append(uac_path)
if patch_gen_board_device_config_file(gen_board_device_config_path):
changed_files.append(gen_board_device_config_path)
if not changed_files:
print('No changes needed.')
return 0
for path in changed_files:
print(f'Updated {path.relative_to(project_dir)}')
return 0
if __name__ == '__main__':
try:
raise SystemExit(main())
except RuntimeError as exc:
print(f'Error: {exc}', file=sys.stderr)
raise SystemExit(1)