diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f22405fd..685c2d14 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,7 +83,7 @@ jobs: fi build: - name: Build ${{ matrix.name }} + name: Build ${{ matrix.full_name }} needs: prepare if: ${{ needs.prepare.outputs.variants != '[]' }} strategy: @@ -106,6 +106,6 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: xiaozhi_${{ matrix.name }}_${{ github.sha }}.bin + name: xiaozhi_${{ matrix.full_name }}_${{ github.sha }} path: build/merged-binary.bin if-no-files-found: error diff --git a/CMakeLists.txt b/CMakeLists.txt index a32048cb..871bd88b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,5 +9,5 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake) # "Trim" the build. Include the minimal set of components, main, and anything it depends on. idf_build_set_property(MINIMAL_BUILD ON) -set(PROJECT_VER "2.2.2") +set(PROJECT_VER "2.2.3") project(xiaozhi) diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root deleted file mode 120000 index 945c9b46..00000000 --- a/_codeql_detected_source_root +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 840a4ddc..249db54f 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -705,17 +705,17 @@ elseif(CONFIG_BOARD_TYPE_HU_087) set(BUILTIN_ICON_FONT font_awesome_14_1) endif() -file(GLOB BOARD_SOURCES if(MANUFACTURER) - ${CMAKE_CURRENT_SOURCE_DIR}/boards/${MANUFACTURER}/${BOARD_TYPE}/*.cc - ${CMAKE_CURRENT_SOURCE_DIR}/boards/${MANUFACTURER}/${BOARD_TYPE}/*.c -else - ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc - ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.c + file(GLOB BOARD_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/boards/${MANUFACTURER}/${BOARD_TYPE}/*.cc + ${CMAKE_CURRENT_SOURCE_DIR}/boards/${MANUFACTURER}/${BOARD_TYPE}/*.c + ) +else() + file(GLOB BOARD_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc + ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.c + ) endif() - - -) list(APPEND SOURCES ${BOARD_SOURCES}) # Select audio processor according to Kconfig diff --git a/main/boards/lceda-course-examples/eda-robot-pro/config.json b/main/boards/lceda-course-examples/eda-robot-pro/config.json index 9fa7d89d..98cd49b7 100644 --- a/main/boards/lceda-course-examples/eda-robot-pro/config.json +++ b/main/boards/lceda-course-examples/eda-robot-pro/config.json @@ -1,4 +1,5 @@ { + "manufacturer": "lceda-course-examples", "target": "esp32s3", "builds": [ { diff --git a/main/boards/lceda-course-examples/eda-super-bear/config.json b/main/boards/lceda-course-examples/eda-super-bear/config.json index 9a420da7..750db8a7 100644 --- a/main/boards/lceda-course-examples/eda-super-bear/config.json +++ b/main/boards/lceda-course-examples/eda-super-bear/config.json @@ -1,4 +1,5 @@ { + "manufacturer": "lceda-course-examples", "target": "esp32s3", "builds": [ { diff --git a/main/boards/lceda-course-examples/eda-tv-pro/config.json b/main/boards/lceda-course-examples/eda-tv-pro/config.json index e8443696..431867f6 100644 --- a/main/boards/lceda-course-examples/eda-tv-pro/config.json +++ b/main/boards/lceda-course-examples/eda-tv-pro/config.json @@ -1,4 +1,5 @@ { + "manufacturer": "lceda-course-examples", "target": "esp32s3", "builds": [ { diff --git a/main/boards/waveshare/esp32-p4-nano/esp32-p4-nano.cc b/main/boards/waveshare/esp32-p4-nano/esp32-p4-nano.cc index c100922e..97449393 100644 --- a/main/boards/waveshare/esp32-p4-nano/esp32-p4-nano.cc +++ b/main/boards/waveshare/esp32-p4-nano/esp32-p4-nano.cc @@ -15,6 +15,7 @@ #include "esp_lcd_mipi_dsi.h" #include "esp_lcd_jd9365.h" +#include "lcd_init_cmds.h" #include "config.h" #include diff --git a/main/main.cc b/main/main.cc index 0d4e5e1d..f7e8bc3b 100755 --- a/main/main.cc +++ b/main/main.cc @@ -8,7 +8,6 @@ #include #include "application.h" -#include "system_info.h" #define TAG "main" diff --git a/scripts/download_github_runs.py b/scripts/download_github_runs.py index cd812179..b98c8f8c 100644 --- a/scripts/download_github_runs.py +++ b/scripts/download_github_runs.py @@ -126,11 +126,14 @@ def rename_artifact(original_name: str, version: str) -> str: - Remove "xiaozhi_" prefix - Remove hash suffix (underscore followed by hex string) - Add version prefix (e.g., "v2.0.4_") - - Change extension to .zip + - Add .zip extension - Example: - xiaozhi_atk-dnesp32s3-box0_43ef2f4e7f0957dc62ec7d628ac2819d226127b8.bin + Examples: + xiaozhi_atk-dnesp32s3-box0_43ef2f4e7f0957dc62ec7d628ac2819d226127b8 -> v2.0.4_atk-dnesp32s3-box0.zip + + xiaozhi_waveshare-esp32-p4-nano-10.1-a_43ef2f4e7f0957dc62ec7d628ac2819d226127b8 + -> v2.0.4_waveshare-esp32-p4-nano-10.1-a.zip Args: original_name: Original artifact name diff --git a/scripts/release.py b/scripts/release.py index dc8de7cb..19894202 100755 --- a/scripts/release.py +++ b/scripts/release.py @@ -74,9 +74,12 @@ def _collect_variants(config_filename: str = "config.json") -> list[dict[str, st """Traverse all boards under main/boards, collect variant information. Return example: - [{"board": "bread-compact-ml307", "name": "bread-compact-ml307"}, ...] + [{"board": "bread-compact-ml307", "name": "bread-compact-ml307", "full_name": "bread-compact-ml307"}, ...] + [{"board": "waveshare/esp32-p4-nano", "name": "esp32-p4-nano-10.1-a", "full_name": "waveshare-esp32-p4-nano-10.1-a"}, ...] """ variants: list[dict[str, str]] = [] + errors: list[str] = [] + for cfg_path in _BOARDS_DIR.rglob(config_filename): board_dir = cfg_path.parent if board_dir.name == "common": @@ -87,41 +90,74 @@ def _collect_variants(config_filename: str = "config.json") -> list[dict[str, st with cfg_path.open() as f: cfg = json.load(f) + manufacturer = _get_manufacturer(cfg) + + # Check manufacturer consistency with directory structure + if "/" in board: + # Board is in a subdirectory (e.g., waveshare/esp32-p4-nano) + expected_manufacturer = board.split("/")[0] + if not manufacturer: + errors.append( + f"{cfg_path}: Board is in '{expected_manufacturer}/' subdirectory, " + f"but config.json is missing \"manufacturer\": \"{expected_manufacturer}\"" + ) + elif manufacturer != expected_manufacturer: + errors.append( + f"{cfg_path}: manufacturer mismatch, " + f"directory is '{expected_manufacturer}/' but config.json has \"{manufacturer}\"" + ) + else: + # Board is directly under boards/ directory + if manufacturer: + errors.append( + f"{cfg_path}: Board is not in a manufacturer subdirectory, " + f"but config.json defines manufacturer \"{manufacturer}\", " + f"please move board to main/boards/{manufacturer}/{board}/" + ) + for build in cfg.get("builds", []): name = build["name"] + full_name = f"{manufacturer}-{name}" if manufacturer else name variants.append({ "board": board, - "name": name + "name": name, + "full_name": full_name }) except Exception as e: - print(f"[ERROR] 解析 {cfg_path} 失败: {e}", file=sys.stderr) + print(f"[ERROR] Failed to parse {cfg_path}: {e}", file=sys.stderr) + + # Report all errors at once + if errors: + print("\n[ERROR] Found manufacturer configuration issues:", file=sys.stderr) + for err in errors: + print(f" - {err}", file=sys.stderr) + print(file=sys.stderr) + sys.exit(1) return variants -def _parse_board_config_map() -> dict[str, str]: - """Build the mapping of CONFIG_BOARD_TYPE_xxx and board_type from main/CMakeLists.txt""" - cmake_file = Path("main/CMakeLists.txt") - mapping: dict[str, str] = {} - lines = cmake_file.read_text(encoding="utf-8").splitlines() - for idx, line in enumerate(lines): - if "if(CONFIG_BOARD_TYPE_" in line: - config_name = line.strip().split("if(")[1].split(")")[0] - if idx + 1 < len(lines): - next_line = lines[idx + 1].strip() - if next_line.startswith("set(BOARD_TYPE"): - board_type = next_line.split('"')[1] - mapping[config_name] = board_type - return mapping - - def _find_board_config(board_type: str) -> Optional[str]: - """Find the corresponding CONFIG_BOARD_TYPE_xxx for the given board_type""" - for config, b_type in _parse_board_config_map().items(): - if b_type == board_type: - return config + """Find the corresponding CONFIG_BOARD_TYPE_xxx for the given board_type + + Search backwards from 'set(BOARD_TYPE "xxx")' to find the nearest if(CONFIG_BOARD_TYPE_). + """ + board_leaf = board_type.split("/")[-1] + pattern = f'set(BOARD_TYPE "{board_leaf}")' + + cmake_file = Path("main/CMakeLists.txt") + lines = cmake_file.read_text(encoding="utf-8").splitlines() + + for idx, line in enumerate(lines): + if pattern in line: + # Found the BOARD_TYPE line, search backwards for the config + for back_idx in range(idx - 1, -1, -1): + back_line = lines[back_idx] + if "if(CONFIG_BOARD_TYPE_" in back_line: + return back_line.strip().split("if(")[1].split(")")[0] + break return None @@ -190,7 +226,7 @@ def release(board_type: str, config_filename: str = "config.json", *, filter_nam """ cfg_path = _BOARDS_DIR / Path(board_type) / config_filename if not cfg_path.exists(): - print(f"[WARN] {cfg_path} 不存在,跳过 {board_type}") + print(f"[WARN] {cfg_path} does not exist, skipping {board_type}") return project_version = get_project_version() @@ -205,7 +241,7 @@ def release(board_type: str, config_filename: str = "config.json", *, filter_nam if filter_name: builds = [b for b in builds if b["name"] == filter_name] if not builds: - print(f"[ERROR] 未在 {board_type} 的 {config_filename} 中找到变体 {filter_name}", file=sys.stderr) + print(f"[ERROR] Variant {filter_name} not found in {board_type}'s {config_filename}", file=sys.stderr) sys.exit(1) for build in builds: @@ -213,12 +249,12 @@ def release(board_type: str, config_filename: str = "config.json", *, filter_nam board_leaf = board_type.split("/")[-1] if board_leaf not in name: - raise ValueError(f"build.name {name} 必须包含 {board_leaf}") + raise ValueError(f"build.name {name} must contain {board_leaf}") final_name = f"{manufacturer}-{name}" if manufacturer else name output_path = Path("releases") / f"v{project_version}_{final_name}.zip" if output_path.exists(): - print(f"跳过 {final_name} 因为 {output_path} 已存在") + print(f"Skipping {final_name} because {output_path} already exists") continue # Process sdkconfig_append @@ -265,11 +301,11 @@ def release(board_type: str, config_filename: str = "config.json", *, filter_nam if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument("board", nargs="?", default=None, help="板子类型或 all") - parser.add_argument("-c", "--config", default="config.json", help="指定 config 文件名,默认 config.json") - parser.add_argument("--list-boards", action="store_true", help="列出所有支持的 board 及变体列表") - parser.add_argument("--json", action="store_true", help="配合 --list-boards,JSON 格式输出") - parser.add_argument("--name", help="指定变体名称,仅编译匹配的变体(使用原始name,不带厂商前缀)") + parser.add_argument("board", nargs="?", default=None, help="Board type or 'all'") + parser.add_argument("-c", "--config", default="config.json", help="Config filename (default: config.json)") + parser.add_argument("--list-boards", action="store_true", help="List all supported boards and variants") + parser.add_argument("--json", action="store_true", help="Output in JSON format (use with --list-boards)") + parser.add_argument("--name", help="Variant name to compile (original name without manufacturer prefix)") args = parser.parse_args() @@ -288,7 +324,7 @@ if __name__ == "__main__": merge_bin() curr_board_type = get_board_type_from_compile_commands() if curr_board_type is None: - print("未能从 compile_commands.json 解析 board_type", file=sys.stderr) + print("Failed to parse board_type from compile_commands.json", file=sys.stderr) sys.exit(1) project_ver = get_project_version() zip_bin(curr_board_type, project_ver) @@ -300,7 +336,7 @@ if __name__ == "__main__": # Check board_type in CMakeLists if board_type_input != "all" and not _board_type_exists(board_type_input): - print(f"[ERROR] main/CMakeLists.txt 中未找到 board_type {board_type_input}", file=sys.stderr) + print(f"[ERROR] board_type {board_type_input} not found in main/CMakeLists.txt", file=sys.stderr) sys.exit(1) variants_all = _collect_variants(config_filename=args.config) @@ -314,10 +350,10 @@ if __name__ == "__main__": for bt in sorted(target_board_types): if not _board_type_exists(bt): - print(f"[ERROR] main/CMakeLists.txt 中未找到 board_type {bt}", file=sys.stderr) + print(f"[ERROR] board_type {bt} not found in main/CMakeLists.txt", file=sys.stderr) sys.exit(1) cfg_path = _BOARDS_DIR / bt / args.config if bt == board_type_input and not cfg_path.exists(): - print(f"开发板 {bt} 未定义 {args.config} 配置文件,跳过") + print(f"Board {bt} has no {args.config} config file, skipping") sys.exit(0) release(bt, config_filename=args.config, filter_name=name_filter if bt == board_type_input else None)