# HTTP-канал управления RF-001 Текущее состояние: **HTTP-КАНАЛ РАБОТАЕТ; ВЕРСИОННЫЙ МЕХАНИЗМ ОБНОВЛЕНИЯ И НЕБЛОКИРУЮЩИЙ `STAIRCASE_SEARCH` ПРОВЕРЕНЫ БЕЗ НОВОГО ДОСТУПА К РАДИО**. Канал заменяет Git как транспорт между работающими компьютерами. Git остаётся для исходного кода и истории. Старые watcher-ы сохранены как резервный вариант. ## Граница этапа 1 Реализованы: - JSON-сервер на основном ПК; - исходящее подключение RX-агента с ноутбука к основному ПК; - подпись каждого запроса HMAC-SHA256; - защита от повторного использования запроса по времени и nonce; - ограничение адреса RX-агента на сервере; - фиксированные задачи `INVENTORY`, `OFFLINE_VERIFY`, `RX_CAPTURE_START`, `RX_CAPTURE_STATUS`, `CAPTURE_DECODE`, `CAPTURE_DIAGNOSTICS` и `STAIRCASE_SEARCH` и `UPDATE_AGENT`; - чтение `hostname`, `whoami`, состояния Git и `hackrf_info`; - сохранение результата на основном ПК; - обязательное поле `rf_tx = 0` во всех сообщениях. На RX-ноутбуке 23 сентября 2026 года автономная проверка завершилась так: - ветка `video-development`; - HEAD `a94f2db4ee8377201a97263166cb09431df5f5d6`; - 100 CRC-корректных пакетов из 100; - 100 точных пакетов из 100; - `hardware_accessed = false`; - ошибок нет; - `rf_tx = 0`. В сеансе `RF001A_20260925T125829Z_227EADB4` уже были выполнены: - один конечный RX-захват с фиксированным профилем; - проверка READY по фактическому PID, обнаруженному CLKIN и растущему файлу; - чтение итогового состояния захвата; - потоковое декодирование принятого IQ; - полный потоковый поиск эталонной лестницы без обращения к SDR. Новые захваты и передачи не входят в текущее состояние и требуют отдельного явного разрешения. Завершённый поиск лестницы сохраняет исходный результат `NOT_DETECTED`; последующая диагностика должна записываться отдельно и не подменять этот результат. Не входят в управляющий канал: - запуск `hackrf_transfer` в режиме TX; - команда или сетевой метод RF TX; - изменение firmware, CPLD, USB-драйвера или Zadig; - commit и push. Для сервера и RX-агента подготовлен пользовательский автозапуск через Планировщик заданий Windows. Службы Windows и права администратора для этого не нужны. Сервер и агент работают постоянно после входа соответствующего пользователя в Windows. Агент не содержит произвольной shell-команды. ## Схема ```text ОСНОВНОЙ ПК 192.168.255.185:8765 HTTP JSON server очередь только фиксированных типов заданий ^ | исходящее соединение с подписью запроса | RX-НОУТБУК 192.168.255.56 polling agent hostname / whoami / Git / hackrf_info / offline 100/100 RF TX = 0 ``` Сервер не раздаёт каталоги и произвольные пути. Он может выдать только заранее зарегистрированный архив агента с точным `release_id` через ограниченный маршрут обновлений. Произвольной shell-команды в протоколе нет. Неизвестный тип задания и любое значение `rf_tx`, отличное от нуля, отклоняются. ## Файлы - `tools/rf001_http_control.py`: сервер, локальная очередь и клиент управления; - `tools/rf001_rx_http_agent.py`: RX-агент с фиксированной инвентаризацией; - `tools/rf001_offline_decode.py`: фиксированный программный `legacy`-декодер; - `tools/rf001_staircase_search.py`: потоковый поиск эталонной лестницы без обращения к SDR; - `tools/rf001_staircase_job.py`: фиксированный дочерний процесс длительного поиска и сохранение результата до сетевого подтверждения; - `tools/rf001_agent_update.py`: строгая проверка состава и распаковка версионного архива; - `tools/rf001_agent_launcher.py`: стабильный запускатель, переключение версии и локальный откат при неудачном запуске; - `tools/rf001_build_agent_packages.py`: воспроизводимая сборка выпусков и первоначального пакета без включения секрета; - `tools/rf001_rx_capture.py`: жёсткие RX-параметры и проверки READY/COMPLETE; - `tools/rf001_capture_runner.py`: один конечный фоновый RX-процесс и журнал; - `.local/rf001_http_token.txt`: общий секрет вне Git; - `.local/rf001_http_server_state.json`: локальное состояние вне Git. ## Подготовка общего секрета На основном ПК из корня проекта один раз выполнить: ```powershell python -B tools\rf001_http_control.py init-token ``` Команда не перезаписывает существующий секрет. Файл `.local\rf001_http_token.txt` надо скопировать на RX-ноутбук по доверенному каналу и не добавлять в Git. Сервер и агент должны читать одинаковое содержимое. ## Запуск сервера на основном ПК ```powershell python -B tools\rf001_http_control.py serve ` --bind 192.168.255.185 ` --port 8765 ` --allowed-agent-ip 192.168.255.56 ``` Ожидаемый стартовый вывод: ```text SERVER = http://192.168.255.185:8765 ALLOWED AGENT IP = 192.168.255.56 TASK KINDS = INVENTORY, OFFLINE_VERIFY, RX_CAPTURE_START, RX_CAPTURE_STATUS, CAPTURE_DECODE, CAPTURE_DIAGNOSTICS, STAIRCASE_SEARCH, UPDATE_AGENT RF TX = 0 ``` Действующее правило Windows Firewall должно оставаться ограниченным программой Python, TCP-портом `8765`, локальным адресом `192.168.255.185`, удалённым адресом `192.168.255.56` и беспроводным интерфейсом. ## Постановка задания на основном ПК ```powershell python -B tools\rf001_http_control.py enqueue-inventory --agent-id user-pc ``` Это локальная операция. Сервер принимает её только от собственного адреса и с правильной подписью. Задание не содержит произвольной команды. ## Автозапуск агента на RX-ноутбуке Первоначальный пакет содержит `INSTALL_RX_AGENT.cmd`. После распаковки его надо запустить один раз. Установщик проверяет HMAC-манифест существующим секретом, размеры и SHA256 всех файлов, сохраняет прежнюю установку и XML задания, а затем меняет только действие существующего пользовательского задания `SDR Rover RX Agent`. Пользователь, триггеры, параметры и уровень прав задания сохраняются. Ожидаемый итог: ```text BOOTSTRAP_INSTALL=COMPLETE TASK_STATE=Running AGENT_VERSION=2026.09.29.1 ARBITRARY_SHELL=DISABLED RF_TX=0 ``` После этого ручной запуск на ноутбуке для штатных обновлений не требуется. Запускатель хранит выпуски в отдельных каталогах, проверяет запуск по PID, версии и одноразовой метке и при сбое возвращается к предыдущему локальному выпуску. Очередь MAIN, IQ, эталоны, результаты, конфигурация и секрет находятся вне каталога конкретной версии. ## Модель доверия обновлений Манифест каждого выпуска подписывается `HMAC-SHA256` из стандартной библиотеки Python тем же общим секретом, которым уже подписываются HTTP-запросы. Подпись охватывает отдельный домен `RF001-UPDATE-MANIFEST-V1`, `release_id`, версию агента, совместимую версию протокола, размер и SHA256 архива и хеш внутреннего манифеста. Разрешение MAIN дополнительно привязано к `agent_id` и сроку действия. Сам секрет в ZIP не включается и при установке не заменяется. Ограничение модели: общий симметричный секрет находится и на MAIN, и на RX-ноутбуке. Компрометация одного из этих узлов позволяет создавать корректные HMAC-подписи. Аппаратного корня доверия и независимой издательской подписи у этого контура нет. Перед переключением агент скачивает архив не более двух раз за одну сохранённую попытку обновления, проверяет подпись, размер, SHA256, точный список файлов, хеш каждого файла, допустимость путей, предел распакованного объёма, совместимость и свободное место. Затем выполняется программная самопроверка без SDR. Если агент занят локальной задачей, обновление остаётся в состоянии `WAITING_FOR_IDLE`. Наличие файлов само по себе не считается установкой: фактическую версию MAIN получает из следующего сообщения работающего агента. ## Поиск эталонной лестницы `STAIRCASE_SEARCH` принимает только идентификатор существующего сеанса и ожидаемые SHA256 RX-файла и эталона. Агент сам строит пути внутри `%USERPROFILE%\Documents\SDR_Rover_Runtime`: запись берётся из каталога `rx_capture`, а эталон — из отдельного каталога `references`. Сетевой запрос не может передать путь или команду. Перед запуском агент проверяет оба SHA256. Отчёт сохраняется рядом с записью под именем `staircase_search_report.json`. Если подходящий отчёт уже существует, он проверяется и возвращается без повторного анализа и без перезаписи. Для задачи всегда заданы `hardware_accessed = false`, `rf_tx = 0` и `automatic_retry = false`. Поиск выполняется отдельным фиксированным процессом. Агент продолжает опрос сервера и сообщает фактическую фазу, число обработанных комплексных отсчётов и общий объём. Эти значения берутся из потокового анализатора, а не оцениваются по времени. Активная аренда продлевается даже после истечения обычного короткого тайм-аута. Указатель задачи записывается до запуска процесса, поэтому перезапуск агента не создаёт второй анализатор. Готовый результат остаётся на диске до подтверждения MAIN и после обрыва сети отправляется без повторного вычисления. ## Диагностический однократный запуск агента Команду выполнять из фактического клона `SDR_Rover_Video` на ноутбуке. Пути к репозиторию, секрету и `hackrf_info.exe` надо подставить по результатам инвентаризации ноутбука: ```powershell python -B tools\rf001_rx_http_agent.py ` --server http://192.168.255.185:8765 ` --token-file <путь-к-rf001_http_token.txt> ` --agent-id user-pc ` --repository <путь-к-SDR_Rover_Video> ` --hackrf-info <путь-к-hackrf_info.exe> ` --hackrf-clock <путь-к-hackrf_clock.exe> ` --hackrf-transfer <путь-к-hackrf_transfer.exe> ` --once ``` Без `--once` агент работает постоянно. Этот ручной режим нужен только для диагностики; при установленном автозапуске его не используют. ## Просмотр результата на основном ПК ```powershell python -B tools\rf001_http_control.py status ``` Для завершённой инвентаризации сервер показывает состояние задания `COMPLETE` или `FAILED`, фактические результаты команд и `rf_tx = 0`. ## Автономная проверка 100/100 После подтверждения одинакового HEAD на обоих компьютерах основной ПК ставит фиксированное программное задание: ```powershell python -B tools\rf001_http_control.py enqueue-offline-verify ` --agent-id user-pc ` --expected-head a94f2db4ee8377201a97263166cb09431df5f5d6 ``` Агент сверяет ветку и HEAD чтением `.git`, поэтому `git.exe` для этой проверки не нужен. Затем он запускает только два заранее заданных проектных сценария: создание детерминированной RF-001A волны и её программное декодирование через встроенный `legacy`-декодер, не требующий Numba. Рабочие файлы сохраняются вне Git в `Documents\SDR_Rover_Runtime\offline_verify`. Успех требует ровно 100 CRC-корректных и 100 точных пакетов. HackRF при этом не открывается, `hardware_accessed = false`, `rf_tx = 0`. ## Подготовленный RX-захват Сервер не примет постановку RX-захвата без точной локальной фразы `AUTHORIZE RF RX`. До отдельного разрешения эту команду не выполнять: ```powershell python -B tools\rf001_http_control.py enqueue-rx-capture ` --agent-id user-pc ` --expected-head a94f2db4ee8377201a97263166cb09431df5f5d6 ` --authorize-rx "AUTHORIZE RF RX" ``` Агент перед захватом проверяет: - ветку и HEAD без обязательного наличия `git.exe`; - отсутствие конфликтующих SDR-процессов; - серийный номер RX `000000000000000097c063dc2e5327d3`; - строку `clock signal detected` от `hackrf_clock.exe`; - не менее `6000000000` свободных байт; - неизменность частоты `1400000000` Гц, частоты дискретизации `8000000` отсчётов/с, LNA/VGA `24/24` дБ, выключенных RF amp и antenna bias. Для ручного барьера TX захват длится 300 секунд: `2400000000` комплексных отсчётов, ожидаемый файл `4800000000` байт. Значение 20 секунд в исходном профиле проверяется как часть исходных данных, но управляющий контур расширяет окно до 300 секунд. Это зафиксировано в журнале сеанса. Автоматического повтора нет. Фоновый процесс запускает фиксированный Python-runner. Старый `capture_process_runner.ps1` и Git watcher-ы не изменены и остаются резервом. Состояние конкретного сеанса запрашивается отдельной фиксированной задачей: ```powershell python -B tools\rf001_http_control.py enqueue-rx-status ` --agent-id user-pc ` --session-id ``` TX разрешён только при свежем результате `READY`, открытом окне захвата и после точной отдельной фразы `AUTHORIZE RF TX`. В сетевом протоколе операции TX нет. После завершения захвата сервер может поставить потоковое декодирование с тремя фактическими временами. Отчёт и IQ остаются на RX-ноутбуке вне Git. ## Текущее продолжение На RX-ноутбуке работает версия агента `2026.09.29.2`; штатное обновление через подписанный HTTP-канал и полный `STAIRCASE_SEARCH` завершены. Дальнейшая работа с существующим сеансом является только потоковой офлайн-диагностикой сохранённой IQ-записи. Новый RX-захват и любой RF TX требуют нового отдельного разрешения; разрешения, использованные в завершённом сеансе, повторно не применяются.