Реверс прошивки FM33LG025: результаты и требования к будущему прибору
Дата: 13 сентября 2026. Исследование сохранённого C:\dump\fw_128k.bin, не новое чтение подключённого аппарата. Исходные дампы не изменялись; к USB/J-Link и реальной памяти прибора в этой работе не обращались. Исходники будущего ядра также не менялись.
Короткий вывод
Из бинарника восстановлены рабочие алгоритмы измерений, несколько моделей калибровки, температурные поправки, пороговые тревоги, запись журнала, основные экраны и последовательность запуска. Выводы проверялись по машинным инструкциям; существенные участки дополнительно исполнялись в изолированном ARM-эмуляторе с искусственными входами.
Для будущей прошивки наиболее важны четыре результата:
- Нужна полноценная цепочка измерения с качеством и временем данных, индивидуальной калибровкой и состоянием каждого канала. Текущий эмулятор проекта эту цепочку пока лишь частично изображает.
- В старом приборе есть отдельная I²C-память для калибровок, настроек и журнала. Flash-дамп содержит алгоритмы и встроенные начальные значения, но не заменяет дамп этой памяти.
- Встроенная начальная конфигурация — EX, O₂, H₂S, CO, а не O₂/CO/H₂S/CO₂. В общей таблице поддерживаемых подписей CO₂ есть, но это не доказывает его наличие на данной плате. Название EX само по себе не определяет модель сенсора.
- Некоторые приёмы старой прошивки не стоит повторять: принудительная фиксация диапазона показаний одним числом, потеря видимого количества записей при заполнении журнала, игнорирование ошибки записи. Мы восстанавливаем поведение, а не принимаем его за эталон безопасности или точности.
Навигация
- Измерения, фильтры, калибровка, температура — формулы, поля RAM, адреса и ограничения.
- Память, пороги, журнал — формат записей и подтверждённые пограничные особенности.
- Батарея и завершение работы — пороги и влияние предупреждения на основной цикл.
- Запуск, меню и сервисные операции — состояния, обработчики, подтверждения и таймауты.
- Временная база — расчёт программных периодов и его условия.
- Что действительно реализовано в нашем проекте — проверка исходников и пробелов.
- Проверяемые требования к будущему ядру — предлагаемый порядок реализации и приёмочные сценарии.
- Как повторить исследование, сводка проверок (локальный материал), происхождение файлов (локальный материал).
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 (локальный материал).
Это восстановило указатели на тексты меню и встроенную конфигурацию. Совпадение двух файлов не доказывает, что в них присутствуют все области памяти микросхемы или что именно эта версия работает сейчас на подключённом аппарате. Эталонной контрольной суммы производителя нет: непротиворечивость копий не исключает повреждения, уже присутствовавшего при их получении.
Карта основных функций
| Область | Адреса 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, начиная с контракта измерения и настоящей калибровки.