使用自定义应用程序无法连接到BLE设备,未使用nRF Connect的解决方法

4

问题的概述和背景

作为大学项目的一部分,我们需要使用自定义应用程序连接到蓝牙LE模块(BL654)以更新特性。

问题是,在没有先进行解决方法的情况下,我无法连接到我们的模块。我可以毫无问题地搜索设备,我们的模块也出现在搜索结果中。我希望该应用程序不必依赖其他应用程序才能正常工作。

在手机(Pixel 3XL / Pixel 3 / LG G5)进行干净启动和干净操作系统安装后,我无法连接到我们的模块。但是,我可以连接到其他BLE设备,如树莓派和HTV Vive基站。

我在Android Studio Logcat中收到的错误信息是:

D/BluetoothGatt: onClientConnectionState() - status=133 clientIf=7 device=C2:A1:E0:B3:69:54

在使用 nRF Connect 连接另一台设备后,我就能够通过 nRF Connect 连接到我们的模块,并随后在我的应用程序中连接到该模块。Nordic 制造了运行于板子上的固件和 nRF Connect 应用程序。这让我相信两者之间有特殊的联系。

我正在使用标准的 Android 库进行连接,并尝试使用 RxAndroidBle。

我已经研究了近一个月关于此错误和可能的解决方案,但仍无法解决问题。如有任何指导,将不胜感激。

以下是尝试过程失败时的Logcat ,以及使用解决方法后成功连接的Logcat

下面将显示相关代码片段。如果需要更多代码,我很乐意分享。

代码片段

我将代码分为 Kotlin 类文件和 MainActivity.kt,据我所知,我在这两个文件之间传递了所有正确的参数。我是 Kotlin 的初学者,请多多包涵。

查找蓝牙设备(在 mBluetoothLEAdapter.kt 中):

fun findBluetoothDevices(mBluetoothAdapter: BluetoothAdapter?){
        // Get and instance of the Bluetooth Low Energy Scanner
        scanner = mBluetoothAdapter?.bluetoothLeScanner

        // Create search settings object
        val mSettings = ScanSettings.Builder().
            setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).
            setReportDelay(reportDelay).
            build()

        // Create a scanning filter
        val mFilter = ScanFilter.Builder().setDeviceName("AEsir ADC Test").build()
        val scannerFilter = arrayListOf<ScanFilter>()
        scannerFilter.add(mFilter)

        // Stop previous scan if there was one
        stopScanningBluetoothDevices()

        //Start new scanner
        tools.showToast("Scanning...")
        scanner?.startScan(null, mSettings, mCallback)
    }

扫描回调(位于mBluetoothLEAdapter.kt内):
inner class MCallBack: ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
            super.onScanResult(callbackType, result)
            stopScanningBluetoothDevices()
            tools.showToast("Single Result Found!")
        }

        override fun onScanFailed(errorCode: Int) {
            super.onScanFailed(errorCode)
            stopScanningBluetoothDevices()
            tools.showToast("Error on Scan!")
            tools.showToast(errorCode.toString())
        }

        override fun onBatchScanResults(results: MutableList<ScanResult>?) {
            super.onBatchScanResults(results)
            stopScanningBluetoothDevices()
            tools.showToast("Batch Results Found!")
            scanResults = results
            val mAdapter = DeviceListAdapter(activity, scanResults)
            val deviceList = activity.findViewById<ListView>(R.id.device_list)
            deviceList.adapter = mAdapter
        }
    }

连接设备(在MainActivity.kt内):

// Runs when an item in the Device List is pressed.
    // This initiates a GATT connection to the selected device.
    override fun onListPressed(): AdapterView.OnItemClickListener? {
        return AdapterView.OnItemClickListener { parent, _, position, _ ->

            if (bluetoothGatt != null) {
                bluetoothGatt?.disconnect()
                bluetoothGatt?.close()
            }

            val clickedItem = parent.getItemAtPosition(position) as ScanResult
            //val device = clickedItem.device
            val address = clickedItem.device.address
            tools.showToast("Connecting to: $address")

            // CONNECTION NOT WORKING. HAVE TO USE nRF Connect to make it work
            bluetoothGatt = clickedItem.device.connectGatt(applicationContext, false, mGattCallback, BluetoothDevice.TRANSPORT_LE)
        }
    }

GattCallback(在MainActivity.kt中):
inner class GattCallback : BluetoothGattCallback() {
        override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
            super.onConnectionStateChange(gatt, status, newState)
            //If we connected to the GATT server find services on device
            if (status == BluetoothGatt.GATT_SUCCESS) {
                gatt.discoverServices()
            }
            else if (status == BluetoothGatt.STATE_CONNECTING) {
                tools.showToast("Connecting I am")
            }
            else if (status == BluetoothGatt.STATE_DISCONNECTED) {
                bluetoothGatt?.close()
                bluetoothGatt = null
                tools.showToast("I got here and closed the connection")
            }
        }

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

        override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
            //"Notification"
        }

        override fun onCharacteristicWrite(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) {
            super.onCharacteristicWrite(gatt, characteristic, status)

            //Confirm that the characteristic was actually changed
            tools.showToast("Characteristic was written!")
        }

        override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {

        }

        override fun onDescriptorRead(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {

        }
    }

感谢您能提供的任何帮助 :)
谢谢!
2个回答

1
尝试将报告延迟设置为0。
您的设置现在应该如下所示。
val mSettings = ScanSettings.Builder().
            setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).
            setReportDelay(0).
            build()

你还需要开始使用单个结果回调而非onBatchScanResults,这将需要将结果列表存储在其他地方。
override fun onScanResult(callbackType: Int, result: ScanResult?) {
//add to the list
//adapter.notifyDataSetChanged() if needed
}

我在我的一个应用程序中遇到了这个问题,似乎这是解决方法。
如果向用户呈现列表,似乎这会使得列表更新过快,无法进行点击,因此,如果出现问题,您可能需要添加自己的延迟更新而不使用setReportDelay

133错误是连接错误,与扫描无关。 - Kevin

0
啊,可怕的GATT 133错误。这通常表明Android的BLE堆栈出现了问题,重置蓝牙 - 在旧设备上还包括WiFi - 通常可以解决问题。
您的解决方法有效是因为Android允许在一个应用程序中连接的蓝牙设备在其他应用程序中共享。这似乎是一种可怕的安全漏洞,但这是预期的行为。
从您的经验来看,外围设备可能具有意外的配置。也许尝试使用RxCentralBle - Uber的蓝牙LE集成库 - 示例应用程序,看看是否可以连接到您的设备。示例应用程序和库是开源的,因此您可以根据需要进行调整。
完全披露 - 我是RxCentralBle的作者和维护者。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接