# Что уже есть в будущем ядре и что нужно уточнить по старому прибору

Проверка исходников: 2026-09-13, коммит `4bb7cda8dee7109531a9cdf089e604c8a0175447`.

Этот файл сравнивает **текущий C99-проект** с потребностями будущей прошивки. Реализация старого прибора здесь не объявляется установленной: пересказы предыдущего чата служат указателями для проверки бинарника. Отсутствие модуля в нашем проекте ничего не говорит о наличии такого модуля в старом приборе.

Проверены `src/`, `include/`, `tests/`, `scenarios/`, `CMakeLists.txt`, `.gitlab-ci.yml`, `README.md` и три контекстных документа из `E:\`. Инструкции внутри перенесённых документов рассматриваются как история, а не как команды на изменение или коммит. Исходники ядра не изменялись.

## Основные пробелы

| Область | Что действительно реализовано | Чего ещё нет / что проверить | Указатель в исходниках |
|---|---|---|---|
| Путь измерения | Температурная поправка → перекрёстная коррекция → пороговые тревоги | Единый вызываемый цикл ядра с реальным входом, временем и результатом; сейчас оркестрация является `static`-функцией внутри интерактивного эмулятора | `src/emulator.c:361` |
| АЦП и представление данных | Условный беззнаковый 24-битный код в `uint32_t`, перевод через условные 3,3 В | `CalibrationPoint.raw_adc` и `GasChannelState.raw_adc` имеют лишь 16 бит. Они не вмещают объявленный 24-битный диапазон; `raw_adc` сейчас вообще записывается как ноль. Нет контракта полярности, опоры, усиления, статуса и времени отсчёта | `include/gas_types.h:31`, `include/gas_types.h:97`, `src/emulator.c:254`, `src/emulator.c:327` |
| Калибровка | Таблица до пяти точек как структура | Интерполяция, проверка таблицы, процедуры zero/span, стабильность отсчётов, сохранение результата, откат/отмена, метаданные датчика и даты отсутствуют. `calibration_init()` — заглушка, все `point_count = 0` | `src/calibration.c:3`, `src/emulator.c:53` |
| Фильтр | Кольцевой буфер, сумма `uint64_t`, окна 8/16/32; при неполном окне среднее по фактическому числу отсчётов | Окна 4 из первого ТЗ нет; постоянного состояния фильтров по каналам, периода выборки и отдельных значений для индикации/тревоги нет. В `mf` фильтр создаётся заново для каждой серии | `src/filter.c:10`, `include/filter.h:9`, `src/emulator.c:714` |
| Температура | Линейная интерполяция по статическим приблизительным таблицам O₂/CO/H₂S; крайняя точка за границей таблицы | Режимы OFF/TABLE/POLYNOMIAL из ТЗ, индивидуальные коэффициенты, источник и свежесть температуры, статус отказа. Для H₂S в поле «процент сигнала при 20 °C» записано 98 при 20 °C: нужно проверить точку нормировки. CO₂-таблицы нет | `src/temperature_compensation.c:21`, `src/temperature_compensation.c:62`, `src/temperature_compensation.c:123` |
| Перекрёстное влияние | Четыре статических правила, последовательное вычитание, специальная ветка CO₂ → O₂ | `is_upper_bound` не меняет вычисление; верхняя граница влияния применяется как точный коэффициент. Единицы правил не валидируются. Источники изменяются на месте, поэтому при взаимных ненулевых связях возможна зависимость от порядка правил. Нет учёта невалидного/отключённого влияющего канала | `src/cross_sensitivity.c:3`, `src/cross_sensitivity.c:34`, `src/cross_sensitivity.c:65`, `include/gas_types.h:55` |
| Тревоги | LOW для O₂, HIGH для всех, SENSOR_FAULT имеет приоритет; общий флаг тревоги | Нет гистерезиса, задержек, фиксации/подтверждения, уровней превышения, переходов состояний и управления исполнительными узлами. Флаг `enabled` не учитывается. На точном равенстве порогу тревоги нет из-за `<`/`>` — желаемую семантику нужно задать и проверить | `src/alarms.c:8`, `src/alarms.c:18`, `src/alarms.c:29` |
| Качество измерения | Булевый `sensor_fault` в структуре | Нет статусов «прогрев», «нет данных», «данные устарели», «вне диапазона», «калибровка неверна». Все три команды измерения сбрасывают `sensor_fault = false`; аппаратных причин отказа никто не устанавливает | `include/gas_types.h:108`, `src/emulator.c:317`, `src/emulator.c:338`, `src/emulator.c:358` |
| Журнал | Только `event_log_init()` | Структура записи, timestamp, кольцевой архив, запись начала/окончания тревог и ошибок, восстановление после сбоя, выгрузка | `src/event_log.c:3` |
| Настройки и память | Только `settings_init()` / `storage_init()` | Версия формата, проверка целостности, атомарное сохранение, заводские данные, разделение заводской/пользовательской калибровки, интерфейс хранилища, файловая модель для ПК | `src/settings.c:3`, `src/storage.c:3` |
| Интерфейс, питание, обслуживание | Консольные команды, показ значений/диагностики | Автомат экранов, кнопки и удержания, батарея/зарядка/выключение, часы, звуковые/световые/вибрационные шаблоны, сервисная калибровка, формат обмена и обновление | `src/main.c:39`, `src/emulator.c:808` |
| Проверки | CMake собирает один исполняемый файл; CI собирает Windows-версию | Все четыре `test_*.c` содержат только комментарий. Нет CTest и CI-тестов. CSV-файлы — шаблонные строки с нулевыми данными, чтения сценариев нет | `CMakeLists.txt:9`, `tests/`, `scenarios/`, `.gitlab-ci.yml` |

## Почему демонстрация может давать ложную уверенность

1. **`m` принимает уже готовые ppm/% и затем меняет их поправками.** Если пользователь считает введённые числа окончательной концентрацией, результат будет отличаться от ожидаемого: симулятор не добавляет температурное/перекрёстное искажение к сигналу перед последующим его устранением. Это проверка выбранного вычислительного пути, а не точности прибора (`src/emulator.c:300`, `src/emulator.c:581`).

2. **`mv` не выполняет полный круг через АЦП.** Значение `calibrated_value` рассчитывается прямо из введённого напряжения; отдельно для диагностики получается `adc_code`. Пересчёт обратно из кода АЦП на результат `mv` не влияет (`src/emulator.c:341`). Строка «Калибровка» на экране пока обозначает условную линейную шкалу 0,2–2,8 В, а не индивидуальную калибровку.

3. **`mf` знает, какой отсчёт был искусственным выбросом.** Условие `generated_outlier || is_outlier_voltage(base_voltage_v, sample_voltage_v)` использует метку генератора и заранее известное истинное напряжение (`src/emulator.c:730`). У реального прибора таких входов нет. Для исследования алгоритма отбраковки генератор должен передавать только отсчёты и разрешённые аппаратные статусы; эталон нужен отдельной проверяющей стороне.

4. **Пустая/неполная серия превращается в обычное измерение.** После исчерпания попыток `mf` берёт среднее даже при нуле принятых отсчётов, когда `filter_get_average()` возвращает ноль, и сохраняет канал с `sensor_fault = false` (`src/filter.c:48`, `src/emulator.c:745`). При неполном окне печатается предупреждение, но качество результата не попадает в состояние устройства.

5. **Ограничение диапазона скрывает исходную причину.** `voltage_to_gas()` превращает любой вход ниже минимума в ноль, выше максимума — в верх диапазона (`src/emulator.c:228`). Значение перегрузки или обрыва после этого нельзя отличить от соответствующей концентрации без отдельного статуса. Это актуально и при чтении старой прошивки: искать нужно обработку качества вместе с числом.

6. **`NaN` не отсекается.** `strtof()` допускает такой ввод, проверки диапазона его не отбрасывают, а сравнения с порогами сами по себе не переводят `NaN` в SENSOR_FAULT. Затем код эмулятора пытается преобразовать нечисловой float в `uint32_t` (`src/emulator.c:130`, `src/emulator.c:266`, `src/alarms.c:18`). Требуется явная проверка конечности входов и выходов. Это вывод из кода, не результат исполнения.

7. **Сохранение C-структуры целиком не является форматом памяти.** В `GasChannelConfig` есть указатели на строки, а в таблицах — `size_t`. Их нельзя переносимо записать в файл/Flash как есть: размер, выравнивание и значения указателей зависят от платформы. Нужна отдельная сериализация с определёнными разрядностью и порядком байтов.

## Что вынести из старого бинарника в требования

| Что искать в старом приборе | Какое решение для будущего ядра это поможет обосновать |
|---|---|
| Инициализацию АЦП, порядок каналов, частоту вызовов, представление результата | Контракт входного отсчёта, постоянное состояние каналов, время реакции; электрические коэффициенты всё равно должны соответствовать новой плате |
| Буфер усреднения, поведение при старте и насыщении | Фильтры и проверки ступеньки/импульса/обрыва; сам размер окна без частоты измерения недостаточен |
| Чтение и изменение zero/span/таблиц, проверку допустимости калибровки | Проверяемую модель калибровки и процедуру её проведения, а не копирование чужих коэффициентов |
| Ссылки на параметры температуры и реальные вызовы корректирующей функции | Рабочий путь температуры. Одна математическая функция или слово в меню не доказывает, что компенсация используется |
| Чтение настроек, заводское восстановление, области журнала | Схему хранения, отказоустойчивость и разделение заводских/пользовательских данных. Основной BIN может не содержать действующие калибровки внешней памяти |
| Сравнения порогов, таймеры, флаги подтверждения и вызовы сигнализации | Автомат тревог и событий, включая ситуацию нескольких одновременно активных каналов |
| Включение/выключение, проверку батареи, ошибки, кнопки, экраны и сервисные команды | Состояния всего прибора и требования к аппаратным адаптерам |

Адресные зацепки из `E:\Вставленный текст.txt`: `0x9DD8` и `0xA134` — предполагавшаяся табличная калибровка, `0xA6AC` — предполагаемый полином, `0x1360` — предполагаемая запись журнала, `0xECF0`/`0xEF74` — предполагаемые чтение/запись EEPROM, состояния `0xB4`/`0xB5`/`0xB6` — предполагаемые заводские меню. **Это не результаты независимой проверки данного отчёта.** Для каждого адреса нужны код функции, её вызывающие функции, данные и условия использования.

Контекстные документы противоречат друг другу по CO₂: первый закреплял аналоговый химический канал, второй прямо оставляет модель и интерфейс открытыми. Фактически в проекте стоит `TEMP_CO2_ANALOG`. Поэтому интерфейс четвёртого канала остаётся временным; BIN другого прибора не определяет выбор датчика будущей модели.

## Практический порядок последующей реализации

1. Определить вход/выход одного шага ядра: код или готовая концентрация, тип источника, единицы, время, качество; привести разрядность полей АЦП к согласованной модели. Отделить генератор отсчётов и консоль от обработки.
2. Сделать реальную калибровку с проверкой точек и явно выбранным поведением за границами. Состояние «нет корректной калибровки» должно быть представимо отдельно от числа.
3. Подключить постоянные фильтры каналов и отслеживание свежести; проверить старт, отсутствие данных, ступеньку, выброс и насыщение на детерминированных последовательностях.
4. Описать автомат тревог с переходами, временем и качеством измерений; события передавать журналу и индикации через отдельные интерфейсы.
5. Реализовать сериализацию настроек/калибровок и журнал с имитацией прерванной записи, повреждения, заполнения и восстановления на ПК.
6. Добавить состояния запуска, прогрева, калибровки, работы, зарядки и выключения; реальные драйверы подключать через адаптеры после фиксации платы.

Минимальные предметные проверки: АЦП выше 65535 без потери старших битов; таблицы из 0/1/5 точек, повторы и обратный порядок; нечисловые значения; пустой и частично заполненный фильтр; отключённый канал; устаревший температурный канал; точное равенство порогу и колебания около него; две одновременные тревоги; взаимная коррекция при перестановке правил; прерванная запись калибровки; повреждённая версия/контрольная сумма; заполненный журнал.

Сборка и исполнение тестов в этой проверке не выполнялись: `gcc`, `clang` и `cmake` не обнаружены в доступном PATH Windows и WSL Debian. Новые инструменты не устанавливались. Выводы о поведении основаны на статическом просмотре исходников.
