一.Android 低功耗蓝牙(BLE)的API简介

  1. Android 4.3(API 18)才支持低功耗蓝牙(Bluetooth Low Energy, BLE)的核心功能,
  2. BLE蓝牙协议是GATT协议, BLE相关类不多, 全都位于android.bluetooth包和android.bluetooth.le包的几个类:
  3. android.bluetooth.
  4. .BluetoothGattService 包含多个Characteristic(属性特征值), 含有唯一的UUID作为标识
  5. .BluetoothGattCharacteristic 包含单个值和多个Descriptor, 含有唯一的UUID作为标识
  6. .BluetoothGattDescriptor Characteristic进行描述, 含有唯一的UUID作为标识
  7.  
  8. .BluetoothGatt 客户端相关
  9. .BluetoothGattCallback 客户端连接回调
  10. .BluetoothGattServer 服务端相关
  11. .BluetoothGattServerCallback 服务端连接回调
  12.  
  13. android.bluetooth.le.
  14. .AdvertiseCallback 服务端的广播回调
  15. .AdvertiseData 服务端的广播数据
  16. .AdvertiseSettings 服务端的广播设置
  17. .BluetoothLeAdvertiser 服务端的广播
  18.  
  19. .BluetoothLeScanner 客户端扫描相关(Android5.0新增)
  20. .ScanCallback 客户端扫描回调
  21. .ScanFilter 客户端扫描过滤
  22. .ScanRecord 客户端扫描结果的广播数据
  23. .ScanResult 客户端扫描结果
  24. .ScanSettings 客户端扫描设置
  25.  
  26. BLE设备分为两种设备: 客户端(也叫主机/中心设备/Central), 服务端(也叫从机/外围设备/peripheral)
  27. 客户端的核心类是 BluetoothGatt
  28. 服务端的核心类是 BluetoothGattServer BluetoothLeAdvertiser
  29. BLE数据的核心类是 BluetoothGattCharacteristic BluetoothGattDescriptor

二.低功耗蓝牙(BLE)-手机同时作为BLE客户端和BLE服务端,读写Characteristic数据

完整源码: https://github.com/lifegh/Bluetooth

bt_client.png

bt_server.png

1.蓝牙权限

  1. BLE权限增加了BEL支持检查,其它与上篇的经典蓝牙相同,不再写了
  2. (1).在manifest中添加权限
  3.  
  4. (2).在Activity中设置蓝牙
  5. // 检查是否支持BLE蓝牙
  6. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
  7. Util.toast(this, "本机不支持低功耗蓝牙!");
  8. finish();
  9. return;
  10. }

2.BLE客户端(也叫主机/中心设备/Central)

(1).扫描BLE设备(不包含经典蓝牙)

  1. 注意: BLE设备地址是动态变化(每隔一段时间都会变化),而经典蓝牙设备是出厂就固定不变了!
  2. BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  3. // 下面使用Android5.0新增的扫描API,扫描返回的结果更友好,比如BLE广播数据以前是byte[] scanRecord,而新API帮我们解析成ScanRecord类
  4. // 旧API是BluetoothAdapter.startLeScan(...)
  5. final BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
  6. bluetoothLeScanner.startScan(mScanCallback);
  7. mHandler.postDelayed(new Runnable() {
  8. @Override
  9. public void run() {
  10. bluetoothLeScanner.stopScan(mScanCallback); //停止扫描
  11. isScanning = false;
  12. }
  13. }, 3000);
  14.  
  15. // 扫描结果Callback
  16. private final ScanCallback mScanCallback = new ScanCallback() {
  17. @Override
  18. public void onScanResult(int callbackType, ScanResult result) {、
  19. BluetoothDevice dev = result.getDevice() 获取BLE设备信息
  20. // result.getScanRecord() 获取BLE广播数据
  21. }
  22. };

