原文网址: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. Android开发手记(31) 使用MediaRecorder录音

    使用Android手机的时候,有时我们会用到录音功能,本文简单的介绍了如何使用MediaRecorder通过手机自带麦克风进行录音. 首先,既然是录音,我们需要录音和写外存的权限: <uses- ...

  2. EF FluentAPI映射一对多 关系时候报错

    提示很明显,不可为空的外键为空了,但是 问题是,我只是初始化 关系映射而已:见代码 public ColumnsCategoryMapConfiguration() { ToTable("C ...

  3. windows 20003 扩展安装后不成功的原因

    windows扩展如果安装不成功(PHP扩展)很大的可能就是那个DLL的权限不够.需要分配:AdministratorAuthenticater UsersIIS_WPGSYSTEMUsers

  4. 分享最近写的一个存储过程 SOLVE_LOCK

    CREATE OR REPLACE PROCEDURE SOLVE_LOCK AS V_SQL VARCHAR2(3000); --定义 v_sql 接受抓取锁的sql语句V_SQL02 VARCHA ...

  5. js对象字符串互转

    利用原生JSON对象,将对象转为字符串 var jsObj = {}; jsObj.testArray = [1,2,3,4,5]; jsObj.name = 'CSS3'; jsObj.date = ...

  6. Objective-C总Runtime的那点事儿(一)消息机制【转】

    RunTime简称运行时.就是系统在运行的时候的一些机制,其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ).编译完成之后直接顺序执行,无任何 ...

  7. Linux抓包工具tcpdump详解

    tcpdump是一个用于截取网络分组,并输出分组内容的工具,简单说就是数据包抓包工具.tcpdump凭借强大的功能和灵活的截取策略,使其成为Linux系统下用于网络分析和问题排查的首选工具. tcpd ...

  8. EasyUI 1.3之前DataGrid中动态选中、获取Checkbox

    这几天做项目,由于项目中用到的EasyUI版本过低,不能使用自带操作DataGrid中CheckBox的方法. 所以自己写了一个临时方案: 根据ID集合选中所属行的CheckBox: data={1, ...

  9. 运行在TQ2440开发板上以及X86平台上的linux内核编译

    一.运行在TQ2440开发板上的linux内核编译 1.获取源码并解压 直接使用天嵌移植好的“linux-2.6.30.4_20100531.tar.bz2”源码包. 解压(天嵌默认解压到/opt/E ...

  10. bzoj1038: [ZJOI2008]瞭望塔

    Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, ...