在嵌入式Linux上使用CF接口的蓝牙模块

2019-07-13 03:08发布

 随着各种支持蓝牙通信技术的设备的出现, 蓝牙通信变得越来越普及和广泛. 因此在嵌入式设备上集成蓝牙模块的需求变得越来越普遍. 本文以Anycom公司的CF接口的LSE139蓝牙模块为例, 介绍了如何配置使其在具有CF插槽的嵌入式arm-linux上工作.

1. 配置环境
操作系统: arm-linux
内核: 2.4.19

2. 内核/驱动支持
为了使内核支持蓝牙, 需要给内核打补丁: 我使用的是http://www.holtmann.org/linux/kernel/patch-2.4.19-mh18.gz  这里需要根据你的内核版本下载不同的补丁. 设备驱动方面, 这个就要看你的运气了, 因为不同版本的内核对蓝牙设备的支持是不一样的. 低版本的内核支持的蓝牙设备要少一些. 我使用的这款蓝牙模块直到内核2.6.6-rc2才得以支持. 所以我不得不更改驱动KERNEL_SOURCE_DIR/drivers/bluetooth/bluecard_cs.c, 使得LSE139在2.4的内核上也可以正常工作. 如果你需要这个Patch, 可以给我发消息或者写信. 我的Email地址是lijinlei1@hotmail.com.

然后对内核作出以下配置:

#
# Bluetooth support
#
CONFIG_BLUEZ
=m
CONFIG_BLUEZ_L2CAP
=y
CONFIG_BLUEZ_SCO
=y
CONFIG_BLUEZ_RFCOMM
=m
CONFIG_BLUEZ_RFCOMM_TTY
=y
CONFIG_BLUEZ_BNEP
=m
CONFIG_BLUEZ_BNEP_MC_FILTER
=y
CONFIG_BLUEZ_BNEP_PROTO_FILTER
=y

#
# Bluetooth device drivers
#
CONFIG_BLUEZ_HCIUSB
=n
CONFIG_BLUEZ_HCIUART
=n
CONFIG_BLUEZ_HCIUART_H4
=n
CONFIG_BLUEZ_HCIDTL1
=n
CONFIG_BLUEZ_HCIBT3C
=n
CONFIG_BLUEZ_HCIBLUECARD
=m
CONFIG_BLUEZ_HCIBTUART
=n
CONFIG_BLUEZ_HCIVHCI
=n
CONFIG_BLUEZ_HCIUSB_SCO
=n
CONFIG_BLUEZ_HCIUART_BCSP
=n
CONFIG_BLUEZ_HCIBFUSB
=n

注意CONFIG_BLUEZ_HCIBLUECARD是对"CF"接口的蓝牙设备的支持.
重新编译内核和模块, 然后安装到设备上并重新启动设备. 如果你不知道怎样编译内核和模块, 请参阅其他文献.

2. pcmcia_cs的修改
由于CF卡通过PCMCIA总线工作, 所以对pcmcia设备的配置也必须修改, 以保证cardmgr能够正确识别新设备并装载正确的Driver. 以下必须手工修改: /etc/pcmcia/config:

--- config.orig 2007-09-28 16:18:54.000000000 +0200
+++ config      2007-09-28 16:17:40.000000000 +0200
@@ -
23,6 +23,9 @@
 
device "serial_cs"
   class 
"serial" module "serial_cs"
 
+device "bluecard_cs"
+  class "bluetooth" module "bluecard_cs"
+
 
# dummy drivers
 
 
device "dummy_cs" module "dummy_cs"
@@ -
52,3 +55,8 @@
 card 
"Serial or Modem"
   function serial_port
   bind 
"serial_cs"
+
+card "Anycom LSE139 Bluetooth Compact Flash Card"
+  version "BTCFCARD", "LSE139"
+  bind "bluecard_cs"
+
注意其中增加(前面带+的)的部分. 做了这部分的修改后, 必须重新启动cardmgr. 然后插入蓝牙模块, 这时cardmgr应该可以正确的识别蓝牙模块并装载bluecard_cs.o. 如果一切正常应该没有任何警告和错误消息出现. 如果出现类似"收到不能识别的数据包" 之类的错误, 八成是驱动有问题了.

3.  安装bluez
需要交叉编译并安装到设备上的包有:
bluez-libs_2.21
bluez-utils_2.21
如果你安装高版本的bluez, 那么你可能还需要DBUS, 在这里不带DBUS功能的bluez于我的嵌入式设备已经够用, 所以我选择了一个低版本的Bluez. 当我编译bluez的时候编译器抱怨PATH_MAX未定义, 这个时候在出错的C文件头部加上#include

4. 启动蓝牙设备
root@ereader:~#/etc/init.d/bluetooth start 如果你没有这个脚本, 从其他Linux计算机上拷贝一个稍微修改一下就可以用了.
运行这个脚本后, 确保hcid 和 krfcommd这两个后台进程已经跑起来了.

然后可以运行hciconfig hci0, 可以看到蓝牙模块已经成功被初始化, 而且会显示正确的BD地址.

5. 扫描周围的蓝牙模块
root@ereader:~#hcitool scan
Scanning 
...
        
00:12:37:95:57:C9       Alex Henzen
        
00:0C:76:47:33:2F       edbuntu-0
        
00:17:B0:4C:B0:71       Nokia 6021
        
00:16:41:F6:E0:E0       NB003
        
00:16:41:D7:84:D7       NB024
        
00:16:41:D9:1A:1C       jinlei-Windows 现在可以说你的蓝牙设备已经可以正常工作了. 但如果我们想利用蓝牙通信帮助我们做一点事情, 还有很多其他工作要做. 下面我们举两个应用场景.

