获取蓝牙rssi的实例


有一次蓝牙耳机不知滚落何方,遍寻不得,因此想到可否利用蓝牙发射信号强度rssi来寻找蓝牙设备,着手写了以下三个实例。

读取蓝牙rssi的基本方法

基本方法有两种,一种是通过扫描或搜索的方式获取rssi,另一种是连接以后连续读取rssi。

读取低功耗蓝牙rssi

用扫描低功耗蓝牙的方法,可以在回调中读取蓝牙rssi。

首先取得BluetoothAdapter的实例

    val bluetoothAdapter: BluetoothAdapter = (MyApplication.context
        .getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager)
        .adapter

低功耗蓝牙用扫描方法获得蓝牙设备信息,需要定义扫描器。

	scanner = bluetoothAdapter.bluetoothLeScanner

启动扫描器时,需要注入一个回调函数,在回调函数的onScanResult()中取得蓝牙设备信息以及rssi值。

    private val scanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult) {
            addDeviceList(MyDevice(result.device,result.rssi))
        }
    }

启动扫描器

	scanner.startScan(scanCallback)

其余工作把回调函数中取得的设备名称和rssi值放在deviceList里,通过recyclerView显示。

读取常规蓝牙rssi

获取常规蓝牙rssi的方法与低功耗蓝牙相似,具体实现略有不同。没有扫描器和回调,取而代之的是Discovery和BroadcastReceiver。

同样取得BluetoothAdapter的实例

    val bluetoothAdapter: BluetoothAdapter = (MyApplication.context
        .getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager)
        .adapter

定义一个蓝牙相关的广播接收器,用于获得蓝牙操作的结果。
当接收到BluetoothDevice.ACTION_FOUND事件后,可以从intent中读取蓝牙设备信息以及rssi值。

    private inner class BluetoothReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            Log.i(tag, "onReceive() intent=${intent?.action}")
            when (intent?.action) {
                BluetoothDevice.ACTION_FOUND -> {
                    //发现设备
                    val device: BluetoothDevice? =
                        intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
                    val rssi: Int = (intent.extras?.getShort(BluetoothDevice.EXTRA_RSSI) ?: 0).toInt()
                    device?.let {
                        val index = indexOf(it, deviceList)
                        if (index == -1) {  // deviceList中没有这个device,则追加
                            deviceList.add(MyDevice(it, rssi))
                            deviceAdapter.notifyItemInserted(deviceList.size - 1)
                            Log.i(tag, "onReceive() ItemInserted device.name=${device.name}")
                        } else { // 如果deviceList中存在该device,则修改rssi值
                            deviceList[index].rssi = rssi
                            deviceAdapter.notifyItemChanged(index)
                            Log.i(tag, "onReceive() ItemChanged(${index}) device.name=${device.name} rssi=${rssi}")
                        }
                    }
                }
                ACTION_DISCOVERY_FINISHED -> {
                    if (btnScanIsChecked) startScan()
                }
            }
        }
    }

注册上述蓝牙广播接收器。

        val filter = IntentFilter()
        filter.addAction(BluetoothDevice.ACTION_FOUND)
        filter.addAction(ACTION_DISCOVERY_FINISHED)
        bluetoothReceiver = BluetoothReceiver()
        MyApplication.context.registerReceiver(bluetoothReceiver, filter)

启动蓝牙搜寻

        bluetoothAdapter.startDiscovery()

其余工作把广播接收器中取得的设备名称和rssi值放在deviceList里,通过recyclerView显示。

连续读取BluetoothGatt蓝牙rssi

对于已经连接的蓝牙设备,目前只找到BluetoothGatt协议支持的方法。

同样取得BluetoothAdapter的实例

    val bluetoothAdapter: BluetoothAdapter = (MyApplication.context
        .getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager)
        .adapter

同样需要一个回调,用于处理连接过程的各种事件。

class BluetoothCallback : BluetoothGattCallback()  {

    private val tag = this.javaClass.simpleName

    companion object {
        const val PACKAGE_NAME = "com.wxson.blt_rssi"
        const val ON_CONNECTED = "com.wxson.blt_rssi.action.OnConnected"
        const val ON_DISCONNECTED = "com.wxson.blt_rssi.action.OnDisconnected"
        const val ON_READ_RSSI_SUCCESS = "com.wxson.blt_rssi.action.OnReadRssiSuccess"
        const val ON_GATT_FAILED = "com.wxson.blt_rssi.action.OnGattFailed"
    }

