The task is to transfer information from a chip with BLE 4.0 to an Android device at high speed (at least 24 kbps). Bluetooth specification allows it. We used two methods: write / read (we write the request into one characteristic, the answer is read from the other) and notify (the chip constantly transmitted packets with a frequency of 50 ms). In the case of write / read, the time for rewriting and reading a packet varies in the region of 100 ms. When using notify, the time was set to 50 ms, but Android was losing packets. Instead, he received the old values of the packets, or missed and read the next one twice, although the chip accurately sent notifications with new values. How can I solve or work around this problem?
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
updateConnectionState(R.string.connected);
invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
invalidateOptionsMenu();
clearUI();
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
//displayGattServices(mBluetoothLeService.getSupportedGattServices());
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
stopT =System.currentTimeMillis();
//double td=stopT-startT;
time1.add(stopT - startT);
//double td = Math;
double sum = 0;
for(int i =0;i<time1.size();i++) sum+= time1.get(i);
double td = sum/time1.size();
TextView textView3 = (TextView) findViewById(R.id.textView3);
textView3.setText(String.valueOf(td));
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
//for (int i = 0; i < BluetoothLeService.byteArray.length; i++) time.add(Double.valueOf(BluetoothLeService.byteArray[i]));
float[] floatArray = new float[BluetoothLeService.byteArray.length];
for (int i = 0; i < BluetoothLeService.byteArray.length; i++) floatArray[i] = (float)BluetoothLeService.byteArray[i];
float[] tmp = new float[time2.length + floatArray.length];
System.arraycopy(time2, 0, tmp, 0, time2.length);
System.arraycopy(floatArray, 0, tmp, time2.length, floatArray.length);
time2 = tmp;
if (cnt1 < 51) {
Matr[cnt1]=floatArray;
cnt1++;
}
if (flag == 1) {
startT = System.currentTimeMillis();
//mBluetoothLeService.readCustomCharacteristic();
mBluetoothLeService.writeCustomCharacteristic(hex);
}
if(flag_notify == 1)startT = System.currentTimeMillis();
} else if (BluetoothLeService.ACTION_CHARACTERISTIC_WRITE.equals(action)) {
mBluetoothLeService.readCustomCharacteristic();
}
}
};
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement 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_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Heart rate format UINT8.");
}
final int heartRate = characteristic.getIntValue(format, 1);
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
} else {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
byteArray =data;
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);
}
BluetoothGattCallback:
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;
//gatt.requestMtu(512);
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
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
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_CHARACTERISTIC_WRITE, characteristic);
} else {
Log.w(TAG, "onCharacteristicWrite received: " + status);
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
Upd.: Changes in Callback function.
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
StopT = System.currentTimeMillis();
if (cnt1 < kolvo) {
save[cnt1]=characteristic.getValue();
td1 [cnt1] = StopT - StartT;
StartT = System.currentTimeMillis();
cnt1++;
}
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}