(2).建立连接

  1. // 获取扫描设备,建立连接
  2. closeConn();
  3. BluetoothDevice dev = result.getDevice()
  4. mBluetoothGatt = dev.connectGatt(BleClientActivity.this, false, mBluetoothGattCallback); // 连接蓝牙设备
  5.  
  6. // BLE中心设备连接外围设备的数量有限(大概2~7个),在建立新连接之前必须释放旧连接资源,否则容易出现连接错误133
  7. private void closeConn() {
  8. if (mBluetoothGatt != null) {
  9. mBluetoothGatt.disconnect();
  10. mBluetoothGatt.close();
  11. }
  12. }
  13.  
  14. // 与服务端连接的Callback
  15. public BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {
  16. @Override
  17. public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
  18. BluetoothDevice dev = gatt.getDevice();
  19. Log.i(TAG, String.format("onConnectionStateChange:%s,%s,%s,%s", dev.getName(), dev.getAddress(), status, newState));
  20. if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
  21. isConnected = true;
  22. gatt.discoverServices(); //启动服务发现
  23. } else {
  24. isConnected = false;
  25. closeConn();
  26. }
  27. logTv(String.format(status == 0 ? (newState == 2 ? "与[%s]连接成功" : "与[%s]连接断开") : ("与[%s]连接出错,错误码:" + status), dev));
  28. }
  29.  
  30. @Override
  31. public void onServicesDiscovered(BluetoothGatt gatt, int status) {
  32. Log.i(TAG, String.format("onServicesDiscovered:%s,%s,%s", gatt.getDevice().getName(), gatt.getDevice().getAddress(), status));
  33. if (status == BluetoothGatt.GATT_SUCCESS) { //BLE服务发现成功
  34. // 遍历获取BLE服务Services/Characteristics/Descriptors的全部UUID
  35. for (BluetoothGattService service : gatt.getServices()) {
  36. StringBuilder allUUIDs = new StringBuilder("UUIDs={nS=" + service.getUuid().toString());
  37. for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
  38. allUUIDs.append(",nC=").append(characteristic.getUuid());
  39. for (BluetoothGattDescriptor descriptor : characteristic.getDescriptors())
  40. allUUIDs.append(",nD=").append(descriptor.getUuid());
  41. }
  42. allUUIDs.append("}");
  43. Log.i(TAG, "onServicesDiscovered:" + allUUIDs.toString());
  44. logTv("发现服务" + allUUIDs);
  45. }
  46. }
  47. }
  48.  
  49. @Override
  50. public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
  51. UUID uuid = characteristic.getUuid();
  52. String valueStr = new String(characteristic.getValue());
  53. Log.i(TAG, String.format("onCharacteristicRead:%s,%s,%s,%s,%s", gatt.getDevice().getName(), gatt.getDevice().getAddress(), uuid, valueStr, status));
  54. logTv("读取Characteristic[" + uuid + "]:n" + valueStr);
  55. }
  56.  
  57. @Override
  58. public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
  59. UUID uuid = characteristic.getUuid();
  60. String valueStr = new String(characteristic.getValue());
  61. Log.i(TAG, String.format("onCharacteristicWrite:%s,%s,%s,%s,%s", gatt.getDevice().getName(), gatt.getDevice().getAddress(), uuid, valueStr, status));
  62. logTv("写入Characteristic[" + uuid + "]:n" + valueStr);
  63. }
  64.  
  65. @Override
  66. public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
  67. UUID uuid = characteristic.getUuid();
  68. String valueStr = new String(characteristic.getValue());
  69. Log.i(TAG, String.format("onCharacteristicChanged:%s,%s,%s,%s", gatt.getDevice().getName(), gatt.getDevice().getAddress(), uuid, valueStr));
  70. logTv("通知Characteristic[" + uuid + "]:n" + valueStr);
  71. }
  72.  
  73. @Override
  74. public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
  75. UUID uuid = descriptor.getUuid();
  76. String valueStr = Arrays.toString(descriptor.getValue());
  77. Log.i(TAG, String.format("onDescriptorRead:%s,%s,%s,%s,%s", gatt.getDevice().getName(), gatt.getDevice().getAddress(), uuid, valueStr, status));
  78. logTv("读取Descriptor[" + uuid + "]:n" + valueStr);
  79. }
  80.  
  81. @Override
  82. public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
  83. UUID uuid = descriptor.getUuid();
  84. String valueStr = Arrays.toString(descriptor.getValue());
  85. Log.i(TAG, String.format("onDescriptorWrite:%s,%s,%s,%s,%s", gatt.getDevice().getName(), gatt.getDevice().getAddress(), uuid, valueStr, status));
  86. logTv("写入Descriptor[" + uuid + "]:n" + valueStr);
  87. }
  88. };