    override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
        super.onConnectionStateChange(gatt, status, newState)
        Log.i(tag, "onConnectionStateChange()")
        if (status == BluetoothGatt.GATT_SUCCESS) {
            if (newState == BluetoothGatt.STATE_CONNECTED) {
                runOnUiThread {
                    onConnected()
                }
            } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
                gatt.close()
                runOnUiThread{
                    onDisconnected()
                }
            }
        } else {
            runOnUiThread {
                onGattFailed()
                onFinish()
            }
            gatt.close()
        }
    }

    override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
        super.onServicesDiscovered(gatt, status)
    }

    override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) {
        super.onReadRemoteRssi(gatt, rssi, status)
        Log.i(tag, "onReadRemoteRssi()")
        if (status == BluetoothGatt.GATT_SUCCESS) {
            runOnUiThread {
                onReadRssiSuccess(rssi)
                onFinish()
            }
        } else {
            runOnUiThread {
                onGattFailed()
                onFinish()
            }
        }
    }

    private fun onConnected() {
        Log.i(tag, "onConnected()")
        BluetoothService.isConnected = true
        sendMyBroadcast(intentOnConnected)
    }

    private fun onDisconnected() {
        Log.i(tag, "onDisconnected()")
        BluetoothService.isConnected = false
        sendMyBroadcast(intentOnDisconnected)
    }
    private fun onGattFailed() {
        Log.i(tag,"onGattFailed()")
        BluetoothService.isConnected = false
        sendMyBroadcast(intentOnDisconnected)
//        sendMyBroadcast(intentOnGattFailed)
        onFailure()
    }

    private fun onFailure() {
        Log.i(tag,"onFailure()")
    }

    private fun onReadRssiSuccess(rssi: Int) {
        Log.i(tag,"onReadRssiSuccess() rssi=${rssi}")
        sendMyBroadcast(intentOnReadRssiSuccess.putExtra("rssi", rssi))
    }

    private fun onFinish() {
        Log.i(tag,"onFinish()")
        BluetoothService.connectFinished()
    }

    // Notification to caller
    private val intentOnConnected = Intent(ON_CONNECTED).apply { `package` = PACKAGE_NAME }
    private val intentOnDisconnected = Intent(ON_DISCONNECTED).apply { `package` = PACKAGE_NAME }
    private val intentOnReadRssiSuccess = Intent(ON_READ_RSSI_SUCCESS).apply { `package` = PACKAGE_NAME }
    private val intentOnGattFailed = Intent(ON_GATT_FAILED).apply { `package` = PACKAGE_NAME }
    private fun sendMyBroadcast(intent: Intent) {
        MyApplication.context.sendBroadcast(intent)
    }
}

首先与指定的蓝牙设备连接,上述回调是连接必须的参数。

    fun connectGatt(device: BluetoothDevice, callback: BluetoothCallback) {
        Log.i(tag, "connectGatt()")
        if (!isConnected) {
            MyApplication.runOnUiThread {
                bluetoothGatt = device.connectGatt(MyApplication.context, false, callback)
            }
        }
    }

定义一个蓝牙相关的广播接收器,用于获得蓝牙操作的结果。

    private inner class BluetoothReceiver : BroadcastReceiver() {
        @SuppressLint("NotifyDataSetChanged")
        override fun onReceive(context: Context, intent: Intent) {
            Log.i(tag, "onReceive() intent=${intent.action}")
            when (intent.action) {
                BluetoothCallback.ON_GATT_FAILED ->{
                    _msgLiveData.value = Msg("showMsg", "ON_GATT_FAILED")
                }
                BluetoothCallback.ON_CONNECTED -> {
                    // set item color red
                    deviceAdapter.notifyDataSetChanged()
                    // set connection flag connected
                    _msgLiveData.value = Msg("connectStatus", true)
                }
                BluetoothCallback.ON_DISCONNECTED -> {
                    // set item color black
                    deviceAdapter.currentPosition = -1
                    deviceAdapter.notifyDataSetChanged()
                    // set connection flag disconnected
                    _msgLiveData.value = Msg("connectStatus", false)
                }
                BluetoothCallback.ON_READ_RSSI_SUCCESS -> {
                    // get rssi value to display
                    val rssi = intent.extras?.getInt("rssi", 0)
                    // display rssi
                    _msgLiveData.value = Msg("rssi", rssi)
                }
            }
        }
    }

