code_enthusiast Ответов: 2

Bluetooth low energy-Программирование windows


Я новичок в разработке приложений для Windows. В настоящее время я работаю над проектом по написанию коммуникационного уровня с использованием Bluetooth low energy, который должен работать как на windows 8.1, так и на windows 10. Ниже приведен код, который я использовал для запуска списка служб BLE,

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
#include <bthdef.h>
#include <bluetoothleapis.h>
#pragma comment(lib, "SetupAPI")
#pragma comment(lib, "BluetoothApis.lib")
#define TO_SEARCH_DEVICE_UUID "{0000b81d-0000-1000-8000-00805f9b34fb}" 


void EventNotif(BTH_LE_GATT_EVENT_TYPE EventType, PVOID EventOutParameter, PVOID Context)
{
    printf("notification obtained ");
    PBLUETOOTH_GATT_VALUE_CHANGED_EVENT ValueChangedEventParameters = (PBLUETOOTH_GATT_VALUE_CHANGED_EVENT)EventOutParameter;

    HRESULT hr;
    if (0 == ValueChangedEventParameters->CharacteristicValue->DataSize) {
        hr = E_FAIL;
        printf("datasize 0\n");
    }
    else {
        printf("char ");
        unsigned heart_rate;
        if (0x01 == (ValueChangedEventParameters->CharacteristicValue->Data[0] & 0x01)) {
            heart_rate = ValueChangedEventParameters->CharacteristicValue->Data[1] * 256 + ValueChangedEventParameters->CharacteristicValue->Data[2];
        }
        else {
            heart_rate = ValueChangedEventParameters->CharacteristicValue->Data[1];
        }
        printf("%d\n", heart_rate);
    }
}

HANDLE GetBLEHandle(__in GUID AGuid)
{
    HDEVINFO hDI;
    SP_DEVICE_INTERFACE_DATA did;
    SP_DEVINFO_DATA dd;
    GUID BluetoothInterfaceGUID = AGuid;
    HANDLE hComm = NULL;

    hDI = SetupDiGetClassDevs(&BluetoothInterfaceGUID, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);

    if (hDI == INVALID_HANDLE_VALUE) return NULL;

    did.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    dd.cbSize = sizeof(SP_DEVINFO_DATA);

    for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDI, NULL, &BluetoothInterfaceGUID, i, &did); i++)
    {
        SP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;

        DeviceInterfaceDetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

        DWORD size = 0;

        if (!SetupDiGetDeviceInterfaceDetail(hDI, &did, NULL, 0, &size, 0))
        {
            int err = GetLastError();

            if (err == ERROR_NO_MORE_ITEMS) break;

            PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)GlobalAlloc(GPTR, size);

            pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

            if (!SetupDiGetDeviceInterfaceDetail(hDI, &did, pInterfaceDetailData, size, &size, &dd))
                break;

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

            GlobalFree(pInterfaceDetailData);
        }
    }

    SetupDiDestroyDeviceInfoList(hDI);
    return hComm;
}


