bluetooth(藍牙)在S3C2410上的移植

(一) 在Red hat 9上安裝Bluez
在pc上的安裝我參考了O'Reilly的Linux Unwired一書,chapter 7中詳細地介紹了linux下的bluetooth的基礎知識、安裝、配置和使用。安裝前必須瞭解一下bluez的基本結構,直接位於發射傳輸協議之上的 協議是HCI(host control interface),我的手機和藍牙GPS用到的高層協議是服務發現協議SDP和模擬串口的協議RFCOMM,中間那一層協議是L2CAP,應該是處理 邏輯鏈路的吧,我並不是很清楚,請參考bluez的官方文檔。
S3C2410上用到內核版本是2.4.18,於是我在pc上安裝bluez時也使 用了2.4.18的內核。使用bluez必須要對內核打 patch的,於是到www.kernel.org上下載了linux-2.4.18.tar.bz2後到http: //www.bluez.org/patches.html上下載針對2.4.18的patch,patch-2.4.18-mh15.gz。於是,解 壓,打patch:
# tar xjvf linux-2.4.18.tar.bz2
# cd linux/
# gzip -dc ../patch-2.4.18-mh15.gz | patch -p1
注意一下這時的patch的輸出,在源代碼方面的patch是針對driver/、include/、net/目錄下的代碼的修改,並沒有修改到內核部分的內容,應該沒有修改到linux核心的東西,在移植到S3C2410時應該不會有太大的問題。
下面就是編譯內核,在config的時候關於bluez我的配置是這樣的:
#
# Bluetooth support
#

