26
26
import android .bluetooth .BluetoothGattCharacteristic ;
27
27
import android .bluetooth .BluetoothGattService ;
28
28
import android .content .Context ;
29
+ import android .text .TextUtils ;
29
30
31
+ import java .io .UnsupportedEncodingException ;
30
32
import java .util .LinkedList ;
31
33
import java .util .Queue ;
32
34
import java .util .UUID ;
36
38
public class UARTManager extends BleManager <UARTManagerCallbacks > {
37
39
/** Nordic UART Service UUID */
38
40
private final static UUID UART_SERVICE_UUID = UUID .fromString ("6E400001-B5A3-F393-E0A9-E50E24DCCA9E" );
39
- /** TX characteristic UUID */
40
- private final static UUID UART_TX_CHARACTERISTIC_UUID = UUID .fromString ("6E400002-B5A3-F393-E0A9-E50E24DCCA9E" );
41
41
/** RX characteristic UUID */
42
- private final static UUID UART_RX_CHARACTERISTIC_UUID = UUID .fromString ("6E400003-B5A3-F393-E0A9-E50E24DCCA9E" );
42
+ private final static UUID UART_RX_CHARACTERISTIC_UUID = UUID .fromString ("6E400002-B5A3-F393-E0A9-E50E24DCCA9E" );
43
+ /** TX characteristic UUID */
44
+ private final static UUID UART_TX_CHARACTERISTIC_UUID = UUID .fromString ("6E400003-B5A3-F393-E0A9-E50E24DCCA9E" );
45
+ /** The maximum packet size is 20 bytes. */
46
+ private static final int MAX_PACKET_SIZE = 20 ;
43
47
44
- private BluetoothGattCharacteristic mTXCharacteristic , mRXCharacteristic ;
48
+ private BluetoothGattCharacteristic mRXCharacteristic , mTXCharacteristic ;
49
+ private byte [] mOutgoingBuffer ;
50
+ private int mBufferOffset ;
45
51
46
52
public UARTManager (final Context context ) {
47
53
super (context );
@@ -60,30 +66,59 @@ protected BleManagerGattCallback getGattCallback() {
60
66
@ Override
61
67
protected Queue <Request > initGatt (final BluetoothGatt gatt ) {
62
68
final LinkedList <Request > requests = new LinkedList <>();
63
- requests .push (Request .newEnableNotificationsRequest (mRXCharacteristic ));
69
+ requests .push (Request .newEnableNotificationsRequest (mTXCharacteristic ));
64
70
return requests ;
65
71
}
66
72
67
73
@ Override
68
74
public boolean isRequiredServiceSupported (final BluetoothGatt gatt ) {
69
75
final BluetoothGattService service = gatt .getService (UART_SERVICE_UUID );
70
76
if (service != null ) {
71
- mTXCharacteristic = service .getCharacteristic (UART_TX_CHARACTERISTIC_UUID );
72
77
mRXCharacteristic = service .getCharacteristic (UART_RX_CHARACTERISTIC_UUID );
78
+ mTXCharacteristic = service .getCharacteristic (UART_TX_CHARACTERISTIC_UUID );
79
+ }
80
+
81
+ boolean writeRequest = false ;
82
+ boolean writeCommand = false ;
83
+ if (mRXCharacteristic != null ) {
84
+ final int rxProperties = mRXCharacteristic .getProperties ();
85
+ writeRequest = (rxProperties & BluetoothGattCharacteristic .PROPERTY_WRITE ) > 0 ;
86
+ writeCommand = (rxProperties & BluetoothGattCharacteristic .PROPERTY_WRITE_NO_RESPONSE ) > 0 ;
87
+
88
+ // Set the WRITE REQUEST type when the characteristic supports it. This will allow to send long write (also if the characteristic support it).
89
+ // In case there is no WRITE REQUEST property, this manager will divide texts longer then 20 bytes into up to 20 bytes chunks.
90
+ if (writeRequest )
91
+ mRXCharacteristic .setWriteType (BluetoothGattCharacteristic .WRITE_TYPE_DEFAULT );
73
92
}
74
- return mTXCharacteristic != null && mRXCharacteristic != null ;
93
+
94
+ return mRXCharacteristic != null && mTXCharacteristic != null && (writeRequest || writeCommand );
75
95
}
76
96
77
97
@ Override
78
98
protected void onDeviceDisconnected () {
79
- mTXCharacteristic = null ;
80
99
mRXCharacteristic = null ;
100
+ mTXCharacteristic = null ;
81
101
}
82
102
83
103
@ Override
84
104
public void onCharacteristicWrite (final BluetoothGatt gatt , final BluetoothGattCharacteristic characteristic ) {
85
- final String data = characteristic .getStringValue (0 );
86
- mCallbacks .onDataSent (data );
105
+ // When the whole buffer has been sent
106
+ final byte [] buffer = mOutgoingBuffer ;
107
+ if (mBufferOffset == buffer .length ) {
108
+ try {
109
+ mCallbacks .onDataSent (new String (buffer , "UTF-8" ));
110
+ } catch (final UnsupportedEncodingException e ) {
111
+ // do nothing
112
+ }
113
+ mOutgoingBuffer = null ;
114
+ } else { // Otherwise...
115
+ final int length = Math .min (buffer .length - mBufferOffset , MAX_PACKET_SIZE );
116
+ final byte [] data = new byte [length ]; // We send at most 20 bytes
117
+ System .arraycopy (buffer , mBufferOffset , data , 0 , length );
118
+ mBufferOffset += length ;
119
+ mRXCharacteristic .setValue (data );
120
+ writeCharacteristic (mRXCharacteristic );
121
+ }
87
122
}
88
123
89
124
@ Override
@@ -100,13 +135,30 @@ protected boolean shouldAutoConnect() {
100
135
}
101
136
102
137
/**
103
- * Sends the given text to TH characteristic.
138
+ * Sends the given text to RX characteristic.
104
139
* @param text the text to be sent
105
140
*/
106
141
public void send (final String text ) {
107
- if (mTXCharacteristic != null ) {
108
- mTXCharacteristic .setValue (text );
109
- writeCharacteristic (mTXCharacteristic );
142
+ // An outgoing buffer may not be null if there is already another packet being sent. We do nothing in this case.
143
+ if (!TextUtils .isEmpty (text ) && mOutgoingBuffer == null ) {
144
+ final byte [] buffer = mOutgoingBuffer = text .getBytes ();
145
+ mBufferOffset = 0 ;
146
+
147
+ // 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),
148
+ // or divide it into up to 20 bytes chunks and send them one by one.
149
+ final boolean writeRequest = (mRXCharacteristic .getProperties () & BluetoothGattCharacteristic .PROPERTY_WRITE ) > 0 ;
150
+
151
+ if (!writeRequest ) { // no WRITE REQUEST property
152
+ final int length = Math .min (buffer .length , MAX_PACKET_SIZE );
153
+ final byte [] data = new byte [length ]; // We send at most 20 bytes
154
+ System .arraycopy (buffer , 0 , data , 0 , length );
155
+ mBufferOffset += length ;
156
+ mRXCharacteristic .setValue (data );
157
+ } else { // there is WRITE REQUEST property
158
+ mRXCharacteristic .setValue (buffer );
159
+ mBufferOffset = buffer .length ;
160
+ }
161
+ writeCharacteristic (mRXCharacteristic );
110
162
}
111
163
}
112
164
}
0 commit comments