Require BLE probe publication and document WinRT diagnostics

This commit is contained in:
evgeny committed 2026-10-29 22:42:36 +01:00
1 parent 4a7f3253f6
commit 33a3774938
2 files changed
+47 -10

No files matched your search

+28 -3
View File
@@ -169,8 +169,10 @@ Windows выбирает PHY с peer. Отсутствие/отказ API не
Перед остановкой uasync снять источники событий, отменить операции и posted_task.
WinRT может сохранять физический ACL для других сервисов. Гарантия close относится
к нашей сессии и ресурсам; принудительный разрыв общего ACL в API не обещается.
Нужен адаптер с central+peripheral и Windows с GATT server API/BytesSent
(Windows 10 1709+); версия ОС сама по себе поддержку драйвером не гарантирует.
Нужен адаптер с central+peripheral и Windows 10 2004 / build 19041 или новее:
помимо GATT server API/BytesSent требуется BluetoothAddressType принятого объявления.
Наличие свойства проверяется при старте, интерфейса EventArgs2 — на фактическом событии;
отсутствие даёт явную причину отказа. Версия ОС сама по себе поддержку драйвером не гарантирует.
Радио Windows необходимо проверить на реальном Windows-ПК; Wine этого не заменяет.
Сборка и проверка
@@ -188,8 +190,14 @@ test_ble_transport: реальные common transports с управляемым
test_ble_bluez: отдельный dbus-run-session с подставным BlueZ; настоящее
экспортирование сервиса/объявлений, два AcquireNotify fd, адресные подтверждения,
приём кадров и независимое закрытие. К системному Bluetooth тест не обращается.
test_ble_winrt (Windows): настоящий mailbox и hresult_error без радио; исключение
одного link не останавливает другого, ошибка radio прекращает доставку batch,
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 — причины отброса/отказа. Содержимое кадров/объявлений не выводится.
@@ -201,16 +209,33 @@ WARN/ERROR — причины отброса/отказа. Содержимое
Ранние ошибки подготовки INI всегда пишутся в chatgui.log до чтения настроек лога;
их точные причины также показаны в окне ошибки независимо от фильтра.
INFO: семейство/версия Windows (DeviceFamilyVersion), доступность обязательного
BluetoothAddressType, wire=3, каналы DATA/INVITE/ACK. Waiting и Stopping publisher
имеют разные причины состояния; Waiting означает ожидание ресурсов публикации.
DEBUG: адаптер (BLE, central/peripheral, extended advertising, поддержка 2M/Coded),
этап/результат каждой служебной async-операции, состояния рекламы и сканирования,
адрес и роль соединения, список UUID/свойств характеристик, CCCD, MTU/PDU,
сводка трафика, закрытие с pending-состоянием и очистка mailbox.
HRESULT записывается с названием операции и текстом Windows; BluetoothError —
HRESULT записывается с именем события, конкретной отмеченной операцией, link ID
и текстом Windows даже при выключенном DEBUG/TRACE. Например:
event=Watcher.Received event_link=0: ... phase=Received.BluetoothAddressType link=0 HRESULT=0x80004002.
Регистрация обработчиков помечена auto_revoke: E_NOINTERFACE на этом этапе
нужно отличать от ошибки доступа к свойству в уже принятом событии.
Ошибка события с известным link ID закрывает этот link; ошибка общего события
переводит radio в failed. Повторный запуск после общей ошибки: выключить Bluetooth
в настройках приложения, применить, затем включить и применить ещё раз.
BluetoothError записывается
числом и именем, GATT status — числом, ATT protocol error — числом либо -1 (нет).
GATT status: 0=Success, 1=Unreachable, 2=ProtocolError, 3=AccessDenied.
PHY_2M_supported — возможность адаптера, НЕ измеренная скорость соединения;
-1 у необязательных возможностей означает отсутствие API в этой версии Windows.
Для отдельных кадров, ATT-фрагментов и переходов backpressure использовать discovery=trace.
WinRT TRACE содержит channel (0=DATA, 1=INVITE, 2=ACK), направление, длину и elapsed_us
локальной отправки до её обработки в uasync; это время включает ожидание mailbox.
DEBUG показывает число подписчиков DATA/INVITE/ACK, недостающие подписки конкретного
устройства и ATT-ошибку записи CCCD. Первое входящее значение перечитывает подписки,
если Windows ещё не доставил SubscribedClientsChanged.
На DEBUG раз в 5 секунд активного соединения и при его закрытии пишется BLE traffic:
TX/RX_Bps полезных байтов BLE-кадров (оба канала вместе, до вычета заголовков ETCP),
число кадров/фрагментов/отбросов, среднее/максимальное локальное ожидание GATT,
+19 -7
View File
@@ -5,33 +5,45 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int ready, failed;
static int ready, failed, published, changed, republished;
static enum ble_state advertising = BLE_STARTING;
static struct ble_transport* transport;
static void status(void* arg, enum ble_state state, const char* reason) {
(void)arg; printf("BLE status=%d reason=%s\n", state, reason); fflush(stdout);
(void)arg; DEBUG_INFO(DEBUG_CATEGORY_DISCOVERY, "BLE probe status=%d reason=%s", state, reason);
if (state == BLE_READY) { ready = 1; if (ble_advertise(transport, "vibechat-probe", 14) != BLE_OK) failed = 1; }
if (state == BLE_CLOSED && strcmp(reason, "stopped")) failed = 1;
}
static void advertising_status(void* arg, enum ble_state state, const char* reason) {
(void)arg; advertising = state;
DEBUG_INFO(DEBUG_CATEGORY_DISCOVERY, "BLE probe advertising=%d updated=%d reason=%s", state, changed, reason);
if (state == BLE_READY) { if (changed) republished = 1; else published = 1; }
}
static void broadcast(void* arg, const struct ble_endpoint* ep, const uint8_t* data, size_t len, int rssi) {
(void)arg; (void)data; printf("BLE broadcast endpoint=%s bytes=%zu rssi=%d\n", ep->id, len, rssi);
(void)arg; (void)data;
DEBUG_DEBUG(DEBUG_CATEGORY_DISCOVERY, "BLE probe broadcast endpoint=%s bytes=%zu rssi=%d", ep->id, len, rssi);
}
int main(int argc, char** argv) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); debug_set_category_level(DEBUG_CATEGORY_DISCOVERY, DEBUG_LEVEL_DEBUG);
int seconds = argc > 1 ? atoi(argv[1]) : 5;
if (seconds < 1 || seconds > 60) return 2;
if (seconds < 1 || seconds > 60) { DEBUG_ERROR(DEBUG_CATEGORY_DISCOVERY, "BLE probe seconds must be 1..60"); return 2; }
struct UASYNC* ua = uasync_create();
if (!ua) { DEBUG_ERROR(DEBUG_CATEGORY_DISCOVERY, "BLE probe cannot create uasync"); return 1; }
struct ble_config cfg = {0}; cfg.node_id = 0x5643424c45544553ULL; cfg.company_id = 0xffff;
cfg.callbacks.status = status; cfg.callbacks.broadcast = broadcast;
cfg.callbacks.advertising = advertising_status;
transport = ble_create(ua, &cfg);
if (!transport || ble_start(transport) != BLE_OK) failed = 1;
uint64_t start = get_time_us(), end = start + (uint64_t)seconds * 1000000;
int changed = 0;
while (!failed && get_time_us() < end) {
uasync_poll(ua, 100);
if (ready && !changed && get_time_us() >= start + 1000000) {
if (published && !changed && get_time_us() >= start + 1000000) {
changed = 1; if (ble_advertise(transport, "vibechat-updated", 16) != BLE_OK) failed = 1;
}
}
int ok = ready && published && republished && advertising == BLE_READY && !failed;
if (ok) DEBUG_INFO(DEBUG_CATEGORY_DISCOVERY, "BLE probe PASS: radio ready, advertisement published and updated");
else DEBUG_ERROR(DEBUG_CATEGORY_DISCOVERY, "BLE probe FAIL: ready=%d published=%d updated=%d advertising=%d failed=%d seconds=%d",
ready, published, republished, advertising, failed, seconds);
ble_destroy(transport); uasync_destroy(ua, 0);
printf("BLE probe ready=%d failed=%d\n", ready, failed); return failed || !ready;
return !ok;
}