C++/WinRT GattCharacteristic ValueChanged 事件从不触发/触发器
C++/WinRT GattCharacteristic ValueChanged Event Never Fires / Triggers
GattCharacteristic.ValueChanged
Event 似乎从未在非常简单的 C++/WinRT 控制台应用程序中启动。
对于具有配置的设备
- 本地名称:
TestDevice
- 广告服务:
FFFF
- 特征:
EEEE
下面的程序将简单
- 搜索设备
TestDevice
- 使用 ShortID
FFFF
查找 TestDevice
的服务
- 查找具有 shortID 的服务的特征
EEEE
- Write the ClientCharacteristicConfigurationDescriptor
GattClientCharacteristicConfigurationDescriptorValue
到 EEEE
,其中有 属性 读取、写入和通知
- 注册一个从
TypedEventHandler<GattCharacteristic,GattValueChangedEventArgs>
到 ValueChanged
的 lambda 转换, 应该 在值更新时打印 New Value
更新特征值不会触发ValueChanged
事件。但是,相同的设备设置已成功通过其他蓝牙堆栈进行了测试。
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Devices.Bluetooth.h>
#include <winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h>
#include <winrt/Windows.Devices.Bluetooth.Advertisement.h>
using winrt::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
using winrt::Windows::Devices::Bluetooth::BluetoothLEDevice;
using winrt::Windows::Devices::Bluetooth::BluetoothUuidHelper;
using winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementReceivedEventArgs;
using winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementWatcher;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
using namespace winrt;
class WinBleCentral
{
public:
WinBleCentral()
{
bleWatcher.Received(
[this](BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
hstring testHstring{ std::wstring_view(L"TestDevice") };
if (testHstring == eventArgs.Advertisement().LocalName())
{
this->bleWatcher.Stop();
std::cout << "Matched\n";
BluetoothLEDevice::FromBluetoothAddressAsync(eventArgs.BluetoothAddress()).Completed(
[this](IAsyncOperation<BluetoothLEDevice> sender, AsyncStatus status)
{
if (auto device = sender.GetResults(); device)
{
std::cout << "Connected\n";
winrt::guid serviceGUID = BluetoothUuidHelper::FromShortId(0xFFFF);
device.GetGattServicesForUuidAsync(serviceGUID).Completed(
[this](IAsyncOperation<GattDeviceServicesResult> sender, AsyncStatus status)
{
GattDeviceServicesResult result = sender.get();
if (result && status == winrt::Windows::Foundation::AsyncStatus::Completed)
{
winrt::guid charGUID = BluetoothUuidHelper::FromShortId(0xEEEE);
std::cout << "Num Services: " << result.Services().Size() << '\n';
for (auto&& service : result.Services())
{
service.GetCharacteristicsForUuidAsync(charGUID).Completed(
[this](IAsyncOperation<GattCharacteristicsResult>sender, AsyncStatus status)
{
std::cout << "Get Characteristics\n";
if (auto result = sender.GetResults(); result)
{
std::cout << "Num Characteristics: " << result.Characteristics().Size() << '\n';
for (auto character : result.Characteristics())
{
character.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify).Completed(
[this, character](IAsyncOperation<GattCommunicationStatus>sender, AsyncStatus status)
{
character.ValueChanged([this](GattCharacteristic characteristic, GattValueChangedEventArgs const& args)
{
std::cout << "New Value!\n";
});
});
}
}
});
}
}
}
);
}
});
}
});
bleWatcher.Start();
};
BluetoothLEAdvertisementWatcher bleWatcher;
};
int main()
{
WinBleCentral bleCentral;
while (getchar() != '\n');
}
这似乎是由于 GattCharacteristic
对象超出了范围。通过简单地保留对 tha 变量的引用,上述工作按预期进行。
下面是与上面相同的程序,但为了提高可读性,去掉了 Async
的一面。我已经测试过,两种情况下显示的行为完全相同。
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Devices.Bluetooth.h>
#include <winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h>
#include <winrt/Windows.Devices.Bluetooth.Advertisement.h>
using winrt::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
using winrt::Windows::Devices::Bluetooth::BluetoothLEDevice;
using winrt::Windows::Devices::Bluetooth::BluetoothUuidHelper;
using winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementReceivedEventArgs;
using winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementWatcher;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
using namespace winrt;
class WinBleCentral
{
public:
WinBleCentral()
{
std::cout << "Start\n";
bleWatcher.Received(
[this](BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
hstring testHstring{ std::wstring_view(L"TestDevice") };
if (testHstring == eventArgs.Advertisement().LocalName())
{
this->bleWatcher.Stop();
std::cout << "Matched\n";
auto device = BluetoothLEDevice::FromBluetoothAddressAsync(eventArgs.BluetoothAddress()).get();
std::cout << "Device\n";
winrt::guid serviceGUID = BluetoothUuidHelper::FromShortId(0xFFFF);
auto serviceResults = device.GetGattServicesForUuidAsync(serviceGUID).get();
std::cout << "Service Results\n";
winrt::guid charGUID = BluetoothUuidHelper::FromShortId(0xEEEE);
auto service = serviceResults.Services().GetAt(0);
std::cout << "Services\n";
auto characteristicResults = service.GetCharacteristicsForUuidAsync(charGUID).get();
std::cout << "Characteristic Results\n";
auto characteristic = characteristicResults.Characteristics().GetAt(0);
characteristics.push_back(characteristic);
std::cout << "Characterstic\n";
auto gattCommunicationStatus = characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify).get();
std::cout << "WriteClientCharacteristicConfiguration\n";
characteristic.ValueChanged([this](GattCharacteristic const& notifyingCharacteristic, GattValueChangedEventArgs args)
{
std::cout << "New Value!\n";
});
}
});
bleWatcher.Start();
}
std::vector<GattCharacteristic> characteristics;
BluetoothLEAdvertisementWatcher bleWatcher;
};
int main()
{
WinBleCentral bleCentral;
while (getchar() != '\n');
}
即使从未使用过 std::vector<GattCharacteristic> characteristics
,但 characteristics.push_back(characteristic)
的简单操作足以使引用保持活动状态。这种行为绝对出乎意料。
为了与整个 UWP 风格保持一致,我最初使用了 IVector
and the Append
方法,但整个事情在 check_hresult(WINRT_IMPL_SHIM(winrt::Windows::Foundation::Collections::IVector<T>)->Append(impl::bind_in(value)));
崩溃了,因为它似乎是一个空指针。
对于上述内容,为了便于阅读,所有错误检查都被避免了。实际实施应该对所有异步操作进行健康检查,以确保数据确实存在。
GattCharacteristic.ValueChanged
Event 似乎从未在非常简单的 C++/WinRT 控制台应用程序中启动。
对于具有配置的设备
- 本地名称:
TestDevice
- 广告服务:
FFFF
- 特征:
EEEE
下面的程序将简单
- 搜索设备
TestDevice
- 使用 ShortID
FFFF
查找 - 查找具有 shortID 的服务的特征
EEEE
- Write the ClientCharacteristicConfigurationDescriptor
GattClientCharacteristicConfigurationDescriptorValue
到EEEE
,其中有 属性 读取、写入和通知 - 注册一个从
TypedEventHandler<GattCharacteristic,GattValueChangedEventArgs>
到ValueChanged
的 lambda 转换, 应该 在值更新时打印New Value
TestDevice
的服务
更新特征值不会触发ValueChanged
事件。但是,相同的设备设置已成功通过其他蓝牙堆栈进行了测试。
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Devices.Bluetooth.h>
#include <winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h>
#include <winrt/Windows.Devices.Bluetooth.Advertisement.h>
using winrt::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
using winrt::Windows::Devices::Bluetooth::BluetoothLEDevice;
using winrt::Windows::Devices::Bluetooth::BluetoothUuidHelper;
using winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementReceivedEventArgs;
using winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementWatcher;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
using namespace winrt;
class WinBleCentral
{
public:
WinBleCentral()
{
bleWatcher.Received(
[this](BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
hstring testHstring{ std::wstring_view(L"TestDevice") };
if (testHstring == eventArgs.Advertisement().LocalName())
{
this->bleWatcher.Stop();
std::cout << "Matched\n";
BluetoothLEDevice::FromBluetoothAddressAsync(eventArgs.BluetoothAddress()).Completed(
[this](IAsyncOperation<BluetoothLEDevice> sender, AsyncStatus status)
{
if (auto device = sender.GetResults(); device)
{
std::cout << "Connected\n";
winrt::guid serviceGUID = BluetoothUuidHelper::FromShortId(0xFFFF);
device.GetGattServicesForUuidAsync(serviceGUID).Completed(
[this](IAsyncOperation<GattDeviceServicesResult> sender, AsyncStatus status)
{
GattDeviceServicesResult result = sender.get();
if (result && status == winrt::Windows::Foundation::AsyncStatus::Completed)
{
winrt::guid charGUID = BluetoothUuidHelper::FromShortId(0xEEEE);
std::cout << "Num Services: " << result.Services().Size() << '\n';
for (auto&& service : result.Services())
{
service.GetCharacteristicsForUuidAsync(charGUID).Completed(
[this](IAsyncOperation<GattCharacteristicsResult>sender, AsyncStatus status)
{
std::cout << "Get Characteristics\n";
if (auto result = sender.GetResults(); result)
{
std::cout << "Num Characteristics: " << result.Characteristics().Size() << '\n';
for (auto character : result.Characteristics())
{
character.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify).Completed(
[this, character](IAsyncOperation<GattCommunicationStatus>sender, AsyncStatus status)
{
character.ValueChanged([this](GattCharacteristic characteristic, GattValueChangedEventArgs const& args)
{
std::cout << "New Value!\n";
});
});
}
}
});
}
}
}
);
}
});
}
});
bleWatcher.Start();
};
BluetoothLEAdvertisementWatcher bleWatcher;
};
int main()
{
WinBleCentral bleCentral;
while (getchar() != '\n');
}
这似乎是由于 GattCharacteristic
对象超出了范围。通过简单地保留对 tha 变量的引用,上述工作按预期进行。
下面是与上面相同的程序,但为了提高可读性,去掉了 Async
的一面。我已经测试过,两种情况下显示的行为完全相同。
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Devices.Bluetooth.h>
#include <winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h>
#include <winrt/Windows.Devices.Bluetooth.Advertisement.h>
using winrt::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
using winrt::Windows::Devices::Bluetooth::BluetoothLEDevice;
using winrt::Windows::Devices::Bluetooth::BluetoothUuidHelper;
using winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementReceivedEventArgs;
using winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementWatcher;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
using namespace winrt;
class WinBleCentral
{
public:
WinBleCentral()
{
std::cout << "Start\n";
bleWatcher.Received(
[this](BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
hstring testHstring{ std::wstring_view(L"TestDevice") };
if (testHstring == eventArgs.Advertisement().LocalName())
{
this->bleWatcher.Stop();
std::cout << "Matched\n";
auto device = BluetoothLEDevice::FromBluetoothAddressAsync(eventArgs.BluetoothAddress()).get();
std::cout << "Device\n";
winrt::guid serviceGUID = BluetoothUuidHelper::FromShortId(0xFFFF);
auto serviceResults = device.GetGattServicesForUuidAsync(serviceGUID).get();
std::cout << "Service Results\n";
winrt::guid charGUID = BluetoothUuidHelper::FromShortId(0xEEEE);
auto service = serviceResults.Services().GetAt(0);
std::cout << "Services\n";
auto characteristicResults = service.GetCharacteristicsForUuidAsync(charGUID).get();
std::cout << "Characteristic Results\n";
auto characteristic = characteristicResults.Characteristics().GetAt(0);
characteristics.push_back(characteristic);
std::cout << "Characterstic\n";
auto gattCommunicationStatus = characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify).get();
std::cout << "WriteClientCharacteristicConfiguration\n";
characteristic.ValueChanged([this](GattCharacteristic const& notifyingCharacteristic, GattValueChangedEventArgs args)
{
std::cout << "New Value!\n";
});
}
});
bleWatcher.Start();
}
std::vector<GattCharacteristic> characteristics;
BluetoothLEAdvertisementWatcher bleWatcher;
};
int main()
{
WinBleCentral bleCentral;
while (getchar() != '\n');
}
即使从未使用过 std::vector<GattCharacteristic> characteristics
,但 characteristics.push_back(characteristic)
的简单操作足以使引用保持活动状态。这种行为绝对出乎意料。
为了与整个 UWP 风格保持一致,我最初使用了 IVector
and the Append
方法,但整个事情在 check_hresult(WINRT_IMPL_SHIM(winrt::Windows::Foundation::Collections::IVector<T>)->Append(impl::bind_in(value)));
崩溃了,因为它似乎是一个空指针。
对于上述内容,为了便于阅读,所有错误检查都被避免了。实际实施应该对所有异步操作进行健康检查,以确保数据确实存在。