95 lines
6.1 KiB
C++
95 lines
6.1 KiB
C++
/* Ручной тест Windows: один GATT advertising; проверка visible/hidden/restored без manufacturer publisher.
|
|
* Запускать при закрытом VibeChat. Не является транспортом: входящие соединения отклоняются. */
|
|
#include "../ble_winrt.cpp"
|
|
#include <cstdlib>
|
|
|
|
struct ble_transport { bool ready = false, failed = false; };
|
|
extern "C" void ble_backend_status(ble_transport* t, int ready, const char* reason) {
|
|
DEBUG_INFO(CAT, "BLE advertising probe radio ready=%d reason=%s", ready, reason);
|
|
t->ready = ready; if (!ready) t->failed = true;
|
|
}
|
|
extern "C" void ble_backend_advertising(ble_transport*, ble_state state, const char* reason) {
|
|
DEBUG_INFO(CAT, "BLE advertising probe publication state=%d reason=%s", state, reason);
|
|
}
|
|
extern "C" uint64_t ble_backend_peer(ble_transport*, ble_link_id) { return 0; }
|
|
extern "C" ble_link_id ble_backend_incoming(ble_transport*, const ble_endpoint* ep) {
|
|
DEBUG_WARN(CAT, "BLE advertising probe rejects incoming connection endpoint=%s; discovery test only", ep->id); return 0;
|
|
}
|
|
extern "C" void ble_backend_broadcast(ble_transport*, const ble_endpoint*, const uint8_t*, size_t, int) {}
|
|
extern "C" void ble_backend_closed(ble_transport* t, ble_link_id, const char*) {
|
|
DEBUG_ERROR(CAT, "BLE advertising probe unexpected connection close"); t->failed = true;
|
|
}
|
|
extern "C" void ble_backend_opened(ble_transport* t, ble_link_id, unsigned) {
|
|
DEBUG_ERROR(CAT, "BLE advertising probe unexpected connection open"); t->failed = true;
|
|
}
|
|
extern "C" void ble_backend_received(ble_transport* t, ble_link_id, ble_wire_channel, const uint8_t*, size_t) {
|
|
DEBUG_ERROR(CAT, "BLE advertising probe unexpected connection data"); t->failed = true;
|
|
}
|
|
extern "C" void ble_backend_sent(ble_transport* t, ble_link_id, int) {
|
|
DEBUG_ERROR(CAT, "BLE advertising probe unexpected connection send"); t->failed = true;
|
|
}
|
|
|
|
/* Только probe: Windows 1809 отвечает на наш StopAdvertising событием Aborted/Success.
|
|
* При работающем GATT либо ненулевом BluetoothError такой ответ остаётся ошибкой. */
|
|
struct ProbeGatt {
|
|
bool requested = true, stop_confirmed = false;
|
|
GattServiceProviderAdvertisementStatus last = GattServiceProviderAdvertisementStatus::Created;
|
|
void changed(WinState& s, GattServiceProviderAdvertisementStatus status, BluetoothError error) {
|
|
last = status;
|
|
DEBUG_INFO(CAT, "BLE advertising probe GATT event requested=%d state=%d error=%d (%s)",
|
|
requested, int(status), int(error), bluetooth_error(error));
|
|
if (error != BluetoothError::Success) { s.radio_error("probe GATT advertising", error); return; }
|
|
if (!requested && (status == GattServiceProviderAdvertisementStatus::Stopped ||
|
|
status == GattServiceProviderAdvertisementStatus::Aborted)) {
|
|
stop_confirmed = true; s.service_ready = false;
|
|
DEBUG_INFO(CAT, "BLE advertising probe requested GATT stop confirmed state=%d error=0", int(status));
|
|
} else if (status == GattServiceProviderAdvertisementStatus::Started) {
|
|
s.service_ready = true;
|
|
} else if (status == GattServiceProviderAdvertisementStatus::Aborted) {
|
|
s.radio_error("probe unexpected GATT advertising abort", error);
|
|
}
|
|
}
|
|
bool matches(int actual) const {
|
|
if (requested) return last == GattServiceProviderAdvertisementStatus::Started && actual == int(last);
|
|
return stop_confirmed && (actual == int(GattServiceProviderAdvertisementStatus::Stopped) ||
|
|
actual == int(GattServiceProviderAdvertisementStatus::Aborted));
|
|
}
|
|
};
|
|
|
|
/* API Started проверяется весь интервал; выход в эфир подтверждается сканером другого устройства. */
|
|
static bool observe(WinState& s, ble_transport& owner, const char* phase, unsigned seconds) {
|
|
uint64_t end = get_time_us() + uint64_t(seconds) * 1000000;
|
|
do {
|
|
uasync_poll(s.ua, 100);
|
|
if (s.failed || owner.failed) return false;
|
|
auto actual = s.radio_status();
|
|
if (!s.service_stop_pending && s.service_ready && actual.service != 2) {
|
|
DEBUG_ERROR(CAT, "BLE probe unstable phase=%s service=%d scan=%d", phase, actual.service, actual.scan); return false;
|
|
}
|
|
} while (get_time_us() < end);
|
|
auto actual = s.radio_status();
|
|
bool ok = s.service_ready && !s.service_stop_pending && actual.service == 2 && actual.scan == 1;
|
|
DEBUG_INFO(CAT, "BLE probe phase=%s result=%d UUID=%s discoverable=%d service=%d scan=%d single_provider=1",
|
|
phase, ok, s.service_uuid.c_str(), s.broadcast_enabled, actual.service, actual.scan);
|
|
return ok;
|
|
}
|
|
int main(int argc, char** argv) {
|
|
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); debug_set_category_level(CAT, DEBUG_LEVEL_DEBUG);
|
|
unsigned seconds = argc > 1 ? unsigned(std::atoi(argv[1])) : 10;
|
|
if (seconds < 10 || seconds > 60) { DEBUG_ERROR(CAT, "Usage: ble_advertising_probe.exe [10..60 seconds per phase]"); return 2; }
|
|
debug_enable_file_output("ble_advertising_probe.log", 1);
|
|
UASYNC* ua = uasync_create(); if (!ua) return 1;
|
|
ble_transport owner; ble_config cfg{}; cfg.node_id = UINT64_C(0x5643424c45544553); cfg.company_id = 0xffff;
|
|
cfg.initial_advertisement_size = ble_identity_encode(cfg.initial_advertisement, cfg.node_id, "WinGATT-probe");
|
|
ble_backend* backend = ble_backend_create(&owner, ua, &cfg); bool ok = backend != nullptr;
|
|
if (backend) {
|
|
auto& s = *backend->state;
|
|
ok = observe(s, owner, "visible", seconds);
|
|
if (ok) ok = ble_backend_advertise(backend, nullptr, 0) == BLE_OK && observe(s, owner, "hidden", seconds);
|
|
if (ok) ok = ble_backend_advertise(backend, cfg.initial_advertisement, cfg.initial_advertisement_size) == BLE_OK &&
|
|
observe(s, owner, "restored", seconds);
|
|
ble_backend_destroy(backend);
|
|
}
|
|
uasync_destroy(ua, 0); DEBUG_INFO(CAT, "BLE single GATT advertising probe result=%s", ok ? "PASS" : "FAIL"); return !ok;
|
|
}
|