USB interrupt transfer lost data - android

Since few days I am dealing with confusing USB problem. My Android(4.2) application should have connect with USB device which transmit/receive data using USB HID interrupt protocol. Sending data from Android to device works perfectly but I have got plenty of problems with receiving proper data. Main application based on 3 tasks: main task (UI), USB receive task and USB transmit task. USB's tasks have separate queue to insert received data (receiver) or obtain data to send (sender) which comes from main task. I try to sniff data that comes over USB (using android virtual machine and Windows USB analyzer) and everything looks fine but Android receives only zeros (sometimes receives another expected values).
Here is my reading and writting code - both works in separate Runnable instance:
public boolean writeRawData(UsbDeviceConnection connection, UsbRequest request, ByteBuffer buffer, int bufsize)
{
if (request.queue(buffer, bufsize) == true)
{
return true;
}
return false;
}
public ByteBuffer readRawData(UsbDeviceConnection connection, UsbRequest request, ByteBuffer buffer, int bufsize)
{
if (request.queue(buffer, bufsize) == true)
{
if (connection.requestWait() == request)
{
//deal with received data -> almost always wrong!
}
}
return null;
}

Related

Making READ, WRITE and NOTIFY working on Android BLE (version 21 and above)

In my application, I got the READ and WRITE to work on specific BluetoothGattCharacteristic objects.
The BluetoothGattCallback onCharacteristicWrite and onCharacteristicRead are properly called.
I have then tried to setup the NOTIFY option so my Android app gets notified when a specific characteristic on the device changes.
I have set this up via the following code:
// Local notifications
mGatt.setCharacteristicNotification(statusTypeCharacteristic, notify);
// Remote notifications
BluetoothGattDescriptor desc = statusTypeCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
Log.d("Descriptor", desc.toString());
boolean test;
test = desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); // return value = true
test = mGatt.writeDescriptor(desc); // return value = true
When the characteristic changes, the callback: onCharacteristicChanged is being called as expected
However, now all READ and WRITE operations do not work anymore.
When I comment the lines dealing with the descriptor, the READ and WRITE work again.
A part I am very unclear is around the UUID used to get the descriptor. Is it correct? Should I scan instead all descriptors from the characteristic and enable notification on one? How do I know which one to set as I have multiple ones coming back?
Ok, so I have figured out the issue.
At the beginning of my application, I am configuring (i.e. writing) to lots of descriptors.
2 issues with it:
1- A descriptor can only be written one at a time
2- No read/write operations can happen when a descriptor is being written to
The fix is to create a queue of write descriptor operations and perform the next descriptor write in the onDescriptorWrite callback.
private void writeGattDescriptor(BluetoothGattDescriptor d) {
//put the descriptor into the write queue
descriptorWriteQueue.add(d);
//if there is only 1 item in the queue, then write it. If more than 1, we handle asynchronously in the
// callback
if(descriptorWriteQueue.size() == 1) {
mGatt.writeDescriptor(d);
}
}
And then in the callback:
#Override
public void onDescriptorWrite (BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
// Called when the descriptor is updated for notification
Log.d("onDescriptorWrite", descriptor.getUuid().toString());
// pop the item that we just finishing writing
descriptorWriteQueue.remove();
// if there is more to write, do it!
if(descriptorWriteQueue.size() > 0) {
mGatt.writeDescriptor(descriptorWriteQueue.element());
}
// Inform the framework that the scope has connected, configured and ready to process commands
if(descriptorWriteQueue.size() == 0) {
// Do something else, such as reads and writes
}
}

Android runtime exec with NetworkRequest

