Prepare WinRT subscriptions afresh and test BlueZ session replacement

This commit is contained in:
evgeny committed 2026-10-30 21:41:38 +01:00
1 parent 68444ef192
commit 752a3a7d95
2 files changed
+48 -15

No files matched your search

+22 -12
View File
@@ -743,7 +743,7 @@ struct WinState : std::enable_shared_from_this<WinState> {
l->value_changed = s.watch_value(id, l->tx, BLE_WIRE_DATA);
l->invite_changed = s.watch_value(id, l->invite, BLE_WIRE_INVITE);
l->ack_changed = s.watch_value(id, l->ack, BLE_WIRE_ACK);
s.subscribe_channel(id, BLE_WIRE_DATA);
s.subscribe_channel(id, BLE_WIRE_DATA, true);
});
}
GattCharacteristic::ValueChanged_revoker watch_value(ble_link_id id, GattCharacteristic const& characteristic, enum ble_wire_channel channel) {
@@ -752,7 +752,12 @@ struct WinState : std::enable_shared_from_this<WinState> {
DEBUG_DEBUG(CAT, "BLE WinRT register ValueChanged link=%llu channel=%d", (unsigned long long)id, channel);
return characteristic.ValueChanged(auto_revoke, [weak, id, channel](auto const&, GattValueChangedEventArgs const& args) {
if (auto s = weak.lock()) s->post("GattCharacteristic.ValueChanged", id, [id, channel, args](WinState& s) {
if (!s.link(id)) return;
auto* l = s.link(id); if (!l) return;
if (!l->opened) {
DEBUG_DEBUG(CAT, "BLE WinRT notification ignored during CCC preparation link=%llu channel=%d",
(unsigned long long)id, channel);
return;
}
s.step("ValueChanged.CharacteristicValue/DataReader", id);
auto data = bytes(args.CharacteristicValue());
DEBUG_TRACE(CAT, "BLE WinRT RX value link=%llu channel=%d bytes=%zu", (unsigned long long)id, channel, data.size());
@@ -760,24 +765,29 @@ struct WinState : std::enable_shared_from_this<WinState> {
});
});
}
void subscribe_channel(ble_link_id id, enum ble_wire_channel channel) {
// Сбросить весь набор CCC до включения: ACL и удалённые CCC могут пережить прежнюю сессию.
void subscribe_channel(ble_link_id id, enum ble_wire_channel channel, bool reset) {
auto* l = link(id);
auto characteristic = channel == BLE_WIRE_ACK ? l->ack : channel == BLE_WIRE_DATA ? l->tx : l->invite;
auto mode = channel == BLE_WIRE_INVITE ? GattClientCharacteristicConfigurationDescriptorValue::Indicate :
GattClientCharacteristicConfigurationDescriptorValue::Notify;
auto mode = reset ? GattClientCharacteristicConfigurationDescriptorValue::None :
channel == BLE_WIRE_INVITE ? GattClientCharacteristicConfigurationDescriptorValue::Indicate :
GattClientCharacteristicConfigurationDescriptorValue::Notify;
step("GattCharacteristic.WriteCCCDWithResultAsync", id);
DEBUG_DEBUG(CAT, "BLE WinRT subscribe request link=%llu channel=%d mode=%d", (unsigned long long)id, channel, (int)mode);
DEBUG_DEBUG(CAT, "BLE WinRT CCC request link=%llu reset=%d channel=%d mode=%d", (unsigned long long)id, reset, channel, (int)mode);
await("subscribe channel", characteristic.WriteClientCharacteristicConfigurationDescriptorWithResultAsync(mode), id,
[id, channel](WinState& s, GattWriteResult const& result) {
[id, channel, reset](WinState& s, GattWriteResult const& result) {
auto status = result.Status(); auto protocol = result.ProtocolError();
DEBUG_DEBUG(CAT, "BLE WinRT subscribe link=%llu channel=%d status=%d", (unsigned long long)id, channel, (int)status);
DEBUG_DEBUG(CAT, "BLE WinRT CCC complete link=%llu reset=%d channel=%d status=%d",
(unsigned long long)id, reset, channel, (int)status);
if (status != GattCommunicationStatus::Success) {
DEBUG_WARN(CAT, "BLE WinRT subscription failed link=%llu channel=%d status=%d ATT_error=%d",
(unsigned long long)id, channel, (int)status, protocol ? int(protocol.Value()) : -1);
DEBUG_WARN(CAT, "BLE WinRT CCC failed link=%llu reset=%d channel=%d status=%d ATT_error=%d",
(unsigned long long)id, reset, channel, (int)status, protocol ? int(protocol.Value()) : -1);
s.error(id, "GATT subscription failed"); return;
}
if (channel == BLE_WIRE_DATA) { s.subscribe_channel(id, BLE_WIRE_INVITE); return; }
if (channel == BLE_WIRE_INVITE) { s.subscribe_channel(id, BLE_WIRE_ACK); return; }
if (channel == BLE_WIRE_DATA) { s.subscribe_channel(id, BLE_WIRE_INVITE, reset); return; }
if (channel == BLE_WIRE_INVITE) { s.subscribe_channel(id, BLE_WIRE_ACK, reset); return; }
if (reset) { s.subscribe_channel(id, BLE_WIRE_DATA, false); return; }
DEBUG_INFO(CAT, "BLE WinRT subscriptions ready link=%llu DATA=notify INVITE=indicate ACK=notify", (unsigned long long)id);
auto* l = s.link(id); l->opened = true; ble_backend_opened(s.owner, id, l->session.MaxPduSize());
});
}
+26 -3
View File
@@ -19,7 +19,7 @@ static struct UASYNC* ua;
static sd_bus* bus;
static struct ble_transport* transport;
static char application[256];
static int ready, broadcasts, ready_links, advertisement_count;
static int ready, broadcasts, ready_links, advertisement_count, closed_links;
static ble_link_id links[4];
static unsigned commands, requests, ack_requests, ack_values;
static int ack_fds[2] = {-1, -1};
@@ -127,6 +127,7 @@ static void status(void* arg, enum ble_state state, const char* reason) {
static void connection(void* arg, ble_link_id id, uint64_t node, enum ble_state state, const char* reason) {
(void)arg; (void)reason;
if (state == BLE_READY) { CHECK(node < 4); links[node] = id; ready_links++; }
if (state == BLE_CLOSED) closed_links++;
}
static void broadcast(void* arg, const struct ble_endpoint* ep, const uint8_t* data, size_t len, int rssi) {
(void)arg; CHECK(strstr(ep->id, "dev_A")); CHECK(len == 3 && !memcmp(data, "abc", 3)); CHECK(rssi == -42); broadcasts++;
@@ -241,6 +242,28 @@ int main(void) {
CHECK(send(invite2, "\1", 1, MSG_NOSIGNAL) == 1); poll_all();
}
CHECK(ack_values >= 2);
/* Повторный AcquireNotify до HUP старого fd: новая сессия A, действующая сессия B не затронута. */
ble_link_id old_a = links[1], old_b = links[2];
int closed_before = closed_links;
int new_fd1 = acquire(ADAPTER "/dev_A", 0);
CHECK(closed_links == closed_before + 1 && ready_links == 2);
CHECK(recv(invite1, data, sizeof(data), MSG_DONTWAIT) == 0);
close(ack_fds[0]); ack_fds[0] = -1;
close(invite1); close(fd1); fd1 = new_fd1;
invite1 = acquire(ADAPTER "/dev_A", 1);
CHECK(ready_links == 2);
ack_fds[0] = acquire(ADAPTER "/dev_A", 2);
hello(ADAPTER "/dev_A", fd1, 1);
CHECK(ready_links == 3 && links[1] != old_a && links[2] == old_b);
CHECK(!ble_tx_put(transport, old_b, frame(0xf1))); poll_all();
for (int offset = 0; offset < 31; offset += 11) {
CHECK(recv(fd2, data, sizeof(data), MSG_DONTWAIT) == (offset == 22 ? 18 : 20));
CHECK(data[8] == offset && data[9] == 0xf1);
}
write_value(ADAPTER "/dev_B", data, 2, 2);
write_value(ADAPTER "/dev_A", incoming, sizeof(incoming), 0);
e = ble_rx_get(transport, links[1]); CHECK(e && e->len == 3 && !memcmp(e->dgram, incoming + 9, 3));
queue_dgram_free(e); queue_entry_free(e);
close(ack_fds[0]); close(ack_fds[1]); ack_fds[0] = ack_fds[1] = -1;
close(invite1); close(invite2);
close(fd1); poll_all(); close(fd2); poll_all();
@@ -248,10 +271,10 @@ int main(void) {
struct ble_endpoint ep = {REMOTE};
CHECK(ble_connect(transport, &ep, 3)); poll_all();
/* Кеш UUID доступен сразу, но до ServicesResolved нельзя объявлять GATT готовым с прежним MTU23. */
CHECK(ready_links == 2 && commands == 0);
CHECK(ready_links == 3 && commands == 0);
remote_resolved = 1;
CHECK(sd_bus_emit_properties_changed(bus, REMOTE, "org.bluez.Device1", "ServicesResolved", NULL) >= 0);
poll_all(); CHECK(ready_links == 3 && commands == 1);
poll_all(); CHECK(ready_links == 4 && commands == 1);
CHECK(!ble_tx_put(transport, links[3], frame(0xe5)));
CHECK(!ble_channel_tx_put(transport, links[3], BLE_CHANNEL_INVITE, frame(0xe6)));
poll_all(); CHECK(commands == 2 && requests == 1 && ack_requests >= 1); /* MTU517 и ACK Write Command. */