Android 低功耗藍牙(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后要分解成所用的組合(本文代碼已含此分解方法)。

處理Service發送過來的各種時間.

ACTION_GATT_CONNECTED: 連接上了一個GATT服務.
ACTION_GATT_DISCONNECTED: 斷開了一個GATT服務.
ACTION_GATT_SERVICES_DISCOVERED: 發現了GATT服務.
ACTION_DATA_AVAILABLE: 從設備接收到數據. 這里可能是一個讀取或者通知操作的結果。

BluetoothAdapter.ACTION_STATE_CHANGED 藍牙狀態值發生改變
BluetoothAdapter.ACTION_SCAN_MODE_CHANGED 藍牙掃描狀態(SCAN_MODE)發生改變
BluetoothAdapter.ACTION_DISCOVERY_STARTED 藍牙掃描過程開始
BluetoothAdapter.ACTION_DISCOVERY_FINISHED 藍牙掃描過程結束
BluetoothAdapter. ACTION_LOCAL_NAME_CHANGED 藍牙設備Name發生改變
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE 請求用戶選擇是否使該藍牙能被掃描
PS:如果藍牙沒有開啟,用戶點擊確定后,會首先開啟藍牙,繼而設置藍牙能被掃描。
BluetoothAdapter. ACTION_REQUEST_ENABLE 請求用戶選擇是否打開藍牙

BluetoothDevice.ACTION_FOUND (該常量字段位于BluetoothDevice類中,稍后講到)
說明:藍牙掃描時,掃描到任一遠程藍牙設備時,會發送此廣播。

private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
            mConnected = true;
            updateConnectionState(R.string.connected);
            invalidateOptionsMenu();

        } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
            mConnected = false;
            updateConnectionState(R.string.disconnected);
            invalidateOptionsMenu();
            clearUI();

        } else if (BluetoothLeService.
                ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
            // 顯示所有支持的service和characteristic。
            displayGattServices(mBluetoothLeService.getSupportedGattServices());

        } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
            displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));

        }else  if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
                addBandDevices(device);
            } else {
                addUnbondDevices(device);
            }
        }
    }
};

1、BluetoothAdapter STATE 狀態值 , 即開關狀態

          int STATE_OFF        藍牙已經關閉
          int STATE_ON        藍牙已經打開
          int STATE_TURNING_OFF      藍牙處于關閉過程中 ,關閉ing
          int STATE_TURNING_ON        藍牙處于打開過程中 ,打開ing

2、在這里首先要了解對藍牙操作一個核心類BluetoothAdapter

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();  
//直接打開系統的藍牙設置面板  
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
startActivityForResult(intent, 0x1);  
//直接打開藍牙  
adapter.enable();  
//關閉藍牙  
adapter.disable();  
//打開本機的藍牙發現功能(默認打開120秒,可以將時間最多延長至300秒)  
Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);//設置持續時間(最多300秒)  

3、搜索藍牙設備

使用BluetoothAdapter的startDiscovery()方法來搜索藍牙設備
startDiscovery()方法是一個異步方法,調用后會立即返回。該方法會進行對其他藍牙設備的搜索,該過程會持續12秒。該方法調用后,搜索過程實際上是在一個System Service中進行的,所以可以調用cancelDiscovery()方法來停止搜索(該方法可以在未執行discovery請求時調用)。

請求Discovery后,系統開始搜索藍牙設備,在這個過程中,系統會發送以下三個廣播:
ACTION_DISCOVERY_START:開始搜索
ACTION_DISCOVERY_FINISHED:搜索結束
ACTION_FOUND:找到設備,這個Intent中包含兩個extra fields:EXTRA_DEVICE和EXTRA_CLASS,分別包含BluetooDevice和BluetoothClass。



GATT層中定義的所有屬性都有一個UUID值,UUID是全球唯一的128位的號碼,它用來識別不同的特性。
首先來說明一下含義:
GATT(Generic Attribute Profile),通用屬性配置文件,其中的數據都是實際發送的,也就是藍牙事件所產生的協議棧事件都是在這里發生的。
UUID(Universally Unique Identifier),通用唯一識別碼。
UUID一般可以分為兩種:1、藍牙技術聯盟UUIDs;2、供應商特定的UUID

