diff --git a/doc/ble_transport.txt b/doc/ble_transport.txt index c7e2fbab..467cbd4e 100644 --- a/doc/ble_transport.txt +++ b/doc/ble_transport.txt @@ -208,14 +208,15 @@ test_ble_bluez: отдельный dbus-run-session с подставным Blue test_ble_winrt (Windows): объявления с настоящим QueryInterface без EventArgs2 (1809) и с EventArgs2 (2004), сохранение адреса/типа; настоящий mailbox и hresult_error без радио; исключение одного link не останавливает другого, ошибка radio прекращает доставку batch, -shutdown отменяет posted_task и поздние callbacks. Тест можно запускать в Wine; +shutdown отменяет диагностический таймер, posted_task и поздние callbacks. Тест можно запускать в Wine; он не проверяет драйвер, доступность Bluetooth API и физическую передачу. ble_probe 3: ручная проверка реального радио (scan, GATT registration, публикация и замена тестового manufacturer-объявления); не подключается к чужим устройствам. Успех требует READY радио, первоначальной и обновлённой публикации. Одного scan/GATT ready недостаточно. Для диагностики ожидания ресурсов: ble_probe 15. Логи: discovery=debug. INFO — состояния и режим DATA; DEBUG — подписки и сводка трафика; -WARN/ERROR — причины отброса/отказа. Содержимое кадров/объявлений не выводится. +WARN/ERROR — причины отброса/отказа. Для объявлений выводятся заголовок/версия и node_id; +полный payload не выводится. Отладка Bluetooth на Windows --------------------------- @@ -233,6 +234,32 @@ INFO: семейство/версия Windows (major.minor.build.revision и Dev само отсутствие нового интерфейса не переводит radio в failed. Waiting и Stopping publisher имеют разные причины состояния; Waiting означает ожидание ресурсов публикации. +Если Waiting длится не менее 10 секунд, ближайшая периодическая сводка выдаёт WARN +один раз за этот период ожидания; последующие сводки содержат waiting_ms. +Выход из Waiting пишет длительность и новое состояние. Это диагностика, без +автоматического перезапуска или изменения политики публикации/сканирования. + +При пустом списке устройств смотреть две сводки discovery=debug каждые 10 секунд +и при остановке (счётчики накопительные, включая нулевой приём): +- BLE WinRT scan totals: events — все callbacks watcher, no_manufacturer — нет + manufacturer-полей, other_company — нет нужного company_id, matching_events — + события с нужным company_id, forwarded_fields — переданные общему слою поля, + oversized_fields — поля длиннее BLE_BROADCAST_MAX. Одно событие может содержать + несколько полей; Windows callbacks обновляют счётчики параллельно со снимком. + publisher_state — последнее событие состояния (-1: publisher ещё не создан). +- BLE discovery totals: received — поступившие в driver поля, accepted — + добавления/обновления соседа, self — собственный node_id, full — нет места; + отдельные счётчики неверных аргументов/длины/заголовка/версии/ID/UTF-8. + +BLE discovery packet показывает endpoint, RSSI, длину, первые два байта header +(ожидается 5643), принятую version (-1: байта нет), expected и конкретный reason. +Причины: accepted, self-node-id, neighbor-table-full, invalid-argument, +invalid-length, foreign-header, version-mismatch, zero-node-id, invalid-utf8. +Первые три случая каждой причины за жизнь driver пишутся в WARN (отказ) либо DEBUG +(приём/свой ID), все остальные — в TRACE и в счётчики. oversized в WinRT ограничен +аналогично. При ошибке decode peer=0: частичный результат не используется. +version-mismatch требует сравнить версии сборок обоих участников; это не ошибка +радиодрайвера. events>0 сам по себе не означает приём объявления VibeChat. DEBUG: адаптер (BLE, central/peripheral, extended advertising, поддержка 2M/Coded), этап/результат каждой служебной async-операции, состояния рекламы и сканирования, diff --git a/lib/ble/ble_winrt.cpp b/lib/ble/ble_winrt.cpp index 406ea12d..13fa03e6 100644 --- a/lib/ble/ble_winrt.cpp +++ b/lib/ble/ble_winrt.cpp @@ -148,7 +148,7 @@ struct WinState : std::enable_shared_from_this { auto& s = *static_cast(arg); s.diagnostics_timer = nullptr; s.discovery_stats("periodic"); if (s.stopped) return; - s.diagnostics_timer = uasync_set_timeout(s.ua, 10000, &s, diagnostics_tick, "ble_winrt_diagnostics"); + s.diagnostics_timer = uasync_set_timeout(s.ua, 100000, &s, diagnostics_tick, "ble_winrt_diagnostics"); /* 10s, TB=0.1ms. */ if (!s.diagnostics_timer) DEBUG_WARN(CAT, "BLE WinRT diagnostics timer allocation failed; periodic summaries unavailable"); } static void dispatch(void* arg) { diff --git a/tools/cgathui_common/ble_etcp.c b/tools/cgathui_common/ble_etcp.c index 7fbe288c..ec3d11bf 100644 --- a/tools/cgathui_common/ble_etcp.c +++ b/tools/cgathui_common/ble_etcp.c @@ -53,6 +53,7 @@ struct ble_etcp { struct ble_neighbor neighbors[BLE_NEIGHBORS_MAX]; uint64_t broadcast_received, broadcast_accepted, broadcast_self, broadcast_full; uint64_t broadcast_invalid[1 - BLE_IDENTITY_ERR_UTF8]; /* Индекс — минус код decode; счётчики за жизнь driver. */ + uint64_t broadcast_stats_us; /* Последняя сводка; основной tick остаётся раз в секунду. */ uint64_t retry[BLE_NEIGHBORS_MAX]; struct ble_etcp_link* links[BLE_LINKS_MAX]; ble_link_id rejected[BLE_LINKS_MAX]; /* Закрыть вне BLE callback при отказе выделения ctx. */ @@ -536,8 +537,8 @@ static void run(void* arg) { } static void tick(void* arg) { struct ble_etcp* d = arg; d->timer = NULL; - broadcast_stats(d, "periodic"); uint64_t now = get_time_us(); + if (now - d->broadcast_stats_us >= 10000000) { broadcast_stats(d, "periodic"); d->broadcast_stats_us = now; } for (int i = 0; i < BLE_NEIGHBORS_MAX; i++) { struct ble_neighbor* n = &d->neighbors[i]; if (n->identity.node_id && now - n->seen_us > BLE_NEIGHBOR_TTL_US) { @@ -556,6 +557,7 @@ struct ble_etcp* ble_etcp_create(struct UASYNC* ua, struct UTUN_INSTANCE* inst, struct ble_etcp* d = u_calloc(1, sizeof(*d)); if (!d) { DEBUG_ERROR(CAT, "BLE driver allocation failed"); return NULL; } d->ua = ua; d->instance = inst; d->observer = *cfg; + d->broadcast_stats_us = get_time_us(); struct ble_config c = *cfg; c.arg = d; c.callbacks = (struct ble_callbacks){broadcast, status, advertising, validate, connection, received, writable, invite_received, invite_writable}; if (inst) c.tx_limit = 1;