# Реверс прошивки FM33LG025: результаты и требования к будущему прибору

Дата: 13 сентября 2026. Исследование **сохранённого** `C:\dump\fw_128k.bin`, не новое чтение подключённого аппарата. Исходные дампы не изменялись; к USB/J-Link и реальной памяти прибора в этой работе не обращались. Исходники будущего ядра также не менялись.

## Короткий вывод

Из бинарника восстановлены рабочие алгоритмы измерений, несколько моделей калибровки, температурные поправки, пороговые тревоги, запись журнала, основные экраны и последовательность запуска. Выводы проверялись по машинным инструкциям; существенные участки дополнительно исполнялись в изолированном ARM-эмуляторе с искусственными входами.

**Для будущей прошивки наиболее важны четыре результата:**

1. Нужна полноценная цепочка измерения с качеством и временем данных, индивидуальной калибровкой и состоянием каждого канала. Текущий эмулятор проекта эту цепочку пока лишь частично изображает.
2. В старом приборе есть отдельная I²C-память для калибровок, настроек и журнала. Flash-дамп содержит алгоритмы и встроенные начальные значения, но не заменяет дамп этой памяти.
3. Встроенная начальная конфигурация — **EX, O₂, H₂S, CO**, а не O₂/CO/H₂S/CO₂. В общей таблице поддерживаемых подписей CO₂ есть, но это не доказывает его наличие на данной плате. Название EX само по себе не определяет модель сенсора.
4. Некоторые приёмы старой прошивки не стоит повторять: принудительная фиксация диапазона показаний одним числом, потеря видимого количества записей при заполнении журнала, игнорирование ошибки записи. Мы восстанавливаем поведение, а не принимаем его за эталон безопасности или точности.

## Навигация

- [Измерения, фильтры, калибровка, температура](measurement/findings.md) — формулы, поля RAM, адреса и ограничения.
- [Память, пороги, журнал](storage-alarm/findings.md) — формат записей и подтверждённые пограничные особенности.
- [Батарея и завершение работы](storage-alarm/power.md) — пороги и влияние предупреждения на основной цикл.
- [Запуск, меню и сервисные операции](ui-startup.md) — состояния, обработчики, подтверждения и таймауты.
- [Временная база](timing.md) — расчёт программных периодов и его условия.
- [Что действительно реализовано в нашем проекте](project-gap.md) — проверка исходников и пробелов.
- [Проверяемые требования к будущему ядру](future-firmware-requirements.md) — предлагаемый порядок реализации и приёмочные сценарии.
- [Как повторить исследование](REPRODUCE.md), [сводка проверок](evidence/test-summary.json), [происхождение файлов](evidence/verification.json).
- `generated/functions/` — автоматический псевдокод по адресам; `generated/instructions.txt` — инструкции; `generated/references.tsv` — ссылки; `generated/switch_tables.tsv` — восстановленные таблицы переходов. Это инструменты исследования, **не исходный C-код для сборки**.

## Надёжность исходного материала

| Проверка | Результат |
|---|---|
| Основной BIN | 131072 байта, адрес загрузки 0, ARM Thumb little-endian |
| SHA-256 | `fa0ff6bb9fdd148ac1449d6a12b491c04434ec47ca6283439f0b6e6875a62560` |
| `fw_128k_check.bin` | Побайтно совпадает с основным |
| BIN внутри `fw_128k.zip` | Побайтно совпадает с основным |
| `test4k.bin` | Фрагмент основного по адресу `0xDC20`, не начало прошивки |
| `fm33_dataflash_00010000.bin` | Точная верхняя половина основного BIN, не доказательство отдельного Data Flash |
| Старый листинг `Untitled-1.txt` | Проверено 130329 представленных байтов, расхождений нет; это не доказательство правильной разметки кода/данных |
| Нулевые BIN | Пустые результаты прежних попыток, данных для реверса не содержат; сохранены |

Начальный указатель стека `0x200028B8`, вход после сброса `0xDC` с Thumb-битом в векторе. Найденная таблица startup по `0x16878` распаковывает 3856 байт из `0x1689C` в `0x20000000`, затем обнуляет 6568 байт начиная с `0x20000F10`. Трансляция распаковщика и независимое исполнение его исходных инструкций дали одинаковый результат; см. [проверку startup](evidence/startup-emulation.json).

