分类: C/C++
2008-04-03 13:31:18
// 远程蓝牙设备详细信息
typedef struct _RemoteBthDevInfo
{
_RemoteBthDevInfo ()
{
memset ( szName, 0, sizeof(szName) );
memset ( &RemoteAddr, 0, sizeof(BT_ADDR) );
memset ( &LocalAddr, 0, sizeof(BT_ADDR) );
}
TCHAR szName[64];
BT_ADDR RemoteAddr;
BT_ADDR LocalAddr;
} t_RemoteBthDevInfo;
typedef CArray t_Ary_RemoteBthDevInfo;
搜索周边蓝牙设备的具体代码如下: //
// 用Socket 函数搜索附近的蓝牙设备,成功时返回设备数,否则返回-1
//
int CBlueTooth_WM::ScanNearbyBthDev_Direct ()
{
m_Ary_RemoteBthDevInfo.RemoveAll ();
SetWaitCursor ();
WSAQUERYSET querySet;
HANDLE hLookup;
DWORD flags = LUP_RETURN_NAME | LUP_RETURN_ADDR;
union
{
CHAR buf[5000];
double __unused; // ensure proper alignment
};
LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf;
DWORD dwSize = sizeof(buf);
BOOL bHaveName;
ZeroMemory(&querySet, sizeof(querySet));
querySet.dwSize = sizeof(querySet);
querySet.dwNameSpace = NS_BTH;
if ( ::WaitForSingleObject ( m_hEvtEndModule, 0 ) == WAIT_OBJECT_0 )
return -1;
if (ERROR_SUCCESS != WSALookupServiceBegin (&querySet, LUP_CONTAINERS, &hLookup))
{
ResotreCursor ();
MsgBoxErr ( _T("WSALookupServiceBegin failed") );
return (-1);
}
ZeroMemory(pwsaResults, sizeof(WSAQUERYSET));
pwsaResults->dwSize = sizeof(WSAQUERYSET);
pwsaResults->dwNameSpace = NS_BTH;
pwsaResults->lpBlob = NULL;
BOOL bError = FALSE;
while ( TRUE )
{
if ( ::WaitForSingleObject ( m_hEvtEndModule, 0 ) == WAIT_OBJECT_0 )
break;
if ( ERROR_SUCCESS == WSALookupServiceNext (hLookup, flags, &dwSize, pwsaResults) )
{
ASSERT (pwsaResults->dwNumberOfCsAddrs == 1);
BT_ADDR b = ((SOCKADDR_BTH *)pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr;
bHaveName = pwsaResults->lpszServiceInstanceName && *(pwsaResults->lpszServiceInstanceName);
t_RemoteBthDevInfo RemoteBthDevInfo;
if ( bHaveName )
{
hwSnprintf ( RemoteBthDevInfo.szName, sizeof(RemoteBthDevInfo.szName), _T("%s"),
pwsaResults->lpszServiceInstanceName );
}
RemoteBthDevInfo.RemoteAddr = b;
CSADDR_INFO* pCSAddr = (CSADDR_INFO *)pwsaResults->lpcsaBuffer;
RemoteBthDevInfo.LocalAddr = ((SOCKADDR_BTH *)pCSAddr->LocalAddr.lpSockaddr)->btAddr;
TRACE (L"%s ( %04x%08x )\n", RemoteBthDevInfo.szName, GET_NAP(b), GET_SAP(b) );
Add_RemoteBthDevInfo ( RemoteBthDevInfo );
}
else
{
if ( WSAGetLastError() != WSA_E_NO_MORE )
{
bError = TRUE;
ResotreCursor ();
MsgBoxErr ( L"Lookup bluetooth device failed" );
}
break;
}
}
WSALookupServiceEnd(hLookup);
ResotreCursor ();
if ( bError ) return (-1);
return (int)m_Ary_RemoteBthDevInfo.GetSize();
}
搜索周边的蓝牙设备重要的是要得到他们的蓝牙地址,这个地址是通信建立的关键,以上代码将搜索到的地址、设备名称等信息保存在m_Ary_RemoteBthDevInfo数组中了。那接下来就是该建立连接了,我现在测试的是将Windows Mobile手机和一个装有蓝牙芯片的心电仪设备建立连接,该设备的提供的蓝牙名称为“CONTRON”,连接过程其实很简单,做过SOCKET网络编程的人都知道,代码如下: //
// 连接到蓝牙服务器中的某一个服务,成功返回,失败返回错误代码
//
int CBlueTooth_WM::ConnectToBlueToothServer ( BT_ADDR ServerAddress, LPCTSTR lpszServiceGUID )
{
if ( m_socketClient==INVALID_SOCKET )
{
GUID ServerGuid;
if ( !StringToGUID(lpszServiceGUID, &ServerGuid) )
return -1;
m_socketClient = socket (AF_BT, SOCK_STREAM, BTHPROTO_RFCOMM);
if (m_socketClient == INVALID_SOCKET)
{
return WSAGetLastError();
}
SOCKADDR_BTH sa;
memset (&sa, 0, sizeof(sa));
sa.addressFamily = AF_BT;
sa.serviceClassId = ServerGuid;
sa.btAddr = ServerAddress;
if (connect (m_socketClient, (SOCKADDR *)&sa, sizeof(sa)) == SOCKET_ERROR)
{
m_socketClient = INVALID_SOCKET;
return WSAGetLastError();
}
}
return 0;
}
SOCKET连接一旦建立起来,就能像访问普通的网络通信套接字一样来访问蓝牙设备里的数据了,请看一下数据通信代码: //
// 数据传输(收/发)
// 返回成功传输的字节数。失败时返回-1;连接已经断开,返回-2;处理不能立即完成,返回-3
//
int CBlueTooth_WM::Transmite ( LPVOID lpData, int nSize, BOOL bSend )
{
if ( m_socketClient==INVALID_SOCKET ) return -1;
if ( !lpData ) return -1;
if ( nSize < 1 ) return 0;
int iBytesTransmited = 0;
if ( bSend )
iBytesTransmited = send (m_socketClient, (char *)lpData, nSize, 0);
else
iBytesTransmited = recv (m_socketClient, (char *)lpData, nSize, 0);
if ( iBytesTransmited > 0 ) return iBytesTransmited;
int nLastError = WSAGetLastError ();
if ( nLastError == WSAENETDOWN ||
nLastError == WSAENOTCONN ||
nLastError == WSAENOTSOCK ||
nLastError == WSAESHUTDOWN ||
nLastError == WSAETIMEDOUT )
{
Disconnect ();
return -2;
}
if ( nLastError == WSAEWOULDBLOCK )
return -3;
return -1;
}
其实用虚拟串口的方式也可以实现蓝牙的通信,在Windows Mobile 中使用如下代码就可以虚拟出一个串口设备: PORTEMUPortParams pp; memset (&pp, 0, sizeof(pp)); pp.channel = 0; pp.flocal = FALSE; pp.device = reinterpret_cast<_SOCKADDR_BTH*>(pwsaResults->lpcsaBuffer->LocalAddr.lpSockaddr)->btAddr; memcpy(&pp.uuidService, &CLSID_NULL, sizeof(GUID)); pp.uiportflags = RFCOMM_PORT_FLAGS_REMOTE_DCB; int port = 4; // 1到9中任何一个数 HANDLE bth = RegisterDevice (L"COM", port, L"btd.dll", (DWORD)&pp));串口创建好以后直接使用 CreateFile()、WriteFile()、ReadFile()、DeviceIoControl()等函数像操作普通串口一样来操作它。例如:
HANDLE hCommPort = CreateFile (L"COM4:", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);附带源代码是一个简单的蓝牙通信程序。程序执行后,出现如下界面:
先选择“Setting …”菜单,打开如下画面:
按下“Scan”按钮,程序开始搜索周边的蓝牙设备,并将所有找到的设备名称添加在下拉列表中,这里选择我的心电仪设备“CONTRON”,并设置好我将要使用的蓝牙服务GUID,然后选择“OK”菜单保存配置信息,回到前面的界面。
选择菜单“Connect Bluetooth Device”,程序将开始连接刚才配置的蓝牙设备,连接成功以后便可选择菜单“Send Test Data”来进行收发数据的测试了。
由于时间和水平的关系,代码和文章写得都不咋的,但愿能起到抛砖引玉的作用。