(3).传输数据(读写CHARACTERISTIC和DESCRIPTOR)

  1. 注意:
  2. 1.每次读写数据最多20个字节,如果超过,只能分包
  3. 2.连续频繁读写数据容易失败,读写操作间隔最好200ms以上,或等待上次回调完成后再进行下次读写操作!
  4. // 读取数据成功会回调->onCharacteristicChanged()
  5. public void read(View view) {
  6. BluetoothGattService service = getGattService(BleServerActivity.UUID_SERVICE);
  7. if (service != null) {
  8. BluetoothGattCharacteristic characteristic = service.getCharacteristic(BleServerActivity.UUID_CHAR_READ_NOTIFY);//通过UUID获取可读的Characteristic
  9. mBluetoothGatt.readCharacteristic(characteristic);
  10. }
  11. }
  12.  
  13. // 写入数据成功会回调->onCharacteristicWrite()
  14. public void write(View view) {
  15. BluetoothGattService service = getGattService(BleServerActivity.UUID_SERVICE);
  16. if (service != null) {
  17. String text = mWriteET.getText().toString();
  18. BluetoothGattCharacteristic characteristic = service.getCharacteristic(BleServerActivity.UUID_CHAR_WRITE);//通过UUID获取可写的Characteristic
  19. characteristic.setValue(text.getBytes()); //单次最多20个字节
  20. mBluetoothGatt.writeCharacteristic(characteristic);
  21. }
  22. }
  23.  
  24. // 获取Gatt服务
  25. private BluetoothGattService getGattService(UUID uuid) {
  26. BluetoothGattService service = mBluetoothGatt.getService(uuid);
  27. if (service == null)
  28. Util.toast(this, "没有找到服务UUID=" + uuid);
  29. return service;
  30. }

(4).设置通知,实时监听CHARACTERISTIC变化

  1. // Characteristic变化会回调->onCharacteristicChanged()
  2. BluetoothGattService service = getGattService(BleServerActivity.UUID_SERVICE);
  3. if (service != null) {
  4. // 设置Characteristic通知
  5. BluetoothGattCharacteristic characteristic = service.getCharacteristic(BleServerActivity.UUID_CHAR_READ_NOTIFY);//通过UUID获取可通知的Characteristic
  6. mBluetoothGatt.setCharacteristicNotification(characteristic, true);
  7.  
  8. // 向Characteristic的Descriptor属性写入通知开关,使蓝牙设备主动向手机发送数据
  9. BluetoothGattDescriptor descriptor = characteristic.getDescriptor(BleServerActivity.UUID_DESC_NOTITY);
  10. // descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);//和通知类似,但服务端不主动发数据,只指示客户端读取数据
  11. descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
  12. mBluetoothGatt.writeDescriptor(descriptor);
  13. }

