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!

Parents
  • Hello,

    I observed there is a BIG delay between writings to a specific characteristic

    How long is the delay in question? Please be specific.

    the queue size will increase and phone will continue to send the data over a few seconds.

    What are your connection parameters in your Blinky central application? It sounds like the connection interval might be longer than needed.

    Best regards,
    Karl 

     

  • Hello Karl, thanks for the answer,

    I tried with other application and the data is sent instantly.

    With NRF BLinky example, at most 3 to 5 transmissions are made per second, so if I have 15 events (from a slider) in a second the transmission of all data will last more than 5 seconds...

    This is a picture sample from the NRF Blinky Example Code, but it is not modified, basically the code is this, https://github.com/NordicSemiconductor/Android-nRF-Blinky only with a Characteristics UUID modified and a seekbar. So on value change of seekbar I setup and writeCharacteristic() with specific UUID.

  • Bujanca Ovidiu said:
    thanks for the answer,

    No problem at all, I am happy to help!

    Bujanca Ovidiu said:
    I tried with other application and the data is sent instantly.

    Which other application do you refer to - another smartphone application? If so, which smartphone application?
    If the difference lies in which smartphone application is being used, then we need to look at your smartphone applications connection parameters.

    Bujanca Ovidiu said:
    With NRF BLinky example, at most 3 to 5 transmissions are made per second, so if I have 15 events (from a slider) in a second the transmission of all data will last more than 5 seconds...

    This is not a limitation by BLE, so we only need to identify where the slow speed is configured.
    Have you modified the connection parameters of the Blinky application?
    Particularly, we are interested in the connection interval that the smartphone application is configuring. This parameter decides the time between each transffer, and may range from 7.5 ms to 4 s, which means it could be configured too high for your application. From your description, it sounds to be in the 200-300 ms range, while you would like it to be at ~ 65 ms.
    The connection interval is specified as an interval with a _MAX and _MIN. Setting them both to the same value restricts the available range to that single number.

    Best regards,
    Karl

  • Regarding the other application, it was created using MIT App creator name APP Inventor V2, using blocks of code, so I cannot access the code behind the blocks in order to see the connection parameters.. It is a simple drag and drop application creator.

    I did not modified the connection parameters of the Blinky application. It is the default code as I said, with small modifications regarding UUIDs used with writeCharacteristic() function..

    Regarding connection interval in the code, the nordic ble library is compiled in a .jar, so I cannot make modications to it, or at least I do not know how.

    I made a search for 'connection interval' and found multiple results, but In the end I ended up with something called Parcel received as input - this set the interval value.

    You can take a look at the bellow photo.

    It would be helpful if you can take a look in the Blinky example project for the connection interval variable that needs to be modified..

    In the Microcontroller the _MIN interval was set to 100ms and _MAX was set to 200ms.

    Currently I will try to set the _min and _max value on microcontroller to the same value of 10 ms and see what happens.

    Thanks for the help

    • Add to Phrasebook
      • No word lists for English -> English...
      • Create a new word list...
    • Copy
    • Add to Phrasebook
      • No word lists for English -> English...
      • Create a new word list...
    • Copy
  • Hello,

    Bujanca Ovidiu said:
    Regarding the other application, it was created using MIT App creator name APP Inventor V2, using blocks of code, so I cannot access the code behind the blocks in order to see the connection parameters.. It is a simple drag and drop application creator.

    I understand. I am personally not familiar with the MIT App creator APP Inventor V2 drag-and-drop program that you mention, but I would think that they list how to change the connection parameters as part of their documentation - since it is an integral part of the Bluetooth Low Energy specification.

    Bujanca Ovidiu said:
    I did not modified the connection parameters of the Blinky application. It is the default code as I said, with small modifications regarding UUIDs used with writeCharacteristic() function..

    Thank you for verifying this for me. The default connection interval ranges from 100 to 200 ms, if you application default to choosing the 200 ms connection interval that would reasonably explain why you are seeing between 3 and 5 packages per second.

    Bujanca Ovidiu said:
    Regarding connection interval in the code, the nordic ble library is compiled in a .jar, so I cannot make modications to it, or at least I do not know how.

    I would think that you would not have to make a change to the libraries they provide. Normally, you would just have to set the connection parameters - including connection interval min / max - as part of your BLE initiation.

    Bujanca Ovidiu said:
    You can take a look at the bellow photo.

    The photo depicts the legal values that those connection parameters can take. Each unit is 1.25 ms, and the possible connection intervals from the BLE specification ranges from 7.5 ms to 4 s - this equals the range 6 -  3200 in 1.25 ms units.

    Bujanca Ovidiu said:

    It would be helpful if you can take a look in the Blinky example project for the connection interval variable that needs to be modified..

    In the Microcontroller the _MIN interval was set to 100ms and _MAX was set to 200ms.

    You can change the parameters MIN_CONN_INTERVAL and MAX_CONN_INTERVAL in the Blinky example to whatever you want that is within the specified range, but the central might still reject the connection if it can not support the connection interval that the peripheral demands.
    I encourage you to test this out by changing the Blinky connection interval to 10 ms, your APP Inventor V2 might very well accept this connection interval.
    I would appreciate it if you could let me know if this solves the connection parameter issue with APP Inventor V2.

    Bear in mind that a shorter connection interval will require more active radio time, leading to higher power consumption. You are probably already aware of this, but I mention it just in case.

    Bujanca Ovidiu said:
    Thanks for the help

    No problem at all, I am happy to help!

    Best regards,
    Karl

  • 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

Reply
  • 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

Children
No Data
Related