C#下蓝牙开发.docx

上传人:b****6 文档编号:4776375 上传时间:2022-12-08 格式:DOCX 页数:8 大小:19.58KB
下载 相关 举报
C#下蓝牙开发.docx_第1页
第1页 / 共8页
C#下蓝牙开发.docx_第2页
第2页 / 共8页
C#下蓝牙开发.docx_第3页
第3页 / 共8页
C#下蓝牙开发.docx_第4页
第4页 / 共8页
C#下蓝牙开发.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

C#下蓝牙开发.docx

《C#下蓝牙开发.docx》由会员分享,可在线阅读,更多相关《C#下蓝牙开发.docx(8页珍藏版)》请在冰豆网上搜索。

C#下蓝牙开发.docx

C#下蓝牙开发

在WindowsMobile软件开发中.net正扮演着日益重要的角色,我们已经可以看到很多用.NetCF开发的软件,这些软件涉及到了日常应用的方方面面。

在智能设备的软件开发中,无线互联是一个相当重要的一块,我们可以看到,红外几乎是所有智能设备的标配,而蓝牙也日益在越来越多的智能设备上出现,有了硬件,显然要有相应的软件相关的应用。

  我们也知道,用.NETCF开发红外通信应用时相当轻松的,因为.NETCF中有一个命名空间System.Net.IrDA就是用于红外通信的通信模块。

但是,.NETCF中还没有关于蓝牙通信的模块,所以目前来讲做这方面的开发还有一定的困难。

下面,就谈谈如何用C#开发.NETCF蓝牙通信模块。

  一.基本要点

  首先明确一点,因为涉及到驱动硬件的问题,所以仅靠了解C#开发的相关知识显然是无法完成开发的,我们必须对C++开发有所了解。

但是为了简单起见,我们不希望用C++写半行代码,所有的编码工作全部使用C#,也就是说,使用的开发环境只需要使用VisualS,不需要用其他的编辑器。

  作为开发这类驱动硬件的程序的知识准备,您需要了解C++的基本知识,知道头文件是怎么一回事,知道托管代码如何与非托管代码交互。

因为本文的核心是说明如何开发.netCF蓝牙通信模块,所以前述这些准备知识并不作讲述。

  二.关于蓝牙

  做蓝牙通信模块开发,自然先要知道蓝牙通信是怎么一回事。

在我看来,蓝牙通信应该和红外通信模块类似,当然我是从开发者的角度来讲,抽象化以后应该就是这样,当然蓝牙和红外通信也有很多不一样的地方,这在面向对象设计里面怎么讲,我想一定有很多人理解的比我透彻。

好了,这就是我们的基本思路了。

我曾经在网上查过关于蓝牙开发的文章,很多人在.netCF开发中把蓝牙通信当作一个串行通信来处理,这也是不错的,但是我不是很喜欢,因为这样做的话,并不是针对蓝牙来开发的,换言之,在使用过程中,需要先手动开启蓝牙,配对,连接,建立串行通道,然后开启应用程序使用,你还要在应用程序中设置串行端口,对最终用户来讲,这是非常麻烦的。

我觉得,这样的解决方案冠上蓝牙通信的名头简直就是……不多说了,书归正传。

  在红外通信中,我们知道,设备的DeviceID是一个Byte数组,那么蓝牙设备的DeviceID什么样子呢?

我想这个大家都很清楚,是一串以“:

”分隔的16进制数字。

  红外通信中,一般而言红外并没有开启、关闭之类的状态,但是蓝牙有开启、关闭、可发现三种状态。

  红外没有安全设置,而蓝牙有安全设置,所以我们需要对蓝牙设备进行配对,而红外通信这部需要。

  我们查看.net的Socket地址族里有IrDA,但是没有蓝牙相关的地址族,这是我们需要解决的问题。

  三.获取设备ID

  1.获取本地设备的ID

  我们查看WindowCE4.2的SDK文档,得知获取本地设备ID的函数是BthReadLocalAddr,在btdrt.dll中。

SDK文档中的英文原文是这样的:

“ThisfunctionretrievestheBluetoothaddressofthecurrentdevice.”好了,知道了这个就好说了:

  首先封装本地托管函数:

[DllImport("Btdrt.dll",SetLastError=true)]

publicstaticexternintBthReadLocalAddr(byte[]PBa);

  这个函数得到的本地DeviceID也是一组byte数组,为了向人们显示出来,我们要把它变为String:

stringtext1="";

text1=text1+pba[5].ToString("X2")+":

";

text1=text1+pba[4].ToString("X2")+":

";

text1=text1+pba[3].ToString("X2")+":

";

text1=text1+pba[2].ToString("X2")+":

";

text1=text1+pba[1].ToString("X2")+":

";

return(text1+pba[0].ToString("X2"));

  2.获取远程设备的ID

  其实谈到获取远程设备的ID就涉及到如何去发现远程设备了,所以这里就一并把发现设备的方法也说明了吧。

发现设备需要用到三个WinsockAPI,分别是WSALookupServiceBegin、WSALookupServiceNext和WSALookupServiceEnd,这三个API到底起什么作用可以去查看WindowsCE4.2的SDK,这里就不详细解释了,只谈一下几个需要注意的地方。

  WSALookupServiceBegin的函数原形是这样的:

INTWSALookupServiceBegin(

LPWSAQUERYSETlpqsRestrictions,

DWORDdwControlFlags,

LPHANDLElphLookup

);

  我们用托管代码进行包装:

[DllImport("ws2.dll",EntryPoint="WSALookupServiceBegin",SetLastError=true)]

publicstaticexternintCeLookupServiceBegin(byte[]pQuerySet,LookupFlagsdwFlags,refintlphLookup);

  可以看到,本来lpqsRestrictions是一个struct,经过包装后在托管代码中成为了byte[],我们计算好该struct大概要占用多少个byte,struct中每一个成员在byte数组中的位置是怎样的,装配出来就好了。

  由于是针对蓝牙作的开发,所以我们要查看一下这些参数应该是哪些值。

WindowsCE4.2的SDK中说,蓝牙开发时,structLPWSAQUERYSET中的如下成员应当为这些值:

ThedwSizemembermustbesizeof(WSAQUERYSET).

ThelpBlobmember(itselfapointertoaBLOBstructure)isoptional,butifused,thedeviceinquireparametersvalidforLUP_FLUSHCACHEarethefollowing:

ThecbSizememberoftheBLOBstructuremustbesizeof(BTH_QUERY_DEVICE).

ThepBlobDatamemberisapointertoaBTH_QUERY_DEVICEstructure,forwhichtheLAPmemberistheBluetoothinquiryAccesscode,andthelengthmemberisthelengthoftheinquiry,inseconds.

ThedwNameSpacemembermustbeNS_BTH.

AllotherWSAQUERYSETmembersareignored.

  具体什么意思各位可以自己去理解,我想比我翻译出来要好些,毕竟我英语很差的。

根据以上要求,我们这样装配pQuerySet:

byte[]buffer1=newbyte[0x400];

BitConverter.GetBytes(60).CopyTo(buffer1,0);

GCHandlehandle1=GCHandle.Alloc(blob1.ToByteArray(),GCHandleType.Pinned);

IntPtrptr1=handle1.AddrOfPinnedObject();

BitConverter.GetBytes((int)(ptr1.ToInt32()+4)).CopyTo(buffer1,0x38);

  另外的两个API也照类似方法调用即可。

  在调用了WSALookupServiceNext之后,bytes数组pQuerySet中便包含了远程设备的地址信息,下面我们需要把它找出来。

通过阅读SDK中WSAQUERYSET结构的说明和计算每个成员的位置之后,我们写出如下代码:

intnum5=BitConverter.ToInt32(buffer1,0x30);

intnum6=Marshal.ReadInt32((IntPtr)num5,8);

intnum7=Marshal.ReadInt32((IntPtr)num5,12);

SocketAddressaddress1=newSocketAddress(AddressFamily.Unspecified,num7);

  因为.net框架的地址族里面没有蓝牙,所以我们这里用的是AddressFamily.Unspecified。

  然后的工作就是从中获取远程设备的ID了:

前面我们已经计算出,这个Address里面的前六个字节是byte数组形式的设备ID,第七到第二十二个字节是蓝牙的ServiceGuid,在后面四个字节是端口号,所以我们只需要分别提取出来即可。

四.监听服务

  监听服务调用的是非托管APIWSASetService,其原型是

INTWSASetService(

LPWSAQUERYSETlpqsRegInfo,

WSAESETSERVICEOPessoperation,

DWORDdwControlFlags

);

  可以看到关键也是第一个参数,lpqsRegInfo,这也是一个struct,我们的包装方法与前面的发现设备采用的方法类似,做蓝牙通信时要注意其成员要如下设置:

