Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

USB interface in android

Tags:

android

usb

I rooted my device and working in host mode. I can able to detect the usb device connected to my tab but Am having two questions.

1) i try to display my device name using device.getDeviceName(); but its showing something like/dev/usb/002/002 I need to get the manufacturer name of the usb device name. I thing its available in accessory mode but i need to get the manufacturer name in host mode.

2)I need to transfer some data from my app to the usb port in android. i can able to detect the device but please help in transfering some data or file from my android app to mass storage connected to usb port.

like image 655
Arun Avatar asked Nov 04 '12 10:11

Arun


3 Answers

Probably you will actually need to read the Raw USB Descriptors to get at the data you want. Here's a basic USB device discovery program I wrote for my own purposes. Mind you that I'm looking for a specific device (a Dajac Easy I/O 1000 data acquisition system) but you can apply the same principles. I do show you how to get the data you're looking for.

Here's the code first. My package is usbtest3, and the file is MainActivity.java:

package com.hotspotoffice.usbtest3;

// David Schofield, Hotspot Office, LLC., Pittsburgh, PA.
// Donations via PayPal always welcome! schofield (dot) david (at) verizon.net

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import android.os.Bundle;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.View;
import android.view.Menu;
import android.widget.Button;
import android.widget.TextView;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbInterface;


public class MainActivity extends Activity {

    protected static final int STD_USB_REQUEST_GET_DESCRIPTOR = 0x06;
    // http://libusb.sourceforge.net/api-1.0/group__desc.html
    protected static final int LIBUSB_DT_STRING = 0x03;
    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";

    private Button btnDiscover;
    private TextView txtInfo;
    private PendingIntent mPermissionIntent; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnDiscover=(Button)findViewById(R.id.btnDiscover);
        txtInfo=(TextView)findViewById(R.id.txtInfo);

        mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        registerReceiver(mUsbReceiver, filter);

        btnDiscover.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // txtInfo.setText("Button has been Pressed for "+(++i)+" Times.");

                UsbManager manager = (UsbManager)getSystemService(Context.USB_SERVICE);

                HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
                Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
                while(deviceIterator.hasNext()){
                    UsbDevice device = deviceIterator.next();

                    manager.requestPermission(device, mPermissionIntent);

                    txtInfo.append("Model:" + device.getDeviceName() + "\n");  
                    txtInfo.append("DeviceID:" + device.getDeviceId() + "\n");
                    txtInfo.append("Vendor:" + device.getVendorId() + "\n");
                    txtInfo.append("Product:" + device.getProductId() + "\n");
                    txtInfo.append("Class:" + device.getDeviceClass() + "\n");
                    txtInfo.append("Subclass:" + device.getDeviceSubclass() + "\n");
                    txtInfo.append("Protocol:" + device.getDeviceProtocol() + "\n");

                    UsbInterface intf = device.getInterface(0);
                    int epc = 0;
                    epc = intf.getEndpointCount();
                    txtInfo.append("Endpoints:" + epc + "\n");

                    txtInfo.append("Permission:" + Boolean.toString(manager.hasPermission(device))  + "\n");

                    UsbDeviceConnection connection = manager.openDevice(device);
                    if(null==connection){
                        txtInfo.append("(unable to establish connection)\n");
                    } else {

                        // Claims exclusive access to a UsbInterface. 
                        // This must be done before sending or receiving data on 
                        // any UsbEndpoints belonging to the interface.
                        connection.claimInterface(intf, true);

                        // getRawDescriptors can be used to access descriptors 
                        // not supported directly via the higher level APIs, 
                        // like getting the manufacturer and product names.
                        // because it returns bytes, you can get a variety of
                        // different data types.
                        byte[] rawDescs = connection.getRawDescriptors();
                        String manufacturer = "", product = "";

                        try
                        {
                            byte[] buffer = new byte[255];
                            int idxMan = rawDescs[14];
                            int idxPrd = rawDescs[15];

                            int rdo = connection.controlTransfer(UsbConstants.USB_DIR_IN
                                    | UsbConstants.USB_TYPE_STANDARD, STD_USB_REQUEST_GET_DESCRIPTOR,
                                    (LIBUSB_DT_STRING << 8) | idxMan, 0, buffer, 0xFF, 0);
                            manufacturer = new String(buffer, 2, rdo - 2, "UTF-16LE");

                            rdo = connection.controlTransfer(UsbConstants.USB_DIR_IN
                                            | UsbConstants.USB_TYPE_STANDARD, STD_USB_REQUEST_GET_DESCRIPTOR,
                                    (LIBUSB_DT_STRING << 8) | idxPrd, 0, buffer, 0xFF, 0);
                            product = new String(buffer, 2, rdo - 2, "UTF-16LE");

                        } catch (UnsupportedEncodingException e)
                        {
                        e.printStackTrace();
                        }

                        txtInfo.append("Manufacturer:" + manufacturer + "\n");                      
                        txtInfo.append("Product:" + product + "\n");                        
                        txtInfo.append("Serial#:" + connection.getSerial() + "\n");                     
                    }

                    txtInfo.append("------------------------------------\n");                   
                }               

            }
        });

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if(device != null){
                          //call method to set up device communication
                       }
                    } 
                    else {
                        txtInfo.append("permission denied for device " + device);
                    }
                }
            }
        }
    };

}

My manifest file containing the intents and requirements for the USB Host device support:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hotspotoffice.usbtest3"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-feature android:name="android.hardware.usb.host" />

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.hotspotoffice.usbtest3.MainActivity"
            android:label="@string/app_name" >

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>

            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/device_filter" />

        </activity>
    </application>

</manifest>

Finally, you will need a device filter. This is located under \res\xml\device_filter.xml Note that I had to create the xml folder myself, under \res.

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="7635" product-id="1" class="255" subclass="255" protocol="0" />
</resources>

Note that all the fields need to be in decimal, not hex. You'll need to substitute your own vendor, product, class and subclass values from your own device. You can use a program like "USB Host View" or "USB Device Info" to discover these values. (download them free from the Play Store.)

Finally, here's how I defined the user interface in Activity_Main.xml
You'll need at least the Discover button, and the TextMultiline for output. (Ignore the Init and On/Off buttons.)

BTW, I'm using a 10" Toshiba Thrive tablet, so YMMV.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <EditText
        android:id="@+id/txtInfo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/btnDiscover"
        android:layout_alignRight="@+id/textView1"
        android:layout_centerVertical="true"
        android:ems="10"
        android:inputType="textMultiLine"
        android:maxLines="50"
        android:minLines="20"
        android:minWidth="400dp" >

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/btnToggleDIO"
        android:layout_marginLeft="192dp"
        android:layout_toRightOf="@+id/btnDiscover"
        android:text="@string/lblDIO"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <Button
        android:id="@+id/btnDiscover"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/btnInit"
        android:layout_alignBottom="@+id/btnInit"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="73dp"
        android:text="@string/strDiscover" />

    <ToggleButton
        android:id="@+id/btnToggleDIO"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/btnInit"
        android:layout_alignBottom="@+id/btnInit"
        android:layout_alignLeft="@+id/textView1"
        android:text="@string/strIOState" />

    <Button
        android:id="@+id/btnInit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/txtInfo"
        android:layout_marginBottom="29dp"
        android:layout_marginLeft="48dp"
        android:layout_toRightOf="@+id/btnDiscover"
        android:text="@string/strInit" />

</RelativeLayout>

When I run my program and plug in my device, it asks for my permission to connect and I say "Ok". then I click Discover, and it tells me among other things that the manufacturer is "Dajac Inc." the product is "EIO1000" and the serial# is "0000004B".

I wish you good providence; you can give me credit but it's only by standing on the shoulders of others (with a lot of my own sweat) I've been able to see this far. Pass it forward! -David

like image 142
David at HotspotOffice Avatar answered Nov 15 '22 09:11

David at HotspotOffice


Code above works fine for most of the devices except Samsung mobile devices. For making them supply Language ID else you will get stall.

int rdo = connection.controlTransfer(UsbConstants.USB_DIR_IN
| UsbConstants.USB_TYPE_STANDARD, STD_USB_REQUEST_GET_DESCRIPTOR,
(LIBUSB_DT_STRING << 8) | idxMan, 0x0409, buffer, 0xFF, 0);
like image 20
Sunil Kumar Avatar answered Nov 15 '22 09:11

Sunil Kumar


device name

This looks like the internal device name from the Linux Kernel.

manufacturer name

You only get this indirectly via the USB VID (Vendor ID). They are assigned and maintained by the USB-IF.

A device may provide a name for the manufacturer in its string descriptor, but AFAIK this is optional - and not exposed in the high level android java interface.

You can try your luck with UsbDeviceConnection.getRawDescriptors, but that would require rather ugly fiddeling with bytes.

to mass storage

USB Mass storage is a rather complex protocol, so talking directly via USB Host API would be rather difficult to implement. Some Android firmware images can mount USB flash drives, that would be much simpler.

like image 36
Turbo J Avatar answered Nov 15 '22 11:11

Turbo J