android5.1 藍芽子系統介紹(一)Android下bluedroid、bluetooth apk介紹
前言
本文件主要介紹android平臺下bluetooth的應用層軟體,先介紹bluetooth應用層的框架,接著分別介紹Bluedroid層軟體、Bluetooth應用程式(Bluetooth.apk),Bluetooth framework層,最後完整分析一些藍芽的操作流程。基於android 5.1的平臺,涉及的bluetooth硬體為realtek的藍芽。文件主要針對藍芽的初學者,提供基礎的學習指導。
1 Bluetooth應用層框架介紹
要介紹android平臺bluetooth應用層的軟體,首先介紹一下bluetooth的應用層整體框架,如圖1為android下的bluetooth的框架。
圖1 bluetooth應用層框架
Applications:Android藍芽應用程式,就是使用藍芽的API的程式;
java Framework:提供給應用使用的API,我們平時使用的BluetoothAdapter,BluetoothDevice,BluetoothSocket等;
BluetoothAPP:這個應該也是屬於java framework範疇,不過由於它比較特殊,所以獨立出來,提供所有的上層服務以及與Bluedroid底層進行互動。其中btAdapter主要提供藍芽的基本操作,比如enable, disable, discovery, pair, unpair, createRfcomm等,其他的就都是Profile的各自的Service了;
Bluedroid:藍芽協議棧,提供所有藍芽的實際操作,開關藍芽,藍芽的管理,搜尋管理,鏈路管理,各種profile的實現,包括HCI,ACL,SCO,L2CAP,各種profile等;
這裡Bluedroid分為三部分:
BTIF(Bluetooth Interface):提供所有Bluetooth.apk需要的API(使用HAL)
BTA(Bluetooth Application):藍芽應用,一般指藍芽的Profile的Bluedroid實現。
Stack:實現所有藍芽底層的操作,其中還要分為btm(Bluetooth manager),btu(Bluetooth Upper Layer)等。
2 Bluedroid軟體介紹
在第一節的bluetooth應用層框架圖中,已可看到bluedroid的一個架構,但bluedroid與底層的介面就沒表示出來。圖2為bluedroid各層互動的框架圖。
圖2 bluedroid框架圖
下面再看一下bluedroid下的目錄結構及每個目錄的功能。
圖3 bluedroid目錄結構
audio_a2dp_hw: Implements hal for bluedroid a2dp audio device。 a2dp在bluedroid中的hal層實現。它通過socket與stack通訊(通訊機制實現參考udv目錄下的uipc);
bta:buetooth application layer,實現應用層的一些介面,但都由Btif層進行管理和呼叫。
Ag:audio gateway (AG) subsystem of BTA
Ar:implementation for the audio/video registration module.
Av:implementation of the API for the advanced audio/video (AV)
* subsystem of BTA, Broadcom’s Bluetooth application layer for mobile
* phones.
Dm:API implementation file for the BTA device manager
Fs: implementation file for the file system call-in functions. //phone
Gattr: the GATT server and client implementation
Hh:host hid
btif:all BTIF functions accessed from main bluetooth HAL(與android的Bluetooth apk的jni層通訊的介面,真正的為app提供interface的介面);
conf:是Bluedroid的一些配置檔案;
embdrv: 主要負責sbc編碼,SBC是由藍芽特別興趣組(SIG)提出的一種用於藍芽裝置標準音頻編解碼器的高效編碼方法。在藍芽技術的A2DP的音訊資料規格中,SBC是用來保持互連能力的一個十分重要的音訊資料編碼方法,它是MP3和MPEG-4 AAC的規定選項;
gki/osi:general kernel interface/os interface,針對os的移植層,包括多工和timer實現,實際就是為stack程式碼提供一個抽象的多工和時間控制環境,達到可移植的目的;
hci:host control interface,實現hci的協議,並連線stack層與底層通訊的實現;
main:處理配置資訊,各個模組的初始化,連線btif與hci,提供btif控制hci的介面;
stack: 協議棧程式碼,各種profile;
udrv:程式碼作用是跟a2dp端進行socket通訊,處理命令和a2dp資料pcm流,media task呼叫這裡的介面,實際就是跟audio_a2dp_hw 的audio hal通訊;
utils:雜項,很簡單,目前就是提高a2dp任務優先順序的函式;
vnd: vendor specific feature for BLE;
其中還有一個bt vendor沒包含在bluedroid中,對於realtek的藍芽,都是使用相同的bluedroid,但不同的藍芽模組有不同的bt vendor庫,該vendor庫的功能是給藍芽模組上、掉電,開啟、關閉、配置串列埠,download fw(usb介面藍芽的download fw在驅動內實現)。
2.1 Bluedroid對上層介面
Bluedroid與上層有多個介面, bluedroid\btif\src\bluetooth.c為一個主要介面,負責藍芽的開關及基本控制, bluedroid\audio_a2dp_hw\audio_a2dp_hw.c專門針對a2dp的控制,還有部分profile也提供一些介面,這些介面為不同profile的獨立介面。其中bluetooth.c實現一系列介面,由上層呼叫來控制藍芽,同時在初始化的時候,上層會傳遞過來一個回撥介面,當bluedroid有訊息或結果需要通知上層時,就通過該回調介面。但像藍芽的opp、hid等profile的資料就不是通過介面傳遞的,都是建立socket介面來互動資料的。
\bluedroid\btif\src\bluetooth.c
static const bt_interface_t bluetoothInterface = {
sizeof(bluetoothInterface),
init,
enable,
disable,
get_recv_byte,
get_send_byte,
cleanup,
get_adapter_properties,
get_adapter_property,
set_adapter_property,
get_remote_device_properties,
get_remote_device_property,
set_remote_device_property,
get_remote_service_record,
get_remote_services,
start_discovery,
cancel_discovery,
create_bond,
remove_bond,
cancel_bond,
get_connection_state,
pin_reply,
ssp_reply,
get_profile_interface,
dut_mode_configure,
dut_mode_send,
#if BLE_INCLUDED == TRUE
le_test_mode,
#else
NULL,
#endif
config_hci_snoop_log,
set_os_callouts,
read_energy_info,
};
hardware\libhardware\include\hardware\bluetooth.h
typedef struct { /* 藍芽介面結構體定義 */
/** set to sizeof(bt_interface_t) */
size_t size;
/**
* Opens the interface and provides the callback routines
* to the implemenation of this interface.
*/
int (*init)(bt_callbacks_t* callbacks );
/** Enable Bluetooth. */
int (*enable)(void);
/** Disable Bluetooth. */
int (*disable)(void);
/** Get Bluetooth recv */
int (*get_recv_byte)(void);
…… /* 省略中間程式碼 */
int (*read_energy_info)();
} bt_interface_t;
\bluedroid\btif\src\bluetooth.c
static int init(bt_callbacks_t* callbacks ) /* 初始化時,上層傳遞下來的回撥介面結構體 */
{
ALOGI(“init”);
/* sanity check */
if (interface_ready() == TRUE)
return BT_STATUS_DONE;
/* store reference to user callbacks */
Bt_hal_cbacks = callbacks;
/* add checks for individual callbacks ? */
bt_utils_init();
/* init btif */
btif_init_bluetooth();
return BT_STATUS_SUCCESS;
}
hardware\libhardware\include\hardware\bluetooth.h
/** Bluetooth DM callback structure. */ /* 回撥結構體 */
typedef struct {
/** set to sizeof(bt_callbacks_t) */
size_t size;
adapter_state_changed_callback adapter_state_changed_cb;
adapter_properties_callback adapter_properties_cb;
remote_device_properties_callback remote_device_properties_cb;
device_found_callback device_found_cb;
discovery_state_changed_callback discovery_state_changed_cb;
pin_request_callback pin_request_cb;
ssp_request_callback ssp_request_cb;
bond_state_changed_callback bond_state_changed_cb;
acl_state_changed_callback acl_state_changed_cb;
callback_thread_event thread_evt_cb;
dut_mode_recv_callback dut_mode_recv_cb;
le_test_mode_callback le_test_mode_cb;
energy_info_callback energy_info_cb;
} bt_callbacks_t;
其中在get_profile_interface函式中會返回各種profile提供的介面。
\bluedroid\btif\src\bluetooth.c
static const void* get_profile_interface (const char *profile_id)
{
ALOGI("get_profile_interface %s", profile_id);
/* sanity check */
if (interface_ready() == FALSE)
return NULL;
/* check for supported profile interfaces */
if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
return btif_hf_get_interface();
if (is_profile(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID))
return btif_hf_client_get_interface();
if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID)) /* rfcomm使用 */
return btif_sock_get_interface();
if (is_profile(profile_id, BT_PROFILE_PAN_ID))
return btif_pan_get_interface();
if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
return btif_av_get_src_interface();
if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_SINK_ID))
return btif_av_get_sink_interface();
if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
return btif_hh_get_interface();
if (is_profile(profile_id, BT_PROFILE_HEALTH_ID))
return btif_hl_get_interface();
if (is_profile(profile_id, BT_PROFILE_MAP_CLIENT_ID))
return btif_mce_get_interface();
#if ( BTA_GATT_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
if (is_profile(profile_id, BT_PROFILE_GATT_ID))
return btif_gatt_get_interface();
#endif
if (is_profile(profile_id, BT_PROFILE_AV_RC_ID))
return btif_rc_get_interface();
if (is_profile(profile_id, BT_PROFILE_AV_RC_CTRL_ID))
return btif_rc_ctrl_get_interface();
return NULL;
}
下面為使用rfcomm通訊時的使用的介面:
\bluedroid\btif\src\btif_sock.c
static btsock_interface_t sock_if = {
sizeof(sock_if),
btsock_listen,
btsock_connect
};
btsock_interface_t *btif_sock_get_interface()
{
return &sock_if;
}
audio_a2dp_hw.c的介面就沒有看到回撥函式,但audio_a2dp_hw.c中建立了2個socket介面,一個用於控制命令,一個用於a2dp資料的傳輸。
\bluedroid\audio_a2dp_hw\audio_a2dp_hw.c
static int adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
…… /* 省略中間程式碼 */
adev->device.get_parameters = adev_get_parameters;
adev->device.get_input_buffer_size = adev_get_input_buffer_size;
adev->device.open_output_stream = adev_open_output_stream;
adev->device.close_output_stream = adev_close_output_stream;
adev->device.open_input_stream = adev_open_input_stream;
adev->device.close_input_stream = adev_close_input_stream;
adev->device.dump = adev_dump;
…… /* 省略中間程式碼 */
static struct hw_module_methods_t hal_module_methods = {
.open = adev_open,
};
struct audio_module HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = AUDIO_HARDWARE_MODULE_ID,
.name = "A2DP Audio HW HAL",
.author = "The Android Open Source Project",
.methods = &hal_module_methods,
},
};
\bluedroid\audio_a2dp_hw\audio_a2dp_hw.c
static int adev_open_input_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
struct audio_config *config,
struct audio_stream_in **stream_in,
audio_input_flags_t flags __unused,
const char *address __unused,
audio_source_t source __unused)
{
…… /* 省略中間程式碼 */
in->stream.common.set_parameters = in_set_parameters;
in->stream.common.get_parameters = in_get_parameters;
in->stream.common.add_audio_effect = in_add_audio_effect;
in->stream.common.remove_audio_effect = in_remove_audio_effect;
in->stream.set_gain = in_set_gain;
in->stream.read = in_read; /* 該函式會開啟data socket */
in->stream.get_input_frames_lost = in_get_input_frames_lost;
/* initialize a2dp specifics */
a2dp_stream_common_init(&in->common);
*stream_in = &in->stream;
a2dp_dev->input = in;
a2dp_open_ctrl_path(&in->common);
\bluedroid\audio_a2dp_hw\audio_a2dp_hw.c
static void a2dp_open_ctrl_path(struct a2dp_stream_common *common)
{
int i;
/* retry logic to catch any timing variations on control channel */
for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++)
{
/* connect control channel if not already connected */
if ((common->ctrl_fd = skt_connect(A2DP_CTRL_PATH, common->buffer_sz)) > 0)
{
\bluedroid\audio_a2dp_hw\audio_a2dp_hw.c
static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
size_t bytes)
{
…… /* 省略中間程式碼 */
/* only allow autostarting if we are in stopped or standby */
if ((in->common.state == AUDIO_A2DP_STATE_STOPPED) ||
(in->common.state == AUDIO_A2DP_STATE_STANDBY))
{
pthread_mutex_lock(&in->common.lock);
if (start_audio_datapath(&in->common) < 0)
\bluedroid\audio_a2dp_hw\audio_a2dp_hw.c
static int start_audio_datapath(struct a2dp_stream_common *common)
{
…… /* 省略中間程式碼 */
/* connect socket if not yet connected */
if (common->audio_fd == AUDIO_SKT_DISCONNECTED)
{
common->audio_fd = skt_connect(A2DP_DATA_PATH, common->buffer_sz);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
2.2 Bluedroid中HCI層介面
Hci層處於bluedroid架構的最下面,向下與bt-vendor、核心互動,向上與bluedroid核心層互動。
2.2.1 Bluedroid中HCI與bt-vendor介面
Bluedroid與下層的互動介面全由hci目錄的程式碼實現,在vendor.c檔案中載入bt-vendor庫,使用bt-vendor提供的介面,並把一個回撥結構體傳遞給bt-vendor。
\bluedroid\hci\src\vendor.c
static const char *VENDOR_LIBRARY_NAME = "libbt-vendor.so"; /* 固定的bt-vendor庫名 */
bool vendor_open(const uint8_t *local_bdaddr) {
assert(lib_handle == NULL);
lib_handle = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
if (!lib_handle) {
ALOGE("%s unable to open %s: %s", __func__, VENDOR_LIBRARY_NAME, dlerror());
goto error;
}
vendor_interface = (bt_vendor_interface_t *)dlsym(lib_handle, VENDOR_LIBRARY_SYMBOL_NAME);
if (!vendor_interface) {
ALOGE("%s unable to find symbol %s in %s: %s", __func__, VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
goto error;
}
/* 呼叫bt-vendor的初始化並傳遞迴調結構體 */
int status = vendor_interface->init(&vendor_callbacks, (unsigned char *)local_bdaddr);
\bluedroid\hci\include\bt_vendor_lib.h
typedef struct { /* bt-vendor提供的3個介面 */
/** Set to sizeof(bt_vndor_interface_t) */
size_t size;
/**
* Caller will open the interface and pass in the callback routines
* to the implemenation of this interface.
*/
int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr);
/** Vendor specific operations */
int (*op)(bt_vendor_opcode_t opcode, void *param);
/** Closes the interface */
void (*cleanup)(void);
} bt_vendor_interface_t;
\bluedroid\hci\src\vendor.c
static const bt_vendor_callbacks_t vendor_callbacks = { /* hci傳遞給bt-vendor的回撥結構體 */
sizeof(vendor_callbacks),
firmware_config_cb,
sco_config_cb,
low_power_mode_cb,
sco_audiostate_cb,
buffer_alloc,
buffer_free,
transmit_cb,
epilog_cb
};
Bt-vendor庫中,init和cleanup函式只是做開始時初始化及退出時清理的工作,主要工作都在op函式中實現。
\modules\rtl8723bs\libbt\src\bt_vendor_rtk.c
static int op(bt_vendor_opcode_t opcode, void *param)
{
switch(opcode)
{
case BT_VND_OP_POWER_CTRL:
…… /* 省略中間程式碼 */ /* 控制藍芽模組的上掉電 */
break;
case BT_VND_OP_FW_CFG:
/* uart介面藍芽載入fw */
/* usb介面藍芽fw在驅動中載入,藍芽上電時就自動載入,這裡直接返回成功 */
…… /* 省略中間程式碼 */
break;
case BT_VND_OP_SCO_CFG:
…… /* 省略中間程式碼 */
break;
case BT_VND_OP_USERIAL_OPEN:
/* 開啟uart口,把開啟的fd傳回給hci層。無論是uart介面藍芽,還是usb介面藍芽(usb介面藍芽在驅動層虛擬出一個uart口),對bt-vendor層都是開啟一個串列埠,所以從bluedroid層看,與底層的資料收發就是對uart口的收發 */
…… /* 省略中間程式碼 */
break;
case BT_VND_OP_USERIAL_CLOSE:
…… /* 省略中間程式碼 */ /* 關閉uart口 */
break;
case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
…… /* 省略中間程式碼 */
break;
case BT_VND_OP_LPM_SET_MODE:
…… /* 省略中間程式碼 */
break;
case BT_VND_OP_LPM_WAKE_SET_STATE:
…… /* 省略中間程式碼 */
break;
case BT_VND_OP_EPILOG:
…… /* 省略中間程式碼 */
break;
}
\bluedroid\hci\src\userial.c
bool userial_open(userial_port_t port) {
/* hci層呼叫bt-vendor層開啟uart口,返回uart口控制代碼,hci層對資料的收發就使用該控制代碼 */
…… /* 省略中間程式碼 */
int num_ports = vendor_send_command(BT_VND_OP_USERIAL_OPEN, &fd_array);
if (num_ports != 1) {
ALOGE("%s opened wrong number of ports: got %d, expected 1.", __func__, num_ports);
goto error;
}
userial_cb.fd = fd_array[0];
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
2.2.2 Bluedroid中HCI層協議
Hci層有兩個功能,一個為實現hci層協議,就是所見的h4、h5協議,另一個為連線stack層與bt-vendor層,實現stack層與硬體的通訊傳遞。
HCI有4種分組型別(有資料介紹通過uart傳輸時,還有錯誤訊息分組和協商分組,但從現在的程式碼看,都沒有使用了,只是增加了廠商自定義的操作碼,用於傳送錯誤訊息或協商通訊等),分組型別如表1,4種分組的資料格式如圖4~圖7。
表1 HCI封包型別
HCI本身的分組是不帶包型別識別頭的,在傳輸的時候就需要雙方能識別出傳輸的分組型別,h4的協議就是在hci分組前增加一個位元組的用於區別分組型別,現在使用的boardcom的藍芽就是使用h4協議通過uart傳輸。從上面的各種分組結構看,都沒有唯一的識別標誌,在通過uart傳輸時,由於共用一個通道,就有資料同步問題,否則就無法找到分組頭及解析資料分組。所以h4協議使用uart傳輸時,就需要有Error Recovery機制,只要通訊雙方有一個丟失同步,就需要進行同步恢復。如果h4協議使用usb傳輸,就不會存在該問題,usb通過不同的端點傳輸不同的分組型別,並且usb協議可以保證分組的完整。由於h4使用uart傳輸存在同步問題,後面有了h5協議,h5協議其實就是把h4協議的包重新封裝一下,加入字元轉換來實現唯一的分組頭、分組尾標識,同時加入完整性校驗,這樣,即使一個分組資料出錯了,下一個分組資料還是能正確解析的,不需要什麼同步恢復機制。H5的封包如圖8~圖10。
從上面可以看出,H5協議比H4協議在可靠性方面有增強,但同時需要處理的工作量也增多了,所以H5的傳輸效率會比H4低一些。
H4或H5的協議都提供相同的使用介面,HCI層實際使用哪種協議,現在bluedroid的做法是在程式碼編譯的時候就固定的,如下面程式碼所示。
\bluedroid\hci\src\bt_hci_bdroid.c
static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
{
…… /* 省略中間程式碼 */
vendor_open(local_bdaddr); /* 載入bt-vendor庫 */
utils_init();
#ifdef HCI_USE_MCT
extern tHCI_IF hci_mct_func_table;
p_hci_if = &hci_mct_func_table;
#elif defined HCI_USE_RTK_H5
extern tHCI_IF hci_h5_func_table;
p_hci_if = &hci_h5_func_table; /* 使用h5協議 */
#else
extern tHCI_IF hci_h4_func_table;
p_hci_if = &hci_h4_func_table; /* 使用h4協議 */
#endif
\bluedroid\hci\include\hci.h
typedef struct { /* h4,h5的結構體 */
tHCI_INIT init;
tHCI_CLEANUP cleanup;
tHCI_SEND send; /* 傳送介面 */
tHCI_SEND_INT send_int_cmd; /* 為廠商專用傳送介面 */
tHCI_ACL_DATA_LEN_HDLR get_acl_max_len;
#ifdef HCI_USE_MCT
tHCI_RCV evt_rcv;
tHCI_RCV acl_rcv;
#else
tHCI_RCV rcv; /* 接收介面 */
#endif
} tHCI_IF;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
2.2.3 Bluedroid中HCI與核心層介面
Hci層與bluedroid的核心層的互動介面,也是通過把介面封裝在一個結構體提供給核心層,同時核心層提供一個回撥的結構體。
\bluedroid\hci\src\bt_hci_bdroid.c
static const bt_hc_interface_t bluetoothHCLibInterface = {
sizeof(bt_hc_interface_t),
init, /* 載入bt-vendor庫,選擇使用的hci層協議 */
set_power, /* 藍芽上掉電控制 */
lpm,
preload, /* 開啟uart,載入fw */
postload,
transmit_buf, /* 傳送資料 */
logging,
cleanup,
tx_hc_cmd,
};
const bt_hc_interface_t *bt_hc_get_interface(void) /* 獲取hci介面的結構體 */
{
return &bluetoothHCLibInterface;
}
\bluedroid\main\bte_main.c
static void bte_main_in_hw_init(void)
{
if ( (bt_hc_if = (bt_hc_interface_t *) bt_hc_get_interface()) \
== NULL)
…… /* 省略中間程式碼 */
static void bte_hci_enable(void)
{
APPL_TRACE_DEBUG("%s", __FUNCTION__);
preload_start_wait_timer();
if (bt_hc_if)
{
/* 初始化hci介面,傳遞迴調結構體 */
int result = bt_hc_if->init(&hc_callbacks, btif_local_bd_addr.address);
\bluedroid\hci\include\bt_hci_lib.h
typedef struct {
/** set to sizeof(bt_hc_callbacks_t) */
size_t size;
/* notifies caller result of preload request */
preload_result_cb preload_cb;
/* notifies caller result of postload request */
postload_result_cb postload_cb;
/* notifies caller result of lpm enable/disable */
lpm_result_cb lpm_cb;
/* notifies hardware on host wake state */
hostwake_ind_cb hostwake_ind;
/* buffer allocation request */
alloc_mem_cb alloc;
/* buffer deallocation request */
dealloc_mem_cb dealloc;
/* notifies stack data is available */
data_ind_cb data_ind; /* hci層往上提交資料介面 */
/* notifies caller when a buffer is transmitted (or failed) */
tx_result_cb tx_result;
} bt_hc_callbacks_t;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
2.2.4 Bluedroid中HCI層流程例子
如圖11為HCI層初始化的流程,包含介面的初始化,給藍芽上電,開啟串列埠,載入fw,由於載入fw過程涉及多重回調,沒放到下面的框圖。
2.3 Bluedroid的核心層
Bluedroid的核心層負責藍芽的管理,藍芽協議的處理,狀態的管理等,整個核心層的執行都是由事件驅動的,由上層傳送的事件,底層處理結果的事件,底層接收資料的事件,底層狀態變化的事件,加上定時器的超時事件,維護著整個核心層的正常執行。由於藍芽核心層還不能很好理清流程及整理一個直觀的框圖,這裡沒給出核心層的架構圖,後面從程式碼流程及整體的執行流程從側面瞭解一下核心層的架構。
2.3.1 Bluedroid核心層的啟動
Bluedroid的整個功能及執行,都是從enable Bluetooth開始,到disable Bluetooth結束。
\bluedroid\btif\src\bluetooth.c
static int init(bt_callbacks_t* callbacks )
{
…… /* 省略中間程式碼 */
bt_utils_init();
/* init btif */
btif_init_bluetooth();
return BT_STATUS_SUCCESS;
}
\bluedroid\btif\src\btif_core.c
bt_status_t btif_init_bluetooth()
{
UINT8 status;
btif_config_init(); /* 配置初始化 */
bte_main_boot_entry(); /* Entry point for BTE chip/stack initialization */
/* As part of the init, fetch the local BD ADDR */
memset(&btif_local_bd_addr, 0, sizeof(bt_bdaddr_t));
btif_fetch_local_bdaddr(&btif_local_bd_addr);
/* start btif task */
status = GKI_create_task(btif_task, BTIF_TASK, BTIF_TASK_STR,
(UINT16 *) ((UINT8 *)btif_task_stack + BTIF_TASK_STACK_SIZE),
sizeof(btif_task_stack));
if (status != GKI_SUCCESS)
return BT_STATUS_FAIL;
return BT_STATUS_SUCCESS;
}
\bluedroid\btif\src\bluetooth.c
static int enable( void )
{
ALOGI("enable");
/* sanity check */
if (interface_ready() == FALSE)
return BT_STATUS_NOT_READY;
return btif_enable_bluetooth();
}
\bluedroid\btif\src\btif_core.c
bt_status_t btif_enable_bluetooth(void)
{
…… /* 省略中間程式碼 */
/* Create the GKI tasks and run them */
bte_main_enable();
return BT_STATUS_SUCCESS;
}
\bluedroid\main\bte_main.c
void bte_main_enable()
{
APPL_TRACE_DEBUG("%s", __FUNCTION__);
/* Initialize BTE control block */
BTE_Init();
lpm_enabled = FALSE;
GKI_create_task((TASKPTR)btu_task, BTU_TASK, BTE_BTU_TASK_STR,
(UINT16 *) ((UINT8 *)bte_btu_stack + BTE_BTU_STACK_SIZE),
sizeof(bte_btu_stack));
bte_hci_enable(); /* 初始化hci層介面,上一節內容 */
GKI_run();
}
\bluedroid\stack\btu\btu_task.c
BTU_API UINT32 btu_task (UINT32 param) /* 初始化工作及進行訊息處理 */
{
…… /* 省略中間程式碼 */
/* Initialize the mandatory core stack control blocks
(BTU, BTM, L2CAP, and SDP)
*/
btu_init_core();
/* Initialize any optional stack components */
BTE_InitStack();
#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
bta_sys_init();
#endif
/* Initialise platform trace levels at this point as BTE_InitStack() and bta_sys_init()
* reset the control blocks and preset the trace level with XXX_INITIAL_TRACE_LEVEL
*/
#if ( BT_USE_TRACES==TRUE )
BTE_InitTraceLevels();
#endif
/* Send a startup evt message to BTIF_TASK to kickstart the init procedure */
GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT);
prctl(PR_SET_NAME, (unsigned long)"BTU TASK", 0, 0, 0);
raise_priority_a2dp(TASK_HIGH_BTU);
/* Wait for, and process, events */
for (;;)
\bluedroid\btif\src\btif_core.c
void btif_enable_bluetooth_evt(tBTA_STATUS status, BD_ADDR local_bd)
{ /* Bluetooth enable完成時收到事件,會呼叫該函式 */
…… /* 省略中間程式碼 */
bte_main_postload_cfg();
#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
bte_main_enable_lpm(TRUE);
#endif
/* add passing up bd address as well ? */
/* callback to HAL */
if (status == BTA_SUCCESS)
{
/* initialize a2dp service */
btif_av_init();
/* init rfcomm & l2cap api */
btif_sock_init();
/* init pan */
btif_pan_init();
/* load did configuration */
bte_load_did_conf(BTE_DID_CONF_FILE);
\bluedroid\btif\src\btif_av.c
bt_status_t btif_av_init()
{
if (btif_av_cb.sm_handle == NULL)
{
if (btif_a2dp_start_media_task() != GKI_SUCCESS)
return BT_STATUS_FAIL;
btif_enable_service(BTA_A2DP_SERVICE_ID);
/* Also initialize the AV state machine */
btif_av_cb.sm_handle = btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
btif_a2dp_on_init();
\bluedroid\btif\src\btif_media_task.c
int btif_a2dp_start_media_task(void)
{
…… /* 省略中間程式碼 */
/* start a2dp media task */
retval = GKI_create_task((TASKPTR)btif_media_task, A2DP_MEDIA_TASK,
A2DP_MEDIA_TASK_TASK_STR,
(UINT16 *) ((UINT8 *)a2dp_media_task_stack + A2DP_MEDIA_TASK_STACK_SIZE),
sizeof(a2dp_media_task_stack));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100