I bought a Syba USB Bluetooth 2.0 dongle adapter from Amazon recently in an attempt to bluetooth enable my aging home PC. This adapter has a Broadcom 2045 wireless chip. If you have one of those new bluetooth enabled smartphones, you can do a lot of cool things with a bluetooth connection to your PC like synchronizing messages, tasks and contacts with Outlook, transfer files with the help of an OBEX file transfer client on your phone, play music from your phone on the PC speakers among other things.
Broadcom has published their bluetooth SDK which can be downloaded at:
http://www.broadcom.com/support/bluetooth/sdk.php
using which you can do quite a bit of bluetooth programming to control Broadcom bluetooth adapters. Since the SDK has source header files for C++ it is most natural to use C++ to call the APIs – but you don’t have to. Perl is my choice scripting language for this kind of explorations. I found that Perl has an inline CPP module that will allow you to embed C++ code snippets in your Perl program. Of course you need a C++ compiler installed on your PC to make use of this module. On Windows platform your inline C++ code gets compiled into a DLL which will get called at run time by your Perl code.
I thought it is a cool way to do my bluetooth programming. I can write the core functionality in C++ classes and then instantiate those classes from Perl and call their methods. I use Microsoft Visual C++ 6.0 compiler. Below is the sample code for listing all bluetooth enabled devices in your PC’s neighborhood. To compile and run it you will need:
- Microsoft Visual C++ compiler (or any other suitable C++ compiler. Modify the include and library paths accordiningly.)
- Perl with Inline CPP Module
- Broadcom Bluetooth SDK and (of course)
- Bluetooth Adapter with Broadcom chip connected to your PC
Don’t forget to change the include and library paths to point to the appropriate locations in your environment. Download Perl source code here: http://infinilogix.com/downloads/btoothcpp.zip
#!/usr/bin/perl
use strict;
use warnings;
use Win32::OLE;
use Inline CPP => Config =>
LIBS => '-l"T:\Widcomm\BTW DK\SDK\Release\WidcommSdklib.lib" \
-L"C:\Program Files\Microsoft Visual Studio\VC98\Lib"',
INC => '-I"T:\Widcomm\BTW DK\SDK\Inc"',
CCFLAGS => '-TP -LD -I"T:\Widcomm\BTW DK\SDK\Inc" \
-nologo -GF -W3 -D_M_M68K -O1 -DWIN32 -D_CONSOLE \
-D_AFXDLL -D_BTWLIB -DNO_STRICT -DHAVE_DES_FCRYPT \
-DNO_HASH_SEED -DUSE_SITECUSTOMIZE -DPERL_IMPLICIT_CONTEXT \
-DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_MSVCRT_READFIX',
LDDLFLAGS => '/DLL /libpath:"C:\Perl\lib\CORE" \
/libpath:"T:\Widcomm\BTW DK\SDK\Release" \
/libpath:"C:\Program Files\Microsoft Visual Studio\VC98\Lib" \
/nodefaultlib:"msvcrt.lib"',
BUILD_NOISY =>1;
use Inline CPP => <<'EOC';
//Some of the functionality below has been adapted from
//Broadcom Bluetooth SDK.
//Copyright (c) 2000-2006, Broadcom Corporation.
#include "BtIfDefinitions.h"
#include "BtIfClasses.h"
#define CHAR_0 '0'
#define CHAR_CAP_A 'A'
#define CHAR_CAP_F 'F'
#define CHAR_A 'a'
#define CHAR_F 'f'
class CDeviceInfo
{
public:
CDeviceInfo(BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn)
{
memcpy (bd_addr, bda, BD_ADDR_LEN);
memcpy (dev_class, dc, DEV_CLASS_LEN);
memcpy (bd_name, bdn, BD_NAME_LEN);
pNext = NULL;
m_nServices = 0;
m_hFtp = 0;
m_sSPPPort = 0;
m_sLAPPort = 0;
m_sDUNPort = 0;
m_sFAXPort = 0;
}
CDeviceInfo *pNext;
BD_ADDR bd_addr;
DEV_CLASS dev_class;
BD_NAME bd_name;
int m_nServices;
long m_hFtp;
short m_sSPPPort;
short m_sLAPPort;
short m_sDUNPort;
short m_sFAXPort;
};
class Test : public CBtIf
{
public:
Test():CBtIf() { }
~Test() { }
/* init() will start the device enquiry */
char* init()
{
ok = 0;
pFirstDeviceInfo = NULL;
StartInquiry();
return "Success";
}
/* Are we done with all devices in the neighborhood? */
int Done()
{
return ok;
}
/* Get the first device in the list of devices we found */
char* GetFirstDevice()
{
return pFirstDeviceInfo?(LPSTR)pFirstDeviceInfo->bd_name:NULL;
}
/* Get the next device in the list of devices we found */
char* GetNextDevice()
{
pCurrDeviceInfo = pCurrDeviceInfo->pNext?
pCurrDeviceInfo->pNext:NULL;
return pCurrDeviceInfo?
(LPSTR)pCurrDeviceInfo->bd_name:NULL;
}
private:
int ok;
CDeviceInfo *pFirstDeviceInfo;
CDeviceInfo *pCurrDeviceInfo;
/* Callback method that gets called when
a device responds to our query */
void OnDeviceResponded(BD_ADDR p_bda,
DEV_CLASS dev_class,
BD_NAME bd_name,
BOOL bConnected)
{
CDeviceInfo *pDeviceInfo;
// Check if this is an update for an already known device
for (pDeviceInfo = pFirstDeviceInfo;
pDeviceInfo;
pDeviceInfo = pDeviceInfo->pNext)
{
if (!memcmp (pDeviceInfo->bd_addr, p_bda, BD_ADDR_LEN))
break;
}
BOOL new_item = FALSE;
//We have found a new device. Add it to our linked list.
if (!pDeviceInfo)
{
new_item = TRUE;
pDeviceInfo = new CDeviceInfo (p_bda, dev_class, bd_name);
if (!pFirstDeviceInfo)
pFirstDeviceInfo = pCurrDeviceInfo = pDeviceInfo;
else
{ CDeviceInfo *p;
for (p = pFirstDeviceInfo; p->pNext; p = p->pNext)
;
p->pNext = pDeviceInfo;
}
}
}
/* Callback method that gets called when
the query has completed */
void OnInquiryComplete (BOOL success,
short num_responses)
{
ok = 1;
}
/* Utility method to convert from a hex string to int */
WORD axtoi(char *pch)
{
register char ch;
register WORD n = 0;
while((ch = *pch++) != 0)
{
if (isdigit(ch))
ch -= CHAR_0;
else if (ch >= CHAR_CAP_A && ch <= CHAR_CAP_F)
ch += (char)(10 - CHAR_CAP_A);
else if (ch >= CHAR_A && ch <= CHAR_F)
ch += (char)(10 - CHAR_A);
else
break; //ch = (char)0;
n = 16 * n + ch;
}
return n;
}
BOOL string2BDAddr(BD_ADDR bdAddr, char *lpbdAddrString)
{
if ( strlen(lpbdAddrString) != (BD_ADDR_LEN * 3 - 1))
return FALSE;
for (int i = 0; i<BD_ADDR_LEN; i++)
bdAddr[i] = (char)axtoi(&lpbdAddrString[i *3]);
return TRUE;
}
};
EOC
my $t = new Test;
my $result = $t->init();
while (!$t->Done())
{
Win32::OLE->SpinMessageLoop();
}
my $dev = $t->GetFirstDevice();
while($dev)
{
print "$dev\n";
$dev = $t->GetNextDevice();
}
Recent Comments