2013-04-11 10 views
14

Prendo in considerazione la possibilità di compilare un certo programma C che consente il controllo delle prese di corrente di Gembird SilverShield via USB per Android. Sul mio Android TV-stick HDMI sarebbe molto utile. Esiste un progetto aperto per this. Funziona sotto Linux e dipende da libusb. La piattaforma di destinazione è Android ICS. Voglio sviluppare su Ubuntu Linux. Quali sono le possibilità che funzioni? Quali sono i passaggi richiesti. Impostazione di Android SDK, NDK, crosscompiler ...
C'è una domanda precedente here, correlata a libusb su Android ma nessuna informazione su come.
È forse più semplice trasferire l'applicazione nella libreria USB di androids?Compilare e collegarsi a libusb per Android

+0

Ecco un progetto chiamato libusbdroid http://sourceforge.net/projects/libusbdroid/. Come collegherò sispmctl e installarlo? – highsciguy

risposta

23

Libusb può funzionare su un Android non rootato (a condizione che il dispositivo supporti l'host USB ... questo è MOLTO importante poiché non tutti i dispositivi lo fanno). È necessario utilizzare lo stack USB standard di Android. È quindi possibile ottenere un descrittore di dispositivo dal dispositivo USB e trasferirlo su libusb.

Sfortunatamente è necessario modificare anche libusb. Fortunatamente altre persone hanno spiegato come è necessario modificare LibUSB.

LibUSB è stato modificato here.

Buona fortuna!

Edit:

In primo luogo è necessario definire un ricevitore di broadcast:

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) 
        { 
         UsbDeviceConnection deviceConnection = mUsbManager.openDevice(device); 
         Log.d("USB", deviceConnection.getSerial()); 
        } 
       } 
       else 
       { 
        Log.d("USB", "permission denied for device " + device); 
       } 
      } 
     } 
    } 
} 

Ora è necessario creare un USBManager ed enumerare i dispositivi:

mUsbManager   = (UsbManager) getSystemService(Context.USB_SERVICE); 
    HashMap< String, UsbDevice > stringDeviceMap =  mUsbManager.getDeviceList(); 
    Collection<UsbDevice> usbDevices    = stringDeviceMap.values(); 

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

    Iterator<UsbDevice> usbDeviceIter    = usbDevices.iterator(); 
    while(usbDeviceIter.hasNext()) 
    { 
     if (USBDeviceValid(usbDevice)) 
     { 
      // Request permission to access the device. 
      mUsbManager.requestPermission(usbDevice, mPermissionIntent); 

      // Open the device. 
      UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice); 
      int fd = connection.getFileDescriptor(); 

      // Now pass the file descriptor to libusb through a native call. 
     } 
    } 

Modifica 2:

Ottenere libusb di costruire è solo una questione di mettere i file da qualche parte a portata di mano (li ho messi in JNI/libusb) e quindi aggiungendo le seguenti righe al tuo Android.mk:

include $(CLEAR_VARS) 
LOCAL_MODULE := libusb 
LOCAL_SRC_FILES := libusb/core.c libusb/descriptor.c libusb/io.c libusb/sync.c libusb/os/linux_usbfs.c 

LOCAL_LDLIBS := -llog 
include $(BUILD_SHARED_LIBRARY) 
+0

Posso trovare da qualche parte un esempio per la creazione e il passaggio del descrittore del dispositivo. – highsciguy

+0

@highsciguy: post modificato. – Goz

+0

@highsciguy: questo aiuto? – Goz

1

Anche se è stato compilato, Android probabilmente non consentirà l'accesso al dispositivo USB tramite libusb a meno che il dispositivo non sia rootato. Se è possibile portare la tua app a Android's native USB stack, quella sarebbe quasi sicuramente una soluzione più stabile.

+1

Il dispositivo è rootato. Questo vale anche per tutti gli altri stick HDMI Rikomagic III con firmware aggiornato. Se questa è l'unica ragione per non usare libusb, proverei. Ma sarebbe anche interessante sapere come sono simili stack USB e libusb di Android, se ne sai qualcosa ... Inoltre: Come posso usarlo in C. – highsciguy

