蓝芽最早由瑞典Ericsson提出,其名称是古代瑞典的一位国王,因为总吃某种诡异果品 (似乎是草莓的一个品种,不太了解植物学,错了的话不要拍我),把牙齿弄得蓝乎乎的,被称作蓝牙(bluetooth)。古代瑞典可不像现在的一样,那时 的瑞典统治整个北欧,可气派了,同样有野心的爱立信于是使用BT这个名字来命名这个被他们寄予厚望的短距离互联技术。
Bluetooth用于连接个人周边的外围设备,比如无线耳机、打印机、扫描仪、手机、计算机等等,在这些设备之间交换文件和数据,替代低速串行线的工作,常用用途包括
- 文件共享、传输
- 语音传输
- 远程打印
- RS-232串行口线替代
因 为Bluetooth的功能十分实用、一经提出,立刻有一种一呼百应的感觉,随着成本的下降,蓝芽的用途也越来越广(当然了,这个过程也不是一帆风顺的 了),大量的中低端手机也开始装备上了这项技术,以其更丰富、完善的协议栈,略高的传输速率,以及相对于红外线来说摆脱了必须毫无障碍的束缚,几乎完全取 代了原来商务手机上普遍装备的红外接口。
蓝芽来到中国,把“牙”替换成了更有东方美感的“芽”字。
蓝芽实际上并不是一种简单的协议,相反,十分复杂
- 从网络结构和组网方式讲,蓝芽在10米区域内形成一个网络,其中可以有1个主设备,7个从设备,一共8个激活的设备,当然睡觉的设备还可以有很多,不打呼噜就行了。对于更多的设备,可以使用ad hoc的方式互联,学网络的同学们看到这个来精神了吧,不过我可不打算讲了。
- 从应用来看,BT支持语音通信和串行线模拟,并且通过Profile来支持各种周边智能设备的应用,比如耳机、打印机……并且定义了一套服务发现和调用机制,还是瞒有意思的。
蓝芽最有意思的模过于第2层互联和应用层的Profile了,至于底层的跳频什么的倒是新意不大。另外就是,虽然蓝芽使用的频率和微波炉烹饪的频率毫无二致,但发射功率还是很小的,基本不足以把我们这么大块的肉弄熟。
Linux下的蓝芽协议栈Linux 下有若干个蓝芽协议栈,目前生存状况比较健康的是bluez和affix,后者大概是Nokia支持的吧,前者则是目前蓝芽的Linux官方版本,集成在 Linux内核之中,也就是说,如果你有一个比较新的2.6内核,那么,你多半已经支持蓝芽了,而如果还不支持的话,重新编译一下也就好了。
不 要觉得Linux的协议栈比不上Windows里面的,事实是,这里风景独好,bluez协议栈支持的硬件设备远远多于windows系统支持的。如果你 和我一样只用Linux,那么,买了蓝芽适配器之后,大概就可以把臃肿的驱动光盘丢进垃圾桶,然后心情愉快的使用蓝芽了,跟我来吧,
内核的协议栈支持主要包含这么几个部分:
- HCI. 这个是最底层的了,称为 Host Control Interface. 之所以称为 HCI 是源于蓝芽的应用模型的。蓝芽是连接智能外设的无线接口,接口的一侧是设备,另一侧就是主机 (Host) 了,采用类似记法的还有 USB, IEEE1394,所以,从设计初衷来看,这几个东东都是针对差不多的市场的,当然,各有所长了。一个蓝芽适配器是否能被驱动起来,就看 HCI 的支持性了。最常见的蓝芽适配器就是笔者持有的这类 USB 接口的了,对于大部分标准的蓝芽设备,它的驱动模块是: hci-usb,对于我们的 2.6 内核,插入这个适配器,该模块就被自动加载了。
- 在 HCI 之上是 L2CAP,Logical Link Control and Adaptation Protocal 这一层的功能承上启下,向上层提供异步数据传输的链路控制功能,所谓异步,就是不存在一个主时钟来同步所有传输的一种传输方式,通常用于数据的传输;与之相反,同步传输是完全与时钟同步的,通常用在诸如语音或是多媒体通话之中,在蓝芽中,语音同步传输也是被支持的,bluez 协议栈中的 SCO 就是支持同步模式的。
- L2CAP之上有两个协议被较广地使用着:RFCOMM和BNEP,前者用于取代传统的串行口,包括串行口上的各种应用,比如,传真和拨号上网、打印机、文件图片等数据传输;后者则可以提供一个以太网接口,更适于计算机组网。自然地,对于手机和计算机之间,RFCOMM 总是更常被用到。
截止到这里就是内核提供的几乎所有蓝芽协议栈了,不过,仅有这些,蓝芽还不足以为我所用,只有有了用户态的协议栈和工具相配合,才有幸福的蓝芽生活 :)
用户空间中的蓝芽协议栈与相关工具接着刚才的协议栈,这次势在用户空间实现的了:
- 在最上层,蓝芽定义了很多的Profile,每个Profile对应着一种应用,比如打印、耳机(Headset)、文件传输、Fax/Modem拨号功能等。其中,文件交换对应着Obex协议,这是一个基于蓝芽、红外(IrDA)、串口等介质的文件(对象)交换协议,这几种介质被列到一起一点也不会让人感到意外,毕竟前两个都是用来在某种意义上取代串口的。当然,有些Profile,比如一些人机交互设备 (键盘鼠标之类的) 的profile 是在内核中实现的。
- 实 际上,我们还有一个重要的协议没有介绍,这就是SDP --- 服务发现协议,这个协议可以认为和RFCOMM处于统一层次,因为它并不承载于RFCOMM之上,不过,这个协议却十分特殊而重要,通过它,我们才能识别 出某一蓝芽设备提供了哪些服务(Profile),从而为我所用。
嗯,协议栈已经有了,那我们怎么使用蓝芽呢? 回忆一下怎么把大象放到冰箱里吧:
- 打开冰箱门
- 把大象放进冰箱
- 关上冰箱门
就是这么简单,一个蓝芽服务也是这么容易:
- 找到蓝芽设备,这是HCI层负责的,使用 bluez-utils 包提供的 hcitool 来找到蓝芽设备;
- 找到服务,RFCOMM 是通过不同的频道 (channel) 来提供不同的Profile的,所以,我们需要找到我们要用的服务在设备上的哪个频道上,这是通过同一个软件包里的 sdptool 来完成的,没错,就是 SDP,服务发现协议。
- 连接恰当的服务,使用
蓝芽的特点就是如上所属的那些了,而用户态的工具所要完成的任务就是:
- 发现服务
- 使用服务
首 先,我们需要启动 hcid,让 HCI 层的通信可以进行,对于 Debian 用户来说,你需要安装 bluez-utils 包,并启动 hcid。如果你运行了 bluetooth 服务,并在 /etc/default/bluetooth 之中设置启动了 HCID 的话
HIDD_ENABLED=1
插入 USB 适配器后,你的 hcid 就已经在运行了,看看相关信息吧:
inspiration:/etc/bluetooth# hciconfig -a
hci0: Type: USB
BD Address: 11:11:11:11:11:11 ACL MTU: 678:8 SCO MTU: 48:10
UP RUNNING PSCAN ISCAN
RX bytes:413 acl:0 sco:0 events:19 errors:0
TX bytes:323 acl:0 sco:0 commands:19 errors:0
Features: 0xbf 0xfe 0x8d 0x78 0x08 0x18 0x00 0x00
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy: RSWITCH HOLD SNIFF PARK
Link mode: MASTER
Name: 'inspiration-0'
Class: 0x3e0100
Service Classes: Networking, Rendering, Capturing, Object Transfer, Audio
Device Class: Computer, Uncategorized
HCI Ver: 1.2 (0x2) HCI Rev: 0x1fe LMP Ver: 1.2 (0x2) LMP Subver: 0x1fe
Manufacturer: Integrated System Solution Corp. (57)
这个过程是自动的,当然,你也可以用 hciconfig (8) 来手工控制。
HCI 已经启动了,现在就可以用它来寻找蓝芽设备了,当然,一定要先开启蓝芽设备的蓝芽功能,这个不是废话,手机的蓝芽是默认关闭的,只有在手动控制之下才会发 送信号,允许被扫描到,不过设备的个体差异性太大了,这里就没法介绍了,我假设你已经自己摸索或参照说明书打开了设备的蓝芽电源,现在,找找看吧
inspiration:/home/gnawux# hcitool scan
Scanning ...
00:17:00:7B:18:B8 Motorola SLVR
命令一出,略等片刻,蓝芽设备就会被顺利地找到。
查看设备提供的服务利用 SDP 协议,我们还可以查看每个设备都有功能,能提供什么服务,每种基于 RFCOMM 的服务都使用某种协议,占据一个“频道 (channel)”,这是我们使用服务时的一个重要参数
下面是例子,先看看自己:
gnawux@inspiration:~$ sdptool browse localBrowsing FF:FF:FF:00:00:00 ...
Service Name: OBEX Object Push
Service RecHandle: 0x10000
Service Class ID List:
"OBEX Object Push" (0x1105)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 9
"OBEX" (0x0008)
Profile Descriptor List:
"OBEX Object Push" (0x1105)
Version: 0x0100
再看看别人 (手机)
gnawux@inspiration:~$ sdptool browse 00:17:00:7B:18:B8Browsing 00:17:00:7B:18:B8 ...
Service RecHandle: 0x0
Service Class ID List:
"SDP Server" (0x1000)
Protocol Descriptor List:
"L2CAP" (0x0100)
"SDP" (0x0001)
Profile Descriptor List:
"SDP Server" (0x1000)
Version: 0x0100
Service Name: Dialup Networking Gateway
Service Description: Dialup Networking Gateway
Service Provider: Motorola
Service RecHandle: 0x10001
Service Class ID List:
"Dialup Networking" (0x1103)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 1
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
code_ISO639: 0x7a68
encoding: 0x6a
base_offset: 0xc800
Profile Descriptor List:
"Dialup Networking" (0x1103)
Version: 0x0100
Service Name: Voice Gateway
Service Description: Headset Audio Gateway
Service Provider: Motorola
Service RecHandle: 0x10003
Service Class ID List:
"Headset Audio Gateway" (0x1112)
"Generic Audio" (0x1203)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 3
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
code_ISO639: 0x7a68
encoding: 0x6a
base_offset: 0xc800
Profile Descriptor List:
"Headset" (0x1108)
Version: 0x0100
Service Name: Handsfree Voice Gateway
Service Description: Handsfree Voice Gateway
Service Provider: Motorola
Service RecHandle: 0x10007
Service Class ID List:
"Handfree Audio Gateway" (0x111f)
"Generic Audio" (0x1203)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 7
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
code_ISO639: 0x7a68
encoding: 0x6a
base_offset: 0xc800
Profile Descriptor List:
"Handsfree" (0x111e)
Version: 0x0101
Service Name: OBEX Object Push
Service Description: OBEX Object Push
Service Provider: Motorola
Service RecHandle: 0x10008
Service Class ID List:
"OBEX Object Push" (0x1105)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 8
"OBEX" (0x0008)
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
code_ISO639: 0x7a68
encoding: 0x6a
base_offset: 0xc800
Profile Descriptor List:
"OBEX Object Push" (0x1105)
Version: 0x0100
Service Name: OBEX File Transfer
Service Description: OBEX File Transfer
Service Provider: Motorola
Service RecHandle: 0x10009
Service Class ID List:
"OBEX File Transfer" (0x1106)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 9
"OBEX" (0x0008)
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
code_ISO639: 0x7a68
encoding: 0x6a
base_offset: 0xc800
Profile Descriptor List:
"OBEX File Transfer" (0x1106)
Version: 0x0100
Service Name: Image Push
Service Description: Image Push
Service Provider: Motorola
Service RecHandle: 0x1000a
Service Class ID List:
"Imaging Responder" (0x111b)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 10
"OBEX" (0x0008)
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
code_ISO639: 0x7a68
encoding: 0x6a
base_offset: 0xc800
Profile Descriptor List:
"Imaging" (0x111a)
Version: 0x0100
手机的比较多,我也没有截短,方便大家看看手机可能提供的丰富蓝芽功能。下一节我们将介绍几个利用蓝芽可以做的事情:
蓝芽应用上一节,通过 sdptool,我们看到笔者的手机提供了拨号、耳机、文件传输等功能,现在我们就来试试看。利用蓝芽传输文件
利用蓝芽传送文件使用的都是前面提到的 Obex 协议,这里介绍几个用法。
与手机互相推送文件这是使用手机或计算机提供的"OBEX Object Push" (0x1105)服务,由另一方向其推送文件。使用的工具是 openobex-apps 包里的 obex_test工具
首先是向手机推送,对于我的手机,推送服务在频道8:
gnawux@inspiration:~$ obex_test -b 00:17:00:7B:18:B8 8
Using Bluetooth RFCOMM transport
OBEX Interactive test client/server.
> c
Connect OK!
Version: 0x10. Flags: 0x00
> p wangxu.jpg me.jpg
PUT file (local, remote)> name=wangxu.jpg, size=34177
Going to send 34177 bytes
Made some progress...
Made some progress...
Made some progress...
Made some progress...
Made some progress...
PUT successful!
> q
可 以看到,执行完 obex_test 之后,进入一个交互状态,首先建立连接,然后传送文件 (本地文件名是 wangxu.jpg,存在手机上叫 me.jpg,这个是我随便取的),最后,退出。这个过程需要看着点手机屏幕,可能要你确认是否连接,文件存放在哪里,当然,这个和手机有关。
现在也可以看看手机向计算机推送,首先应该让手机进入接收状态,如果本地没有启动 Object PUSH 服务,己把它加上:
gnawux@inspiration:~$ sdptool add OPUSH
OBEX Object Push service registered
现在进入接收状态,注意要使用计算机 (local) 的地址和频道号:
gnawux@inspiration:~$ obex_test -b FF:FF:FF:00:00:00 9
Using Bluetooth RFCOMM transport
OBEX Interactive test client/server.
> s
现在,计算机进入了接收模式,在手机侧发送文件到计算机就可以了。
使用"OBEX File Transfer" (0x1106)服务的 obexftp 是一个方便的工具,我们可以查看手机上的内容,并进行上传下载,对于我的手机,对应的频道是 9 (参考上面的 sdptool browse 的结果)。
看看有哪些目录:
gnawux@inspiration:~$ obexftp -b 00:17:00:7B:18:B8 -B 9 -l
Browsing 00:17:00:7B:18:B8 ...
Channel: 9
Connecting...done
Receiving "(null)"...|<?xml version="1.0" ?>
<!DOCTYPE folder-listing SYSTEM "obex-folder-listing.dtd">
<folder-listing>
<parent-folder />
<folder name="audio" size="0" type="folder" modified="20060805T144844Z" user-perm="RW" />
<folder name="video" size="0" type="folder" modified="20060805T144844Z" user-perm="RW" />
<folder name="picture" size="0" type="folder" modified="20060805T144844Z" user-perm="RW" />
<folder name="MMC(Removable)" size="0" type="folder" modified="19700101T000000Z" user-perm="RW" />
</folder-listing>
done
Disconnecting...done
可以看到,有四个有读写 (RW) 权限的目录,现在,再看看 audio 里面有什么
gnawux@inspiration:~$ obexftp -b 00:17:00:7B:18:B8 -B 9 -l audio
Browsing 00:17:00:7B:18:B8 ...
Channel: 9
Connecting...done
Receiving "audio"...|<?xml version="1.0" ?>
<!DOCTYPE folder-listing SYSTEM "obex-folder-listing.dtd">
<folder-listing>
<parent-folder />
<file name="a.mp3" size="977920" type="audio/mp3" modified="20060805T145050Z" user-perm="RW" />
</folder-listing>
done
Disconnecting...done
可以看到,这里有一个 mp3 文件,我们把它取下来
gnawux@inspiration:~$ obexftp -b 00:17:00:7B:18:B8 -B 9 -c audio -g a.mp3
Browsing 00:17:00:7B:18:B8 ...
Channel: 9
Connecting...done
Sending "audio"...done
Receiving "a.mp3"...-done
Disconnecting...done
经过一段漫长的等待,传送终于完成了,有点后悔选择这么大的文件进行传输。现在,再把 wangxu.jpg 放到 picture 目录去
gnawux@inspiration:~$ obexftp -b 00:17:00:7B:18:B8 -B 9 -c picture -p wangxu.jpg
Browsing 00:17:00:7B:18:B8 ...
Channel: 9
Connecting...done
Sending "picture"... done
Sending "wangxu.jpg"...\done
Disconnecting...done
其他 obexftp(1) 的用法,大家自己学习文档吧 :)
还有 obexserver, qobex (qt based) 等工具,使用起来更为简单,就不介绍了。
我们说过,蓝芽的一个几本功能就是模仿串口,串口的重要作用之一 (可能是最重要的了) 就是拨号,传统的 DTE 也就是 Modem 嘛。实际上,通过 rfcomm,蓝芽连接可以反映在 /dev/rfcomm0 这样的字符设备上,像串口一样操作。当然,我们最好先定义 /etc/bluetooth/rfcomm.conf,里面根据手机的设备号和频道号写上
rfcomm0 {
# Automatically bind the device at startup
bind yes;
# Bluetooth address of the device
device 00:17:00:7B:18:B8;
# RFCOMM channel for the connection
channel 1;
# Description of the connection
comment "Motorola SLVR L7";
}
这样,在启动 bluetooth 服务的时候,就已经自动连接上了,而不需要使用rfcomm (1) 命令自己费力气了。现在,可以使用任意一个喜欢的串口程序 (minicom, gtkterm 等等) 来对 /dev/rfcomm0 进行拨号了
输入 AT 命令的第一个命令:
AT
OK
试着播一下号
ATD139012345;
这个是随便写的号码,大家找认识的号码播哦 (故意少写了两位,省得万一试到人家头上,呵呵),当然,也可以连接GPRS,这里,我们借助于最基本的拨号程序pppd 来实现,实际也是通过AT Command来实现的。
rfcomm1
115200
debug
noauth
defaultroute
usepeerdns
connect-delay 10000
crtscts
lock
lcp-echo-failure 4
lcp-echo-interval 65535
connect '/usr/sbin/chat -v -t3 -f /etc/ppp/peers/gprs_chat'
根据这个文件的内容,pppd 将利用 gprs_chat 这个文件的内容,在串口 rfcomm1 (也就是到我的L7手机的蓝芽连接) 上进行交互,建立ppp连接,这个chat 文件的内容就是一些 AT Command 的交互:
inspiration:/home/gnawux# cat /etc/ppp/peers/gprs_chat
ABORT 'NO CARRIER'
ABORT 'ERROR'
ABORT 'NO DIALTONE'
ABORT 'BUSY'
ABORT 'NO ANSWER'
'' 'ATZ'
'OK' 'ATE0V1'
'OK' 'AT+CGDCONT=1,"IP","cmwap.cmcc.com","0.0.0.0",0,0'
'OK' 'ATD*99***1#'
上面就是一个GPRS建立需要的几条 AT Command,文件建立之后,需要的操作很简单,只要运行
pppd call gprs
就可以建立连接了,这是 ifconfig 得到的信息
ppp0 Link encap:Point-to-Point Protocol
inet addr:10.14.7.136 P-t-P:192.168.100.101 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:4 errors:1 dropped:0 overruns:0 frame:0
TX packets:13 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:64 (64.0 b) TX bytes:543 (543.0 b)
这是路由表和DNS设置:
inspiration:/etc/ppp/peers# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.100.101 * 255.255.255.255 UH 0 0 0 ppp0
default * 0.0.0.0 U 0 0 0 ppp0
inspiration:/etc/ppp/peers# cat /etc/resolv.conf
nameserver 221.130.33.52
nameserver 221.130.33.60
呵呵,非常简单吧。
小结至此,Linux与蓝芽手机的全部内容,理论到操作已经全部完成了,基于的操作系统是使用 2.6 内核的 Debian GNU Linux,测试的手机包括 Motorola SLVR L7 和 Nokia N-Gage QD 各一部,蓝芽适配器芯片是 Integrated System Solution Corp. KY-BT100 Bluetooth Adapter,所有测试都非常顺利,也祝读者朋友玩得开心。