Это восстановило указатели на тексты меню и встроенную конфигурацию. **Совпадение двух файлов не доказывает**, что в них присутствуют все области памяти микросхемы или что именно эта версия работает сейчас на подключённом аппарате. Эталонной контрольной суммы производителя нет: непротиворечивость копий не исключает повреждения, уже присутствовавшего при их получении.

## Карта основных функций

| Область | Адреса Flash | Что восстановлено |
|---|---|---|
| ADC/DMA | `0x11C0`, `0xC6F8`, `0xF5C` | Шесть каналов, аппаратное усреднение, обработка десяти сканов, порядок результатов |
| Цепочка измерений | `0xAEC4`, вызов из `0x1056C` | Поочерёдная обработка четырёх газовых слотов до значения для тревог |
| Фильтры | `0xFE48`, `0x1044C` | Скользящее среднее 8 и округлённое `0.8*новое + 0.2*предыдущее` |
| Калибровка | `0x9A7C`, `0xA9A4`, `0xA490` | Возрастающая/убывающая кусочно-линейная и нелинейная ветви |
| Температура | `0x11478`, `0xA6AC`, `0xE758` | Отдельный аналоговый вход, температура калибровки, полиномиальные поправки |
| Тревоги | `0xC1F6–0xC6D0`, `0x1534` | Две ступени/допустимый интервал, переходы событий, приоритеты оповещения |
| NVM | `0xECF0`, `0xEF74` | Чтение/запись внешней памяти, страницы 64 байта |
| Калибровочные копии | `0x11150`, `0x112E8` | Восстановление/сохранение заводских полей |
| Журнал | `0x1360`, `0x2188` | Запись при смене ступени, просмотр 14-байтных записей |
| Интерфейс | `0x1056C`, `0x4684`, `0x4330` | Основной автомат, меню, сервисный ввод |
| Подписи газов | `0x77E8`, `0x3B74` | Тип из настроек выбирает строку в восстановленной RAM |

### Измерения: что нельзя упустить

Последовательность старого тракта: **аппаратное усреднение 8× → десять отсчётов с удалением одного минимума и максимума → масштабирование → скользящее среднее 8 → рекурсивное сглаживание → пересчёт по калибровке и температуре → смещение нуля/специальные преобразования → ограничение диапазона → тревоги**. Конкретные ветви зависят от типа и режима канала: для H₂S/CO температурная ветвь является альтернативным двухточечным пересчётом с особым span, а не универсальной поправкой поверх четырёхузловой таблицы.

Четыре слоя фильтрации нельзя переносить без оценки задержки. При обычном начальном RCHF 8 МГц код настраивает CPU 24 МГц, SysTick 1 мс и шаг планировщика 10 мс. Основная задача готова каждые 100 мс; при четырёх включённых каналах номинально получается **400 мс на обновление одного канала**. Это расчёт программной конфигурации, а не измерение платы. Уже скользящему среднему из восьми значений для полной замены старого окна нужно восемь обновлений. Для будущего прибора важен проверяемый срок обнаружения изменения, а не сходство количества фильтров.

| Слот по умолчанию | Подпись из кода | ADC | H / L во внутренней шкале |
|---:|---|---:|---|
| 0 | EX | CH6 | 50 / 20 |
| 1 | O₂ | CH13 | 235 / 195, один десятичный знак |
| 2 | H₂S | CH15 | 20 / 10 |
| 3 | CO | CH14 | 200 / 50 |

Температура — CH5, батарея — CH27 (VBAT/3). Это **встроенные исходные настройки**, которые загрузка внешней памяти может заменить; не измеренные текущие настройки аппарата и не рекомендуемые нормативные пороги нового изделия.

Калибровочная запись занимает 57 байт на слот, содержит опорные точки, смещение, температуру и дополнительные параметры. Восстановлен путь до четырёх узлов; пустая таблица местами заменяется встроенным поведением, а не явным отказом. Для нового ядра отсутствие/невалидность калибровки нужно представлять отдельным состоянием.

Особенно важно: старый код фиксирует кислородное показание `203 < x <= 216` в `209` при соответствующих настройках; есть зоны фиксации нуля и дополнительные условные поправки. Итог после этих преобразований используется и тревогами. Нельзя считать такие изменения только оформлением экрана.

### Тревоги, память и журнал

