藍牙基本概念
兩種藍牙技術:Basic Rate (BR)和Low Energy(LE)
這兩種技術是不能互通的,也就是不能相互兼容。如果要確保和所有的藍牙設備互通,只能同時實現這兩種技術。
BR
Basic Rage是正宗的藍牙技術,包括可選的(optional)的EDR(Enhanced Data Rate)技術,以及Alternate(交替使用的)MAC層和PHY層擴展(簡稱AMP)。
LE
BR技術的進化路線,就是傳輸速率的加快。能量是守恆的,想要加快傳輸速率,代價就是要消耗更多的能量。再有些應用場景下,並不關心傳輸速率,反而關心功耗,這就是BLE產生的背景。
物理層
物理層負責提供數據傳輸的物理信道,藍牙的物理層分未Physical Channel 和Physiccal Links
Physical Channel
頻率範圍:2.400-2.4835GHz
BR/EDR物理信道定義:
1.ISM頻率範圍被分成79個Channel,每個Channel佔用1M的帶寬。在0 Channel和78 Channel設立gurad band(保護帶寬,Lower Guard Band爲2MHz,Upper Guard Band爲3.5MHz)
2.採用跳頻技術(hopping),也就是說摸一個物理信道並不是固定的佔用79個channel中的某一個,而是以一定的規律在跳動(該規律在技術上叫做“僞隨機碼”,就是假的隨機碼)。因此藍牙的物理信道也可以稱作跳頻信道(hopping channel);
3. BR/EDR技術定義了5種物理信道(跳頻信道),BR/EDR Basic Piconet Physical Channel(用於連接狀態的藍牙設備之間的通訊,使用全部79個頻點);BR/EDR Adapted Piconet Physical Channel(用於連接狀態下藍牙設備之間的通訊,使用79個跳頻點種的子集,但是跳頻數目不能少於20個);BR/EDR Page Scan Physical Channel(用於發現藍牙設備的發現操作Discovery);BR/EDR Inquriy Scan Physical Channel(用於藍牙設備的連接操作Connect);BR/EDR synchronization Scan Channel(用於無連接的廣播通訊).
4. 同一時刻,BT設備只能在其中一個物理信道上通信,爲了支持多個並行的操作,藍牙系統採用分時方式,即不同的時間點採用不同的信道
LE的物理信道定義:
1.ISM頻率範圍被分成40個channel,每個channel佔用2M的帶寬,在0channel和39channel之外設立guradband(保護帶寬,Lower Guard爲2MHz,Upper Guard Band爲3.5MHz)
2.LE技術定義了2種物理信道,LE Piconet channed(用於連接狀態的藍牙設備件的通訊,和BR/EDR一樣,採用調頻技術,但是只會在40個頻點種的37箇中進行跳頻)和LE advertisement Broadcast Channel(用於在設備間進行無連接的廣播通訊,這些廣播通信用於藍牙設備的返現,連接操作,亦可用於無連接的數據傳輸)
AMP爲高速數據傳輸設計的技術,其物理規範直接採用802.11的PHY規範,主要有如下特點:AMP物理信道只有一種,即AMP Physical Channel,主要用於已連接設備之間的數據通訊。
Physical Links(物理鏈路)
由上面的描述可知,藍牙協議爲BR/EDR, LE和AMP三種技術定義了8種類型的物理信道。物理鏈路是對這些物理信道的進一步封裝。
AMP Physical Channel /LE Piconet Channel/LE Advertisement Broadcast Channel均有一個對應的Physical Link,分別是Amp Physical Link/LE Active Physical Link/LE Advertising Physical Channel。
邏輯層
邏輯層的主要功能是再已連接的藍牙設備之間,基於物理鏈路,建立邏輯信道。
藍牙邏輯信道的劃分依據是傳輸類型,主要包含下面三類:
1.用於管理底層物理鏈路的控制類傳輸,包括AMP-C,ACL-C,PSB-C,LE-C,ADVB-C
2.傳輸用戶數據的用戶類傳輸,包括AMP-U,ACL-U,PSB-U,LE-U,ADVB-U
3.其他比較特殊的傳輸類型,包括流式傳輸stream,PBD(Profile Broadcast Data)
以上每種Logic Link都會在下層對應一個Logical Transport,這些Logical Transport具有一些屬性,如流控,應答,重傳機制等。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TTgSQloV-1587893425132)(./images/1573809760433.png)]
Android Bluetooth系統框圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mTyIIFJH-1587893425133)(./images/Bluetooth.png)]
com_android_bluetooth_btservice_AdapterService.cpp中的sBluetoothInterface對應下面文件
hardware/realtek/bluetooth/rtkbt/code/bluedroid/btif/src/bluetooth.c
藍牙源碼分析
typedef struct {
int cmd_fdr, cmd_fdw;//通過socketpair獲得
int poll_count;//記錄加入到poll中的fd個數,或者說是pollslot的個數
poll_slot_t ps[MAX_POLL];//最大值爲8,
int psi[MAX_POLL]; //index of poll slot
volatile pid_t thread_id;
btsock_signaled_cb callback;
btsock_cmd_cb cmd_callback;
int used; //標誌着這個thread slot有沒有被使用,最大值爲8
} thread_slot_t;
藍牙的構成
在android系統裏面,個人感覺是比較複雜的,起碼比無線複雜。下面就以amlogic sdk爲例來進行分析。總體來說,android中藍牙由以下部分組成:
1.libbt-vendor.so。這部分應該是由硬件決定的。比如說這個藍牙芯片是通過usb接入到主芯片還是通過uart接入到主芯片。這次代碼閱讀時通過uart的方式接入到主芯片的。代碼位置爲:hardware/realtek/bluetooth/rtkbt/code/libbt-vendor
2.bluetooth.default。這部分包含了藍牙協議部分;代碼位置爲:hardware/realtek/bluetooth/rtkbt/
3.Bluetooth.apk,通過jni與bluetooth.default進行數據的交換。代碼位置爲:packages/apps/Bluetooth。
4.Android System中藍牙有關的service & adapter。在打開藍牙時,將會通過AIDL(IBluetooth)連接上步中的Service。同時提供統一的api接口供apk進行調用;
5.Settings,也就是設置。在這部分主要是提供一個界面,供用戶進行操作。
隨手筆記
在設置中的藍牙部分的入口爲:BluetoothSettings.java.這部分主要就是對系統中的BluetoothAdapter進行了封裝,然後監聽藍牙的狀態進行更新以及負責ui部分的邏輯。這部分比較簡單就不進行源碼分析了
1.打開藍牙過程:
sequenceDiagram
BluetoothManagerService.java ->>BluetoothManagerService.java:handler send MESSAGE_ENABLE msg
BluetoothManagerService.java ->>BluetoothManagerService.java:handleEnable.bind service and call enable
BluetoothManagerService.java ->>AdapterService.java:enable()
AdapterService.java ->>AdapterState.java:handler send USER_TURN_ON msg
AdapterState.java ->> AdapterService.java:OffState call processStart
Note right of AdapterService.java:processStart 這個函數裏面啓動profile對應的service並且發送廣播,init jnicallback回調函數,
JniCallbacks.java ->> AdapterService.java:processProfileServiceStateChanged,
Note right of AdapterService.java:更新profile狀態,如果都啓動的話,啓動native 層
AdapterService.java ->> AdapterState.java:Handler 發送STARTED消息
AdapterState.java ->> AdapterService.java:enableNative
AdapterService.java->>com_android_bluetooth_btservice_AdapterService.cpp:JNI調用 enableNative
com_android_bluetooth_btservice_AdapterService.cpp ->> bluetooth.c:調用enable()
bluetooth.c ->> btif_core.c:btif_enable_bluetooth
btif_core.c ->> bte_main.c:bte_main_enable
Note right of bte_main.c:初始化hci,創建一個線程運行btu_task,這個task有兩個作用:1.初始話底層的一些協議:2.創建一個循環,讀取mbox中的消息進行處理
在這裏面需要注意的是,底層產生的信息是通過JniCallbacks這個java類進行反饋上來的。
關於藍牙硬件初始化的邏輯結構參考如下圖所示:
藍牙Discovery流程分析
BluetoothAdapter初始化分析
1.在Android中,對藍牙進行操作都是通過BluetoothAdapter進行的。那麼先看一下它的初始化函數
BluetoothAdapter.java
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);//獲得系統中的Bluetooth Manager Service
if (b != null) {
IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
sAdapter = new BluetoothAdapter(managerService);
} else {
Log.e(TAG, "Bluetooth binder is null");
}
}
return sAdapter;
}
/**
* Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
*/
BluetoothAdapter(IBluetoothManager managerService) {
if (managerService == null) {
throw new IllegalArgumentException("bluetooth manager service is null");
}
try {
mService = managerService.registerAdapter(mManagerCallback);//註冊callback函數,這裏需要注意的是返回的實際上是AdapterService代理。對藍牙的操作都是使用這個代理進行的。
} catch (RemoteException e) {Log.e(TAG, "", e);}
mManagerService = managerService;
mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
mHandler = new Handler(Looper.getMainLooper());
}
BluetoothManagerService.java
public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
//Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
//msg.obj = callback;
//mHandler.sendMessage(msg);
synchronized(mConnection) {
boolean added = mCallbacks.register(callback);
return mBluetooth;
}
}
private class BluetoothHandler extends Handler {
···
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
mBluetooth = IBluetooth.Stub.asInterface(service);
···
}
之前在介紹打開藍牙的分析中提到過,打開藍牙的時候Bind了AdapterService。從上面可以看出,BluetoothAdapter實際上是使用Bluetooth.apk中的AdapterService進行藍牙操作的。
下面言歸正傳,在Settings中的Bluetooth設置界面點擊搜索按鍵時就會按照下面的順序進行調用:
LocalBluetoothAdapter ->BluetoothAdapter ->AdapterService.下面就是調用native層中的startDiscoveryNative函數。
在JNI中 對應函數包含在文件:com_android_bluetooth_btservice_AdapterService.cpp中。
static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
ALOGV("%s:",__FUNCTION__);
jboolean result = JNI_FALSE;
if (!sBluetoothInterface) return result;
int ret = sBluetoothInterface->start_discovery();
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
在這個函數中涉及到的sBluetoothInterface就是藍牙構成裏面介紹的bluetooth.default的入口。
那麼bluetooth.default是如何加載的呢?
static void classInitNative(JNIEnv* env, jclass clazz) {
···
char value[PROPERTY_VALUE_MAX];
property_get("bluetooth.mock_stack", value, "");
const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID : BT_STACK_TEST_MODULE_ID);
err = hw_get_module(id, (hw_module_t const**)&module);//只是加載對應的庫文件
if (err == 0) {
hw_device_t* abstraction;
//實際上調的是Bluetooth.c中的open_bluetooth_stack
err = module->methods->open(module, id, &abstraction);
if (err == 0) {
bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction;
sBluetoothInterface = btStack->get_bluetooth_interface();
} else {
ALOGE("Error while opening Bluetooth library");
}
} else {
ALOGE("No Bluetooth Library found");
}
···
}
具體的是根據什麼去加載的細節問題這裏就不在詳細介紹了,就是根據name進行加載的。
那麼sBluetoothInterface對應的實現文件是bluetooth.c
繼續分析discovery流程
bluetooth.c
static int start_discovery(void)
{
/* sanity check */
if (interface_ready() == FALSE)
return BT_STATUS_NOT_READY;
return btif_dm_start_discovery();
}
bt_status_t btif_dm_start_discovery(void){
···
BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
···
}
void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{
tBTA_DM_API_SEARCH *p_msg;
if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
{
memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));
p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
p_msg->services = services;
p_msg->p_cback = p_cback;
p_msg->rs_res = BTA_DM_RS_NONE;
bta_sys_sendmsg(p_msg);
}
}
看到就是填充一個信息相關的機構,表明事件類型爲BTA_DM_API_SEARCH_EVT,之後發送這個消息。
這裏面就涉及到了藍牙中的消息是如何循環處理的問題了。這部分還是有點複雜,後面有時間再寫出來分析。
總之會根據調用到bta_dm_act.c中的bta_dm_search_start函數。
void bta_dm_search_start (tBTA_DM_MSG *p_data){
···
result.status = BTM_StartInquiry( (tBTM_INQ_PARMS*)&p_data->search.inq_params,
bta_dm_inq_results_cb,
(tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb);
···
}
btm_inq.c
tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
tBTM_CMPL_CB *p_cmpl_cb){
···
else if ((status = btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
p_inqparms->duration)) != BTM_CMD_STARTED)
{
···
}
btm_ble_gap.c
tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration){
···
if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE))
···
}
hciblecmds.c
BOOLEAN btsnd_hcic_ble_set_scan_enable (UINT8 scan_enable, UINT8 duplicate)
{
BT_HDR *p;
UINT8 *pp;
if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE)) == NULL)
return (FALSE);
pp = (UINT8 *)(p + 1);
p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE;
p->offset = 0;
UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_ENABLE);
UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE);
UINT8_TO_STREAM (pp, scan_enable);
UINT8_TO_STREAM (pp, duplicate);
btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
return (TRUE);
}
void btu_hcif_send_cmd (UINT8 controller_id, BT_HDR *p_buf){
···
HCI_CMD_TO_LOWER(p_buf);
···
}
這個宏定義爲:
#define HCI_CMD_TO_LOWER(p) bte_main_hci_send((BT_HDR *)(p), BT_EVT_TO_LM_HCI_CMD)
bte_main.c
void bte_main_hci_send (BT_HDR *p_msg, UINT16 event){
···
if (bt_hc_if)
bt_hc_if->transmit_buf((TRANSAC)p_msg, \
(char *) (p_msg + 1), \
p_msg->len);
···
}
transmit_buf這個函數實際上就是動用了uart的寫入函數,將數據寫入到節點中。至此discover命令的發送就結束了。
歡迎使用 {小書匠}(xiaoshujiang)編輯器,您可以通過 小書匠主按鈕>模板
裏的模板管理來改變新建文章的內容。