Friday, July 24, 2015

Studying at College

Studying At College

Studying At College

Introduction

This blog has spent a significant amount of time providing insight into AP Computer Science. The next step ultimately will be going to College. AP courses offer a taste of college material but that material is spread over the course of a school year. In college that same material is covered in about 15 weeks. That really is the difference and it's a huge difference. There is very little room for an error. There will be fewer tests each covering more material. Since many who come to this site are just starting out in the field of Computer Science I thought I would collect some web sites here that can provide you some help on studying.

My own experience, way back when, was a hodge podge of mistakes and mishaps. I only wish the world wide web was around when I was going to college. If nothing else than to find out what help was available at my school for subjects I was having trouble with. Instead I would ask around or ask someone who was doing well in the course but in the end they had limited time to help. My college years were spent muddling through as best I could, studying long hours without seeing much success on these tough courses. In my day jobs were plentiful and GPA was important but it wasn't everything. Once you graduated and gained real life experience you could shift jobs, change direction without much difficulty.

Those days are gone. Jobs are a little more difficult to come by. US corporations keep lobbying for increases in the H1B visa program so they can bring in foreign STEM workers cheap. Why should I hire a B student from any State University when I can grab an A student from India Institute of Technology? In a better day US companies were restricted from doing things like that. Now, not so much. That doesn't mean you can't find a job it just means that now more than ever your GPA right out of college is your ticket to getting your foot in the door of corporate America.

Do what you love and never work a day in your life.

There is truth to this old saying. You have to be realistic of course. No one is going to pay you to eat and drink beer all day. But you can get paid for a variety of fun jobs. If you like programming computers and designing software there are jobs available that pay pretty well. If you like training dogs there are ways to make money doing this. So your first step when you go to college is to figure out what Major you are going to love.

I didn't do that. I decided that Computer Science was too easy and that I needed to understand how the electronics worked behind the computer. So I suffered through an Electrical Engineering degree, when I could have breezed through a Computer Science degree. In the end it worked out OK but it took me 4 years after college to finally land a software job. In the end the hardware and software experience would help me start up a company so I can't complain. But I could have taken Computer Science as my major and taken the fun courses in Electrical Engineering as part of my electives and looked a heck of a lot better on paper.

I bore you with this only because if you are a college student who is struggling with their course load, I know the feeling, I've been there. I've made every mistake in the book. I've told myself every excuse there was on how it wasn't my fault. The reality was two fold: First I was in the wrong major and second I had no idea how much time I was supposed to be spending on studying. From my high school experience I needed a couple of hours of studying the night before a test. In college that is not going to cut it unless your a super genius and if you are a super genius thank you for reading my blog! But if you're a mere mortal like me it would be nice to know the minimum amount of time you should be working.

Getting into "The Flow"

You may have experienced what people call "The Flow" when working on a computer project. It's that point in time where the work ahead is clear in your mind and you are just spitting out lines of a program quickly and easily. When you come out you realize you have just been super productive have gotten 80 to 90% of the work done and you're wondering: why couldn't that have happened sooner? I would have been completely finished by now. You may have experienced "The Flow" when reading a good book. You get to a particular section where the story sort of tells itself and you don't really notice the time passing. You become "absorbed" in the book.

The key is to get into "The Flow" for whatever you happen to be studying. This can be quite difficult for a required course you don't like very much and it can be simple for a course you love. The point is you need to train yourself to get into "The Flow" quickly whenever you need to whether you like the material or not. That is easier said than done and I don't know of a method to guarantee this happens quickly. My method is to observe yourself. How long do you have to sit there and what things do you do to get yourself into "The Flow"?

Start creating a routine (this is where you start to become OCD and superstitious) that you do before you begin to study. If you have to pace back and forth 5 times after you set up your study material on the desk, so be it. If you need a sip of coffee, red bull or diet coke make sure you have it handy. If you need to wash your hands 5 times OK whatever, it doesn't matter. What does matter is that you develop a routine that you do every time you start to study. The idea is to condition the mind over time that this routine will lead to "The Flow" and sooner or later your mind will start to cooperate.

For me, I found that I basically needed 5 hours to study 3 (meaning over the 5 hours I sat down to study only 3 hours of "good" study happened). Sometimes 5 hours to get 2 hours of good study. This becomes the crux of the matter, I alluded to the minimum amount of time you needed to study for each course in the previous section. We will get to that number shortly but that number represents good study time. By observing yourself and objectively assessing your use of study time, you should be able to set up a schedule for yourself and map out your entire week. Guess what. If you need 5 hours to study 3 there isn't going to be much time left for extracirricular activities.

The Formula credit hours to study hours