CONFIG_BLUEZ=m
CONFIG_BLUEZ_L2CAP=m
CONFIG_BLUEZ_SCO=m
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=m
# CONFIG_BLUEZ_HCIUSB_SCO is not set
CONFIG_BLUEZ_HCIUART=m
CONFIG_BLUEZ_HCIUART_H4=m
CONFIG_BLUEZ_HCIUART_BCSP=m
# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set
# CONFIG_BLUEZ_HCIBFUSB is not set
CONFIG_BLUEZ_HCIDTL1=m
CONFIG_BLUEZ_HCIBT3C=m
CONFIG_BLUEZ_HCIBLUECARD=m
CONFIG_BLUEZ_HCIBTUART=m
CONFIG_BLUEZ_HCIVHCI=m
供大家參考,Linux Unwired一書中有詳細的說明,注意如果使用make menuconfig,一定要打開一下.config文件看看CONFIG_BLUEZ_RFCOMM_TTY=y,不能爲n或者m。還有注意 CONFIG_USB_BLUETOOTH一定不能選(在USB support下),否則會影響到bluez的運行的。
內核編譯好了就開始準備bluez的庫和工具了。到http: //www.bluez.org/download.html上下載最新的bluez程序包,我只下載了bluez-libs-2.20.tar.gz, bluez-utils-2.20.tar.gz,bluez-pin- 0.25.tar.gz三個包,分別是庫,工具集和由bluez提供的一個 pin_helper。由於在pc下,安裝的過程沒什麼好說的,解壓,./configure,make,make install。
然後就是注意一下默認配置目錄/etc/bluetooth/下的hcid.conf配置文件,這是用來配置後臺daemon進程hcid的。如果把這 臺pc機器+藍牙適配器看成是一個藍牙設備的話,進程hcid就管理這個藍牙設備的基本配置信息,例如名稱,class,地址,feature等等。還有 當設備與其他藍牙設備Bonding/Pairing即所謂的配對時,處理PIN code的程序也是hcid,而在hcid.conf腳本中比較重要的一項就是pin_helper,默認的配置是pin_helper= /usr/bin/bluepin,這個是python寫的用來讀取用戶輸入的PIN code的程序,安裝bluez-pin包的時候裝在/usr/bin下的。
這裏有必要了解一下配對的過程,我感覺就是兩個設備互相通密碼建 立相互之間連接的過程。我看了hcid部分的代碼,瞭解的大致是這樣:比如兩個藍牙設備A和B,A先發送要求配對的請求給B,B由用戶設置好配對的密碼即 PIN code,然後回一個消息給A,說你想配對可以呀,知道我的密碼嗎?然後A就發送PIN code過去,B看和自己的密碼相符合,就發送一個replyOK的消息給A,這樣兩者就建立起來了信任關係。
在pc+藍牙適配器這個藍牙設 備A上,如果這個設備先發送配對請求給另一個遠程設備B,那麼當B發送詢問密碼請求過來時,在A上運行的hcid後臺進程就通過一個pin_helper 的程序讀取PIN code,併發送回給B;如果遠程設備B先發送配對請求給A,hcid上用作驗證的PIN code就是/etc/bluetooth/pin的內容,如果讀取失敗程序在啓動的時候會默認地設置一個密碼的,代碼在bluez- utils/hcid/security.c中的init_security_data函數中,默認的是BlueZ。爲了和我的手機相配,我把它改成了 123,手機只能輸入數字。
關於其他hcid.conf的設置,請man hcid.conf。
設置好以後,換上新內核,啓動 linux。插入USB藍牙適配器,# dmesg | tail會發現有usb.c: USB device 2 (vend/prod 0x1131/0x1001) is not claimed by any active driver.這個問題,不管它,只要有usb.c: registered new driver hci_usb的消息就可以,然後 # lsmod 會發現hci_usb的模塊被安裝了,再# modprobe rfcomm,這樣基本上所有的模塊都安裝齊了。
# hciconfig hci0 up
# hcid -f /etc/bluetooth/hcid.conf
啓動hci設備和hcid精靈進程
# hciconfig -a
hci0: Type: USB
BD Address: 00:11:67:0F:BB:A1 ACL MTU: 678:8 SCO MTU: 48:10
UP RUNNING PSCAN ISCAN
RX bytes:115 acl:0 sc0 events:15 errors:0
TX bytes:313 acl:0 sc0 commands:15 errors:0
Features: 0xff 0xff 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: SLAVE ACCEPT
Name: 'BlueZ (0)'
Class: 0x000100
Service Classes: Unspecified
Device Class: Computer, Uncategorized
HCI Ver: 1.2 (0x2) HCI Rev: 0x1ae LMP Ver: 1.2 (0x2) LMP Subver: 0x1ae
Manufacturer: Integrated System Solution Corp. (57)
可以看到目前設備的配置情況,有些是從hcid.conf中讀取的,有些是從設備中讀取的。
下面,打開手機上的藍牙,啓動藍牙GPS
# hcitool scan
Scanning ...
00:0E:07:58:1A:33 T628
00:08:1B:C0:D1:3C HOLUX GR-231
這樣就看到了兩個設備了,我用的是索愛的T628和HOLUX的藍牙GPS,前面的一串應該是藍牙設備唯一的地址。
#sdptool browse 可以看到每個設備所提供的服務
Inquiring ...
Browsing 00:0E:07:58:1A:33 ...
Service Name: Dial-up Networking
Service RecHandle: 0x10000
Service Class ID List:
"Dialup Networking" (0x1103)
"Generic Networking" (0x1201)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 1
Profile Descriptor List:
"Dialup Networking" (0x1103)
Version: 0x0100

.............

Service Name: Serial Port 1
Service RecHandle: 0x10003
Service Class ID List:
"Serial Port" (0x1101)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 4

............

Service Name: OBEX Object Push
Service RecHandle: 0x10005
Service Class ID List:
"OBEX Object Push" (0x1105)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 10
"OBEX" (0x0008)
Profile Descriptor List:
"OBEX Object Push" (0x1105)
Version: 0x0100

