Android ADK mit PC als USB Host mit libusb, Massenübertragungsfehler

Ich versuche, meinen PC zum USB-Host für Android 2.3.4 Geräte zu machen, um APIs entwickeln zu können, ohne dass du "Zubehör" benötigst. Um dies zu tun, muss ich den PC als USB-Host und das "Gerät" (in meinem Fall ein Nexus One läuft 2.3.4) zu etablieren.

Ich begann mit libusb Code von http://android.serverbox.ch/ als Basis für die PC-Seite und die DemoKit-Code und Android-Dokumentation auf der Android-Seite.

  • Warum ist das Demokit-Programm für die ADK in Arduino nicht kompiliert?
  • ADK und Eclipse wehe - com.android.future und USBAccessory?
  • Build.xml gibt Fehler beim Kompilieren einer Verarbeitungsskizze, die ArduinoAdkUsb enthält
  • Vorgeschlagenes Protokoll für android-arduino Kommunikation
  • Einschließlich anderer Eclipse-Projekte in einem Android-Anwendungsprojekt
  • Welche Android-Geräte unterstützen das ADK / Open-Zubehör
  • Die beiden scheinen die Verbindung gut zu verhandeln, und die Schnittstelle wird "behauptet", aber stirbt auf dem eigentlichen Versuch der Massenübertragung. Bei OSX ist der Fehler -5 (LIBUSB_ERROR_NOT_FOUND) und auf Ubuntu Linux (als root) der Fehler -1 (LIBUSB_ERROR_IO). (Neueste Veröffentlichungen von jeweils mit dem neuesten libusb 1.0.8).

    Hier ist der Code. Andere Kommentare zu Problemen willkommen, obwohl dies ist meist ein Proof-of-Konzept, so bin ich wirklich nur auf der Suche nach dem Grund der Massenübertragung funktioniert nicht:

    #include <stdio.h> #include <libusb.h> #include <string.h> #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 /* ON OSX gcc adktest.c -I/usr/local/include -o adktest -lusb-1.0.0 -I/usr/local/include -I/usr/local/include/libusb-1.0 ON UBUNTU gcc adktest.c -I/usr/include -o adktest -lusb-1.0 -I/usr/include -I/usr/include/libusb-1.0 Testing on Nexus One with Gingerbread 2.3.4 */ static int transferTest(); static int init(void); static int shutdown(void); static void error(int code); static void status(int code); 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[]){ if(init() < 0) return; if(setupAccessory( "PCHost", "PCHost1", "Description", "1.0", "http://www.mycompany.com", "SerialNumber") < 0){ fprintf(stdout, "Error setting up accessory\n"); shutdown(); return -1; }; if(transferTest() < 0){ fprintf(stdout, "Error in transferTest\n"); shutdown(); return -1; } shutdown(); fprintf(stdout, "Finished\n"); return 0; } static int transferTest(){ // TEST BULK IN/OUT const static int PACKET_BULK_LEN=64; const static int TIMEOUT=5000; int r,i; int transferred; char answer[PACKET_BULK_LEN]; char question[PACKET_BULK_LEN]; for (i=0;i<PACKET_BULK_LEN; i++) question[i]=i; // ***FAILS HERE*** r = libusb_bulk_transfer(handle, ENDPOINT_BULK_OUT, question, PACKET_BULK_LEN, &transferred,TIMEOUT); if (r < 0) { fprintf(stderr, "Bulk write error %d\n", r); error(r); return r; } fprintf(stdout, "Wrote %d bytes", r); r = libusb_bulk_transfer(handle, ENDPOINT_BULK_IN, answer,PACKET_BULK_LEN, &transferred, TIMEOUT); if (r < 0) { fprintf(stderr, "Bulk read error %d\n", r); error(r); return r; } fprintf(stdout, "Read %d bytes", r); if (transferred < PACKET_BULK_LEN) { fprintf(stderr, "Bulk transfer short read (%d)\n", r); error(r); return -1; } printf("Bulk Transfer Loop Test Result:\n"); // for (i=0;i< PACKET_BULK_LEN;i++) printf("%i, %i,\n ",question[i],answer[i]); 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 init(){ libusb_init(NULL); if((handle = libusb_open_device_with_vid_pid(NULL, VID, PID)) == NULL){ fprintf(stdout, "Problem acquiring handle\n"); return -1; } libusb_claim_interface(handle, 0); return 0; } static int shutdown(){ if(handle != NULL) libusb_release_interface (handle, 0); libusb_exit(NULL); 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 response; response = libusb_control_transfer( handle, //handle 0xC0, //bmRequestType 51, //bRequest 0, //wValue 0, //wIndex ioBuffer, //data 2, //wLength 0 //timeout ); if(response < 0){error(response);return-1;} devVersion = ioBuffer[1] << 8 | ioBuffer[0]; fprintf(stdout,"Version Code Device: %d\n", devVersion); usleep(1000);//sometimes hangs on the next transfer :( response = libusb_control_transfer(handle,0x40,52,0,0,(char*)manufacturer,strlen(manufacturer),0); if(response < 0){error(response);return -1;} response = libusb_control_transfer(handle,0x40,52,0,1,(char*)modelName,strlen(modelName)+1,0); if(response < 0){error(response);return -1;} response = libusb_control_transfer(handle,0x40,52,0,2,(char*)description,strlen(description)+1,0); if(response < 0){error(response);return -1;} response = libusb_control_transfer(handle,0x40,52,0,3,(char*)version,strlen(version)+1,0); if(response < 0){error(response);return -1;} response = libusb_control_transfer(handle,0x40,52,0,4,(char*)uri,strlen(uri)+1,0); if(response < 0){error(response);return -1;} response = libusb_control_transfer(handle,0x40,52,0,5,(char*)serialNumber,strlen(serialNumber)+1,0); if(response < 0){error(response);return -1;} fprintf(stdout,"Accessory Identification sent\n", devVersion); response = libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0); if(response < 0){error(response);return -1;} fprintf(stdout,"Attempted to put device into accessory mode\n", devVersion); if(handle != NULL) libusb_release_interface (handle, 0); int tries = 4; for(;;){ tries--; if((handle = libusb_open_device_with_vid_pid(NULL, VID, ACCESSORY_PID)) == NULL){ if(tries < 0){ return -1; } }else{ break; } sleep(1); } libusb_claim_interface(handle, 0); fprintf(stdout, "Interface claimed, ready to transfer data\n"); return 0; } // error reporting function left out for brevity 

    Und hier ist die Android-App:

     package com.cengen.android.pchost; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.ParcelFileDescriptor; import com.android.future.usb.UsbAccessory; import com.android.future.usb.UsbManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class MainActivity extends Activity implements Runnable { private final Logger logger = LoggerFactory.getLogger("PCHost"); private UsbManager usbManager; UsbAccessory accessory; ParcelFileDescriptor accessoryFileDescriptor; FileInputStream accessoryInput; FileOutputStream accessoryOutput; private final BroadcastReceiver usbBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) { synchronized (this) { accessory = UsbManager.getAccessory(intent); } } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) { UsbAccessory accessory = UsbManager.getAccessory(intent); if (accessory != null) { // call your method that cleans up and closes communication with the accessory } } } }; Handler messageHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: logger.info("Got message type {}", msg.what); // SendFileMessage m = (SendFileMessage) msg.obj; // handleSendFile(m); break; case 2: logger.info("Got message type {}", msg.what); // SendFileMessage m = (SendFileMessage) msg.obj; // handleSendFile(m); break; case 3: logger.info("Got message type {}", msg.what); // SendFileMessage m = (SendFileMessage) msg.obj; // handleSendFile(m); break; } } }; /** * Main USB reading loop, processing incoming data from accessory and parsing * it into messages via the defined format. */ public void run() { int ret = 0; byte[] buffer = new byte[16384]; int i; while (ret >= 0) { try { ret = accessoryInput.read(buffer); logger.debug("Read {} bytes.", ret); } catch (IOException e) { logger.debug("Exception in USB accessory input reading", e); break; } i = 0; while (i < ret) { int len = ret - i; switch (buffer[i]) { case 0x1: if (len >= 3) { Message m = Message.obtain(messageHandler, 1); // m.obj = new MessageTypeOne(buffer[i + 1], buffer[i + 2]); messageHandler.sendMessage(m); } i += 3; break; case 0x4: if (len >= 3) { Message m = Message.obtain(messageHandler, 1); // m.obj = new MessageTypeTwo(buffer[i + 1], buffer[i + 2]); messageHandler.sendMessage(m); } i += 3; break; default: logger.debug("unknown msg: " + buffer[i]); i = len; break; } } } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); usbManager = UsbManager.getInstance(this); IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); registerReceiver(usbBroadcastReceiver, filter); if (getLastNonConfigurationInstance() != null) { accessory = (UsbAccessory) getLastNonConfigurationInstance(); openAccessory(accessory); } setContentView(R.layout.main); } @Override public Object onRetainNonConfigurationInstance() { return accessory != null ? accessory : super.onRetainNonConfigurationInstance(); } @Override public void onResume() { super.onResume(); Intent intent = getIntent(); if (accessoryInput != null && accessoryOutput != null) return; // TODO: verify, docs don't do this simple thing, not sure why? UsbAccessory accessory = UsbManager.getAccessory(intent); if (accessory != null) openAccessory(accessory); else logger.error("Failed to resume accessory."); } @Override public void onPause() { super.onPause(); closeAccessory(); } @Override public void onDestroy() { unregisterReceiver(usbBroadcastReceiver); super.onDestroy(); } private void openAccessory(UsbAccessory accessory) { accessoryFileDescriptor = usbManager.openAccessory(accessory); if (accessoryFileDescriptor != null) { this.accessory = accessory; FileDescriptor fd = accessoryFileDescriptor.getFileDescriptor(); accessoryInput = new FileInputStream(fd); accessoryOutput = new FileOutputStream(fd); Thread thread = new Thread(null, this, "AndroidPCHost"); thread.start(); logger.debug("accessory opened"); // TODO: enable USB operations in the app } else { logger.debug("accessory open fail"); } } private void closeAccessory() { // TODO: disable USB operations in the app try { if (accessoryFileDescriptor != null) accessoryFileDescriptor.close(); } catch (IOException e) {} finally { accessoryFileDescriptor = null; accessory = null; } } } 

    Und das Manifest (einschließlich der Absicht-Filterung, so dass es automatisch assoziiert und Auto-perms das Gerät, nach den docs):

     <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mycompany.android.pchost" android:versionCode="1" android:versionName="1.0"> <uses-feature android:name="android.hardware.usb.accessory" /> <uses-sdk android:minSdkVersion="10" /> <application android:label="@string/app_name" android:icon="@drawable/icon"> <uses-library android:name="com.android.future.usb.accessory" /> <activity android:name="MainActivity" android:label="@string/app_name" android:launchMode="singleInstance"> <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_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity> </application> </manifest> 

  • Slide RecyclerEntwickeln Sie, wie Sie es aufwischen, oder schieben Sie recyclerview unten, während Sie unten rutschen
  • Robojuice / Butterknife @InjectView AutoFormatting Problem in Android Studio
  • Android wie man startActivityForResult in einem Adapter aufruft
  • Wie kann man sich von Facebook-SDK-Ereignisprotokollierung abmelden?
  • So speichern Sie Dateien im externen Speicher Public Directory DOKUMENTE auf Android 4.1.2
  • Entfernen Sie das Kennwort-Symbol in Android N
  • 2 Solutions collect form web for “Android ADK mit PC als USB Host mit libusb, Massenübertragungsfehler”

    Anfängliches Problem ist, dass die ursprüngliche Verbindung zum Gerät, um zu sagen, dass es in den Zusatzmodus geht, niemals geschlossen wird. Das USB-Subsystem und / oder libusb werfen einen Fehler nicht aus, wenn du dann eine Schnittstelle wiedereröffnet und beanspruchst, während das Originalgerät noch offen bleibt. Sie erhalten nur einen IO oder NOT FOUND Fehler, wenn Sie tatsächlich versuchen, zu / von einem Endpunkt zu schreiben.

    Beim Hinzufügen:

     libusb_close(handle); 

    Innerhalb der if-Anweisung, bei der die anfängliche Schnittstelle von der anfänglichen Verbindung freigegeben wird, wird die libusb-Seite des Problems aufgelöst.

    Die nächste Ausgabe, die verhindert, dass Daten in dieser speziellen Kombination von Software passieren, ist, dass die Android-Seite auf ein größeres Segment von Bytes wartet, bevor es das Lesen akzeptiert, was zu einem Timeout führt (noch nicht ausgearbeitet, auf welcher Seite noch) Und wenn du also den Puffer auf die Libusb-Seite (64) passt, bekommst du einen ersten Satz von Bytes, die vom PC auf das Android-Gerät geschrieben wurden. Die Software wird immer noch brechen, da die PC / libusb Seite dann versucht, Daten zu lesen, aber die Android-Seite ist nicht schreiben, aber das ist einfach unvollendet Software und nicht im Rahmen der Frage.

    Das Codebeispiel ist sehr hilfreich, es braucht nur einige Modifikationen, um unter Windows mit libusb und WinUSB-Treiber über Zadig zu installieren .

     #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; } 

    Neben einigen Refactoring und Hinzufügen der notwendigen libusb_close(handle) Anrufe in @ ColinM Antwort erwähnt, ist dies vor allem Hinzufügen:

    1. Aufzählung über die verfügbaren Endpunkte
    2. Angenommen, das Gerät befindet sich bereits im Zusatzmodus, wenn das erste PID / VID nicht gefunden wurde
    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.