i don't receive more then one packet on my smartphone - java

For a project I want to send acceleration data via BLE 4.2 (with DLE). An acceleration packet consists of 81 values (24 bits each, total 243 bytes). My goal is to send 18 packets (1458 acceleration packets or 4374 bytes). I use a Samsung Galaxy A3 2017 Edition as a central and a microcontroller (nRF52832dk) as a peripheral. After all packets have been sent, the connection to the smartphone is terminated and new 1458 acceleration packets are recorded. After that, an RTC activates sleep mode, on the nRF52832dk, for 1 minute. After 1 minute, the nRF52832dk is going to advertising for a new connection with the smartphone. The following figure illustrates the problem:
https://ibb.co/Syb4GDg
The software on the nRF52832dk works perfectly fine. I am able to record data, go into sleep mode, wake-up after 1 minute and advertise for new connection. My problem is the software application. I use these tutorials:
• https://github.com/googlesamples/android-BluetoothLeGatt
• https://developer.android.com/guide/topics/connectivity/bluetooth-le
in BluetoothLeGatt I have changed:
mBluetoothGatt = device.connectGatt(this, true, mGattCallback);
with the second parameter on true its possible for the smartphone to autoconnect. This works fine (for the first connection with the nRF)
Originally it was:
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Once a connection has been established, the callback routine is called by the GATT handler.
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
// Change in the characteristic
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}; </i>
after the connection is established and the first packet is received, i get into the broadcastUpdate
<i>private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the nRF52 profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
if (UUID_NRF.equals(characteristic.getUuid())) {
byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
}
} else {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
}
}
sendBroadcast(intent);
}
Now I got two problems (I had the same two problems before did the change in the code).
First Problem:
My first problem is, that I just receive only one of the 18 BLE package (the first one).
Second Problem:
My first Problem is also causing my second Problem. The Application does not recognize that the connection has been terminated from the nRF52832dk.
and I have another question. what exactly does
endBroadcast(intent);
?

This post is very complicated, I think you mean you cannot receive nrf52 data.
You need check nrf52 support how many MTU, BLE protect max is '247' and valid data length is '244' valid length is (DEVICE_MTU - OPCODE_LENGTH(1) - HANDLE_LENGTH(2));
So as you say you want receive 2474 bytes, it's at least 17 times.
current process at android is onCharacteristicChanged - > onCharacteristicRead
if you want trigger onCharacteristicChanged you need open remote device notification like this:
private void EnableNotification(BluetoothGattDescriptor d, BluetoothGatt gatt)
{
gatt.SetCharacteristicNotification(d.Characteristic, true);
d.SetValue(new byte[] { 1, 1 });
gatt.WriteDescriptor(d);
}

Related

BLE Gatt status 133 in onCharacteristicWrite

I'm trying to connect to a BLE device that has one characteristic to write requests for data and another that sends notifications with said data. I'm able to write to the CCCD with no problems, but when I write to the write characteristic, 9 times out of 10 I get a gatt status 133 error. I've checked the properties, set the write type, and added a 600ms wait before each command, but nothing seems to be helping.
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.d(MY_TAG, "Wrote " + descriptor.getUuid() + " with status " + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(MY_TAG, "Write Successful");
enableAllNotifications();
try {
writeData(new byte[] {4, 0, 36});
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
Log.d(MY_TAG, "Write failed");
}
}
};
enableAllNotifications() just sets notifications on my end, since onCharacteristicChanged() only seems to be called when both have notifications set.
private void writeData(byte[] message) throws InterruptedException {
BluetoothGattCharacteristic characteristic = mainActivity.deviceServices.get(0)
.getCharacteristic(ActiCharacteristicUuids.WriteUUID);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
characteristic.setValue(message);
TimeUnit.MILLISECONDS.sleep(600);
bluetoothGatt.writeCharacteristic(characteristic);
}
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(MY_TAG, "Inside onCharactersiticWrite with status: " + status);
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.d(MY_TAG, "Write failed");
retryWrite(characteristic);
} else {
Log.d(MY_TAG, "Write Successful");
gatt.readCharacteristic(characteristic);
}
}
I don't know if this is helpful, but I've been testing with a Samsung Galaxy S10+ and a Samsung Galaxy S8 Active, and both seem to have these issues. I don't have another device to test if this is just a Samsung issue.
I don't know why this worked, but I had called writeDescriptor inside the main activity. For some reason, changing that call to readDescriptor, and then writing to the CCC inside readDescriptor solved the problem. I guess it was a threading issue? So, if anyone else is experiencing this problem, try to have all of your writes (including writeDescriptor and writeCharacteristic) on the same thread.

