精华内容
下载资源
问答
  • Windows 上的蓝牙编程并不方便,由于操作系统并没有提供统一的蓝牙操作接口,通常是由各个蓝牙设备商提供蓝牙栈,所以要想编程...蓝牙虚拟串口是一个较为常见的需求,为了兼容已有使用串口设备的程序,需要将蓝牙...

    Windows 上的蓝牙编程并不方便,由于操作系统并没有提供统一的蓝牙操作接口,通常是由各个蓝牙设备商提供蓝牙栈,所以要想编程兼容这些不同的厂商蓝牙是一个问题。好在有个软件项目 32feet.NET 针对主流蓝牙协议栈提供了支持,包括 Microsfot, Widcomm, BlueSolei 等,同时还支持红外传输协议。

    蓝牙虚拟串口是一个较为常见的需求,为了兼容已有使用串口设备的程序,需要将蓝牙连接转为系统上的虚拟串口,然后提供给其他程序或库使用。32feet.NET 对此也提供了支持。

    32feet.NET 依赖 .NET 3.5 版本以上框架,支持 Windows 桌面版本、Wndows CE 以及 Windows Phone。

    安装

    如果使用 Visual Studio 2015 或者 安装有 NuGet 工具的,可以直接通过 NuGet 安装。在 NuGet 命令行中输入

    1

    Install-Package 32feet.NET

    这样 NuGet 会自动下载安装并添加到当前 .NET 项目中。可以检查项目 References 项,如果存在 InTheHand.Net.Personal 则表明已成功加入到项目中,如果没有,可以手动添加引用,NuGet 下载存放在 SolutionName\packages\32feet.NET.x.x.x.x\ 路径下。

    使用

    下面主要讲解 32feet.NET 的使用,覆盖蓝牙搜索、配对、直接连接以及虚拟串口服务。

    1. 检测系统蓝牙可用性

    如果系统没有蓝牙设备或者蓝牙设备被禁用,那么可以通过以下函数来进行检查:

    123456789101112131415

    /* 定义于类 BTHelper 中 */

    public static bool IsPlatformSupportBT()

    {

    BluetoothClient bc;

    try

    {

    bc = new BluetoothClient();

    }

    catch (PlatformNotSupportedException)

    {

    return false;

    }

    bc.Close();

    return true;

    }

    如果系统不支持蓝牙设备,那么 new BluetoothClient 会抛出 PlatformNotSupportedException 异常,通过捕获这个异常,来检测系统蓝牙设备可用性。

    2. 蓝牙搜索

    BluetoothClient 对象有个方法 DiscoverDevices 用于搜索蓝牙设备,该方法有多个重载版本,最终都是调用如下这个接口:

    1

    public BluetoothDeviceInfo[] DiscoverDevices(int maxDevices, bool authenticated, bool remembered, bool unknown, bool discoverableOnly);

    第一个参数表明搜索的最大设备数,第二个参数表示是否搜索已配对设备,第三个表示是否搜索记住的设备,第四个表示是否搜索未知设备,第五个参数表示是搜索范围内可被发现的设备。

    这里面重要的是第二和第五个参数,第二个代表搜索系统中已配对列表中的设备,即使它们现在并不在线。第五个参数 XP 系统上不支持,表示搜索范围内可被发现的设备。

    如果我们需要获得系统中已配对列表中的蓝牙设备,可以这样调用 DiscoverDevices(255, true, false, false),这里使用了4个参数的重载版本,只将第二个参数置为 true。

    如果我们需要搜索周围环境中可用的蓝牙设备,可以这样调用 DiscoverDevices(255, false, false, false, true),这个调用等同于 DiscoverDevicesInRange()。

    需要注意的是,这个调用是同步阻塞的,在搜索没有结束之前函数不会返回。所以通常我们需要将这个调用放入工作线程中。例外的是,如果只是获取系统中已配对列表中的设备,这个调用会很快完成,不会占用当前线程太多时间。

    库中同时提供了一个异步搜索方法,由类 BluetoothComponent 提供,由事件 DiscoverDevicesProgress 和 事件 DiscoverDevicesComplete 以及方法 DiscoverDevicesAsync 来实现。这个和用 BackgroundWorker 来实现 DiscoverDevices() 异步查找是一样的。

    PS: 可以通过 VS 的 Object Browser 查看 InTheHand.Net.Personal 库中的函数接口说明,说明非常翔实。

    3. 检测蓝牙设备是否在范围内

    当需要检查一个蓝牙设备是否在有效范围内,可以通过查询一个 Fake Service ID 来实现。

    如果蓝牙设备在范围内可访问,那么查询的结果是返回的服务记录为空,表示不支持此服务;如果蓝牙设备不在范围内,那么会抛出套接字异常。

    以下为检测代码:

    12345678910111213141516171819

    /* 定义于类 BTHelper 中 */

    public static bool TestingIfInRange(BluetoothAddress addr)

    {

    bool inRange = false;

    Guid fakeUuid = new Guid("{F13F471D-47CB-41d6-9609-BAD0690BF891}");

    BluetoothDeviceInfo device = new BluetoothDeviceInfo(addr);

    try

    {

    ServiceRecord[] records = device.GetServiceRecords(fakeUuid);

    Debug.Assert(records.Length == 0, "Why are we getting any records? len: " + records.Length);

    inRange = true;

    }

    catch (SocketException)

    {

    inRange = false;

    }

    return inRange;

    }

    需要注意的是,因为蓝牙设备通信需要时间,所以这个调用也需要较长时间才能完成,未完成之前进入阻塞不返回,所以这个方法也需要放入工作线程中执行。

    4. 蓝牙设备配对

    蓝牙配对功能由类 BluetoothSecurity 的静态方法 PairRequest(BluetoothAddress device, string pin) 提供,其中第一个参数是目标设备地址,第二个参数是用于配对的 Pin 码。配对成功返回 true,失败返回 false。

    解除配对是 BluetoothSecurity.RemoveDevice(BluetoothAddress device) 。

    配对操作也需要将长时间完成,所以这个方法也需要放入工作线程中执行。

    5. 蓝牙直接连接

    如果不需要蓝牙虚拟串口而直接读写蓝牙数据,那么可以使用直接连接,这个可以参照官方文档:General Bluetooth Data Connections.

    通过直接连接获取一个可读写的 System.IO.Stream 流对象,就可以直接对蓝牙进行读写数据操作了。以下为官方样例中的代码

    1234567891011

    BluetoothAddress addr = BluetoothAddress.Parse("001122334455");

    Guid serviceClass;

    serviceClass = BluetoothService.SerialPort;

    // - or - etc// serviceClass = MyConsts.MyServiceUuid//var ep = new BluetoothEndPoint(addr, serviceClass);

    var cli = new BluetoothClient();

    cli.Connect(ep);

    Stream peerStream = cli.GetStream();

    // peerStream.Write/Read ...

    6. 蓝牙虚拟串口

    这部分讲解如何实现将蓝牙连接转为系统上的虚拟串口并获取串口名,还可以参阅官方文档: Bluetooth Serial Ports.

    首先需要说明的是,虚拟串口和直接连接数据读写不能同时使用,如果已经使用了其中一个方法进行读写,那么另外的一个方法会失败。

    生成虚拟串口需要将蓝牙设备服务设置为 BluetoothService.SerialPort,官方样例代码如下:

    1234

    BluetoothAddress addr = BluetoothAddress.Parse("123456789012");

    BluetoothDeviceInfo device = new BluetoothDeviceInfo(addr); // Or from discovery etcbool state = true;

    device.SetServiceState(BluetoothService.SerialPort, state, true);

    SetServiceState 的第一个函数表示服务标识,第二个表示要设置的服务状态,true 为启用, false 为禁用,第三个参数表示如果设置失败是否抛出异常。

    但在实际使用中,某些双模蓝牙在设置时,虽然设置成功但是依然会抛出 Win32Exception 异常,所以这里建议调用此函数的重载版本 SetServiceState(System.Guid service, bool state),而想要知道是否设置成功,下面会介绍其他方法来获得。

    这个方法调用并不会告诉我们新生成的串口名,官方文档中的建议是通过设置前后的系统串口列表差异来获取新生成的串口名,而获取系统串口列表则可以调用静态方法 SerialPort.GetPortNames。

    但是不建议用这个方法来获取虚拟串口名,因为这个不可靠而且容易出错,下面介绍另外一个可靠方法,而且这个方法也可以同时告诉我们设置虚拟串口服务是否成功。

    获取蓝牙虚拟串口名

    蓝牙虚拟串口在系统中都有记录,我们可以通过检索这个记录,来找到所设置的设备的虚拟串口名,同时也可以得知我们的蓝牙虚拟串口是否设置成功。

    通过调用 WMI 查询,可以枚举出系统中每个串口的详细信息。这里可以通过 PowerShell 来查询:

    1

    C:\> Get-WmiObject -query "select DeviceID,PNPDeviceID from Win32_SerialPort"

    输出样例(其中 COM66 对应的蓝牙设备地址为 00803A686519):

    1234

    DeviceID : COM66

    PNPDeviceID : BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}\7&1D80ECD3&0&00803A686519_C00000003

    ......

    可以看出蓝牙虚拟串口的 PNPDeviceID 是以 BTHENUM 开头,并且会将蓝牙地址存放其中。

    这个查询也可以通过 C# 代码实现:

    12345678910111213

    using System.Management;

    const string Win32_SerialPort = "Win32_SerialPort";

    SelectQuery q = new SelectQuery(Win32_SerialPort);

    ManagementObjectSearcher s = new ManagementObjectSearcher(q);

    foreach (object cur in s.Get()) {

    ManagementObject mo = (ManagementObject)cur;

    object id = mo.GetPropertyValue("DeviceID");

    object pnpId = mo.GetPropertyValue("PNPDeviceID");

    console.WriteLine("DeviceID: {0} ", id);

    console.WriteLine("PNPDeviceID: {0} ", pnpId);

    console.WriteLine("");

    }//for

    综上,我们可以定义一个函数,这个函数通过 WMI 检索所有串口设备信息,然后返回一个 Hashtable,其中存储的键为蓝牙设备地址,存储的值为串口名。

    函数定义如下:

    123456789101112131415161718192021222324252627282930313233343536373839

    /* 定义于类 BTHelper 中 */

    public static Hashtable QueryBTHPorts()

    {

    const string Win32_SerialPort = "Win32_SerialPort";

    SelectQuery q = new SelectQuery(Win32_SerialPort);

    ManagementObjectSearcher s = new ManagementObjectSearcher(q);

    Hashtable hashResult = new Hashtable();

    foreach (object cur in s.Get())

    {

    ManagementObject mo = (ManagementObject)cur;

    string id = mo.GetPropertyValue("DeviceID").ToString();

    string pnpId = mo.GetPropertyValue("PNPDeviceID").ToString();

    Debug.WriteLine("WMI>>DeviceID: " + id);

    Debug.WriteLine("WMI>>PNPDeviceID: " + pnpId);

    Debug.WriteLine("");

    /* 仅处理蓝牙串口 */

    if (pnpId.StartsWith("BTHENUM"))

    {

    /* 从 PNPDeviceID 中提取出蓝牙地址,策略是逆序字符串 & 后 _ 之前 */

    /* 蓝牙地址为6字节,HEX为12位字符 */

    int rBound = pnpId.LastIndexOf('_');

    int lBound = pnpId.LastIndexOf('&');

    Debug.Assert(rBound - lBound == 13, "Get BT Addr, this will nevery happened.");

    string addr = pnpId.Substring(lBound + 1, 12);

    if (!hashResult.Contains(addr))

    {

    hashResult.Add(addr, id);

    }

    else

    {

    Debug.WriteLine("Get BT Addr, addr" + addr + " has more than 1 ports");

    }

    }

    }

    return hashResult;

    }

    同样,WMI 检索也比较耗时,所以这个函数调用需要放入工作线程中执行。

    有了这个函数,我们可以通过结果中查找我们设置的蓝牙设备地址,就可以得知对应的虚拟串口名,而如果结果中没有我们设置的蓝牙设备地址,那么就可以认定设置虚拟串口服务失败了。

    样例代码

    这里介绍通过配合使用 BackgroundWorker 来实现蓝牙设备的配对、生成虚拟串口的样例代码:

    我们通过传入蓝牙设备地址给 worker,worker 在 DoWork 中帮我们处理所有步骤,过程中报告进度,并最终告诉我们结果。

    worker 的 DoWork 事件代码:

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495

    /* 进行蓝牙连接操作的后台线程执行函数 */

    /* 传入 蓝牙地址字符串 作为参数 */

    /* 利用 ReportProgress 报告进度 */

    /* 利用 DoWorkEventArgs.Result 报告状态 */

    void bgworkerConnection_DoWork(object sender, DoWorkEventArgs e)

    {

    BackgroundWorker worker = sender as BackgroundWorker;

    string args = e.Argument as string;

    string finalportname = "";

    do

    {

    BluetoothAddress addr = BluetoothAddress.Parse(args);

    BluetoothDeviceInfo deviceinfo = new BluetoothDeviceInfo(addr);

    /* 检测设备是否在服务范围内,有些设备能被发现但不能被配对连接(如果已经被其他终端配对连接) */

    /* 不在范围内则报告错误信息 */

    worker.ReportProgress(10, "Testing if device in range...");

    if (!BTHelper.TestingIfInRange(addr))

    {

    string msg = string.Format("Error: Device {0}({1}) is not reachable!",

    deviceinfo.DeviceName,

    deviceinfo.DeviceAddress.ToString());

    e.Result = msg;

    return;

    }

    worker.ReportProgress(10, "Device is in range.");

    /* 检测设备是否是已配对设备 */

    if (deviceinfo.Authenticated)

    {

    /* 已配对设备枚举系统蓝牙串口,检测是否已绑定虚拟串口 */

    worker.ReportProgress(10, "Querying Bluetooth serialport...");

    Hashtable bthTable1 = BTHelper.QueryBTHPorts();

    if (bthTable1.ContainsKey(addr.ToString()))

    { /* 获取绑定串口 */

    finalportname = bthTable1[addr.ToString()] as string;

    /* !!! 跳出 !!! */

    break;

    }

    /* 此处 else 需考虑枚举结果中没有绑定串口的处理,如果没有绑定串口,那么重新设置串口服务 */

    /* 此处 else 部分会在下面的流程处理,见下方设置串口服务部分 */

    }

    else /* 需要进行配对 */

    {

    worker.ReportProgress(10, "Start pairing...");

    if (!BluetoothSecurity.PairRequest(addr, "1234"))

    { /* 配对失败 */

    string msg = string.Format("Error: Can not pair to Device {0}({1})!",

    deviceinfo.DeviceName,

    deviceinfo.DeviceAddress.ToString());

    e.Result = msg;

    return;

    }

    }

    /* 设置串口服务 */

    /* SLC蓝牙设置串口服务时,如果 SetServiceState */

    /* 第三个参数为 true (允许异常) 那么则一定会抛出异常,即使虚拟串口创建成功 */

    /* 所以这里调用2个参数的重载版本 */

    /* 之后检查串口服务是否设置成功的方法就是 设置后检索蓝牙串口 */

    worker.ReportProgress(10, "Enable serialport service...");

    deviceinfo.SetServiceState(BluetoothService.SerialPort, true);

    /* 枚举系统蓝牙串口,检查对应蓝牙是否有串口绑定 */

    Hashtable bthTable2 = BTHelper.QueryBTHPorts();

    if (bthTable2.ContainsKey(addr.ToString()))

    {

    /* 获取绑定的串口 */

    finalportname = bthTable2[addr.ToString()] as string;

    /* !!! 跳出 !!! */

    break;

    }

    else

    { /* 启用串口服务失败或者无法检测到绑定串口 */

    string msg = string.Format("Error: Failed to set Serialport service for Device {0}({1})!",

    deviceinfo.DeviceName,

    deviceinfo.DeviceAddress.ToString());

    e.Result = msg;

    return;

    }

    } while (false);

    worker.ReportProgress(10, "Open serialport...");

    Debug.WriteLine(string.Format(">>PORT NMAE: {0}", finalportname));

    /* 成功 */

    /* 将串口名放入消息中返回 */

    string okmsg = string.Format("OK: {0}", finalportname);

    e.Result = okmsg;

    }

    代码中通过灵活使用 string 作为 Result 来表明执行结果。

    worker 的 RunCompleted 事件代码:

    123456789101112

    void bgworkerConnection_RunCompleted(object sender, RunWorkerCompletedEventArgs e)

    {

    string msg = e.Result as string;

    if(msg.StartsWidth("OK"))

    { /* OK */

    MessageBox.Show(msg);

    }

    else

    { /* Error */

    MessageBox.Show(msg);

    }

    }

    后续可以通过字符串处理提取出生成的串口名。

    worker 的启动代码:

    1

    bgworkerConnection.RunWorkerAsync(addrstring);

    这样子我们就获取到了绑定的虚拟串口名,但是在使用串口中要注意的是,虚拟串口打开过程中,本质上还是发起了一个蓝牙数据连接,所以打开过程会耗时较长,所以这个虚拟串口打开过程也需要放入工作线程中处理。如果虚拟串口对应的蓝牙设备没有在线或者其他原因造成不可用,那么打开时会抛出异常,需要在代码上进行处理。

    一旦蓝牙设备经过绑定并且设置虚拟串口服务成功,那么对应的串口会一直存在与系统的串口列表中,但这并不代表它是可用的,请在打开这类串口时添加异常处理代码。

    (完)

    展开全文
  • 写在前面 由于个人是个C++和windows ...申请到蓝牙虚拟串口后,后面的通信就把蓝牙当串口用了。算是完成了领导交代的任务… 1 用到的函数 1.1 BluetoothSetServiceState DWORD BluetoothSetServiceState( HANDLE hRa

    写在前面

    由于个人是个C++和windows API方面的小白,蓝牙配对这部分涉及到回调方面,实在使不上劲,快要放弃之际,开发小伙伴告诉我公司蓝牙都是直连模式,可以跳过配对这部分。无奈这下,只能先跳过配对这部分(后面再琢磨)。
    申请到蓝牙虚拟串口后,后面的通信就把蓝牙当串口用了。算是完成了领导交代的任务…

    1 用到的函数

    1.1 BluetoothSetServiceState

    DWORD BluetoothSetServiceState(
      HANDLE                      hRadio,
      const BLUETOOTH_DEVICE_INFO *pbtdi,
      const GUID                  *pGuidService,
      DWORD                       dwServiceFlags
    );
    

    2 实现

    // 申请串口服务
    		const BLUETOOTH_DEVICE_INFO *bdi = NULL;
    		bdi = &remote_bluetooth[i];
    		const GUID *guid = NULL;
    		guid = &SerialPortServiceClass_UUID;
    		BluetoothSetServiceState(hRadio, bdi, guid, BLUETOOTH_SERVICE_ENABLE);
    

    一个问题

    蓝牙虚拟串口是建立了,但是怎么能够知道哪个串口是蓝牙的?我这里用的比较笨的办法:
    1.申请蓝牙虚拟串口前扫描一次windows的所有串口,并保存串口名字
    2.申请蓝牙虚拟串口后再扫描一次windows的所有串口,与之前扫描结果对比,多出来的就是这个蓝牙串口
    要是那个小伙伴有其他方法,麻烦指教一下,请评论或私信,谢谢

    3 扫描windows蓝牙并返回串口列表

    // 获取windows所有串口列表
    int scanComServer(string comlist[]) {
    	HKEY hKey;
    	LPCTSTR data_Set = _T("HARDWARE\\DEVICEMAP\\SERIALCOMM\\");
    	LONG ret0 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, data_Set, 0, KEY_READ, &hKey);
    	if (ret0 != ERROR_SUCCESS)
    	{
    		wcout << (L"错误:无法打开有关的hKEY");
    		return -1;
    	}
    
    	DWORD dwIndex = 0;
    	int count = 0;
    	while (1)
    	{
    		LONG Status;
    		CHAR Name[256] = { 0 };
    		UCHAR szPortName[80] = { 0 };
    		DWORD dwName;
    		DWORD dwSizeofPortName;
    		DWORD Type;
    		dwName = sizeof(Name);
    		dwSizeofPortName = sizeof(szPortName);
    		Status = RegEnumValue(hKey, dwIndex++, (LPWSTR)Name, &dwName, NULL, &Type,
    			szPortName, &dwSizeofPortName);
    
    		if ((Status == ERROR_SUCCESS) || (Status == ERROR_MORE_DATA))
    		{
    			CString str;
    			str.Format(L"%s", szPortName);
    			comlist[count] = CT2A(str.GetBuffer());
    			count++;
    			//TRACE("\n-------%s", str);COM_SERIAL_PORT_LIST.AddString(str);    
    			/*cout << comlist[count];*/
    		}
    		else
    		{
    			break;
    		}
    	}
    	RegCloseKey(hKey);
    	return 0;
    };
    
    展开全文
  • windows蓝牙虚拟串口通信

    万次阅读 2015-11-17 15:48:44
    windows下可以通过RFCOMM虚拟串口进行通信. RFCOMM简介: RFCOMM仿真RS232串口,该仿真过程包括非数据通路状态的传输。RFCOMM不限制人工速率或步长,如果通信链路两端的设备都是负责将数据转发到其他通信介质的...

    windows下可以通过RFCOMM虚拟的串口进行通信.
    RFCOMM简介:
    RFCOMM仿真RS232串口,该仿真过程包括非数据通路状态的传输。RFCOMM不限制人工速率或步长,如果通信链路两端的设备都是负责将数据转发到其他通信介质的第二类设备,或在两端RFCOMM设备接口上进行数据传输,实际数据吞吐一般将反映波特率的设置.RFCOMM支持两个设备之间的多串口仿真,也支持多个设备多串口的仿真.
    winsock支持RFCOMM,其地址是SOCKADDR_BTH,地址族是AF_BTH.
    1.首先把蓝牙名字转换成能链接的地址。

    ULONG CBlueTooth::NameToBthAddr( const char *pszRemoteName, PSOCKADDR_BTH pRemoteBtAddr)
    {
        int             iResult = CXN_SUCCESS;
        BOOL            bContinueLookup = FALSE, bRemoteDeviceFound = FALSE;
        ULONG           ulFlags = 0, ulPQSSize = sizeof(WSAQUERYSET);
        HANDLE          hLookup = NULL;
        PWSAQUERYSET    pWSAQuerySet = NULL;
    
        ZeroMemory(pRemoteBtAddr, sizeof(*pRemoteBtAddr));
        pWSAQuerySet = (PWSAQUERYSET) HeapAlloc(GetProcessHeap(),
            HEAP_ZERO_MEMORY,
            ulPQSSize);
        if ( NULL == pWSAQuerySet ) 
        {
            iResult = STATUS_NO_MEMORY;
        }
        if ( CXN_SUCCESS == iResult)
        {
            for ( int iRetryCount = 0;!bRemoteDeviceFound && (iRetryCount < CXN_MAX_INQUIRY_RETRY);iRetryCount++ )
            {   
                ulFlags = LUP_CONTAINERS;               
                ulFlags |= LUP_RETURN_NAME;             
                ulFlags |= LUP_RETURN_ADDR;
    
                if ( 0 != iRetryCount )
                {                                       
                    ulFlags |= LUP_FLUSHCACHE;                  
                    Sleep(CXN_DELAY_NEXT_INQUIRY * 1000);
                }
    
                iResult = CXN_SUCCESS;
                hLookup = 0;
                bContinueLookup = FALSE;
                ZeroMemory(pWSAQuerySet, ulPQSSize);
                pWSAQuerySet->dwNameSpace = NS_BTH;
                pWSAQuerySet->dwSize = sizeof(WSAQUERYSET);
                iResult = WSALookupServiceBegin(pWSAQuerySet, ulFlags, &hLookup);
    
                if ( (NO_ERROR == iResult) && (NULL != hLookup) ) 
                {
                    bContinueLookup = TRUE;
                } else if ( 0 < iRetryCount )
                {                   
                    break;
                }
    
                while ( bContinueLookup )
                {                   
                    if ( NO_ERROR == WSALookupServiceNext(hLookup,
                        ulFlags,
                        &ulPQSSize,
                        pWSAQuerySet) )
                    {
                        if ( ( pWSAQuerySet->lpszServiceInstanceName != NULL ) &&
                            ( CXN_SUCCESS == stricmp(pWSAQuerySet->lpszServiceInstanceName, pszRemoteName) ) )
                        {                               
                            CopyMemory(pRemoteBtAddr,
                                (PSOCKADDR_BTH) pWSAQuerySet->lpcsaBuffer->RemoteAddr.lpSockaddr,
                                sizeof(*pRemoteBtAddr));
                            bRemoteDeviceFound = TRUE;
                            bContinueLookup = FALSE;
                        }
                    } else
                    {
                        iResult = WSAGetLastError();
                        if ( WSA_E_NO_MORE == iResult )
                        { 
                            bContinueLookup = FALSE;
                        }
                        else if ( WSAEFAULT == iResult )
                        {                           
                            HeapFree(GetProcessHeap(), 0, pWSAQuerySet);
                            pWSAQuerySet = (PWSAQUERYSET) HeapAlloc(GetProcessHeap(),
                                HEAP_ZERO_MEMORY,
                                ulPQSSize);
                            if ( NULL == pWSAQuerySet )
                            {                               
                                iResult = STATUS_NO_MEMORY;
                                bContinueLookup = FALSE;
                            }
                        }
                        else
                        {                       
                            bContinueLookup = FALSE;
                        }
                    }
                }
    
                WSALookupServiceEnd(hLookup);
                if ( STATUS_NO_MEMORY == iResult )
                {
                    break;
                }
            }
    
        }
        if ( NULL != pWSAQuerySet )
        {
            HeapFree(GetProcessHeap(), 0, pWSAQuerySet);
            pWSAQuerySet = NULL;
        }
        if ( bRemoteDeviceFound )
        {
            iResult = CXN_SUCCESS;
        } else
        {
            iResult = CXN_ERROR;
        }
    
        return iResult;
    }

    2.建立链接

    //HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\BTHPORT\Parameters\LocalServices\{00001101-0000-1000-8000-00805f9b34fb}
    /*
    CBlueTooth:是本模块的底层通讯的类,该类为ECU类提供服务,该类把ECU要发送的类容抽象成类,通过发送和接收缓冲,保存该流的内容,而不管实际的发送或
    接收的数据的意义。
    */
    DEFINE_GUID(g_guidServiceClass,0x00001101,0x0000,0x1000,0x80,0x00,0x00,0x80,0x5f,0x9b,0x34,0xfb);
    //RemoteBthAddr,蓝牙设备的地址
        SOCKADDR_BTH  SockAddrBthServer= RemoteBthAddr;
        SockAddrBthServer.addressFamily = AF_BTH;
        SockAddrBthServer.serviceClassId = g_guidServiceClass;
        SockAddrBthServer.port = 0;
        if (INVALID_SOCKET != LocalSocket)
        {
            closesocket(LocalSocket);
        }
        LocalSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
        if ( INVALID_SOCKET == LocalSocket )
        {
            return status;
        }
        //建立蓝牙连接
        if ( 0 == connect(LocalSocket,
            (struct sockaddr *) &SockAddrBthServer,
            sizeof(SOCKADDR_BTH)) ) 
        {
            status=true;
        }

    3.发送数据

    ResetEvent(hSendEvent);
        int sum=0;
        while (sum < PDU.size())
        {
            int iCount=send(LocalSocket,PDU.data()+sum,PDU.size()-sum,0);
            if (iCount == SOCKET_ERROR)
            {
                bConnect = false;
            }
            sum += iCount;
        }
    4.接收数据
    
    while(1)
            {
                char buffer[100]={0};
                int count=recv(LocalSocket,buffer,sizeof(buffer),0);
                if (count < 0)
                {               
                    continue;               
                }
                CurSum +=count; 
                if (0 != count)
                {
    
                    for (int i=0;i<count;i++)
                    {
                        ReceiveBuffer.push_back(buffer[i]);
                    }
                                }
                if(ReceiveBuffer.size() >= 6 && (DestSum == 8))
                {
                    unsigned short int *p =(unsigned short int*)(ReceiveBuffer.data()+4);
                    DestSum += *p;              
                }
                if (DestSum != 0 && CurSum >= DestSum)
                {
                    break;
                }
    展开全文
  • 基于Windows蓝牙虚拟串口通信

    千次阅读 2018-11-20 17:18:32
    一、枚举本地蓝牙设备 /******************************************************************************\ 枚举本地所有蓝牙设备到 m_arrLocal,返回本地蓝牙设备数 \******************************************...

    一、枚举本地蓝牙设备

    /******************************************************************************\
    枚举本地所有蓝牙设备到 m_arrLocal,返回本地蓝牙设备数
    \******************************************************************************/
    int CBlueTooth::EnumLocalDev()
    {
        RemoveAllLocalDev();

        HANDLE                      hRadio  =   NULL;
        BLUETOOTH_FIND_RADIO_PARAMS bfrp    =   {sizeof(bfrp)};
        HBLUETOOTH_RADIO_FIND       hFind   =   BluetoothFindFirstRadio(&bfrp,&hRadio);

        if(hFind)
        {
            do{
                if(hRadio)
                {
                    m_arrLocal.Add(hRadio);
                }
            }while(BluetoothFindNextRadio(hFind,&hRadio));
            BluetoothFindRadioClose(hFind);
        }
        return (int)m_arrLocal.GetSize();
    }

    二、搜索远程蓝牙设备

    //
    // 用蓝牙 APIs 搜索附近的蓝牙设备,成功时返回设备数,否则返回-1
    //
    int CBlueTooth::Scan(HANDLE hRadio,BOOL fReturnAuthenticated,BOOL fReturnRemembered,BOOL fReturnUnknown
                        ,BOOL fReturnConnected,BOOL fIssueInquiry,UCHAR cTimeoutMultiplier)
    {
        RemoveAllRemoteDev();
        BLUETOOTH_DEVICE_INFO           bdi =   { sizeof(BLUETOOTH_DEVICE_INFO) };
        BLUETOOTH_DEVICE_SEARCH_PARAMS  bdsp;

        ZeroMemory(&bdsp, sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS));
        bdsp.dwSize                 =   sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
        bdsp.hRadio                 =   hRadio;
        bdsp.fReturnAuthenticated   =   fReturnAuthenticated;
        bdsp.fReturnRemembered      =   fReturnRemembered;
        bdsp.fReturnUnknown         =   fReturnUnknown;
        bdsp.fReturnConnected       =   fReturnConnected;
        bdsp.fIssueInquiry          =   fIssueInquiry;
        bdsp.cTimeoutMultiplier     =   cTimeoutMultiplier;
        HBLUETOOTH_DEVICE_FIND  hbf =   BluetoothFindFirstDevice(&bdsp, &bdi);
        if(hbf == NULL)
        {
            return -1;
        }
        do
        {
            TRACE ( _T("%s ( %s )\n"), bdi.szName, AddrToStr(bdi.Address.rgBytes) );

            RemoteDev dev;
            dev.Address =   bdi.Address.ullLong;
            dev.sName   =   bdi.szName;
            m_arrRemote.Add(dev);
        }while(BluetoothFindNextDevice(hbf,&bdi));
        BluetoothFindDeviceClose(hbf);
        return m_arrRemote.GetSize();
    }

    三、与指定的蓝牙设备配对

            int nSelLocal   =   0;
            int nSelRemote  =   0;
            BLUETOOTH_DEVICE_INFO bdi;
            if(!GetSomeInfo(&nSelLocal,&nSelRemote,&bdi))
            {
                return;
            }
            CDlgPairSend dlg;
            dlg.m_sLocal    =   m_ListLocal. GetItemText(nSelLocal ,0) + _T(" - ") + m_ListLocal .GetItemText(nSelLocal ,1);
            dlg.m_sRemote   =   m_ListRemote.GetItemText(nSelRemote,0) + _T(" - ") + m_ListRemote.GetItemText(nSelRemote,1);
            if(dlg.DoModal() == IDOK)
            {

                int     nLenW   =   MultiByteToWideChar(CP_ACP,0,dlg.m_sPwd,dlg.m_sPwd.GetLength(),NULL,0);
                wchar_t*wzPwd   =   new wchar_t[nLenW + 1];
                MultiByteToWideChar(CP_ACP,0,dlg.m_sPwd,dlg.m_sPwd.GetLength(),wzPwd,nLenW);

                t_RemoteBthDevInfo RemoteBthDevInfo;
                RemoteBthDevInfo.Address.ullLong = bdi.Address.ullLong;
                m_BlueTooth.EnumerateInstalledServices ( RemoteBthDevInfo );

                if(BluetoothAuthenticateDevice(m_hWnd,m_BlueTooth.m_arrLocal[nSelLocal],&bdi,wzPwd,nLenW)==ERROR_SUCCESS)
                {
                    MessageBox(_T("配对成功"));

                }
                else
                {
                    MessageBox(_T("配对失败"));
                }
                delete[] wzPwd;

    四、连接蓝牙设备,枚举串口,寻找蓝牙虚拟串口,发送握手指令 ,

            HKEY hKey;
            LPCTSTR lpSubKey="HARDWARE\\DEVICEMAP\\SERIALCOMM\\";

            if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &hKey)!= ERROR_SUCCESS)
            {
                return ;
            }

            char szValueName[NAME_LEN];
            BYTE szPortName[NAME_LEN];
            LONG status;
            DWORD dwIndex = 0;
            DWORD dwSizeValueName=100;
            DWORD dwSizeofPortName=100;
            DWORD Type;
            dwSizeValueName = NAME_LEN;
            dwSizeofPortName = NAME_LEN;
            do
            {
                status = RegEnumValue(hKey, dwIndex++, szValueName, &dwSizeValueName, NULL, &Type,
                    szPortName, &dwSizeofPortName);
                if((status == ERROR_SUCCESS))
                {
                    CString str;
                    str=(char *)szPortName;
                    m_SerialPort.SetCom(str);

                    if (m_SerialPort.OpenConnection())
                    { 
                        //发送指令,判断串口是否有回复,有回复即为蓝牙虚拟串口
                        unsigned char data[2]={0xa5,0x5a}; //握手
                        m_SerialPort.WriteComm(data,2);
                        
                        char *Buf=new char[10];
                        memset(Buf,0,10);
                        int nCount=0;
                        nCount=m_SerialPort.ReadComm(Buf,1);
                        byte bt=Buf[0];
                        if (bt==0xa5)
                        {
                            MessageBox(_T("连接成功"));
                            Start();
                            break;
                        }
                    }
                }
                dwSizeValueName = NAME_LEN;
                dwSizeofPortName = NAME_LEN;
            } while((status!= ERROR_NO_MORE_ITEMS));
            RegCloseKey(hKey);

    五、通过串口与远程蓝牙设备通信


    源码参考:https://download.csdn.net/download/qq_23565865/10789156

    展开全文
  • 在之前的两篇文章分别讲述了在.NET Compact Framework下使用Windows Embedded Source Tools for Bluetooth和32feet.NET进行Bluetooth的开发,链接如下:.NET Compact Framework下的Bluetooth开发 之 Windows ...
  • Windows主动向串口蓝牙适配器发起连接时所使用的虚拟串口号 传入COM端口 是串口蓝牙适配器主动向Windows发起连接时所使用的虚拟串口号。 就是选择电脑蓝牙的主从模式. 用电脑上的蓝牙连接其他蓝牙适配器从机...
  • Thinkpad T550 蓝牙虚拟串口服务失败

    千次阅读 2015-12-31 11:07:56
    上位机软件与下位机程序通过串口通信,上位机是windows7 64位系统,因为windows通信协议栈存在蓝牙地址族,通过 RFCOMM 仿真串口通信,部分代码如下: SOCKADDR_BTH SockAddrBthServer= RemoteBthAddr; ...
  • 在之前的两篇文章分别讲述了在.NET Compact Framework下使用Windows Embedded Source Tools for Bluetooth和32feet.NET进行Bluetooth的开发,链接如下:.NET Compact Framework下的Bluetooth开发 之 Windows ...
  • 该源代码通过BluetoothAPIs.h扫描本地和远程蓝牙设备并发送配对请求,完成配对,通过增加串口服务开启虚拟串口,然后通过SerialPort进行串口通信,该代码在vs2008环境中运行成功
  • Compact Framework下的Bluetooth开发 之 Windows Embedded Source Tools for Bluetooth  .NET Compact Framework下的Bluetooth开发 之 32feet.NET  在这篇文章讲述Bluetooth Virtual Serial Port的开发,所谓...
  • 摘要:蓝牙通信平台在嵌入式系统的实现过程中,OBEX(对象交换)始终是很重要的一部分,基于OBEX的蓝牙文件传输得到...由于OBEX上的文件传输应用建立在RFCOMM实现的蓝牙仿真串口上,本文介绍OBEX文件传输的蓝牙虚拟串口
  • 因此,对于都有蓝牙模块的电脑,可以通过将蓝牙虚拟串口,进行双机通讯。对于Electron的串口应用,蓝牙串口也是一种可选方式。 Window系统对蓝牙协议版本的支持 对于蓝牙模块之间的互连,如果支持的协议不兼容,是...
  • 串口编程 - windows如何枚举串口|获取活跃串口号 ...- 虚拟串口:com0com 或 ELTIMA Virtual Serial Port 等 - 蓝牙转串口 - USB转串口 - STM32虚拟COM端口 (设备管理器显示 `STMicroelectronics Virtual COM Port`)
  • 串口模拟器处于蓝牙协议栈的顶层,在虚拟串口的基础上提供连接RFCOMM的通路。它没有暴露栈的接口,而是提供了一个API层来向远程蓝牙设备开放连接。Microsoft® Windows® CE的蓝牙实现允许你建立一个piconet。按照...
  • 串口模拟器处于蓝牙协议栈的顶层,在虚拟串口的基础上提供连接RFCOMM的通路。它没有暴露栈的接口,而是提供了一个API层来向远程蓝牙设备开放连接。Microsoft® Windows® CE的蓝牙实现允许你建立一个piconet。按照...
  • 传出COM端口和传入COM端口代表了通讯双方主动和被动的关系,传出COM端口是Windows主动向串口蓝牙适配器发起连接时所使用的虚拟串口号,而传入COM端口则是串口蓝牙适配器主动向Windows发起连接时所使用的虚拟串口号。...
  • 需要做个安卓端蓝牙连接、收发数据的APP,程序写...windows可以直接将蓝牙虚拟串口(也可能非系统而是蓝牙驱动的功能) 右键右下角蓝牙图表-打开设置(如果是win10会进入新的设置界面,找到更多蓝牙选项,可进入...
  • (我有个pad和蓝牙背夹一配对就可以连接了,但走的是虚拟串口);问题2:我用winsock客户端代码连接 始终连接不上背夹。纠结。有没有详细的例子,我照着MSDN上API也没有成功,会不会是蓝牙模块走的是串口,只要配对...

空空如也

空空如也

1 2 3
收藏数 46
精华内容 18
关键字:

windows蓝牙虚拟串口