int main(int argc, char *argv[], char *envp[])
{

    GUID AGuid;
    CLSIDFromString(TEXT(TO_SEARCH_DEVICE_UUID), &AGuid);

    HANDLE hLEDevice = GetBLEHandle(AGuid);


    USHORT serviceBufferCount;


    HRESULT hr = BluetoothGATTGetServices(
        hLEDevice,
        0,
        NULL,
        &serviceBufferCount,
        BLUETOOTH_GATT_FLAG_NONE);

    if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) != hr) {
        printf("BluetoothGATTGetServices - Buffer Size %d", hr);
    }

    PBTH_LE_GATT_SERVICE pServiceBuffer = (PBTH_LE_GATT_SERVICE)
        malloc(sizeof(BTH_LE_GATT_SERVICE) * serviceBufferCount);

    if (NULL == pServiceBuffer) {
        printf("pServiceBuffer out of memory\r\n");
    }
    else {
        RtlZeroMemory(pServiceBuffer,
            sizeof(BTH_LE_GATT_SERVICE) * serviceBufferCount);
    }



    USHORT numServices;
    hr = BluetoothGATTGetServices(
        hLEDevice,
        serviceBufferCount,
        pServiceBuffer,
        &numServices,
        BLUETOOTH_GATT_FLAG_NONE);

    if (S_OK != hr) {
        printf("BluetoothGATTGetServices - Buffer Size %d", hr);
    }





    USHORT charBufferSize;
    hr = BluetoothGATTGetCharacteristics(
        hLEDevice,
        pServiceBuffer,
        0,
        NULL,
        &charBufferSize,
        BLUETOOTH_GATT_FLAG_NONE);

    if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) != hr) {
        printf("BluetoothGATTGetCharacteristics - Buffer Size %d", hr);
    }

    PBTH_LE_GATT_CHARACTERISTIC pCharBuffer;
    if (charBufferSize > 0) {
        pCharBuffer = (PBTH_LE_GATT_CHARACTERISTIC)
            malloc(charBufferSize * sizeof(BTH_LE_GATT_CHARACTERISTIC));

        if (NULL == pCharBuffer) {
            printf("pCharBuffer out of memory\r\n");
        }
        else {
            RtlZeroMemory(pCharBuffer,
                charBufferSize * sizeof(BTH_LE_GATT_CHARACTERISTIC));
        }

        USHORT numChars;
        hr = BluetoothGATTGetCharacteristics(
            hLEDevice,
            pServiceBuffer,
            charBufferSize,
            pCharBuffer,
            &numChars,
            BLUETOOTH_GATT_FLAG_NONE);

        if (S_OK != hr) {
            printf("BluetoothGATTGetCharacteristics - Actual Data %d", hr);
        }

        if (numChars != charBufferSize) {
            printf("buffer size and buffer size actual size mismatch\r\n");
        }
    }




    PBTH_LE_GATT_CHARACTERISTIC currGattChar;
    for (int ii = 0; ii <charBufferSize; ii++) {
        currGattChar = &pCharBuffer[ii];
        USHORT charValueDataSize;
        PBTH_LE_GATT_CHARACTERISTIC_VALUE pCharValueBuffer;



        USHORT descriptorBufferSize;
        hr = BluetoothGATTGetDescriptors(
            hLEDevice,
            currGattChar,
            0,
            NULL,
            &descriptorBufferSize,
            BLUETOOTH_GATT_FLAG_NONE);

        if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) != hr) {
            printf("BluetoothGATTGetDescriptors - Buffer Size %d", hr);
        }

        PBTH_LE_GATT_DESCRIPTOR pDescriptorBuffer;
        if (descriptorBufferSize > 0) {
            pDescriptorBuffer = (PBTH_LE_GATT_DESCRIPTOR)
                malloc(descriptorBufferSize
                    * sizeof(BTH_LE_GATT_DESCRIPTOR));

            if (NULL == pDescriptorBuffer) {
                printf("pDescriptorBuffer out of memory\r\n");
            }
            else {
                RtlZeroMemory(pDescriptorBuffer, descriptorBufferSize);
            }

            ////////////////////////////////////////////////////////////////////////////
            // Retrieve Descriptors
            ////////////////////////////////////////////////////////////////////////////

            USHORT numDescriptors;
            hr = BluetoothGATTGetDescriptors(
                hLEDevice,
                currGattChar,
                descriptorBufferSize,
                pDescriptorBuffer,
                &numDescriptors,
                BLUETOOTH_GATT_FLAG_NONE);

            if (S_OK != hr) {
                printf("BluetoothGATTGetDescriptors - Actual Data %d", hr);
            }

            if (numDescriptors != descriptorBufferSize) {
                printf("buffer size and buffer size actual size mismatch\r\n");
            }

            for (int kk = 0; kk<numDescriptors; kk++) {
                PBTH_LE_GATT_DESCRIPTOR  currGattDescriptor = &pDescriptorBuffer[kk];
                ////////////////////////////////////////////////////////////////////////////
                // Determine Descriptor Value Buffer Size
                ////////////////////////////////////////////////////////////////////////////
                USHORT descValueDataSize;
                hr = BluetoothGATTGetDescriptorValue(
                    hLEDevice,
                    currGattDescriptor,
                    0,
                    NULL,
                    &descValueDataSize,
                    BLUETOOTH_GATT_FLAG_NONE);

                if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) != hr) {
                    printf("BluetoothGATTGetDescriptorValue - Buffer Size %d", hr);
                }

                PBTH_LE_GATT_DESCRIPTOR_VALUE pDescValueBuffer = (PBTH_LE_GATT_DESCRIPTOR_VALUE)malloc(descValueDataSize);

                if (NULL == pDescValueBuffer) {
                    printf("pDescValueBuffer out of memory\r\n");
                }
                else {
                    RtlZeroMemory(pDescValueBuffer, descValueDataSize);
                }

                ////////////////////////////////////////////////////////////////////////////
                // Retrieve the Descriptor Value
                ////////////////////////////////////////////////////////////////////////////

                hr = BluetoothGATTGetDescriptorValue(
                    hLEDevice,
                    currGattDescriptor,
                    (ULONG)descValueDataSize,
                    pDescValueBuffer,
                    NULL,
                    BLUETOOTH_GATT_FLAG_NONE);
                if (S_OK != hr) {
                    printf("BluetoothGATTGetDescriptorValue - Actual Data %d", hr);
                }

                if (currGattDescriptor->AttributeHandle < 255) {
                    BTH_LE_GATT_DESCRIPTOR_VALUE newValue;

                    RtlZeroMemory(&newValue, sizeof(newValue));

                    newValue.DescriptorType = ClientCharacteristicConfiguration;
                    newValue.ClientCharacteristicConfiguration.IsSubscribeToNotification = TRUE;

                    hr = BluetoothGATTSetDescriptorValue(
                        hLEDevice,
                        currGattDescriptor,
                        &newValue,
                        BLUETOOTH_GATT_FLAG_NONE);
                    if (S_OK != hr) {
                        printf("BluetoothGATTGetDescriptorValue - Actual Data %d", hr);
                    }
                    else {
                        printf("setting notification for serivice handle %d\n", currGattDescriptor->ServiceHandle);
                    }

                }

            }
        }


        BLUETOOTH_GATT_EVENT_HANDLE EventHandle;

        if (currGattChar->IsNotifiable) {
            printf("Setting Notification for ServiceHandle %d\n", currGattChar->ServiceHandle);
            BTH_LE_GATT_EVENT_TYPE EventType = CharacteristicValueChangedEvent;

            BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION EventParameterIn;
            EventParameterIn.Characteristics[0] = *currGattChar;
            EventParameterIn.NumCharacteristics = 1;
            //hr = BluetoothGATTRegisterEvent(
            //hLEDevice,
            //EventType,
            //&EventParameterIn,
            //EventNotif,
            //NULL,
            //&EventHandle,
            //BLUETOOTH_GATT_FLAG_NONE);

            if (S_OK != hr) {
                printf("BluetoothGATTRegisterEvent - Actual Data %d", hr);
            }
        }


        if (currGattChar->IsReadable) {
            hr = BluetoothGATTGetCharacteristicValue(
                hLEDevice,
                currGattChar,
                0,
                NULL,
                &charValueDataSize,
                BLUETOOTH_GATT_FLAG_NONE);

            if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) != hr) {
                printf("BluetoothGATTGetCharacteristicValue - Buffer Size %d", hr);
            }

            pCharValueBuffer = (PBTH_LE_GATT_CHARACTERISTIC_VALUE)malloc(charValueDataSize);

            if (NULL == pCharValueBuffer) {
                printf("pCharValueBuffer out of memory\r\n");
            }
            else {
                RtlZeroMemory(pCharValueBuffer, charValueDataSize);
            }

            hr = BluetoothGATTGetCharacteristicValue(
                hLEDevice,
                currGattChar,
                (ULONG)charValueDataSize,
                pCharValueBuffer,
                NULL,
                BLUETOOTH_GATT_FLAG_NONE);

            if (S_OK != hr) {
                printf("BluetoothGATTGetCharacteristicValue - Actual Data %d", hr);
            }

            //print the characeteristic Value

            printf("\n Printing a read (not notifiable) characterstic (maybe) body sensor value");
            for (int iii = 0; iii< pCharValueBuffer->DataSize; iii++) {// ideally check ->DataSize before printing
                printf("%d", pCharValueBuffer->Data[iii]);
            }
            printf("\n");


            free(pCharValueBuffer);
            pCharValueBuffer = NULL;
        }

    }


    while (1) {
        Sleep(1000);

        //printf("look for notification\n");
        UCHAR dataBuffer[sizeof(int)];
        BTH_LE_GATT_CHARACTERISTIC_VALUE newValue;

        newValue.DataSize = 4;
        newValue.Data[0] = 1234;



            if (hr != S_OK) {
                printf("Failed to write characteristic\n");
            }
        }

    CloseHandle(hLEDevice);



    if (GetLastError() != NO_ERROR &&
        GetLastError() != ERROR_NO_MORE_ITEMS)
    {

        return 1;
    }

    return 0;
}



