Skip to content

Commit

Permalink
UART divides long text into 20B parts
Browse files Browse the repository at this point in the history
UART now checks the RX characteristic properties and:
1) it will use long write if WRITE REQUEST is set,
2) it will divide the text into up to 20-bytes packets
Also the app background has been fixed.
  • Loading branch information
philips77 committed Aug 17, 2015
1 parent 54507a1 commit 341ecf5
Show file tree
Hide file tree
Showing 35 changed files with 316 additions and 75 deletions.
16 changes: 9 additions & 7 deletions app/app.iml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
<afterSyncTasks>
<task>generateDebugAndroidTestSources</task>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
Expand All @@ -24,7 +26,7 @@
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
<exclude-output />
Expand All @@ -34,13 +36,13 @@
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
Expand Down Expand Up @@ -70,7 +72,7 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/22.2.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/22.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/22.2.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
Expand All @@ -89,7 +91,7 @@
<orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="gson-2.3.1" level="project" />
<orderEntry type="library" exported="" name="design-22.2.0" level="project" />
<orderEntry type="library" exported="" name="design-22.2.1" level="project" />
<orderEntry type="library" exported="" name="nrf-logger-v2.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-22.2.1" level="project" />
<orderEntry type="library" exported="" name="achartengine-1.1.0" level="project" />
Expand Down
6 changes: 3 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ android {
applicationId "no.nordicsemi.android.nrftoolbox"
minSdkVersion 18
targetSdkVersion 22
versionCode 35
versionName "1.14.2"
versionCode 36
versionName "1.14.3"
}
buildTypes {
release {
Expand All @@ -21,7 +21,7 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.1'
compile 'com.android.support:design:22.2.0'
compile 'com.android.support:design:22.2.1'
compile project(':dfu')
compile files('libs/achartengine-1.1.0.jar')
compile files('libs/nrf-logger-v2.0.jar')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ protected final boolean enableNotifications(final BluetoothGattCharacteristic ch
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) == 0)
return false;

Logger.d(mLogSession, "gatt.setCharacteristicNotification(" + characteristic.getUuid() + ", true)");
gatt.setCharacteristicNotification(characteristic, true);
final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
if (descriptor != null) {
Expand All @@ -366,6 +367,7 @@ protected final boolean enableIndications(final BluetoothGattCharacteristic char
if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) == 0)
return false;

Logger.d(mLogSession, "gatt.setCharacteristicNotification(" + characteristic.getUuid() + ", true)");
gatt.setCharacteristicNotification(characteristic, true);
final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
if (descriptor != null) {
Expand Down Expand Up @@ -414,7 +416,7 @@ protected final boolean writeCharacteristic(final BluetoothGattCharacteristic ch
if ((properties & (BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) == 0)
return false;

Logger.v(mLogSession, "Writing characteristic " + characteristic.getUuid());
Logger.v(mLogSession, "Writing characteristic " + characteristic.getUuid() + " (" + getWriteType(characteristic.getWriteType()) + ")");
Logger.d(mLogSession, "gatt.writeCharacteristic(" + characteristic.getUuid() + ")");
return gatt.writeCharacteristic(characteristic);
}
Expand Down Expand Up @@ -921,4 +923,17 @@ private String bondStateToString(final int state) {
return "UNKNOWN";
}
}

private String getWriteType(final int type) {
switch (type) {
case BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT:
return "WRITE REQUEST";
case BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE:
return "WRITE COMMAND";
case BluetoothGattCharacteristic.WRITE_TYPE_SIGNED:
return "WRITE SIGNED";
default:
return "UNKNOWN: " + type;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.text.TextUtils;

import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.UUID;
Expand All @@ -36,12 +38,16 @@
public class UARTManager extends BleManager<UARTManagerCallbacks> {
/** Nordic UART Service UUID */
private final static UUID UART_SERVICE_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
/** TX characteristic UUID */
private final static UUID UART_TX_CHARACTERISTIC_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
/** RX characteristic UUID */
private final static UUID UART_RX_CHARACTERISTIC_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
private final static UUID UART_RX_CHARACTERISTIC_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
/** TX characteristic UUID */
private final static UUID UART_TX_CHARACTERISTIC_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
/** The maximum packet size is 20 bytes. */
private static final int MAX_PACKET_SIZE = 20;

private BluetoothGattCharacteristic mTXCharacteristic, mRXCharacteristic;
private BluetoothGattCharacteristic mRXCharacteristic, mTXCharacteristic;
private byte[] mOutgoingBuffer;
private int mBufferOffset;

public UARTManager(final Context context) {
super(context);
Expand All @@ -60,30 +66,59 @@ protected BleManagerGattCallback getGattCallback() {
@Override
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.push(Request.newEnableNotificationsRequest(mRXCharacteristic));
requests.push(Request.newEnableNotificationsRequest(mTXCharacteristic));
return requests;
}

@Override
public boolean isRequiredServiceSupported(final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID);
if (service != null) {
mTXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
mRXCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID);
mTXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID);
}

boolean writeRequest = false;
boolean writeCommand = false;
if (mRXCharacteristic != null) {
final int rxProperties = mRXCharacteristic.getProperties();
writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;
writeCommand = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0;

// Set the WRITE REQUEST type when the characteristic supports it. This will allow to send long write (also if the characteristic support it).
// In case there is no WRITE REQUEST property, this manager will divide texts longer then 20 bytes into up to 20 bytes chunks.
if (writeRequest)
mRXCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);

This comment has been minimized.

Copy link
@metc

metc May 17, 2016

@philips77 The WRITE_TYPE_DEFAULT correspond to ATT R/W requests (with peer acknowledge).
So by setting the write type to WRITE_TYPE_DEFAULT, this will send a long write and the data will be spitted in chunk of 20 bytes ? I did no find anything in the Android API documentation about this feature. Where di you find the information ?
I am very curious about this feature, I will try it and check with a BLE sniffer ;)

This comment has been minimized.

Copy link
@philips77

philips77 May 17, 2016

Author Member

Yes. There is no special API for long writes, like for reliable. Android handles it automatically. Tested, works on all phones. No documentation, of course :)

This comment has been minimized.

Copy link
@metc

metc May 17, 2016

This is good to know, thanks !
So let's say you send 100 bytes, you will get only one onCharacteristicWrite event even if 5 write request have been sent ? They are no seq. diagrams, I will need my sniffer tomorrow ;)

On the nRF side (ble_nus implementation), how the Rx characteristic has to be defined ? Is it still a 20 bytes characteristic ?

This comment has been minimized.

Copy link
@philips77

philips77 May 18, 2016

Author Member

Hmm.. no idea. You have to handle some event and have a buffer. Please ask this question on the DevZone.

This comment has been minimized.

Copy link
@metc

metc May 18, 2016

Okay, no problem ;) Thanks for you help !

This comment has been minimized.

Copy link
@AlejandroHCruz

AlejandroHCruz Apr 5, 2018

Asking the question here since there's no documentation: We don't need to explicitly set the write type to be default in order to send longer bytes since it is set to that value by default, correct?

This comment has been minimized.

Copy link
@philips77

philips77 Apr 5, 2018

Author Member

The default value is determined by the characteristic properties. If there is write_request property, the default is used. If only the write_no_response - the corresponding one. But I'd set it off you're using no response, as there was a big in some Android version and the default one was always set as a default.

}
return mTXCharacteristic != null && mRXCharacteristic != null;

