Опубликован: 11.01.2013 | Доступ: свободный | Студентов: 623 / 124 | Длительность: 12:06:00
Лекция 9:

Лабораторный практикум по технологиям Bluetooth и Wi-Fi

< Лекция 8 || Лекция 9: 12345
Аннотация: Лабораторные работки, посвященные технологиям Bluetooth и Wi-Fi.

Простейшее Bluetooth-приложение: Поиск доступных Bluetooth устройств

Лабораторная работа №1. Данная лабораторная работа открывает курс из трех лабораторных работ по программированию Bluetooth для операционных систем Windows с использованием стека Microsoft. Она посвящена выполнению специфичной для Bluetooth функции – поиску устройств, доступных в нашем радиусе действия. Навыки, полученные при ее выполнении, служат основой для успешной сдачи следующих лабораторных работ, т.к. в каждой из них требуется выполнить начальный поиск устройств перед выполнением последующих действий.

Постановка задачи

Написать программу, которая выводит на экран список всех доступных Bluetooth-устройств. Для каждого устройства необходимо вывести на экран его сетевое имя.

Методические рекомендации

При программировании Bluetooth под стек Microsoft используется стандартный Windows Sockets API, с помощью которого пишется большинство сетевых приложений для Windows.

Поэтому в начале работы любого Bluetooth приложения необходимо проинициализировать WinSock с помощью функции WSAStartup().

 WSADATA data;
if (WSAStartup(0x0202, &data) != 0) // Используем WinSock 2.2
{
    // Выход по ошибке
}

Поиск устройств осуществляется при помощи последовательного вызова функций WSALookupServiceBegin(), WSALookupServiceNext() и WSALookupServiceEnd().

int WSALookupServiceBegin(LPWSAQUERYSET lpqsRestrictions,
     DWORD         dwControlFlags,
     LPHANDLE      lphLookup);

int WSALookupServiceNext(HANDLE        hLookup,
    DWORD         dwControlFlags,
    LPDWORD       lpdwBufferLength,
    LPWSAQUERYSET lpqsResults);

int WSALookupServiceEnd(HANDLE hLookup);

WSALookupServiceBegin() инициализирует поиск устройств и возвращает через параметр lphLookup дескриптор (handle), который используется затем для последовательного опроса всех устройств с целью получения необходимой информации о них. В случае успешной инициализации функция вернет 0, в противном случае SOCKET_ERROR. Описание возникшей ошибки (это касается всех сокетных функций) можно получить при помощи функции WSAGetLastError().

Настройка параметров и получение результата поиска происходит через структуру WSAQUERYSET.

 struct WSAQUERYSET 
{
    DWORD         dwSize;
    LPTSTR        lpszServiceInstanceName;
    LPGUID        lpServiceClassId;
    LPWSAVERSION  lpVersion;
    LPTSTR        lpszComment;
    DWORD         dwNameSpace;
    LPGUID        lpNSProviderId;
    LPTSTR        lpszContext;
    DWORD         dwNumberOfProtocols;
    LPAFPROTOCOLS lpafpProtocols;
    LPTSTR        lpszQueryString;
    DWORD         dwNumberOfCsAddrs;
    LPCSADDR_INFO lpcsaBuffer;
    DWORD         dwOutputFlags;
    LPBLOB        lpBlob;
};

Большинство полей данной структуры нам не понадобится. Детальное их описание при желании можно посмотреть в MSDN.

Указатель на эту структуру, который затем передается WSALookupServiceNext() для получения информации о конкретном устройстве, является также указателем на буфер, в который будут записываться выходные результаты. Поэтому память нужно выделять большего размера, чем размер самой структуры. Чтобы не было непонятных ошибок, советуем выделять 10Kb памяти, этого точно хватит.

После выделения памяти, необходимо установить правильные значения для двух полей WSAQUERYSET: dwSize должен содержать настоящий размер структуры, dwNameSpace для Bluetooth должен быть равен NS_BTH.

Для инициализации поиска устройств параметр dwControlFlags у WSALookupServiceBegin() должен быть равен LUP_CONTAINERS. Чтобы иформация бралась не из кэша, можно его скомбинировать с LUP_FLUSHCACHE.

Пример инициализации поиска устройств:

#define BUF_SIZE 10240    

// Выделяем память под буфер
WSAQUERYSET* pQuerySet = (WSAQUERYSET*) new BYTE[BUF_SIZE];

// Очищаем его и устанавливаем необходимые параметры
ZeroMemory(pQuerySet, BUF_SIZE);
pQuerySet->dwSize = sizeof(WSAQUERYSET);
pQuerySet->dwNameSpace = NS_BTH;

// Запускаем поиск устройств
HANDLE lookupHandle = 0;
int    lookupResult = WSALookupServiceBegin(pQuerySet,
            LUP_CONTAINERS | LUP_FLUSHCACHE,
            &lookupHandle);
if (lookupResult != 0)
{
    // Ошибка при инициализации поиска
}

Если инициализация поиска прошла успешно, можно начинать сам опрос устройств. Опрос следующего устройства осуществляется с помощью функции WSALookupServiceNext(), в которую нужно передать дескриптор, возвращенный WSALookupServiceBegin(). Если устройств больше нет, функция вернет 0. Параметр dwControlFlags определяет, какую информацию мы хотим получить при опросе. Например, задав его LUP_RETURN_NAME, нам вернут имя устройства, LUP_RETURN_ADDR – его сокетный адрес (он нам понадобится для следующих лабораторных работ). Имя устройства будет тогда находиться в поле lpszServiceInstanceName структуры WSAQUERYSET, сокетный адрес – в поле lpcsaBuffer->RemoteAddr.lpSockaddr. Данные флаги можно комбинировать между собой. Описание всех флагов можно найти в MSDN. В lpdwBufferLength нужно передать реальный размер буфера, который мы выделили. Если он слишком маленький, WSAGetLastError() вернет WSAEFAULT.

Поиск нужно завершать вызовом WSALookupServiceEnd(), передав в нее дескриптор поиска.

while (lookupResult == 0)
{
    DWORD  bufferLen = BUF_SIZE;

    lookupResult = WSALookupServiceNext(lookupHandle,
                 LUP_RETURN_NAME | LUP_RETURN_ADDR,
                 &bufferLen,
                  pQuerySet);
    if (lookupResult != 0)
        break;

    cout << "Device found: " << pQuerySet->lpszServiceInstanceName << endl;
}

WSALookupServiceEnd(lookupHandle);

В конце работы с Windows Sockets for Bluetooth нужно вызвать WSACleanup().

< Лекция 8 || Лекция 9: 12345