Код успешно скомпилирован и работает в режиме отладки. Однако ближайшие услуги BLE не перечислены. Кроме того, когда я закрываю приложение из режима отладки, я получаю следующие ошибки в консоли отладки,

onecore\drivers\bluetooth\legacy\win32leadapter\client\lib\gattlegacyapiclient.cpp(164)\BluetoothApis.dll!5177642F: (caller: 51773B3A) ReturnHr(1) tid(2094) 80070006 The handle is invalid. onecore\drivers\bluetooth\legacy\win32leadapter\client\lib\gattlegacyapiclient.cpp(164)\BluetoothApis.dll!5177642F: (caller: 51773B3A) ReturnHr(2) tid(2094) 80070006 The handle is invalid. onecore\drivers\bluetooth\legacy\win32leadapter\client\lib\gattlegacyapiclient.cpp(308)\BluetoothApis.dll!51775956: (caller: 517739ED) ReturnHr(3) tid(2094) 80070006 The handle is invalid.


Что я уже пробовал:

Моя среда разработки-VS 2017 на Windows 10.

Пожалуйста, помогите мне разобраться в этом вопросе

2 Ответов

Рейтинг:
1

Jochen Arndt

Вы, вероятно, никогда не получите действительный дескриптор от GetBLEHandle. Ваш код в main() не проверяет возвращаемое значение и сама функция работает не так, как ожидалось:

