1. 程式人生 > >android5.1 藍芽子系統介紹(一)Android下bluedroid、bluetooth apk介紹

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