From 3b481365afa02d044b65b8f7bf1b5db4143ddcb7 Mon Sep 17 00:00:00 2001 From: Andreas Buhr Date: Tue, 25 May 2021 13:37:04 +0200 Subject: QLowEnergyController: ATT-MTU backend on Windows In c5a5d1c9105f1fe1974b05d8276e041f2dc52bd6 an API to obtain the ATT-MTU size was introduced. This was unimplemented in the Windows backend so far. This patch adds an implementation for Windows. Fixes: QTBUG-93827 Change-Id: If8ea6d7bc514220496bd3e005694c69f5b839387 Reviewed-by: Oliver Wolff --- src/bluetooth/qlowenergycontroller_winrt.cpp | 85 +++++++++++++++++++++++++++- src/bluetooth/qlowenergycontroller_winrt_p.h | 7 +++ 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/bluetooth/qlowenergycontroller_winrt.cpp b/src/bluetooth/qlowenergycontroller_winrt.cpp index 75ec528c..c2981b1d 100644 --- a/src/bluetooth/qlowenergycontroller_winrt.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt.cpp @@ -73,6 +73,7 @@ using namespace ABI::Windows::Storage::Streams; QT_BEGIN_NAMESPACE typedef ITypedEventHandler StatusHandler; +typedef ITypedEventHandler MtuHandler; typedef ITypedEventHandler ValueChangedHandler; typedef GattReadClientCharacteristicConfigurationDescriptorResult ClientCharConfigDescriptorResult; typedef IGattReadClientCharacteristicConfigurationDescriptorResult IClientCharConfigDescriptorResult; @@ -483,6 +484,36 @@ void QLowEnergyControllerPrivateWinRT::connectToDevice() setState(QLowEnergyController::UnconnectedState); return; } + + // get GattSession: 1. get device id + ComPtr device4; + hr = mDevice.As(&device4); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return ); + + ComPtr deviceId; + hr = device4->get_BluetoothDeviceId(&deviceId); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not get bluetooth device id", return ) + + // get GattSession: 2. get session statics + ComPtr sessionStatics; + hr = GetActivationFactory( + HString::MakeReference( + RuntimeClass_Windows_Devices_Bluetooth_GenericAttributeProfile_GattSession) + .Get(), + &sessionStatics); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain GattSession statics", return ) + + // get GattSession: 3. get session + ComPtr> gattSessionFromIdOperation; + hr = sessionStatics->FromDeviceIdAsync(deviceId.Get(), &gattSessionFromIdOperation); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not get GattSession from id", return ) + hr = QWinRTFunctions::await(gattSessionFromIdOperation, mGattSession.GetAddressOf(), + QWinRTFunctions::ProcessMainThreadEvents, 5000); + CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not complete Gatt session acquire", return ) + + // subscribe to changed event + registerForMtuChanges(); + BluetoothConnectionStatus status; hr = mDevice->get_ConnectionStatus(&status); CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain device's connection status", return) @@ -507,7 +538,9 @@ void QLowEnergyControllerPrivateWinRT::disconnectFromDevice() setState(QLowEnergyController::ClosingState); unregisterFromValueChanges(); unregisterFromStatusChanges(); + unregisterFromMtuChanges(); mAbortPending = true; + mGattSession = nullptr; mDevice = nullptr; setState(QLowEnergyController::UnconnectedState); emit q->disconnected(); @@ -622,6 +655,18 @@ HRESULT QLowEnergyControllerPrivateWinRT::onValueChange(IGattCharacteristic *cha emit characteristicChanged(handle, byteArrayFromBuffer(buffer)); return S_OK; } +HRESULT QLowEnergyControllerPrivateWinRT::onMtuChange(IGattSession *session, IInspectable *args) +{ + qCDebug(QT_BT_WINDOWS) << __FUNCTION__; + if (session != mGattSession.Get()) { + qCWarning(QT_BT_WINDOWS) << "Got MTU changed event for wrong GattSession."; + return S_OK; + } + + Q_Q(QLowEnergyController); + emit q->mtuChanged(mtu()); + return S_OK; +} bool QLowEnergyControllerPrivateWinRT::registerForStatusChanges() { @@ -634,7 +679,7 @@ bool QLowEnergyControllerPrivateWinRT::registerForStatusChanges() hr = mDevice->add_ConnectionStatusChanged( Callback(this, &QLowEnergyControllerPrivateWinRT::onStatusChange).Get(), &mStatusChangedToken); - RETURN_IF_FAILED("Could not add status callback on Xaml thread", return false) + RETURN_IF_FAILED("Could not add status callback", return false) return true; } @@ -647,6 +692,30 @@ void QLowEnergyControllerPrivateWinRT::unregisterFromStatusChanges() } } +bool QLowEnergyControllerPrivateWinRT::registerForMtuChanges() +{ + if (!mDevice || !mGattSession) + return false; + + qCDebug(QT_BT_WINDOWS) << __FUNCTION__; + + HRESULT hr; + hr = mGattSession->add_MaxPduSizeChanged( + Callback(this, &QLowEnergyControllerPrivateWinRT::onMtuChange).Get(), + &mMtuChangedToken); + RETURN_IF_FAILED("Could not add MTU callback", return false) + return true; +} + +void QLowEnergyControllerPrivateWinRT::unregisterFromMtuChanges() +{ + qCDebug(QT_BT_WINDOWS) << __FUNCTION__; + if (mDevice && mGattSession && mMtuChangedToken.value) { + mGattSession->remove_MaxPduSizeChanged(mMtuChangedToken); + mMtuChangedToken.value = 0; + } +} + HRESULT QLowEnergyControllerPrivateWinRT::onStatusChange(IBluetoothLEDevice *dev, IInspectable *) { Q_Q(QLowEnergyController); @@ -663,6 +732,8 @@ HRESULT QLowEnergyControllerPrivateWinRT::onStatusChange(IBluetoothLEDevice *dev invalidateServices(); unregisterFromValueChanges(); unregisterFromStatusChanges(); + unregisterFromMtuChanges(); + mGattSession = nullptr; mDevice = nullptr; setError(QLowEnergyController::RemoteHostClosedError); setState(QLowEnergyController::UnconnectedState); @@ -1489,8 +1560,16 @@ void QLowEnergyControllerPrivateWinRT::addToGenericAttributeList(const QLowEnerg int QLowEnergyControllerPrivateWinRT::mtu() const { - // not supported yet - return -1; + uint16_t mtu = 23; + if (!mGattSession) { + qCDebug(QT_BT_WINDOWS) << "mtu queried before GattSession available. Using default mtu."; + return mtu; + } + + HRESULT hr = mGattSession->get_MaxPduSize(&mtu); + RETURN_IF_FAILED("could not obtain MTU size", return mtu); + qCDebug(QT_BT_WINDOWS) << "mtu determined to be" << mtu; + return mtu; } void QLowEnergyControllerPrivateWinRT::handleCharacteristicChanged( diff --git a/src/bluetooth/qlowenergycontroller_winrt_p.h b/src/bluetooth/qlowenergycontroller_winrt_p.h index 4cb45c54..7e6c8823 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_p.h +++ b/src/bluetooth/qlowenergycontroller_winrt_p.h @@ -143,7 +143,10 @@ private: bool mAbortPending = false; Microsoft::WRL::ComPtr mDevice; + Microsoft::WRL::ComPtr + mGattSession; EventRegistrationToken mStatusChangedToken; + EventRegistrationToken mMtuChangedToken; struct ValueChangedEntry { ValueChangedEntry() {} ValueChangedEntry(Microsoft::WRL::ComPtr c, @@ -165,6 +168,10 @@ private: void unregisterFromValueChanges(); HRESULT onValueChange(ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic *characteristic, ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattValueChangedEventArgs *args); + HRESULT onMtuChange(ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattSession *session, + IInspectable *args); + bool registerForMtuChanges(); + void unregisterFromMtuChanges(); bool registerForStatusChanges(); void unregisterFromStatusChanges(); -- cgit v1.2.3