The University of Michigan at Flint study website (https://www.umflint.edu/advising/surviving_college) says you need:

  • 2 hours of study for every 1 credit hour of class
  • So a 12 credit hour semester = 24 hours of extra study per week.

Based on that, between classes and studying you will chew up 36 hours per week. So even a light semester schedule is equivalent to a full time job in terms of hours spent. If you're like me and you need 4 - 5 hours to get 2 hours of good study you are looking at about 60 hours per week. That's the equivalent of full time job and a part time job at night. If you want weekends off you will need to start work at 8am and finish by 5pm Monday - Friday (includes 1 hour lunch) if your an efficient studier. To get to 60 and have weekends off 8am - 10pm with an hour for lunch and an hour for dinner included. If you want to join a club and need your evenings free, you need to study more efficiently (good luck with that because if your still reading then your doomed like me ot be an inefficient studier, not because you're reading slowly but because your still looking for advice) or you will need to use your weekend time to make up the difference.

This may seem absurd to you but I assure you that in the real world of the salaried employee there are many times where you are called on to work 60 - 80 hours per week. That's the point of college, right? To prepare you for what you might have to do in the real world? I hope you take my advice because I assure you I have tried everything to avoid having to aquiesce to this reality and in the end I found out that there is no way around hard work. Trust me on this I spent a lot of time in my life trying to make up for this fact. After college if I wasn't studying at night to perform better at my job I was taking courses so I could get the job I really wanted. So the hard work eventually gets put in, it's all a matter of timing. It also shows that what employers are really buying when they hire a college graduate is a person who has learned how to study. It provides a level of confidence that when new stuff crops up on the job the employee will be able to work through it and figure out a way to accoplish it. In a technical field most of your knowledge will be obsolete in 5 years anyway, so the reality is your entire value you bring to the table as a college graduate is your ability to study.

Links to other study sites

I would encourage you to do your own web search on the topic of study skills or study in college on a frequent basis. You may discover something that is very helpful to your own personality. Remember you must take this information and personalize it for yourself. Somethings that work for other people may not work for you. But you need to keep searching for the answers.

Study block or the little voice that won't

In any endeavor there is a part of your mind that tells you: you can't do it. this is a waste of time. Your a fool for trying. This will never work. I noticed it first when I played keeper in Soccer. It was fun to dive at first but after a few dives I noticed the thought process increased (ie. that little voice got louder). Sometimes your internal dialog is helpful, but a lot of times it's your own worst enemy. Somewhere during a game the thoughts would be you're never going to stop this guy's shots why even bother to dive? or He's in too close the ball will be well past you even if you try to dive. At this point I would dive no matter what. Even if my reaction time was off and I'm diving well after the shot. The point was to show that part of my mind we are diving anyway there is no way to avoid the pain so from now on let's get with the program and see if we can stop these shots.

That same thought process happens when you try to study. It starts as: "lets play a video game first". "Check what's on TV we can study later". "It's such a long walk to the library why bother just read a little bit hear in your room". But if you choose to entertain the thought process it devolves into. "You're going to fail anyway". "2 hours is enough you know all you can get is a C". "You're just not good at this course so why bother with it". This is all part of what I call study block. It's like writer's block but it encompasses the whole study process not just the writing part.

The way out of the thought process is rituals. By going through rituals you are telling your inner voice I'm not listening. See I'm getting ready to study and there's nothing you can do about it. Over time you train yourself to get into a study mode. I would make the following suggestions if you're having trouble studying:

  • Find a study area that is not part of your living quarters, your home should be the reward and sanctuary for good studying, or used on special occasions.
  • If possible find a place where you have access to a white board or chalk board
  • Try to get a study room if they are available rather than a carol where you have a table to spread out on
  • If you must listen to music choose instrumentals rather than anything with singing. Experiment with your musical selections and see if any produce better studying.
  • If you find that you keep reading the same passage over and over read aloud for a while. Reading aloud forces you to engage more of your brain. It slows you down a little because you can read faster when you read silently, but if it's the only way to push through the material so be it.
  • Make a cheat sheet. Not to cheat mind you, but hypothetically if you were to cheat what could you put down on an 8.5 x 11 inch piece of paper that would guarantee you a good grade? This is really a good method of condensing your notes but, somehow, because you call it a cheat sheet, the "little voice" gets intriuged and starts to help you: "Don't for get to put down stuff for this section"

More on flow

There's a lot on the internet about flow. It's a concept that's been around a while and everyone rediscovers it from time to time. Back in the late 80's early 90's I remember an article that talked about helping programmers achieve flow. The single most important thing they found was to provide them an office with a door. Literally to shut out distractions.

In Software Development there are always discussions about "The Flow". I believe that the reason so many programmers work into the wee hours of the morning has to do with maintaining the flow state. There are fewer distractions at night. You are tired which I believe stops the internal chatter that can get in the way of achieving the flow state. There is also the reward of going to bed when you're finished. I can't tell you how many times I've told myself, at 1 in the morning, let me finish up the code for this last method and make sure it compiles and I'll call it a night and finally crawl into bed around 3.

Just to show you I'm not making this stuff up check out the following short article:

One thing you will see mentioned about flow, in some articles,is to do something that you love. That's something that College Students may not have the luxury of doing. You are not going to love every course you take. But you still need to try to get into flow if you are going to study well. The above article does a good job of describing some of the symptoms of flow. But you don't really know your in it until your out of it. Then you realize that wow I just got alot done or you find that 2 hours have gone by and you hardly noticed. This state is highly personalized as well. Don't feel too bad if you don't have the highly romanticized experiences described on the web. In the end you're just looking for some highly productive time where things seemed to finally click. In the end "The Flow" is just some good efficient study time, if you get anymore emotional benefits from it it's just icing on the cake.

Author: Nasty Old Dog

Validate

Thursday, October 9, 2014

Android: Working with USB and Arduino

Android Working with USB Peripherals

Android Working with USB Peripherals

Introduction

When it comes to working with popular tablets Google Android and Apple IOS are the likely choices. Google provides a near normal Java development platform and that gives it enough of an edge to be my platform of choice. This is more because I'm lazy rather than any real difference. Objective C is easy enough to get used to. The other advantage in favor of Google is a standard miniUSB connector. I have plenty of those lying around the house which again is a sign of laziness on my part. Ultimately if one were to do this sort of thing for a living learning both platforms makes you more marketable. I do this stuff part time so using a familiar platform is an important consideration.

In terms of asthetic appeal I think the Apple IOS platform wins. I seem to prefer using my iphone and ipad over the Google tablet I have. This is a very subjective consideration and my laziness wins out over it.

Self deprecation aside what I mean to say is that I am not trying to advocate one platform over another. If something I design is useful enough at some point an Apple application would be built. But most of my design work is based on learning things that interest me and not about market research into which is the best platform to launch an application on.

NOTE: for those who like to do rather than read a link to a zipped Eclipse project with source code is included at the end of this article.

USB

For a while now Google Android has provided a USB API. For the code in this article I have been developing on the Eclipse IDE with the Android SDK. Android provides both a USB accessory API and a USB Host API. The Host API is what this article is about. This is where the Google tablet provides the USB power and a USB device is attached via USB cable. In particular an Arduino MEGA 2256.

The Android documentation on UsbHost is good but it is not a tutorial. It is very general because there are a multitude of USB device you might want to attach. In this particular case there is only one device the Arduino and it acts as an RS232 device communicating over USB.

The references below provide some extra documentation and much of the code I ended up modifying came from: (place link here). For how basic the communications were there is quite a bit of code that is needed to accomplish the USB communication tasks.

Most of my changes came from creating an object class to encapsulate as much of the USB API calls into one class so it does not take up room in the MainActivity class. I don't really consider this to be a clean separation because so much of the access to the USB API relies on System level objects placed into the Context object of the MainActivity. The current code is certainly workable and hopefully to future users is not too cumbersome.

Application and USB states

The application (Activity in Android-speak) has lifecycle states that are imposed by the Android API. Some can be ignored in most activities as there is built in default behavior provided by the API. The Activity handles these lifecycle events by overriding onCreate, onStart, onResume, onPause, onStop and onDestroy methods as needed.

Android activities do not run like typical computer applications where the user starts them and then quits when they are done. In an activity they can pause or stop. But the user does not have one touch access to quitting the Activity. The Android OS will decide when to take the Activity out of memory and make it restart from scratch. Not the most useful model for controlling a piece of hardware with USB but that's what we have to work with.

The USB has states that don't exist directly in the API, but must be dealt with. For example is a USB device connected or not? Has the communication channel been set up if it is connected. These have to be determined as the Activity is running and continually checked.

Android lifecycle considerations

The main lifecycle method that most methods deal with is the onCreate method. This is where initialization occurs for many objects that make up the Activity. This is usually auto-generated if you are using Eclipse as the development platform when you first define the activity in Eclipse. The developer is then free to add in any initializations they want in this method.

Android logging - What is it and Where is it?

Android provides a Logging API via the Log class. After placing the Android device in developer debugging mode, this class allows the developer to place logging information (ie. simple text) in the Android system log.

The easy part is placing the logging code into the source code. I tend to use 2 methods from the log class: the "i" method (short for info) and the "e" method (short for error). The info logs are used to tell when a method has been entered or when certain USB functions have been called. The error logs are used for when the code takes an unexpected turn, or when a test for a null pointer is true.

The Log methods take 2 strings. The first string is a TAG that is usually set up to tell you what class you are operating in. The second string is the developer message for what is happening or where it is happening.

public static final String version = "Version 1.12";
private final String TAG = MainActivity.class.getSimpleName() + MainActivity.version;

The version field is made static and public so it can be used by other classes TAG fields for logging purposes. The purpose of using the version string is to allow the developer to search the large Android Log file and easily find the log messages output by the Activity.

The following is an example of a Log statement using the above TAG field:

Log.i(TAG, "onCreate(): entered");

The more difficult part is to access the log file once the Activity has run. The easiest way is to plug the tablet into the USB of your development computer. Then locate the location where your Android SDK is placed. Then open a terminal window (if you're using Mac or Unix) and set your PATH variable to point at the SDK/bin directory. Now you can use the adb command to run logcat on the tablet to dump the log file. The only problem is it never returns giving a live feed so you need to Ctrl-C out of the program to get access back to the command prompt.

adb logcat >android.log   
vi android.log

I happen to use vi as an editor for this but any text editor will do.

[Add copy of vi display of the log output]

Intents

Many of the system level events that happen are communicated back to the MainActivity through the use of Intent objects. Separate Handler classes are required to handle these Intent events. The Android system can be made to map these events to a particular Activity. This allows the system to open the application when the event occurs.

USB Permission Receiver

This code gets called after the User sees a Dialog box asking for permission to use a USB device and clicks the OK button. This is a non-system level intent meaning it is created by the Activity itself and the Activity must tell the Android OS about the Intent and then register it as follows:

// register the broadcast receiver
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
                ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);

This needs to be done because we need the Android OS to pause our Activity and display a permission dialog box. This seems to be a round about way to get permission when the application already knows which device it wants to control and that the Activity could just as easily asked the user directly. Android OS seems to need this to keep track of whether it can use the USB connection to the Arduino device. So a receiver must be defined in the MainActivity to handle this intent when we ask the OS to trigger it.

Once the permission has been established this receiver will go ahead and try to establish USB communication by calling setupUsbComm() in the UsbController class. Once that is accomplished communications should be able to take place between the Tablet and the Arduino board.

private final BroadcastReceiver mUsbDeviceDetachedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                Log.i(TAG, "mUsbDeviceDetachedReceiver.onReceive()" + version);
                if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                        if (usbController != null) {
                                usbController.releaseUsb();
                                textSearchedEndpoint
                                                .append("\nACTION_USB_DEVICE_DETACHED: usbController released\n");
                        } else {
                                textSearchedEndpoint
                                                .append("\nACTION_USB_DEVICE_DETACHED: usbController null no release\n");
                        }
                }
        }
};

