This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

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

The following code snippet 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[i] & 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;
}

Related