3.BLE服务端(也叫从机/外围设备/peripheral)

  1. public static final UUID UUID_SERVICE = UUID.fromString("10000000-0000-0000-0000-000000000000"); //自定义UUID
  2. public static final UUID UUID_CHAR_READ_NOTIFY = UUID.fromString("11000000-0000-0000-0000-000000000000");
  3. public static final UUID UUID_DESC_NOTITY = UUID.fromString("11100000-0000-0000-0000-000000000000");
  4. public static final UUID UUID_CHAR_WRITE = UUID.fromString("12000000-0000-0000-0000-000000000000");
  5. private BluetoothLeAdvertiser mBluetoothLeAdvertiser; // BLE广播
  6. private BluetoothGattServer mBluetoothGattServer; // BLE服务端
  7.  
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. ......
  11. BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
  12. // BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
  13. BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  14.  
  15. // ============启动BLE蓝牙广播(广告) =================================================================================
  16. //广播设置(必须)
  17. AdvertiseSettings settings = new AdvertiseSettings.Builder()
  18. .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) //广播模式: 低功耗,平衡,低延迟
  19. .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) //发射功率级别: 极低,低,中,高
  20. .setConnectable(true) //能否连接,广播分为可连接广播和不可连接广播
  21. .build();
  22. //广播数据(必须,广播启动就会发送)
  23. AdvertiseData advertiseData = new AdvertiseData.Builder()
  24. .setIncludeDeviceName(true) //包含蓝牙名称
  25. .setIncludeTxPowerLevel(true) //包含发射功率级别
  26. .addManufacturerData(1, new byte[]{23, 33}) //设备厂商数据,自定义
  27. .build();
  28. //扫描响应数据(可选,当客户端扫描时才发送)
  29. AdvertiseData scanResponse = new AdvertiseData.Builder()
  30. .addManufacturerData(2, new byte[]{66, 66}) //设备厂商数据,自定义
  31. .addServiceUuid(new ParcelUuid(UUID_SERVICE)) //服务UUID
  32. // .addServiceData(new ParcelUuid(UUID_SERVICE), new byte[]{2}) //服务数据,自定义
  33. .build();
  34. mBluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
  35. mBluetoothLeAdvertiser.startAdvertising(settings, advertiseData, scanResponse, mAdvertiseCallback);
  36.  
  37. // 注意:必须要开启可连接的BLE广播,其它设备才能发现并连接BLE服务端!
  38. // =============启动BLE蓝牙服务端=====================================================================================
  39. BluetoothGattService service = new BluetoothGattService(UUID_SERVICE, BluetoothGattService.SERVICE_TYPE_PRIMARY);
  40. //添加可读+通知characteristic
  41. BluetoothGattCharacteristic characteristicRead = new BluetoothGattCharacteristic(UUID_CHAR_READ_NOTIFY,
  42. BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_READ);
  43. characteristicRead.addDescriptor(new BluetoothGattDescriptor(UUID_DESC_NOTITY, BluetoothGattCharacteristic.PERMISSION_WRITE));
  44. service.addCharacteristic(characteristicRead);
  45. //添加可写characteristic
  46. BluetoothGattCharacteristic characteristicWrite = new BluetoothGattCharacteristic(UUID_CHAR_WRITE,
  47. BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE);
  48. service.addCharacteristic(characteristicWrite);
  49. if (bluetoothManager != null)
  50. mBluetoothGattServer = bluetoothManager.openGattServer(this, mBluetoothGattServerCallback);
  51. mBluetoothGattServer.addService(service);
  52. }
  53.  
  54. // BLE广播Callback
  55. private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
  56. @Override
  57. public void onStartSuccess(AdvertiseSettings settingsInEffect) {
  58. logTv("BLE广播开启成功");
  59. }
  60.  
  61. @Override
  62. public void onStartFailure(int errorCode) {
  63. logTv("BLE广播开启失败,错误码:" + errorCode);
  64. }
  65. };
  66.  
  67. // BLE服务端Callback
  68. private BluetoothGattServerCallback mBluetoothGattServerCallback = new BluetoothGattServerCallback() {
  69. @Override
  70. public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
  71. Log.i(TAG, String.format("onConnectionStateChange:%s,%s,%s,%s", device.getName(), device.getAddress(), status, newState));
  72. logTv(String.format(status == 0 ? (newState == 2 ? "与[%s]连接成功" : "与[%s]连接断开") : ("与[%s]连接出错,错误码:" + status), device));
  73. }
  74.  
  75. @Override
  76. public void onServiceAdded(int status, BluetoothGattService service) {
  77. Log.i(TAG, String.format("onServiceAdded:%s,%s", status, service.getUuid()));
  78. logTv(String.format(status == 0 ? "添加服务[%s]成功" : "添加服务[%s]失败,错误码:" + status, service.getUuid()));
  79. }
  80.  
  81. @Override
  82. public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
  83. Log.i(TAG, String.format("onCharacteristicReadRequest:%s,%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, offset, characteristic.getUuid()));
  84. String response = "CHAR_" + (int) (Math.random() * 100); //模拟数据
  85. mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, response.getBytes());// 响应客户端
  86. logTv("客户端读取Characteristic[" + characteristic.getUuid() + "]:n" + response);
  87. }
  88.  
  89. @Override
  90. public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
  91. // 获取客户端发过来的数据
  92. String requestStr = new String(requestBytes);
  93. Log.i(TAG, String.format("onCharacteristicWriteRequest:%s,%s,%s,%s,%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, characteristic.getUuid(),
  94. preparedWrite, responseNeeded, offset, requestStr));
  95. mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, requestBytes);// 响应客户端
  96. logTv("客户端写入Characteristic[" + characteristic.getUuid() + "]:n" + requestStr);
  97. }
  98.  
  99. @Override
  100. public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
  101. Log.i(TAG, String.format("onDescriptorReadRequest:%s,%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, offset, descriptor.getUuid()));
  102. String response = "DESC_" + (int) (Math.random() * 100); //模拟数据
  103. mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, response.getBytes()); // 响应客户端
  104. logTv("客户端读取Descriptor[" + descriptor.getUuid() + "]:n" + response);
  105. }
  106.  
  107. @Override
  108. public void onDescriptorWriteRequest(final BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
  109. // 获取客户端发过来的数据
  110. String valueStr = Arrays.toString(value);
  111. Log.i(TAG, String.format("onDescriptorWriteRequest:%s,%s,%s,%s,%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, descriptor.getUuid(),
  112. preparedWrite, responseNeeded, offset, valueStr));
  113. mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);// 响应客户端
  114. logTv("客户端写入Descriptor[" + descriptor.getUuid() + "]:n" + valueStr);
  115.  
  116. // 简单模拟通知客户端Characteristic变化
  117. if (Arrays.toString(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE).equals(valueStr)) { //是否开启通知
  118. final BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
  119. new Thread(new Runnable() {
  120. @Override
  121. public void run() {
  122. for (int i = 0; i < 5; i++) {
  123. SystemClock.sleep(3000);
  124. String response = "CHAR_" + (int) (Math.random() * 100); //模拟数据
  125. characteristic.setValue(response);
  126. mBluetoothGattServer.notifyCharacteristicChanged(device, characteristic, false);
  127. logTv("通知客户端改变Characteristic[" + characteristic.getUuid() + "]:n" + response);
  128. }
  129. }
  130. }).start();
  131. }
  132. }
  133.  
  134. @Override
  135. public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
  136. Log.i(TAG, String.format("onExecuteWrite:%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, execute));
  137. }
  138.  
  139. @Override
  140. public void onNotificationSent(BluetoothDevice device, int status) {
  141. Log.i(TAG, String.format("onNotificationSent:%s,%s,%s", device.getName(), device.getAddress(), status));
  142. }
  143.  
  144. @Override
  145. public void onMtuChanged(BluetoothDevice device, int mtu) {
  146. Log.i(TAG, String.format("onMtuChanged:%s,%s,%s", device.getName(), device.getAddress(), mtu));
  147. }
  148. };

