diff --git a/lib/ble/ble_transport.c b/lib/ble/ble_transport.c index 63a55b6e..750f1fd9 100644 --- a/lib/ble/ble_transport.c +++ b/lib/ble/ble_transport.c @@ -53,7 +53,7 @@ struct ble_transport { struct ble_connection links[BLE_LINKS_MAX]; ble_link_id sequence; void* timer; - int started, ready, reject_incoming; + int started, ready, reject_incoming, initial_advertisement_pending; }; static uint16_t read16(const uint8_t* p) { return (uint16_t)((p[0] << 8) | p[1]); } static void write16(uint8_t* p, uint16_t v) { p[0] = v >> 8; p[1] = v; } @@ -278,6 +278,7 @@ static void tick(void* arg) { } struct ble_transport* ble_create(struct UASYNC* ua, const struct ble_config* config) { if (!ua || !config || !config->node_id || config->tx_limit > BLE_QUEUE_MAX || config->tx_window > BLE_QUEUE_MAX || + config->initial_advertisement_size > BLE_BROADCAST_MAX || (config->adapter && strlen(config->adapter) >= 64)) { DEBUG_ERROR(CAT, "BLE create invalid configuration"); return NULL; } @@ -292,6 +293,7 @@ struct ble_transport* ble_create(struct UASYNC* ua, const struct ble_config* con int ble_start(struct ble_transport* t) { if (!t || t->started) { DEBUG_ERROR(CAT, "BLE invalid/repeated start"); return BLE_ERROR; } t->started = 1; + t->initial_advertisement_pending = t->config.initial_advertisement_size != 0; t->backend = ble_backend_create(t, t->ua, &t->config); if (!t->backend) { t->started = 0; DEBUG_ERROR(CAT, "BLE backend creation failed"); return BLE_ERROR; } t->timer = uasync_set_timeout(t->ua, 1000, t, tick, "ble_tick"); @@ -380,6 +382,14 @@ ble_link_id ble_backend_incoming(struct ble_transport* t, const struct ble_endpo struct ble_connection* c = new_link(t, ep, 0, 0); return c ? c->id : 0; } void ble_backend_status(struct ble_transport* t, int ready, const char* reason) { + if (ready && t->initial_advertisement_pending) { + t->initial_advertisement_pending = 0; + /* WinRT уже запустил эти байты до GATT и принимает повтор без перезапуска; остальные backend начинают здесь. */ + if (ble_backend_advertise(t->backend, t->config.initial_advertisement, t->config.initial_advertisement_size) != BLE_OK) { + DEBUG_ERROR(CAT, "BLE initial advertisement failed bytes=%zu", t->config.initial_advertisement_size); + ready = 0; reason = "initial BLE advertisement failed"; + } + } t->ready = ready; if (!ready) { DEBUG_ERROR(CAT, "BLE radio failed: %s", reason); diff --git a/lib/ble/ble_transport.h b/lib/ble/ble_transport.h index d87f70d1..6c984dc3 100644 --- a/lib/ble/ble_transport.h +++ b/lib/ble/ble_transport.h @@ -51,6 +51,8 @@ struct ble_config { void* arg; /* Заимствованный контекст callbacks, живёт до destroy. */ unsigned tx_limit; /* Целых TX-пакетов, включая фрагментируемый: 0=64, 1..64. */ unsigned tx_window; /* DATA в очереди/отправке/ожидании удалённого ACK: 0=BLE_TX_WINDOW_FRAMES, 1..64. */ + uint8_t initial_advertisement[BLE_BROADCAST_MAX]; /* Начальное объявление; копируется вместе с config. */ + size_t initial_advertisement_size; /* 0: выключено; 1..24: Windows запускает publisher до GATT. */ }; /* Создать остановленный transport. ua/config заимствованы только ua; возвращает handle или NULL с логом. */ struct ble_transport* ble_create(struct UASYNC* ua, const struct ble_config* config); diff --git a/tools/chatgui/transport/desktop_ble.cpp b/tools/chatgui/transport/desktop_ble.cpp index 92c9ba63..d906f127 100644 --- a/tools/chatgui/transport/desktop_ble.cpp +++ b/tools/chatgui/transport/desktop_ble.cpp @@ -45,6 +45,10 @@ void DesktopBle::apply(int flags, const char* name) { } ble_config config{}; config.node_id = m_nodeId; config.company_id = 0xffff; config.arg = this; + if (flags & 2) { + memcpy(config.initial_advertisement, bytes, size_t(length)); + config.initial_advertisement_size = size_t(length); + } config.callbacks.status = [](void* arg, ble_state state, const char* reason) { auto* self = static_cast(arg); self->m_snapshot.state = state; self->m_snapshot.reason = QString::fromUtf8(reason);