应用场景1: 通过蓝牙手机拨号上网
首先你需要一个可以上网的手机, 支持数据业务, 支持蓝牙通信, 并正确的配置好. 然后在设备上使用modprobe rfcomm插入rfcomm.o模块.

第一步, 扫描手机提供的蓝牙服务类型
root@ereader:~# sdptool browse 00:12:D2:CE:6C:A1
Browsing 
00:12:D2:CE:6C:A1 ...

Service Name: Headset Audio Gateway
Service RecHandle: 
0x10005
Service Class ID List:
  
"Headset Audio Gateway" (0x1112)
  
"Generic Audio" (0x1203)
Protocol Descriptor List:
  
"L2CAP" (0x0100)
  
"RFCOMM" (0x0003)
    Channel: 
29
Language Base Attr List:
  code_ISO639: 
0x454e
  encoding:    
0x6a
  base_offset: 
0x100
Profile Descriptor List:
  
"Headset" (0x1108)
    Version: 
0x0100

Service Name: Dial-Up Networking
Service RecHandle: 
0x10042
Service Class ID List:
  
"Dialup Networking" (0x1103)
Protocol Descriptor List:
  
"L2CAP" (0x0100)
  
"RFCOMM" (0x0003)
    Channel: 
2
Language Base Attr List:
  code_ISO639: 
0x454e
  encoding:    
0x6a
  base_offset: 
0x100
Profile Descriptor List:
  
"Dialup Networking" (0x1103)
    Version: 
0x0100

可以看到这个手机提供了两种蓝牙服务类型, 便携式耳麦和拨号服务. 我们只对后者感兴趣. 注意该手机在Channel 2上提供拨号连接.

第二步, 与手机配对(Pair)
root@ereader:~#rfcomm connect 0 00:12:D2:CE:6C:A1 2 请参考rfcomm的帮助了解各个参数的意义. 倒数第二个参数是手机的BD地址, 最后一个参数是连接到哪个channel.  为了确保这一步可以成功, 修改/etc/bluetooth/hcid.conf, 了解pin_helper的用法, 为自己的蓝牙设备设置一个PIN码. 以后这个PIN码就成为配对时的鉴权工具. 当手机收到配对请求时, 输入相同的PIN码即可.

第三步, 安装拨号工具
交叉编译pppd并安装到设备上. 在这之前你可能还要做很多其他的工作比如重新编译内核使其具备对PPP协议的支持等. 可以参考我的另外一篇文章"在嵌入式Linux上使用CF接口的Modem (CDMA/GPRS) "

第四步, 编写拨号脚本 (假设这个手机是使用中国联通运营商的CDMA手机)
建立文件/etc/ppp/chat-unicom (这里以中国联通的UIM卡为例),使之具有下面的内容:
# /etc/ppp/chat-unicom
# this is the chat script for unicom

ABORT 
"NO CARRIER"
ABORT 
"NO DIALTONE"
ABORT 
"ERROR"
ABORT 
"NO ANSWER"
ABORT 
"BUSY"
TIMEOUT 
120
"" at
OK atdt
#777
CONNECT
ABORT "***" 意思是如果结果回显中碰到这样的字符串则中断拨号程序,#777是通过中国联通通信网络上网的拨号号码.

第五步, 开始拨号
modprobe ppp_async
ln -s
/dev/rfcomm0 /dev/modem /usr/sbin/pppd connect '/usr/sbin/chat -v -f /etc/ppp/chat-unicom' user card password card /dev/modem 115200 nodetach crtscts debug usepeerdns defaultroute nodetach的意思是pppd在前台运行,不脱离控制台,这样可以看到pppd的输出. 默认行为是后台运行。 好了,大功告成,现在可以享受网上冲浪之旅了。 应用场景2: 与PC连接组成无线局域网, 并可以通过PC上网
首先你的电脑需支持蓝牙通信, 并安装了bluez-utils. 然后在设备上使用modprobe bnep插入bnep.o模块. 这里我假设你的电脑运行的是Linux. Windows上的配置应该更为简单, 略.

第一步, 修改/etc/network/interfaces使得当设备与PC连接起来后自动配置Interface:
iface bnep0 inet dhcp 这里我们使用DHCP. 因为我想让PC充当DHCP服务器给我的设备分配IP地址.所以我们在PC上也要做一些配置.

第二步, PC配置.
修改/etc/bluetooth/hcid.conf, 如下(只列出改动的部分):
lm accept, master;
PAND_ENABLED
=1
PAND_OPTIONS
="--listen --role=NAP --devup /etc/bluetooth/pan/dev-up" 改动完成后重启bluetooth服务, 确保pand后台服务已经跑起来了.

建立脚本/etc/bluetooth/pan/dev-up, 如下:
#!/bin/sh
echo 1 > /proc/sys/net/ipv4/ip_forward
ifup bnep0
这里的第二行是指我们共享该计算机的Internet连接(IP转发), 第三行是指当bluetooth连接建立起来后自动唤起interface.

然后是配置DHCP服务器(修改/etc/dhcp3/dhcpd.conf), 使得它能够给连接到bnep0上的设备分配IP地址, 并告知DNS服务器的IP地址等, 请参考http://www.yolinux.com/TUTORIALS/DHCP-Server.html获得关于如何配置DHCP服务的信息.

重启DHCP服务.

第三步, 连接到PC
pand -c 00:16:41:D9:1A:1C -r PANU -d NAP -z -n 这里第二个参数是PC上蓝牙模块的BD地址, 其他参数请参考pand的帮助信息. 如果连接成功建立, 使用ifconfig应该可以看到一个新的interface已经建立(bnep0), 然后其IP地址也自动获得. 应该可以PING通PC了, 而且可以上网了.

Good Luck!