Android usb host: asynchronous interrupt transfer - android

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.

Related

Flutter/Dart: Bad State errors when trying to close down a stream pipeline

I'm building a mobile app in flutter which pipes the mic audio (mic_stream lib) to a websocket. I’m really struggling to close down the stream pipeline when I'm done with it. I’m getting various “Bad State” exceptions such as Cannot add event while adding a stream. The particulars depend on how I set up the pipeline but it seems to be at the root because the returned addStream future never completes. Any ideas what would cause that?
As said above, the source stream is from the mic_stream lib which pulls from native via Flutter's EventChannel.receiveBroadcastStream. The docs for this method says its returned stream will only close down when there are no more listeners. I try closing my websocket and get a similar error for the same reason (websocket internal bad state b/c addStream never completes). I'm tried wrapping the mic stream in a StreamController and closing that but I get the error mentioned above.
Starting to feel like it's a bug. Maybe EventChannel's stream is special? Or is it related to it being a "broadcast" stream.
Feeling stuck. Any help appreciated...thx
Flutter makes this a little confusing by returning a stream from EventChannel that you can't really use in the normal pipeline chaining way if you ever need to close it. Perhaps they should have done internally what I'm about to show as the workaround.
First for clarity, when you use addStream on StreamController (StreamConsumer rather) it blocks you from "manual" control via the add() method and also the close() until that stream completes. This makes sense, if you think about it, since the source stream should determine when it closes. That's why addStream() returns a Future – so you know when you can resume using those methods, or add another stream. Doing so beforehand will trigger the Bad State errors mentioned above.
From the docs for EventChannel::receiveBroadcastStream()...
Stream activation happens only when stream listener count changes from 0 to 1. Stream deactivation happens only when stream listener count changes from 1 to 0.
So we need to decide when it is done, and to do this we need to control its subscription rather than bury it in a pipeline or a StreamController's private internals via the addStream() method. So instead we'll listen to it directly, capturing the subscription to close when we're done. Then we just proxy the data into a StreamController or pipeline manually via add()
Stream<Uint8List> micStream = await MicStream.microphone(
sampleRate: AUDIO_SAMPLE_RATE,
channelConfig: ChannelConfig.CHANNEL_IN_MONO,
audioFormat: AudioFormat.ENCODING_PCM_16BIT);//,
// audioSource: AudioSource.MIC); // ios only supports default at the mo'
StreamController? s;
// We need to control the listener subscription
// so we can end this stream as per the docs instructions
final micListener = micStream.listen((event) {
print('emitting...');
// Feed the streamcon manually
s!.add(event);
});
s= StreamController();
// Let the SCon's close() trigger the Listener's cancel()
s!.onCancel = () {
print("onCancel");
micListener.cancel();
};
s!.done.whenComplete(() {
print("done");
});
// Further consumers will use the _StreamCon's_ stream,
// _not_ the micStream above
s!.stream.listen((event) => print("listening..."));
// Now we can close the StreamController when we are done.
Future.delayed(Duration(seconds: 3), () {
s!.close();
});

Queue Android Gatt operations

