< Asynchronous Transfer Mode (ATM) | Winsock2 Supported Protocols Main | Bluetooth Device Query Example >
What do we have in this chapter 4 part 11?
|
Bluetooth
Bluetooth is an industry-standard protocol that enables wireless connectivity for computers, handheld devices, mobile phones, and other devices. In normal applications it already surpassed the infrared technology. Bluetooth is designed for use by C/C++ programmers and some Bluetooth features are available with Windows Sockets. Microsoft Bluetooth supports begin with Windows XP with Service Pack 1 (SP1). Support for Bluetooth 2.1 is offered via the latest Windows Vista Feature Pack for Wireless. The header file associated with this update is available at Microsoft Connect via the Windows Vista Feature Pack for Wireless Developers Supplement download.
Stack
A diagram of the Bluetooth stack is shown in Figure 4-2. The lower three layers - Baseband, Link Manager Protocol, and the first Host Controller Interface (HCI) layer, are implemented in the Bluetooth hardware. The layers above the hardware and below the application are provided by Windows CE, although it’s possible for third parties to extend the Bluetooth stack by providing additional profiles above the HCI layer. Applications interact with the Bluetooth stack through one of two interfaces. The preferred method is for applications to use the Winsock API to access the Bluetooth stack. Just as with IrDA, applications use standard Winsock functions to open sockets associated with the Bluetooth stack. Control is accomplished through various WSAxxx() functions. Data transfer is accomplished through the standard socket send and recv functions.
Figure 4-2 A diagram of the Bluetooth stack on Windows CE |
Winsock support for Bluetooth depends on the Winsock stack installed on the device. If the system has Winsock 2.0 installed, such as Windows Mobile devices, Bluetooth functionality is accessed directly through Winsock calls such as setsockopt(). For systems with Winsock 1.1 installed, the Bluetooth stack needs to be configured through a dedicated Bluetooth API. For example, to query the current mode of an asynchronous connection, an application can use the dedicated function BthGetCurrentMode() or, if Winsock 2.0 is on the system, a call to getsockopt() with the option name SO_BTH_GET_MODE.
The other way applications can work with Bluetooth is through virtual serial ports. With this method, applications load a Bluetooth-dedicated serial driver. Control of the stack is accomplished through DeviceIoControl() calls to the COM driver. Calling WriteFile() and ReadFile() to write and read the COM port sends and receives data across the Bluetooth connection.
In the programming part of the bluetooth, normally are based on the two bluetooth stacks: Microsoft and Widcomm/Broadcom. Program created based on the Microsoft stack cannot be run on the Widcomm/Broadcom. In simple word, there isn't a single method which works on all stacks. Most notebook and IPAQ range of products for example, use Widcomm/Broadcom stack. Widcomm provide their own SDK for their bluetooth stack and you can download the widcomm SDK from their website for bluetooth programming. Some OEMs have chosen not to use the Microsoft bluetooth stack. This means the examples created based on the Microsoft stack will not operate on those devices.
The winsock APIs only work with the Microsoft stack and there are Windows CE SDK and Win32 Platform SDK for bluetooth programming. The Bluetooth APIs exposed on a Windows CE/Windows Mobile device has a slightly different design. With some features not exposed and others exposed differently. The header files and libraries used also different except winsock.h/winsock2.h (ws2_32.lib). In this chapter we will try to demonstrate code samples from both Windows CE SDK and Win32 Platform SDK. It is better for you to choose one SDK and not mix both SDKs in one program. For desktop bluetooth application development, of course to choose the Win32 Platform SDK.
An application can create a query for discovering remote Bluetooth devices within range, by using the following standard Winsock programming elements:
The sample that ships with Windows Embedded CE contains source code for discovering Bluetooth devices by using Winsock. To perform device discovery and retrieve the address of a remote Bluetooth device:
1. Prepare the caller application by providing Winsock-related data such as version and implementation details. This data can be retrieved by calling the WSAStartup() function as the following example shows.
WSADATA wsd;
WSAStartup (MAKEWORD(1,0), &wsd);
2. Create and initialize a WSAQUERYSET variable to specify search parameters. Set the dwNameSpace member to NS_BTH to restrict the query to Bluetooth devices. The following code example shows the values to set in WSAQUERYSET.
WSAQUERYSET wsaq;
ZeroMemory(&wsaq, sizeof(wsaq));
wsaq.dwSize = sizeof(wsaq);
wsaq.dwNameSpace = NS_BTH;
wsaq.lpcsaBuffer = NULL;
3. To start an inquiry, call the WSALookupServiceBegin() function. The following code example shows how to call WSALookupServiceBegin() to perform a device inquiry by passing the WSAQUERYSET variable, created in step 1.
int iRet = WSALookupServiceBegin (&wsaq, LUP_CONTAINERS, &hLookup);
In the preceding example, LUP_CONTAINERS is passed in the dwFlags parameter. This enables Service Discovery Protocol (SDP) to search for other Bluetooth devices within range. Passing zero (0) in the dwFlags parameter performs a service search. The WSALookupServiceBegin() function returns a handle in the hLookup parameter.
4. To enumerate devices that were scanned in the previous call to WSALookupServiceBegin(), call the WSALookupServiceNext() function. This function returns a pointer to a buffer that stores the result set in a WSAQUERYSET structure.
a. Configure a WSAQUERYSET structure to store device data returned by WSALookupServiceNext(). The following code shows how to configure this structure.
CHAR buf[4096];
LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf;
ZeroMemory(pwsaResults, sizeof(WSAQUERYSET));
pwsaResults->dwSize = sizeof(WSAQUERYSET);
pwsaResults->dwNameSpace = NS_BTH;
pwsaResults->lpBlob = NULL;
b. Call WSALookupServiceNext() by passing the handle returned by WSALookupServiceBegin() in the hLookUp parameter. To improve performance, the call to WSALookupServiceBegin() returns only the addresses of the devices, and these addresses are stored in memory. To retrieve the name and address of the device, pass LUP_RETURN_NAME | LUP_RETURN_ADDR in the dwFlags parameter. The following code shows how to call WSALookupServiceNext().
DWORD dwSize = sizeof(buf);
int iRet = WSALookupServiceNext (hLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR, &dwSize, pwsaResults)
5. To enumerate the devices, the caller application can loop through the list of devices, by calling WSALookupServiceNext() repetitively.
6. To terminate the device discovery process, call the WSALookupServiceEnd() function. This function releases the lookup handle created by WSALookupServiceBegin(). The following code shows how to call WSALookupServiceEnd().
WSALookupServiceEnd(hLookup);
7. To terminate the use of Winsock services, call the WSACleanup() function. There must be a call to WSACleanup() for every successful call to WSAStartup() made by an application.
The following code example performs a device inquiry displays the device name in a console. Create a new empty Win32 console mode application and add the project/solution name.
----------------------------------------------------------------
Add the following source code.
// Note: These header files used are from the
// Windows SDKs v6.0A. The Windows CE header files
// are different though some of the file names might be similar
// and this is 'tally' with the VS project type. In full version VS
// there is a project template for Windows CE which is SmartDevice.
// Choosing the SmartDevice project template will 'bind' the project
// to the appropriate header files and library
// Link to ws2_32.lib
#include <winsock2.h>
#include <ws2bth.h>
#include <BluetoothAPIs.h>
#include <stdio.h>
#define MAX_NAME 248
typedef ULONGLONG bt_addr, *pbt_addr, BT_ADDR, *PBT_ADDR;
union {
// Storage for returned struct
CHAR buf[5000];
// properly align buffer to BT_ADDR requirements
SOCKADDR_BTH _Unused_;
} butuh;
//------------------------------------------------------------------------
// Function: FindingBtDevices
// Purpose: Performs a device inquiry displays the device name in a console
//------------------------------------------------------------------------
BOOL FindingBtDevices()
{
WSAQUERYSET wsaq;
HANDLE hLookup;
LPWSAQUERYSET pwsaResults;
DWORD dwSize;
BOOL bHaveName;
BT_ADDR btAddr;
DWORD dwNameSpace;
pwsaResults = (LPWSAQUERYSET) butuh.buf;
dwSize = sizeof(butuh.buf);
ZeroMemory(&wsaq, sizeof(wsaq));
wsaq.dwSize = sizeof(wsaq);
// namespace MUST be NS_BTH for bluetooth queries
wsaq.dwNameSpace = NS_BTH;
wsaq.lpcsaBuffer = NULL;
printf("\n");
// initialize searching procedure
if (WSALookupServiceBegin(&wsaq, LUP_CONTAINERS, &hLookup) == SOCKET_ERROR)
{
printf("WSALookupServiceBegin() failed %d\r\n", WSAGetLastError());
return FALSE;
}
else
printf("WSALookupServiceBegin() pretty damn OK!\n");
ZeroMemory(pwsaResults, sizeof(WSAQUERYSET));
pwsaResults->dwSize = sizeof(WSAQUERYSET);
pwsaResults->dwNameSpace = NS_BTH;
pwsaResults->lpBlob = NULL;
// iterate through all found devices, returning name and address
while (WSALookupServiceNext(hLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR, &dwSize, pwsaResults) == 0)
{
btAddr = ((SOCKADDR_BTH *)pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr;
// Verify the returned name
bHaveName = (pwsaResults->lpszServiceInstanceName) && *(pwsaResults->lpszServiceInstanceName);
dwNameSpace = pwsaResults->dwNameSpace;
// print name and address
wprintf (L"Name\tNAP Address\tSAP Address\tName Space\n");
wprintf (L"%s\t0X%04X\t\t0X%08X\t0X%0X\n", pwsaResults->lpszServiceInstanceName, GET_NAP(btAddr), GET_SAP(btAddr),
dwNameSpace);
}
if(WSALookupServiceEnd(hLookup) == 0)
printf("WSALookupServiceEnd(hLookup) is OK!\n");
else
printf("WSALookupServiceEnd(hLookup) failed with error code %ld\n",WSAGetLastError());
return TRUE;
}
int main(int argc, char **argv)
{
WSADATA wsd;
BOOL retVal;
if(WSAStartup(MAKEWORD(2,2), &wsd) != 0)
printf("WSAStartup() failed with error code %ld\n", WSAGetLastError());
else
printf("WSAStartup() is OK!\n");
retVal = FindingBtDevices();
if(FindingBtDevices() == FALSE)
printf("\nNo bulutooth device in range found!\n");
else
printf("\nWell, found some bluetooth devices around!\n");
if(WSACleanup() == 0)
printf("WSACleanup() is OK!\n");
else
printf("WSACleanup() failed with error code %ld\n", WSAGetLastError());
return 0;
}
Build and run the project. The following is a sample output screenshot.
< Asynchronous Transfer Mode (ATM) | Winsock2 Supported Protocols Main | Bluetooth Device Query Example >