How to configure ble advertisement in android for ios to detect

With my current configuration, other android device gets to read the set UUID just fine but when it comes to iOS, my colleague is getting variants of UUID from this advertisement/GATT broadcast. Do I really need to broadcast GATT for iOS to discover me?
Starting the advertisement:
#ReactMethod
private void advertise(Callback advCallBack) {
...
private static UUID myUUID = UUID.fromString("A85A30E5-93F3-42AE-86EB-33BFD8133597");
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH).setConnectable(false).build();
ParcelUuid pUuid = new ParcelUuid(myUUID);
AdvertiseData data = new AdvertiseData.Builder().setIncludeDeviceName(false).addServiceUuid(pUuid)
.setIncludeTxPowerLevel(true).build();
AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
}
#Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
}
};
advertiser.startAdvertising(settings, data, advertisingCallback);
}
Starting the GATT Server:
#ReactMethod
private void startServer(Callback srvCallBack) {
mBluetoothGattServer = mBluetoothManager.openGattServer(getReactApplicationContext(), mGattServerCallback);
if (mBluetoothGattServer == null) {
srvCallBack.invoke(false);
return;
}
mBluetoothGattServer.addService(new BluetoothGattService(myUUID, BluetoothGattService.SERVICE_TYPE_PRIMARY));
srvCallBack.invoke(true);
}
private BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {
#Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
return;
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
return;
}
}
};
We don't need to connect to each other, we just need to scan for its existence and maybe pass bits of information which I can't do right now from android because just including the device name is giving me an Error code 1 which basically means that the payload is bigger than the allowed 31 bytes for the advertisement packet. Any advise?
I solved the problem by including a serviceData on the advertising data.
AdvertiseData advertiseData = new AdvertiseData.Builder().setIncludeDeviceName(true)
.addServiceUuid(new ParcelUuid(SERVICE_UUID)).addServiceData(new ParcelUuid(SERVICE_UUID), serviceData)
.setIncludeTxPowerLevel(true).build();

(java, bluetooth-lowenergy, ble) how to get data from android device via BLE

i'm beginner of BLE(Bluetooth-LowEnergy). I wanted to get data from android device via BLE.
I've already read about characteristic in Google Document.
and i've already searched on google too.
my device didn't respond to my request byte code.
i think it's because i set wrong characteristics.
cus i think i didn't understand about characteristics perfectly.
does anybody help me to set right characteristics please ?
Here's custom Uuid(it's better to see added Images on the top.)
CUSTOM SERVICE
0783b03e-8535-b5a0-7140-a304d2495cb7
NOTIFY Uuid : 0783B03E-8535-B5A0-7140-A304D2495CB8
Read Uuid : 00002a19-0000-1000-8000-00805f9b34fb
Write Uuid : 0783b03e-8535-b5a0-7140-a304d2495cba
and Here's Uuid I set
public final UUID serviceUuid = UUID.fromString("0783b03e-8535-b5a0-7140-a304d2495cb7");
public final UUID notifyUuid = UUID.fromString("0783b03e-8535-b5a0-7140-a304d2495cb8");
public final UUID readUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
public final UUID writeUuid = UUID.fromString("0783b03e-8535-b5a0-7140-a304d2495cba");
and Here's my code
BluetoothHandler.java
targetGattCharacteristic = targetGattService.getCharacteristic(Define.GetInstance().notifyUuid);
BluetoothGattCharacteristic readGattCharacteristic = targetGattService.getCharacteristic(Define.GetInstance().notifyUuid);
if (readGattCharacteristic != null) {
mBleService.setCharacteristicNotification(readGattCharacteristic, true);
} else {
callInterface();
return;
}
(BluetoothService.java)
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor gD = new BluetoothGattDescriptor(UUID.fromString(Define.GetInstance().readUuid.toString()), BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattDescriptor.PERMISSION_READ);
characteristic.addDescriptor(gD);
if (Define.GetInstance().notifyUuid.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(Define.GetInstance().readUuid.toString()));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
i solved it by referring to this site.
https://medium.com/#avigezerit/bluetooth-low-energy-on-android-22bc7310387a

How can I receive data from a BLE Device?

