信息时代的特点便是更加方便快速的信息传播,正是基于这一点,技术人员也在努力开发更加出色的信息数据传输方式。蓝牙,对于手机乃至整个 IT业而言已经不仅仅是一项简单的技术,而是一种概念。当蓝牙联盟信誓旦旦地对未来前景作着美好的憧憬时,整个业界都为之震动。抛开传统连线的束缚,彻底地享受无拘无束的乐趣,蓝牙给予我们的承诺足以让人精神振奋。蓝牙技术是一种无线数据与语音通信的开放性规范,它以低成本的近距离无线连接为基础,为固定与移动设备通信环境建立一个特别连接。其程序写在一个9 x 9 mm的微芯片中。例如,如果把蓝牙技术引入到移动电话和膝上型电脑中,就可以去掉移动电话与膝上型电脑之间的令人讨厌的连接电缆而而通过无线使其建立通信。打印机、PDA、桌上型电脑、传真机、键盘、游戏操纵杆以及所有其它的数字设备都可以成为蓝牙系统的一部分。除此之外,蓝牙无线技术还为已存在的数字网络和外设提供通用接口以组建一个远离固定网络的个人特别连接设备群。
Microsoft Windows CE .NET 是 Windows CE 3.0 的后续产品,它不仅是一个功能强劲的实时嵌入式操作系统,而且提供了众多强大工具,允许用户利用它快速开发出下一代的智能化小体积连接设备。借助于完善的操作系统功能和开发工具, Windows CE .NET 为开发人员提供了构建、调试和部署基于 Windows CE.NET 的定制设备所需的一切特性。平台开发工具 Platform Builder 是一个完全集成的开发环境( IDE ),并且包括一个软件开发工具包( SDK )导出工具。 Windows CE .NET 支持 Microsoft eMbedded Visual C++? 和 Microsoft Visual Studio.NET ,为面向 Microsoft .NET Compact Framework ( Microsoft .NET Framework 的一个子集)的 Web 服务和应用程序开发提供了一个完整的开发环境。利用这些工具,开发人员可以迅速开发出能够在硬件上运行各种应用程序的智能化设计。
因为在微软的。NET Compact Framework 2.0的类库中还未包含针对蓝牙通讯模块的类库,而且目前关于在Windows CE中开发蓝牙通讯模块应用程序的介绍还很少,同时开发蓝牙通讯技术的应用需要十分广泛,所以本文将就此进行一些讨论。
1 基于托管码开发蓝牙通讯模块
基于托管码的开发就是使用一套运行时环境(run-time environment)的应用程序接口来开发。
一般情况下,托管码应用程序的开发会比较简单和快速,并且可跨软件平台和处理器来运行,所以开发出的托管码也能重新使用并有较高的可移植性。
另外,内存管理、资源管理、资源收集、安全性管理等琐碎工作都由运行时环境来处理。应用程序开发工程师不必费心处理。托管应用程序在目标机器上运行,是通过目标机器端的实时编译器来实时把托管码编译成目标机器码后在目标机器上执行。
由于在。NET平台下,采用CLR(公共语言运行时)可以用不同的语言来调用。NET Compact Framework来开发相同功能的应用程序,所以本文托管码部分仅采用C#语言为例来介绍蓝牙通讯模块开发。
1.1 利用P/Invoke方法编写蓝牙通讯模块
蓝牙通讯模块是一个涉及到驱动硬件的应用程序开发,而。NET Compact Framework并不是一个对Win32API进行了完整封装的类库。 所以在基于托管码开发蓝牙通讯模块中必须利用到托管代码如何与非托管代码交互技术。P/Invoke全称为Platform Invoke,是。NET开 发平台下允许托管代码调用DLL库的本地代码函数的服务,类似于JA-VA中的GNI的概念。说明了P/Invoke方法的工作原理。首先用相应语言 的编译器将托管的源代码编译成Assembly的形式,其中包括元数据和中间语言代码。而此时P/Invoke的声明会以元数据的形式存在于 Assembly中,当Assembly被CLR调用的时候,CLR会根据元数据的声明在对应的DLL函数中查找DLL的实现。如果找到,就将其加载到内 存中,并定位此DLL函数的人口点。将托管的参数人栈,并将函数的人口点指向对应的native dll,从而完成了托管代码调用非托管代码的DLL.
利用P/Invoke方法编写蓝牙通讯模块,DllI-port属性非常有用。下面的代码将用例子说明此通用方案,例中托管程序将调用MessageBox(位于User32.lib中):
using
using namespace System:: Runtime::InteropSer-vices;
namespace SysWin32
{
[DllImport ( "user32. dll", EntryPoint = "MessageBox", CharSet = Unicode)]
int MessageBox(void * hWnd, wchar_t * lpText,wchar_t * lpCaption, unsigned int uType);
}
int main()
SysWin32 :: MessageBox(0, L" Hello world ! ", L"Greetings", 0)
}
注意包含DllImport的代码行。此代码行根据参数值通知编译器,使之声明位于User32.dll中的函数,并将签名中出现的所有字符串(如参数或 返回值)视为Unicode字符串。如果缺少EntryPoint参数,则默认值为函数名。另外,由于CharSet参数指定Unicode,因此公共语 言运行库将首先查找称为MessageBoxW的函数。如果运行库未找到此函数,它将根据调用约定查找MessageBox以及相应的修饰名。
当调用用户定义的DLL中所包含的函数时,有必要将extern"C"添加在DLL函数声明之前,如下所示:extern"C"SAMPLEDLL_API int fnSam-pleDLL(void);
在调用非本机码时,需要注意的是要将非结构化参数由托管封送处理为本机码形式。可以利用CharSet参数值的作用,将参数中字符串(string*类 型)都自动转换为wchar_t*.同样,所有Int32参数类型转换为非托管int,UInt32参数类型转换为非托管unsignedint,而 Intl6参数类型转换为了short int.char*用于[in]参数的为String*(CharSet=Ansi),用于[out]参数或返回 值的为Text::StringBuilder*.wchar-t*用于[in]参数为String*(CharSet=Unicode),用于 [out]参数或返回值的为Text::StringBuilder*.需要注意的是函数指针必须具有_stdcall调用约定,这是因为这是 DllImport支持的类型。对于数组来说数组(如wchar_t*[ ]),CharSet参数仅应用于函数参数的根类型。因此,无论 CharSet的值是什么,String*_ _gc[ ]将被封送处理为wchar_t*[].除简单类型外,运行库还提供了一种机制,可以将简单结构 由托管上下文封送处理为非托管上下文。简单结构不包含任何内部数据成员指针、结构化类型的成员或其他元素。
在做一个关于蓝牙通讯程序前,还需要一些关于蓝牙的基础知识。一个蓝牙模块程序需要包含开启蓝牙,配对,连接,建立串行通道,然后开启通讯过程,还需要在 应用程序中设置串行端口。因为蓝牙技术有安全方面的设置,所以需要对蓝牙设备进行配对。蓝牙的工作状态总共有3种,分别为开启、关闭、可发现。并且所有的 通讯设备都必须有一个对应的DeviceID,蓝牙也不例外,蓝牙的DeviceID是一串以":"分隔的16进制的数字。有了上述知识,就可以在托管码中利用P/Invoke方法开始编写蓝牙通讯模块了。
对应的每一步需要调用的基本函数如下:
获取本地设备的ID
[DllImport ( "Btdrt. dll", SetLastError = true) ]
public static extern int BthReadLocalAddr (byte[]PBa)
获取远程设备的ID
[DllImport( "ws2. dll", EntryPoint = "WSALook-upServiceBegin", SetLastError= true)]
public static extern int CeLookupServiceBegin(byte[ ] pQuerySet, LookupFlags dwFlags, ref intlphLookup)
监听服务
[DllImport (" ws2. dll", EntryPoint = "WSASetSer-vice", SetLastError= true)]
public static extern int CeSetService
(byte[ ] pQuerySet, RNRSERVICE_REGISTER,LookupFlags dwFlags)
连接
[DllImport ( "mscoree", EntryPoint = "@ 339" )]
public static extern int connect (int s, byte []name, int namelen)
蓝牙的安全设置
获取配对码请求
[DllImport("Btdrt. dll", SetLastError= true)]
public static extern int BthGetPINRequest(byte[]pba)
设置配对码
[DllImport( "btdrt. dll", SetLastError= true)
public static extern int BthSetPIN(byte[] pba, intcPinLength, byte [] ppin)
创建ACL连接:
[DllImport("Btdrt. dll", SetLastError= true)
public static extern int BthCreateACLConnection (byte[] pbt, ref ushort phandle);
然后是配对码验证:
[DllImport("Btdrt. dll", SetLastError= true)]
public static extern int BthAuthenticate (byte []pbt);
然后一定要关闭连接:
[DllImport("Btdrt. dll", SetLastError= true)]
public static extern int BthCloseConnection(ushorthandle);
设置蓝牙无线电状态
[DllImport("BthUtil. dll", SetLastError= true)]public static extern int BthSetMode (RadioModedwMode)
在建立好蓝牙设备的连接后,就可以进行两个蓝牙设备之间的通讯了。由于可以将蓝牙通信当作一个虚拟的串行通信来处理,所以在建立通讯的过程中可以采用类似于串口之间的通讯方式。而关于串口通讯这方面资料很多,本文就不具体详述了。
1.2 利用微软蓝牙嵌入式工具包编写蓝牙通讯模块
微软蓝牙嵌入式工具包是微软公司新推出来基于。NET Compact Framework 2.0的一款专门用来快速开发蓝牙应用程序的工具包,直接 在。NET平台下直接调用其中类库,可以快速,简单的开发一般的蓝牙应用程序。不过该工具包只能在Windows CE 5.0下使用。利用工具包可以完 成:启动一个蓝牙服务,寻找周边蓝牙设备,连接已存在的蓝牙设备或者服务。工具包可以在微软网站。
利用此工具做两个蓝牙设备间进行简单文本传输的程序部分代码如下:
Server 端:
Guid serviceGuid = new Guid (" { 81553B2B-FFOB-4415-86C9-22B799058B81 } ");
ServerHandle sh = btseore. CreateService (ser-viceGuid);
NetworkStream ns= sh. AceeptConnection()Sting dataToSend= " Hello";
Byte [] dataBuffer = System. Text. ASCIIEncoding. ASCII. GetBytes(dataToSend);
ns. Write(dataBuffer, 0, dataBuffer. Length);
ns. Flush();
ns. Close();
Client 端:
PairedDevices= btsCore. GetPairedDevices();
Foreach (BluetoothDevice device in pairedDevices)
{pairedDevicesListBox. Item. Add (device. deviceName) ;}
Guid serviceGuid = new Guid (" { 01550D2D-FF0D-4415-86C9-22B799058B81 } ");
If (pairedDevicesListBox. SelectedIndex﹥=0);
{ BluetoothDevice deviceToConnect= ( BluetoothDevice ) pairedDevices [ pairedDevicesListBox. Selected];
NetworkStream ns = btsCore. Connect (deviceTo-Connect, serviceGuid);
byte[ ] buffer=new byte[2000]
ns. Read(buffer, 0,50);
char[ ] bufferAsChars= System. Text. ASCII. GetChars(buffer)
System. String s= System. Text. Encoding. ASCIIGetString(buffer, 0, buffer, length);
Message. Show(s)
ns. Close(); }
1.3 利用OpenNETCF编写蓝牙通讯模块
OpenNETCF项目的主要产品是 Smart Device Framework,它是一个补充 .NET Compact Framework 1.0 版和 2.0 版的扩展类集。Smart Device Framework 提供很多可以在整个 .NET Framework 中使用的类、属性和方法,以及对特定于 Windows CE 环境的类的较大补充。有两种方式可以来使用它:一种是可以将其当作一个组件安装在 Visual Studio2005中;另一种是可以将其原代码编辑拿来使用。在OpenNETCF开源类库中就包括有蓝牙方面的,所以也可以利用 OpenNETCF来编写蓝牙通讯模块。在类库中,可以利用命名空间 OpenNETCF.IO.Ports下的Blue-toothSerialPort来建立蓝牙连接,利用命名空间 OpenNETCF.IO.Serial中内容进行蓝牙程序的通讯。
2 基于本机码开发蓝牙通讯模块
本机码应用程序是使用一套特定软件平台的应用程序开发接口来开发,并且被编译成一个特定处理器的目的码或机器码。一般情况下,本机码提供较高的效能和 的资源要求,但是被编译好的本机码或是可执行文件却只能在此软件平台或特定处理器上运行。此外,本机码应用程序常需要应用开发者自行处理类似内存管理、资 源管理、安全性管理等。在Visual Studio 2005中已经可以利用C++语言来开发基于MFC,ATL或Win32API的本机码WinCE 程序。这就提供了类似于用eMbedded Visual C++来开发windows mobile设备的方法。而本文在利用P/Invoke方法编写 蓝牙通讯模块时介绍的就是调用本机码开发蓝牙应用程序,方法类似,所以此处就不再进行具体的分析了。
3 结束语
本文讨论了在Visual Studio 2005里分别利用托管码和本机码来开发Windows mobile设备蓝牙通讯模块的几种方法。文中介绍的 蓝牙通讯模块各种开发方法都有各自的优点和缺点,如果用户开发的蓝牙通讯设备需要较高的效能和的资源要求,一定是采用本机码的方法来开发是的。因 为采用本机码开发的程序是直接被编译成机器码来执行的,从而可以获得更高的性能。但是采用本机码来开发程序的缺点就是开发难度大,开发周期长,所以并 不适用于一般要求的用户。而在对效能和资源要求并不是很高的产品中采用文中所述的托管码中的几种方法来开发蓝牙通讯模块则是更好的选择,用托管码开发的程 序会比较的简单和快速,同时又由于其并不直接生成终的机器代码,而是生成了中间代码来执行,所以用托管码开发的程序可以跨平台和处理器来运行,但是这是 以牺牲一定的访问速度为代价的。在基于托管码开发蓝牙通讯设备中本文共介绍了3种方法,因为到。NET FRAMEWORK 2.0的时候微软公司都没有 开发针对蓝牙通讯模块的类库,所以利用P/Invoke方法编写蓝牙通讯模块是在托管码下开发蓝牙通讯模块比较常见的选择。而微软蓝牙嵌入式工具包和 OpenNETCF类库编写蓝牙通讯模块方法比较类似,其都是类库对底层API的类封装,所以开发起来较为简单和快速,更适合于一般要求的蓝牙通讯模块的 开发。
蓝牙设备在嵌入式环境下的应用有着十分广阔的前景,目前还有很多工作尚需研究。解决如何在Windows mobile平台下开发更好更高效的蓝牙应用程序能够推动蓝牙技术在嵌入式产品上的更好利用。这一方面的开发将具有极强的实用性,将成为以后研究工作的重点
免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。