I made a app the connects to a ble device and receives data from it. I was following this link "http://toastdroid.com/2014/09/22/android-bluetooth-low-energy-tutorial" at the Hints and observation section it says to Queue All GATT operations. How do I do that?
Check out NordicSemiconductors open source project Puck Central, or more specifically the GattManager class, who perfectly demonstrates how to queue all GATT operations.
If you don't want to handle this sort low level bluetooth specifics yourself however, I can recommend the great library RxAndroidBle, which does much of the heavy lifting for you.
To queue the requests you could make a queue class which has an Arraylist of requests.
Every time you want to make a request add it to the queue and start processing the queue (if the queue isn't already being processed). Once you've processed the current item check if there are still items to process and carry on processing them.
You'll also probably need to add a timeout in case one of the requests gets stuck.
Sample code on how you could process a queue using a handler:
private void startProcessingQueue() {
if (queueIsRunning) {
return;
}
queueIsRunning = true;
h.postDelayed(new Runnable(){
public void run(){
processQueue();
if(queue.isEmpty()) {
queueIsRunning = false;
return;
}
h.postDelayed(this, QUEUE_PROCESSING_DELAY);
}
}, QUEUE_PROCESSING_DELAY);
}

Android - OkHttp - Tagging all network requests with TrafficStats

I'm trying to figure out specifically how much of my app's data use is being used by the requests I send with OkHttpClient, and I saw that I can use TrafficStats to tag a thread and then see it's network activity with the tag.
if I do something like
TrafficStats.setThreadStatsTag(1234);
okHttpClient.execute(request);
then it actually tags it okay(ish), but then when I use the async method (okHttpClient.enqueue(request)) it doesn't (which is kinda obvious though I hoped they'd have support for that).
So I tried a couple of things:
Setting a dispatcher for the client where it's a normal dispatcher which basically on every execute replaces the Runnable it receives with a new runnable that first tags the thread an then runs the original runnable - some traffic was tagged but a lot wasn't.
Setting a socket factory which basically tags every socket it produces - still some some traffic tagged but most of it wasn't.
Any ideas?
I think TrafficStats.setThreadStatsTag() is for thread, so maybe we can add an interceptor for okhttp client.
private static class TrafficStatInterceptor implements Interceptor {
int mTrafficTag;
TrafficStatInterceptor(int trafficTag) {
mTrafficTag = trafficTag;
}
#Override
public Response intercept(Chain chain) throws IOException {
if (mTrafficTag > 0) {
TrafficStatUtils.setThreadStatsTag(mTrafficTag);
} else {
Log.w(TAG, "invalid traffic tag " + mTrafficTag);
}
return chain.proceed(chain.request());
}
}
then just add this interceptor
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.addNetworkInterceptor(new TrafficStatInterceptor(trafficTag));
It’s difficult to do generally because with HTTP/2 sockets are shared across requests. With HTTP/1.1 they’re reused. Your best bet will be to write a network interceptor to tag the current thread. That’ll handle all HTTP/1.1 traffic and outgoing HTTP/2 traffic. There’s currently no API to access the thread that reads incoming HTTP/2 traffic.

How do user-space applications control hardware (Location/Network/Wifi) in Android?

