Android 藍牙4.0(BLE) 理解--緊隨智能家居和可穿戴設備潮流

本文轉自:http://blog.csdn.net/chaoyue0071/article/details/43450183/


正文 :


本文簡單結合兩篇文章

http://blog.csdn.net/hellogv/article/details/24267685

http://blog.csdn.net/jimoduwu/article/details/21604215

在BLE協議中,有兩個角色,周邊(Periphery)和中央(Central),一箇中央可以同時連接多個周邊,但是一個周邊某一時刻只能連接一箇中央。但是不管是Periphery還是Central都是可以實現 GATT server 和 GATT client去傳輸數據,但是無法同時都是。

大概瞭解了概念後,看看Android BLE SDK的四個關鍵類(class):

a) BluetoothGattServer作爲周邊來提供數據;BluetoothGattServerCallback返回周邊的狀態。

b) BluetoothGatt作爲中央來使用和處理數據;BluetoothGattCallback返回中央的狀態和周邊提供的數據。

因爲我們討論的是Android的BLE SDK,下面所有的BluetoothGattServer代表周邊,BluetoothGatt代表中央。

          

一.創建一個周邊(雖然目前周邊API在Android手機上不工作,但還是看看)

 a)先看看周邊用到的class,藍色橢圓


b)說明:

每一個周邊BluetoothGattServer,包含多個服務Service,每一個Service包含多個特徵Characteristic。

1.new一個特徵:character = new BluetoothGattCharacteristic(
UUID.fromString(characteristicUUID),
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ);

2.new一個服務:service = new BluetoothGattService(UUID.fromString(serviceUUID),
BluetoothGattService.SERVICE_TYPE_PRIMARY);

3.把特徵添加到服務:service.addCharacteristic(character);

4.獲取BluetoothManager:manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

5.獲取/打開周邊:BluetoothGattServer server = manager.openGattServer(this,
new BluetoothGattServerCallback(){...}); 

6.把service添加到周邊:server.addService(service);

7.開始廣播service:Google還沒有廣播Service的API,等吧!!!!!所以目前我們還不能讓一個Android手機作爲周邊來提供數據。


二.創建一箇中央(這次不會讓你失望,可以成功創建並且連接到周邊的)

a)先看看中央用到的class,藍色橢圓



b)說明:

爲了拿到中央BluetoothGatt,可要爬山涉水十八彎:

1.先拿到BluetoothManager:bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

2.再拿到BluetoothAdapt:btAdapter = bluetoothManager.getAdapter();

3.開始掃描:btAdapter.startLeScan( BluetoothAdapter.LeScanCallback);

4.從LeScanCallback中得到BluetoothDevice:public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {.....}

5.用BluetoothDevice得到BluetoothGatt:gatt = device.connectGatt(this, true, gattCallback);

終於拿到中央BluetoothGatt了,它有一堆方法(查API吧),調用這些方法,你就可以通過BluetoothGattCallback和周邊BluetoothGattServer交互了。


官方有給出BLE 通信的sample ,下面是牛人簡化了代碼,簡化得簡單明瞭
本文來自http://blog.csdn.net/hellogv/ ,引用必須註明出處!

最近穿戴設備發展得很火,把相關技術也帶旺了,其中一項是BLE(Bluetooth Low Energy)。BLE是藍牙4.0的核心Profile,主打功能是快速搜索,快速連接,超低功耗保持連接和傳輸數據,弱點是數據傳輸速率低,由於BLE的低功耗特點,因此普遍用於穿戴設備。Android 4.3纔開始支持BLE API,所以請各位客官把本文代碼運行在藍牙4.0和Android 4.3及其以上的系統,另外本文所用的BLE終端是一個藍牙4.0的串口藍牙模塊。

PS:我的i9100刷了4.4系統後,竟然也能跟BLE藍牙模塊通信。


BLE分爲三部分Service、Characteristic、Descriptor,這三部分都由UUID作爲唯一標示符。一個藍牙4.0的終端可以包含多個Service,一個Service可以包含多個Characteristic,一個Characteristic包含一個Value和多個Descriptor,一個Descriptor包含一個Value。一般來說,Characteristic是手機與BLE終端交換數據的關鍵,Characteristic有較多的跟權限相關的字段,例如PERMISSION和PROPERTY,而其中最常用的是PROPERTY,本文所用的BLE藍牙模塊竟然沒有標準的Characteristic的PERMISSION。Characteristic的PROPERTY可以通過位運算符組合來設置讀寫屬性,例如READ|WRITE、READ|WRITE_NO_RESPONSE|NOTIFY,因此讀取PROPERTY後要分解成所用的組合(本文代碼已含此分解方法)。


