Search code examples
androidwindowsusbdrivers

Communicating with android device from Windows PC via USB


I have android device and windows drivers for it. I have to communicate using my own binary protocol in accessory mode. Is it possible to send data to this device without writing custom USB driver?


Solution

  • USB is a complex protocol because it is 'universal' and can handle a large variety of devices (mass storage, cameras,...). So on your android device has to be implemented a basic USB structure to use standard libraries like libusb or something like that. You can assume that this is the case, because android is in most cases used on processors with USB port.

    See http://www.beyondlogic.org/usbnutshell/usb1.shtml.

    You can get more information about the USB device classes, interfaces, configurations, endpoints ur android device impmenets by using libusb -v

    Then if you know what the USB structure on your android device looks like you can use libusb or another library to write data to specific endpoints in the usb structure by e.g. libusb_bulk_transfer(), libusb_control_transfer()

    http://libusb.sourceforge.net/api-1.0/io.html

    If you want to program in java you can use usb4java however this is a bit flaky http://usb4java.org/quickstart/libusb.html

    The general USB structure is device -> (configuration) -> interface -> endpoint

    So the way to write data to an endpoint is:

    libusb_init(NULL); 
    libusb_open_device_with_vid_pid(NULL, vendor_id, product_id);
    libusb_claim_interface(devh, 0);
    libusb_bulk_transfer(dev_handle, (2 | LIBUSB_ENDPOINT), data, 
            4, &p, 0); //example
    ... release interface...
    ...
    libusb_close(devh);
    libusb_exit(NULL);
    

    Here is C++ example copied from http://www.dreamincode.net/forums/topic/148707-introduction-to-using-libusb-10/

    #include <iostream>
    #include <libusb.h>
    
    using namespace std;
    
    int main() {
        libusb_device **devs; //pointer to pointer of device, used to      
                                retrieve a list of devices
        libusb_device_handle *dev_handle; //a device handle
        libusb_context *ctx = NULL; //a libusb session
    
        int r; //for return values
        ssize_t cnt; //holding number of devices in list
        r = libusb_init(&ctx); //initialize the library for the session we 
                                 just declared
        if(r < 0) {
            cout<<"Init Error "<<r<<endl; //there was an error
            return 1;
        }
        libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in 
                                    the documentation
    
        cnt = libusb_get_device_list(ctx, &devs); //get the list of devices
        if(cnt < 0) {
            cout<<"Get Device Error"<<endl; //there was an error
            return 1;
        }
        cout<<cnt<<" Devices in list."<<endl;
    
        dev_handle = libusb_open_device_with_vid_pid(ctx, 5118, 7424);  
                  //these are vendorID and productID I found for my usb device
    
        if(dev_handle == NULL)
            cout<<"Cannot open device"<<endl;
        else
            cout<<"Device Opened"<<endl;
        libusb_free_device_list(devs, 1); //free the list, unref the devices 
                                             in it
    
        unsigned char *data = new unsigned char[4]; //data to write
    
        data[0]='a';data[1]='b';data[2]='c';data[3]='d'; //some dummy values
    
        int actual; //used to find out how many bytes were written
        if(libusb_kernel_driver_active(dev_handle, 0) == 1) { //find out if 
                                                   kernel driver is attached
            cout<<"Kernel Driver Active"<<endl;
            if(libusb_detach_kernel_driver(dev_handle, 0) == 0) //detach it
                cout<<"Kernel Driver Detached!"<<endl;
        }
        r = libusb_claim_interface(dev_handle, 0); //claim interface 0 (the   
        first) of device (mine had jsut 1)
        if(r < 0) {
            cout<<"Cannot Claim Interface"<<endl;
            return 1;
        }
        cout<<"Claimed Interface"<<endl;
    
        cout<<"Data->"<<data<<"<-"<<endl; //just to see the data we want to 
        write : abcd
        cout<<"Writing Data..."<<endl;
        r = libusb_bulk_transfer(dev_handle, (2 | LIBUSB_ENDPOINT_OUT), data, 
        4, &actual, 0); //my device's out endpoint was 2, found with trial- 
        the device had 2 endpoints: 2 and 129
        if(r == 0 && actual == 4) //we wrote the 4 bytes successfully
            cout<<"Writing Successful!"<<endl;
        else
            cout<<"Write Error"<<endl;
    
        r = libusb_release_interface(dev_handle, 0); //release the claimed 
                                                        interface
        if(r!=0) {
            cout<<"Cannot Release Interface"<<endl;
            return 1;
        }
        cout<<"Released Interface"<<endl;    
    
        libusb_close(dev_handle); //close the device we opened
        libusb_exit(ctx); //needs to be called to end the
        delete[] data; //delete the allocated memory for data
        return 0;
    }
    

    So as your device runs android it has a USB structure/functionality. To investigate the USB functionality of your device (device class like mass storage, RNDIS,...) use libusb -v and the see the code above to write custom data to one of the endpoints on the device.