if (!SetupDiGetDeviceInterfaceDetail(hDI, &did, NULL, 0, &size, 0))
{
int err = GetLastError();
if (err == ERROR_NO_MORE_ITEMS) break;
// ...
В приведенном выше фрагменте вы проверяете наличие ошибок (SetupDiGetDeviceInterfaceDetail возвращается FALSE) но нет else условие для случая успеха.

Вам понадобится что-то вроде этого:
DWORD dwErr = 0;
for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDI, NULL, &BluetoothInterfaceGUID, i, &did); i++)
{
    SP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
    DeviceInterfaceDetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    DWORD size = 0;
    if (!SetupDiGetDeviceInterfaceDetail(hDI, &did, NULL, 0, &size, 0))
    {
        DWORD err = GetLastError();
        // Set main error if not just no more items
        if (err != ERROR_NO_MORE_ITEMS)
        {
            dwErr = err;
            TRACE1("SetupDiGetDeviceInterfaceDetail failed with error %d\n", err);
        }
        break;
    }
    // Further processing goes here
}
Обратите внимание на TRACE оператор, который будет информировать вас об ошибках при запуске из отладчика. Такие действительно полезны, когда что-то работает не так, как ожидалось, и распечатывает коды ошибок. В качестве альтернативы запустите приложение шаг за шагом из отладчика и проверьте свои переменные, чтобы увидеть, где происходит что-то неожиданное.

Обратите внимание также, что как только вы исправите эту ошибку, ваш цикл откроет все найденные интерфейсы и вернет только дескриптор для последнего. Вы должны разорвать цикл после открытия первого интерфейса или сохранить имена в массиве и предоставить возможность выбора из найденных интерфейсов.

Также нет необходимости использовать GlobalAlloc здесь. Просто использовать new и delete.

Я не проверил весь оставшийся код, потому что вышеуказанные ошибки находятся в начальных частях кода и поэтому должны быть проверены в первую очередь. Если их больше, используйте отладчик и / или расширенные проверки ошибок. Во время печати некоторых сообщений об ошибках вы также должны возвращать сообщения об ошибках, чтобы избежать вызова следующих функций с недопустимыми параметрами.


Рейтинг:
0

KarstenK

В API есть какая-то ошибка. Прочтите эту статью по адресу Переполнение стека с некоторыми дополнительными подсказками для обновления.

Ваш поток кода глючит. Никогда не используйте дескриптор повторно несколько раз, это уникальный ресурс sysetm.
И не закрывайте дескриптор несколько раз, а установите значение NULL, когда закончите!!!