1、藍牙技術聯盟UUIDs

藍牙核心規范制定了兩種不同的UUID,1、基本的UUID;2、代替基本UUID的16位UUID。

注意:所有的藍牙技術聯盟定義UUID共用了一個基本的UUID:0x0000xxxx-0000-1000-8000-00805F9B34FB。總共128位,換算成8位位組(octet)也就是16個8位位組(8*16=128嘛)。為了進一步簡化基本UUID,每一個藍牙技術聯盟定義的屬性有一個唯一的16位UUID,以代替上面的基本UUID的‘x’部分,也就是第12、13個八位位組。

2、供應商特定的UUID

與藍牙技術聯盟定義的UUID類似,供應商特定的UUID也有基本UUID和16位的UUID(類似一個別名,再加載在基本UUID之上)。基本UUID由nRFgo Studio產生,16位UUID可以按照自己的意圖來任意分配。
因此,按照上述原則,nRF51822的SDK關于UUID的數據結構如下所示:

/** @brief 128 bit UUID values. */  
typedef struct  
{   
    unsigned char uuid128[16];  
} ble_uuid128_t;  

/** @brief  Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */  
typedef struct  
{  
    uint16_t    uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */  
    uint8_t     type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is   BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */  
} ble_uuid_t;  

結構體ble_uuid128_t內部只有一個結構體成員,其中結構體成員為一個包含16個無符號字符型元素的一維數組,也就是16個8位位組,剛好能夠表示128位UUID。
按照SDK中的注釋,結構體ble_uuid_t是低功耗藍牙UUID類型,壓縮了16位和128位UUID。其中,包含兩個結構體成員,1、無符號16位整型數uuid,也就是16位UUID值或者128位UUID的第12-13個八位位組;2、無符號8位整型數type,也就是UUID類型,其值有如下三種情況:

/** @defgroup BLE_UUID_TYPES Types of UUID 
 * @{ */  
        #define BLE_UUID_TYPE_UNKNOWN       0x00 /**< Invalid UUID type. */  
        #define BLE_UUID_TYPE_BLE           0x01 /**< Bluetooth SIG UUID (16-bit). */  
        #define BLE_UUID_TYPE_VENDOR_BEGIN  0x02 /**< Vendor UUID types start at this index (128-bit). */  
/** @} */  

1、BLE_UUID_TYPE_UNKNOWN:不可用的UUID類型,這也與ble_uuid_t中的如果類型是BLE_UUID_TYPE_UNKNOWN,UUID值是未定義的。
2、BLE_UUID_TYPE_BLE:藍牙興趣小組的UUID。
3、BLE_UUID_TYPE_VENDOR_BEGIN:供應商UUID類型開始在這個指針(128位)。

通過如下協議棧函數可以添加一個供應商特定的UUID。
uint32_t sd_ble_uuid_vs_add| ( ble_uuid128_t const *const p_vs_uuid)

Note
Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by the 16-bit uuid field inble_uuid_t

Parameters

[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific UUID disregarding bytes 12 and 13.
[out] p_uuid_type Pointer where the type field inble_uuid_tcorresponding to this UUID will be stored.

由注意可以知道,提供的UUID的12、13字節并不會被內部直接使用,因為他們通常被ble_uuid_t中的16位UUID位域代替。


5、手機的BLE默認有2個服務

(1)Service 通用屬性規范 00001801-0000-1000-8000-00805f9b34fb (null) 
         a)Characteristic 服務改變 00002a05-0000-1000-8000-00805f9b34fb 
(2)Service 通用接入規范 00001800-0000-1000-8000-00805f9b34fb 
         a)Characteristic 設備名稱 00002a00-0000-1000-8000-00805f9b34fb 
         b)Characteristic 設備外觀 00002a01-0000-1000-8000-00805f9b34fb (00 00) 
         c)Characteristic 設備外觀 00002aa6-0000-1000-8000-00805f9b34fb (01) 

注意:因為00002aa6不在定義中,因此可以認為是廠商或者用戶自定義的特征(或服務)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容