# Состояние переносимого ядра — 2026-09-13

Это реализация программных этапов из `reverse-engineering/future-firmware-requirements.md`,
а не утверждение готовности законченного измерительного прибора. Исходный аналоговый
проект O2/CO/H2S/CO2 сохранён; альтернативный цифровой вход — дополнительный контракт,
не выбор другого CO2-сенсора. Дамп чужого прибора и физическое устройство не менялись.

## Реализовано и проверено

| Область | Реализация | Основная проверка |
|---|---|---|
| Измерения M01–M04 | ADC24 и отдельный ввод концентрации; время, качество, единицы, независимые окна; сброс после ошибки | Отсутствие/старение/обрыв, смена источника, выход за диапазон |
| Калибровка C01–C04 | 2–5 точек, оба направления, прямой/обратный расчёт; zero/span-сеанс; профиль/версия/температура/дата | Узлы, интервалы, нестабильность, отмена, сбой записи без изменения RAM |
| Температура T01 | Проверяемая табличная модель `Ccal × R(Tcal) / R(T)`; контроль возраста | Диапазон, NaN/Inf, нулевой отклик, переполнение, восстановление |
| Межгазовая коррекция T02 | Неизменяемый снимок входов, суммирование поправок; верхние оценки пропускаются | Перестановка правил/каналов, невозможный результат, повторный tick |
| Тревоги A01–A04 | HIGH_ONLY / INTERVAL / TWO_HIGH, включительные пороги, гистерезис, задержки, фиксация, ack | Точные границы, задержка, дребезг, новый HIGH после mute, отказ |
| Время M05–M06 | `AnalyzerCore`: submit/tick без участия экрана; цифровые входы не имитируют ADC | Ступенька с окном 4 и задержкой 100 мс; старение всех каналов |
| Хранение S01–S02 | Указатели/size_t не сериализуются; формат LE/IEEE754, версии, CRC32, два слота, барьеры sync | Каждый байт обрыва обновления; каждый байт повреждения новой копии |
| Журнал L01–L02 | 16 записей по кольцу; sequence/head/count; raw24, качество, наличие значения | 100 событий, кольцо, переполнение sequence, сохранение/загрузка |
| Состояния U01–U03 | Отдельный supervisor; запрос самотеста не равен обратной связи; подтверждение restore | Калибровка/низкая батарея одновременно с тревогой; неподтверждённый выход |

14 групп CTest включают сценарии консоли и перезапуск с файлом настроек.
Проверки C принудительно включены также в Release. Дополнительно выполнены
AddressSanitizer/UndefinedBehaviorSanitizer и анализ GCC `-fanalyzer`.
Windows x64 собран MinGW; все 13 C-тестов и сценарии консоли/файлового хранения
также выполнены нативно в Windows. Готовая сборка размещена в `build/gas_analyzer_core.exe`.
Это набор инженерных проверок, не метрологические или сертификационные испытания.

## Что именно хранится

Настройки: для каждого канала профиль ID, модель версии 1, календарная дата калибровки
в Unix seconds (0 = не задана), температура, точки и политика тревог. Байтовый формат
SET1 — 400 байт. Таблицы температурных профилей остаются в реестре приложения;
их указатели/строки не записываются. Смена профиля требует нового ID/версии.

Эмулятор использует один файл 4096 байт:

| Смещение | Область | Два слота |
|---|---|---|
| 0 | Рабочие настройки | 2 × 512 байт |
| 1024 | Защищённая опорная копия | 2 × 512 байт |
| 2048 | Журнал | 2 × 1024 байт |

Заголовок каждого слота: magic GAS1, версия 1, sequence, длина, CRC32; затем payload
и нулевое заполнение. Последние 4 байта CMIT пишутся после тела и sync. CRC покрывает
всё тело с обнулённым полем CRC, но не CMIT. Следующая запись идёт в неактивный слот.
При повреждении обеих копий нет молчаливой подстановки заводских значений.

Настройки и журнал не являются общей транзакцией. Ошибка sync или контрольного чтения
после commit может означать, что новая запись уже сохранена: после такого ответа
нужно перечитать хранилище. При первой оборванной записи, если ещё нет ни одной
валидной копии, автоматического восстановления нет. Файловый адаптер использует
flush + fsync/_commit; это не доказательство поведения конкретной EEPROM при пропадании питания.
Файл рассчитан на одного писателя. Журнал сохраняется снимком, а не оптимизирован
по ресурсу перезаписи EEPROM. У core нет автоматической фоновой записи: её планирует адаптер.

## Контракт интеграции

1. Приложение задаёт каналы, подтверждённые профили и политики тревог, затем вызывает `analyzer_core_init`.
2. Температурный адаптер обновляет температуру, признак валидности и монотонное время в DeviceState.
3. Драйвер передаёт `AdcMeasurement` либо `ConcentrationMeasurement`. Цифровое значение —
   уже калиброванная концентрация, перед необязательными дальнейшими коррекциями.
4. Планировщик вызывает `analyzer_core_tick`/`device_supervisor_tick` регулярно независимо от UI,
   включая отсутствие новых данных. Часы uint32; шаги меньше 2^31 мс, допускается переполнение.
5. UI читает качество, final_value и тревоги. Не округлять/не «приклеивать» final_value ради экрана.
6. Сервисные операции и блокирующее файловое хранение не вызываются внутри измерительного tick.
   Для реальной платы нужны ограниченные по времени/асинхронные драйверы и измерение загрузки/стека.

Межгазовые правила в AnalyzerCore выключены по умолчанию. Приложение может явно
подключить проверенные правила; тогда неполный набор входов делает коррекцию невалидной,
а не выдаёт «норму без поправки». Эмулятор сохраняет отдельный демонстрационный режим:
при неполном наборе он сообщает о пропуске поправки. Это не политика готового прибора.

## Ограничения и следующий аппаратный этап

- Коэффициенты имеющихся температурных таблиц демонстрационные. Модель корректирует
  чувствительность, но не температурное смещение нуля. Для другого физического эффекта
  нужен подтверждённый профиль/алгоритм, а не произвольно подобранный полином.
- Настройки гистерезиса, задержек, фиксации и допустимой нестабильности калибровки должны
  быть утверждены для прибора. В эмуляторе задержки и гистерезис нулевые, фиксация выключена.
- Zero/span API протестирован на синтетических отсчётах. `cal` — ручной редактор таблицы,
  не автоматическая подача эталонного газа и не физическая процедура поверки.
- Эмулятор интерактивный и с виртуальным временем. Это не фоновый опрос USB-устройства.
- Самотест без обратной связи остаётся UNVERIFIED. Решение о допустимом ручном подтверждении
  и обязательных выходах требует схемы и продуктовых требований.
- STM32/HAL/AD7124, реальная температура, GPIO, заряд/питание, часы, EEPROM/Flash,
  аппаратный дисплей и кнопки не реализованы: в переданном описании точный MCU и плата ещё не выбраны.
- Для следующего этапа нужны точный MCU, схема аналоговых каналов и ADC (режим, масштаб,
  опорное напряжение), точная модель CO2, температурный датчик, память и схема оповещения.
- Затем: ресурс стека/RAM/Flash и износ памяти на целевой платформе, HIL/обрыв питания,
  реальные газовые смеси, температурная камера и фактическое время реакции.

Подключённый китайский аппарат не является целевой платой новой прошивки. Без этих
данных переносить в него получившееся ядро или выдавать модель за готовый газоанализатор нельзя.