1

È puoi anche provare a usare android serial port api

Ecco un esempio di porta seriale init.

private FileDescriptor mFd; 
private FileInputStream mFileInputStream; 
private FileOutputStream mFileOutputStream; 

public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { 

    /* Check access permission */ 
    if (!device.canRead() || !device.canWrite()) { 
     try { 
      /* Missing read/write permission, trying to chmod the file */ 
      Process su; 
      su = Runtime.getRuntime().exec("/system/bin/su"); 
      String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" 
        + "exit\n"; 
      su.getOutputStream().write(cmd.getBytes()); 
      if ((su.waitFor() != 0) || !device.canRead() 
        || !device.canWrite()) { 
       throw new SecurityException(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
      throw new SecurityException(); 
     } 
    } 

    mFd = open("/dev/ttyACM0", 9600, 0); 
    if (mFd == null) { 
     Log.e(TAG, "native open returns null"); 
     throw new IOException(); 
    } 
    mFileInputStream = new FileInputStream(mFd); 
    mFileOutputStream = new FileOutputStream(mFd); 
} 

Così ha fatto con i dispositivi di uso su host USB.

4

La soluzione che ho implementato è quella di aprire il dispositivo USB utilizzando le API Java e quindi utilizzare il descrittore di file con libusb.Ho usato libusb dal progetto OpenNI da PrimeSense (https://github.com/OpenNI/OpenNI2)

bit codice:

di apertura del dispositivo (Uso sorso):

int LibUsbAndroid::android_open(libusb_device *device, libusb_device_handle **devHandle) 
{ 
    int fd = USBJNICallbacks::getCallback()->getDeviceFd(device->bus_number, device->device_address); 

    __android_log_print(ANDROID_LOG_VERBOSE,"USB","Got FD:%d",fd); 
    if(fd==-1) 
    { 
     __android_log_print(ANDROID_LOG_ERROR,"USB","android_open, bad fd"); 
     return -1; 
    } 

    return libusb_open(device, devHandle, fd); 
} 

L'apertura del dispositivo in codice Java (non in esecuzione sul thread principale!):

public int getDeviceFd(int busNumber, int deviceAddress) { 
     UsbDevice device = findDevice(busNumber, deviceAddress); 

     if(device!=null) 
     { 
      mReceivedPermission = false; 
      PermissionRequester pr = new PermissionRequester(device); 
      pr.run(); 

      if(!mUsbManager.hasPermission(device)) 
      { 
       Log.v("USB", "Requesting permissiom to device"); 
       mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0); 
       IntentFilter filterPermission = new IntentFilter(ACTION_USB_PERMISSION); 
       mContext.registerReceiver(mUsbPermissionReceiver, filterPermission); 
       mUsbManager.requestPermission(device, mPermissionIntent); 
      } 
      else 
      { 
       Log.v("USB", "Already has permission"); 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 

       mReceivedPermission = true; 

       Log.v("USB", "Opening device"); 
       OpenDevice od = openDevice(device); 
       Log.v("USB", "Adding to open devices"); 
       mOpenDevices.put(""+busNumber+"/"+deviceAddress, od); 


      } 

      Log.v("USB", "Waiting for permission"); 
      waitForPermissionResult(); 
      OpenDevice od = mOpenDevices.get(""+busNumber+"/"+deviceAddress); 
      if(od!=null) 
      { 
       Log.v("USB", "Getting FD"); 
       int result = od.mConnection.getFileDescriptor(); 

       Log.i("USB","USB File desc:"+result); 
       return result; 
      } 
      else 
      { 
       Log.v("USB", "Error getting FD"); 
       return -1; 
      } 
     } 

     return -1; 
    } 

permesso codice di gestione:

privato BroadcastReceiver mUsbPermissionReceiver = new BroadcastReceiver() {

@Override 
public void onReceive(Context context, Intent intent) { 

    Log.v("USB", "Received permission result"); 
    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)) { 
       Log.v("USB", "Received permission result OK"); 
       if(device != null){ 
        Log.v("USB", "Device OK"); 
        mContext.unregisterReceiver(this);  
        Log.v("USB", "Openning device"); 
        OpenDevice od = openDevice(device); 
        Log.v("USB", "Adding to open device list"); 
        mOpenDevices.put(""+od.mBus+"/"+od.mAddress,od); 

        Log.v("USB", "Received permission is true"); 
        mReceivedPermission = true; 
       } 
       else { 
        Log.d(TAG, "permission denied for device " + device); 
       } 
      } 
     } 
    } 
} 

};

