免費論壇 繁體 | 簡體
Sclub交友聊天~加入聊天室當版主
分享
返回列表 回復 發帖

BLE 參考資料

最後帶一下一種滿好用的 AD Type, 叫作 Service UUID, 是一個很值得被善用的 AD Type, 如下所示, 會有 16-bit, 32-bit 以及 128-bit  三種

128-bit UUID 是完整的 UUID, 如下所示

75BEB663-74FC-4871-9737-AD184157450E

而 32-bit 則是基於 Bluetooth base UUID 後只改變前 32 bits, 如下所示

XXXXXXXX-0000-1000-8000-00805F9B34FB

而 16-bit 則是如下所示填入 XXXX 的這 16-bit 資料的結果就是實際 UUID 的內容

0000XXXX-0000-1000-8000-00805F9B34FB


參考連結
BLE物理層



在我們討論如何發送廣告包之前,我們想談談BLE物理層。物理層負責實際通過空中發送信號。這包括實際的RF無線電。
藍牙低功耗與經典藍牙有一些相似之處。兩者都使用2.4GHz頻譜。基本速率(BR)和BLE都使用1Mbps的GFSK調製,但它們的調製指數不同。增強數據速率(EDR)使用與GFSK完全不同的調製。與LE的40個頻道相比,經典藍牙有79個頻道。通道的間隔也不同。這兩種差異使LE和Classic不同且不兼容,因此無法進行通信。雙模式無線電,如CC256x,通過切換調製參數及其運行的通道來支持LE和Classic。

藍牙的2.4GHz頻譜從2402MHz擴展到2480MHz。LE使用40個1MHz寬的通道,編號為0到39.每個通道間隔2MHz。
信道37,38和39僅用於發送廣告分組。其餘用於連接期間的數據交換。我們對這3個頻道中發生的事情感興趣,這就是我們將在這裡介紹的內容。
在BLE通告期間,BLE外圍設備一個接一個地在3個廣告信道上發送分組。掃描設備或信標的中央設備將收聽廣告數據包的這些頻道,這有助於它發現附近的設備。
信道37,38和39故意分佈在2.4GHz頻譜上。37和39是樂隊中的第一個和最後一個頻道,而38則在中間。如果任何單個廣告頻道被阻止,其他頻道可能是免費的,因為它們被相當於幾MHz的帶寬分開。
這尤其正確,因為大多數干擾BLE的其他設備都是窄帶。特別是通道38放置在Wi-Fi信道1和6之間,因此它避免了Wi-Fi信號。廣告頻道的寬間距有助於BLE更好地管理來自Wi-Fi,經典藍牙,微波爐,嬰兒監視器等的干擾,以確保廣告成功。



Android 蓝牙 BLE 开发笔记Android 蓝牙 BLE 开发笔记
最近公司头戴换了一块蓝牙4.0 BLE模块,所以我们Android组要适配 BLE。
Android BLE 需要 4.3 以上系统,api 还是非常简单的, 第一步就是扫描, 扫描到设备后就可以连接了,
连接成功后在 onServicesDiscovered 中拿到 Service Characteristic Descriptor 就可以了。
不过还是遇到了几个小坑
第一: setCharacteristicNotification 时 onCharacteristicChanged 中收不到回调 原因是 BLE 不能连续执行写操作,必须等前一个
写完了再写一下个, 所以应该维护一个队列等前一个写完了再写下一个。

启用通知

复制代码
BluetoothGattCharacteristic rxCharacteristic = uartService
        .getCharacteristic(UUID.fromString(BleConst.UUID_RX_CHARACTERISTIC));
if (rxCharacteristic != null) {
    BluetoothGattDescriptor rxCharacteristicDescriptor = rxCharacteristic
            .getDescriptor(UUID.fromString(BleConst.UUID_RX_CHARACTERISTIC_DESCRIPTOR));
    // 设置 Characteristic 可以接收通知
    gatt.setCharacteristicNotification(rxCharacteristic, true);
    if (rxCharacteristicDescriptor != null) {
        // enable descriptor notification
        rxCharacteristicDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        mBluetoothGatt.writeDescriptor(rxCharacteristicDescriptor);
    }
}
复制代码
第二:蓝牙自动配对
自动配对就是通过反射去调用 BluetoothDevice 的 createBond 方法

Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
createBondMethod.invoke(btDevice);
第三:蓝牙自动连接
配对和连接是不一样的,自动配对后还要连接上蓝牙, stackoverflow 查了一些下面的方法可以自动连接 A2DP 和 HFP 两个 profile
监听 BluetoothDevice.ACTION_BOND_STATE_CHANGED 广播,蓝牙配对成功后调用下面的方法连接上两个 profile 就行了。