return mRXCharacteristic != null && mTXCharacteristic != null && (writeRequest || writeCommand);
}

@Override
protected void onDeviceDisconnected() {
mTXCharacteristic = null;
mRXCharacteristic = null;
mTXCharacteristic = null;
}

@Override
public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
final String data = characteristic.getStringValue(0);
mCallbacks.onDataSent(data);
// When the whole buffer has been sent
final byte[] buffer = mOutgoingBuffer;
if (mBufferOffset == buffer.length) {
try {
mCallbacks.onDataSent(new String(buffer, "UTF-8"));
} catch (final UnsupportedEncodingException e) {
// do nothing
}
mOutgoingBuffer = null;
} else { // Otherwise...
final int length = Math.min(buffer.length - mBufferOffset, MAX_PACKET_SIZE);
final byte[] data = new byte[length]; // We send at most 20 bytes
System.arraycopy(buffer, mBufferOffset, data, 0, length);
mBufferOffset += length;
mRXCharacteristic.setValue(data);
writeCharacteristic(mRXCharacteristic);
}
}

@Override
Expand All @@ -100,13 +135,30 @@ protected boolean shouldAutoConnect() {
}

/**
* Sends the given text to TH characteristic.
* Sends the given text to RX characteristic.
* @param text the text to be sent
*/
public void send(final String text) {
if (mTXCharacteristic != null) {
mTXCharacteristic.setValue(text);
writeCharacteristic(mTXCharacteristic);
// An outgoing buffer may not be null if there is already another packet being sent. We do nothing in this case.
if (!TextUtils.isEmpty(text) && mOutgoingBuffer == null) {
final byte[] buffer = mOutgoingBuffer = text.getBytes();
mBufferOffset = 0;

// Depending on whether the characteristic has the WRITE REQUEST property or not, we will either send it as it is (hoping the long write is implemented),
// or divide it into up to 20 bytes chunks and send them one by one.
final boolean writeRequest = (mRXCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;

if (!writeRequest) { // no WRITE REQUEST property
final int length = Math.min(buffer.length, MAX_PACKET_SIZE);
final byte[] data = new byte[length]; // We send at most 20 bytes
System.arraycopy(buffer, 0, data, 0, length);
mBufferOffset += length;
mRXCharacteristic.setValue(data);
} else { // there is WRITE REQUEST property
mRXCharacteristic.setValue(buffer);
mBufferOffset = buffer.length;
}
writeCharacteristic(mRXCharacteristic);
}
}
}
34 changes: 0 additions & 34 deletions app/src/main/res/drawable/background.xml

This file was deleted.

8 changes: 8 additions & 0 deletions app/src/main/res/layout-land/activity_feature_bpm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -293,5 +293,13 @@
android:onClick="onConnectClicked"
android:text="@string/action_connect" />

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/background_title"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="6dp"/>

</no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout>
</LinearLayout>
8 changes: 8 additions & 0 deletions app/src/main/res/layout-land/activity_feature_csc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -290,5 +290,13 @@
android:onClick="onConnectClicked"
android:text="@string/action_connect" />

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/background_title"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="6dp"/>

</no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout>
</LinearLayout>
8 changes: 8 additions & 0 deletions app/src/main/res/layout-land/activity_feature_dfu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -260,5 +260,13 @@
android:onClick="onConnectClicked"
android:text="@string/action_select" />

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/background_title"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="6dp"/>

</no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout>
</LinearLayout>
8 changes: 8 additions & 0 deletions app/src/main/res/layout-land/activity_feature_gls.xml
Original file line number Diff line number Diff line change
Expand Up @@ -214,5 +214,13 @@
android:onClick="onConnectClicked"
android:text="@string/action_connect" />

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/background_title"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="6dp"/>

</no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout>
</LinearLayout>
8 changes: 8 additions & 0 deletions app/src/main/res/layout-land/activity_feature_hrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,13 @@
android:onClick="onConnectClicked"
android:text="@string/action_connect" />

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/background_title"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="6dp"/>

</no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout>
</LinearLayout>
7 changes: 7 additions & 0 deletions app/src/main/res/layout-land/activity_feature_hts.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@
android:onClick="onConnectClicked"
android:text="@string/action_connect" />

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/background_title"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="6dp"/>

</no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout>
</LinearLayout>
8 changes: 8 additions & 0 deletions app/src/main/res/layout-land/activity_feature_proximity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,13 @@
android:onClick="onConnectClicked"
android:text="@string/action_connect" />

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/background_title"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="6dp"/>

</no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout>
</LinearLayout>
Loading

0 comments on commit 341ecf5

Please sign in to comment.