简体   繁体   English

针对Android的libusb进行编译和链接

[英]Compile and link against libusb for android

I consider trying to compile a certain C-programm which allows the control of Gembird SilverShield power outlets via USB for android. 我考虑尝试编译某个C程序,该程序允许通过USB for Android控制Gembird SilverShield电源插座。 On my android HDMI TV-stick this would be very useful. 在我的Android HDMI电视棒上,这将非常有用。 There is an open project for this . 为此有一个开放项目。 It works under Linux and depends on libusb. 它在Linux下工作,并依赖libusb。 The target platform is android ICS. 目标平台是android ICS。 I want to develop on Ubuntu Linux. 我想在Ubuntu Linux上进行开发。 What are the chances I get it working? 我有什么机会可以使用它? What are the required steps. 所需步骤是什么。 Setup android SDK, NDK, crosscompiler ... 设置android SDK,NDK,交叉编译器...
There is an older question here , related to libusb on android but no information how. 有一个老问题, 在这里 ,与libusb在Android上,但没有信息的方式有关。
Is it maybe easier to port the application to androids own usb library? 将应用程序移植到android自己的usb库也许更容易?

Libusb can work on a non-rooted android (provided the device supports USB host ... this is VERY important as not all devices do). Libusb可以在非root用户的android上运行(前提是该设备支持USB主机...这非常重要,因为并非所有设备都支持)。 You need to use the standard android USB stack. 您需要使用标准的android USB堆栈。 You can then get a device descriptor from the USBDevice and pass that over to libusb. 然后,您可以从USBDevice获取设备描述符,并将其传递给libusb。

Unfortunately you also need to modify libusb. 不幸的是,您还需要修改libusb。 Fortunately other people have explained how you need to modify LibUSB. 幸运的是,其他人已经解释了如何修改LibUSB。

LibUSB has been modified here . LibUSB在这里已被修改。

Good luck! 祝好运!

Edit : 编辑

First you need to define a broadcast receiver: 首先,您需要定义一个广播接收器:

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

Now you need to create a USBManager and enumerate the devices: 现在,您需要创建一个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.
        }
    }

Edit 2 : 编辑2

Getting libusb to build is just a matter of putting the files somewhere handy (I put them in jni/libusb) and then adding the following lines to your Android.mk: 建立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)

The solution I implemented is to open the USB device using the Java APIs and then using the file descriptor with libusb.I used libusb from openni project by primesense( https://github.com/OpenNI/OpenNI2 ) 我实现的解决方案是使用Java API打开USB设备,然后将文件描述符与libusb一起使用。我通过primesense( https://github.com/OpenNI/OpenNI2 )从openni项目中使用libusb。

Code bits: 代码位:

Opening the device(Using swig): 打开设备(使用swig):

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

Opening the device in JAVA code(Not running on main thread!): 用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;
    }

Permission handling code: 权限处理代码:

private BroadcastReceiver mUsbPermissionReceiver=new BroadcastReceiver(){ 私人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);
                }
            }
        }
    }
}

}; };

Open function: 打开功能:

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 change(core.c): 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) change: 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);
}

Even if you get it compiled, Android is probably not going to let you access the USB device through libusb unless your device is rooted. 即使您将其编译,Android也可能不会允许您通过libusb访问USB设备,除非您的设备已植根。 If it is feasible to port your app to Android's native USB stack , that would almost certainly be a more stable solution. 如果将您的应用程序移植到Android的本地USB堆栈是可行 ,那几乎肯定是一个更稳定的解决方案。

You can also try to use android serial port api 您也可以尝试使用android串口API

Here is example of serial port 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);
}

So did it with use devices on USB host. USB主机上的使用设备也是如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM