androidarduinousbhidteensy

Teensy Arduino as Android HID Device, stalls after a few inputs


My project is to read button inputs from my car's steering wheel controls and convert them (using a Teensy 3.2 Arduino-alike) into android system actions of my choosing (e.g. Volume Up, Next Track, OK Google).

I have tried several different modes that the Teensy provides in order to solve this, initially as a keyboard emulation, followed by Joystick emulation and now finally a Raw HID device. All of these modes work flawlessly on Windows and Linux but do not work on android (I've tried on the target device running Android 4.1 and an Android 5 device, neither work).

The closest I've managed to get this working is as a RawHID Device with a small app i wrote to decode the packets and convert to system actions. This actually works...for about 2-5 button presses. Then nothing. In order to get my next 2-5 button presses i have to unplug the device and restart the program. The program halts on thisConnection.requestWait() forever. In an older version i used bulkTransfer and it has a similar effect, returning -1 and no data perpetually after 2-5 button presses.

Code for OpenConnection:

    public boolean OpenConnection(UsbManager pUsbManager)
    {

        if(ActiveDevice == null) return false;
        if(!hasPermission) return false;
        if(ActiveConnection != null && ActiveEndpoint != null) return true;

        if(hasAssociatedUsbDevice()) {

            ActiveInterface = ActiveDevice.getInterface(InterfaceIndex);
            ActiveEndpoint = ActiveInterface.getEndpoint(EndpointIndex);
            ActiveConnection = pUsbManager.openDevice(ActiveDevice);
            ActiveConnection.claimInterface(ActiveInterface, true);
            ActiveRequest = new UsbRequest();
            ActiveRequest.initialize(ActiveConnection,ActiveEndpoint);

            return true;
        }

        return false;
    }

Code for the device loop (run on a separate low priority thread)

private void deviceLoop(Config.HIDDevice pHIDDevice)
{

    try
    {
        if (!pHIDDevice.OpenConnection(mUsbManager)) return;


        ByteBuffer dataBufferIn = ByteBuffer.allocate(64);

        //String activeAppName = mAppDetector.getForegroundAppName(); //TODO: Refactor, causing excessive memory alloc


        String activeAppName = null;

        Config.AppProfile activeProfile = pHIDDevice.getAppProfile(activeAppName);

        while (!mExitDeviceThreads)
        {
            UsbDeviceConnection thisConnection = pHIDDevice.getActiveConnection();
            if (thisConnection == null) break; //connection dropped

            UsbRequest thisRequest = pHIDDevice.getActiveRequest();
            if (thisRequest == null) break; //connection dropped 

            thisRequest.queue(dataBufferIn, dataBufferIn.capacity());

            if (thisConnection.requestWait() == thisRequest)
            {
                byte[] dataIn = dataBufferIn.array();

                for (Config.ButtonPacketMapping thisButtonMapping : pHIDDevice.getButtonPacketMappings())
                {
                    if (thisButtonMapping.Update(dataIn))
                    {
                        for (Config.ButtonAction thisButtonAction : activeProfile.getButtonActions(thisButtonMapping.getName()))
                        {
                            if (thisButtonMapping.getLastValue() == false && thisButtonMapping.getValue() == true)
                            {
                                if (thisButtonAction.buttonAction == Config.ButtonAction.eButtonActionType.Press)
                                {
                                    thisButtonAction.Set();
                                }
                            }
                            else if (thisButtonMapping.getLastValue() == true && thisButtonMapping.getValue() == false)
                            {
                                if (thisButtonAction.buttonAction == Config.ButtonAction.eButtonActionType.Release)
                                {
                                    thisButtonAction.Set();
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                break; //Connection dropped or something went very wrong
            }
        }
    }
    finally
    {
        pHIDDevice.CloseConnection();
    }
}

So my question more succinctly is:

Has anyone managed to get a Teensy Arduino to interface with Android in any way at all over USB? Is there anything wrong with my HID approach to cause this "stalling" problem?


Solution

  • In the end, I switched to an Arduino Pro Micro which has native USB support, and used the Project-HID library using the "Consumer Device" method. This works perfectly with any OS/Hardware combo that I've tried.