2013-04-11 100 views
14

我认为试图编译一个特定的C程序,它允许通过USB控制Gembird SilverShield电源插座为Android。在我的android HDMI电视棒上,这将非常有用。有一个开放的项目this。它在Linux下工作,取决于libusb。目标平台是android ICS。我想在Ubuntu Linux上开发。我有什么机会让它工作?什么是必需的步骤。安装android SDK,NDK,交叉编译器...
有一个旧的问题here,与Android上的libusb相关,但没有信息如何。
将应用程序移植到androids自己的usb库可能更容易吗?编译并链接到Android的libusb

+0

这里有一个项目叫libusbdroid http://sourceforge.net/projects/libusbdroid/。我将如何链接sispmctl并进行安装? – highsciguy 2013-04-19 12:36:43

回答

23

Libusb可以在非root的android上工作(假设设备支持USB主机...这是非常重要的,因为并非所有的设备都是如此)。你需要使用标准的android USB栈。然后您可以从USBDevice获取设备描述符并将其传递给libusb。

不幸的是,您还需要修改libusb。幸运的是,其他人已经解释了您需要如何修改LibUSB。

LibUSB已被修改here

祝你好运!

编辑

首先,你需要定义一个广播接收器:

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

现在,你需要创建一个USBManager和枚举的设备:

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. 
     } 
    } 

编辑2

获得libusb的建立只是把文件放在方便(我把它们放在JNI/libusb的),然后添加以下行到你的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

我可以在某处找到创建和传递设备描述符。 – highsciguy 2013-04-26 10:31:35

+0

@highsciguy:发布编辑。 – Goz 2013-04-26 11:08:10

+0

@highsciguy:这有帮助吗? – Goz 2013-04-26 19:29:39

1

即使你编译了它,Android可能也不会让你通过libusb访问USB设备,除非你的设备是根植的。如果将应用程序移植到Android's native USB stack是可行的,那几乎肯定会是更稳定的解决方案。

+1

设备已生根。对于所有其他具有最新固件的Rikomagic III HDMI支架也是如此。如果这是不使用libusb的唯一原因,我会试一试。但是,知道类似Android的USB堆栈和libusb是多么的有趣,如果你对它有所了解......另外:我怎样才能在C中使用它。 – highsciguy 2013-04-26 08:27:37

1

你也可以尝试使用android serial port api

这里是串口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); 
} 

在USB主机上使用设备也是如此。

4

我实现的解决方案是使用Java API打开USB设备,然后使用带有libusb的文件描述符。我由PrimeSense的(https://github.com/OpenNI/OpenNI2)使用的libusb从openni项目

码位:

打开设备(使用痛饮):

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

开放Java代码的设备(在主线程不运行! ):

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

权限处理代码:

private 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); 
       } 
      } 
     } 
    } 
} 

};

开放功能:

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); 

    } 

USB LIB变化(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)变化:

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

谢谢,这很有帮助。您还可以分享如何创建调用libusb_open()所需的libusb_device *? – rsp1984 2016-10-22 15:45:34