Document QEMU emulation in README and improve tool descriptions
Add QEMU section to README with install instructions and tool reference. Enrich MCP tool docstrings with workflow context, cross-references to related tools, and guidance on when to use each tool — these descriptions are read by the calling LLM to decide tool selection.
This commit is contained in:
parent
740164f582
commit
cb4822a0a4
24
README.md
24
README.md
@ -10,6 +10,7 @@ FastMCP server providing AI-powered ESP32/ESP8266 development workflows through
|
||||
- **Production Tools**: Factory programming and batch operations
|
||||
- **Middleware System**: Universal CLI tool integration with bidirectional MCP communication
|
||||
- **ESP-IDF Integration**: Host application support for hardware-free development
|
||||
- **QEMU Emulation**: Virtual ESP32 devices for testing without physical hardware
|
||||
|
||||
## Quick Start
|
||||
|
||||
@ -64,6 +65,29 @@ The server implements a component-based architecture with middleware for CLI too
|
||||
- `OTAManager`: Over-the-air update workflows
|
||||
- `ProductionTools`: Factory programming and quality control
|
||||
- `Diagnostics`: Memory dumps and performance profiling
|
||||
- `QemuManager`: QEMU-based ESP32 emulation with download mode, efuse, and flash support
|
||||
|
||||
## QEMU Emulation
|
||||
|
||||
Run virtual ESP32 devices without physical hardware. Requires [Espressif's QEMU fork](https://github.com/espressif/qemu):
|
||||
|
||||
```bash
|
||||
# Install via ESP-IDF tools
|
||||
source /path/to/esp-idf/export.sh
|
||||
python3 $IDF_PATH/tools/idf_tools.py install qemu-xtensa qemu-riscv32
|
||||
```
|
||||
|
||||
The server auto-detects QEMU binaries from `~/.espressif/tools/`. Once available, five tools are exposed:
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `esp_qemu_start` | Launch a virtual ESP device (supports esp32, esp32s2, esp32s3, esp32c3) |
|
||||
| `esp_qemu_stop` | Stop a running instance |
|
||||
| `esp_qemu_list` | List all running instances |
|
||||
| `esp_qemu_status` | Detailed instance info |
|
||||
| `esp_qemu_flash` | Write firmware to a virtual device's flash |
|
||||
|
||||
Virtual devices appear in `esp_scan_ports` alongside physical hardware, connected via `socket://localhost:<port>`.
|
||||
|
||||
## Configuration
|
||||
|
||||
|
||||
@ -149,14 +149,30 @@ class QemuManager:
|
||||
boot_mode: str = "download",
|
||||
extra_args: list[str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Start a QEMU ESP32 emulation instance
|
||||
"""Start a virtual ESP device using QEMU emulation. No physical hardware needed.
|
||||
|
||||
Returns a socket URI (socket://localhost:PORT) that works with all
|
||||
esptool operations: esp_detect_chip, esp_flash_firmware, esp_scan_ports, etc.
|
||||
Virtual devices also appear automatically in esp_scan_ports results.
|
||||
|
||||
Boot modes:
|
||||
- "download" (default): Device starts in serial bootloader. Use this for
|
||||
esptool interactions like flashing, chip identification, and flash reading.
|
||||
- "normal": Device boots from flash and runs firmware. Use this to observe
|
||||
application output after flashing.
|
||||
|
||||
Typical workflow:
|
||||
1. esp_qemu_start (download mode) -> get socket URI
|
||||
2. esp_flash_firmware with socket URI -> flash your firmware
|
||||
3. esp_qemu_stop -> stop the instance
|
||||
4. esp_qemu_start (normal mode, same flash image) -> boot firmware
|
||||
|
||||
Args:
|
||||
chip_type: Target chip (esp32, esp32s2, esp32s3, esp32c3)
|
||||
flash_image: Path to flash image file (creates blank if not specified)
|
||||
flash_size_mb: Flash size in MB for blank images (default: 4)
|
||||
tcp_port: TCP port for virtual serial (auto-assigned if not specified)
|
||||
flash_image: Path to existing flash image file. Creates a blank erased
|
||||
flash (all 0xFF) if not specified.
|
||||
flash_size_mb: Flash size in MB when creating blank images (default: 4)
|
||||
tcp_port: TCP port for virtual serial (auto-assigned from pool if not specified)
|
||||
boot_mode: "download" for esptool interaction (default), "normal" to boot from flash
|
||||
extra_args: Additional QEMU command-line arguments
|
||||
"""
|
||||
@ -168,28 +184,34 @@ class QemuManager:
|
||||
async def qemu_stop(
|
||||
context: Context, instance_id: str | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Stop a running QEMU instance
|
||||
"""Stop a running QEMU virtual device. Terminates the QEMU process and frees the TCP port.
|
||||
|
||||
The flash image is preserved on disk, so the instance can be restarted
|
||||
with esp_qemu_start using the same flash_image path (e.g., to switch
|
||||
from download mode to normal boot mode after flashing).
|
||||
|
||||
Args:
|
||||
instance_id: Instance ID to stop (stops all if not specified)
|
||||
instance_id: Instance ID to stop (stops all running instances if not specified)
|
||||
"""
|
||||
return await self._stop_impl(context, instance_id)
|
||||
|
||||
@self.app.tool("esp_qemu_list")
|
||||
async def qemu_list(context: Context) -> dict[str, Any]:
|
||||
"""List all QEMU instances with status"""
|
||||
"""List all QEMU virtual device instances with their status, chip type, port, and boot mode.
|
||||
|
||||
Returns running and stopped instances. Use this to find instance IDs
|
||||
for esp_qemu_stop or esp_qemu_status, or to get socket URIs for esptool operations."""
|
||||
return await self._list_impl(context)
|
||||
|
||||
@self.app.tool("esp_qemu_status")
|
||||
async def qemu_status(
|
||||
context: Context, instance_id: str | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Get detailed status of a QEMU instance
|
||||
"""Get detailed status of a QEMU virtual device including uptime, PID, socket URI,
|
||||
boot mode, and flash/efuse image paths.
|
||||
|
||||
Args:
|
||||
instance_id: Instance to inspect (first running if not specified)
|
||||
instance_id: Instance to inspect (returns first running instance if not specified)
|
||||
"""
|
||||
return await self._status_impl(context, instance_id)
|
||||
|
||||
@ -200,17 +222,21 @@ class QemuManager:
|
||||
firmware_path: str,
|
||||
address: str = "0x0",
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Flash a firmware binary to a QEMU instance's flash image
|
||||
"""Write a firmware binary directly into a QEMU instance's flash image file.
|
||||
|
||||
The instance must be stopped first. This writes the binary at the
|
||||
given offset into the raw flash image file, then you can restart
|
||||
the instance.
|
||||
This is an offline operation — the instance must be stopped first.
|
||||
It patches the raw flash image at the given offset, then you can restart
|
||||
with esp_qemu_start in "normal" boot mode to run the firmware.
|
||||
|
||||
For most use cases, prefer using esp_flash_firmware with the instance's
|
||||
socket URI while it's running in download mode — that uses esptool's
|
||||
full flash protocol including verification. Use this tool only when you
|
||||
need direct image manipulation (e.g., pre-loading a merged binary).
|
||||
|
||||
Args:
|
||||
instance_id: Target QEMU instance
|
||||
firmware_path: Path to firmware binary to write
|
||||
address: Flash address offset (hex string, default: 0x0)
|
||||
instance_id: Target QEMU instance (must be stopped)
|
||||
firmware_path: Path to firmware binary to write into the flash image
|
||||
address: Flash address offset as hex string (default: "0x0")
|
||||
"""
|
||||
return await self._flash_impl(context, instance_id, firmware_path, address)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user