Обычная схема: `x < L` — норма, `L <= x < H` — первая ступень, `x >= H` — высокая. В кислородной ветви `x < L` — низкая тревога, `L <= x < H` — норма, `x >= H` — высокая. Однако при нулевом первом u16-поле калибровочной записи эта специальная ветка пропускается, причём прошлое состояние не обязательно очищается. В проверенном фрагменте самостоятельного гистерезиса нет. Переход в другую **тревожную** ступень пишет событие, повтор той же ступени и возврат в норму — нет.

Внешняя память имеет 7-битный адрес `0x50`, используются 32 КиБ и страницы по 64 байта. Это совместимо с организацией 24C256, но маркировку микросхемы ещё нужно подтвердить. Калибровки находятся с `0x0000`, настройки каналов с `0x0201`, журнал с `0x1203`, его счётчик с `0x1201`.

Проверено исполнением: после записи №2000 счётчик становится нулём; ошибка записи не предотвращает обновление счётчика; один байт записи не инициализируется. Для нашей реализации нужны иной формат, контроль целостности, обработка ошибок и тесты прерывания питания. «Журнал на 2000 записей» сам по себе не означает устойчивый кольцевой журнал.

### Запуск и обслуживание

Есть многошаговый запуск, ожидание Starting/Please Wait, последовательное включение световых/вибрационных/звуковых выходов, основное меню, калибровочные и заводские операции. Наличие управляющего импульса не доказывает самодиагностику исправности исполнительного узла: в исследованном обработчике обратная связь не обнаружена.

Сервисные действия нужно разделить по последствиям: изменение порогов, новая калибровка, восстановление заводских данных, перезапись заводской копии. Старые постоянные пароли и скрытые режимы не являются моделью защиты для нового изделия.

### Питание: важная зависимость от экрана

Найдены разные состояния предупреждения и критического питания. Для фильтрованной оценки батареи проверено: ниже 3555 при исходном состоянии возникает экран предупреждения 7; ниже 3455 после завершённого предупреждения выполняются команды завершения работы; выше 3650 состояние предупреждения сбрасывается. Равенство порогу не равно его пересечению. Масштаб согласуется с милливольтами, но физическое напряжение и отключение питания эмуляция не проверяет.

В режиме 7 главный обработчик **пропускает вызов обработки газа `0xAEC4`** до завершения предупреждения батареи. Это не означает остановку самого ADC, но показывает нежелательную зависимость критического расчётного пути от интерфейса. В новой архитектуре обработку газа следует отделить от отображения предупреждений.

## Что уже проверено, а что остаётся неизвестным

Исполнялись **отдельные исходные функции**, а не весь прибор. Память, кнопки и входные значения задавались моделью; физические драйверы на границах подменялись. **235 сценариев прошли**: 102 измерительных, 108 тревог/журнала, 20 интерфейса и 5 питания; отдельно проверены копии дампа и распаковка startup. Состав и результаты хранятся в `evidence/test-summary.json`. Из этого не следует, что дефектов нет: часть сценариев как раз подтверждает нежелательное поведение старого кода.

Открытые вопросы, которые нельзя подменять догадкой:

- Индивидуальные коэффициенты, реальные настройки и история **конкретного аппарата**: нужен отдельный read-only дамп внешней NVM.
- Полная привязка схемы/сенсоров, опоры, усилителей и исполнительных линий к плате; подтверждение модели внешней памяти.
- Фактические частоты и джиттер scheduler/ADC, поведение при перегрузке, режимы отключённых каналов и суммарная задержка тревоги. Номинальное расписание установлено в `timing.md`, аппаратная проверка ещё нужна.
- Полная политика отказов, зарядки, выключения и сохранения при падении питания. Часть ветвей найдена, целиком не проверена.
- Все варианты калибровочного workflow: критерии стабильности, запреты, ошибки коэффициентов, прерывание/отмена.
- Наличие и фактическое использование межгазовой компенсации, TWA/STEL, отдельного error log, интерфейсов обслуживания/обновления: текущий анализ не даёт основания объявлять их ни реализованными, ни отсутствующими.
- Сборка и тесты нового C99-ядра: в этой работе анализировались исходники, но его поведение не выдаётся за проверенное исполнением. Нынешние тестовые файлы проекта — заглушки.

Рабочий следующий шаг **в рамках реверса**: все ветви калибровки и отказов, фактические задержки; затем read-only исследование внешней памяти после подтверждения её типа и подключения. Следующий шаг **в разработке**: отдельное решение о реализации требований из `future-firmware-requirements.md`, начиная с контракта измерения и настоящей калибровки.
