Bluetooth LE WinRT C++ code works if device NOT paired. Fails with unreachable if device is paired

  • Thread starter Thread starter Ev1lC
  • Start date Start date
E

Ev1lC

Guest
The following code snuppet works if the Bluetooth LE device is NOT paired. After pairing the same device, the call to WriteClientCharacteristicConfigurationDescriptorAsync() fails with UNREACHABLE. No PIN code required for pairing.

Can anyone please help? The code will become part of a library with Java JNI bindings, so needs to be in C++. That's why I'm using the WinRT stuff. I'm using VS 2017 target SDK 10.0.18362.0 running on Windows 10 1903.

#include "pch.h"

#include <combaseapi.h>

using namespace winrt;
using namespace Windows::Foundation;
using namespace winrt::Windows::Foundation;
using namespace Windows::Storage::Streams;
using namespace Windows::Devices::Bluetooth;
using namespace Windows::Foundation::Collections;
using namespace Windows::Devices::Bluetooth::Advertisement;
using namespace Windows::Devices::Bluetooth::GenericAttributeProfile;

#define NU_SERVICE "{6E400001-B5A3-F393-E0A9-E50E24DCCA9E}"
#define TX_CHARACTERISTIC "{6E400002-B5A3-F393-E0A9-E50E24DCCA9E}"
#define RX_CHARACTERISTIC "{6E400003-B5A3-F393-E0A9-E50E24DCCA9E}"

std::wstring guidToString(GUID uuid) {
std::wstring guid;
WCHAR* wszUuid = NULL;
if(::UuidToString(&uuid, (RPC_WSTR*) &wszUuid) == RPC_S_OK) {
guid = wszUuid;
::RpcStringFree((RPC_WSTR*) &wszUuid);
}
return guid;
}

void str2ba(const char *straddr, unsigned long long *btaddr) {
int i;
unsigned int aaddr[6];
unsigned long long tmpaddr = 0;

if (sscanf_s(straddr, "%02x:%02x:%02x:%02x:%02x:%02x", &aaddr[0], &aaddr[1], &aaddr[2], &aaddr[3], &aaddr[4], &aaddr[5]) != 6) {
return;
}
*btaddr = 0;
for (i = 0; i < 6; i++) {
tmpaddr = (unsigned long long) (aaddr & 0xff);
*btaddr = ((*btaddr) << 8) + tmpaddr;
}
}

IAsyncAction OpenDevice(unsigned long long deviceAddress) {
auto device = co_await BluetoothLEDevice::FromBluetoothAddressAsync(deviceAddress);

std::wcout << std::hex <<
"Device Information: " << std::endl <<
"\tName :" << device.Name().c_str() << std::endl <<
"\tAddress :" << device.BluetoothAddress() << std::endl <<
"\tStatus :" << (device.ConnectionStatus() == BluetoothConnectionStatus::Connected ? "Connected" : "Disconnected") << std::endl <<
"\tDeviceId :" << device.DeviceId().c_str() << std::endl <<
std::endl;

GUID nusGUID, txcGUID, rxcGUID;
CLSIDFromString(TEXT(NU_SERVICE), &nusGUID);
CLSIDFromString(TEXT(TX_CHARACTERISTIC), &txcGUID);
CLSIDFromString(TEXT(RX_CHARACTERISTIC), &rxcGUID);

auto services = co_await device.GetGattServicesAsync();//BluetoothCacheMode::Cached);
for(GenericAttributeProfile::GattDeviceService const & s : services.Services()) {
std::wcout << std::hex << "\t\tService - Guid: [" << guidToString(s.Uuid()) << "]" << std::endl;

auto characteristics = co_await s.GetCharacteristicsAsync();
for(GenericAttributeProfile::GattCharacteristic const & c : characteristics.Characteristics()) {
std::wcout << std::hex << "\t\tCharacteristic - Guid: [" << guidToString(c.Uuid()) << "]" << std::endl;

if(c.CharacteristicProperties() == GattCharacteristicProperties::Notify) {
printf("Notify supported\n");

GattCommunicationStatus status = co_await c.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify);
switch (status) {
case GattCommunicationStatus::AccessDenied:
printf("access denied\n");
break;
case GattCommunicationStatus::ProtocolError:
printf("protocol error\n");
break;
case GattCommunicationStatus::Unreachable:
printf("unreachable\n");
break;
case GattCommunicationStatus::Success:
c.ValueChanged([](GattCharacteristic const& charateristic, GattValueChangedEventArgs const& args) {
std::wcout << std::hex <<
"\t\tNotified GattCharacteristic - Guid: [" << guidToString(charateristic.Uuid()) << "]" << std::endl;
});

//
// Code to write to BT device ommitted.... Sleep 5 secs then exit.
//
Sleep(5000);
}
}
}
}

device.Close();
}

int main() {
init_apartment();

// Connect to a specific Bluetooth device.
unsigned long long deviceAddress;
str2ba("db:e7:df:00:52:32", &deviceAddress);
printf("device = %lld\n", deviceAddress);

try {
OpenDevice(deviceAddress).get();
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
return FALSE;
}
return TRUE;
}

Continue reading...
 
Back
Top