MobileExperiencing This Mysterious Bluetooth Stack Programming

Experiencing This Mysterious Bluetooth Stack Programming

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

If you ever were involved in any Bluetooth-related development at application level, you admit that it is one big headache from portability point of view. Most mobile devices have either Widcomm BT stack or Microsoft’s one. There are also some others, but those two are very popular. Putting aside an issue that they are totally incompatible, developers have had another big trouble: Microsoft’s BT SDK was free, while Widcomm BT Stack and SDK were commercial products and therefore were quite (if such a word is appropriate for a price of about USD1500 per developer license) expensive. There were also some third-party products created as wrappers around original SDK, but they usually were not good enough to address all requirements. Recently times have changed, and now, after Broadcomm acquired Widcomm, this SDK has changed its status too—you can download it from here.

As I said above, Microsoft and Widcomm BT Stacks are quite different. For instance, while Microsoft follows its regular C style, Widcomm SDK is implemented as a set of C++ classes. Besides, the latter SDK doesn’t have sockets support, but does expose virtual COM ports. As a result, you might need to maintain separate wrapper classes for every BT stack. You can go even further and use standard Microsoft’s structures to keep various information about BT devices and so forth to minimize maintenance effort. This article will discuss Widcomm Bluetooth SDK.

Widcomm SDK and So Forth

Now, when we are ready to put our hands on something useful, let’s consider some simple application which enumerates BT devices lurked around. For every found entity, you will request a list of available services and some other information. So, your magic door to Widcomm SDK is called BtSdkCE.h. Tbe first thing to do is to list exported classes:

  • class WIDCOMMSDK CBtIf
  • class WIDCOMMSDK CL2CapIf
  • class WIDCOMMSDK CL2CapConn
  • class WIDCOMMSDK CSdpService
  • class WIDCOMMSDK CSdpDiscoveryRec
  • class WIDCOMMSDK CRfCommIf
  • class WIDCOMMSDK CRfCommPort
  • class WIDCOMMSDK CFtpClient
  • class WIDCOMMSDK COppClient
  • class WIDCOMMSDK CLapClient
  • class WIDCOMMSDK CDunClient
  • class WIDCOMMSDK CSppClient
  • class WIDCOMMSDK CSppServer
  • class WIDCOMMSDK CPrintClient

As you see, you have wide range of API to perform all required operations with BT stack: device discovery interface, few communication clients and servers, virtual serial ports, different connection type interfaces and so forth. In addition, you have a number of OBEX classes available.

A class of our main interest is CBtIf, which you will usually inherit and implement few virtual functions to get notified about; for example, discovered device:

   virtual void OnAudioConnected(UINT16 audioHandle){};
   virtual void OnAudioDisconnect(UINT16 audioHandle){};
   virtual void OnStackStatusChange(CBtIf::STACK_STATUS new_status) {}
   virtual void OnInquiryComplete (BOOL success,
                                   short num_responses) {}    // {}
   virtual void OnDeviceResponded (BD_ADDR bda, DEV_CLASS devClass,
                                   BD_NAME bdName,
                                   BOOL bConnected) {}        // = 0;
   virtual void OnDiscoveryComplete () {}                     // = 0;

A couple of them are pure virtual; in other words, you must provide your own implementation. Now, take a look at typical tasks you might want to get solved.

Device Inquiry

What you really should keep in mind is that the Widcomm Bluetooth stack is designed as multiuser, thus all operations are asynchronous. This design influences all your code. To add to this nice but complicating feature, you have to keep in mind that all your derived functions run in a separate thread and therefore must be thread-safe to avoid sporadical and weird behavior. This specifically relates to MFC classes if you ever use them. If the answer is “Yes,” you should avoid sharing such objects across the thread boundaries and rather make heap-based copies of data passed via parameters.

The stack itself provides few callback functions, but you will probably use the Windows messaging mechanism to propagate the BT events occurred, either with single or multiple messages. An alternative method is to use user-defined callback functions.

Having said this, you start from your own BT class derived from CBtIf:

#include <BtSdkCE.h>
...
class CBTWidcommStack : public CBtIf
{
public:
   CBTWidcommStack();
   virtual ~CBTWidcommStack();

   virtual void OnDeviceResponded(BD_ADDR bda, DEV_CLASS devClass,
                                  BD_NAME bdName, BOOL bConnected);
   virtual void OnDiscoveryComplete();
   virtual void OnInquiryComplete(BOOL bSuccess, short nResponses);
   ...
};

You can find in the SDK documentation that OnDeviceResponded is called upon every response from a found BT device. You may easily receive multiple responses from the same device several times during the given inquiry operation. You are responsible for filtering out such duplications.

