mirror of
https://github.com/MrUnknownDE/OpenIris-ESPIDF.git
synced 2026-05-02 20:36:04 +02:00
cleaning up board config and switch tool
This commit is contained in:
@@ -50,16 +50,23 @@ After this, you’re ready for the Quick start below.
|
|||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
### 1) Pick your board (loads the default configuration)
|
### 1) Pick your board (loads the default configuration)
|
||||||
|
Boards are auto‑discovered from the `boards/` directory. First list them, then pick one:
|
||||||
|
|
||||||
Windows (cmd):
|
Windows (cmd):
|
||||||
```cmd
|
```cmd
|
||||||
python .\tools\switchBoardType.py --board xiao-esp32s3 --diff
|
python .\tools\switchBoardType.py --list
|
||||||
|
python .\tools\switchBoardType.py --board seed_studio_xiao_esp32s3 --diff
|
||||||
```
|
```
|
||||||
macOS/Linux (bash):
|
macOS/Linux (bash):
|
||||||
```bash
|
```bash
|
||||||
python3 ./tools/switchBoardType.py --board xiao-esp32s3 --diff
|
python3 ./tools/switchBoardType.py --list
|
||||||
|
python3 ./tools/switchBoardType.py --board seed_studio_xiao_esp32s3 --diff
|
||||||
```
|
```
|
||||||
- Set `--board` to your target board
|
Notes:
|
||||||
- `--diff` shows what changed in the config
|
- Use `--list` to see all detected board keys.
|
||||||
|
- Board key = relative path under `boards/` with `/` replaced by `_` (and duplicate tail segments collapsed, e.g. `project_babble/project_babble` -> `project_babble`).
|
||||||
|
- `--diff` shows what will change vs the current `sdkconfig`.
|
||||||
|
- You can also pass partial or path‑like inputs (e.g. `facefocusvr/eye_L`), the tool normalizes them.
|
||||||
|
|
||||||
### 2) Build & flash
|
### 2) Build & flash
|
||||||
- Set the target (e.g., ESP32‑S3).
|
- Set the target (e.g., ESP32‑S3).
|
||||||
@@ -118,6 +125,17 @@ If you want to dig deeper: commands are mapped via the `CommandManager` under `c
|
|||||||
- UVC doesn’t appear on the host?
|
- UVC doesn’t appear on the host?
|
||||||
- Switch mode to UVC via CLI tool, replug USB and wait 20s.
|
- Switch mode to UVC via CLI tool, replug USB and wait 20s.
|
||||||
|
|
||||||
|
### Adding a new board configuration
|
||||||
|
1. Create a new config file under `boards/` (you can nest folders): for example `boards/my_family/my_variant`.
|
||||||
|
2. Populate it with only the `CONFIG_...` lines that differ from the shared defaults. Shared baseline lives in `boards/sdkconfig.base_defaults` and is always merged first.
|
||||||
|
3. The board key the script accepts will be the relative path with `/` turned into `_` (example: `boards/my_family/my_variant` -> `my_family_my_variant`).
|
||||||
|
4. Run `python tools/switchBoardType.py --list` to verify it’s detected, then switch using `-b my_family_my_variant`.
|
||||||
|
5. If you accidentally create two files that collapse to the same key the last one found wins—rename to keep keys unique.
|
||||||
|
|
||||||
|
Tips:
|
||||||
|
- Use `--diff` after adding a board to sanity‑check only the intended keys change.
|
||||||
|
- For Wi‑Fi overrides on first flash: add none—pass `--ssid` / `--password` when switching if needed.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Feedback, issues, and PRs are welcome.
|
Feedback, issues, and PRs are welcome.
|
||||||
@@ -67,7 +67,7 @@ CONFIG_MONITORING_LED_GAIN=11
|
|||||||
CONFIG_MONITORING_LED_SHUNT_MILLIOHM=22000
|
CONFIG_MONITORING_LED_SHUNT_MILLIOHM=22000
|
||||||
CONFIG_MONITORING_LED_SAMPLES=10
|
CONFIG_MONITORING_LED_SAMPLES=10
|
||||||
CONFIG_MONITORING_LED_INTERVAL_MS=500
|
CONFIG_MONITORING_LED_INTERVAL_MS=500
|
||||||
CONFIG_GENERAL_WHO_AM_I="facefocusvr_eye"
|
CONFIG_GENERAL_BOARD="facefocusvr_eye"
|
||||||
# CONFIG_GENERAL_ENABLE_WIRELESS is not set
|
# CONFIG_GENERAL_ENABLE_WIRELESS is not set
|
||||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80=y
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80=y
|
||||||
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 is not set
|
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 is not set
|
||||||
@@ -14,7 +14,7 @@ CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
|
|||||||
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
|
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
|
||||||
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
|
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
|
||||||
# Camera sensor pinout configuration
|
# Camera sensor pinout configuration
|
||||||
CONFIG_CAMERA_MODULE_NAME="ESP32S3_XIAO_SENSE"
|
CONFIG_CAMERA_MODULE_NAME="FaceFocusVR_Face"
|
||||||
CONFIG_PWDN_GPIO_NUM=-1
|
CONFIG_PWDN_GPIO_NUM=-1
|
||||||
CONFIG_RESET_GPIO_NUM=-1
|
CONFIG_RESET_GPIO_NUM=-1
|
||||||
CONFIG_XCLK_GPIO_NUM=10
|
CONFIG_XCLK_GPIO_NUM=10
|
||||||
@@ -54,9 +54,26 @@ CONFIG_SPIRAM_SPEED_80M=y
|
|||||||
# CONFIG_SPIRAM_SPEED_120M is not set
|
# CONFIG_SPIRAM_SPEED_120M is not set
|
||||||
CONFIG_SPIRAM_SPEED=80
|
CONFIG_SPIRAM_SPEED=80
|
||||||
CONFIG_SPIRAM_SPEED_80M=y
|
CONFIG_SPIRAM_SPEED_80M=y
|
||||||
# CONFIG_LED_EXTERNAL_CONTROL is not set
|
CONFIG_LED_EXTERNAL_CONTROL=y
|
||||||
|
CONFIG_LED_EXTERNAL_GPIO=9
|
||||||
|
CONFIG_LED_EXTERNAL_PWM_FREQ=20000
|
||||||
|
CONFIG_LED_EXTERNAL_PWM_DUTY_CYCLE=50
|
||||||
CONFIG_CAMERA_USB_XCLK_FREQ=23000000
|
CONFIG_CAMERA_USB_XCLK_FREQ=23000000
|
||||||
CONFIG_GENERAL_INCLUDE_UVC_MODE=y
|
CONFIG_GENERAL_INCLUDE_UVC_MODE=y
|
||||||
# CONFIG_START_IN_UVC_MODE is not set
|
CONFIG_START_IN_UVC_MODE=y
|
||||||
# CONFIG_MONITORING_LED_CURRENT is not set
|
CONFIG_MONITORING_LED_CURRENT=y
|
||||||
CONFIG_GENERAL_WHO_AM_I="xiao_esp32s3"
|
CONFIG_MONITORING_LED_ADC_GPIO=3
|
||||||
|
CONFIG_MONITORING_LED_GAIN=11
|
||||||
|
CONFIG_MONITORING_LED_SHUNT_MILLIOHM=22000
|
||||||
|
CONFIG_MONITORING_LED_SAMPLES=10
|
||||||
|
CONFIG_MONITORING_LED_INTERVAL_MS=500
|
||||||
|
CONFIG_GENERAL_BOARD="facefocusvr_eye"
|
||||||
|
# CONFIG_GENERAL_ENABLE_WIRELESS is not set
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80=y
|
||||||
|
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 is not set
|
||||||
|
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240 is not set
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=80
|
||||||
|
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80=y
|
||||||
|
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160 is not set
|
||||||
|
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240 is not set
|
||||||
|
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=80
|
||||||
@@ -67,7 +67,7 @@ CONFIG_MONITORING_LED_GAIN=11
|
|||||||
CONFIG_MONITORING_LED_SHUNT_MILLIOHM=22000
|
CONFIG_MONITORING_LED_SHUNT_MILLIOHM=22000
|
||||||
CONFIG_MONITORING_LED_SAMPLES=10
|
CONFIG_MONITORING_LED_SAMPLES=10
|
||||||
CONFIG_MONITORING_LED_INTERVAL_MS=500
|
CONFIG_MONITORING_LED_INTERVAL_MS=500
|
||||||
CONFIG_GENERAL_WHO_AM_I="facefocusvr_face"
|
CONFIG_GENERAL_BOARD="facefocusvr_face"
|
||||||
# CONFIG_GENERAL_ENABLE_WIRELESS is not set
|
# CONFIG_GENERAL_ENABLE_WIRELESS is not set
|
||||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80=y
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80=y
|
||||||
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 is not set
|
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 is not set
|
||||||
@@ -54,5 +54,5 @@ CONFIG_CAMERA_USB_XCLK_FREQ=23000000
|
|||||||
CONFIG_GENERAL_INCLUDE_UVC_MODE=y
|
CONFIG_GENERAL_INCLUDE_UVC_MODE=y
|
||||||
# CONFIG_START_IN_UVC_MODE is not set
|
# CONFIG_START_IN_UVC_MODE is not set
|
||||||
# CONFIG_MONITORING_LED_CURRENT is not set
|
# CONFIG_MONITORING_LED_CURRENT is not set
|
||||||
CONFIG_GENERAL_WHO_AM_I="project_babble"
|
CONFIG_GENERAL_BOARD="project_babble"
|
||||||
CONFIG_GENERAL_ENABLE_WIRELESS=y
|
CONFIG_GENERAL_ENABLE_WIRELESS=y
|
||||||
@@ -573,7 +573,7 @@ CONFIG_ENV_GPIO_OUT_RANGE_MAX=48
|
|||||||
# CONFIG_GENERAL_INCLUDE_UVC_MODE is not set
|
# CONFIG_GENERAL_INCLUDE_UVC_MODE is not set
|
||||||
# CONFIG_START_IN_UVC_MODE is not set
|
# CONFIG_START_IN_UVC_MODE is not set
|
||||||
# CONFIG_GENERAL_STARTUP_DELAY is not set
|
# CONFIG_GENERAL_STARTUP_DELAY is not set
|
||||||
CONFIG_GENERAL_Version="0.0.1"
|
CONFIG_GENERAL_VERSION="0.0.1"
|
||||||
# end of OpenIris: General Configuration
|
# end of OpenIris: General Configuration
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -59,5 +59,5 @@ CONFIG_CAMERA_USB_XCLK_FREQ=23000000
|
|||||||
CONFIG_GENERAL_INCLUDE_UVC_MODE=y
|
CONFIG_GENERAL_INCLUDE_UVC_MODE=y
|
||||||
# CONFIG_START_IN_UVC_MODE is not set
|
# CONFIG_START_IN_UVC_MODE is not set
|
||||||
# CONFIG_MONITORING_LED_CURRENT is not set
|
# CONFIG_MONITORING_LED_CURRENT is not set
|
||||||
CONFIG_GENERAL_WHO_AM_I="xiao_esp32s3"
|
CONFIG_GENERAL_BOARD="xiao_esp32s3"
|
||||||
CONFIG_GENERAL_ENABLE_WIRELESS=y
|
CONFIG_GENERAL_ENABLE_WIRELESS=y
|
||||||
@@ -251,8 +251,8 @@ CommandResult getLEDCurrentCommand(std::shared_ptr<DependencyRegistry> registry)
|
|||||||
|
|
||||||
CommandResult getInfoCommand(std::shared_ptr<DependencyRegistry> /*registry*/)
|
CommandResult getInfoCommand(std::shared_ptr<DependencyRegistry> /*registry*/)
|
||||||
{
|
{
|
||||||
const char* who = CONFIG_GENERAL_WHO_AM_I;
|
const char* who = CONFIG_GENERAL_BOARD;
|
||||||
const char* ver = CONFIG_GENERAL_Version;
|
const char* ver = CONFIG_GENERAL_VERSION;
|
||||||
// Ensure non-null strings
|
// Ensure non-null strings
|
||||||
if (!who) who = "";
|
if (!who) who = "";
|
||||||
if (!ver) ver = "";
|
if (!ver) ver = "";
|
||||||
|
|||||||
+22
-15
@@ -7,28 +7,35 @@ endmenu
|
|||||||
menu "OpenIris: General Configuration"
|
menu "OpenIris: General Configuration"
|
||||||
|
|
||||||
config START_IN_UVC_MODE
|
config START_IN_UVC_MODE
|
||||||
bool "Start in UVC Mode"
|
bool "Default initial streaming mode = UVC"
|
||||||
default false
|
default false
|
||||||
help
|
help
|
||||||
Enables UVC (wired) support in the firmware by default.
|
Sets the power‑on default streaming mode (before any user preference is stored).
|
||||||
To be used when a board is designed to be used primarily with wired headsets.
|
If enabled AND UVC support is compiled in (GENERAL_INCLUDE_UVC_MODE), the device
|
||||||
When enabled, the default device streaming mode will be UVC unless overridden by a
|
will default to UVC mode on first boot. If disabled it defaults to SETUP mode,
|
||||||
saved preference. When disabled, the default mode is AUTO.
|
waiting for a user choice or commands. This option does NOT compile UVC support in;
|
||||||
|
it only changes the initial preference used when no saved mode exists.
|
||||||
|
|
||||||
config GENERAL_INCLUDE_UVC_MODE
|
config GENERAL_INCLUDE_UVC_MODE
|
||||||
bool "Wired mode"
|
bool "Include UVC (USB Video Class) support"
|
||||||
default false
|
default false
|
||||||
help
|
help
|
||||||
Enables UVC (wired) support in the firmware. When enabled, the
|
Compiles in UVC (USB Video Class) streaming support (camera + CDC bridge).
|
||||||
default device streaming mode will be UVC unless overridden by a
|
Disable this on boards that are Wi‑Fi only or where USB bandwidth / memory
|
||||||
saved preference. When disabled, the default mode is AUTO.
|
should be conserved. If disabled any attempt to switch to UVC mode will log
|
||||||
|
an error and fall back to Wi‑Fi (if wireless is enabled). Combine with
|
||||||
|
START_IN_UVC_MODE only when the hardware supports UVC.
|
||||||
|
|
||||||
config GENERAL_STARTUP_DELAY
|
config GENERAL_STARTUP_DELAY
|
||||||
int "UVC delay (s)"
|
int "Setup grace period (s)"
|
||||||
default 30
|
default 30
|
||||||
range 10 10000
|
range 10 10000
|
||||||
help
|
help
|
||||||
Delay in seconds before the ESP reports itself as a UVC device.
|
Number of seconds the device remains in SETUP / heartbeat mode on boot (when the
|
||||||
|
current streaming mode resolves to SETUP) before automatically launching the
|
||||||
|
selected streaming backend (UVC or Wi‑Fi). During this window host commands can
|
||||||
|
change mode or other settings. After the timer expires, streaming starts
|
||||||
|
automatically unless a command was received or startup was paused.
|
||||||
|
|
||||||
config GENERAL_ENABLE_WIRELESS
|
config GENERAL_ENABLE_WIRELESS
|
||||||
bool "Enable wireless (WiFi/Bluetooth)"
|
bool "Enable wireless (WiFi/Bluetooth)"
|
||||||
@@ -38,13 +45,13 @@ menu "OpenIris: General Configuration"
|
|||||||
and any Bluetooth memory (if present on the SoC) should be left released. This can
|
and any Bluetooth memory (if present on the SoC) should be left released. This can
|
||||||
reduce power consumption when operating solely in UVC mode or without networking.
|
reduce power consumption when operating solely in UVC mode or without networking.
|
||||||
|
|
||||||
config GENERAL_WHO_AM_I
|
config GENERAL_BOARD
|
||||||
string "Who am I (device identifier)"
|
string "Board / device identifier"
|
||||||
default "OpenIris"
|
default "OpenIris"
|
||||||
help
|
help
|
||||||
A human-readable product or device identifier exposed via the get_info command.
|
A human-readable board or device identifier exposed via the get_info command.
|
||||||
|
|
||||||
config GENERAL_Version
|
config GENERAL_VERSION
|
||||||
string "Firmware version"
|
string "Firmware version"
|
||||||
default "0.0.0"
|
default "0.0.0"
|
||||||
help
|
help
|
||||||
|
|||||||
-2532
File diff suppressed because it is too large
Load Diff
+151
-47
@@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
|
from typing import Dict, Optional, List
|
||||||
|
|
||||||
HEADER_COLOR = "\033[95m"
|
HEADER_COLOR = "\033[95m"
|
||||||
OKGREEN = '\033[92m'
|
OKGREEN = '\033[92m'
|
||||||
@@ -7,38 +8,125 @@ WARNING = '\033[93m'
|
|||||||
OKBLUE = '\033[94m'
|
OKBLUE = '\033[94m'
|
||||||
ENDC = '\033[0m'
|
ENDC = '\033[0m'
|
||||||
|
|
||||||
sdkconfig_defaults = "sdkconfig.base_defaults"
|
BOARDS_DIR_NAME = "boards"
|
||||||
supported_boards = [
|
SDKCONFIG_DEFAULTS_FILENAME = "sdkconfig.base_defaults"
|
||||||
"xiao-esp32s3",
|
|
||||||
"project_babble",
|
|
||||||
"facefocusvr_face",
|
|
||||||
"facefocusvr_eye"
|
|
||||||
]
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("-b", "--board", help="Board to switch to", choices=supported_boards)
|
|
||||||
parser.add_argument("--dry-run", help="Dry run, won't modify files", action="store_true", required=False)
|
|
||||||
parser.add_argument("--diff", help="Show the difference between base config and selected board", action="store_true", required=False)
|
|
||||||
parser.add_argument("--ssid", help="Set the SSID for the selected board", required=False, type=str, default="")
|
|
||||||
parser.add_argument("--password", help="Set the password For the provided network", required=False, type=str, default="")
|
|
||||||
parser.add_argument("--clear-wifi", help="Should we clear the wifi details", action="store_true", required=False)
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
def get_root_path() -> str:
|
def get_root_path() -> str:
|
||||||
return os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
|
return os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_boards_root() -> str:
|
||||||
|
return os.path.join(get_root_path(), BOARDS_DIR_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
def enumerate_board_configs() -> Dict[str, str]:
|
||||||
|
"""Walk the boards directory and build a mapping of board names to absolute file paths.
|
||||||
|
|
||||||
|
Naming strategy:
|
||||||
|
- Relative path from boards/ to file with path separators replaced by '_'.
|
||||||
|
- If the last two path segments are identical (e.g. project_babble/project_babble) collapse to a single segment.
|
||||||
|
- For facefocusvr eye boards we keep eye_L / eye_R suffix to distinguish configs even though WHO_AM_I is same.
|
||||||
|
"""
|
||||||
|
boards_dir = get_boards_root()
|
||||||
|
mapping: Dict[str, str] = {}
|
||||||
|
if not os.path.isdir(boards_dir):
|
||||||
|
return mapping
|
||||||
|
for root, _dirs, files in os.walk(boards_dir):
|
||||||
|
for f in files:
|
||||||
|
if f == SDKCONFIG_DEFAULTS_FILENAME:
|
||||||
|
continue
|
||||||
|
rel_path = os.path.relpath(os.path.join(root, f), boards_dir)
|
||||||
|
parts = rel_path.split(os.sep)
|
||||||
|
if len(parts) >= 2 and parts[-1] == parts[-2]: # collapse duplicate tail
|
||||||
|
parts = parts[:-1]
|
||||||
|
board_key = "_".join(parts)
|
||||||
|
mapping[board_key] = os.path.join(root, f)
|
||||||
|
return mapping
|
||||||
|
|
||||||
|
|
||||||
|
BOARD_CONFIGS = enumerate_board_configs()
|
||||||
|
|
||||||
|
def build_arg_parser() -> argparse.ArgumentParser:
|
||||||
|
p = argparse.ArgumentParser()
|
||||||
|
p.add_argument("-b", "--board", help="Board name (run with --list to see options). Flexible: accepts path-like or partial if unique.")
|
||||||
|
p.add_argument("--list", help="List discovered boards and exit", action="store_true")
|
||||||
|
p.add_argument("--dry-run", help="Dry run, won't modify files", action="store_true")
|
||||||
|
p.add_argument("--diff", help="Show the difference between base config and selected board", action="store_true")
|
||||||
|
p.add_argument("--ssid", help="Set the WiFi SSID", type=str, default="")
|
||||||
|
p.add_argument("--password", help="Set the WiFi password", type=str, default="")
|
||||||
|
p.add_argument("--clear-wifi", help="Clear WiFi credentials", action="store_true")
|
||||||
|
return p
|
||||||
|
|
||||||
|
def list_boards():
|
||||||
|
print("Discovered boards:")
|
||||||
|
width = max((len(k) for k in BOARD_CONFIGS), default=0)
|
||||||
|
for name, path in sorted(BOARD_CONFIGS.items()):
|
||||||
|
print(f" {name.ljust(width)} -> {os.path.relpath(path, get_root_path())}")
|
||||||
|
|
||||||
|
def _suggest_boards(partial: str) -> List[str]:
|
||||||
|
if not partial:
|
||||||
|
return []
|
||||||
|
partial_low = partial.lower()
|
||||||
|
contains = [b for b in BOARD_CONFIGS if partial_low in b.lower()]
|
||||||
|
if contains:
|
||||||
|
return contains[:10]
|
||||||
|
# simple levenshtein distance limited (manual lightweight)
|
||||||
|
def distance(a: str, b: str) -> int:
|
||||||
|
if len(a) < len(b):
|
||||||
|
a, b = b, a
|
||||||
|
prev = list(range(len(b)+1))
|
||||||
|
for i, ca in enumerate(a, 1):
|
||||||
|
cur = [i]
|
||||||
|
for j, cb in enumerate(b, 1):
|
||||||
|
ins = cur[j-1] + 1
|
||||||
|
dele = prev[j] + 1
|
||||||
|
sub = prev[j-1] + (ca != cb)
|
||||||
|
cur.append(min(ins, dele, sub))
|
||||||
|
prev = cur
|
||||||
|
return prev[-1]
|
||||||
|
ranked = sorted(BOARD_CONFIGS, key=lambda k: distance(partial_low, k.lower()))
|
||||||
|
return ranked[:5]
|
||||||
|
|
||||||
|
def normalize_board_name(raw: Optional[str]) -> Optional[str]:
|
||||||
|
if raw is None:
|
||||||
|
return None
|
||||||
|
candidate = raw.strip()
|
||||||
|
if not candidate:
|
||||||
|
return None
|
||||||
|
candidate = candidate.replace('\\', '/').rstrip('/')
|
||||||
|
# strip leading folders like tools/, boards/
|
||||||
|
parts = [p for p in candidate.split('/') if p not in ('.', '') and p not in ('tools', 'boards')]
|
||||||
|
if parts:
|
||||||
|
candidate = parts[-1] if len(parts) == 1 else "_".join(parts)
|
||||||
|
candidate = candidate.replace('-', '_')
|
||||||
|
# exact match
|
||||||
|
if candidate in BOARD_CONFIGS:
|
||||||
|
return candidate
|
||||||
|
# try ending match
|
||||||
|
endings = [b for b in BOARD_CONFIGS if b.endswith(candidate)]
|
||||||
|
if len(endings) == 1:
|
||||||
|
return endings[0]
|
||||||
|
if len(endings) > 1:
|
||||||
|
print(f"Ambiguous board '{raw}'. Could be: {', '.join(endings)}")
|
||||||
|
return None
|
||||||
|
# attempt case-insensitive
|
||||||
|
lower_map = {b.lower(): b for b in BOARD_CONFIGS}
|
||||||
|
if candidate.lower() in lower_map:
|
||||||
|
return lower_map[candidate.lower()]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_main_config_path() -> str:
|
def get_main_config_path() -> str:
|
||||||
return os.path.join(get_root_path(), "sdkconfig")
|
return os.path.join(get_root_path(), "sdkconfig")
|
||||||
|
|
||||||
|
|
||||||
def get_board_config_path() -> str:
|
def get_board_config_path(board_key: str) -> str:
|
||||||
return os.path.join(get_root_path(), f"sdkconfig.board.{args.board}")
|
return BOARD_CONFIGS[board_key]
|
||||||
|
|
||||||
|
|
||||||
def get_base_config_path() -> str:
|
def get_base_config_path() -> str:
|
||||||
return os.path.join(get_root_path(), sdkconfig_defaults)
|
# base defaults moved under boards directory
|
||||||
|
return os.path.join(get_boards_root(), SDKCONFIG_DEFAULTS_FILENAME)
|
||||||
|
|
||||||
|
|
||||||
def parse_config(config_file) -> dict:
|
def parse_config(config_file) -> dict:
|
||||||
@@ -53,15 +141,17 @@ def parse_config(config_file) -> dict:
|
|||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def handle_wifi_config(_new_config: dict, _main_config: dict) -> dict:
|
def handle_wifi_config(_new_config: dict, _main_config: dict, _args) -> dict:
|
||||||
if args.ssid:
|
if _args.ssid:
|
||||||
_new_config["CONFIG_WIFI_SSID"] = f"\"{args.ssid}\""
|
_new_config["CONFIG_WIFI_SSID"] = f"\"{_args.ssid}\""
|
||||||
_new_config["CONFIG_WIFI_PASSWORD"] = f"\"{args.password}\""
|
_new_config["CONFIG_WIFI_PASSWORD"] = f"\"{_args.password}\""
|
||||||
else:
|
else:
|
||||||
|
if "CONFIG_WIFI_SSID" in _main_config:
|
||||||
_new_config["CONFIG_WIFI_SSID"] = _main_config["CONFIG_WIFI_SSID"]
|
_new_config["CONFIG_WIFI_SSID"] = _main_config["CONFIG_WIFI_SSID"]
|
||||||
|
if "CONFIG_WIFI_PASSWORD" in _main_config:
|
||||||
_new_config["CONFIG_WIFI_PASSWORD"] = _main_config["CONFIG_WIFI_PASSWORD"]
|
_new_config["CONFIG_WIFI_PASSWORD"] = _main_config["CONFIG_WIFI_PASSWORD"]
|
||||||
|
|
||||||
if args.clear_wifi:
|
if _args.clear_wifi:
|
||||||
_new_config["CONFIG_WIFI_SSID"] = "\"\""
|
_new_config["CONFIG_WIFI_SSID"] = "\"\""
|
||||||
_new_config["CONFIG_WIFI_PASSWORD"] = "\"\""
|
_new_config["CONFIG_WIFI_PASSWORD"] = "\"\""
|
||||||
return _new_config
|
return _new_config
|
||||||
@@ -79,44 +169,55 @@ def compute_diff(_parsed_base_config: dict, _parsed_board_config: dict) -> dict:
|
|||||||
return _diff
|
return _diff
|
||||||
|
|
||||||
|
|
||||||
print(f"{OKGREEN}Switching configuration to board:{ENDC} {OKBLUE}{args.board}{ENDC}")
|
def main():
|
||||||
print(f"{OKGREEN}Using defaults from :{ENDC} {get_base_config_path()}", )
|
parser = build_arg_parser()
|
||||||
print(f"{OKGREEN}Using board config from :{ENDC} {get_board_config_path()}")
|
args = parser.parse_args()
|
||||||
|
|
||||||
main_config = open(get_main_config_path(), "r+")
|
if args.list:
|
||||||
|
list_boards()
|
||||||
|
return
|
||||||
|
|
||||||
|
board_input = args.board
|
||||||
|
if not board_input:
|
||||||
|
parser.error("--board is required (or use --list)")
|
||||||
|
normalized = normalize_board_name(board_input)
|
||||||
|
if not normalized:
|
||||||
|
print(f"{WARNING}Unknown board '{board_input}'.")
|
||||||
|
suggestions = _suggest_boards(board_input)
|
||||||
|
if suggestions:
|
||||||
|
print("Did you mean: " + ", ".join(suggestions))
|
||||||
|
print("Use --list to see all boards.")
|
||||||
|
raise SystemExit(2)
|
||||||
|
|
||||||
|
if not os.path.isfile(get_base_config_path()):
|
||||||
|
raise SystemExit(f"Base defaults file not found: {get_base_config_path()}")
|
||||||
|
|
||||||
|
print(f"{OKGREEN}Switching configuration to board:{ENDC} {OKBLUE}{normalized}{ENDC}")
|
||||||
|
print(f"{OKGREEN}Using defaults from :{ENDC} {get_base_config_path()}")
|
||||||
|
print(f"{OKGREEN}Using board config from :{ENDC} {get_board_config_path(normalized)}")
|
||||||
|
|
||||||
|
with open(get_main_config_path(), "r+") as main_config:
|
||||||
parsed_main_config = parse_config(main_config)
|
parsed_main_config = parse_config(main_config)
|
||||||
main_config.close()
|
|
||||||
|
|
||||||
base_config = open(get_base_config_path(), "r")
|
|
||||||
board_config = open(get_board_config_path(), "r")
|
|
||||||
|
|
||||||
|
with open(get_base_config_path(), "r") as base_config, open(get_board_config_path(normalized), "r") as board_config:
|
||||||
parsed_base_config = parse_config(base_config)
|
parsed_base_config = parse_config(base_config)
|
||||||
parsed_board_config = parse_config(board_config)
|
parsed_board_config = parse_config(board_config)
|
||||||
|
|
||||||
base_config.close()
|
|
||||||
board_config.close()
|
|
||||||
|
|
||||||
new_board_config = {**parsed_base_config, **parsed_board_config}
|
new_board_config = {**parsed_base_config, **parsed_board_config}
|
||||||
new_board_config = handle_wifi_config(new_board_config, parsed_main_config)
|
new_board_config = handle_wifi_config(new_board_config, parsed_main_config, args)
|
||||||
|
|
||||||
if args.diff:
|
if args.diff:
|
||||||
print("---"*5, f"{WARNING}DIFF{ENDC}", "---"*5)
|
print("---"*5, f"{WARNING}DIFF{ENDC}", "---"*5)
|
||||||
diff = compute_diff(parsed_main_config, new_board_config)
|
diff = compute_diff(parsed_main_config, new_board_config)
|
||||||
if not diff:
|
if not diff:
|
||||||
print(f"{HEADER_COLOR}[DIFF]{ENDC} Nothing has changed between the base config and {OKBLUE}{args.board}{ENDC} config")
|
print(f"{HEADER_COLOR}[DIFF]{ENDC} No changes between existing main config and {OKBLUE}{normalized}{ENDC}")
|
||||||
else:
|
else:
|
||||||
print(f"{HEADER_COLOR}[DIFF]{ENDC} The following keys have changed between the base config and {OKBLUE}{args.board}{ENDC} config:")
|
print(f"{HEADER_COLOR}[DIFF]{ENDC} Keys differing (main -> new {OKBLUE}{normalized}{ENDC}):")
|
||||||
for key in diff:
|
for key in sorted(diff):
|
||||||
print(f"{HEADER_COLOR}[DIFF]{ENDC} {key} : {diff[key]}")
|
print(f"{HEADER_COLOR}[DIFF]{ENDC} {key} : {diff[key]}")
|
||||||
print("---"*14)
|
print("---"*14)
|
||||||
|
|
||||||
if not args.dry_run:
|
if not args.dry_run:
|
||||||
# the main idea is to always replace the main config with the base config
|
|
||||||
# and then add the board config on top of that, overriding where necessary.
|
|
||||||
# This way we can have known working defaults safe from accidental modifications by espidf
|
|
||||||
# with know working per-board config
|
|
||||||
# and a still modifiable sdkconfig for espidf
|
|
||||||
|
|
||||||
print(f"{WARNING}Writing changes to main config file{ENDC}")
|
print(f"{WARNING}Writing changes to main config file{ENDC}")
|
||||||
with open(get_main_config_path(), "w") as main_config:
|
with open(get_main_config_path(), "w") as main_config:
|
||||||
for key, value in new_board_config.items():
|
for key, value in new_board_config.items():
|
||||||
@@ -126,4 +227,7 @@ if not args.dry_run:
|
|||||||
main_config.write(f"{key}\n")
|
main_config.write(f"{key}\n")
|
||||||
else:
|
else:
|
||||||
print(f"{WARNING}[DRY-RUN]{ENDC} Skipping writing to files")
|
print(f"{WARNING}[DRY-RUN]{ENDC} Skipping writing to files")
|
||||||
print(f"{OKGREEN}Done. ESP-IDF is setup to build for:{ENDC} {OKBLUE}{args.board}{ENDC}")
|
print(f"{OKGREEN}Done. ESP-IDF is setup to build for:{ENDC} {OKBLUE}{normalized}{ENDC}")
|
||||||
|
|
||||||
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user