January 22, 2021
Hot Topics:

Experiencing This Mysterious Bluetooth Stack Programming

  • By Alex Gusev
  • Send Email »
  • More Articles »

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
   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:


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

Page 1 of 2

This article was originally published on October 13, 2006

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date