Aperto funzione:

public OpenDevice openDevice(UsbDevice device) { 
     UsbDeviceConnection connection = mUsbManager.openDevice(device); 

     Log.i("USB","Device name="+device.getDeviceName()); 

     int bus = getBusNumber(device.getDeviceName()); 
     int address = getAddress(device.getDeviceName()); 

     return new OpenDevice(device, connection, bus, address); 

    } 

cambiamento lib USB (core.c):

int API_EXPORTED libusb_open(libusb_device *dev, 
    libusb_device_handle **handle, int fd) 
{ 
    struct libusb_context *ctx = DEVICE_CTX(dev); 
    struct libusb_device_handle *_handle; 
    size_t priv_size = usbi_backend->device_handle_priv_size; 
    int r; 
    usbi_dbg("open %d.%d", dev->bus_number, dev->device_address); 

    _handle = malloc(sizeof(*_handle) + priv_size); 
    if (!_handle) 
     return LIBUSB_ERROR_NO_MEM; 

    r = usbi_mutex_init(&_handle->lock, NULL); 
    if (r) { 
     free(_handle); 
     return LIBUSB_ERROR_OTHER; 
    } 

    _handle->dev = libusb_ref_device(dev); 
    _handle->claimed_interfaces = 0; 
    memset(&_handle->os_priv, 0, priv_size); 

    r = usbi_backend->open(_handle,fd); 
    if (r < 0) { 
     usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r); 
     libusb_unref_device(dev); 
     usbi_mutex_destroy(&_handle->lock); 
     free(_handle); 
     return r; 
    } 

    usbi_mutex_lock(&ctx->open_devs_lock); 
    list_add(&_handle->list, &ctx->open_devs); 
    usbi_mutex_unlock(&ctx->open_devs_lock); 
    *handle = _handle; 
    /* At this point, we want to interrupt any existing event handlers so 
    * that they realise the addition of the new device's poll fd. One 
    * example when this is desirable is if the user is running a separate 
    * dedicated libusb events handling thread, which is running with a long 
    * or infinite timeout. We want to interrupt that iteration of the loop, 
    * so that it picks up the new fd, and then continues. */ 
    usbi_fd_notification(ctx); 

    return 0; 
} 

op_open (libusb_fs.c) cambio:

static int op_open(struct libusb_device_handle *handle, int fd) 
{ 
    struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); 
    char filename[PATH_MAX]; 

    _get_usbfs_path(handle->dev, filename); 
    usbi_dbg("opening %s", filename); 

    hpriv->fd = fd; 

    if (hpriv->fd < 0) { 
     if (errno == EACCES) { 
      usbi_err(HANDLE_CTX(handle), "libusb couldn't open USB device %s: " 
       "Permission denied.", filename); 
      usbi_err(HANDLE_CTX(handle), 
       "libusb requires write access to USB device nodes."); 
      return LIBUSB_ERROR_ACCESS; 
     } else if (errno == ENOENT) { 
      usbi_err(HANDLE_CTX(handle), "libusb couldn't open USB device %s: " 
       "No such file or directory.", filename); 
      return LIBUSB_ERROR_NO_DEVICE; 
     } else { 
      usbi_err(HANDLE_CTX(handle), 
       "open failed, code %d errno %d", hpriv->fd, errno); 
      return LIBUSB_ERROR_IO; 
     } 
    } 

    return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); 
} 
+0

Grazie, questo è abbastanza utile. Puoi condividere anche come crei il dispositivo libusb_device * richiesto per la chiamata a libusb_open()? – rsp1984