6
votes

I am writing program for Win 8 tablet. I need to connect an external BLE device. The device is already paired with Windows and I can see it in Device Manager. But I can not figure out how to connect it.

With SetupDiEnumDeviceInfo and SetupDiGetDeviceProperty I can get some information about the BLE-device, but to perform, e.g. BluetoothGATTGetServices Handle device requires. I do not know where to take it. Perhaps i can use CreateFile, but it is not clear that the substitute as the first argument lpFileName.

Here's a piece of code with which I'm looking for my device.

HDEVINFO hDevInfo;
   SP_DEVINFO_DATA DeviceInfoData;
   DWORD i;

   // Create a HDEVINFO with all present devices.
   hDevInfo = SetupDiGetClassDevs(
        &BluetoothClassGUID,                     /* GUID_DEVCLASS_BLUETOOTH */
        0, 0, DIGCF_PRESENT);

   if (hDevInfo == INVALID_HANDLE_VALUE)
   {
       // Insert error handling here.
       return ;//1;
   }

   // Enumerate through all devices in Set.

   DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
   for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,
       &DeviceInfoData);i++)
   {
       DWORD DataT;
       LPTSTR buffer = NULL;
       DWORD buffersize = 0;

       while (!SetupDiGetDeviceRegistryProperty(
               hDevInfo,
               &DeviceInfoData,
               SPDRP_FRIENDLYNAME,
               &DataT,
               (PBYTE)buffer,
               buffersize,
               &buffersize))
       {
           if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
               // Change the buffer size.
               if (buffer) delete(buffer);
               // Double the size to avoid problems on
               // W2k MBCS systems per KB 888609.
               buffer = new wchar_t[buffersize * 2];
           }else{
               // Insert error handling here.
               break;
           }
       }
                   /* Here i just compare by name is this my device or not */
                   ...
                   /* Here i just compare by name is this my device or not */
        if (buffer) delete(buffer);
   }


   if ( GetLastError()!=NO_ERROR &&
        GetLastError()!=ERROR_NO_MORE_ITEMS )
   {
       // Insert error handling here.
       return; //1;
   }

   //  Cleanup
   SetupDiDestroyDeviceInfoList(hDevInfo);

   return;// 0;

I moved a little further, but still i can't get the data from device.

  1. To obtain "Device Interface Path" had to use the other functions: SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces and SetupDiGetDeviceInterfaceDetail.

  2. Next, with CreateFile I get HANDLE BLE-device.

    hComm = CreateFile(pInterfaceDetailData->DevicePath, GENERIC_WRITE | GENERIC_READ,NULL,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);

  3. Next using WinAPI BluetoothGATTGetServices and BluetoothGATTGetCharacteristics I get the appropriate structures.

But when trying to get the property value with BluetoothGATTGetCharacteristicsValue, I get ERROR_ACCESS_DENIED.

And then I do not know what to do. What could be wrong?

2
Any progress with that?Pupsik
Which interface UUID did you use to find your device? GUID_BTHPORT_DEVICE_INTERFACE only returned the internal BLE scanner.Myon

2 Answers

0
votes

Andrey, I think the problem is that your device is not connected and BluetoothGATTGetCharacteristicsValue is not triggering a connection.

Try manually to connect your device using Windows tools. I've the following flow that helps me: Unpair device, Pair device -> It should appear as connected ( it worked in my case ;) )

Anyway, If this is not helping, try to run "As Administrator", this helps in some cases.

Good luck!!!

0
votes

Note: Would be very interested to know how to retrievethe device path for the BTLE device in order to call BluetoothGATTGetServices?

gattServiceGUID is any long form BLE UUID supported by your device.

"{00001803-0000-1000-8000-00805F9B34FB"} can be used to open a handle to the Link Loss service if supported by the device you are trying to open

HDEVINFO hDevInfo = SetupDiGetClassDevs(&gattServiceGUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

if (hDevInfo != INVALID_HANDLE_VALUE)
{
    SP_DEVICE_INTERFACE_DATA interfaceData;
    ZeroMemory(&interfaceData,sizeof(SP_DEVICE_INTERFACE_DATA));
    interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    for (DWORD dwDeviceIndex = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &gattServiceGUID, dwDeviceIndex, &interfaceData); dwDeviceIndex++)
    {                       
        dwDeviceCount++;
        SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, NULL, 0, &dwBytesNeeded, NULL);
        if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
            pInterfaceDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA) new byte[dwBytesNeeded];

            SP_DEVINFO_DATA spDeviceInfoData = { sizeof(SP_DEVINFO_DATA) };

            ZeroMemory(pInterfaceDetail, sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA));
            pInterfaceDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);

            //  grab the interface detail
            if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, pInterfaceDetail, dwBytesNeeded, NULL, &spDeviceInfoData) == TRUE)
            {
                //  request a handle to the GATT service path
                m_hGattServiceHandle = CreateFile(pInterfaceDetail->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
                if (m_hGattServiceHandle != INVALID_HANDLE_VALUE)
                {
                    now you can drill down the characteristics and descriptors with the m_hGattServiceHandle 
                }
            }
        }
    }
}