Коротко: в unified firmware ExpressLRS 4.1 конфигурационный блок действительно добавляется после ESP firmware image, но его начало нельзя задавать одним вечным абсолютным offset. ExpressLRS сначала вычисляет конец конкретного image, выравнивает позицию, а затем записывает product name, device/Lua name, defines и hardware layout.
Проверено по исходному коду: ExpressLRS tag 4.1.0, commit release a9d4a9c, файл src/python/UnifiedConfiguration.py. Структура ниже относится только к firmware, для которого этот unified layout применим.
Почему «фиксированный offset от начала файла» неверен
В ExpressLRS 4.1 функция findFirmwareEnd() разбирает ESP image и вычисляет его реальный конец. Алгоритм проверяет magic byte 0xE9, учитывает layout ESP8266/ESP8285, проходит по firmware segments, затем выравнивает итоговую позицию.
Упрощённо логика такая:
- прочитать ESP image header;
- проверить magic
0xE9; - определить особый путь ESP8266/8285 по структуре segments;
- пройти все segments по их размерам;
- выровнять позицию:
(pos + 16) & ~15; - для non-8285 добавить ещё 32 bytes;
- только после этого начинается unified configuration.
firmware.bin могут иметь unified block по разным абсолютным адресам. Надёжный инструмент должен сначала воспроизвести логику поиска конца image, а не писать по hard-coded offset.Структура unified block в ExpressLRS 4.1.0
Пусть BASE — позиция, возвращённая логикой, эквивалентной findFirmwareEnd(). Тогда базовые поля идут последовательно:
product_name128 bytes
lua/device name16 bytes
defines512 bytes
hardware layout2048 bytes
| Поле | Диапазон относительно BASE | Размер | Формат |
|---|---|---|---|
| Product name | 0…127 |
128 B | UTF-8 bytes, NUL-padded/truncated |
| Device/Lua name | 128…143 |
16 B | UTF-8 bytes, NUL-padded/truncated |
| Defines/options | 144…655 |
512 B | encoded configuration, NUL-padded |
| Hardware layout | 656…2703 |
2048 B | JSON layout, NUL-padded |
После 2704 bytes блок может продолжаться
Нельзя считать BASE + 2704 обязательным концом конфигурации. Код ExpressLRS 4.1.0 после hardware layout может дописывать дополнительные данные:
- logo data, если target использует
logo_file; - marker
BE EF CA FEиprior_target_name, если эта информация присутствует в target config.
Поэтому инструмент, который просто «обрезает всё после 2704 bytes», потенциально портит firmware.
Что допустимо редактировать
Безопасный подход — менять только те поля unified configuration, структура которых подтверждена для exact release и target class. Например, текстовое имя или JSON layout можно анализировать отдельно от машинного кода.
Недопустимо:
- искать красивую ASCII-строку и предполагать, что рядом всегда находится тот же layout;
- записывать данные длиннее выделенного поля;
- сдвигать последующие bytes;
- менять ESP segments или executable code без отдельного анализа;
- применять offsets 4.1.0 к другой major/release без проверки source.
Минимальная процедура безопасной проверки
- Сделайте копию исходного
firmware.bin. - Посчитайте SHA-256 исходного файла.
- Подтвердите exact target и release.
- Вычислите BASE из ESP image structure.
- Прочитайте product/device/defines/layout без записи.
- Убедитесь, что JSON fields декодируются и соответствуют ожидаемому hardware.
- Изменяйте только разрешённое поле, сохраняя его фиксированный размер.
- Снова проверьте JSON/UTF-8.
- Сделайте binary diff исходного и candidate.
- Убедитесь, что изменились только ожидаемые bytes внутри разрешённого range.
- Сохраните SHA-256 candidate.
- Прошивайте только устройство с известным recovery path.
Каким должен быть автоматический тест инструмента
Если на сайте используется HEX/firmware parser, он должен иметь fixture из известной сборки ExpressLRS 4.1.0 и автоматически проверять:
- magic/header распознан;
- BASE вычислен корректно;
- product name читается;
- device name читается;
- defines помещаются в 512 B;
- hardware JSON помещается в 2048 B и валиден;
- patch не меняет длину базовых фиксированных slots;
- diff не выходит за разрешённые ranges;
- machine-code segments остаются неизменными.
hardware.json/recovery workflow.Платформенные ограничения
| Платформа | Применимость этой статьи |
|---|---|
| Unified ESP8285 / ESP8266 class | Да, при подтверждённом target/layout |
| Unified ESP32 class | Да, при подтверждённом target/layout |
| SPI RX в flight controller | Нет — это часть firmware FC |
| STM32 legacy ELRS | Нет для 4.x |
| Unknown firmware.bin | Нет |
Почему hardware.json обычно лучше HEX
Если устройство загружается и WebUI/обычный configuration path доступен, используйте штатный hardware.json workflow. Binary patching нужен только когда есть конкретная причина работать с unified block и понятен путь восстановления.
Перед major upgrade 3.x → 4.x учитывайте переход SPIFFS → LittleFS: пользовательские изменения hardware/options нужно сохранить заранее.
Связанные материалы
Источник структуры
ExpressLRS 4.1.0 — UnifiedConfiguration.py. Для claims этой статьи использовать именно tag 4.1.0, а не меняющуюся ветку master.
