NDK级别的Android上的低级USB API,可在Qt Android上使用 [英] Low-level USB API on Android at NDK level to use on Qt Android

查看:88
本文介绍了NDK级别的Android上的低级USB API,可在Qt Android上使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要与Android上的HID设备进行交互.问题是我使用的是Qt Android,而我使用的不是Java UsbManager类.

I need to interact with an HID device on Android. The problem is that i'm using Qt Android, and i'm not using Java UsbManager classes.

是否可以链接任何C库,以便与Android上的HID设备通信而无需使用Java API?

Is there any C lib which I can link against in order to communicate with an HID device on Android without having to work with the Java API?

我发现了这一点

http://source.android.com/devices/reference/bt__hh_8h_source.html

哪个似乎是定义HID通信的标头,但我找不到关联的库.有什么想法吗?

Which seems to be an header that defines HID communication but I can't find the associated lib. Any ideas?

预先感谢

推荐答案

我找到了一种方法.就我而言,我正在为设备开发控制面板,我需要它在每个设备上都能正常工作而无需植根设备.

I have found a way of doing this. In my case, i'm developing a control panel for a device and I need it to work on every device without having the device rooted.

基本上,我正在使用UsbManager查找并抓取设备.然后,我打开设备并从UsbDeviceConnection调用getFileDescriptor()方法.然后,我将此int传递给本机代码端.从那里,我可以使用任何类型的请求轻松地从设备获取数据,而不必通过JNI将数据从本机代码传递到Java,反之亦然.

Basically I'm using UsbManager to find and grab the device. I then open the device and call getFileDescriptor() method from UsbDeviceConnection. I then pass this int to the native code side. From there I can easily obtain data from the device using any kind of requests without having to pass data from native code to java and vice versa thru JNI which is slow and slow dying work.

最棘手的部分实际上是在进行ioctl调用,它需要具有特殊的格式.

The most tricky part is actually doing the ioctl calls which need to have a special format.

在libusb源代码中已经很好地举例说明了部分代码,因为这是它们实现对Linux内核的libsub调用的方式.

Part of this codes are already well exemplified on libusb source code since it's the way they implement libsub calls to linux kernel.

如果有人知道更好的解决方案,请告诉我.

If anyone knows an even better solution to this problem just let me know.

带有USBManager挂钩的Android活动代码:

Android activity code with USBManager hooking:

public class MyActivity extends QtActivity
{
    private static MyActivity m_instance;
    private UsbAccessory accessory;
    private String TAG = "TAG";
    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
    private PendingIntent mPermissionIntent;
    private UsbManager manager;
    private UsbDeviceConnection connection;
    private HashMap<Integer, Integer> connectedDevices;

    public MyActivity()
    {
        m_instance = this;

        connectedDevices = new HashMap<Integer, Integer>();
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        manager = (UsbManager) getSystemService(Context.USB_SERVICE);

        registerReceiver(usbManagerBroadcastReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED));
        registerReceiver(usbManagerBroadcastReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
        registerReceiver(usbManagerBroadcastReceiver, new IntentFilter(ACTION_USB_PERMISSION));

        mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);

        final Handler handler = new Handler();

        handler.postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                checkForDevices();
            }
        }, 1000);
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);
    }

    private static native void notifyDeviceAttached(int fd);
    private static native void notifyDeviceDetached(int fd);

    private final BroadcastReceiver usbManagerBroadcastReceiver = new BroadcastReceiver()
    {
        public void onReceive(Context context, Intent intent)
        {
            try
            {
                String action = intent.getAction();

                Log.d(TAG, "INTENT ACTION: " + action);

                if (ACTION_USB_PERMISSION.equals(action))
                {
                    Log.d(TAG, "onUsbPermission");

                    synchronized (this)
                    {
                        UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
                        {
                            if(device != null)
                            {
                                int fd = connectToDevice(device);
                                Log.d(TAG,"device file descriptor: " + fd);
                                notifyDeviceAttached(fd);
                            }
                        }
                        else
                        {
                            Log.d(TAG, "permission denied for device " + device);
                        }
                    }
                }

                if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action))
                {
                    Log.d(TAG, "onDeviceConnected");

                    synchronized(this)
                    {
                        UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                        if (device != null)
                        {
                            manager.requestPermission(device, mPermissionIntent);
                        }
                    }
                }

                if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action))
                {
                    Log.d(TAG, "onDeviceDisconnected");

                    synchronized(this)
                    {
                        UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                        int fd = connectedDevices.get(device.getDeviceId());

                        Log.d(TAG, "device: " + device.getDeviceId() + " disconnected. fd: " + fd);

                        notifyDeviceDetached(fd);

                        connectedDevices.remove(device.getDeviceId());
                    }
                }
            }
            catch(Exception e)
            {
                Log.d(TAG, "Exception: " + e);
            }
        }
    };

    private int connectToDevice(UsbDevice device)
    {
        connection = manager.openDevice(device);
        // if we make this, kernel driver will be disconnected
        connection.claimInterface(device.getInterface(0), true);

        Log.d(TAG, "inserting device with id: " + device.getDeviceId() + " and file descriptor: " + connection.getFileDescriptor());
        connectedDevices.put(device.getDeviceId(), connection.getFileDescriptor());

        return connection.getFileDescriptor();
    }

    private void checkForDevices()
    {
        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();

        while(deviceIterator.hasNext())
        {
            UsbDevice device = deviceIterator.next();

            if (device.getVendorId()==VID && device.getProductId()==PID)
            {
                Log.d(TAG, "Found a device: " + device);

                manager.requestPermission(device, mPermissionIntent);
            }
        }
    }
}