USB Device Attached Intent Receiver

This code gets called after the user attaches a USB device to the USB port of the Android Tablet. This Intent is generated by the Android OS and it has an ACTION string defined by the API already. So to register a handler for this intent requires one line in onCreate() to make that happen:

registerReceiver(mUsbDeviceAttachedReceiver, new IntentFilter(
                UsbManager.ACTION_USB_DEVICE_ATTACHED));

Now the receiver for this is somewhat complicated by the fact that if we just attached the USB then the UsbController class object that encapsulates the USB functionality will not have been set up properly (no device no setup). This handler must see to it that if the connected USB is the one we are looking for then we initialize it and get permission for it. Yes this handler must trigger the permission handler above. There are 2 possibilities:

  1. There is no UsbController object yet so we need to use the constructor for the class to set one up
  2. Some code has been run that has partially set up the object in the MainActivity but there was no device found to go any further

The second one occurs because we have to take into account that the device may already be connected when the Activity is run for the first time. In that case there will be no ACTIONUSBDEVICEATTACHED sent to the Activity because the device was attached long before the Activity came into being. So since the Activity may have gone through a partial setup this code is overly complex.

In both cases an important part of the code is to get the UsbDevice found by Android OS and place it in the UsbController object for use. The intent object seems to be the only place where this information (the UsbDevice) exists.

private final BroadcastReceiver mUsbDeviceAttachedReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                Log.i(TAG, "mUsbDeviceAttachedReceiver.onReceive()");
                if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                        // The device is provided as part of the intent
                        // in a larger context (ie. android attached to USB hub)
                        // it may not be our device of interest there could be other
                        // devices. But for now assume only one device
                        UsbDevice device = (UsbDevice) intent
                                        .getParcelableExtra(UsbManager.EXTRA_DEVICE);

                        if (usbController == null) {
                                textDisplayLog
                                                .append("\nACTION_USB_DEVICE_ATTACHED: usbController was null now created\n");
                                usbController = new UsbControls(
                                                UsbControls.targetVendorID,
                                                UsbControls.targetProductID,
                                                device);
                                Log.i(TAG,
                                                "mUsbDeviceAttachedReceiver: USB Controller set up");
                        } else {
                                textDisplayLog
                                                .append("\nACTION_USB_DEVICE_ATTACHED: usbController not null UsbDevice set\n");
                                usbController.setUsbDevice(device);
                                Log.i(TAG,
                                                "mUsbDeviceAttachedReceiver: USB Controller already available UsbDevice set");
                        }

                        usbController.usbInit((UsbManager) context
                                        .getSystemService(USB_SERVICE));

                        // Get permission to use
                        // mUsbManager.requestPermission(device, mPermissionIntent);
                        if (usbController.getUsbPermission(
                                        (UsbManager) context.getSystemService(USB_SERVICE),
                                        mPermissionIntent)) {
                                Log.i(TAG, "mUsbAttachedReceiver: USB ready");
                    } else {
                           Log.e(TAG, "mUsbAttachedReceiver: Cannot get permission for USB");
                    }
                }
        }
};