简书: https://www.jianshu.com/p/8ac31a5070d4

CSDN: https://blog.csdn.net/qq_32115439/article/details/80643906

GitHub博客: http://lioil.win/2018/06/10/Android-BLE.html

Coding博客: http://c.lioil.win/2018/06/10/Android-BLE.html

Android-低功耗蓝牙(BLE)-客户端(主机/中心设备)和服务端(从机/外围设备)的更多相关文章

  1. 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体解释

    转载请注明来源: http://blog.csdn.net/kjunchen/article/details/50909410 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体 ...

  2. Android 低功耗蓝牙BLE 开发注意事项

    基本概念和问题 1.蓝牙设计范式? 当手机通过扫描低功耗蓝牙设备并连接上后,手机与蓝牙设备构成了客户端-服务端架构.手机通过连接蓝牙设备,可以读取蓝牙设备上的信息.手机就是客户端,蓝牙设备是服务端. ...

  3. Android低功耗蓝牙(BLE)开发的一点感受

    最近一段时间,因为产品的需要我做了一个基于低功耗蓝牙设备的Android应用,其中碰到了一些困难,使我深深体会到Android开发的难处:不同品牌,不同型号和不同版本之间的差异使得Android应用适 ...

  4. Android低功耗蓝牙(BLE)使用详解

    代码地址如下:http://www.demodashi.com/demo/13390.html 与普通蓝牙相比,低功耗蓝牙显著降低了能量消耗,允许Android应用程序与具有更严格电源要求的BLE设备 ...

  5. Android低功耗蓝牙(蓝牙4.0)——BLE开发(上)

    段时间,公司项目用到了手机APP和蓝牙设备的通讯开发,这里也正好对低功耗蓝牙(蓝牙4.0及以后标准)的开发,做一个总结. 蓝牙技术联盟在2010年6月30号公布了蓝牙4.0标准,4.0标准在蓝牙3.0 ...

  6. 低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端

    低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端 Android对外模模式(peripheral)的支持 从Android5.0开始才支持 关键术语和概念 以下是关键BLE术语和 ...

  7. 【转】Android低功耗蓝牙应用开发获取的服务UUID

    原文网址:http://blog.csdn.net/zhangjs0322/article/details/39048939 Android低功耗蓝牙应用程序开始时获取到的蓝牙血压计所有服务的UUID ...

  8. 深入浅出低功耗蓝牙(BLE)协议栈

    深入浅出低功耗蓝牙(BLE)协议栈 BLE协议栈为什么要分层?怎么理解蓝牙"连接"?如果蓝牙协议只有ATT没有GATT会发生什么? 协议栈框架 一般而言,我们把某个协议的实现代码称 ...

  9. 深入浅出讲解低功耗蓝牙(BLE)协议栈

    详解BLE连接建立过程https://www.cnblogs.com/iini/p/8972635.html 详解BLE 空中包格式—兼BLE Link layer协议解析https://www.cn ...