连接成功以后,启动连续读取rss的i线程或协程,这里用的是协程。

    private lateinit var job: Job   // background job for coroutine
    private lateinit var scope: CoroutineScope
    fun startReadRssiCoroutine() {
        job = Job()
        scope = CoroutineScope(job)
        scope.launch {
            Log.i(tag, "RssiCoroutine start")
            while (true) {
                readRssi()
                delay(500)
            }
        }
    }

    private fun readRssi() {
            bluetoothGatt?.let{
                if (it.readRemoteRssi()) {
                    Log.i(tag, "readRemoteRssi success")
                } else {
                    Log.i(tag, "readRemoteRssi failed")
                }
            }
    }

如果读取成功,会在广播接收器中收到BluetoothCallback.ON_READ_RSSI_SUCCESS消息,此时可以从intent中读取rssi值。
三个实例的源码都在github上,请参考 https://github.com/wxson7282/Bluetooth-Detector
欢迎交流。

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
获取蓝牙设备的RSSI(接收信号强度指示器),你需要使用蓝牙适配器的API。以下是在C++获取蓝牙设备RSSI的基本步骤: 1. 初始化蓝牙适配器。 2. 扫描附近的蓝牙设备。 3. 找到目标蓝牙设备并建立连接。 4. 获取目标蓝牙设备的RSSI。 以下是一个简单的示例代码: ```c++ #include <winsock2.h> #include <ws2bth.h> #include <BluetoothAPIs.h> #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "irprops.lib") int main() { // 初始化蓝牙适配器 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); HANDLE hRadio; HBLUETOOTH_RADIO_FIND hFind; BLUETOOTH_FIND_RADIO_PARAMS btfrp = { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; HBLUETOOTH_DEVICE_FIND hFindDevice; BLUETOOTH_DEVICE_SEARCH_PARAMS btsp = { sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS) }; BLUETOOTH_DEVICE_INFO btdi = { sizeof(BLUETOOTH_DEVICE_INFO) }; DWORD dwSize; hFind = BluetoothFindFirstRadio(&btfrp, &hRadio); if (hFind == NULL) { return 0; } // 扫描附近的蓝牙设备 btsp.fReturnAuthenticated = TRUE; btsp.fReturnRemembered = TRUE; btsp.fReturnUnknown = TRUE; btsp.fIssueInquiry = TRUE; btsp.cTimeoutMultiplier = 2; hFindDevice = BluetoothFindFirstDevice(&btsp, &btdi); if (hFindDevice == NULL) { return 0; } // 找到目标蓝牙设备并建立连接 while (BluetoothFindNextDevice(hFindDevice, &btdi)) { if (wcsstr(btdi.szName, L"目标设备名称") != NULL) { BLUETOOTH_DEVICE_INFO_EX btdie = { sizeof(BLUETOOTH_DEVICE_INFO_EX) }; btdie.Address.ullLong = btdi.Address.ullLong; btdie.ulClassofDevice = btdi.ulClassofDevice; HANDLE hDevice; if (BluetoothOpenDeviceEx(&btdie, &hDevice) == ERROR_SUCCESS) { // 获取目标蓝牙设备的RSSI BLUETOOTH_DEVICE_INFO btdi_rssi = { sizeof(BLUETOOTH_DEVICE_INFO) }; DWORD dwSize_rssi = sizeof(BLUETOOTH_DEVICE_INFO); if (BluetoothGetDeviceInfo(hDevice, &btdi_rssi) == ERROR_SUCCESS) { if (btdi_rssi.rssi != 0) { // btdi_rssi.rssi 就是目标设备的RSSI值 } } CloseHandle(hDevice); } } } BluetoothFindDeviceClose(hFindDevice); BluetoothFindRadioClose(hFind); WSACleanup(); return 0; } ``` 请注意,此代码仅适用于Windows平台,并且需要使用Winsock和Windows Bluetooth API。此外,代码的“目标设备名称”应替换为你要获取RSSI的蓝牙设备的名称。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值