Android BLE開發——Android手機與BLE終端通訊初識

藍牙BLE官方Demo下載地址:   http://download.csdn.net/detail/lqw770737185/8116019
參考博客地址:    http://www.eoeandroid.com/thread-563868-1-1.html?_dsign=843d16d6html

 

     設備:MX5手機一臺,農藥殘留檢測儀一臺(BLE終端設備)android

     目的:實現手機控制儀器,如發送打印指令,儀器能進行打印操做等數組

 

      關於如何打開藍牙,配置相關權限,搜索BLE設備等步驟網上有不少資料,這裏就很少作做解釋了,本文主要講通訊方面的內容。須要注意的是搜索BLE設備的結果是異步返回的,在BluetoothAdapter.LeScanCallback這個回調中返回,而且搜索過程是一個很是耗電的過程,因此咱們應該作好相應處理,例如可讓它搜索10s就中止搜索等。異步

      在咱們理解Android設備與BLE終端設備通訊過程以前,咱們須要來先了解幾個類:ide

      BluetoothGatt:BluetoothGatt 是咱們用的最多,也是咱們最重要的一個類,爲了儘量通俗的理解,這裏咱們能夠把它當作Android手機與BLE終端設備創建通訊的一個管道,只有有了這個管道,咱們纔有了通訊的前提。函數

      BluetoothGattService:藍牙設備的服務,在這裏咱們把BluetoothGattService比喻成班級。而Bluetoothdevice咱們把它比喻成學校,一個學校裏面能夠有不少班級,也就是說咱們每臺BLE終端設備擁有多個服務,班級(各個服務)之間經過UUID(惟一標識符)區別。ui

      BluetoothGattCharacteristic: 藍牙設備所擁有的特徵,它是手機與BLE終端設備交換數據的關鍵,咱們作的全部事情,目的就是爲了獲得它。在這裏咱們把它比喻成學生,一個班級裏面有不少個學生,也就是說咱們每一個服務下擁有多個特徵,學生(各個特徵)之間經過UUID(惟一標識符)區別。this

      總結:當咱們想要用手機與BLE設備進行通訊時,實際上也就至關於咱們要去找一個學生交流,首先咱們須要搭建一個管道,也就是咱們須要先獲取獲得一個BluetoothGatt,其次咱們須要知道這個學生在哪個班級,學號是什麼,這也就是咱們所說的serviceUUID,和charUUID。這裏咱們還須要注意一下,找到這個學生後並非直接和他交流,他就好像一箇中介同樣,在手機和BLE終端設備之間幫助這二者傳遞着信息,咱們手機所發數據要先通過他,在由他傳遞到BLE設備上,而BLE設備上的返回信息,也是先傳遞到他那邊,而後手機再從他那邊進行讀取。spa

      Android手機與BLE終端設備通訊結果都是以回調的形式返回,以下是幾個常見的返回回調(可見於官方Demo的BluetoothLeservice類):.net

複製代碼
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {

        //鏈接狀態改變的回調
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status,
                int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                // 鏈接成功後啓動服務發現
                Log.e("AAAAAAAA", "啓動服務發現:" + mBluetoothGatt.discoverServices());
            }
        };

        //發現服務的回調
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {                                   
                 Log.e(TAG, "成功發現服務");
                           }else{
                   Log.e(TAG, "服務發現失敗,錯誤碼爲:" + status);
                        }
        };
                 
        //寫操做的回調
        public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                  Log.e(TAG, "寫入成功" +characteristic.getValue());
                       }
               };
          
       //讀操做的回調
       public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                    Log.e(TAG, "讀取成功" +characteristic.getValue());
                    }
                }
                
      //數據返回的回調(此處接收BLE設備返回數據)
      public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {
                };
            };
      }
複製代碼

1、鏈接藍牙BLE終端設備

       在咱們打開藍牙,掃描發現想要鏈接的設備後,接下來要作的,固然就是去鏈接它了,鏈接方法很簡單,咱們一句代碼就能夠實現了(以下)。能夠發現,當咱們開始鏈接BLE終端設備的時候,鏈接方法就自動就幫咱們返回了一個BluetoothGatt對象了,前面咱們說到BluetoothGatt是咱們最重要的一個類,它至關於一個管道,是咱們創建通訊的前提:(這裏面有三個參數,第一個參數是上下文對象,第二個參數是是否自動鏈接,這裏設置爲false,第三個參數就是上面的回調方法)

mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

鏈接成功與否都會經過下面這個回調來告訴咱們:

複製代碼
// 鏈接狀態改變的回調
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status,
                int newState) {
                        //表明鏈接成功,此處咱們能夠發送一個廣播回去告訴activity已成功鏈接
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                //鏈接成功後啓動服務發現
                Log.e("AAAAAAAA", "啓動服務發現:" + mBluetoothGatt.discoverServices());
            }
        }
複製代碼

2、啓動服務發現

 鏈接成功後,咱們就要去尋找咱們所須要的服務,這裏須要先啓動服務發現,使用一句代碼便可:

mBluetoothGatt.discoverServices() ;

啓動服務發現,它的結果也是經過回調函數返回:

複製代碼
        // 發現服務的回調
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {      
            //成功發現服務後能夠調用相應方法獲得該BLE設備的全部服務,而且打印每個服務的UUID和每一個服務下各個特徵的UUID
            if (status == BluetoothGatt.GATT_SUCCESS) {
                    List<BluetoothGattService> supportedGattServices =mBluetoothGatt.getServices();
                    for(int i=0;i<supportedGattServices.size();i++){
                       Log.e("AAAAA","1:BluetoothGattService UUID=:"+supportedGattServices.get(i).getUuid());
                       List<BluetoothGattCharacteristic> listGattCharacteristic=supportedGattServices.get(i).getCharacteristics();
                       for(int j=0;j<listGattCharacteristic.size();j++){
                                Log.e("a","2:   BluetoothGattCharacteristic UUID=:"+listGattCharacteristic.get(j).getUuid());
                                    }
                                 }
            } else {
                Log.e("AAAAA", "onservicesdiscovered收到: " + status);
            }
        }