So, I am developing a Java BLE Android Module using Eclipse (to code the module and Appcelerator (to make the Android App). I am trying to receive data from a BLE Device and show it on an Android Phone. I can scan the device and connect to it.
But I really, really can't receive any data from it.
I have tried at least 10 different stuff but...
The main problem is that I don't know the BLE API very well, and I am a little noobie in Java. Can anyone please help a poor soul to actually read the data from the device?
The main problem is setting the Bluetooth Characteristic UUID (which I have). I just don't know how to do it...
Bellow are the codes for the Module...
public class AndroidbleModule extends KrollModule {
public static final String LCAT = "BLE";
private BluetoothManager btManager;
private BluetoothAdapter btAdapter;
private BluetoothDevice btDevice;
private TiApplication appContext;
private Activity activity;
private KrollFunction onFound;
private KrollFunction onConnections;
private BluetoothLeScanner btScanner;
private UUID uuid;
BluetoothGatt bluetoothGatt;
BluetoothGattCharacteristic btChar;
BluetoothGattCallbackHandler btData;
KrollDict kd;
Boolean isConnected = false;
BluetoothGatt connectedGatt;
private ScanCallback scanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
if (device != null) {
BluetoothDeviceProxy btDeviceProxy = new
BluetoothDeviceProxy(device);
if (device.getName() != null) {
Log.d(LCAT, "Found: " + device.getName() + " " +
device.getAddress());
ArrayList<String> ids = new ArrayList<String>();
if (device.getUuids() != null) {
for (ParcelUuid id1 : device.getUuids()) {
ids.add(id1.toString());
}
}
btDevice = device;
kd = new KrollDict();
kd.put("name", btDevice.getName());
kd.put("macaddress", btDevice.getAddress());
fireEvent("nb_DevicesFound", kd);
btScanner.stopScan(scanCallback);
}
}
}
};
#Kroll.method
public boolean connect()
{
try {
bluetoothGatt = btDevice.connectGatt(appContext, true,
new BluetoothGattCallbackHandler(AndroidbleModule.this));
if (bluetoothGatt != null) {
System.out.println("***** ***** Connected to: =====>>>>> " + btDevice.getAddress() + " " + btDevice.getName());
this.fireEvent("nb_onConnect",null);
isConnected = true;
bluetoothGatt = connectedGatt;
}
} catch (Exception e) {
isConnected = false;
this.fireEvent("nb_NoConnection", null);
}
return true;
};
#Kroll.method
public void readData()
{
System.out.println("WHAT THE HELL DO I DO????");
}
}
public final class BluetoothGattCallbackHandler extends
BluetoothGattCallback {
private static final String LCAT = AndroidbleModule.LCAT;
private KrollProxy proxy;
private static final String UUID_SERVICE_TS002004 = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
private static final String UUID_CHARACTERISTIC_WRITE_TS002004 = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
private static final String UUID_CHARACTERISTIC_NOTIFY_TS002004 = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
BluetoothGattCharacteristic btCharacteristic;
public BluetoothGattCallbackHandler(KrollProxy proxy) {
super();
this.proxy = proxy;
}
#Override
public void onConnectionStateChange(final BluetoothGatt gatt,
final int status, final int newState) {
KrollDict kd = new KrollDict();
kd.put("newState", newState);
kd.put("status", status);
if (proxy.hasListeners("didConnectionStateChange")) {
proxy.fireEvent("didConnectionStateChange", kd);
}
gatt.discoverServices();
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
Log.i(LCAT,"onServicesDiscovered");
if (status != BluetoothGatt.GATT_SUCCESS) return;
btCharacteristic =
gatt.getService(UUID.fromString(UUID_SERVICE_TS002004)).getCharacteristic(UUID.fromString(UUID_CHARACTERISTIC_NOTIFY_TS002004));
gatt.setCharacteristicNotification(btCharacteristic,true);
BluetoothGattDescriptor descriptor = btCharacteristic.getDescriptor(UUID.fromString(UUID_CHARACTERISTIC_WRITE_TS002004));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic) {
byte[] data = characteristic.getValue();
Log.i(LCAT, "Char changed " + data.toString());
for (BluetoothGattDescriptor descriptor :
characteristic.getDescriptors()) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.i(LCAT,"onCharacteristicRead");
}
#Override
public void onDescriptorRead(BluetoothGatt gatt,
BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
Log.i(LCAT,"onDescriptorRead");
}
}
I expect to some good soul that will go to Heaven to have mercy on me and help me get those sweet bytes of data.
One of the things that is missing in your code, is to Set Notifications, so the Central can listen to the Peripheral's response.
Try something like this:
public void setNotifications() {
BluetoothGattService service = bluetoothGatt.getService(SERVICE_UUID);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC_UUID);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
characteristic.addDescriptor(descriptor);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
bluetoothGatt.writeDescriptor(descriptor);
bluetoothGatt.setCharacteristicNotification(characteristic, true);
}
After that, you can send commands to the device and hear it's return.
public void returnData(String data) {
BluetoothGattService service = bluetoothGatt.getService(SERVICE_UUID);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC_UUID);
String dataString = data;
dataString.getBytes();
writeCharacteristic.setValue(dataString);
writeCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
bluetoothGatt.writeCharacteristic(writeCharacteristic);
}
First of all, read the bluetooth overview. Check if bluetooth permissions have been added to the project.
One thing that is wrong here is that isConnected=true is set too early, because you can consider that you are connected after ble services has been discovered and (status == BluetoothGatt.GATT_SUCCESS). Otherwise, you can't read and write characteristics.
A good starting point can be this repo from google. It is old project and I'm not sure if you have to update some dependency to make it compile, but nothing important.
Establish a connection and start reading bytes is easy, but if you want establish a reliable connection with ble device, due to android fragmentation and manufacturerers that don't follow the bluetooth specs, it can be super difficult, almost imposible to make a bluetooth low energy that works perfect for all devices.
Once you have started to read some bytes, I suggest this video to learn some important tricks about. If you want go deeper, read carefully this fantastic resource about ble.
Once you start to get desperate with ble, probably it will be a good moment to read this list of known issues
Finally, you will discover that the best thing that you can do with ble low energy in android is use open source libraries like the Nordic semiconductor ble library or RxAndroid Ble.
But before use a ble library, it is a good practice understand what is doing the library and understand why you need it.
EDIT: I have never used appcelerator, but here you have a bluetooth module for appcelerator titanium.
You have the wrong uuid for the Client Characteristic Configuration Descriptor. It should be 00002902-0000-1000-8000-00805f9b34fb but you have written 6E400002-B5A3-F393-E0A9-E50E24DCCA9E.

