Я пытался выяснить, как заставить эти телефоны общаться друг с другом через Bluetooth.У меня телефон Android настроен как периферийное устройство, и на моем iPhone запущено приложение nrf connect .Я могу рекламировать и подключаться к телефону Android с iPhone, и я могу подписаться на уведомления и видеть обновленную характеристику.Проблема в том, что если я не отправляю характерное уведомление, примерно через 7-10 секунд соединение теряется.Я получаю обратный вызов обработчика обратного вызова connectionStateChanged
, и я не могу понять, что является причиной этого.Я не думаю, что это приложение NRF, потому что я связан с другими вещами, и он просто остается на связи всегда.Я что-то упускаю?
Вот код:
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 : Поэтому я добавил onCharacteristicRead
& onCharacteristicWrite
обратные вызовы.Но это, кажется, ничего не меняет, и это имеет смысл для меня, потому что я ничего не делаю в них, кроме как вызвать super.onCharacteristicRead()
в любом случае.Кроме того, они не будут вызваны, если я не делаю чтения и записи.И кажется, что Bluetooth должен оставаться подключенным более 30 секунд, даже если нет запроса на чтение или запись.
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 для завершения запроса.
Так что, как только я обновил свой обратный вызов, чтобы он выглядел какэто:
@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());
}
, а затем каждые несколько секунд считывает данные, после чего время ожидания не отключается.