分类: 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”来进行收发数据的测试了。
由于时间和水平的关系,代码和文章写得都不咋的,但愿能起到抛砖引玉的作用。