本文代碼改自Android 4.3 Sample的BluetoothLeGatt,把冗餘代碼去掉,獲取的BLE設備信息都通過Log,還有一些必要的讀寫藍牙方法,應該算是簡化到大家一看就可以懂了。本文代碼可以到http://download.csdn.net/detail/hellogv/7228819下載。接下來貼出本文運行的結果,首先是連接BLE設備後,枚舉出設備所有Service、Characteristic、Descriptor,並且手機會往Characteristic uuid=0000ffe1-0000-1000-8000-00805f9b34fb寫入“send data->”字符串,BLE終端收到數據通過串口傳到PC串口助手(見PC串口助手的截圖):

04-21 18:28:25.465: E/DeviceScanActivity(12254): -->service type:PRIMARY
04-21 18:28:25.465: E/DeviceScanActivity(12254): -->includedServices size:0
04-21 18:28:25.465: E/DeviceScanActivity(12254): -->service uuid:00001800-0000-1000-8000-00805f9b34fb
04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char uuid:00002a00-0000-1000-8000-00805f9b34fb
04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char property:READ
04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char uuid:00002a01-0000-1000-8000-00805f9b34fb
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char property:READ
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char uuid:00002a02-0000-1000-8000-00805f9b34fb
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char property:READ|WRITE|
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char uuid:00002a03-0000-1000-8000-00805f9b34fb
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char property:READ|WRITE|
04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char uuid:00002a04-0000-1000-8000-00805f9b34fb
04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char property:READ
04-21 18:28:25.475: E/DeviceScanActivity(12254): -->service type:PRIMARY
04-21 18:28:25.475: E/DeviceScanActivity(12254): -->includedServices size:0
04-21 18:28:25.475: E/DeviceScanActivity(12254): -->service uuid:00001801-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char uuid:00002a05-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char property:INDICATE
04-21 18:28:25.480: E/DeviceScanActivity(12254): -------->desc uuid:00002902-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
04-21 18:28:25.480: E/DeviceScanActivity(12254): -->service type:PRIMARY
04-21 18:28:25.480: E/DeviceScanActivity(12254): -->includedServices size:0
04-21 18:28:25.480: E/DeviceScanActivity(12254): -->service uuid:0000ffe0-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char uuid:0000ffe1-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char property:READ|WRITE_NO_RESPONSE|NOTIFY|
04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc uuid:00002902-0000-1000-8000-00805f9b34fb
04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc uuid:00002901-0000-1000-8000-00805f9b34fb
04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
04-21 18:28:26.025: E/DeviceScanActivity(12254): onCharRead BLE DEVICE read 0000ffe1-0000-1000-8000-00805f9b34fb -> 00

這裏紅字是由BluetoothGattCallback的onCharacteristicRead()回調而打出Log




以下Log是PC上的串口工具通過BLE模塊發送過來,由BluetoothGattCallback的 onCharacteristicChanged()打出Log
04-21 18:30:18.260: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:18.745: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:19.085: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:19.350: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:19.605: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:19.835: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:20.055: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:20.320: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:20.510: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:20.735: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:21.000: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone

接下來貼出本文核心代碼:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class DeviceScanActivity extends ListActivity {  
  2.     private final static String TAG = DeviceScanActivity.class.getSimpleName();  
  3.     private final static String UUID_KEY_DATA = "0000ffe1-0000-1000-8000-00805f9b34fb";  
  4.   
  5.     private LeDeviceListAdapter mLeDeviceListAdapter;  
  6.     /**搜索BLE終端*/  
  7.     private BluetoothAdapter mBluetoothAdapter;  
  8.     /**讀寫BLE終端*/  
  9.     private BluetoothLeClass mBLE;  
  10.     private boolean mScanning;  
  11.     private Handler mHandler;  
  12.   
  13.     // Stops scanning after 10 seconds.  
  14.     private static final long SCAN_PERIOD = 10000;  
  15.   
  16.     @Override  
  17.     public void onCreate(Bundle savedInstanceState) {  
  18.         super.onCreate(savedInstanceState);  
  19.         getActionBar().setTitle(R.string.title_devices);  
  20.         mHandler = new Handler();  
  21.   
  22.         // Use this check to determine whether BLE is supported on the device.  Then you can  
  23.         // selectively disable BLE-related features.  
  24.         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {  
  25.             Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();  
  26.             finish();  
  27.         }  
  28.   
  29.         // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to  
  30.         // BluetoothAdapter through BluetoothManager.  
  31.         final BluetoothManager bluetoothManager =  
  32.                 (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);  
  33.         mBluetoothAdapter = bluetoothManager.getAdapter();  
  34.           
  35.         // Checks if Bluetooth is supported on the device.  
  36.         if (mBluetoothAdapter == null) {  
  37.             Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();  
  38.             finish();  
  39.             return;  
  40.         }  
  41.         //開啓藍牙  
  42.         mBluetoothAdapter.enable();  
  43.           
  44.         mBLE = new BluetoothLeClass(this);  
  45.         if (!mBLE.initialize()) {  
  46.             Log.e(TAG, "Unable to initialize Bluetooth");  
  47.             finish();  
  48.         }  
  49.         //發現BLE終端的Service時回調  
  50.         mBLE.setOnServiceDiscoverListener(mOnServiceDiscover);  
  51.         //收到BLE終端數據交互的事件  
  52.         mBLE.setOnDataAvailableListener(mOnDataAvailable);  
  53.     }  
  54.   
  55.   
  56.     @Override  
  57.     protected void onResume() {  
  58.         super.onResume();  
  59.   
  60.         // Initializes list view adapter.  
  61.         mLeDeviceListAdapter = new LeDeviceListAdapter(this);  
  62.         setListAdapter(mLeDeviceListAdapter);  
  63.         scanLeDevice(true);  
  64.     }  
  65.   
  66.     @Override  
  67.     protected void onPause() {  
  68.         super.onPause();  
  69.         scanLeDevice(false);  
  70.         mLeDeviceListAdapter.clear();  
  71.         mBLE.disconnect();  
  72.     }  
  73.   
  74.     @Override  
  75.     protected void onStop() {  
  76.         super.onStop();  
  77.         mBLE.close();  
  78.     }  
  79.       
  80.     @Override  
  81.     protected void onListItemClick(ListView l, View v, int position, long id) {  
  82.         final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);  
  83.         if (device == nullreturn;  
  84.         if (mScanning) {  
  85.             mBluetoothAdapter.stopLeScan(mLeScanCallback);  
  86.             mScanning = false;  
  87.         }  
  88.           
  89.         mBLE.connect(device.getAddress());  
  90.     }  
  91.   
  92.     private void scanLeDevice(final boolean enable) {  
  93.         if (enable) {  
  94.             // Stops scanning after a pre-defined scan period.  
  95.             mHandler.postDelayed(new Runnable() {  
  96.                 @Override  
  97.                 public void run() {  
  98.                     mScanning = false;  
  99.                     mBluetoothAdapter.stopLeScan(mLeScanCallback);  
  100.                     invalidateOptionsMenu();  
  101.                 }  
  102.             }, SCAN_PERIOD);  
  103.   
  104.             mScanning = true;  
  105.             mBluetoothAdapter.startLeScan(mLeScanCallback);  
  106.         } else {  
  107.             mScanning = false;  
  108.             mBluetoothAdapter.stopLeScan(mLeScanCallback);  
  109.         }  
  110.         invalidateOptionsMenu();  
  111.     }  
  112.   
  113.     /** 
  114.      * 搜索到BLE終端服務的事件 
  115.      */  
  116.     private BluetoothLeClass.OnServiceDiscoverListener mOnServiceDiscover = new OnServiceDiscoverListener(){  
  117.   
  118.         @Override  
  119.         public void onServiceDiscover(BluetoothGatt gatt) {  
  120.             displayGattServices(mBLE.getSupportedGattServices());  
  121.         }  
  122.           
  123.     };  
  124.       
  125.     /** 
  126.      * 收到BLE終端數據交互的事件 
  127.      */  
  128.     private BluetoothLeClass.OnDataAvailableListener mOnDataAvailable = new OnDataAvailableListener(){  
  129.   
  130.         /** 
  131.          * BLE終端數據被讀的事件 
  132.          */  
  133.         @Override  
  134.         public void onCharacteristicRead(BluetoothGatt gatt,  
  135.                 BluetoothGattCharacteristic characteristic, int status) {  
  136.             if (status == BluetoothGatt.GATT_SUCCESS)   
  137.                 Log.e(TAG,"onCharRead "+gatt.getDevice().getName()  
  138.                         +" read "  
  139.                         +characteristic.getUuid().toString()  
  140.                         +" -> "  
  141.                         +Utils.bytesToHexString(characteristic.getValue()));  
  142.         }  
  143.           
  144.         /** 
  145.          * 收到BLE終端寫入數據回調 
  146.          */  
  147.         @Override  
  148.         public void onCharacteristicWrite(BluetoothGatt gatt,  
  149.                 BluetoothGattCharacteristic characteristic) {  
  150.             Log.e(TAG,"onCharWrite "+gatt.getDevice().getName()  
  151.                     +" write "  
  152.                     +characteristic.getUuid().toString()  
  153.                     +" -> "  
  154.                     +new String(characteristic.getValue()));  
  155.         }  
  156.     };  
  157.   
  158.     // Device scan callback.  
  159.     private BluetoothAdapter.LeScanCallback mLeScanCallback =  
  160.             new BluetoothAdapter.LeScanCallback() {  
  161.   
  162.         @Override  
  163.         public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {  
  164.             runOnUiThread(new Runnable() {  
  165.                 @Override  
  166.                 public void run() {  
  167.                     mLeDeviceListAdapter.addDevice(device);  
  168.                     mLeDeviceListAdapter.notifyDataSetChanged();  
  169.                 }  
  170.             });  
  171.         }  
  172.     };  
  173.   
  174.     private void displayGattServices(List<BluetoothGattService> gattServices) {  
  175.         if (gattServices == nullreturn;  
  176.   
  177.         for (BluetoothGattService gattService : gattServices) {  
  178.             //-----Service的字段信息-----//  
  179.             int type = gattService.getType();  
  180.             Log.e(TAG,"-->service type:"+Utils.getServiceType(type));  
  181.             Log.e(TAG,"-->includedServices size:"+gattService.getIncludedServices().size());  
  182.             Log.e(TAG,"-->service uuid:"+gattService.getUuid());  
  183.               
  184.             //-----Characteristics的字段信息-----//  
  185.             List<BluetoothGattCharacteristic> gattCharacteristics =gattService.getCharacteristics();  
  186.             for (final BluetoothGattCharacteristic  gattCharacteristic: gattCharacteristics) {  
  187.                 Log.e(TAG,"---->char uuid:"+gattCharacteristic.getUuid());  
  188.                   
  189.                 int permission = gattCharacteristic.getPermissions();  
  190.                 Log.e(TAG,"---->char permission:"+Utils.getCharPermission(permission));  
  191.                   
  192.                 int property = gattCharacteristic.getProperties();  
  193.                 Log.e(TAG,"---->char property:"+Utils.getCharPropertie(property));  
  194.   
  195.                 byte[] data = gattCharacteristic.getValue();  
  196.                 if (data != null && data.length > 0) {  
  197.                     Log.e(TAG,"---->char value:"+new String(data));  
  198.                 }  
  199.   
  200.                 //UUID_KEY_DATA是可以跟藍牙模塊串口通信的Characteristic  
  201.                 if(gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA)){                    
  202.                     //測試讀取當前Characteristic數據,會觸發mOnDataAvailable.onCharacteristicRead()  
  203.                     mHandler.postDelayed(new Runnable() {  
  204.                         @Override  
  205.                         public void run() {  
  206.                             mBLE.readCharacteristic(gattCharacteristic);  
  207.                         }  
  208.                     }, 500);  
  209.                       
  210.                     //接受Characteristic被寫的通知,收到藍牙模塊的數據後會觸發mOnDataAvailable.onCharacteristicWrite()  
  211.                     mBLE.setCharacteristicNotification(gattCharacteristic, true);  
  212.                     //設置數據內容  
  213.                     gattCharacteristic.setValue("send data->");  
  214.                     //往藍牙模塊寫入數據  
  215.                     mBLE.writeCharacteristic(gattCharacteristic);  
  216.                 }  
  217.                   
  218.                 //-----Descriptors的字段信息-----//  
  219.                 List<BluetoothGattDescriptor> gattDescriptors = gattCharacteristic.getDescriptors();  
  220.                 for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {  
  221.                     Log.e(TAG, "-------->desc uuid:" + gattDescriptor.getUuid());  
  222.                     int descPermission = gattDescriptor.getPermissions();  
  223.                     Log.e(TAG,"-------->desc permission:"+ Utils.getDescPermission(descPermission));  
  224.                       
  225.                     byte[] desData = gattDescriptor.getValue();  
  226.                     if (desData != null && desData.length > 0) {  
  227.                         Log.e(TAG, "-------->desc value:"new String(desData));  
  228.                     }  
  229.                  }  
  230.             }  
  231.         }//  
  232.   
  233.     }  
  234. }  
發佈了22 篇原創文章 · 獲贊 33 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章