USB Device Detatched Intent Receiver

This code gets called when the device is disconnected from the USB port of the Android Tablet. This must be registered to the Android OS

registerReceiver(mUsbDeviceDetachedReceiver, new IntentFilter(
                UsbManager.ACTION_USB_DEVICE_DETACHED));

Without a device all of the USB objects held within the UsbController object need to be released, hence the call to usbController.releaseUsb(). There is the possiblility that something went wrong and there is no valid usbController object so we check it for a null pointer before using it.

private final BroadcastReceiver mUsbDeviceDetachedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                Log.i(TAG, "mUsbDeviceDetachedReceiver.onReceive()");
                if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                        if (usbController != null) {
                                usbController.releaseUsb();
                                textDisplayLog
                                                .append("\nACTION_USB_DEVICE_DETACHED: usbController released\n");
                        } else {
                                textDisplayLog
                                                .append("\nACTION_USB_DEVICE_DETACHED: usbController null no release\n");
                        }
                }
        }
};

Finally after we have used the Activity to our heart's content and have started using other Activities on the tablet we should unregister the Intents if the MainActivity gets "destroyed" by the Android OS. So in the onDestroy lifecycle call back the following unregister calls are made:

unregisterReceiver(mUsbReceiver);
unregisterReceiver(mUsbDeviceAttachedReceiver);
unregisterReceiver(mUsbDeviceDetachedReceiver);

Strings and bytes

Strings are the usual class used for handling text and for most Android Activities involving graphics and user input this is fine. For USB communication however bytes are the coin of the realm. For this USB program the transmit message is setup directly in bytes. But to display the message returned by the Arduino over USB a conversion from bytes to string is needed. There maybe an easier way but I chose to terminate the USB bytes with the ASCII return character 0x0A. This way you just need to loop through the bytes and find that ASCII character as the end of the message:

for (int i = 0; i < result; i++) {
    if (buf[i] != 0x0a) {
        sb.append(String.format("%c", buf[i]));
    } else {
        synchronized (syncToken) {
            msg = sb.toString();
        }
        sb = new StringBuilder();
        mHandler.sendEmptyMessage(0);
        break; // There is a question whether there is new valid data 
              // after newline but am assuming not for now
    }
}

The Code

MainActivity.java - Simple user interface to test USB communication

This MainActivity has been set up with a title, a scrolling TextView to act as a DisplayLog window for realtime feedback as to how the application is running. Finally a button that when pressed sends a preset message to the Arduino board. onStart() is probably the most complex method because it makes sure that if a USB board is attached that we try to establish communication and make sure we have permission to connect to it. The rest of the code is as explained above with the Intent receivers in their proper location. I have implemented all of the lifecycle methods with logging so when debugging connectivity with the USB you have an understanding of when things are happening. Therefore as your Activity becomes more complex you will have some insight to where things should go in the lifecycle method callbacks.

The Graphical User Interface was set up with Eclipse and looks as follows:

The actual MainActivity code:

package com.llsc.androidusb;


import android.app.Activity;
import android.app.ActionBar;
import android.app.Fragment;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.os.Build;

public class MainActivity extends Activity {
        public static final String version = "Version 1.12";
        private final String TAG = MainActivity.class.getSimpleName() + MainActivity.version;


        TextView textDisplayLog;

        Button msgButton;

        UsbControls usbController;

        Boolean fromOnPause = false;

        private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";

        PendingIntent mPermissionIntent;

        Handler mHandler1;
        Object syncObj;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                Log.i(TAG, "onCreate(): entered");

                setContentView(R.layout.activity_main);

                if (savedInstanceState == null) {
                        getFragmentManager().beginTransaction()
                                        .add(R.id.container, new PlaceholderFragment()).commit();
                }