连接或断开具有所需VID和PID的设备时,将调用本机调用notifyDeviceAttached(int fd)和notifyDeviceDetached(int fd),将设备的文件描述符发送到本机端.在我的情况下,我实例化了一个类型为Device的类.此时,设备已经打开,您可以开始对其进行呼叫.在Linux中,您像libusb一样进行ioctl调用.您可以在下面看到有关getFeature和setFeature的代码.如果您除此以外还需要其他任何东西,可以查看libusb源代码.

When the device with the wished VID and PID is connected or disconnected the native calls notifyDeviceAttached(int fd) and notifyDeviceDetached(int fd) are called sending the file descriptor of the device to the native side. In my case I instantiate a class of type Device. At this point the device is already open and you can start doing calls to it. In Linux you make ioctl calls just like libusb does. You can see the code below for getFeature and setFeature. If you need anything else than this you can look at libusb source code.

C ++本机辅助代码:

C++ native side code:

#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>

#include <QDebug>
#include <QElapsedTimer>

static inline uint16_t cpu_to_le16(const uint16_t x)
{
    union
    {
        uint8_t  b8[2];
        uint16_t b16;
    } _tmp;

    _tmp.b8[1] = (uint8_t) (x >> 8);
    _tmp.b8[0] = (uint8_t) (x & 0xff);

    return _tmp.b16;
}

struct usbdevfs_ctrltransfer
{
    unsigned char bRequestType;
    unsigned char bRequest;
    unsigned short wValue;
    unsigned short wIndex;
    unsigned short wLength;
    unsigned int timeout;
    void *data;
};

Device::Device(int fileDescriptor, QObject *parent) :
    fd(fileDescriptor)
{
}

int Device::getFeature(unsigned char reportId, unsigned char *buffer, int length)
{
    struct usbdevfs_ctrltransfer data;

    data.bRequestType = (0x01 << 5)|0x01|0x80;
    data.bRequest = 0x01;
    data.wValue = cpu_to_le16((3 << 8) | reportId);
    data.wIndex = cpu_to_le16(0);
    data.wLength = cpu_to_le16(length);
    data.data = buffer;
    data.timeout = 1000;

    int res = ioctl(fd, _IOWR('U', 0, struct usbdevfs_ctrltransfer), &data);

    if (res<0)
    {
        qDebug() << "error: " << strerror(errno);
    }

    return res;
}

int Device::setFeature(unsigned char reportId, unsigned char *buffer, int length)
{
    struct usbdevfs_ctrltransfer data;

    data.bRequestType = (0x01 << 5)|0x01|0x00;
    data.bRequest = 0x09;
    data.wValue = cpu_to_le16((3 << 8) | reportId);
    data.wIndex = cpu_to_le16(0);
    data.wLength = cpu_to_le16(length);
    data.data = buffer;
    data.timeout = 1000;

    int res = ioctl(fd, _IOWR('U', 0, struct usbdevfs_ctrltransfer), &data);

    if (res<0)
    {
        qDebug() << "error: " << strerror(errno);
    }

    return res;
}

此致

努诺·桑托斯(Nuno Santos)

Nuno Santos

这篇关于NDK级别的Android上的低级USB API,可在Qt Android上使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