I am running a command line argument in my Android application like:
ProcessBuilder pb = new ProcessBuilder(cmds);
Process process = pb.start();
process.waitFor();
Where cmds are a list of arguments to run. My commands probe a remote URL over a http connection. My device is connected to a WiFi network that does not have access to the internet, but does host the URL I want to probe. My device also has a cellular connection that does have access to the internet, but not the URL. My device is running Android 6.0 Marshmallow.
Normally in Lollipop or above, Android defaults to the network with a connection to the internet. To access WiFi networks without internet you need to use NetworkRequest, e.g: https://stackoverflow.com/a/27958106/1847734.
How can I pass an obtained Network to the above Process, so that the connection goes over my WiFi network, not my cellular network?
Do I instead need to use ConnectivityManager#bindProcessToNetwork? How do I join the process to set the network using this method? There doesn't seem to be an option to give the process.
Starting from Lollipop Network is Parcelable so you can write it to a byte array and then read back. Let's start from the writing part.
final Parcel parcel = Parcel.obtain();
try {
// Create a byte array from Network.
parcel.writeParcelable(network, 0);
final byte[] data = parcel.marshall();
// Start a process.
ProcessBuilder pb = new ProcessBuilder(cmds);
Process process = pb.start();
// Send serialized Network to the process.
final DataOutputStream out = new DataOutputStream(process.getOutputStream());
out.write(data.length);
out.write(data);
// Wait until the process terminates.
process.waitFor();
} finally {
parcel.recycle();
}
And the reading part.
// Read data from the input stream.
final DataInputStream in = new DataInputStream(System.in);
final int length = in.readInt();
final byte[] data = new byte[length];
in.readFully(data);
final Parcel parcel = Parcel.obtain();
try {
// Restore Network from a byte array.
parcel.unmarshall(data, 0, data.length);
final Network network = parcel.readParcelable(null);
// Use the Network object to bind the process to it.
connectivityManager.bindProcessToNetwork(network);
} finally {
parcel.recycle();
}
This code will work on Android 6.0 only. If you want it to work on Lollipop you should use ConnectivityManager.setProcessDefaultNetwork(Network) instead of ConnectivityManager.bindProcessToNetwork(Network). And this code is not going to work on devices before Android 5.0.
UPDATE:
For a non-Android process you can create a socket, bind it to the nework with Network.bindSocket(Socket) and pass a socket descriptor to the child process.
If the previous approach doesn't work for you, you can call NDK function android_setsocknetwork from multinetwork.h or even try and do what Android does when you bind a process to a given network. Everything you might be interested in happens in netd client. NetdClient sends a message to fwmarkd here passing a network id. Actual message sending happens here. But I would recommend to use this approach as the last chance way to solve your problem.

Android, holding tcp connection in sleep mode

I am trying to keep a tcp connection to a server alive even while the phone goes into sleep mode. I have searched everywhere and tried everything. This problem occurs on some phones and not others which is kind of random.
So basically one client sends a request to the server, then the server sends the request to another client. What happens is that the receiving client doesn't get the request at all. I have tested this with a debugger and the next line of code after the read never gets called. It is important for the device to receive the message right away. I am wondering how viber is achieving this. I thought about google cloud messaging but i would have to re-implement a lot, also according to the documentation, even with google cloud messaging the message doesn't necessarily reach the destination right away.
here is my code:
class BackgroundReadThread extends Thread {
#Override
public void run()
{
while(connectedToServer)
{
try
{
int bytesRead=0;
if(myWifiLock!=null && !myWifiLock.isHeld())
myWifiLock.acquire();
byte val=(byte)myInputStream.read();
myWakeLock.acquire();//this line never gets called when in sleep
if(val==-1)
{
unexpectedDisconnectionFromServer();
if(myWifiLock!=null && myWifiLock.isHeld())
myWifiLock.release();
myWakeLock.release();
return;
}
bytesRead=myInputStream.read(myBuffer, 0, bufferSize);
if(bytesRead<1)
{
unexpectedDisconnectionFromServer();
if(myWifiLock!=null && myWifiLock.isHeld())
myWifiLock.release();
myWakeLock.release();
return;
}
byte[] dataArray=Arrays.copyOfRange(myBuffer,0,bytesRead);
ByteBuffer data=ByteBuffer.allocate(bytesRead+1).put(val).put(dataArray);
myParent.invokeReceiveAction(data, bytesRead+1);
}
catch (IOException e)
{
myWakeLock.acquire();
unexpectedDisconnectionFromServer();
e.printStackTrace();
}
finally
{
if(myWifiLock!=null && myWifiLock.isHeld())
myWifiLock.release();
if(myWakeLock!=null && myWakeLock.isHeld())
myWakeLock.release();
}
}
}
}
EDIT: forgot to mention that this code is running in a service
I have no idea why but the problem only occurs sometimes and it only occurs on the debug version of the application. I have tested the release version of the application and it never failed once on any of the phones ive tested it on. So i guess the problem is with the debug version although i have no idea why. Hope this helps someone having similar problems.