                // register the broadcast receiver
                mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
                                ACTION_USB_PERMISSION), 0);
                IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
                registerReceiver(mUsbReceiver, filter);

                registerReceiver(mUsbDeviceAttachedReceiver, new IntentFilter(
                                UsbManager.ACTION_USB_DEVICE_ATTACHED));
                registerReceiver(mUsbDeviceDetachedReceiver, new IntentFilter(
                                UsbManager.ACTION_USB_DEVICE_DETACHED));

                mHandler1 = new Handler() {
                        public void handleMessage(Message msg) {
                                onMsgRcv();
                        }
                };
                syncObj = new Object();

                usbController = new UsbControls(UsbControls.targetVendorID,
                                UsbControls.targetProductID);
                usbController.setRcvHandler(mHandler1);
                usbController.setSyncObj(syncObj);
                /*
                 * deviceFound = this.getUsbDevice(targetVendorID, targetProductID); if
                 * (deviceFound == null) usbAttached = false; else usbAttached = true;
                 */
        }

        @Override
        protected void onStart() {
                super.onStart();
                Log.i(TAG, "onStart(): entered ");

                textDisplayLog = (TextView) findViewById(R.id.displaylog);
                msgButton = (Button) findViewById(R.id.button1);

                textDisplayLog.append("\nonStart");

                // Make sure usb is ready to go
                // For this section of code to work you must have the device plugged in.
                // if the device is not plugged in null pointers will happen
                // I think this is why this app should trigger usb setup based on device
                // plugged in
                // intent and device detatched events. Then I should be able to do all
                // the setup
                // in the intent handlers.
                // This is not correct onStart must try to establish connectivity
                // because the
                // device may already be attached.
                UsbManager manager = (UsbManager) this.getSystemService(USB_SERVICE);

                // Device maybe attached but not initialized
                        // If USB connected get permission to use
                        // must setup device first before asking for permission
                        // How do I tell if there is a device attached??
                        // Right now none of the stuff below will set up the connection if
                        // something is connected
                        usbController.setUsbDevice(manager);

                                usbController.usbInit(manager);
                                if (usbController.hasPermission(manager)) {
                                        usbController.setupUsbComm(manager);
                                } else { 
                                        if (usbController.getUsbPermission(manager,
                                                mPermissionIntent)) {
                                        Log.i(TAG, "onStart: USB ready");
                                    } else {
                                          Log.e(TAG, "onStart: Cannot get permission for USB");
                                    }
                                }
                fromOnPause = false;
        }

        @Override
        public void onResume() {
                super.onResume();
                Log.i(TAG, "onResume(): entered");
                textDisplayLog.append("\nonResume: called");
        }

        @Override
        public void onPause() {
                super.onPause();
                Log.i(TAG, "onPause(): entered");
                textDisplayLog.append("\nonPause: called");
                fromOnPause = true;
        }

        @Override
        protected void onStop() {
                super.onStop();
                Log.i(TAG, "onStop(): entered");
                if (usbController.usbAttached()) {
                        usbController.releaseUsb();
                }
        }

        @Override
        protected void onDestroy() {
                super.onDestroy();
                Log.i(TAG, "onDestroy(): entered");
                textDisplayLog.append("\nonDestroy");
                unregisterReceiver(mUsbReceiver);
                unregisterReceiver(mUsbDeviceAttachedReceiver);
                unregisterReceiver(mUsbDeviceDetachedReceiver);
        }

        public void onButton1Pressed(View view) {
                byte[] bytesHello = new byte[] { (byte) 'H', 'e', 'l', 'l', 'o', ' ',
                                'f', 'r', 'o', 'm', ' ', 'A', 'n', 'd', 'r', 'o', 'i', 'd' };
                usbController.usbSend(bytesHello);
        }

        private void onMsgRcv() {
                // Message has come in over USB get it from the USB thread
                // Do it in a sync way so buffers don't get stepped on by different
                // threads
                String s = usbController.getRcvMsg();
                textDisplayLog.append("\n\nData Received");
                textDisplayLog.append("\n\n" + s);
        }

        /*
         * @Override protected void onCreate(Bundle savedInstanceState) {
         * super.onCreate(savedInstanceState);
         * setContentView(R.layout.activity_main);
         * 
         * if (savedInstanceState == null) { getFragmentManager().beginTransaction()
         * .add(R.id.container, new PlaceholderFragment()).commit(); } }
         */
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {

                // Inflate the menu; this adds items to the action bar if it is present.
                getMenuInflater().inflate(R.menu.main, menu);
                return true;
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
                // Handle action bar item clicks here. The action bar will
                // automatically handle clicks on the Home/Up button, so long
                // as you specify a parent activity in AndroidManifest.xml.
                int id = item.getItemId();
                if (id == R.id.action_settings) {
                        return true;
                }
                return super.onOptionsItemSelected(item);
        }

        private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

                @Override
                public void onReceive(Context context, Intent intent) {
                        String action = intent.getAction();
                        Log.i(TAG, "mUsbReceiver.onReceive()");
                        if (ACTION_USB_PERMISSION.equals(action)) {
                Log.i(TAG,"mUsbReceiver.onReceive: ACTION_USB_PERMISSION found");
                                synchronized (this) {
                                        UsbManager manager = (UsbManager) context
                                                        .getSystemService(USB_SERVICE);

                                        if (intent.getBooleanExtra(
                                                        UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                                                usbController.usbInit(manager);
                                                usbController.setupUsbComm(manager);

                                                textDisplayLog
                                                                .append("\npermission receiver: permission granted");
                                                Log.i(TAG,
                                                                "mUsbReceiver: permission granted com link attemped");
                                        } else {
                                                textDisplayLog.append("permission denied for device ");
                                                Log.e(TAG, "mUsbReceiver: Permisson denied for device ");
                                        }
                                }
                        }
                }
        };

        private final BroadcastReceiver mUsbDeviceAttachedReceiver = new BroadcastReceiver() {

                @Override
                public void onReceive(Context context, Intent intent) {
                        String action = intent.getAction();
                        Log.i(TAG, "mUsbDeviceAttachedReceiver.onReceive()");
                        if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                                // The device is provided as part of the intent
                                // in a larger context (ie. android attached to USB hub)
                                // it may not be our device of interest there could be other
                                // devices. But for now assume only one device
                                UsbDevice device = (UsbDevice) intent
                                                .getParcelableExtra(UsbManager.EXTRA_DEVICE);

                                if (usbController == null) {
                                        textDisplayLog
                                                        .append("\nACTION_USB_DEVICE_ATTACHED: usbController was null now created\n");
                                        usbController = new UsbControls(
                                                        UsbControls.targetVendorID,
                                                        UsbControls.targetProductID,
                                                        device);
                                        Log.i(TAG,
                                                        "mUsbDeviceAttachedReceiver: USB Controller set up");
                                } else {
                                        textDisplayLog
                                                        .append("\nACTION_USB_DEVICE_ATTACHED: usbController not null UsbDevice set\n");
                                        usbController.setUsbDevice(device);
                                        Log.i(TAG,
                                                        "mUsbDeviceAttachedReceiver: USB Controller already available UsbDevice set");
                                }

                                usbController.usbInit((UsbManager) context
                                                .getSystemService(USB_SERVICE));

                                // Get permission to use
                                // mUsbManager.requestPermission(device, mPermissionIntent);
                                if (usbController.getUsbPermission(
                                                (UsbManager) context.getSystemService(USB_SERVICE),
                                                mPermissionIntent)) {
                                        Log.i(TAG, "mUsbAttachedReceiver: USB ready");
                            } else {
                                   Log.e(TAG, "mUsbAttachedReceiver: Cannot get permission for USB");
                            }
                        }
                }
        };

        private final BroadcastReceiver mUsbDeviceDetachedReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                        String action = intent.getAction();
                        Log.i(TAG, "mUsbDeviceDetachedReceiver.onReceive()");
                        if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                                if (usbController != null) {
                                        usbController.releaseUsb();
                                        textDisplayLog
                                                        .append("\nACTION_USB_DEVICE_DETACHED: usbController released\n");
                                } else {
                                        textDisplayLog
                                                        .append("\nACTION_USB_DEVICE_DETACHED: usbController null no release\n");
                                }
                        }
                }
        };

        /**
         * A placeholder fragment containing a simple view.
         */
        public static class PlaceholderFragment extends Fragment {

                public PlaceholderFragment() {

                }

                @Override
                public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                Bundle savedInstanceState) {
                        View rootView = inflater.inflate(R.layout.fragment_main, container,
                                        false);
                        return rootView;
                }
        }
}

