Following the google ble app, I created two joysticks on the android app. Then, I am sending the joystick values from android phone to an arduino over ble using 1 write characteristics, the packets size is 4 bytes.
when I lift up my finger from the phone screen. The last packet will contain a stop signal, but on my arduino side, I can not receive the last packet 100% of the time.
I came across this post and found this source to build a queue to ensure data gets through.
After implementing the queue, I am able to use logcat to see that the queue is being used. However, I still couldn't receive the stop signal 100% of the time after implementing the queue.
I think it's because by the time calling on the writeCustomCharacteristic(packets, writecharacteristic_uuid) on the last packet, the write operation is still busy writing, therefore, it doesn't event send my last packet out.
following is my code:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d("onCharacteristicWrite", "reach onCharacteristicWrite +++++++++++++");
isWriting = false;
}
.
.
.
public void writeCustomCharacteristic(int value, String uuid_char) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT));
if (mCustomService == null) {
Log.w(TAG, "Custom BLE Service not found");
return;
}
writeValue(value, uuid_char, mCustomService);
/*get the read characteristic from the service*/
// BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString(uuid_char));
// mWriteCharacteristic.setValue(value, android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT16, 0);
// Log.d("CONNECT", "reached writeCustomCharacteristic");
// if (mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false) {
// Log.w(TAG, "Failed to write characteristic");
// }
}
public void writeValue(int dataInt, String uuid_char, BluetoothGattService mCustomService) {
writeQueue.addFirst(dataInt);
//Log.d("WriteQueue", "--------------write queue size: " + Integer.toHexString(writeQueue.peekFirst()));
writeNextValueFromQueue(mCustomService, uuid_char);
}
public void writeNextValueFromQueue(BluetoothGattService mCustomService,String uuid_char) {
if(isWriting) {
// if( (writeQueue.peekFirst() & LEFT_MOTOR_STOP_BIT_MASK ) != (1 << JoyStickActivity.LEFT_MOTOR_STOP_SIGNAL_MASK)) {
// return;
// }
Log.d("isWritingFromQueue", "reach is writing equal to ture -----------> " + Integer.toHexString(writeQueue.peekFirst()));
for(int s : writeQueue) {
System.out.println(Integer.toHexString(s));
Log.d("isWritingFromQueue", Integer.toHexString(s));
}
return;
}
if(writeQueue.size() == 0) {
Log.d("writeNextValueFromQueue", "reach queue size is zero --------------------");
return;
}
isWriting = true;
value = writeQueue.pollFirst();
Log.d("writeNextValueFromQueue", "++++++++++++++++value: " + Integer.toHexString(value));
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString(uuid_char));
mWriteCharacteristic.setValue(value,android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT32,0);
Log.d("CONNECT", "reached writeCustomCharacteristic");
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false){
Log.w(TAG, "Failed to write characteristic");
}
}
}
Update: I added a while statement in my writeNextValueFromQueue() function, now it catches that when I receives the packet with the stop signal, I use the while loop to wait until the onCharacteristicWrite() is done, then send my last packet. This way I ensured that I send the last packet every time, however, it delays the time when the motor stops by a few hundred milliseconds.
Is there any way, where I can drop whatever packets that I am sending when I received my stop signal instead of waiting for the packets to be finished sending, then send the packet that includes my stop signal?
public void writeNextValueFromQueue(BluetoothGattService mCustomService,String uuid_char) {
if(isWriting) {
if( (writeQueue.peekFirst() & LEFT_MOTOR_STOP_BIT_MASK ) != (1 << JoyStickActivity.LEFT_MOTOR_STOP_SIGNAL_MASK)) {
return;
}
while(isWriting) {
}
Log.d("isWritingFromQueue", "reach is writing equal to ture -----------> " + Integer.toHexString(writeQueue.peekFirst()));
for(int s : writeQueue) {
System.out.println(Integer.toHexString(s));
Log.d("isWritingFromQueue", Integer.toHexString(s));
}
// return;
}
if(writeQueue.size() == 0) {
Log.d("writeNextValueFromQueue", "reach queue size is zero --------------------");
return;
}
isWriting = true;
value = writeQueue.pollFirst();
Log.d("writeNextValueFromQueue", "++++++++++++++++value: " + Integer.toHexString(value));
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString(uuid_char));
mWriteCharacteristic.setValue(value,android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT32,0);
Log.d("CONNECT", "reached writeCustomCharacteristic");
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false){
Log.w(TAG, "Failed to write characteristic");
}
}
More Update: Since adding the while statement cause a lag in my app, I am trying to figure out a different solution. Following Emil's suggestion and I started to print out stuff in onCharacteristicWrite() callback. show in the code below:
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
final StringBuilder stringBuilder;
// Log.d("onCharacteristicWrite", "reach onCharacteristicWrite +++++++++++++");
if(status == BluetoothGatt.GATT_SUCCESS){
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
Log.d("onCharacteristicSuccess", "Value is " +stringBuilder.toString() );
}
}
isWriting = false;
}
Following is the log cat that successful sends the stop signal:
04-22 21:21:36.242 11242-11255/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.392 11242-11254/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.544 11242-11254/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.694 11242-11255/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.843 11242-11254/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:36.993 11242-11254/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:37.143 11242-11284/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:37.292 11242-11255/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:37.442 11242-11284/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 80 FF
04-22 21:21:38.947 11242-11284/com.example.android.toybot D/onCharacteristicSuccess: Value is 00 00 C0 00
As you can see, the very last packet contain C0, which is a stop signal. However, this signal does not get received most of the time.