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

BLE 学习记录

ANROID BLE 开发,基于 bluetoothlegatt 分析

  1. mBluetoothAdapter = mBluetoothManager.getAdapter(); 得到 手机上蓝牙主机的适配器 mBluetoothAdapter

    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; 

    }

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

    }

2.获得mBluetoothGatt,注册回调

 * 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.关系

BluetoothGatt 代表一个连接,里面包含一个或者多个 BluetoothGattService , 而每个BluetoothGattService 包含多个BluetoothGattCharacteristic , 一个 BluetoothGattCharacteristic 里面可能包含0个或者多个 BluetoothGattDescriptor

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 事件。 
在这个事件之后,你再重新启动广播,即可

【转】BLE 学习记录的更多相关文章

  1. Quartz 学习记录1

    原因 公司有一些批量定时任务可能需要在夜间执行,用的是quartz和spring batch两个框架.quartz是个定时任务框架,spring batch是个批处理框架. 虽然我自己的小玩意儿平时不 ...

  2. Java 静态内部类与非静态内部类 学习记录.

    目的 为什么会有这篇文章呢,是因为我在学习各种框架的时候发现很多框架都用到了这些内部类的小技巧,虽然我平时写代码的时候基本不用,但是看别人代码的话至少要了解基本知识吧,另外到底内部类应该应用在哪些场合 ...

  3. Apache Shiro 学习记录4

    今天看了教程的第三章...是关于授权的......和以前一样.....自己也研究了下....我觉得看那篇教程怎么说呢.....总体上是为数不多的精品教程了吧....但是有些地方确实是讲的太少了.... ...

  4. UWP学习记录12-应用到应用的通信

    UWP学习记录12-应用到应用的通信 1.应用间通信 “共享”合约是用户可以在应用之间快速交换数据的一种方式. 例如,用户可能希望使用社交网络应用与其好友共享网页,或者将链接保存在笔记应用中以供日后参 ...

  5. UWP学习记录11-设计和UI

    UWP学习记录11-设计和UI 1.输入和设备 通用 Windows 平台 (UWP) 中的用户交互组合了输入和输出源(例如鼠标.键盘.笔.触摸.触摸板.语音.Cortana.控制器.手势.注视等)以 ...

  6. UWP学习记录10-设计和UI之控件和模式7

    UWP学习记录10-设计和UI之控件和模式7 1.导航控件 Hub,中心控件,利用它你可以将应用内容整理到不同但又相关的区域或类别中. 中心的各个区域可按首选顺序遍历,并且可用作更具体体验的起始点. ...

  7. UWP学习记录9-设计和UI之控件和模式6

    UWP学习记录9-设计和UI之控件和模式6 1.图形和墨迹 InkCanvas是接收和显示墨迹笔划的控件,是新增的比较复杂的控件,这里先不深入. 而形状(Shape)则是可以显示的各种保留模式图形对象 ...

  8. UWP学习记录8-设计和UI之控件和模式5

    UWP学习记录8-设计和UI之控件和模式5 1.日历.日期和时间控件 日期和时间控件提供了标准的本地化方法,可供用户在应用中查看并设置日期和时间值. 有四个日期和时间控件可供选择,选择的依据如下: 日 ...

  9. UWP学习记录7-设计和UI之控件和模式4

    UWP学习记录7-设计和UI之控件和模式4 1.翻转视图 使用翻转视图浏览集合中的图像或其他项目(例如相册中的照片或产品详细信息页中的项目),一次显示一个项目. 对于触摸设备,轻扫某个项将在整个集合中 ...

随机推荐

  1. java读取redis的timeout异常

    http://blog.csdn.net/shuaiokshuai/article/details/23266091 FIFO Fist-in Fisrt-out 先进先出

  2. webapp思路和rem适配极其viewport

    webapp在制作时候,页面上要加入viewport标签,用来进行适配; viewport的meta标签,指的是在移动端显示的时候,viewport是多大?移动端的浏览器是屏幕宽,viewport一般 ...

  3. idea 配置node Run

    1.node 2.nodemon 支持热部署 3.supervisor  支持执部署

  4. Linux命令:head命令详解

    概述:head命令用于显示文件文字区块 1.格式 head [参数][文件] 2.参数 -q 隐藏文件名 -v 显示文件名 -c<字节> 显示字节数 -n<行数> 显示的行数 ...

  5. [LeetCode OJ] Distinct Subsequences

    Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequence ...

  6. BIOS中断大全

    BIOS中断大全 BIOS中断:1.显示服务(Video Service——INT 10H)  00H —设置显示器模式0CH —写图形象素01H —设置光标形状0DH —读图形象素02H —设置光标 ...

  7. mac 自带 php 验证码 不显示

    curl -s http://php-osx.liip.ch/install.sh | bash -s 5.5 在命令行中输入上面   ,最后5.5是php版本号 自动安装FreeType ----- ...

  8. mysql数据类型——整型INT(m)

    1.整形分为四种 tinyint smallint mediumint int bigint 注意: 右侧的取值范围是在未加unsigned关键字的情况下,如果加了unsigned,则最大值翻倍,如t ...

  9. Latex及Beamer

    一 资源 Latex编辑部 Codecogs,latex在线编辑可见

  10. 再次探究Android ListView缓存机制

    概述 虽然现在5.0后Google推出了RecycleView,但在5.0 Lollipop普及前Listview仍会被广泛使用,所以打算再次探究一下Listview的源码,了解一下Listview ...