UsbControls.java - the encapsulating class for USB setup and communication

This is the class that tries to encaspulate most of the USB code. The most difficult to understand is the setup of communications.

Enumerating USB devices

The Android UsbHost API documentation covers enumerating USB devices that is housed in the getUsbDevice(vendorID,productID,UsbManager) method. It requires a UsbManager parameter because this is available at the level of the MainActivity. Originally all this code was threaded into the MainActivity class.

Initializing and Endpoint enumeration

It turns out that some investigation of the USB device can take place before permission is given to communicate. These have been separated out into usbInit(UsbManager). Enpoints are USB speak for transmit, receive and control channels available to the board. These need to be in place and intialized before the board can actually transmit and receive information

Communications setup

When permission to use the USB device has been granted setupUsbComm(UsbManager) method does the final connection arrangements and establishes common RS232 control parameters such as Baud Rate, Data bits and Stop bits. This is accomplished by calls to the UsbHost API method controlTransfer().

Sending data

The usbSend(byte[]) method sends data down the USB via the bulkTransfer() method. This routine is rather straight forward and if communication has been established properly works as expected.

The rest is just some flag fields to try to maintain some state information about the communication link.

/**
 * AndroidUsb
 * UsbControls.java
 *
 * Author: Nasty Old Dog
 * Code modified from:
 * http://android.serverbox.ch/?p=370 
 * https://github.com/mik3y/usb-serial-for-android
 */
package com.llsc.androidusb;

import java.util.HashMap;
import java.util.Iterator;

import android.app.PendingIntent;
import android.content.Context;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.util.Log;

/**
 * @author tmcguire
 *
 */
public class UsbControls {
        private final String TAG = UsbControls.class.getSimpleName();
        public static final int targetVendorID = 0x2341;
        public static final int targetProductID = 0x42;

        UsbDevice deviceFound = null;
        UsbInterface usbInterfaceFound = null;
        UsbEndpoint endpointIn = null;
        UsbEndpoint endpointOut = null;
        UsbReceiver rcvThrd;
        UsbInterface usbInterface;
        UsbDeviceConnection usbDeviceConnection;
        int vendorID = 0;
        int productID = 0;
        private String infoText = "No device connected";

        boolean usbAttached = false;
        boolean usbConnected = false;

        private Handler rcvHandler;
        public void setRcvHandler(Handler rcvHandler) {
                this.rcvHandler = rcvHandler;
        }

        private Object syncObj;

        public void setSyncObj(Object syncObj) {
                this.syncObj = syncObj;
        }

        public UsbControls(int vID, int pID) {
                vendorID = vID;
                productID = pID;
        }

        public UsbControls(int vID, int pID, UsbDevice usbDevice) {
                vendorID = vID;
                productID = pID;
                this.deviceFound = usbDevice;
        }

        public void setUsbDevice(UsbManager manager){
                deviceFound = this.getUsbDevice(vendorID, productID, manager);
        }

        public void setUsbDevice(UsbDevice usbDevice) {
                deviceFound = usbDevice;
        }
        public String getInfoText() {
                return infoText;
        }

        public String getRcvMsg() {
                return this.rcvThrd.getMsg();
        }

        public void usbInit(UsbManager manager) {

                Log.i(TAG,"usbInit");

                if (!usbAttached) {
                        deviceFound = this.getUsbDevice(vendorID, productID, manager);
                        if (!usbAttached) {
                                Log.e(TAG, "usbInit: No device connected");
                                return;
                        } else {
                                Log.i(TAG, "usbInit: device found");
                        }
                }

                searchEndPoint(manager);
/*
                if (usbInterfaceFound != null) {
                        setupUsbComm(manager);
                        Log.i(TAG,"connectUsb: usbInterface setup attempted");
                }
                else {
            Log.e(TAG,"connectUsb: usbInterface not found, usb not setup");
                }
*/
        }

        public void releaseUsb() {
                Log.i(TAG," releaseUsb");

                if (rcvThrd != null) {
                        rcvThrd.stopUsbReceiver();

                        // Inserting delay here
                        try {
                                Thread.sleep(5000);
                        } catch (InterruptedException e) {
                                Log.e(TAG, "sleep in releaseUsb failed");
                        }

                        rcvThrd = null;
                }
                if (usbDeviceConnection != null) {
                        if (usbInterface != null) {
                                usbDeviceConnection.releaseInterface(usbInterface);
                                usbInterface = null;
                        }
                        usbDeviceConnection.close();
                        usbDeviceConnection = null;
                }

                deviceFound = null;
                usbInterfaceFound = null;
                endpointIn = null;
                endpointOut = null;
                usbAttached = false;
                usbConnected = false;
        }

        public boolean isUsbConnected() {
                return usbConnected;
        }

        public void setUsbConnected(boolean usbConnected) {
                this.usbConnected = usbConnected;
        }

