#include "desktop_ble.h" #include "../../../lib/ble/ble_identity.h" #include "../../../lib/debug_config.h" DesktopBle::DesktopBle(UASYNC* ua, uint64_t nodeId, UTUN_INSTANCE* instance) : m_ua(ua), m_nodeId(nodeId), m_instance(instance) {} DesktopBle::~DesktopBle() { ble_etcp_destroy(m_driver); } void DesktopBle::advertise() { if (m_snapshot.state != BLE_READY) return; const bool enabled = m_snapshot.flags & 2; if (ble_advertise(m_transport, enabled ? m_identity.constData() : nullptr, enabled ? size_t(m_identity.size()) : 0)) { m_snapshot.advertising = BLE_CLOSED; m_snapshot.advertisingReason = QStringLiteral("Could not publish Bluetooth advertisement"); DEBUG_ERROR(DEBUG_CATEGORY_DISCOVERY, "BLE desktop advertisement request failed"); } } void DesktopBle::apply(int flags, const char* name) { const QByteArray nextName(name); if (flags == m_snapshot.flags && nextName == m_name) return; const int previous = m_snapshot.flags; m_snapshot.flags = flags; m_name = nextName; DEBUG_INFO(DEBUG_CATEGORY_DISCOVERY, "BLE desktop settings: enabled=%d advertise=%d incoming=%d", !!(flags & 1), !!(flags & 2), !!(flags & 4)); if (!(flags & 1)) { ble_etcp_destroy(m_driver); m_driver = nullptr; m_transport = nullptr; m_snapshot = {}; m_snapshot.flags = flags; m_connections.clear(); return; } uint8_t bytes[BLE_BROADCAST_MAX]; const int length = ble_identity_encode(bytes, m_nodeId, name); if (length < 0) { m_snapshot.reason = QStringLiteral("Invalid Bluetooth node identity"); DEBUG_ERROR(DEBUG_CATEGORY_DISCOVERY, "BLE desktop identity encoding failed node=%016llx", (unsigned long long)m_nodeId); return; } m_identity = QByteArray(reinterpret_cast(bytes), length); if (m_transport) { if ((flags ^ previous) & 4) ble_set_incoming(m_transport, !!(flags & 4)); advertise(); return; } ble_config config{}; config.node_id = m_nodeId; config.company_id = 0xffff; config.arg = this; 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); if (state == BLE_CLOSED) { self->m_snapshot.advertising = BLE_CLOSED; self->m_snapshot.advertisingReason = self->m_snapshot.reason; } DEBUG_INFO(DEBUG_CATEGORY_DISCOVERY, "BLE desktop state=%d reason=%s", state, reason); if (state == BLE_READY) self->advertise(); }; config.callbacks.advertising = [](void* arg, ble_state state, const char* reason) { auto* self = static_cast(arg); self->m_snapshot.advertising = state; self->m_snapshot.advertisingReason = QString::fromUtf8(reason); DEBUG_INFO(DEBUG_CATEGORY_DISCOVERY, "BLE desktop advertising=%d reason=%s", state, reason); }; config.callbacks.validate = [](void*, ble_link_id link, uint64_t node) { DEBUG_INFO(DEBUG_CATEGORY_DISCOVERY, "BLE desktop validation allow link=%llu node=%016llx", (unsigned long long)link, (unsigned long long)node); return 1; }; config.callbacks.connection = [](void* arg, ble_link_id link, uint64_t node, ble_state state, const char* reason) { auto* self = static_cast(arg); if (state == BLE_READY) self->m_connections.insert(link, true); else self->m_connections.remove(link); DEBUG_INFO(DEBUG_CATEGORY_DISCOVERY, "BLE desktop connection link=%llu node=%016llx state=%d reason=%s", (unsigned long long)link, (unsigned long long)node, state, reason); }; m_snapshot.state = BLE_STARTING; m_snapshot.reason.clear(); m_driver = ble_etcp_create(m_ua, m_instance, &config); m_transport = ble_etcp_radio(m_driver); if (!m_transport) { m_snapshot.state = BLE_CLOSED; m_snapshot.reason = QStringLiteral("Could not create Bluetooth transport"); DEBUG_ERROR(DEBUG_CATEGORY_DISCOVERY, "BLE desktop transport creation failed"); return; } ble_set_incoming(m_transport, !!(flags & 4)); if (ble_start(m_transport)) { m_snapshot.state = BLE_CLOSED; if (m_snapshot.reason.isEmpty()) m_snapshot.reason = QStringLiteral("Could not start Bluetooth transport"); DEBUG_ERROR(DEBUG_CATEGORY_DISCOVERY, "BLE desktop start failed"); } } DesktopBleSnapshot DesktopBle::snapshot() { m_snapshot.peers.clear(); ble_neighbor peers[BLE_NEIGHBORS_MAX]; const size_t count = ble_etcp_neighbors(m_driver, peers, BLE_NEIGHBORS_MAX); for (size_t i = 0; i < count; i++) { const auto& peer = peers[i]; m_snapshot.peers.append(QStringLiteral("%1 · %2 · %3 dBm").arg(QString::fromUtf8(peer.identity.name), QString::number(peer.identity.node_id, 16).rightJustified(16, '0'), peer.rssi == 127 ? QStringLiteral("?") : QString::number(peer.rssi))); } m_snapshot.connections = m_connections.size(); return m_snapshot; }