From 8a02704f8bb2deb1c72ae31ef8574b4bcb9594ae Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 30 Oct 2026 17:55:26 +0100 Subject: [PATCH] Document BLE startup sequencing and honor publication deadline --- doc/ble_transport.txt | 25 ++++++++++++++++++++++--- lib/ble/ble_winrt.cpp | 8 +++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/doc/ble_transport.txt b/doc/ble_transport.txt index 11a0199dc..d5873418a 100644 --- a/doc/ble_transport.txt +++ b/doc/ble_transport.txt @@ -290,21 +290,40 @@ payload_bytes — тело manufacturer data, manufacturer_ad_bytes включа company ID, AD type и length; это не размер полного пакета, сформированного Windows. Windows: проверка конкуренции GATT и manufacturer publisher на реальном адаптере: +Рабочий desktop передаёт initial_advertisement в ble_config до ble_start. Windows +сначала запускает publisher, проверяет событие Started и текущий Publisher.Status, +затем создаёт GATT-сервис/характеристики и запускает GATT-рекламу/scan. BLE_READY +выдаётся один раз, только после готовности GATT и scan. Без начального объявления +GATT/scan запускаются сразу. BlueZ/Android применяют начальные байты при готовности; +повтор тех же байтов в WinRT — no-op, без Stop/Start publisher. +Смена имени или включение объявления при работающем GATT временно останавливает +только GATT-рекламу, дожидается Stopped/Success либо Aborted/Success на Windows 1809, +обновляет publisher и возвращает GATT-рекламу после его Started. Существующие links +код не закрывает; доступность новых входящих в этот промежуток ограничена. Ошибка ОС +или таймаут публикации 20s переводит BLE в ошибку с причиной в GUI/логе. При выключении +объявления GATT-реклама сохраняется/восстанавливается. Изменения не касаются wire v4, +ACK, tx_window, RX-счётчиков и пакетирования звонков. +В рабочем логе ожидаются create GATT after publication enabled=1 publisher=2, +затем start GATT advertisement, service advertising state=2 и WinRT scan/GATT ready. + 1. Закрыть VibeChat и другие экземпляры probe на проверяемом ПК. 2. После обычной сборки chatgui перейти в tools/chatgui/build и запустить: .\ble_advertising_probe.exe Либо собрать отдельно цель ble_advertising_probe в lib/ble (CMake, Windows). 3. Приложить ble_advertising_probe.log из текущего каталога. -Утилита создаёт тот же GATT-сервис/характеристики, scan и 18-байтовое объявление probe18 +Утилита использует изолированный publisher, чтобы автоматическое согласование +публикаций рабочего backend не изменяло условия эксперимента. Она создаёт тот же +GATT-сервис/характеристики, scan и 18-байтовое объявление probe18 текущей wire-версии. Входящие подключения отклоняются: это тест обнаружения, не чат. Три окна по 20 секунд: gatt_on, gatt_off, gatt_restored. Можно передать длительность каждого окна 10..60 секунд единственным аргументом; startup ограничен ещё 20 секундами. Publisher, payload и scan остаются теми же; меняется только реклама GATT-сервиса. -Только в probe явно запрошенная остановка принимает Stopped/Success и Aborted/Success: +Явно запрошенная остановка принимает Stopped/Success и Aborted/Success: последний ответ наблюдается на Windows 1809. Подтверждение пишется как requested GATT stop confirmed; без события остановки один снимок статуса не завершает этап gatt_off. При восстановлении требуется новое событие Started. Ненулевой BluetoothError и Aborted -без запроса остановки остаются фатальными. Обработчик обычного чата этим не изменён. +без запроса остановки остаются фатальными. Рабочий backend использует то же правило +при замене publisher; экспериментальное ручное переключение остаётся только в probe. В result: количество наблюдений Started/Waiting при нужном состоянии GATT и работающем scan, unsettled_samples (переходные состояния), задержка первого Started и конечные состояния ОС. first_started_ms имеет смысл только при started_samples>0. diff --git a/lib/ble/ble_winrt.cpp b/lib/ble/ble_winrt.cpp index ca815dacd..d805fab36 100644 --- a/lib/ble/ble_winrt.cpp +++ b/lib/ble/ble_winrt.cpp @@ -175,7 +175,12 @@ struct WinState : std::enable_shared_from_this { s.discovery_stats("periodic"); s.publication_timeout(); if (s.stopped || s.failed) return; - s.diagnostics_timer = uasync_set_timeout(s.ua, 100000, &s, diagnostics_tick, "ble_winrt_diagnostics"); /* 10s, TB=0.1ms. */ + uint64_t delay = 100000; /* Сводка раз в 10s, но deadline publisher обслуживается без лишних 10s ожидания. TB=0.1ms. */ + if (s.publication_deadline) { + auto now = get_time_us(); + delay = std::min(delay, s.publication_deadline > now ? (s.publication_deadline - now + 99) / 100 : uint64_t(1)); + } + s.diagnostics_timer = uasync_set_timeout(s.ua, delay, &s, diagnostics_tick, "ble_winrt_diagnostics"); if (!s.diagnostics_timer) DEBUG_WARN(CAT, "BLE WinRT diagnostics timer allocation failed; periodic summaries unavailable"); } static void dispatch(void* arg) { @@ -305,6 +310,7 @@ struct WinState : std::enable_shared_from_this { /* Первичная регистрация — только после Started publisher либо при выключенном объявлении. */ void ensure_service() { if (!adapter_ready || failed || stopped || service_stop_pending) return; + if (broadcast_enabled && (publication_pending || publisher_status != int(BluetoothLEAdvertisementPublisherStatus::Started))) return; if (!server_created) { server_created = true; DEBUG_INFO(CAT, "BLE WinRT create GATT after publication enabled=%d publisher=%d", broadcast_enabled, publisher_status);