        public void searchEndPoint(UsbManager manager) {

        Log.i(TAG,"searchEndPoint");
                usbInterfaceFound = null;
                endpointOut = null;
                endpointIn = null;

                Log.i(TAG, "searchEndPoint: entered");
                // Search device for targetVendorID and targetProductID
                if (deviceFound == null) {
                        deviceFound = this.getUsbDevice(vendorID, productID, manager);
                }
                if (deviceFound == null) {
            Log.e(TAG,"searchEndPoint: Device not found.");
            this.usbAttached = false;
                        return;
                } else {
                        String s = deviceFound.toString() + "\n" + "DeviceID: "
                                        + deviceFound.getDeviceId() + "\n" + "DeviceName: "
                                        + deviceFound.getDeviceName() + "\n" + "DeviceClass: "
                                        + deviceFound.getDeviceClass() + "\n" + "DeviceSubClass: "
                                        + deviceFound.getDeviceSubclass() + "\n" + "VendorID: "
                                        + deviceFound.getVendorId() + "\n" + "ProductID: "
                                        + deviceFound.getProductId() + "\n" + "InterfaceCount: "
                                        + deviceFound.getInterfaceCount();
                        infoText = s;

                        Log.i(TAG, "searchEndPoint: " + s);

                        // Search for UsbInterface with Endpoint of USB_ENDPOINT_XFER_BULK,
                        // and direction USB_DIR_OUT and USB_DIR_IN

                        for (int i = 0; i < deviceFound.getInterfaceCount(); i++) {
                                UsbInterface usbif = deviceFound.getInterface(i);

                                UsbEndpoint tOut = null;
                                UsbEndpoint tIn = null;

                                int tEndpointCnt = usbif.getEndpointCount();
                                if (tEndpointCnt >= 2) {
                                        for (int j = 0; j < tEndpointCnt; j++) {
                                                if (usbif.getEndpoint(j).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                                                        if (usbif.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_OUT) {
                                                                tOut = usbif.getEndpoint(j);
                                                        } else if (usbif.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_IN) {
                                                                tIn = usbif.getEndpoint(j);
                                                        }
                                                }
                                        }

                                        if (tOut != null && tIn != null) {
                                                // This interface have both USB_DIR_OUT
                                                // and USB_DIR_IN of USB_ENDPOINT_XFER_BULK
                                                usbInterfaceFound = usbif;
                                                endpointOut = tOut;
                                                endpointIn = tIn;
                                        }
                                }

                        }

                        if (usbInterfaceFound == null) {
                                Log.e(TAG,"searchEndPoint: No suitable interface found!");
                        } else {
                                Log.i(TAG,"searchEndPoint: UsbInterface found: "
                                                + usbInterfaceFound.toString() + "\n\n"
                                                + "Endpoint OUT: " + endpointOut.toString() + "\n\n"
                                                + "Endpoint IN: " + endpointIn.toString());

                        }
                }
        }

        public boolean setupUsbComm(UsbManager manager) {

                // for more info, search SET_LINE_CODING and

                final int RQSID_SET_LINE_CODING = 0x20;
                final int RQSID_SET_CONTROL_LINE_STATE = 0x22;
                // final int RQSID_SET_LINE_CODING = 0x32;
                // final int RQSID_SET_CONTROL_LINE_STATE = 0x34;

                boolean success = false;

                Log.i(TAG,"setupUsbComm");

                if (!usbAttached) {
                        Log.e(TAG, "setupUsbComm: device not attached");
                        return success;
                }
//              UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
                if (deviceFound == null) {
            Log.e(TAG,"setupUsbComm: device not initialized");
                        return success;
                }

                Boolean permitToRead = manager.hasPermission(deviceFound);

                if (permitToRead) { 
                        Log.i(TAG,"setupUsbComm: permitted to read");
                        usbDeviceConnection = manager.openDevice(deviceFound);
                        if (usbDeviceConnection != null) {
                                usbDeviceConnection.claimInterface(usbInterfaceFound, true);

                                // showRawDescriptors(); // skip it if you no need show
                                // RawDescriptors
                                Log.i(TAG,"setupUsbComm: device connection made");

                                int usbResult;
                                usbResult = usbDeviceConnection.controlTransfer(0x21, // requestType
                                                // usbResult = usbDeviceConnection.controlTransfer(0x40,
                                                // // requestType
                                                RQSID_SET_CONTROL_LINE_STATE, // SET_CONTROL_LINE_STATE
                                                0, // value or in 0x01 for DTR or 0x02 for RTS
                                                0, // index
                                                null, // buffer
                                                0, // length
                                                0); // timeout

                                Log.i(TAG,"setupUsbComm: controlTransfer(SET_CONTROL_LINE_STATE): " + 
                                                usbResult);

                                // baud rate = 9600
                                // 8 data bit
                                // 1 stop bit
                                byte[] encodingSetting = new byte[] { (byte) 0x80, 0x25, 0x00,
                                                0x00, 0x00, 0x00, 0x08 };
                                usbResult = usbDeviceConnection.controlTransfer(0x21, // requestType
                                                // usbResult = usbDeviceConnection.controlTransfer(0x40,
                                                // // requestType
                                                RQSID_SET_LINE_CODING, // SET_LINE_CODING
                                                0, // value
                                                0, // index
                                                encodingSetting, // buffer
                                                7, // length
                                                0); // timeout

                                Log.i(TAG,"setupUsbComm: controlTransfer(RQSID_SET_LINE_CODING): " + 
                                                usbResult);

                                // can set up receive thread
                                // This needs to be in it's own routine. 
                                rcvThrd = new UsbReceiver(usbDeviceConnection, endpointIn,
                                                rcvHandler, syncObj);
                                rcvThrd.start();
                success = true;
                usbConnected = true;
                        }

                } else {
//                      manager.requestPermission(deviceFound, mPermissionIntent);
                        Log.i(TAG,"setupUsbComm: Permission requested");
                }
                return success;
        }

        public boolean hasPermission (UsbManager manager) {
                if (deviceFound != null) {
                return manager.hasPermission(deviceFound);
                } else {
                        Log.e(TAG, "hasPermission: device null should be initialized");
                }
                return false;
        }

        public boolean getUsbPermission (UsbManager manager, PendingIntent mPermissionIntent) {
                if (this.usbAttached) {
                if (deviceFound != null) {
                        manager.requestPermission(deviceFound, mPermissionIntent);
                        Log.i(TAG,"getUsbPermission: Permission requested");
                        if (manager.hasPermission(deviceFound)) {
                                Log.i(TAG,"getUsbPermission: Permission granted");
                                return true;
                        } else {
                                Log.i(TAG,"getUsbPermission: Permission denied");
                                return false;                   
                        }
                    }
                    Log.i(TAG,"getUsbPermission: USB attached but device null");
                    return false;
                }
                Log.i(TAG,"getUsbPermission: USB not attached");
                return false;
        }

        public UsbDevice getUsbDevice(int vendor, int product, UsbManager manager) {
//                      UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
                        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
                        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();

                        if (deviceList.isEmpty()) {
                                this.usbAttached = false;
                                return null;
                        }
                        while (deviceIterator.hasNext()) {
                                UsbDevice device = deviceIterator.next();

                                if (device.getVendorId() == vendor) {
                                        if (device.getProductId() == product) {
                                                this.usbAttached = true;
                                                return device;
                                        }
                                }
                        }
                        this.usbAttached = false;
                        return null;
        }

        public boolean usbAttached() {
                return usbAttached;     // was deviceFound != null
        }

        public void setUsbAttached(boolean attach) {
                usbAttached = attach;
        }