OnDeviceResponded‘s parameters provide you with all you need to know about a BT device: BT address, class, and name as well as its connection status. You may use it to decide whether this given device is of any interest for your application—for example, if it is a printer or mobile phone.

The second pre-virtual function, OnDiscoveryComplete, is called on a query completion when your application requests services list from given device.

Thus, your typical solution may look like the following code snippet:

   ...
   if ( m_BTStack.StartInquiry() )
   {
      // do something
   }
   ...
void CBTWidcommStack::OnDeviceResponded(BD_ADDR bda,
                                        DEV_CLASS devClass,
                                        BD_NAME bdName,
                                        BOOL bConnected)
{
    // Notify the application somehow
}

void CBTWidcommStack::OnInquiryComplete(BOOL bSuccess,
                                        short nResponses)
{
   // Notify the application somehow
}

void CBTWidcommStack::OnDiscoveryComplete()
{
    // Notify the application somehow
}

Here, I would like to note that DEV_CLASS is 3-byte mask, and BD_NAME is represented in ASCII, so you may need to convert it to Unicode. Also, you can stop the device enumeration at any time calling m_BTStack.StopInquiry(). And, to complete this section, Widcomm SDK has a special function to shut down the stack:

WIDCOMMSDK_ShutDown();

that might be quite useful when you want to perform some kind of reset when the device stopped functioning properly for some reason.

Getting the devices’ service list

Well, once your application has trapped some BT device, why not discover which services it actually does support? With the Widcomm SDK, it’s a rather trivial task to accomplish. All you’re supposed to do is to call CBtIf::StartDiscovery(…) to initiate this process. If you know exactly which service you are going to discover, you may specify its GUID as a second parameter to reduce unwanted notifications. A full list of standard service GUIDs may be found in BtIfClasses.h. Again, it is an asynchronous operation, so when it finishes, a derived virtual function CYourStackClass::OnDiscoveryComplete will be launched. You can obtain the data through CBtIf::ReadDiscoveryRecords(…) call it, for example, like this:

CSdpDiscoveryRec sdpData[16];
// optionally, set it to desired service
GUID guidFilter = GUID_SERVICE_XXX;
int nServiceCount =
   m_BTStack.ReadDiscoveryRecords(btAddr,
                                  sizeof(sdpData)/
                                  sizeof(CSdpDiscoveryRec),
                                  sdpData, &guidFilter);
for (int i = 0; i < nServiceCount; i++)
{
   // process data
}

CSdpDiscoveryRec class has a number of member functions to gather any required information about given service: service name, RFComm channel, and so forth. You can easily use it as you please.

Using communications client classes

The Widcomm SDK has a number of communications client classes you may use in a quite straightforward way. I won’t discuss them here because the SDK samples give you an excellent explanation on various areas: FTP client, OBEX, and so on. In many cases, you can easily adjust them to your own purposes.

One Additional Possible Wrapper

To make your code more portable between different BT stacks (and Widcomm and Microsoft aren’t the only ones), you might go one step further and implement a bit more flexible approach that allows you to select a suitable SDK at runtime. Getting access to the classes exported from some DLL is a big headache in C++, so I won’t go this way. My approach employs the same idea as Microsoft ActiveSync with its plug-ins. First, you can declare some common base class with desired functionality that suits your needs:

class CBTInterfaceBase
{
public:
   CBTInterfaceBase();
   virtual ~CBTInterfaceBase();

   virtual int EnumDevices(.../*you can specify all you needs here*/);
   ...
};

Then, an actual implementation will be some kind of wrapping over given BT SDK—the Widcomm SDK in the current case. You can place this implementation into a DLL and load it dynamically. The only thing left to make it work is to declare a couple of functions with predefined names for creation/deletion of a base class object:

YOURAPI CBTInterfaceBase* CreateInterface()
{
   CBaseInterfaceBase *pItfce = new CSpecificClassHere;
   return pItfce;
}

YOURAPI void DestroyInterface(CBaseInterfaceBase*& pItfce)
{
   delete pItfce;
   pItfce = NULL;
}

Thus, you have some outer interface and an actual implementation hidden inside. You even might call it a “COM Interface” if you want because it is actually the same, but doesn’t require any additional registration. From the other side, it may be out of the needs of your application, so it’s up to you to decide whether or not to use it.

Conclusion

You have learned about the one of available BT Stacks SDKs—Widcomm SDK for Windows Mobile OS. It gives you literally all you need to manage surrounding BT devices (well, everything has some bugs in, and this stack isn’t an exception). Sample code snippets in the article illustrate some typical use cases; for more complicated ones, please refer to the SDK documentation. In the next article, you will look at what Microsoft can offer you from their own BT stack.

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. After working almost a decade for an international retail software company as a team leader of the Windows Mobile R department, he has decided to dive into Symbian OS ™ Core development.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories