【转】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 事件。 在这个事件以后,你再从新启动广播,便可

相关文章
相关标签/搜索