複製代碼

咱們也能夠經過調用下面方法得知每一個特徵所具備的屬性:可讀或者可寫或者具有通知功能或者都具有等

複製代碼
// 循環遍歷服務以及每一個服務下面的各個特徵,判斷讀寫,通知屬性
        for (BluetoothGattService gattService :supportedGattServices) {
            List<BluetoothGattCharacteristic> gattCharacteristics =supportedGattServices.getCharacteristics();
            for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                int charaProp = gattCharacteristic.getProperties();
                if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
                    // Log.e("nihao","gattCharacteristic的UUID爲:"+gattCharacteristic.getUuid());
                    // Log.e("nihao","gattCharacteristic的屬性爲:  可讀");
                }
                if ((charaProp | BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
                    // Log.e("nihao","gattCharacteristic的UUID爲:"+gattCharacteristic.getUuid());
                    // Log.e("nihao","gattCharacteristic的屬性爲:  可寫");
                }
                if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
                    // Log.e("nihao","gattCharacteristic的UUID爲:"+gattCharacteristic.getUuid()+gattCharacteristic);
                    // Log.e("nihao","gattCharacteristic的屬性爲:  具有通知屬性");
                }

            }
        }
複製代碼

3、獲取Characteristic

       以前咱們說過,咱們的最終目的就是獲取Characteristic來進行通訊,正常狀況下,咱們能夠從硬件工程師那邊獲得serviceUUID和characteristicUUID,也就是咱們所比喻的班級號和學號,以此來得到咱們的characteristic,但若是咱們沒法得知這兩個所需的UUID時,咱們也能夠經過上一步的方法來獲取(打印全部特徵UUID,取出本身想要的特徵)。此次試驗我就是經過此方法得到,可是經過打印日誌發現,雖然我這邊的BLE終端它每一個服務下的全部特徵都具備可讀可寫可通知屬性,可是隻有characteristicUUID="0000ffe1-0000-1000-8000-00805f9b34fb"這個特徵UUID能進行通訊,它對應的serviceUUID="0000ffe0-0000-1000-8000-00805f9b34fb",暫且就先用這個,反正一個能用就行。假設咱們在知道serviceUUID和characteristicUUID的前提下,咱們就能夠經過下面代碼獲取相應特徵值:  

BluetoothGattService service = mBluetoothGatt.getService(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"));
BluetoothGattCharacteristic characteristic= service.getCharacteristic(UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));

4、開始通訊

       咱們在獲得一個相應的特徵之後,接下來就能夠開始讀寫操做進行通訊了。

      a.讀操做,讀操做比較簡單,只需將相應的特徵值傳入便可獲得該特徵值下的數據,以下代碼:       

mBluetoothGatt.readCharacteristic(characteristic);

讀取的結果經過onCharacteristicRead回調返回:(經過characteristic.getValue()就能夠獲得讀取到的值了)

複製代碼
    // 讀操做的回調
        public void onCharacteristicRead(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.e(TAG, "讀取成功" +characteristic.getValue());
            }
        }
複製代碼

       b.寫操做,寫操做是咱們的重點,咱們能夠經過向characteristic寫入指令(發送指令)以此來達到控制BLE終端設備的目的:

                           //將指令放置進特徵中
                            characteristic.setValue(new byte[] {0x7e, 0x14, 0x00, 0x00,0x00,(byte) 0xaa});
                           //設置回覆形式
                           characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
                           //開始寫數據
                           mBluetoothGatt.writeCharacteristic(chharacteristic);

注:與儀器通訊,咱們這裏發送的是16進制的數據,發送的時候須要先將其裝載到byte[]數組中,例如我發送 7e 14 00 00 00 aa這個指令,我須要把它轉化爲ew byte[] {0x7e, 0x14, 0x00, 0x00,0x00,(byte) 0xaa }這樣去發送,由於BLE傳輸過程每次最大隻能傳輸20個字節,因此若是發送的指令大於20字節的話要分包發送,例如如今要發送28個字節的,能夠先write(前20個字節),開啓線程sleep(幾十毫秒)後在write(後面8個字節)

5、BLE終端設備返回數據
       當咱們向BLE終端設備寫入指令時,若是寫入成功而且指令也正確,咱們就會得到相應的響應指令,在下面這個回調中咱們能夠獲得BLE設備返回回來的響應指令(經過characteristic.getValue()取出返回數據):

    // 數據返回的回調(此處接收機器返回數據並做處理)
        public void onCharacteristicChanged(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic) {
            Log.e("AAAAAAAA",characteristic.getValue());
        };

接收到返回數據的前提是咱們設置了該特徵具備Notification功能,因此完整的寫操做代碼應該是這樣的(注意設置特徵Notification的代碼要放在最前):

複製代碼
           mBluetoothGatt.setCharacteristicNotification(characteristic,true)
           //將指令放置進來
           characteristic.setValue(new byte[] {0x7e, 0x14, 0x00, 0x00,0x00,(byte) 0xaa});
           //設置回覆形式
           characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
           //開始寫數據
           mBluetoothGatt.writeCharacteristic(chharacteristic);
複製代碼

  以上就是本身對Android手機與BLE設備通訊一些初步認識,若是有哪裏說的不正確,還請指正。

相關文章
相關標籤/搜索