复制代码
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    adapter.getProfileProxy(this, new BluetoothProfile.ServiceListener() {
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            try {
                Log.d(TAG, "a2dp onServiceConnected");
                Method connect = BluetoothA2dp.class.getDeclaredMethod("connect", BluetoothDevice.class);
                connect.invoke(proxy, device);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(int profile) {
            Log.d(TAG, "a2dp onServiceDisconnected");
        }
    }, BluetoothProfile.A2DP);

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        adapter.getProfileProxy(this, new BluetoothProfile.ServiceListener() {
            @Override
            public void onServiceConnected(int profile, BluetoothProfile proxy) {
                try {
                    Log.d(TAG, "hfp onServiceConnected");
                    Method connect = BluetoothHeadset.class.getDeclaredMethod("connect", BluetoothDevice.class);
                    connect.invoke(proxy, device);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(int profile) {
                Log.d(TAG, "hfp onServiceDisconnected");
            }
        }, BluetoothProfile.HEADSET);
复制代码
目前头戴所有按键走的都是蓝牙自定义协议,本来Android是可以用 HID 标准键值的, 但由于 IOS 不支持 HID 所已也走自定义协议。

-------------------------------------------------------------------https://stackoverflow.com/questions/36918109/android-ble-list-of-discovered-characteristics-in-service-is-incomplete
Attemptingto read characteristics from a GATT service, the list is incomplete compared tothe list I get from an iOS device, or the manufacturer guide.
I amreading the characteristics as follows:

private
final
BluetoothGattCallback mGattCallback = new
BluetoothGattCallback() {

@Override

public
void onConnectionStateChange(BluetoothGatt gatt, int status,

int newState) {

if (newState == BluetoothProfile.STATE_CONNECTED) {

mConnectionState =STATE_CONNECTED;


mBluetoothGatt = gatt;


if (shouldStartWriting &&writeCharacteristicsQueue.peek() != null) {

mBluetoothGatt.writeCharacteristic(writeCharacteristicsQueue.poll());


}
else {

EventBus.getDefault().post(new
BTGattStatusEvent(BTGattStatusEvent.Status.CONNECTED));

Log.i(TAG, "Attempting to start service discovery:" +

gatt.discoverServices());


}



}
else
if (newState == BluetoothProfile.STATE_DISCONNECTED) {

mConnectionState =STATE_DISCONNECTED;


mBluetoothGatt =
null;

EventBus.getDefault().post(new
BTGattDisconnectedEvent());

}


}



@Override

// New services discovered

public
void onServicesDiscovered(BluetoothGatt gatt, int status) {

EventBus.getDefault().post(new
BTGattStatusEvent(BTGattStatusEvent.Status.DISCOVERED));


if (status == BluetoothGatt.GATT_SUCCESS) {

for (BluetoothGattService service :gatt.getServices()) {

LOGD(TAG,
"Found Service " + service.getUuid().toString());

discoverCharacteristics(service);


}


gatt.readCharacteristic(readCharacteristicsQueue.poll());


}
else {

Log.w(TAG, "onServicesDiscovered received: " + status);

}


}



@Override

// Result of acharacteristic read operation

public
void onCharacteristicRead(BluetoothGatt gatt,

BluetoothGattCharacteristic characteristic,

int status) {

if (status == BluetoothGatt.GATT_SUCCESS) {

parseCharacteristic(characteristic);


LOGD(TAG,
String.format("%s | %s ", characteristic.getUuid(),characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 0)));//(BluetoothGattCharacteristic.FORMAT_UINT16));


if (readCharacteristicsQueue.peek() != null) {

gatt.readCharacteristic(readCharacteristicsQueue.poll());


}
else {

EventBus.getDefault().post(new
BTGattStatusEvent(BTGattStatusEvent.Status.DONE_DISCOVERING));

}


}


}

private
void discoverCharacteristics(BluetoothGattService service)
{
for
(BluetoothGattCharacteristic gattCharacteristic : service.getCharacteristics())
{
LOGD
(TAG,
"Discovered UUID: "
+ gattCharacteristic.getUuid());
readCharacteristicsQueue
.add(gattCharacteristic);
} }

I also attempted to get this characteristic using getCharacteristic, but Ireceived a null.
Thecharacteristics found are:
Discovered UUID:
0000fff1-0000-1000-8000-00805f9b34fbDiscovered UUID:
0000fff2-0000-1000-8000-00805f9b34fbDiscovered UUID:
0000fff3-0000-1000-8000-00805f9b34fbDiscovered UUID:
0000fff4-0000-1000-8000-00805f9b34fbDiscovered UUID:
0000fff5-0000-1000-8000-00805f9b34fb
------------------------------------------------------------------------------------------------------------------


https://blog.csdn.net/mapeifan/article/details/50113669

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;


import com.example.bledemo.BLEService;
import com.example.bledemo.R;
importcom.example.bledemo.SampleGattAttributes;


import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.bluetooth.BluetoothGattCharacteristic;
importandroid.bluetooth.BluetoothGattService;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ExpandableListView;
importandroid.widget.SimpleExpandableListAdapter;
import android.widget.TextView;


public class ScanDeviceActivity extendsActivity {

privatefinal static String TAG = ScanDeviceActivity.class

.getSimpleName();

publicstatic final String EXTRAS_DEVICE_NAME = "DEVICE_NAME";

publicstatic final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";



privateTextView mConnectionState;

privateTextView mDataField;

privateString mDeviceName;

privateString mDeviceAddress;

privateExpandableListView mGattServicesList;
//listview
下拉清單

privateBLEService mBluetoothLeService;

privateArrayList<ArrayList<BluetoothGattCharacteristic>>mGattCharacteristics = newArrayList<ArrayList<BluetoothGattCharacteristic>>();

privateboolean mConnected = false;

privateBluetoothGattCharacteristic mNotifyCharacteristic;



privatefinal String LIST_NAME = "NAME";

privatefinal String LIST_UUID = "UUID";



//Code to manage Service lifecycle.

//代碼管理服務生命週期

privatefinal ServiceConnection mServiceConnection = new ServiceConnection() {



@Override

publicvoid onServiceConnected(ComponentName componentName,

IBinderservice) {

mBluetoothLeService= ((BLEService.LocalBinder) service)

.getService();

if(!mBluetoothLeService.initialize()) {

Log.e(TAG,"Unable to initialize Bluetooth"); //無法初始化藍牙

finish();

}

//Automatically connects to the device upon successful start-up

//initialization.自動連接到設備成功啟動初始化

mBluetoothLeService.connect(mDeviceAddress);

}



@Override

publicvoid onServiceDisconnected(ComponentName componentName) {

mBluetoothLeService= null;

}

};



//Handles various events fired by the Service.

//ACTION_GATT_CONNECTED: connected to a GATT server.

//ACTION_GATT_DISCONNECTED: disconnected from a GATT server.

//ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.

//ACTION_DATA_AVAILABLE: received data from the device. This can be a

//result of read

//or notification operations.

//處理各種事件的發射服務。

//ACTION_GATT_CONNECTED:連接到一個伺服器關貿總協定。

//ACTION_GATT_DISCONNECTED:從關貿總協定伺服器斷開連接。

//ACTION_GATT_SERVICES_DISCOVERED:關貿總協定發現服務。

//ACTION_DATA_AVAILABLE:從設備接收的資料。這可能是一個

//讀取的結果

//或通知操作。

privatefinal BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {

@TargetApi(Build.VERSION_CODES.HONEYCOMB)

@SuppressLint("NewApi")

@Override

publicvoid onReceive(Context context, Intent intent) {

finalString action = intent.getAction();

System.out.println("action= " + action);

//連接到一個GATT server

if(BLEService.ACTION_GATT_CONNECTED.equals(action)) {

mConnected= true;

updateConnectionState(R.string.connected);

invalidateOptionsMenu();

//GATT server斷開連接

}else if (BLEService.ACTION_GATT_DISCONNECTED

.equals(action)){

mConnected= false;

updateConnectionState(R.string.disconnected);

invalidateOptionsMenu();

clearUI();

//發現GATT services

}else if (BLEService.ACTION_GATT_SERVICES_DISCOVERED

.equals(action)){

//Show all the supported services and characteristics on the

//user interface.

displayGattServices(mBluetoothLeService

.getSupportedGattServices());

//從設備接收的資料。這可能是一個讀取的結果或通知操作。

}else if (BLEService.ACTION_DATA_AVAILABLE.equals(action)) {

displayData(intent.getStringExtra(BLEService.EXTRA_DATA));

}

}

};



//If a given GATT characteristic is selected, check for supported features.

//This sample

//demonstrates 'Read' and 'Notify' features. See

//http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for

//the complete
下拉清單的點擊事件

//list of supported characteristic features.

@SuppressLint("NewApi")

privatefinal ExpandableListView.OnChildClickListener servicesListClickListner = newExpandableListView.OnChildClickListener() {

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)

@SuppressLint("NewApi")

@Override

publicboolean onChildClick(ExpandableListView parent, View v,

intgroupPosition, int childPosition, long id) {



if(mGattCharacteristics != null) {

finalBluetoothGattCharacteristic characteristic = mGattCharacteristics

.get(groupPosition).get(childPosition);

finalint charaProp = characteristic.getProperties();

System.out.println("charaProp= " + charaProp + ",UUID = "

+characteristic.getUuid().toString());

Randomr = new Random();



if(characteristic.getUuid().toString()

.equals("0000fff2-0000-1000-8000-00805f9b34fb")){

inttime= 0;


while((time=r.nextInt(9))<=0){



}



Stringdata = time+","+"1,,,,,";

characteristic.setValue(data.getBytes());

mBluetoothLeService.wirteCharacteristic(characteristic);

}



if(characteristic.getUuid().toString()


.equals("0000fff1-0000-1000-8000-00805f9b34fb")){

intR = r.nextInt(255);

intG = r.nextInt(255);

intB = r.nextInt(255);

intBB = r.nextInt(100);

Stringdata = R + "," + G + "," + B + "," + BB;

while(data.length() < 18) {


data += ",";

}

System.out.println(data);

characteristic.setValue(data.getBytes());

mBluetoothLeService.wirteCharacteristic(characteristic);

}

if(characteristic.getUuid().toString()

.equals("0000fff3-0000-1000-8000-00805f9b34fb")){

intR = r.nextInt(255);

intG = r.nextInt(255);

intB = r.nextInt(255);

intBB = r.nextInt(100);

Stringdata = R + "," + G + "," + B + "," + BB;

while(data.length() < 18) {

data+= ",";

}

System.out.println("RT");

characteristic.setValue("RT".getBytes());

mBluetoothLeService.wirteCharacteristic(characteristic);

}

if(characteristic.getUuid().toString()

.equals("0000fff5-0000-1000-8000-00805f9b34fb")){

characteristic.setValue("S".getBytes());

mBluetoothLeService.wirteCharacteristic(characteristic);

System.out.println("sendS");

}else {



if((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {

//If there is an active notification on a

//characteristic, clear

//it first so it doesn't update the data field on the

//user interface.

if(mNotifyCharacteristic != null) {

mBluetoothLeService.setCharacteristicNotification(

mNotifyCharacteristic,false);

mNotifyCharacteristic= null;

}

mBluetoothLeService.readCharacteristic(characteristic);



}

}

if((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {



if(characteristic.getUuid().toString().equals("0000fff6-0000-1000-8000-00805f9b34fb")||characteristic.getUuid().toString().equals("0000fff4-0000-1000-8000-00805f9b34fb")){

System.out.println("enablenotification");

mNotifyCharacteristic= characteristic;

mBluetoothLeService.setCharacteristicNotification(

characteristic,true);




}

}



returntrue;

}

returnfalse;

}

};



privatevoid clearUI() {

mGattServicesList.setAdapter((SimpleExpandableListAdapter)null);

mDataField.setText(R.string.no_data);

}



@TargetApi(Build.VERSION_CODES.HONEYCOMB)

@SuppressLint("NewApi")

@Override

publicvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.scandevice);



finalIntent intent = getIntent();

mDeviceName= intent.getStringExtra(EXTRAS_DEVICE_NAME);

mDeviceAddress= intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);



//Sets up UI references.設置介面的引用

((TextView)findViewById(R.id.device_address)).setText(mDeviceAddress);

mGattServicesList= (ExpandableListView) findViewById(R.id.gatt_services_list);

mGattServicesList.setOnChildClickListener(servicesListClickListner);

mConnectionState= (TextView) findViewById(R.id.connection_state);

mDataField= (TextView) findViewById(R.id.data_value);



getActionBar().setTitle(mDeviceName);

getActionBar().setDisplayHomeAsUpEnabled(true);

IntentgattServiceIntent = new Intent(this, BLEService.class);

booleanbll = bindService(gattServiceIntent, mServiceConnection,

BIND_AUTO_CREATE);

if(bll) {

System.out.println("---------------");

}else {

System.out.println("===============");

}

}


//在整個Activity的生命週期的onResume狀態時,註冊廣播 ,檢查BluetoothLeService的連結情況,如果空,則連結

@Override

protectedvoid onResume() {

super.onResume();
//
註冊廣播

registerReceiver(mGattUpdateReceiver,makeGattUpdateIntentFilter());



if(mBluetoothLeService != null) {

finalboolean result = mBluetoothLeService.connect(mDeviceAddress);

Log.d(TAG,"Connect request result=" + result);

}

}
//取消註冊廣播

@Override

protectedvoid onPause() {

super.onPause();

unregisterReceiver(mGattUpdateReceiver);

}
//解除 綁定的 service

@Override

protectedvoid onDestroy() {

super.onDestroy();

unbindService(mServiceConnection);

mBluetoothLeService= null;

}



@Override

publicboolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.gatt_services,menu);

if(mConnected) {

menu.findItem(R.id.menu_connect).setVisible(false);

menu.findItem(R.id.menu_disconnect).setVisible(true);

}else {

menu.findItem(R.id.menu_connect).setVisible(true);

menu.findItem(R.id.menu_disconnect).setVisible(false);

}

returntrue;

}



@Override

publicboolean onOptionsItemSelected(MenuItem item) {

switch(item.getItemId()) {

caseR.id.menu_connect:

mBluetoothLeService.connect(mDeviceAddress);

returntrue;

caseR.id.menu_disconnect:

mBluetoothLeService.disconnect();

returntrue;

caseandroid.R.id.home:

onBackPressed();

returntrue;

}

returnsuper.onOptionsItemSelected(item);

}



privatevoid updateConnectionState(final int resourceId) {

runOnUiThread(newRunnable() {

@Override

publicvoid run() {

mConnectionState.setText(resourceId);

}

});

}



privatevoid displayData(String data) {

if(data != null) {

mDataField.setText(data);

}

}



//Demonstrates how to iterate through the supported GATT

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)

//Services/Characteristics.

//In this sample, we populate the data structure that is bound to the

//ExpandableListView

//on the UI.

/*


* 演示了如何遍歷所支援的GATT服務/特徵。在這個示例中,我們填充資料結構綁定到ExpandableListViewUI


*/

@SuppressLint("NewApi")

privatevoid displayGattServices(List<BluetoothGattService> gattServices) {

if(gattServices == null)

return;

Stringuuid = null;

StringunknownServiceString = getResources().getString(

R.string.unknown_service);

StringunknownCharaString = getResources().getString(

R.string.unknown_characteristic);

ArrayList<HashMap<String,String>> gattServiceData = new ArrayList<HashMap<String,String>>();

ArrayList<ArrayList<HashMap<String,String>>> gattCharacteristicData = newArrayList<ArrayList<HashMap<String, String>>>();

mGattCharacteristics= new ArrayList<ArrayList<BluetoothGattCharacteristic>>();



//Loops through available GATT Services.

for(BluetoothGattService gattService : gattServices) {

HashMap<String,String> currentServiceData = new HashMap<String, String>();

uuid= gattService.getUuid().toString();

currentServiceData.put(LIST_NAME,

SampleGattAttributes.lookup(uuid,unknownServiceString));

currentServiceData.put(LIST_UUID,uuid);

gattServiceData.add(currentServiceData);



ArrayList<HashMap<String,String>> gattCharacteristicGroupData = newArrayList<HashMap<String, String>>();

List<BluetoothGattCharacteristic>gattCharacteristics = gattService

.getCharacteristics();

ArrayList<BluetoothGattCharacteristic>charas = new ArrayList<BluetoothGattCharacteristic>();



//Loops through available Characteristics.

for(BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {

charas.add(gattCharacteristic);

HashMap<String,String> currentCharaData = new HashMap<String, String>();

uuid= gattCharacteristic.getUuid().toString();

currentCharaData.put(LIST_NAME,

SampleGattAttributes.lookup(uuid,unknownCharaString));

currentCharaData.put(LIST_UUID,uuid);

gattCharacteristicGroupData.add(currentCharaData);

}

mGattCharacteristics.add(charas);

gattCharacteristicData.add(gattCharacteristicGroupData);

}



SimpleExpandableListAdaptergattServiceAdapter = new SimpleExpandableListAdapter(

this,gattServiceData,

android.R.layout.simple_expandable_list_item_2,new String[] {

LIST_NAME,LIST_UUID }, new int[] { android.R.id.text1,

android.R.id.text2}, gattCharacteristicData,

android.R.layout.simple_expandable_list_item_2,new String[] {

LIST_NAME,LIST_UUID }, new int[] { android.R.id.text1,

android.R.id.text2});

mGattServicesList.setAdapter(gattServiceAdapter);

}


// 廣播清單


privatestatic IntentFilter makeGattUpdateIntentFilter() {

finalIntentFilter intentFilter = new IntentFilter();

intentFilter.addAction(BLEService.ACTION_GATT_CONNECTED);

intentFilter.addAction(BLEService.ACTION_GATT_DISCONNECTED);

intentFilter.addAction(BLEService.ACTION_GATT_SERVICES_DISCOVERED);

intentFilter.addAction(BLEService.ACTION_DATA_AVAILABLE);

returnintentFilter;

}

}

-------------------------------------------------------------------------------------

許可權:
<uses-permission
android:name="android.permission.BLUETOOTH"/><uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"/>
5.0以上需要
<!-- 只有當你的 targets API 等於或大於 Android 5.0 (API level 21) 才需要此許可權 --><uses-feature
android:name="android.hardware.location.gps" />
6.0以上設備需要
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/><uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>
--------------------------------------------------------------------------
Bluetooth 藍芽無線通訊 隨著視聽產品的演進,耳機已成為不可或缺的需求,有線耳機總是不方便,無線耳機就應運而生,剛開始的無線耳機採用無線電頻率(Radio Frequency)來傳輸, 由於 RF 訊號屬於類比且無通訊協定,所以 RF 無線耳機在傳輸的過程中,音頻 可能斷斷續續無法連續,手機業者Ericsson 1994 年構思了以無線方式來取代 有線 RS-232 傳輸,以解決音訊在無線傳輸時的同步問題;透過 2.4GHz 頻率來傳 遞聲波,所有的聲波資料透過封包來傳遞,資料交換時透過 master 所產生的時脈 來傳送或接收,就好像有線的 RS-232 傳送方式,除非是藍芽晶片製造公司,讀者不需要對底層多做瞭解,只要針對其應用瞭解,在嵌入式系統內,即可發揮應用,本文也僅針對其應用加以說明。如果讀者要在 Window’s 作業系統下,擷取藍芽的資料,大部分是從 L2CAP 層以上來擷取,如果外界裝置為 HID,為呼叫 Window's 作業系統的 HID.dll 函式 庫來完成,如果外界裝置為模擬 RS-232 通訊,就利用 RFCOMM 層來連結外界藍 芽裝置,當然,如果讀者所在的作業系統非視窗作業系統,那就要看那個作業系 統對藍芽所提供的驅動程式到哪一個地步,最壞的狀況就是,驅動程是要自己寫,如藍芽晶片的製造商,那就要從 HCI Transport Layer 開始囉! 一般人聽到藍芽傳輸,通常會嚇的不知道從何著手,其實瞭解了以後,不過就是 RS-232 的傳輸罷了! 做為系統開發者,重要的是如何將這些不同的介面銜 接起來,往後將會想辦法做一些實作讀取 HID,或 RFCOMM 藍芽裝置的資料, 或是透過藍芽無線傳輸來控制這些裝置。 Victor 於加拿大
返回列表