This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Delay between BLE transmissions using Android Blinky

I started modifying the NRF Android Blinky example project to suits my needs (to control a servo motor). I observed there is a BIG delay between writings to a specific characteristic.

I would like that servo motor to move in real time. If you make multiple modifications per second, the queue size will increase and phone will continue to send the data over a few seconds.

Is there a way to decrease this delay? Can you try to reproduce this issue by sending multiple values/second to a specific characteristic?

As a microcontroller I use NRF52832 with a custom board.

Thank you very much!

  • Hello again,

    I did not manage to solve the problem. In the Microcontroller I changed the _MIN and MAX interval to 10-20ms value. But for the Blinky application I cannot find this variable/whater it is MIN_CONN_INTERVAL or MAX_CONN_INTERVAL.

    In the BlinkyActivity.java there is a call:

    mViewModel.connect(device);

    The parameter device is the selected Discovered bluetooth device from list.

    The connect function can be found in BlinkyViewModel.java

    Can you take a look in the bellow code and tell me where should I change the connection interval? thanks

    /*
     * Copyright (c) 2018, Nordic Semiconductor
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
     * documentation and/or other materials provided with the distribution.
     *
     * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
     * software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    package com.example.a1remotecar.blescanner;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.LinearLayout;
    import android.widget.Switch;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.appcompat.widget.Toolbar;
    import androidx.lifecycle.ViewModelProviders;
    
    
    import com.example.a1remotecar.MainActivity;
    import com.example.a1remotecar.R;
    import com.example.a1remotecar.blescanner.adapter.DiscoveredBluetoothDevice;
    import com.example.a1remotecar.blescanner.viewmodels.BlinkyViewModel;
    
    
    
    import butterknife.BindView;
    import butterknife.ButterKnife;
    import butterknife.OnClick;
    
    
    @SuppressWarnings("ConstantConditions")
    public class BlinkyActivity extends AppCompatActivity {
    	public static final String EXTRA_DEVICE = "no.nordicsemi.android.blinky.EXTRA_DEVICE";
    
    	private BlinkyViewModel mViewModel;
    	private String deviceName = "";
    	@BindView(R.id.led_switch) Switch mLed;
    	@BindView(R.id.button_state) TextView mButtonState;
    
    	@Override
    	protected void onCreate(final Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.ble_activity_blinky);
    		ButterKnife.bind(this);
    
    		final Intent intent = getIntent();
    		final DiscoveredBluetoothDevice device = intent.getParcelableExtra(EXTRA_DEVICE);
    
    
    		if (device != null)
    		{
    		deviceName = device.getName();
    		final String deviceAddress = device.getAddress();
    
    
    		final Toolbar toolbar = findViewById(R.id.toolbarBlinky);
    
    		setSupportActionBar(toolbar);
    
    		getSupportActionBar().setTitle(deviceName);
    		getSupportActionBar().setSubtitle(deviceAddress);
    
    		getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    		}
    		// Configure the view model
    		mViewModel = ViewModelProviders.of(this).get(BlinkyViewModel.class);
    		mViewModel.connect(device);
    
    		// Set up views
    		final TextView ledState = findViewById(R.id.led_state);
    		final LinearLayout progressContainer = findViewById(R.id.progress_container);
    		final TextView connectionState = findViewById(R.id.connection_state);
    		final View content = findViewById(R.id.device_container);
    		final View notSupported = findViewById(R.id.not_supported);
    
    //		mLed.setOnCheckedChangeListener((buttonView, isChecked) -> mViewModel.toggleLED(isChecked));
    		mViewModel.isDeviceReady().observe(this, deviceReady -> {
    			progressContainer.setVisibility(View.GONE);
    			//content.setVisibility(View.VISIBLE);
    			final Intent mainActivityIntent = new Intent(this, MainActivity.class);
    			mainActivityIntent.putExtra(BlinkyActivity.EXTRA_DEVICE, device);
    			startActivity(mainActivityIntent);
    			Toast.makeText(this, "Successfully connected to: " + deviceName + "!", Toast.LENGTH_SHORT).show();
    			finish();
    
    		});
    		mViewModel.getConnectionState().observe(this, text -> {
    			if (text != null) {
    				progressContainer.setVisibility(View.VISIBLE);
    				notSupported.setVisibility(View.GONE);
    				connectionState.setText(text);
    			}
    		});
    		mViewModel.isConnected().observe(this, this::onConnectionStateChanged);
    		mViewModel.isSupported().observe(this, supported -> {
    			if (!supported) {
    				progressContainer.setVisibility(View.GONE);
    				notSupported.setVisibility(View.VISIBLE);
    			}
    		});
    		mViewModel.getLEDState().observe(this, isOn -> {
    			ledState.setText(isOn ? R.string.turn_on : R.string.turn_off);
    			mLed.setChecked(isOn);
    		});
    		mViewModel.getButtonState().observe(this,
    				pressed -> mButtonState.setText(pressed ?
    						R.string.button_pressed : R.string.button_released));
    	}
    
    	@OnClick(R.id.action_clear_cache)
    	public void onTryAgainClicked() {
    		mViewModel.reconnect();
    	}
    
    	private void onConnectionStateChanged(final boolean connected) {
    //		mLed.setEnabled(connected);
    //		if (!connected) {
    //			mLed.setChecked(false);
    //			mButtonState.setText(R.string.button_unknown);
    //		}
    	}
    }
    
    /*
     * Copyright (c) 2018, Nordic Semiconductor
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
     * documentation and/or other materials provided with the distribution.
     *
     * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
     * software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    
    package com.example.a1remotecar.blescanner.viewmodels;
    import android.app.Application;
    import androidx.lifecycle.AndroidViewModel;
    import androidx.lifecycle.LiveData;
    import androidx.lifecycle.MutableLiveData;
    import android.bluetooth.BluetoothDevice;
    import androidx.annotation.NonNull;
    
    import com.example.a1remotecar.R;
    import com.example.a1remotecar.blescanner.adapter.DiscoveredBluetoothDevice;
    import com.example.a1remotecar.blescanner.profile.BlinkyManager;
    import com.example.a1remotecar.blescanner.profile.BlinkyManagerCallbacks;
    
    import no.nordicsemi.android.log.LogSession;
    import no.nordicsemi.android.log.Logger;
    
    public class BlinkyViewModel extends AndroidViewModel implements BlinkyManagerCallbacks {
    	private final BlinkyManager mBlinkyManager;
    	public static BluetoothDevice mDevice;
    
    	// Connection states Connecting, Connected, Disconnecting, Disconnected etc.
    	private final MutableLiveData<String> mConnectionState = new MutableLiveData<>();
    
    	// Flag to determine if the device is connected
    	private final MutableLiveData<Boolean> mIsConnected = new MutableLiveData<>();
    
    	// Flag to determine if the device has required services
    	private final MutableLiveData<Boolean> mIsSupported = new MutableLiveData<>();
    
    	// Flag to determine if the device is ready
    	private final MutableLiveData<Void> mOnDeviceReady = new MutableLiveData<>();
    
    	// Flag that holds the on off state of the LED. On is true, Off is False
    	private final MutableLiveData<Boolean> mLEDState = new MutableLiveData<>();
    
    	// Flag that holds the pressed released state of the button on the devkit.
    	// Pressed is true, Released is false
    	private final MutableLiveData<Boolean> mButtonState = new MutableLiveData<>();
    
    	public LiveData<Void> isDeviceReady() {
    		return mOnDeviceReady;
    	}
    
    	public LiveData<String> getConnectionState() {
    		return mConnectionState;
    	}
    
    	public LiveData<Boolean> isConnected() {
    		return mIsConnected;
    	}
    
    	public LiveData<Boolean> getButtonState() {
    		return mButtonState;
    	}
    
    	public LiveData<Boolean> getLEDState() {
    		return mLEDState;
    	}
    
    	public LiveData<Boolean> isSupported() {
    		return mIsSupported;
    	}
    
    	public BlinkyViewModel(@NonNull final Application application) {
    		super(application);
    
    		// Initialize the manager
    		mBlinkyManager = new BlinkyManager(getApplication());
    		mBlinkyManager.setGattCallbacks(this);
    	}
    
    	/**
    	 * Connect to peripheral.
    	 */
    	public void connect(@NonNull final DiscoveredBluetoothDevice device) {
    		// Prevent from calling again when called again (screen orientation changed)
    		if (mDevice == null) {
    			mDevice = device.getDevice();
    			final LogSession logSession
    					= Logger.newSession(getApplication(), null, device.getAddress(), device.getName());
    			mBlinkyManager.setLogger(logSession);
    			reconnect();
    		}
    	}
    
    	/**
    	 * Reconnects to previously connected device.
    	 * If this device was not supported, its services were cleared on disconnection, so
    	 * reconnection may help.
    	 */
    	public void reconnect() {
    		if (mDevice != null) {
    			mBlinkyManager.connect(mDevice)
    					.retry(3, 100)
    					.useAutoConnect(false)
    					.enqueue();
    		}
    	}
    
    	/**
    	 * Disconnect from peripheral.
    	 */
    	private void disconnect() {
    		mDevice = null;
    		mBlinkyManager.disconnect().enqueue();
    	}
    	public void onBatteryLevelChanged(BluetoothDevice dev, final int bateryVal) {
    
    	}
    	public void onClickSendDCMotorValue(final byte dcValue) {
    		mBlinkyManager.sendDriveMotorValue(dcValue);
    		try {
    			Thread.sleep(40); // wait before next execution
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    	public void onClickSendServoMotorValue(final byte servoValue) {
    		mBlinkyManager.sendServoMotorValue(servoValue);
    //		try {
    //			Thread.sleep(40); // wait before next execution
    //		} catch (InterruptedException e) {
    //			e.printStackTrace();
    //		}
    	}
    
    	public void onClickSendLEDSState(final byte servoValue) {
    		mBlinkyManager.sendLedState(servoValue);
    //		try {
    //			Thread.sleep(40); // wait before next execution
    //		} catch (InterruptedException e) {
    //			e.printStackTrace();
    //		}
    	}
    
    //	public void toggleLED(final boolean isOn) {
    //		//mBlinkyManager.send(isOn);
    //		mLEDState.setValue(isOn);
    //	}
    
    	@Override
    	protected void onCleared() {
    		super.onCleared();
    //		if (mBlinkyManager.isConnected()) {
    //			disconnect();
    //		}
    	}
    
    
    
    	@Override
    	public void onDeviceConnecting(@NonNull final BluetoothDevice device) {
    		mConnectionState.postValue(getApplication().getString(R.string.state_connecting));
    	}
    
    	@Override
    	public void onDeviceConnected(@NonNull final BluetoothDevice device) {
    		mIsConnected.postValue(true);
    		mConnectionState.postValue(getApplication().getString(R.string.state_discovering_services));
    	}
    
    	@Override
    	public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) {
    		mIsConnected.postValue(false);
    	}
    
    	@Override
    	public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
    		mIsConnected.postValue(false);
    	}
    
    	@Override
    	public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
    		mIsConnected.postValue(false);
    	}
    
    	@Override
    	public void onServicesDiscovered(@NonNull final BluetoothDevice device,
    									 final boolean optionalServicesFound) {
    		mConnectionState.postValue(getApplication().getString(R.string.state_initializing));
    	}
    
    	@Override
    	public void onDeviceReady(@NonNull final BluetoothDevice device) {
    		mIsSupported.postValue(true);
    		mConnectionState.postValue(null);
    		mOnDeviceReady.postValue(null);
    	}
    
    	@Override
    	public void onBondingRequired(@NonNull final BluetoothDevice device) {
    		// Blinky does not require bonding
    	}
    
    	@Override
    	public void onBonded(@NonNull final BluetoothDevice device) {
    		// Blinky does not require bonding
    	}
    
    	@Override
    	public void onBondingFailed(@NonNull final BluetoothDevice device) {
    		// Blinky does not require bonding
    	}
    
    	@Override
    	public void onError(@NonNull final BluetoothDevice device,
    						@NonNull final String message, final int errorCode) {
    		// TODO implement
    	}
    
    	@Override
    	public void onDeviceNotSupported(@NonNull final BluetoothDevice device) {
    		mConnectionState.postValue(null);
    		mIsSupported.postValue(false);
    	}
    }
    

    /*
     * Copyright (c) 2018, Nordic Semiconductor
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
     * documentation and/or other materials provided with the distribution.
     *
     * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
     * software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    package com.example.a1remotecar.blescanner.profile;
    
    import android.bluetooth.BluetoothDevice;
    import android.bluetooth.BluetoothGatt;
    import android.bluetooth.BluetoothGattCharacteristic;
    import android.bluetooth.BluetoothGattService;
    import android.content.Context;
    import android.util.Log;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    
    import com.example.a1remotecar.blescanner.profile.callback.BlinkyBatteryLevelDataCallback;
    import com.example.a1remotecar.blescanner.profile.callback.BlinkyLedDataCallback;
    import com.example.a1remotecar.blescanner.profile.callback.BlinkySuperpowerNotificationDataCallback;
    import com.example.a1remotecar.blescanner.profile.data.BlinkyLED;
    
    import java.util.UUID;
    
    import no.nordicsemi.android.ble.BleManager;
    import no.nordicsemi.android.ble.data.Data;
    import no.nordicsemi.android.log.LogContract;
    import no.nordicsemi.android.log.LogSession;
    import no.nordicsemi.android.log.Logger;
    
    public class BlinkyManager extends BleManager<BlinkyManagerCallbacks> {
    
    	/** Nordic Blinky Service UUID. */
    	public final static UUID LBS_UUID_SERVICE = UUID.fromString("00001523-1212-efde-1523-785feabcd123");
    	/** SUPERPOWER NOTIFICATION characteristic UUID. */
    	public final static UUID LBS_UUID_SUPERPOWER_NOTIFY_CHAR = UUID.fromString("00001524-1212-efde-1523-785feabcd123");
    	/** DRIVE MOTOR characteristic UUID. */
    	public final static UUID LBS_UUID_DRIVE_MOTOR_CHAR = UUID.fromString("00001525-1212-efde-1523-785feabcd123");
    	/** SERVO MOTOR characteristic UUID. */
    	public final static UUID LBS_UUID_SERVO_MOTOR_CHAR = UUID.fromString("00001526-1212-efde-1523-785feabcd123");
    	/** LEDs characteristic UUID. */
    	public final static UUID LBS_UUID_FRONT_REVERSE_LEDS_CHAR = UUID.fromString("00001527-1212-efde-1523-785feabcd123");
    
    
    	/** BATTERY LEVEL Service UUID. */
    	public final static UUID LBS_UUID_BATTERY_LEVEL_SERVICE = UUID.fromString("0000180F-0000-1000-8000-00805F9B34FB");
    	/** BATTERY LEVEL Characteristics UUID. */
    	public final static UUID LBS_UUID_BATTERY_LEVEL_CHAR = UUID.fromString("00002A19-0000-1000-8000-00805F9B34FB");
    
    	public static BluetoothGattService serviceBattery;
    	public static BluetoothGattService gattGeneralService;
    	private static BluetoothGatt gattVar = null;
    
    
    	public static BluetoothGattCharacteristic mSuperpowerNotificationCharacteristic, mDriveMotorCharacteristics, mServoMotorCharacteristics, mFwBackLedCharacteristic, mBatteryLevelCharacteristics;
    	private LogSession mLogSession;
    	private boolean mSupported;
    	private int FRONT_LEDS_ENABLED = 1;
    	private int BACK_LEDS_ENABLED = 2;
    
    	private Data mLedState;
    
    	public BlinkyManager(@NonNull final Context context) {
    		super(context);
    	}
    
    	@NonNull
    	@Override
    	public BleManagerGattCallback getGattCallback() {
    		return mGattCallback;
    	}
    
    	public BluetoothGatt getGatt(){
    		return gattVar;
    	}
    	/**
    	 * Sets the log session to be used for low level logging.
    	 * @param session the session, or null, if nRF Logger is not installed.
    	 */
    	public void setLogger(@Nullable final LogSession session) {
    		this.mLogSession = session;
    	}
    
    	@Override
    	public void log(final int priority, @NonNull final String message) {
    		// The priority is a Log.X constant, while the Logger accepts it's log levels.
    		Logger.log(mLogSession, LogContract.Log.Level.fromPriority(priority), message);
    	}
    
    	@Override
    	protected boolean shouldClearCacheWhenDisconnected() {
    		return !mSupported;
    	}
    
    	/**
    	 * The Button callback will be notified when a notification from Button characteristic
    	 * has been received, or its data was read.
    	 * <p>
    	 * If the data received are valid (single byte equal to 0x00 or 0x01), the
    	 * {@link BlinkyButtonDataCallback#onButtonStateChanged} will be called.
    	 * Otherwise, the {@link BlinkyButtonDataCallback#onInvalidDataReceived(BluetoothDevice, Data)}
    	 * will be called with the data received.
    	 */
    //	private	final BlinkySuperpowerNotificationDataCallback mSuperpowerCallback = new BlinkySuperpowerNotificationDataCallback() {
    //		@Override
    //		public void onNotificationStateChanged(@NonNull final BluetoothDevice device,
    //										 final boolean pressed) {
    //			//log(LogContract.Log.Level.APPLICATION, "Button " + (pressed ? "pressed" : "released"));
    //			mCallbacks.onNotificationStateChanged(device, pressed);
    //		}
    //
    //	};
    
    //
    	private final BlinkyBatteryLevelDataCallback mBatteryLevelCallback = new BlinkyBatteryLevelDataCallback() {
    		@Override
    		public void onBatteryLevelChanged(@NonNull final BluetoothDevice device,
    									  final int batterylevel) {
    //			mLedState = ledState;
    			mCallbacks.onBatteryLevelChanged(device, batterylevel);
    		}
    	};
    
    	/**
    	 * The LED callback will be notified when the LED state was read or sent to the target device.
    	 * <p>
    	 * This callback implements both {@link no.nordicsemi.android.ble.callback.DataReceivedCallback}
    	 * and {@link no.nordicsemi.android.ble.callback.DataSentCallback} and calls the same
    	 * method on success.
    	 * <p>
    	 * If the data received were invalid, the
    	 * {@link BlinkyLedDataCallback#onInvalidDataReceived(BluetoothDevice, Data)} will be
    	 * called.
    	 */
    //	private final BlinkyLedDataCallback mFwBckLedCallback = new BlinkyLedDataCallback() {
    //		@Override
    //		public void onLedStateChanged(@NonNull final BluetoothDevice device,
    //									  final int ledState) {
    //			mCallbacks.onLedStateChanged(device, ledState);
    //		}
    //
    //		@Override
    //		public void onInvalidDataReceived(@NonNull final BluetoothDevice device,
    //										  @NonNull final Data data) {
    //			// Data can only invalid if we read them. We assume the app always sends correct data.
    //			log(Log.WARN, "Invalid data received: " + data);
    //		}
    //	};
    
    	/**
    	 * BluetoothGatt callbacks object.
    	 */
    	final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() {
    		@Override
    		protected void initialize() {
    			//setNotificationCallback(mSuperpowerNotificationCharacteristic).with(mSuperpowerCallback);
    			//setNotificationCallback(mSuperpowerNotificationCharacteristic);
    			//readCharacteristic(mSuperpowerNotificationCharacteristic).with(mSuperpowerCallback).enqueue();
    			//readCharacteristic(mSuperpowerNotificationCharacteristic).enqueue();
    			readCharacteristic(mBatteryLevelCharacteristics).with(mBatteryLevelCallback).enqueue();;
    			enableNotifications(mBatteryLevelCharacteristics).enqueue();
    		}
    
    		@Override
    		public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
    			gattGeneralService = gatt.getService(LBS_UUID_SERVICE);
    			gattVar = gatt;
    
    			if (gattGeneralService != null) {
    
    				//mSuperpowerNotificationCharacteristic = gattGeneralService.getCharacteristic(LBS_UUID_SUPERPOWER_NOTIFY_CHAR);
    				mFwBackLedCharacteristic = gattGeneralService.getCharacteristic(LBS_UUID_FRONT_REVERSE_LEDS_CHAR);
    				mDriveMotorCharacteristics  = gattGeneralService.getCharacteristic(LBS_UUID_DRIVE_MOTOR_CHAR);
    				mServoMotorCharacteristics  = gattGeneralService.getCharacteristic(LBS_UUID_SERVO_MOTOR_CHAR);
    			}
    
    			serviceBattery = gatt.getService(LBS_UUID_BATTERY_LEVEL_SERVICE);
    			if (serviceBattery != null) {
    				mBatteryLevelCharacteristics = serviceBattery.getCharacteristic(LBS_UUID_BATTERY_LEVEL_CHAR);
    			}
    
    
    //			boolean writeRequest = false;
    //			if (mFwBackLedCharacteristic != null) {
    //				final int rxProperties = mFwBackLedCharacteristic.getProperties();
    //				writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;
    //			}
    
    			mSupported =  mDriveMotorCharacteristics != null && mServoMotorCharacteristics != null;
    			return mSupported;
    		}
    
    		@Override
    		protected void onDeviceDisconnected() {
    			mFwBackLedCharacteristic = null;
    			mSuperpowerNotificationCharacteristic = null;
    			mBatteryLevelCharacteristics = null;
    			mDriveMotorCharacteristics = null;
    			mServoMotorCharacteristics = null;
    		}
    	};
    
    	public void sendLedState(final byte ledState) {
    		if (mFwBackLedCharacteristic != null) {
    			writeCharacteristic(mFwBackLedCharacteristic, Data.opCode(ledState)).enqueue();
    		}
    	}
    
    	public void sendDriveMotorValue(final byte dcMotorValue) {
    		if (mDriveMotorCharacteristics != null) {
    			writeCharacteristic(mDriveMotorCharacteristics, Data.opCode(dcMotorValue)).enqueue();
    		}
    	}
    
    	public void sendServoMotorValue(final byte servoMotorValue) {
    		if (mServoMotorCharacteristics != null) {
    			Log.d("ServoSend", "Entered in SendServo");
    			writeCharacteristic(mServoMotorCharacteristics, Data.opCode(servoMotorValue)).enqueue();
    		}
    	}
    }
    

  • Hello again,

    Bujanca Ovidiu said:
    I did not manage to solve the problem.

    I am sorry to hear that this is still an issue. I hope we may resolve it together soon.

    Bujanca Ovidiu said:
    In the Microcontroller I changed the _MIN and MAX interval to 10-20ms value.

    Did you notice a difference in connection speed when you connected to the phone with these settings?
    I think you should be receiving a connectionUpdate request in your application, where the peripheral asks to change the connection interval.
    You could also try to set both _MIN and _MAX to 10 ms ( 8 x 1.25 ms units ) to only accept 10 ms connection interval. 

    Bujanca Ovidiu said:
    But for the Blinky application I cannot find this variable/whater it is MIN_CONN_INTERVAL or MAX_CONN_INTERVAL.

    It seems that the Android BLE API does not allow changes to the connection interval directly, only through changing the priority of the connection, based on this discussion.
    However, the Android BLE API should still support connections with intervals from 7.5 ms to 4 s - so if you configure the shorter connection on your nRF device you should be fine.

    In the case that changing the connection interval on your nRF device does not resolve your issue: are you familiar with using the nRF Sniffer?
    This would be useful to see a trace of the communication actually happening between your phone and your nRF device. The nRF Sniffer is a powerful tool when developing with BLE.

    If you are not familiar with the sniffer tool - or do not have the necessary hardware - then perhaps you could use the below functionality from the Android BLE Library to monitor what connection interval your connection is using:

    	/**
    	 * The connection interval determines how often the Central will ask for data from the Peripheral.
    	 * When the Peripheral requests an update, it supplies a maximum and a minimum wanted interval.
    	 * The connection interval must be between 7.5 ms and 4 s.
    	 *
    	 * @return Connection interval used on this connection, 1.25ms unit.
    	 * Valid range is from 6 (7.5ms) to 3200 (4000ms).
    	 */
    	@IntRange(from = 6, to = 3200)
    	public int getConnectionInterval() {
    		return interval;
    	}


    It would be of great help to determine that you devices actually are communicating on the lower ( non 100-200ms ) connection intervals, to identify the root of your issue.

    Looking forward to solving this issue together,

    Best regards,
    Karl

Related