    public void resetConnection(UsbManager manager) {
                deviceFound = this.getUsbDevice(vendorID, productID, manager);
            if (deviceFound == null) {
                Log.e(TAG, "resetConnection: can not find a device");
                return;
            }
            usbInit(manager);
            if (this.hasPermission(manager)) {
                setupUsbComm(manager);
            }
    }

    public void usbSend(byte[] msg) {
                int usbResult;

                if (endpointOut != null && usbDeviceConnection != null) {
                usbResult = usbDeviceConnection.bulkTransfer(endpointOut, msg,
                                msg.length, 1000);
                  Log.i(TAG,"usbSend: Transmitted msg: " + usbResult);
            }
                else {
                        Log.i(TAG,"usbSend: endpointOut null no xmit");
                }
    }
}

UsbReceiver.java - code to receive from USB and notify MainActivity

This class creates its own thread to capture data over the USB connection. Because data may not come in one fell swoop it must loop looking for a terminating character before it places data in the msg field. To create a receiver an handler back to the MainActivity must be established so MainActivity can be signaled when there is data to be inspected and displayed. You also need the inbound endpoint, UsbDeviceConnection and a thread synchronizing object.

The bulkTransfer method is used to receive data on the inbound endpoint and some initialization occurs to make sure control of the inbound endpoint is in place via controlTransfer method.

package com.llsc.androidusb;

import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.os.Handler;
import android.util.Log;

public class UsbReceiver extends Thread {
        private final String TAG = UsbReceiver.class.getSimpleName() + MainActivity.version;
        private boolean urStop = false;
        private Handler mHandler;
        private Object syncToken;
        private UsbDeviceConnection mConnection;
        private UsbEndpoint epIn;
        private String msg;
        final int RQSID_SET_LINE_CODING = 0x20;
        final int RQSID_SET_CONTROL_LINE_STATE = 0x22;

        UsbReceiver(UsbDeviceConnection mConnection, UsbEndpoint epIn, Handler mh,
                        Object st) {
                this.mConnection = mConnection;
                this.epIn = epIn;
                mHandler = mh;
                syncToken = st;
                Log.i(TAG,"UsbReceiver(): Constructor initialized object instance");
        }

        public void stopUsbReceiver() {
                synchronized (syncToken) {
                  urStop = true;
                }
        }

        @Override
        public void run() {
                byte[] buf = new byte[64];         // The Arduino MEGA 2256 sends 64byte messages
                StringBuilder sb = new StringBuilder();
                if (mConnection == null) return;
                // send DTR
                int result = mConnection.controlTransfer(0x21, // requestType
                                // usbResult = usbDeviceConnection.controlTransfer(0x40, //
                                // requestType
                                RQSID_SET_CONTROL_LINE_STATE, // SET_CONTROL_LINE_STATE
                                0x01, // value or in 0x01 for DTR or 0x02 for RTS
                                0, // index
                                null, // buffer
                                0, // length
                                0); // timeout
        Log.i(TAG,"run(): USB Receiver thread set up");
                while (true) {
                                if (urStop) {
                                        break;
                                }
                                if (mConnection == null) return;
                                if (epIn == null) return;

                        result = mConnection.bulkTransfer(epIn, buf, buf.length, 1000);

/*                      int nresult = mConnection.controlTransfer(0x21, // requestType
                                        // usbResult = usbDeviceConnection.controlTransfer(0x40, //
                                        // requestType
                                        RQSID_SET_CONTROL_LINE_STATE, // SET_CONTROL_LINE_STATE
                                        0x00, // value or in 0x01 for DTR or 0x02 for RTS
                                        0, // index
                                        null, // buffer
                                        0, // length
                                        0); // timeout
*/
                        // A full message will be terminated with a Newline character '\n'
                        // so read all characters collected so far. If newline detected that's the
                        // end of the message so store full message send signal to main thread and
                        // create new StringBuilder to get next message, break out of loop 
                        if (result > 0) {
                                for (int i = 0; i < result; i++) {
                                        if (buf[i] != 0x0a) {
                                                sb.append(String.format("%c", buf[i]));
                                        } else {
                                                synchronized (syncToken) {
                                                        msg = sb.toString();
                                                }
                                                sb = new StringBuilder();
                                                mHandler.sendEmptyMessage(0);
                                                break; // There is a question whether there is new valid data 
                                                       // after newline but am assuming not for now
                                        }
                                }
                        }
                }
        }

        public String getMsg() {
                synchronized (syncToken) {
                        return msg;
                }
        }

}

ArduinoUsbTest - Arduino code to accept a message on USB and spit it back out.

This is just some simple arduino code to spit back the incoming message. It also toggles the LED so you have some feed back that data was received and a round trip message was attempted.

/**
 * AndroidUsbTest - testing platform for usb communication with 
 *                  Android usb host
 */
char charRead = 0;
char buffer[41];
char printout[20];  //max char to print: 20
int ledPin = 13;

void setup() {
  // put your setup code here, to run once:
  //Setup Serial Port with baud rate of 9600
  Serial.begin(9600);
    pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin,LOW);
  buffer[0] = 0;
}

void loop() {
  // put your main code here, to run repeatedly:
    while (Serial.available()) {
      int chrs = Serial.readBytesUntil('\n',buffer,40);
      buffer[chrs] = 0;
    }

  if (buffer[0] != 0) {
    digitalWrite(ledPin, digitalRead(ledPin) ^ 1);   // toggle LED pin
    Serial.print("How are you, ");
    Serial.println(buffer);
    buffer[0] = 0;
  }

}

Conclusion

This article is somewhat hastily put together because I spent a large amount of part-time effort on the code. I wanted to get the code out there in the hopes that it will be helpful to people and save them some time setting up Android USB communication. As time allows I will try to refine the article be a little more explanatory. For now hopefully the code and the comments will assist you in getting your USB project going.

All the references below were extremly helpful. Much of what I learned was gleaned from reference 3 with some mix of reference 4. If I could simplify code to match the Android UsbHost API documentation I did so where I could. What this code does over the other applications is it provides expected functionality if you should disconnect and reconnect the USB. This was troublesome to get working to my expectations on how I believe a connected device should work with an Activity.

Finally the Android UsbHost API allows you specify intents in the xml manifest. This will certainly make the application come up when a board is connected but I had a great deal of difficulty making it work well when things are already plugged in or when connect and disconnect occurs repeatedly.

Zipped Eclipse Project Containing Source Code

Author: Nasty Old Dog

Validate