本文介绍了BluetoothGattServer 总是在 30 秒后断开连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在想办法让这些手机通过蓝牙相互通话.我将 Android 手机设置为外围设备,并且我的 iPhone 运行 nrf 连接应用程序.我可以从 iPhone 做广告并连接到 Android 手机,我可以订阅通知并查看更新的特性.问题是,如果我不发送特征通知,大约 7-10 秒后连接就会丢失.我在 connectionStateChanged 回调处理程序上收到一个回调,但我不知道是什么原因造成的.我不认为这是 nrf 应用程序,因为我已经连接到其他东西并且它永远保持连接.有什么我遗漏的吗?

I've been trying to figure out how to get these phones to talk to each other via Bluetooth. I have the android phone set up as a peripheral, and I have my iPhone running the nrf connect app. I am able to advertise and connect to the Android phone from the iPhone, and I am able to subscribe to notifications and see the characteristic updated. The problem is that if I don't send a characteristic notification, after about 7-10 seconds then the connection is lost. I get a callback on the connectionStateChanged callback handler, and I can't figure out what's causing this. I don't think it's the nrf app, because I've connected to other things and it just stays connected forever. Is there something I'm missing?

这是一些代码:

private BluetoothManager bluetoothManager;
private BluetoothGattServer gattServer;
private BluetoothGattCharacteristic test_characteristic;
private BluetoothDevice connected_device;


private BluetoothGattServerCallback gattServerCallback = new BluetoothGattServerCallback() {
    @Override
    public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
        super.onConnectionStateChange(device, status, newState);
        if (newState == 2){ //CONNECTED
            connected_device = device;
        }
        Log.i("chase", "Connection state changed: "+newState);
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    BluetoothRegulator.sharedInstance().appContext = getApplicationContext();
    bluetoothManager = (android.bluetooth.BluetoothManager) this.getSystemService(Context.BLUETOOTH_SERVICE);
    BluetoothRegulator.sharedInstance().initialize(bluetoothManager);

    if( ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
    }


    gattServer = bluetoothManager.openGattServer(this, gattServerCallback);
    String uuid_string = "92D9D153-9BE6-43FF-9672-3E2904628B9D";
    BluetoothGattService service = new BluetoothGattService(UUID.fromString(uuid_string), BluetoothGattService.SERVICE_TYPE_PRIMARY);

    uuid_string = "43FF0001-9BE6-43FF-9672-3E2904628B9D";
    test_characteristic = new BluetoothGattCharacteristic(
            UUID.fromString(uuid_string),
            BluetoothGattCharacteristic.PROPERTY_BROADCAST | BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
    test_characteristic.setValue( ""+System.currentTimeMillis() );
    service.addCharacteristic(test_characteristic);
    gattServer.addService(service);

    findViewById(R.id.send_data_btn).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            shot_detected_characteristic.setValue( ""+System.currentTimeMillis() );
            gattServer.notifyCharacteristicChanged(connected_device, shot_detected_characteristic, false);
        }
    });

    findViewById(R.id.advertise).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            advertise();
        }
    });

}
private void advertise() {
    BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    BluetoothLeAdvertiser advertiser = adapter.getBluetoothLeAdvertiser();
    AdvertiseSettings settings = new AdvertiseSettings.Builder()
            .setAdvertiseMode( AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY )
            .setTxPowerLevel( AdvertiseSettings.ADVERTISE_TX_POWER_HIGH )
            .setConnectable( true )
            .build();
    String uuid_string = "92C9D164-9BE6-43FF-9672-3E2804618B9C";
    ParcelUuid pUuid = new ParcelUuid( UUID.fromString( uuid_string ) );

    AdvertiseData data = new AdvertiseData.Builder()
            .setIncludeDeviceName( true )
            .addServiceData( pUuid, "TEST".getBytes( Charset.forName( "UTF-8" ) ) )
            .build();

    AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            Log.e( "BLE", "Advertising Started");
            super.onStartSuccess(settingsInEffect);
        }

        @Override
        public void onStartFailure(int errorCode) {
            Log.e( "BLE", "Advertising onStartFailure: " + errorCode );
            super.onStartFailure(errorCode);
        }
    };
    advertiser.startAdvertising( settings, data, advertisingCallback );
}

编辑:实际上,我注意到这与闲置无关.实际上每次都在 30 秒处断开连接.

Edit: Actually, I'm noticing that it has nothing to do with being idle. It's actually disconnecting pretty much at the 30 second mark every time.

EDIT:所以我添加了 onCharacteristicRead &onCharacteristicWrite 回调.但这似乎并没有改变任何东西,这对我来说很有意义,因为除了调用 super.onCharacteristicRead() 之外,我什么也没做.此外,如果我不进行读取和写入,则不会调用这些.即使没有读取或写入请求,蓝牙似乎也应该保持连接超过 30 秒.

EDIT: So I added onCharacteristicRead & onCharacteristicWrite callbacks. But that doesn't seem to change anything, and that makes sense to me, because I am not doing anything in them except calling super.onCharacteristicRead() anyway. Also, those aren't going to be called if I am not making reads and writes. And it seems like the Bluetooth should stay connected more than 30 seconds even if there is not a read or write request.

private BluetoothGattServerCallback gattServerCallback = new BluetoothGattServerCallback() {
    @Override
    public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
        super.onConnectionStateChange(device, status, newState);
        if (newState == 2){
            connected_device = device;
            advertiser.stopAdvertising(new AdvertiseCallback() {});
        }
    }

    @Override
    public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
    }

    @Override
    public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
        super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
    }

};

解决方案

所以问题在于 onCharacteristicReadRequest 回调.根据文档:

应用程序必须调用 BluetoothGattServer#sendResponse 才能完成请求.

所以一旦我将回调更新为如下所示:

So once I updated my callback to look like this:

@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
    super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
    gattServer.sendResponse(device, requestId, 1, offset, characteristic.getValue());
}

然后每隔几秒钟读取一次,然后它就不会超时和断开连接.

and then made a read every few seconds, then it wouldn't time out and disconnect.

推荐答案

根据 ble核心规范,用于ATT

未在 30 秒内完成的事务将超时.

在实践中,这通常表现为连接的一侧断开连接.

In practice, this usually manifests as a disconnect by one side of the connection.

某些类型的 GATT 请求需要响应(即指示、读取请求、写入请求).看起来您没有实现诸如 onCharacteristicReadRequest 之类的回调 &onCharacteristicWriteRequest 在您的 Gatt 服务器实现中可能会导致此问题.

Some types of GATT requests require responses (i.e Indications, Read Requests, Write Requests). Doesn't look like you are implementing callbacks such as onCharacteristicReadRequest & onCharacteristicWriteRequest in your Gatt server implementation which could lead to this problem.

这篇关于BluetoothGattServer 总是在 30 秒后断开连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-26 12:17