Android ADK with PC as USB Host with libusb, bulk transfer error

前端 未结 2 588
刺人心
刺人心 2021-01-30 15:21

I\'m trying to make my PC the USB Host for Android 2.3.4 devices in order to be able to develop APIs without needing actual \"accessories\". To do this, I need to establish the

相关标签:
2条回答
  • 2021-01-30 15:32

    The code example is very helpful, it just needs some modifications to work on Windows using libusb and installing WinUSB drivers via Zadig.

    #include <stdio.h>
    #include <libusb.h>
    #include <string.h>
    #ifdef _WIN32
    #include <Windows.h>
    #define sleep Sleep
    #else
    #include <unistd.h>
    #endif
    
    #define ENDPOINT_BULK_IN 0x83
    #define ENDPOINT_BULK_OUT 0x03 // Have tried 0x00, 0x01 and 0x02
    
    #define VID 0x18D1
    #define PID 0x4E11
    
    #define ACCESSORY_PID 0x2D00
    #define ACCESSORY_ADB_PID 0x2D01 // Can't get this to work, if ADB is active, can't get handle on device
    
    #define PACKET_BULK_LEN 64
    #define TIMEOUT 5000
    
    static int transferTest(void);
    static int setupAccessory(
        const char* manufacturer,
        const char* modelName,
        const char* description,
        const char* version,
        const char* uri,
        const char* serialNumber);
    
    //static
    static struct libusb_device_handle* handle;
    
    int main (int argc, char *argv[])
    {
        int r, tries;
    
        libusb_init(NULL);
        if((handle = libusb_open_device_with_vid_pid(NULL, VID, PID)) != NULL)
        {
            libusb_claim_interface(handle, 0);  
    
            r = setupAccessory("PCHost",
                               "PCHost1",
                               "Description",
                               "1.0",
                               "http://www.mycompany.com",
                               "SerialNumber");
    
            libusb_release_interface (handle, 0);
            libusb_close(handle);
    
            if (r < 0)
            {
                libusb_exit(NULL);
                fprintf(stdout, "Error setting up accessory\n");
                return -1;
            }
        }
    
        tries = 4;
        for(;;)
        {
            tries--;
            if((handle = libusb_open_device_with_vid_pid(NULL, VID, ACCESSORY_PID)) == NULL)
            {
                if(tries < 0)
                {
                    libusb_exit(NULL);
                    fprintf(stdout, "Problem acquiring handle\n");
                    return -1;
                }
            }
            else
            {
                break;
            }
            sleep(1);
        }
    
        libusb_claim_interface(handle, 0);
        fprintf(stdout, "Interface claimed, ready to transfer data\n");
    
        r = transferTest();
    
        libusb_release_interface (handle, 0);
        libusb_close(handle);
    
        libusb_exit(NULL);
    
        if (r < 0)
        {
            fprintf(stdout, "Error in transferTest\n");
            return -1;
        }   
        fprintf(stdout, "Finished\n");
        return 0;
    }
    
    static int transferTest(void)
    {
        // TEST BULK IN/OUT
        int r,i;
        int transferred;
        unsigned char answer[PACKET_BULK_LEN];
        unsigned char question[PACKET_BULK_LEN];
        struct libusb_device* device;
        struct libusb_config_descriptor* config;
        struct libusb_interface_descriptor const* interfaceDesc;
        unsigned char epInAddr = ENDPOINT_BULK_IN;
        unsigned char epOutAddr = ENDPOINT_BULK_OUT;
        unsigned char idx;
    
        for (i=0;i<PACKET_BULK_LEN; i++) 
            question[i]=(unsigned char)i;
    
        device = libusb_get_device(handle);
        r = libusb_get_active_config_descriptor(device, &config);
        if (r < 0) 
        {
            fprintf(stderr, "No active descriptor error %d\n", r);
            return r;
        }
    
        interfaceDesc = config->interface[0].altsetting;
    
        for(idx = 0; idx < interfaceDesc->bNumEndpoints; idx++)
        {
            if ((interfaceDesc->endpoint[idx].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK)
            {
                if ((interfaceDesc->endpoint[idx].bEndpointAddress & LIBUSB_ENDPOINT_IN) == LIBUSB_ENDPOINT_IN)
                {
                    epInAddr = interfaceDesc->endpoint[idx].bEndpointAddress;
                }
                else
                {
                    epOutAddr = interfaceDesc->endpoint[idx].bEndpointAddress;
                }
            }
        }
    
        r = libusb_bulk_transfer(handle, epOutAddr, question, PACKET_BULK_LEN,
                                 &transferred,TIMEOUT);
        if (r < 0) 
        {
            fprintf(stderr, "Bulk write error %d\n", r);
            return r;
        }
        fprintf(stdout, "Wrote %d bytes", r);
    
        r = libusb_bulk_transfer(handle, epInAddr, answer,PACKET_BULK_LEN,
            &transferred, TIMEOUT);
        if (r < 0) 
        {
            fprintf(stderr, "Bulk read error %d\n", r);
            return r;
        }
        fprintf(stdout, "Read %d bytes", r);
    
        if (transferred < PACKET_BULK_LEN) 
        {
            fprintf(stderr, "Bulk transfer short read (%d)\n", r);
            return -1;
        }
        printf("Bulk Transfer Loop Test Result:\n");
        for(i = 0; i < PACKET_BULK_LEN; i++) 
        {
            if(i%8 == 0)
                printf("\n");
            printf("%02x, %02x; ",question[i],answer[i]);
        }
        printf("\n\n");
    
        return 0;
    
    }
    
    static int setupAccessory(
        const char* manufacturer,
        const char* modelName,
        const char* description,
        const char* version,
        const char* uri,
        const char* serialNumber)
    {
        unsigned char ioBuffer[2];
        int devVersion;
        int r;
    
        r = libusb_control_transfer(
            handle, //handle
            0xC0, //bmRequestType
            51, //bRequest
            0, //wValue
            0, //wIndex
            ioBuffer, //data
            2, //wLength
            0 //timeout
            );
    
        if(r < 0)
        {
            return-1;
        }
    
        devVersion = ioBuffer[1] << 8 | ioBuffer[0];
        fprintf(stdout,"Version Code Device: %d\n", devVersion);
    
        sleep(1); //sometimes hangs on the next transfer :(
    
        if ((libusb_control_transfer(handle,0x40,52,0,0,(unsigned char*)manufacturer,strlen(manufacturer)+1,0) < 0) ||
            (libusb_control_transfer(handle,0x40,52,0,1,(unsigned char*)modelName,strlen(modelName)+1,0) < 0) ||
            (libusb_control_transfer(handle,0x40,52,0,2,(unsigned char*)description,strlen(description)+1,0) < 0) ||
            (libusb_control_transfer(handle,0x40,52,0,3,(unsigned char*)version,strlen(version)+1,0) < 0) ||
            (libusb_control_transfer(handle,0x40,52,0,4,(unsigned char*)uri,strlen(uri)+1,0) < 0) ||
            (libusb_control_transfer(handle,0x40,52,0,5,(unsigned char*)serialNumber,strlen(serialNumber)+1,0) < 0))
        {
            return -1;
        }
    
        fprintf(stdout,"Accessory Identification sent\n", devVersion);
    
        r = libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0);
        if(r < 0)
        {
            return -1;
        }
    
        fprintf(stdout,"Attempted to put device into accessory mode\n", devVersion);
        return 0;
    }
    

    Besides some refactoring and adding the necessary libusb_close(handle) calls mentioned in @ColinM's answer this is mainly adding:

    1. Enumeration over the available end-points
    2. Assumes the device is already in accessory mode if initial PID/VID not found
    0 讨论(0)
  • 2021-01-30 15:55

    Initial problem is that the original connection to the device in order to tell it to go into accessory mode is never closed. The USB subsystem and/or libusb do not throw an error if you then reopen and claim an interface while the original device is still left open. You only get an IO or NOT FOUND error when you actually try to write to/from an endpoint.

    By adding:

    libusb_close(handle);
    

    within the if statement where the initial interface is released from initial connection the libusb side of the issue is resolved.

    The next issue that prevents data to pass in this particular combination of softwares, is that the Android side is waiting for a larger segment of bytes before it accepts the read which results in a timeout (haven't worked out due to which side yet) and so if you set the buffer to match the libusb side (64), you will get an initial set of bytes written from the PC to the Android device. The software will still break after that since the PC/libusb side then tries to read data but the Android side isn't writing any, but that is simply unfinished software and not within the scope of the question.

    0 讨论(0)
提交回复
热议问题