- also revert the modification in the singature of uninstall function
in all the concerned esp_driver* components and esp_stdio.
- added proper documentation of the feature in the programming guide
Add a `monitor_device` MCP tool that lets an AI agent run a scripted,
non-interactive `esp-idf-monitor` session against a flashed device and
get back a short status plus a log file path, instead of raw serial
output inline.
Under the hood:
- The agent supplies a plain-text command body (expect/send/sleep/reset/
exit/comments). `assemble_monitor_script_from_agent_commands()` frames
it into a script the monitor's non-interactive command mode can
consume via stdin: it appends `exit` if the agent didn't already end
with one, and rewrites every bare `expect <regex>` into `expect
--timeout <timeout_sec> <regex>` via `_monitor_normalize_expect_line()`
(an already-bounded `expect --timeout ...` line is left untouched so
the monitor itself reports a bad value). A leading `reset` is not
prepended - the monitor already resets the chip when it opens the
port - and any `reset` the agent wrote is left in place.
`_monitor_parse_sleep_duration()` extracts each `sleep <n>` duration.
The effective timeout is the sum of every bounded expect duration
plus every sleep duration. Scripts whose sum exceeds
`MONITOR_MAX_SCRIPT_SEC` are rejected. If the script has neither
expect nor sleep (for example only `send`), `timeout_sec` is used so
the process still has a kill bound.
- `monitor_device()` runs `python -m esp_idf_monitor` via
`subprocess.run(..., input=script, timeout=2 * effective_timeout)`.
`no_reset` is forwarded as `--no-reset` so the connection reset can be
skipped; an explicit `-p` is forwarded when a port is given. Extra
arguments match `idf.py monitor` where a build exists: baud (`baud`
tool arg, else `monitor_baud` from `project_description.json`),
toolchain prefix, `--target`/`--revision`, coredump/panic decode, and
ELF files with the app ELF first. The 2x hard timeout is a safety net
independent of the script's own `expect --timeout`/`exit` logic; on
`TimeoutExpired` the process is killed but any output already captured
is preserved and logged. `decode_stream()` normalizes that captured
output, which can be `bytes` on the timeout path even though the
process otherwise runs in text mode.
- The monitor's exit code drives the reported status via
`_monitor_status()`, using `EXIT_EXPECT_TIMEOUT` and
`EXIT_SCRIPT_ERROR` from `esp_idf_monitor.base.constants`: 0 is
success, 110 means an `expect` pattern never showed up before its
`--timeout` elapsed, 2 means the monitor rejected the script (bad
syntax/timeout/regex), anything else is reported generically.
- Serial output and the monitor's own messages share one pipe
(`stderr=STDOUT`) so decoded panic backtraces stay next to the lines
that triggered them. `_save_monitor_output()` writes the full merge to
`<tempdir>/esp_idf_mcp_log/action_monitor/monitor_<timestamp>.log` and
reports a dedicated `Log file:` line. On non-zero exit or process
kill, a short tail of that same merge is also returned inline so the
agent has some failure context without a second file read. If the log
file can't be written, it falls back to inlining a truncated tail.
Closes https://github.com/espressif/esp-idf/issues/18757
Closes https://github.com/espressif/esp-idf/pull/18385
Co-authored-by: Cursor <cursoragent@cursor.com>
The GDMA layer used `max_data_burst_size == 0` as the only way to disable the
data burst. That conflicts with the upstream drivers' convention where a zeroed
config struct means "unset", so users had no way to ask for the driver default
burst size.
GDMA now treats both 0 and 1 as "no data burst": a single-beat burst has no
benefit over the non-burst mode. The MSPI alignment constraint under Flash
Encryption / PSRAM ECC still takes precedence and is reported with a warning.
The upstream drivers using GDMA now apply their own default burst size (16
bytes) when the user leaves `dma_burst_size` as 0, following the UHCI driver:
- esp_async_crc (AHB / AXI GDMA backend)
- esp_async_memcpy (AHB / AXI / LP-AHB / DW_GDMA backend)
Callers that really want no burst can now set `dma_burst_size` to 1.
Add an example under examples/storage/generic_partition_bdl that
partitions a raw block device at run time using only the Block Device
Layer (BDL) interface.
The example obtains a whole-disk BDL (SPI flash data partition by
default, or an SD/eMMC card via menuconfig), writes an MBR partition
table onto it with the esp_ext_part_tables managed component (fetched
via idf_component.yml), then creates a generic-partition BDL for each
MBR entry with esp_blockdev_generic_partition_get() and mounts FATFS on
the FAT slice and LittleFS on the LittleFS slice.
__generate_gdbinit wrote into a single shared directory and derived the
application ELF from a global property, so a project building multiple
executables had their gdbinit files overwrite each other. Take the ELF
path and output directory as arguments, and derive them per executable in
idf_build_generate_metadata.