Android 4.3: How to connect to multiple Bluetooth Low Energy devices

My Question is: Can Android 4.3 (client) have active connections with multiple BLE devices (servers)? If so, how can I achieve it?
What I did so far
I try to evaluate what throughput you can achieve using BLE and Android 4.3 BLE API. In addition I also try to find out how many devices can be connected and active at the same time. I use a Nexus 7 (2013), Android 4.4 as master and TI CC2540 Keyfob as slaves.
I wrote a simple server software for the slaves, which transmits 10000 20Byte packets through BLE notifications. I based my Android App on the Application Accelerator from the Bluetooth SIG.
It works well for one device and I can achieve around 56 kBits payload throughput at a Connection Interval of 7.5 ms. To connect to multiple slaves I followed the advice of a Nordic Employee who wrote in the Nordic Developer Zone:
Yes it's possible to handle multiple slaves with a single app. You would need to handle each slave with one BluetoothGatt instance. You would also need specific BluetoothGattCallback for each slave you connect to.
So I tried that and it partly works. I can connect to multiple slaves. I can also register for notifications on multiple slaves. The problem begins when I start the test. I receive at first notifications from all slaves, but after a couple Connection Intervals just the notifications from one device come trough. After about 10 seconds the other slaves disconnect, because they seem to reach the connection time-out. Sometimes I receive right from the start of the test just notifications from one slave.
I also tried accessing the attribute over a read operation with the same result. After a couple of reads just the answers from one device came trough.
I am aware that there are a few similar questions on this forum: Does Android 4.3 support multiple BLE device connections?, Has native Android BLE GATT implementation synchronous nature? or Ble multiple connection. But none of this answers made it clear for me, if it is possible and how to do it.
I would be very grateful for advice.
I suspect everyone adding delays is just allowing the BLE system to complete the action you have asked before you submit another one. Android's BLE system has no form of queueing. If you do
BluetoothGatt g;
g.writeDescriptor(a);
g.writeDescriptor(b);
then the first write operation will immediately be overwritten with the second one. Yes it's really stupid and the documentation should probably actually mention this.
If you insert a wait, it allows the first operation to complete before doing the second. That is a huge ugly hack though. A better solution is to implement your own queue (like Google should have). Fortunately Nordic have released one for us.
https://github.com/NordicSemiconductor/puck-central-android/tree/master/PuckCentral/app/src/main/java/no/nordicsemi/puckcentral/bluetooth/gatt
Edit: By the way this is the universal behaviour for BLE APIs. WebBluetooth behaves the same way (but Javascript does make it easier to use), and I believe iOS's BLE API also behaves the same.
Re visting the bluetooth-lowenergy problem on android: I am still using delays.
The concept: after every major action that provokes the BluetoothGattCallback (e.g. conenction, service discovery, write, read) a dealy is needed. P.S. have a look at Google example on BLE API level 19 sample for connectivity to understand how Broadcasts should be sent and get some general understanding etc...
Firstly, scan (or scan) for BluetoothDevices, populate the connectionQueue with desired devices and call initConnection().
Have a look on the following example.
private Queue<BluetoothDevice> connectionQueue = new LinkedList<BluetoothDevice>();
public void initConnection(){
if(connectionThread == null){
connectionThread = new Thread(new Runnable() {
#Override
public void run() {
connectionLoop();
connectionThread.interrupt();
connectionThread = null;
}
});
connectionThread.start();
}
}
private void connectionLoop(){
while(!connectionQueue.isEmpty()){
connectionQueue.poll().connectGatt(context, false, bleInterface.mGattCallback);
try {
Thread.sleep(250);
} catch (InterruptedException e) {}
}
}
Now if all is good, you have made connections and BluetoothGattCallback.onConnectionStateChange(BluetoothGatt gatt, int status, int newState) has been called.
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
switch(status){
case BluetoothGatt.GATT_SUCCESS:
if (newState == BluetoothProfile.STATE_CONNECTED) {
broadcastUpdate(BluetoothConstants.ACTION_GATT_CONNECTED, gatt);
}else if(newState == BluetoothProfile.STATE_DISCONNECTED){
broadcastUpdate(BluetoothConstants.ACTION_GATT_DISCONNECTED, gatt);
}
break;
}
}
protected void broadcastUpdate(String action, BluetoothGatt gatt) {
final Intent intent = new Intent(action);
intent.putExtra(BluetoothConstants.EXTRA_MAC, gatt.getDevice().getAddress());
sendBroadcast(intent);
}
P.S. sendBroadcast(intent) might need to be done like this:
Context context = activity.getBaseContext();
context.sendBroadcast(intent);
Then the broadcast is received by BroadcastReceiver.onReceive(...)
public BroadcastReceiver myUpdateReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(BluetoothConstants.ACTION_GATT_CONNECTED.equals(action)){
//Connection made, here you can make a decision: do you want to initiate service discovery.
// P.S. If you are working with multiple devices,
// make sure that you start the service discovery
// after all desired connections are made
}
....
}
}
After doing whatever you want in the broadcast receiver, here is how I continue:
private Queue<BluetoothGatt> serviceDiscoveryQueue = new LinkedList<BluetoothGatt>();
private void initServiceDiscovery(){
if(serviceDiscoveryThread == null){
serviceDiscoveryThread = new Thread(new Runnable() {
#Override
public void run() {
serviceDiscovery();
serviceDiscoveryThread.interrupt();
serviceDiscoveryThread = null;
}
});
serviceDiscoveryThread.start();
}
}
private void serviceDiscovery(){
while(!serviceDiscoveryQueue.isEmpty()){
serviceDiscoveryQueue.poll().discoverServices();
try {
Thread.sleep(250);
} catch (InterruptedException e){}
}
}
Again, after a successful service discovery, BluetoothGattCallback.onServicesDiscovered(...) is called. Again, I send an intent to the BroadcastReceiver (this time with different action String) and it is now that you can start reading, writing and enabling notifications/indications...
P.S. If you are working with multiple devices, make sure that you start the reading, writing etc... stuff after all devices have reported that their services have been discovered.
private Queue<BluetoothGattCharacteristic> characteristicReadQueue = new LinkedList<BluetoothGattCharacteristic>();
private void startThread(){
if(initialisationThread == null){
initialisationThread = new Thread(new Runnable() {
#Override
public void run() {
loopQueues();
initialisationThread.interrupt();
initialisationThread = null;
}
});
initialisationThread.start();
}
}
private void loopQueues() {
while(!characteristicReadQueue.isEmpty()){
readCharacteristic(characteristicReadQueue.poll());
try {
Thread.sleep(BluetoothConstants.DELAY);
} catch (InterruptedException e) {}
}
// A loop for starting indications and all other stuff goes here!
}
BluetoothGattCallback will have all your incoming data from the BLE sensor. A good practice is to send a broadcast with the data to your BroadcastReceiver and handle it over there.
I am developing an app with BLE features myself. The way I managed to connect to multiple devices and turn on notifications was to implement delays.
So I make a new thread (in order not to block UI thread) and in the new thread connect and turn on notifications.
For example, after BluetoothDevice.connectGatt(); call Thread.sleep();
And add the same delay for read/write and enable/dissable notifications.
EDIT
Use wait like this so that Android dindn't reaise ANR
public static boolean waitIdle() {
int i = 300;
i /= 10;
while (--i > 0) {
if (true)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return i > 0;
}
Unfortunately notifications in the current Android BLE stack are a bit buggy. There are some hardcoded limits and I've found some stability issues even with a single device. (I read at one point that you could only have 4 notifications... not sure if that's across all devices or per device. Trying to find the source for that info now.)
I would try switching to a polling loop (say, poll the items in question 1/sec) and seeing if you find your stability increases. I would also consider switching to a different slave device (say a HRM or the TI SensorTag) to see if there is perhaps an issue with the slave-side code (unless you can test that against iOS or another platform and confirm it isn't part of the issue).
Edit: Reference for notification limitation
Rain is right in his answer, you need delays for pretty much everything when you work with BLE in Android. I developed several apps with it and it is really necessary. By using them you avoid a lot of crashes.
In my case, I use delays after every read/write command. Doing so, you ensure you receive the response from the BLE device almost always. I do something like this: (of course everything is done in a separate thread to avoid to much work on the main thread)
readCharacteristic(myChar);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
myChar.getValue();
or:
myChar.setValue(myByte);
writeCharacteristic(myChar);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
This is really useful when you read/write several characteristics in a row... As Android is enough fast to execute the commands almost instantly, if you don't use a delay between them you may get errors or incoherent values...
Hope it helps even if it is not exactly the answer to your question.

Android usb host: asynchronous interrupt transfer

I'm trying to connect a USB-Device ( build by myself ) to communicate with my development board ( ODROID-X )
Unfortunately, the examples are very little, as far as the asynchronous communication. I'd some problems with the interrupt driven data exchange - how to build the connection by using the asynchronous interrupt mode?
In one direction, the transmission was possible ... but in both it doesn't work. Is there an example like this:
send a ByteBuffer with endpoint_OUT
get a message from device on endpoint_IN
both in interrupt mode.
Thanks a lot for your support.
Hardy
Perhaps I am misunderstanding the question here.
The sample missile lanucher app that is part of the API package from level 12 onwards uses the queue() and requestWait() methods to handle interrupt type endpoints.
Requests are either In or Out and depend on the direction of the EndPoint.
The code for a pretty noddy request->reply looks something like this. You would want to structure real code differently but this gives you the gist of what needs to happen (I hope)
public void run() {
int bufferMaxLength=mEndpointOut.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferMaxLength);
UsbRequest request = new UsbRequest(); // create an URB
request.initialize(mConnection, mEndpointOut);
buffer.put(/* your payload here */;
// queue the outbound request
boolean retval = request.queue(buffer, 1);
if (mConnection.requestWait() == request) {
// wait for confirmation (request was sent)
UsbRequest inRequest = new UsbRequest();
// URB for the incoming data
inRequest.initialize(mConnection, mEndpointIn);
// the direction is dictated by this initialisation to the incoming endpoint.
if(inRequest.queue(buffer, bufferMaxLength) == true){
mConnection.requestWait();
// wait for this request to be completed
// at this point buffer contains the data received
}
}
}
If you are actually looking for a way to run this IO in an asynchronous manner without binding a thread to it, then I think you need to consider using the DeviceConnection.getFilehandle() method to return a standard file handle which in theory you can then use as if it were any other file type resource. I would note however that I have not tried this.
If neither of these addresses the issue please revise the question to clarify what you are struggling to find examples of.
I hope this helps.

Categories

Resources