I am writing a Xamarin.Android application, but this question is applicable to native Android and BLE in general. I have a write characteristic that I can write to, and it works as long as I don't send more than 600 characters. Anything over 600 characters gets truncated. Looking at my logs, I can see that the text is being split into 20 character packets, and OnCharacteristicWriteRequest is called for each packet, but stops being called after 600 characters. I am testing with 2 Android tablets. My code to write to the characteristic:
public override void OnServicesDiscovered(BluetoothGatt gatt, [GeneratedEnum] GattStatus status)
{
base.OnServicesDiscovered(gatt, status);
try
{
if (status != GattStatus.Success)
{
Log?.Invoke("discover services failed");
return;
}
Log?.Invoke("services discovered");
if(RequestForAddressExists(gatt.Device.Address))
{
lock (_requestsLocker)
{
Java.Util.UUID serviceUuid = GetRequestedServiceUuid(gatt.Device.Address);
Java.Util.UUID characteristicUuid = GetRequestedCharacteristicUuid(gatt.Device.Address);
BluetoothGattCharacteristic characteristic = gatt.GetService(serviceUuid).GetCharacteristic(characteristicUuid);
Log?.Invoke("characterisitic found");
var request = _requests.FirstOrDefault(r => r.DeviceAddress == gatt.Device.Address);
if (characteristic.Properties.HasFlag(GattProperty.Write))
{
Log?.Invoke("writing characteristic...");
string data = ((WriteCharacteristicRequest)request).Data;
characteristic.SetValue($"{data}{Constants.WriteCharacteristicEndDelimiter}");
characteristic.WriteType = GattWriteType.Default;
gatt.WriteCharacteristic(characteristic);
}
else
{
Log?.Invoke("GattProperty not supported");
_requests.Remove(request);
}
}
}
}
catch (Exception e)
{
Log?.Invoke(e.Message);
}
}
public override void OnCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, [GeneratedEnum] GattStatus status)
{
base.OnCharacteristicWrite(gatt, characteristic, status);
if (status != GattStatus.Success)
{
Log?.Invoke($"OnCharacteristicWrite status not success: {status}");
}
else
{
Log?.Invoke("OnCharacteristicWrite success");
}
gatt.Disconnect();
gatt.Close();
lock (_requestsLocker)
{
var r = _requests.FirstOrDefault(x => x.DeviceAddress == gatt.Device.Address);
if (r != null)
{
_requests.Remove(r);
}
}
}
My code to accept the write request:
public override void OnCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, bool preparedWrite, bool responseNeeded, int offset, byte[] value)
{
base.OnCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
Log?.Invoke("OnCharacteristicWriteRequest");
string data = System.Text.Encoding.UTF8.GetString(value);
Log?.Invoke(data);
string characteristicId = new Guid(characteristic.Uuid.ToString()).ToString().ToUpperInvariant();
var record = _writeCharacteristicsReceived.FirstOrDefault(c => c.DeviceAddress == device.Address && c.CharacteristicId.ToUpperInvariant() == characteristicId);
if(record != null)
{
record.Data += data;
}
else
{
record = new CharacteristicWriteReceived()
{
CharacteristicId = characteristicId,
DeviceAddress = device.Address,
Data = data
};
_writeCharacteristicsReceived.Add(record);
}
if (record.Data.EndsWith(Constants.WriteCharacteristicEndDelimiter) == true)
{
Log?.Invoke("end found");
_writeCharacteristicsReceived.Remove(record);
record.Data = record.Data.Substring(0, record.Data.Length - Constants.WriteCharacteristicEndDelimiter.Length); // remove the end delimeter
Log?.Invoke(record.Data);
OnCharacteristicWriteReceived?.Invoke(record);
}
if (responseNeeded)
{
BluetoothGattServer.SendResponse(device, requestId, GattStatus.Success, 0, value);
}
}
public override void OnExecuteWrite(BluetoothDevice device, int requestId, bool execute)
{
// need to override OnExecuteWrite and call SendResponse here as well,
// since the execute packet corresponds to the last ATT packet that the client sends as a "finish" marker,
// and the client expects a response to know that the server accepted the writes
base.OnExecuteWrite(device, requestId, execute);
BluetoothGattServer.SendResponse(device, requestId, GattStatus.Success, 0, new byte[0]);
}
The funny thing is, even when the text is truncated, I still get status == GattStatus.Success in my OnCharacteristicWrite. Why is it being truncated? Is there a maximum number of packets that can be sent?
Both devices are continuously advertising and scanning on BLE while writing to this characteristic...could that cause a problem?
A characteristic value can only be 512 bytes long per specification. Writing a longer value is not allowed, even if apparently some stacks don't enforce it.
When you write a value longer than what fits in the MTU (default 23 bytes minus 3 for header), the sender Bluetooth stack splits it up in multiple chunks (Prepared Write) and then sends an Execute request to commit. For each chunk you have the offset parameter so you know at which offset to write the current chunk.
Related
I wrote an Android Phone app in Android Studio that connects to a UbloX NINA B1 to send and receive data on the SPS Service.
I'm having issues with the incoming data from the NINA B1 (Peripheral). I'm not sure if I connected correctly and turned the notifications on correctly.
Below is the code where I do the connection to the SPS Service. (Hardcoded to select Group 3 and child 0)
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
// Clicked on a Caracteristic (eg. FIFO or Credits)
public boolean enableNotification() {
// Hardcode for SPS service on NINA B112, can only use this service, other services will not be used
// This groupPosition and childPosition was determined from A_05 code, The selectable list gave these values when selecting SPS service
int groupPosition = 3;
int childPosition = 0;
BluetoothGattCharacteristic characteristic;
characteristic = characteristics_HashMapList.get(services_ArrayList.get(groupPosition).getUuid().toString()).get(childPosition);
// Todo find a better way to do below two lines. This is a temp way to pass characteristic & mBTLE_Service to static variables to use in HomeFragment for sending data
//Copy characteristics of SPS service to static act_characteristic for use by HomeFragment
this.act_characteristic = characteristic;
//Copy mBTLE_Service of SPS service to static act_service for use by HomeFragment
this.act_service = mBTLE_Service;
if (Utils.hasWriteProperty(characteristic.getProperties()) != 0) {
String uuid = characteristic.getUuid().toString();
//act_characteristic.setTitle(uuid);
//act_characteristic.setService(mBTLE_Service);
//act_characteristic.setCharacteristic(characteristic);
//dialog_btle_characteristic.show(getFragmentManager(), "Dialog_BTLE_Characteristic");
} if (Utils.hasReadProperty(characteristic.getProperties()) != 0) {
if (mBTLE_Service != null) {
mBTLE_Service.readCharacteristic(characteristic);
}
} if (Utils.hasNotifyProperty(characteristic.getProperties()) != 0) {
if (mBTLE_Service != null) {
mBTLE_Service.setCharacteristicNotification(characteristic, true);
}
}
return false;
}
Here is where I set the notifications ON, this part I'm not so confident about.
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(getString(R.string.CLIENT_CHARACTERISTIC_CONFIG)));
// Todo: if the indications and notifications is to be used, then mode the indications part back into setCharacteristicNotification() and add a check for Indications, then change below code to set both indication and notify
if (enabled) {
// Enable INDICATION & NOTIFICATION
final byte[] ENABLE_INDICATION_NOTIFICATION = {0x03, 0x00};
descriptor.setValue(ENABLE_INDICATION_NOTIFICATION);
}
else {
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}
//ToDo Shorten the delay time so that the Notifications Enable still works
// Delay in milli seconds
int m_sec = 200;
Delay.delay(m_sec, new Delay.DelayCallback() {
#Override
public void afterDelay() {
// Enable Notifications after 200 m_sec Delay
mBluetoothGatt.writeDescriptor(descriptor);
}
});
}
This is where I handle the incoming Bytes, I send a Modbus message from the Phone to NINA B1, then NINA B1 replies with a Modbus message. The Incoming byte count is always < 20 bytes. And I fill the RxBuff until the correct amount of bytes are received AND the Slave Address is correct, then I decode the received message.
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
intent.putExtra(EXTRA_UUID, characteristic.getUuid().toString());
}
// For all other profiles, writes the data formatted in HEX.
// Only Pack 20 bytes at a time coming from BLE server into data[]
final byte[] rx_Data;
int tempSlavAdr;
rx_Data = characteristic.getValue();
if (rx_Data != null && rx_Data.length > 0) {
// Only handle message if request came from ReadInput_Thread
if (this.request_flag) {
// ToDO: See if other non Modbus data arrives between packets
// Populate RxBuff
for (int i = 0; i < rx_Data.length; i++) {
this.RxBuff[this.WrPtr++] = rx_Data[i];
}
Log.d(TAG,"QTY Bytes in rx_Data = " + (Integer)rx_Data.length);
// Start Decode message only after all expected bytes are received && first message is Slave Address
// Prevent Negative numbers in Slave Address: tempSlavAdr is used in the the next if statement
tempSlavAdr = (byte) this.RxBuff[0];
if (tempSlavAdr < 0) tempSlavAdr += 256;
if ((this.WrPtr == FragmentHome.ExpectedCount_sent) && (tempSlavAdr == slaveAddr)) {
// Copy RxBuff over to Dec_RxBuff
int Dec_RxBuff[] = new int[255];
for (int i = 0; i < this.WrPtr; i++) {
Dec_RxBuff[i] = (this.RxBuff[i]);
Dec_RxBuff[i] += 256;
Dec_RxBuff[i] = Dec_RxBuff[i] & 0xFF;
}
// Clear flag indicating that Thread Send a Request
this.request_flag = false;
message_rx = false;
// Decode ModbusMessage and message Good
if (modbusHandler.DecodeModbusMessage(Dec_RxBuff)){
message_rx = true;
}
// Decode ModbusMessage and message Bad
else{
message_rx = false;
}
// Clear buffers
WrPtr = 0;
Arrays.fill(rx_Data, (byte) 0);
Arrays.fill(RxBuff, (byte) 0);
// Todo What if WrPtr stop short of Expected counter? Do some protection
// WrPtr > ExpectedCount Clear Buffers
} else if (WrPtr > FragmentHome.ExpectedCount_sent) {
// Clear buffers
// HomeFragment.set_Actual(false);
Log.d(TAG,"RX Count to big expected " + FragmentHome.ExpectedCount_sent + " got " + WrPtr);
WrPtr = 0;
Arrays.fill(rx_Data, (byte) 0);
Arrays.fill(RxBuff, (byte) 0);
}
// Todo Use this intent to pass data to a service to Decode Modbus Data (Service not written yet)
// intent.putExtra(EXTRA_DATA, new String(data) + "\n" + Utils.hexToString(data));
}
}
else {
//intent.putExtra(EXTRA_DATA, "0");
}
//sendBroadcast(intent);
}
I still get some data loss, and not sure how to handle this. Phone and NINA B1 is next to one another so distance is not a problem.
Can I get some help on how to set the indications correctly? And why I might lose bytes.
Marinus
I badly need this to proceed further in my application.
I'm very much familiar with Android BLE and using for years.
I have the below code to enable notification and it is working for years with my peripheral. onCharacteristicChanged() method is called with "OK_N1" when notification is enabled.
private void enableNotification(String serviceUUID, String characteristicUUID) {
if (bluetoothGatt == null) {
return;
}
BluetoothGattService service = bluetoothGatt.getService(UUID.fromString(serviceUUID));
if (service == null) {
return;
}
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(characteristicUUID));
bluetoothGatt.setCharacteristicNotification(characteristic, true);
enableDescriptor(characteristic);
}
private void enableDescriptor(BluetoothGattCharacteristic bluetoothGattCharacteristic) {
if (bluetoothGatt == null) {
return;
}
BluetoothGattDescriptor descriptor = bluetoothGattCharacteristic.getDescriptor(
UUID.fromString(PodsServiceCharacteristics.CLIENT_CHARACTERISTIC_CONFIG));
if (descriptor == null)
return;
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
}
Now, I am using Polidea RxAndroidble(ver 1.7.0) with RxJava2 to make things easy.
I have the following code with Polidea's RxAndroidBle which is not working.
public void enableNotifications(#NotNull String[] characteristics) {
if (isConnected()) {
mNotificationSubscriber = mRxBleConnection.setupNotification(UUID.fromString(characteristics[0]))
.doOnNext(notificationObservable -> notificationHasBeenSetUp())
.flatMap(notificationObservable -> notificationObservable)
.subscribe(this::onNotificationReceived, this::onNotificationSetupFailure);
}
}
private void onNotificationReceived(byte[] bytes) {
Log.i(TAG, "onNotificationReceived");
}
private void onNotificationSetupFailure(Throwable throwable) {
Log.i(TAG, "onNotificationSetupFailure" + throwable.getMessage());
}
private void notificationHasBeenSetUp() {
Log.i(TAG, "notificationHasBeenSetUp");
}
notificationHasBeenSetUp() is called but onNotificationReceived() is not called, where I get "OK_N1" bytes
It is probably because your peripheral sends a notification right after the Client Characteristic Configuration Descriptor is set.
By default RxAndroidBle sets up notifications fully before emitting the Observable<byte[]> i.e. the CCC descriptor has to be successfully written before the emission.
Since library version 1.8.0 it is possible to use NotificationSetupMode.QUICK_SETUP which emits Observable<byte[]> as soon as possible — before the CCC descriptor is written allowing to capture such early notifications/indications.
mRxBleConnection.setupNotification(bluetoothGattCharacteristic, NotificationSetupMode.QUICK_SETUP)
Pre 1.8.0 version answer
To not miss any "early" emissions one may leverage NotificationSetupMode.COMPAT in which the library does not handle writing the CCC descriptor*.
(...)
mNotificationSubscriber = mRxBleConnection.discoverServices()
.flatMap(rxBleDeviceServices -> rxBleDeviceServices.getCharacteristic(characteristicUuid))
.flatMapObservable(bluetoothGattCharacteristic -> {
BluetoothGattDescriptor cccDescriptor = bluetoothGattCharacteristic.getDescriptor(PodsServiceCharacteristics.CLIENT_CHARACTERISTIC_CONFIG);
Completable enableNotificationCompletable = mRxBleConnection.writeDescriptor(cccDescriptor, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
Completable disableNotificationCompletable = mRxBleConnection.writeDescriptor(cccDescriptor, BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE).onErrorComplete();
return mRxBleConnection.setupNotification(bluetoothGattCharacteristic, NotificationSetupMode.COMPAT)
.doOnNext(notificationObservable -> notificationHasBeenSetUp())
.flatMap(notificationObservable -> notificationObservable)
.mergeWith(enableNotificationCompletable)
.doOnDispose(disableNotificationCompletable::subscribe) // fire and forget
.share(); // this can be omitted but I put it here in case the resulting `Observable<byte[]>` would be shared among multiple subscribers
})
.subscribe(this::onNotificationReceived, this::onNotificationSetupFailure);
(...)
I think since this is apparently quite common situation it will be handled by the library at some point.
* NotificationSetupMode.COMPAT was introduced mainly for BLE peripherals that do not follow BLE specification and do not have CCC descriptor yet will send notifications all the time
I am trying to write text data to my BLE device. So , i am following Android Bluetooth GATT classes to do the task. But i found writing the text to the Characteristics is fine but while trying to retrieve the Characteristics value , it returns null.
MyCode :
public void writeCharacteristic(BluetoothGattCharacteristic characteristic,
String text) {
String TAGS ="MyBeacon";
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAGS, "BluetoothAdapter not initialized");
return;
} else {
Log.w(TAGS, "Writting ... ");
}
byte[] data = hexStringToByteArray(text);
Log.w(TAGS, "Writting text = " + data);
try {
characteristic.setValue(URLEncoder.encode(text, "utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
boolean writeValue = mBluetoothGatt.writeCharacteristic(characteristic);
Log.w(TAGS, "Writting Status = " + writeValue);
}
// Successfully onCharacteristicWrite also gets called //
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
String TAGS ="MyBeacon";
String text = null;
try {
text = new String(characteristic.getValue(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Log.w(TAGS, "onCharacteristicWrite = " + text+" :: "+status);
}
but while trying to read the Characteristics it returns null.
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
final byte[] data = gattCharacteristic.getValue(); // returns null
if (data != null && data.length > 0) {
Log.d("MyBeacon", " Read Data ")
} else {
Log.d("MyBeacon", " Data is null")
}
}
MyBeacon
Also check the issue in other thread too.
Please help me out , suggest me some solution to write and read data successfully to my Beacon.
Syntax should be as follows,
mBluetoothGatt.readCharacteristic(characteristic);
Reading characteristics:
You can read the characteristic using mBluetoothGatt.readCharacteristic(characteristic);
You can have to read the characteristic's descriptor as follows,
mBluetoothGatt.readDescriptor(ccc);
Once you read it, it should return data by calling the onDescriptorRead callback.
Here you can set up (subscribe) to the charactersitic through either notification or indication by calling:
mBluetoothGatt.setCharacteristicNotification(characteristic, true)
once it returns true you will need to write to the descriptor again (the value of notification or indication)
BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(CCC);
clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
//clientConfig.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(clientConfig);
Once this is done you will get notifications through onCharacteristicChanged callback every time the characteristic changes.
Do update me , if you have any problems while implementing,
I faced a similar issue where the characteristic.getValue returns Null. I was following exactly what is mentioned in the BLE Gatt documentation, and other blogs, but still the issue persisted until finally I understood what I was doing wrong.
At client device end, we setValue into the characteristic that we are interested in using
gatt.WriteCharacteristic(characteristic.setValue("Hello"));
At Server end, the request is received onto the onCharacteristicWriteRequest(....) callback.
Generally we expect the value that we set at client end to be carried by the characteristic parameter but we observe the characteristic.getValue() is null.
Where in the same callback we also have another parameter by name "Value" which actually carries the characteristic value we set at Client end. Please refer this parameter and this should solve the problem.
Did you read it too early? It should be read after onCharacteristicWrite() has been called.
After successfully solving the familiar problem in onCharacteristicwrite, I continue to encounter those status 133 in readCharacteristic function.
A brief code here: I store characteristics to variables in onServicesDiscovered function:
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
try {
syncDataService = gatt.getService(GiraffeFriendAttributes.SYNC_DATA_SERVICE);
if (syncDataService == null) throw new AssertionError("sync data service null!");
syncDataInputChar = syncDataService.getCharacteristic(GiraffeFriendAttributes.SYNC_DATA_INPUT_CHAR);
syncDataOutputChar = syncDataService.getCharacteristic(GiraffeFriendAttributes.SYNC_DATA_OUTPUT_CHAR);
if (syncDataInputChar == null || syncDataOutputChar == null) throw new AssertionError("sync data service null!");
...
} catch ...
}
And then after some writing of SYNC_DATA_INPUT_CHAR into the device, the device will change the value of one of it's characteristic and I will need to fetch that value. So I write codes below.
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d(TAG, String.format("Sync: onCharWrite, status = %d", status));
try {
...
else if (characteristic.getUuid().equals(SYNC_DATA_INPUT_CHAR)) {
Log.d(TAG, String.format("Sync: on write data index: %x, %x", dataIndexs[0], dataIndexs[1]));
gatt.readCharacteristic(syncDataOutputChar);
}
} catch ...
}
Error occurs in the readCharacteristic function, it triggers the onCharacteristicRead function with status 133.
Here are some logs:
D/BluetoothGatt﹕ writeCharacteristic() - uuid: 0000ffa6-0000-1000-8000-00805f9b34fb
D/BluetoothGatt﹕ onCharacteristicRead() - Device=78:A5:04:3D:4F:C6 UUID=0000ffab-0000-1000-8000-00805f9b34fb Status=133
W/BluetoothGatt﹕ Unhandled exception: java.lang.NullPointerException: src == null
onClientConnectionState() - status=0 clientIf=4 device=78:A5:04:3D:4F:C6
As #benka has told me, I've checked the properties of the characteristic and found that the value is 10. I thought it should be 2(PROPERTY_READ) + 8(PROPERTY_WRITE), so directly call function readCharacteristic should be OK. I will put all attributes of the characteristic below.
syncDataOutputChar = {android.bluetooth.BluetoothGattCharacteristic#830030678056}
mDescriptors = {java.util.ArrayList#830030679448} size = 0
mValue = null
mUuid = {java.util.UUID#830030680416}"0000ffab-0000-1000-8000-00805f9b34fb"
mService = {android.bluetooth.BluetoothGattService#830031005904}
mProperties = 10
mPermissions = 0
mKeySize = 16
mInstance = 0
mWriteType = 2
I hope if anyone has this familiar problem and may kindly give me some suggestions.
Thanks a lot!
--- EDIT 1
I forgot to say that, the value above is all decimal, it can be view as hex though.
--- EDIT 2
After trying for a long time, problem remains unsolved, yet I've made some experiments.
Since the characteristic to read is both readable and writable, I tried to write something into it, just to see what will happen.
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d(TAG, String.format("Sync: onCharWrite, status = %d", status));
try {
...
else if (characteristic.getUuid().equals(SYNC_DATA_INPUT_CHAR)) {
Log.d(TAG, String.format("Sync: on write data index: %x, %x", dataIndexs[0], dataIndexs[1]));
//gatt.readCharacteristic(syncDataOutputChar);
syncDataOutputChar.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
syncDataOutputChar.setValue(0, BluetoothGattCharacteristic.FORMAT_SINT32, 0);
gatt.writeCharacteristic(syncDataOutputChar);
}
} catch ...
}
Unexpectedly, it yields a DeadObjectException and quits. This is weird and likely to be some clues leading to the problem. And I also think the Unhandled exception: java.lang.NullPointerException: src == nullin the logs above is worth digging too.
I am trying to receive data from Arduino to my Android device. I started from here
In the activity part of the application, they did
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if(fromUser){
if(sUsbController != null){
sUsbController.send((byte)(progress&0xFF));
}
}
}
In the send function
public void send(byte data) {
mData = data;
synchronized (sSendLock) {
sSendLock.notify();
}
}
And in the UsbRunnable part
private class UsbRunnable implements Runnable {
private final UsbDevice mDevice;
UsbRunnable(UsbDevice dev) {
mDevice = dev;
}
#Override
public void run() {//here the main USB functionality is implemented
UsbDeviceConnection conn = mUsbManager.openDevice(mDevice);
if (!conn.claimInterface(mDevice.getInterface(1), true)) {
return;
}
// Arduino Serial usb Conv
conn.controlTransfer(0x21, 34, 0, 0, null, 0, 0);
conn.controlTransfer(0x21, 32, 0, 0, new byte[] { (byte) 0x80,
0x25, 0x00, 0x00, 0x00, 0x00, 0x08 }, 7, 0);
...
...
conn.bulkTransfer(epOUT, new byte[] { mData }, 1, 0);
So, App took the progress of the seekbar and sent it to the Arduino.
But, I want my app to receive data from Arduino. I guess I need to use bulktransfer function as well. think that I want to save the data to mData variable.
How can I do that?
Using the bulkTransfer method is the way to go. You will need to use the IN endpoint to receive the data. For instance, to get a byte of data from the Arduino use this:
byte[] reply = new byte[1]; // to store data from Arduino
int size = 1; // receive at most 1 byte of data
int timeout = 100; // try to receive data for up to 100 milliseconds
int count = conn.bulkTransfer(epIN, reply, size, timeout);
if(count < 0) {
Log.d("ArduinoUSB", "Failure occurred when receiving from Arduino");
} else {
Log.d("ArduinoUSB", "Received " + count + " bytes: " + Arrays.toString(reply));
}
The data will be stored in reply.