【轉】BLE 學習記錄

原文網址:http://m.blog.csdn.net/blog/chiooo/43985401android

BLE 學習記錄

ANROID BLE 開發,基於 bluetoothlegatt 分析網絡

  1. mBluetoothAdapter = mBluetoothManager.getAdapter(); 獲得 手機上藍牙主機的適配器 mBluetoothAdapterasync

    public boolean initialize() { 
    // For API level 18 and above, get a reference to BluetoothAdapter through 
    // BluetoothManager. 
    if (mBluetoothManager == null) { 
    mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE); 
    if (mBluetoothManager == null) { 
    Log.e(TAG, 「Unable to initialize BluetoothManager.」); 
    return false; 

    }ide

    mBluetoothAdapter = mBluetoothManager.getAdapter();
    if (mBluetoothAdapter == null) {
        Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
        return false;
    }
    
    return true;

    }函數

2.得到mBluetoothGatt,註冊回調post

* Connects to the GATT server hosted on the Bluetooth LE device.
 *
 * @param address The device address of the destination device.
 *
 * @return Return true if the connection is initiated successfully. The connection result
 *         is reported asynchronously through the
 *         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
 *         callback.

public boolean connect(final String address) {
    if (mBluetoothAdapter == null || address == null) {
        Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
        return false;
    }

    // Previously connected device.  Try to reconnect.
    if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
            && mBluetoothGatt != null) {
        Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
        if (mBluetoothGatt.connect()) {
            return true;
        } else {
            return false;
        }
    }

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);  獲得bluetoothdevice
    if (device == null) {
        Log.w(TAG, "Device not found.  Unable to connect.");
        return false;
    }
    // We want to directly connect to the device, so we are setting the autoConnect
    // parameter to false.
    mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);//bluetoothdevice獲得mBluetoothGatt
傳進去的是 BluetoothGattCallback,從名字看就是回調。
    Log.d(TAG, "Trying to create a new connection.");
    mBluetoothDeviceAddress = address;
    return true;
}

3.讀寫BluetoothGattCharacteristic,使能notification學習

mBluetoothGatt.readCharacteristic(characteristic); 讀
mBluetoothGatt.writeCharacteristic(characteristic);  寫


 * Enables or disables notification on a give characteristic.
 *
 * @param characteristic Characteristic to act on.
 * @param enabled If true, enable notification.  False otherwise.

public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                          boolean enabled) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
}


向下寫數據:
//設置數據內容
                gattCharacteristic.setValue("send data->");
                //往藍牙模塊寫入數據
                mBLE.writeCharacteristic(gattCharacteristic); 
   讀數據:
    if(gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA)){                  
                //測試讀取當前Characteristic數據,會觸發mOnDataAvailable.onCharacteristicRead()
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mBLE.readCharacteristic(gattCharacteristic);
                    }
                }, 500);

                //接受Characteristic被寫的通知,收到藍牙模塊的數據後會觸發mOnDataAvailable.onCharacteristicWrite()
                mBLE.setCharacteristicNotification(gattCharacteristic, true);

4.獲得 supported services測試

* Retrieves a list of supported GATT services on the connected device. This should be
 * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
 *
 * @return A {@code List} of supported services.

public List<BluetoothGattService> getSupportedGattServices() {
    if (mBluetoothGatt == null) return null;

    return mBluetoothGatt.getServices();
}

5.關係ui

BluetoothGatt 表明一個鏈接,裏面包含一個或者多個 BluetoothGattService , 而每一個BluetoothGattService 包含多個BluetoothGattCharacteristic , 一個 BluetoothGattCharacteristic 裏面可能包含0個或者多個 BluetoothGattDescriptorgoogle

6.BLE 設備端LOG 
條件: 
主機端:BLEGATTLE 參考程序, 
設備端: NODIC官方BLE UART 程序

串口端LOG:

main start trace
uart_init
..\main.c:leds_init:137> enter_now
..\main.c:timers_init:149> enter_now
..\main.c:ble_stack_init:457> enter_now
..\main.c:gap_params_init:166> enter_now
Start...
..\main.c:advertising_start:331> enter_now
..\main.c:ble_evt_dispatch:442> enter_now
p_ble_evt->header.evt_id:16// connect event
p_ble_evt->header.evt_id:16 
p_ble_evt->header.evt_id:16 
..\main.c:ble_evt_dispatch:442> enter_now
p_ble_evt->header.evt_id:20 
p_ble_evt->header.evt_id:20// BLE_GAP_EVT_SEC_INFO_REQUEST
p_ble_evt->header.evt_id:20 
..\main.c:ble_evt_dispatch:442> enter_now
p_ble_evt->header.evt_id:19 
p_ble_evt->header.evt_id:19// BLE_GAP_EVT_SEC_PARAMS_REQUEST
p_ble_evt->header.evt_id:19 
..\main.c:ble_evt_dispatch:442> enter_now
p_ble_evt->header.evt_id:80  // write event
p_ble_evt->header.evt_id:80 
p_ble_evt->header.evt_id:80 
..\main.c:ble_evt_dispatch:442> enter_now
p_ble_evt->header.evt_id:80 // write event
p_ble_evt->header.evt_id:80 
..\main.c:nus_data_handler:224> enter_now
send data->                         // received data
p_ble_evt->header.evt_id:80     // write event
..\main.c:ble_evt_dispatch:442> enter_now
p_ble_evt->header.evt_id:24//   BLE_GAP_EVT_AUTH_STATUS
p_ble_evt->header.evt_id:24 
p_ble_evt->header.evt_id:24 
..\main.c:ble_evt_dispatch:442> enter_now
p_ble_evt->header.evt_id:23  //   BLE_GAP_EVT_AUTH_KEY_REQUEST
p_ble_evt->header.evt_id:23 
p_ble_evt->header.evt_id:23 
..\main.c:ble_evt_dispatch:442> enter_now
p_ble_evt->header.evt_id:18 
..\main.c:on_conn_params_evt:279> enter_now
p_ble_evt->header.evt_id:18   //  BLE_GAP_EVT_CONN_PARAM_UPDATE
p_ble_evt->header.evt_id:18

7.BLE鏈接參數

#define MIN_CONN_INTERVALMSEC_TO_UNITS(500, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.5 seconds). */6~3200, 就是說7.5MS~ 4S, 1.25MS單位。鏈接時間間隔。
#define MAX_CONN_INTERVALMSEC_TO_UNITS(1000, UNIT_1_25_MS)/**< Maximum acceptable connection interval (1 second). */ 
#define SLAVE_LATENCY0 跳過鏈接事件/**< Slave latency. */
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)  /**< Connection supervisory timeout (4 seconds). */  管理超時,若是超過此時間沒有鏈接成功事件,則認爲是鏈接丟失。

實驗驗證:

#define MIN_CONN_INTERVAL               16                                          /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
#define MAX_CONN_INTERVAL               500                                          /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
#define SLAVE_LATENCY                   0                                          /**< slave latency. */
#define CONN_SUP_TIMEOUT                2000                                         /**< Connection supervisory timeout (4 seconds), Supervision Timeout uses 10 ms units. */
#define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(20000, APP_TIMER_PRESCALER)  /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
#define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000, APP_TIMER_PRESCALER) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
#define MAX_CONN_PARAMS_UPDATE_COUNT    3

測試記錄:

當APP剛鏈接上時,這之間用得鏈接參數是由手機端決定的,通過FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS 後,手機端會發新的參數過來,我測試過的,手機端都是MAX_CONN_INTERVAL 來決定,SLAVE_LATENCY 無論我改爲多少,下發的都是0。

網絡上討論

  1. 對於IOS設備來講, 蘋果設置了一系列規定, 不容許從設備的配置超出這些範圍. 其餘主設備來講目前尚未據說有什麼具體範圍設定. Android設備目前google也尚未明確規定. 因此換句話說, 只要符合主設備的要求, 從設備是能夠在主設備規定的範圍內請求主設備對connection interval進行改變的.
  2. 你經過GAP_SetParamValue()只是設置了參數, 最後是須要經過發送到主設備那裏去請求修改的. 因此這裏不正確.請參考 GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, ..) 函數的作法.
  3. 你能夠經過packet sniffer抓包, 在時間戳上很清楚能看到connection interval. 或者你也能夠本身加點代碼, 從程序裏面獲取, 或者以notify方式發給主設備, 從主設備看, 總之, 方法不少哈. 
    另外附上蘋果對connection interval的要求, 其實還有其餘的鏈接參數要求, 好比slave latency, supervision timeout, 若是不知足這些, IOS設備會拒絕.

    The connection parameter request may be rejected if it does not comply with all of these rules: 
    Interval Max * (Slave Latency + 1) ≤ 2 seconds 
    Interval Min ≥ 20 ms 
    Interval Min + 20 ms ≤ Interval Max 
    Slave Latency ≤ 4 
    connSupervisionTimeout ≤ 6 seconds 
    Interval Max * (Slave Latency + 1) * 3 < connSupervisionTimeout

8.從設備怎麼主動斷開鏈接

你能夠直接調用 GAPRole_TerminateConnection() 來主動斷開鏈接。 那個函數調用後,鏈接順利斷開後會收到 GAP_LINK_TERMINATED_EVENT 事件。 在這個事件以後,你再從新啓動廣播,便可

相關文章
相關標籤/搜索