原文网址: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. Couchbase用的端口

    文档首页: http://www.couchbase.com/documentation http://docs.couchbase.com/couchbase-manual-2.2/#prepara ...

  2. C#中邮件的发送基本操作

    本地配置的邮箱:http://localhost:6080/index.php //邮件的收发需要用到两个类   //1.用来创建一封邮件对象     //1.MailMessage 添加对 usin ...

  3. 苹果App store 2015最新审核标准公布(2015.3)

    苹果近日更新了AppStore审核指南的相关章节,对此前版本进行了修改和完善.除了增加应用截图.预览等限制外,使用ApplePay进行定期付款的应用程序必须展示每个阶段所需款额,费用归属以及如何取消. ...

  4. java 迭代器iterator

    对于如ArrayList<E>类的数据,常用iterator遍历. ArrayList<String> list = new ArrayList<String>() ...

  5. Vijos1523 NOI2002 贪吃的九头龙 树形dp

    思路不算很难,但细节处理很麻烦 前面建图.多叉转二叉,以及确定dp处理序列的过程都是套路,dp的状态转移过程以注释的形式阐述 #include <cstdio> #include < ...

  6. C++ Reference 的“三位一体”诠释

    C++ 是介于汇编语言与高级语言之间的一种“全能”语言.它的能力是其他任何基于VMA(冯-诺曼架构)计算机的高级程序设计语言无法望其项背的,而性能也只有C语言可与之伯仲. 然而长期以来,喜欢C++和憎 ...

  7. Java jdk环境搭建

    java JDK的配置在我的电脑环境变量中配置: 主要的配置参数path  例:path = C:\jdk1.7.0_13\bin ; 另外一个JAVA_HOME 例:JAVA_HOME = C:\j ...

  8. JS判断终端(Android IOS)

    function getMobileOperatingSystem() { var userAgent = navigator.userAgent || navigator.vendor || win ...

  9. wechat-php-sdk

    wechat-php-sdk 微信公众平台php版开发包 支持消息加解密方式的明文模式.兼容模式.安全模式 支持自动接入微信公众平台(步骤) 功能模块 Wechat (处理自动接入.获取与回复微信消息 ...

  10. Linux删除用户

    删除用户 # userdel abc 该删除操作将用户删除但保留用户的home文件夹和邮件文件夹.并且当用户abc正在登录的时候,删除操作将失败,如下: # userdel abc userdel: ...