Browsing 00:08:1B:C0:D1:3C ...
手機上綁定了很多的服務,有撥號服務,音頻服務,串口服務,文件交換服務(OBEX)...在SDP協議下,每個服務綁定到一個Channel上。GPS上沒有綁定服務,它只作爲虛擬串口設備來使用。
利用實用工具rfcomm可以把遵循RFCOMM的服務bind到一個類似的串口設備上。在綁定之前,必須確保/dev下有rfcomm*的設備,如果沒有,就自己建立:
# mknod -m 666 /dev/rfcommX c 216 X (X是數字)
這樣就可以綁定了,比如我需要用手機撥號上網的功能,看到它的Channel 1是RFCOMM的Dialup Networking功能,則:
# rfcomm bind 0 00:0E:07:58:1A:33 1
即將00:0E:07:58:1A:33設備的Channel 1服務綁定到/dev/rfcomm0上,這樣,就相當於建立了一個虛擬的串行連接到一個可以撥號的無線modem上了,打開minicom,設置串口爲 /dev/rfcomm0,波特率19200,8N1,鍵入atz,返回OK。用ppp就可以撥號上網了,第一次連接時手機會彈出個輸入框問PIN code,以後就不用了。
GPS設備只是作爲串口來用的,也很簡單:
# rfcomm bind 1 00:08:1B:C0:D1:3C
打開minicom設置波特率爲4800就可以讀GPS數據了,大功告成!
另外,sdpd程序是本設備提供給對外的看到的服務,可以通過sdptool add --channel=X SP來增加對外的服務,我沒有研究過。還有對於文件傳輸OBEX和個人局域網BNEQ還需要繼續學習。

(二)在S3C2410上的移植
完成了在普通red hat上的安裝,熟悉了藍牙協議棧一些基本的東西,下面的任務就是把協議棧搬到開發板上了。
第一步當然是內核了,由於三星的內核代碼改過,我也不知道從bluez上下載的patch能不能使用,試試看了,只好。
# cd /2410/kernel
# gzip -dc ~/patch-2.4.18-mh15.gz | patch -p1
# find ./ -name '*rej'
./fs/cramfs/inode.c.rej
不好,有文件不能patch,看看是針對cramfs文件系統的patch,我也不清楚爲什麼bluez的patch會修改到cramfs,不過我想問 題應該不大。內核源代碼關於bluetooth的部分三星應該沒有改過,因此patch的主要部分應該是沒有問題的。如果內核編譯後發生問題,我想大概也 只有把內核代碼翻出來看了。
先就這樣了,用用試試看好了。與普通pc上的類似,只不過有些是m的現在統統爲y了。我的配置關於Bluez的部分設置爲:
#
# Bluetooth support
#
CONFIG_BLUEZ=y
CONFIG_BLUEZ_L2CAP=y
# CONFIG_BLUEZ_SCO is not set
CONFIG_BLUEZ_RFCOMM=y
CONFIG_BLUEZ_RFCOMM_TTY=y
CONFIG_BLUEZ_BNEP=y
CONFIG_BLUEZ_BNEP_MC_FILTER=y
CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
# CONFIG_BLUEZ_HIDP is not set
#
# Bluetooth device drivers
#
CONFIG_BLUEZ_HCIUSB=y
# CONFIG_BLUEZ_HCIUSB_SCO is not set
# CONFIG_BLUEZ_HCIUART is not set
# CONFIG_BLUEZ_HCIBFUSB is not set
# CONFIG_BLUEZ_HCIDTL1 is not set
# CONFIG_BLUEZ_HCIBT3C is not set
# CONFIG_BLUEZ_HCIBLUECARD is not set
# CONFIG_BLUEZ_HCIBTUART is not set
# CONFIG_BLUEZ_HCIVHCI is not set

device部分就設了個USB的,其他的就不設置了。
下面繼續make dep;make zImage的常規過程,OK,沒有發生編譯問題,可以稍微舒口氣了。

下面要移植Bluez的基礎庫了,在Redhat 9下執行
# ldd /usr/lib/libbluetooth.so.1.0.17
libc.so.6 => /lib/libc.so.6 (0x4002c000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)
發現沒有依賴什麼莫名其妙的庫,應該換個編譯器就可以了,configure一下就可以了。我的配置命令很簡單:
# ./configure --host=armv4l --prefix=/2410/applications/bluezport/libs CC=/opt/host/armv4l/bin/armv4l-unknown-linux-gcc CPP=/opt/host/armv4l/bin/armv4l-unknown-linux-cpp AR=/opt/host/armv4l/bin/armv4l-unknown-linux-ar STRIP=/opt/host/armv4l/bin/armv4l-unknown-linux-strip RANLIB=/opt/host/armv4l/bin/armv4l-unknown-linux-ranlib
LD=/opt/host/armv4l/bin/armv4l-unknown-linux-ld
# make
# make install
OK了,到了/2410/applications/bluezport/libs下看看,我也不清楚爲什麼,居然只有.a和.la的靜態庫,沒有動態庫。只好自己動手,到bluz-libs-2.17/src/下,自己編譯動態庫:
# /opt/host/armv4l/bin/armv4l-unknown-linux-gcc -shared -o libbluetooth.so.1.0.17 bluetooth.o hci.o sdp.o
再做兩個符號連接
# ln -s libbluetooth.so.1.0.17 libbluetooth.so
# ln -s libbluetooth.so.1.0.17 libbluetooth.so.1
好了,庫交*編譯完畢,mv到/2410/application/bluezport/libs/lib文件夾下就可以了。

