Run firmware in Docker container Args: elf_path: Path to the firmware ELF file mcu: MCU type (e.g., "atmega328p") frequency: MCU frequency in Hz timeout: Execution timeout in seconds output_file: Optional file to write out
(
self,
elf_path: Path,
mcu: str,
frequency: int,
timeout: int = 30,
output_file: Optional[str] = None,
)
| 75 | subprocess.run(["docker", "pull", self.docker_image], check=True) |
| 76 | |
| 77 | def run( |
| 78 | self, |
| 79 | elf_path: Path, |
| 80 | mcu: str, |
| 81 | frequency: int, |
| 82 | timeout: int = 30, |
| 83 | output_file: Optional[str] = None, |
| 84 | ) -> int: |
| 85 | """ |
| 86 | Run firmware in Docker container |
| 87 | |
| 88 | Args: |
| 89 | elf_path: Path to the firmware ELF file |
| 90 | mcu: MCU type (e.g., "atmega328p") |
| 91 | frequency: MCU frequency in Hz |
| 92 | timeout: Execution timeout in seconds |
| 93 | output_file: Optional file to write output to |
| 94 | |
| 95 | Returns: |
| 96 | Exit code (0 for success) |
| 97 | """ |
| 98 | elf_path = Path(elf_path).resolve() |
| 99 | |
| 100 | if not elf_path.exists(): |
| 101 | raise FileNotFoundError(f"Firmware not found: {elf_path}") |
| 102 | |
| 103 | # avr8js requires HEX file, not ELF |
| 104 | # PlatformIO generates both .elf and .hex in the same directory |
| 105 | hex_path = elf_path.with_suffix(".hex") |
| 106 | if not hex_path.exists(): |
| 107 | raise FileNotFoundError(f"HEX file not found: {hex_path}") |
| 108 | |
| 109 | print("Preparing Docker execution environment:") |
| 110 | print(" Firmware format conversion: ELF → HEX (required by avr8js)") |
| 111 | print(f" ELF file: {elf_path}") |
| 112 | print(f" HEX file: {hex_path}") |
| 113 | print() |
| 114 | |
| 115 | # Prepare Docker command with proper path handling |
| 116 | firmware_dir = hex_path.parent |
| 117 | firmware_name = hex_path.name |
| 118 | |
| 119 | # Convert to Docker-compatible path for volume mounting |
| 120 | docker_firmware_dir = self._convert_to_docker_volume_path(firmware_dir) |
| 121 | |
| 122 | print(" Docker volume mounting:") |
| 123 | print(f" Host directory: {firmware_dir}") |
| 124 | print(f" Docker path: {docker_firmware_dir}") |
| 125 | print(" Container mount: /firmware (read-only)") |
| 126 | print() |
| 127 | |
| 128 | docker_cmd: list[str] = [ |
| 129 | "docker", |
| 130 | "run", |
| 131 | "--rm", # Remove container after run |
| 132 | "-v", |
| 133 | f"{docker_firmware_dir}:/firmware:ro", # Mount firmware directory read-only |
| 134 | self.docker_image, |