随机推荐

  1. rocketMq---------相关命令

    搭建就不详细说了,cent7.x的系统,openJdk8,maven3.x,gradle4.10.2, git 1.8.3.1 直接下载相关的二进制压缩包,解压即用,方便. 下面看常用的管理命令 ro ...

  2. python学习笔记之heapq内置模块

    heapq内置模块位于./Anaconda3/Lib/heapq.py,提供基于堆的优先排序算法 堆的逻辑结构就是完全二叉树,并且二叉树中父节点的值小于等于该节点的所有子节点的值.这种实现可以使用 h ...

  3. boost exception jam0.exe 异常错误

    在Windows 8 64 bit下执行boost_1_53_0的bootstrap.bat出现了jam0.exe执行错误 搜索网页发现需要修改两处文件: tools/build/v2/engine/ ...

  4. 3D空间中射线与轴向包围盒AABB的交叉检测算法 【转】

    http://blog.csdn.net/i_dovelemon/article/details/38342739 引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法. 但是,我们应该知道, ...

  5. [学习笔记]Java异常机制

    概述 异常 程序在执行时出现的不正常情况,是对问题的描写叙述.将问题进行对象的封装. Java中的异常,就是对不正常情况进行描写叙述后的对象体现. 异常体系 Throwable     |--Erro ...

  6. 点击选中/取消选中flag

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name ...

  7. Allegro布线基本操作

    转:allegro基本步骤 常见问题 cadence16.5中电源线.地线取消飞线显示 目录: 一.Allegro基本技巧 1.关闭电源和地网络的飞线 2.开启特定NET飞线 3.元器件快速对齐(待完 ...

  8. 笔记08 WPF导航

    如何在winform中做导航,如何重定向界面,就产生了争执. 是用window还是Page还是UserControl? 先不管用啥.我们先比较一下各自的优缺点. 在WPF中使用导航,内容被组织在Pag ...

  9. inception安装步骤---自己整理的安装步骤

    inception安装步骤---自己整理的安装步骤2015-09-18 15:51 6185人阅读 评论(1) 收藏 举报 分类: inception相关版权声明:本文为博主原创文章,未经博主允许不得 ...

  10. tensor搭建--windows 10 64bit下安装Tensorflow+Keras+VS2015+CUDA8.0 GPU加速

    windows 10 64bit下安装Tensorflow+Keras+VS2015+CUDA8.0 GPU加速 原文见于:http://www.jianshu.com/p/c245d46d43f0 ...