接着移植Bluez的工具集。與庫類似,先看一下各個程序需要用到什麼庫,比如:
#ldd /usr/sbin/hcid
libbluetooth.so.1 => /usr/lib/libbluetooth.so.1 (0x40035000)
libc.so.6 => /lib/libc.so.6 (0x40042000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
挨個試試需要用的工具,發現需要的庫三星和Bluez都提供了,應該換個編譯器編譯一下就可以了。編譯之前我爲了到板子上與我自己的手機連接方便修改了 bluez-utils-2.17/hcid/security.c文件,在init_security_data函數中的設置默認的密碼,非常簡單地改了兩行:
strcpy(hcid.pin_code, "123");
hcid.pin_len = 3;
然後configure我想就行了,我的configure設置爲:
# ./configure --prefix=/S3C2410/applications/bluezport/utils --includedir=/S3C2410/applications/bluezport/libs/include --libdir=/S3C2410/applications/bluezport/libs/lib --with-bluez=/S3C2410/applications/bluezport/libs --disable-test --disable-cups --disable-pcmia --host=armv4l CC=/opt/host/armv4l/bin/armv4l-unknown-linux-gcc CPP=/opt/host/armv4l/bin/armv4l-unknown-linux-cpp AR=/opt/host/armv4l/bin/armv4l-unknown-linux-ar STRIP=/opt/host/armv4l/bin/armv4l-unknown-linux-strip RANLIB=/opt/host/armv4l/bin/armv4l-unknown-linux-ranlib LD=/opt/host/armv4l/bin/armv4l-unknown-linux-ld
# make
我在這步make的時候出現了一點小錯誤,好像是說PATH_MAX沒有定義,這個是LINUX設置的存放路徑名緩衝區的最大長度。應該是少包含了一個頭文件造成的。我沒有去仔細考究,就在當前文件下的config.h中添加了三行:
#ifndef PATH_MAX
#define PATH_MAX 4095/* PAGE_SIZE - 1 */
#endif
採用簡單粗魯的添加定義的方式。再make,通過。
# make install
好了,工具集都在/S3C2410/applications/bluezport/util下了
最 後,由於在PC的LINUX下的默認pin_helper /usr/bin/bluepin是用python寫的代碼,在2410上當然不能用了,所以要自己寫一個pin_helper的程序。翻翻 /usr/bin/bluepin的代碼以及hcid/security.c的代碼,事實上hcid進程在驗證PIN code的時候開了一個pipe指向pin_helper進程的標準輸出,pin_helper進程向用戶詢問PIN code,如果用戶輸入密碼XXXX就以"PIN:XXXX"的形式寫到標準輸出中去,如果用戶reject就寫個"ERR"回去。
我以一種最簡單的方式實現pin_helper程序,即固定地寫一個code回去,比如123,犧牲安全性。
用腳本實現就是:
#!/bin/sh

echo "PIN:123"
用C實現一個就是:
#include <stdio.h>

int main(int argc, char* argv[])
{
printf("PIN:123");
}
交*編譯成my_pin_helper再放到板子的/usr/bin下,那麼就可以把板子的hcid.conf修改成:
pin_helper /usr/pin/my_pin_helper
後來,我在板子上也用MiniGUI寫了一個pin_helper,也挺簡單的。
好了,一切準備完畢,做好ramdisk,記得在/dev下mknod幾個rfcomm,放到板子上,可以運行!
插上USB適配器,連模塊都不用probe
# hciconfig hci0 up
# hcid -f /etc/bluetooth/hcid.conf
# hciconfig -a
看到設備了,其他的運行都OK。結合ppp就可以用手機上網了~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章