I have been reading all I can find trying to figure out the software architecture behind Android's BINDER IPC mechanism. From what I understand, BINDER sits in Kernel-space and temporarily gives user-space applications an allocation of shared memory through which messages can be relayed between processes.
Where I begin to lose my grip is how the actual implementation works - specifically related to parcels.
I was looking on the net and found an implementation of an arbitrary service provided by Android, like Network/Wifi/Notificaiton/Battery, ect (Docs). From my reading I've learned that a user-space program should not instantiate a service class itself, but rather get a reference to one though Context.getSystemService(Context.X). As such, I took this as an indirect way of saying that Android already has the service running, or at least has the resources to start it when needed. The implementation was essentially laid out something like:
Battery.class
BatteryManager.setBatteryState(){
Parcel parcelLocal = Parcel.obtain();
parcelLocal.writeInterfaceToken("android.power.BatteryManager");
parcelLocal.writeInt(1/0); //Depending on requested state
BinderObject.transact //Send the data using BINDER
CheckForExceptions(); //Upon return, check for exceptions
ReadResponse(); //If none, read the response from the target
DoAppropriateAction(); //Whatever we need to do after setting the state
parcelLocal.recycle(); //Return the parcel resource
}
At first it seems simple: When the user does something like:
BatteryMonitor bMonitor = Context.getSystemService(Context.POWER_SERVICE);
bMonitor.setBatteryStatus(1);
Then the user's instance will use the BINDER mechanism to communicate with the system's actual service controller (Which is an instance of the same class?). But, however, the code shown above IS the implementation for the system's battery monitoring service, so who is actually receiving the BINDER data?
TL;DR: If this is all very confusing, which it very well may be as I tried to condense a thousand lines of code into 10, the summary is: When a user intends to control the state of hardware - such as Network/Wifi/Location/Notifcations(the touchscreen) - what is actually going on within Android and who is really controlling the hardware associated with these abstracted services?
Note: The above code is completely fabricated and was intended to only show general structure.
Most System Services run as threads within the system_server process. At boot, they pass an invitation-to-call (see calls to addService() in SystemServer.java) to servicemanager which then is able to distribute the invitation to apps calling getSystemService.
Once things are rolling, you can think of the whole setup as a kind of client-server architecture where your app is the client (remote or proxy side) and the server (local or stub side) is the system service that you're talking to. The client and server communicate through the inter-process communication (IPC) subsystem known as binder. There are different parts to the binder: Framework components perform the marshalling and unmarshalling of parcels, while the kernel driver does the actual memory copies to/from ioctl calls and keeps track of who's been invited to call at the process and thread level.
Apps interface with the binder via a proxy. For example, when you use LocationManagerService, you get an instance of android.location.ILocationManager. One of the methods in the Proxy class is getLastLocation():
...
#Override public android.location.Location getLastLocation(android.location.LocationRequest request, java.lang.String packageName) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.location.Location _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((request!=null)) {
_data.writeInt(1);
request.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
_data.writeString(packageName);
mRemote.transact(Stub.TRANSACTION_getLastLocation, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.location.Location.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
...
Here you can see that the transaction code TRANSACTION_getLastLocation is written to the interface along with any necessary data, and a result is read. On the stub side, there's an onTransact() method running in the service's process space which processes all of the incoming transactions according to the transaction code:
...
case TRANSACTION_getLastLocation:
{
data.enforceInterface(DESCRIPTOR);
android.location.LocationRequest _arg0;
if ((0!=data.readInt())) {
_arg0 = android.location.LocationRequest.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
java.lang.String _arg1;
_arg1 = data.readString();
android.location.Location _result = this.getLastLocation(_arg0, _arg1);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
...
In a nutshell, the system_service process acts on behalf of the caller. This allows it to do what are usually privileged operations on hardware or other system resources. The security is based on 1) the app having the invitation to call (obtained from service_manager via getSystemService) and 2) passing whatever checks the service itself implements, such as checking ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION in the case of LocationManagerService (declared in the manifest and approved at install-time by the end-user).
UPDATE: In the case of location service, these hardware operations entail getting the actual NMEA data from the GPS hardware. The way this is currently accomplished is via the GpsLocationProvider class which interfaces to native code via JNI. This native code (com_android_server_location_GpsLocationProvider.cpp) is where the hardware device is opened (via an abstraction layer held in a hw_module_t struct), location callbacks are made (e.g., location_callback()), etc. All of this runs within the system_server process space with privileged UID system. You can verify this by running a location-enabled app, looking for GpsLocationProvider tags in the logcat and confirming that the logged PID is that of system_server. For example:
$ adb logcat | grep -i gps
...
D/GpsLocationProvider( 731): Reset GPS properties, previous size = 8
...
and
$ adb shell ps | grep system_server
system 731 441 1094884 89232 ffffffff b74d1d05 S system_server
$
Finally, I highly recommend the video tutorial Deep Dive Into Android IPC/Binder Framework to learn more about this. The talk's slides can be found here.

how to implement pooling using android bluetooth chat sample app?

I am working on an application that uses BluetoothChat sample application.
In my main activity I am using a webview in which I load an external page. I am handling Bluetooth functionality via a javascript that loads with the external page. Basically I add a bridge between Javascript and native code via the following line:
myWebView.addJavascriptInterface(new WebAppInterface(this,myWebView), "Android");//I pass a refference to the context and a refference to the webview.
WebAppInterface is the class that has all the public methods I can call from Javascript. In this class I have methods like: enableBluetooth, disableBluetooth, listBoundedDevices, connect etc.
I am using BluetoothSerialService class from BluetoothChat sample application. My device has to connect to an embedded device which receives commands and answers back differently depending on the input I give. An example would be like: when I press a button on the webview I call the following native code:
while(true){
out.write(requestKey);//send command - where "out" is the OutputStream
key = in.read();//get response - where "in" is the InputStream
if(key==KEY1){
out.write(activateRFID);//send command - activateRFID
rfidTag = in.read();//get response - RFID Tag
updateUI(rfidTag);//perform function - update the UI with the tag
}
else if(key==KEY2){
out.write(deactivateRFID);//send command - deactivate RFID
response = in.read();//get response
}
else if(key==KEY3){
out.write(anotherCommand);//send command -
response = in.read();//get response
}
}
What I am trying to achieve is sending commands to another device(request the pressed key) and perform functions. This has to happen always (pooling the device for the key pressed and perform a particular function).
How can I start 1 SINGLE THREAD that pools the device (write to the OutputStream and read the response from the InputStream)? The BluetoothChat sample application works a little different: whenever I call BluetoothChatSevice.write() I get a response via ConnectedThread run method that sends messages to UI via a mHandler.
All suggestions are welcome.
I did it today. I suggest that you do a boolean function readWrite() that whenever you write to outputStream you also read from the inputStream and send the readBuffer to UI with mHandler. If both read and write are ok, than return true, if one of them went wrong than return false and use resetConection before closing your ConnectedThread. See my answer here for the resetConnection. Application using bluetooth SPP profile not working after update from Android 4.2 to Android 4.3
But the answer about pooling is the following:
In the ConnectedThread run() method do a while(true), call a method similar to readWrite(byte[] data) inside the loop, where in the first place you write something to the device, and then you read the data from the input stream (from the device). In this readWrite() method, if writing to outpustream went fine, then continue to read from the inputstream. if you got any data to the input stream, send the data to UI for processing with the mHandler (or do some processing before sending to the UI).
It worked very nice for me.

Categories

Resources