lpqsRegInfo

dwSize

sizeof(WSAQUERYSET)

 

lpszServiceInstanceName

NotsupportedonWindowsCE.Setto0.

 

lpServiceClassId

NotsupportedonWindowsCE.Setto0.

 

dwNameSpace

NS_BTH.

 

dwNumberOfCsAddrs

NotsupportedonWindowsCE.Setto0.

 

IpcsaBuffer

NotsupportedonWindowsCE.Setto0.

 

lPBlob

PointstoaBTHNS_SETBLOBstructure,containinginformationabouttheservicetobeadded.

 

*

AllotherWSAQUERYSETfieldsareignored.

  五.连接

  我们知道,IrDA中连接远程服务是使用方法S.Sockets.IrDAClient类中的Connect方法。

而这个方法又是调用的Socket类中的Connect方法。

而Socket类是一个比较抽象的类,它并不绑定某个具体的地址族、SocketType和protocolType,所以在实例化的时候,需要指定这三个参数。

我们也知道,在IrDA中,这三个参数分别是AddressFamily.Irda,SocketType.Stream,和ProtocolType.IP,那么在蓝牙中这三个参数分别是什么呢?

我们好像找不到。

  且慢,真是这样吗?

  我们知道在.net中,这三个参数都是枚举值,而枚举在默认情况下,你可以认为就是int值的替代表现。

  我们该如何知道这三个参数到底是什么呢?

  还是先看Socket类的Connect方法。

  我们查查有关资料,可以知道这个方法实际上是调用的一个非托管函数:

[DllImport("mscoree",EntryPoint="@339")]

publicstaticexternintconnect(ints,byte[]name,intnamelen);

  也就是非托管的SocketAPI。

  我们看WindowsCE4.2的SDK,可以看到,在使用蓝牙进行连接的时候,需要使用WinSock扩展。

我们还可以看到,在使用蓝牙进行连接的时候,三个参数分别应当是AF_BTH、SOCK_STREAM和BTHPROTO_RFCOMM,至于这三个参数分别代表什么,我们就要查看相关的头文件了。

  我们找到ws2bth.h头文件,可以看到AF_BTH代表十进制数32,而BTHPROTO_RFCOMM代表十六进制数0x0003,恰好和ProtocolType.Ggp代表的数值是一致的。

所以,我们在实例化Socket时是这么写的:

newSocket((AddressFamily)0x20,SocketType.Stream,ProtocolType.Ggp);

  Socket实例化出来了,其他的当然就都好说了,这里不再赘述。

  六.蓝牙的安全设置

  蓝牙比红外多了安全方面的设置,所以就需要多一些代码来处理这些。

具体也就不多说了,其实也就是一些非托管代码的包装调用,这些API在Btdrt.dll中:

  获取配对码请求:

[DllImport("Btdrt.dll",SetLastError=true)]

publicstaticexternintBthGetPINRequest(byte[]pba);

  设置配对码:

[DllImport("btdrt.dll",SetLastError=true)]

publicstaticexternintBthSetPIN(byte[]pba,intcPinLength,byte[]ppin);

  比较麻烦点的是配对,总共有三步操作:

  首先是创建ACL连接:

[DllImport("Btdrt.dll",SetLastError=true)]

publicstaticexternintBthCreateACLConnection(byte[]pbt,refushortphandle);

  然后是配对码验证:

[DllImport("Btdrt.dll",SetLastError=true)]

publicstaticexternintBthAuthenticate(byte[]pbt);

  然后一定要关闭连接:

[DllImport("Btdrt.dll",SetLastError=true)]

publicstaticexternintBthCloseConnection(ushorthandle);

  七.设置蓝牙无线电状态

  我们知道,蓝牙无线电有打开、关闭、可发现三种状态,那么我们如何实现编程控制呢?

  我想这个一定大家都知道了,因为网上有很多关于这个的文章:

  先写一个枚举:

publicenumRadioMode

{

 Connectable=1,

 Discoverable=2,

 PowerOff=0

}

  然后写一个函数调用非托管代码即可:

[DllImport("BthUtil.dll",SetLastError=true)]

publicstaticexternintBthSetMode(RadioModedwMode);

  获取无线电状态的话就用下面的函数:

[DllImport("BthUtil.dll",SetLastError=true)]

publicstaticexternintBthGetMode(refRadioModedwMode);

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 高考

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1