Not Receiving BLE Notifications in Android

I am working with a BLE device in ANDROID.
Here is where I set up the endpoint 0000fff4-0000-1000-8000-00805f9b34fb to receive notifications (CLIENT_CHARACTERISTIC_CONFIG is 00002902-0000-1000-8000-00805f9b34fb
public void k2DigitalNotification(BluetoothGattCharacteristic characteristic,
boolean enabled)
{
Boolean myStatus;
if (MY_BLUETOOTH_SERVICE.equals(characteristic.getUuid()))
{
Log.v(TAG, "Characteristic: " + characteristic.getUuid());
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
myStatus = mBluetoothGatt.writeDescriptor(descriptor);
Log.v(TAG,"Write Status::"+myStatus);
bluetoothGatt.setCharacteristicNotification(characteristic, true);
}
}
Here is the code where I write out to the device. THIS WORKS! 100%, the data shows up at the embedded BLE device. (endpoint is 0000fff1-0000-1000-8000-00805f9b34fb )
public void k2digitalWriteToCharacteristic(BluetoothGattCharacteristic characteristic) {
if (BLE_ENDPOINT.equals(characteristic.getUuid()))
{
Log.v(TAG,"0Xfff1");
byte[] data3Send = new byte[4];
data3Send[0] = 0x31;
data3Send[1] = 0x01;
data3Send[2] = 0x5a;
data3Send[2] = 0x0d;;
characteristic.setValue(data3Send);
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
Log.v(TAG, "Status is:" + String.valueOf(status));
}
}
The BLE device is sending the data out.....I've verified this in apps like nRFMaster from Nordic Semi or BLEScanner from Bluepixel.
But I NEVER EVER see the callback.
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
Log.v(TAG,"A Characteristic Change?!?!?!");
byte[] data = characteristic.getValue();
Log.v(TAG,"Here is the data: "+data[0]);
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
Any help? I've been banging my head against the wall all week.
My issue was regarding the ble device was busy. I was attempting to read and subscribe without much gap in time and the ble device was busy. you can check if the enable notification was successful with the following code:
Boolean status = bluetoothGatt.writeDescriptor(descriptor);
This will return true if the writeDescriptor was successful and false otherwise - hence helping you debug if the ble device is busy.

Categories

Resources