Run ESP32/ESP32C3/ESP32S3 firmware in QEMU using Docker. Args: firmware_path: Path to firmware.bin or build directory timeout: Timeout in seconds (timeout is treated as success) interrupt_regex: Regex pattern to detect in output (informational only)
(
self,
firmware_path: Path,
timeout: int = 30,
interrupt_regex: Optional[str] = None,
interactive: bool = False,
output_file: Optional[str] = None,
machine: str = "esp32",
skip_pull: bool = False,
)
| 558 | return cmd |
| 559 | |
| 560 | def run( |
| 561 | self, |
| 562 | firmware_path: Path, |
| 563 | timeout: int = 30, |
| 564 | interrupt_regex: Optional[str] = None, |
| 565 | interactive: bool = False, |
| 566 | output_file: Optional[str] = None, |
| 567 | machine: str = "esp32", |
| 568 | skip_pull: bool = False, |
| 569 | ) -> int: |
| 570 | """Run ESP32/ESP32C3/ESP32S3 firmware in QEMU using Docker. |
| 571 | |
| 572 | Args: |
| 573 | firmware_path: Path to firmware.bin or build directory |
| 574 | timeout: Timeout in seconds (timeout is treated as success) |
| 575 | interrupt_regex: Regex pattern to detect in output (informational only) |
| 576 | interactive: Run in interactive mode (attach to container) |
| 577 | output_file: Optional file path to write QEMU output to |
| 578 | machine: QEMU machine type (esp32, esp32c3, esp32s3, etc.) |
| 579 | skip_pull: Skip pulling Docker image (assumes image already exists) |
| 580 | |
| 581 | Returns: |
| 582 | Exit code: actual QEMU/container exit code, except timeout returns 0 |
| 583 | """ |
| 584 | if not self.check_docker_available(): |
| 585 | print("ERROR: Docker is not available or not running", file=sys.stderr) |
| 586 | print("Please install Docker and ensure it's running", file=sys.stderr) |
| 587 | return 1 |
| 588 | |
| 589 | # Pull image if needed (unless skip_pull is True) |
| 590 | if not skip_pull: |
| 591 | self.pull_image() |
| 592 | else: |
| 593 | print(f"Skipping image pull (using existing {self.docker_image})") |
| 594 | |
| 595 | # Prepare firmware files |
| 596 | print(f"Preparing firmware from: {firmware_path}") |
| 597 | temp_firmware_dir = None |
| 598 | |
| 599 | try: |
| 600 | temp_firmware_dir = self.prepare_firmware(firmware_path) |
| 601 | |
| 602 | # Generate unique container name based on platform family |
| 603 | # Determine platform family from machine type |
| 604 | from ci.docker_utils.build_platforms import get_platform_for_board |
| 605 | |
| 606 | platform = get_platform_for_board(machine) |
| 607 | if platform: |
| 608 | # Use platform-level naming with timestamp for uniqueness |
| 609 | # Simulator containers are temporary (created/destroyed per test) |
| 610 | self.container_name = f"fastled-simulator-{platform}-{int(time.time())}" |
| 611 | else: |
| 612 | # Fallback for unmapped boards |
| 613 | self.container_name = f"fastled-simulator-{machine}-{int(time.time())}" |
| 614 | |
| 615 | # Convert Windows paths to Docker-compatible paths |
| 616 | def windows_to_docker_path(path_str: str | Path) -> str: |
| 617 | """Convert Windows path to Docker volume mount format.""" |