简介
如何在Qt for Android中使用libusb, 其实libusb的文档里面都写的很清楚, 这里只是稍微做下整理。
libusb
libusb github源码
libusb release的版本, 有编译好的静态
步骤
1. 下载libusb
libusb v1.0.027 源码包
2. 整理提取libusb android使用源码
从编译文件 libusb-1.0.27\android\jni\libusb.mk 直到 android所需要的源文件和头文件, 做整理,编译时再看缺少哪些,补齐。
如下是我整理的, config.h 来自libusb-1.0.27\android目录
下面是libusb目录包含的文件
os目录包含的文件
libusb.pri
CCFLAG += -fvisibility=hidden -pthread
INCLUDEPATH += $$PWD
SOURCES += \
$$PWD/libusb/core.c \
$$PWD/libusb/descriptor.c \
$$PWD/libusb/hotplug.c \
$$PWD/libusb/io.c \
$$PWD/libusb/strerror.c \
$$PWD/libusb/sync.c \
$$PWD/os/events_posix.c \
$$PWD/os/linux_netlink.c \
$$PWD/os/linux_usbfs.c \
$$PWD/os/threads_posix.c
HEADERS += \
$$PWD/config.h \
$$PWD/libusb/libusb.h \
$$PWD/libusb/libusbi.h \
$$PWD/libusb/version.h \
$$PWD/libusb/version_nano.h \
$$PWD/os/events_posix.h \
$$PWD/os/linux_usbfs.h \
$$PWD/os/threads_posix.h
3. 创建Qt for Android 并 加入libusb
参考 Qt for android 获取USB设备列表(二)JNI方式 获取,
- 工程文件.pro 添加libusb支持
include ($$PWD/libusb/libusb.pri) - java代码支持, 用于获取usb权限
package usb;
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.io.IOException;
import android.content.pm.PackageManager;
import android.Manifest;
import android.content.Intent;
import android.app.PendingIntent;
import android.util.Log;
import android.os.Bundle;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
// import com.hoho.android.usbserial.driver.Ch34xSerialDriver;
// import com.hoho.android.usbserial.driver.UsbSerialPort;
public class USBListActivity extends org.qtproject.qt.android.bindings.QtActivity
{
private static USBListActivity instance = null;
private static UsbManager usbManager = null;
// private static StorageManager storageManager = null;
private static String tag = "MainClass";
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
public USBListActivity()
{
instance = this;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
// storageManager = (UsbManager)getSystemService(Context.STORAGE_SERVICE);
Log.i(tag, "checkPermission: " + checkPermission());
// getDeviceList();
}
private boolean checkPermission() {
int readPermission = checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
int writePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
return readPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED;
}
public static boolean requestUSBPermission(String portName)
{
if (portName.isEmpty())
{
Log.i(tag, "port empty");
return false;
}
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
UsbDevice device = null;
for (Map.Entry<String, UsbDevice> entry : deviceList.entrySet())
{
if (portName.equals(entry.getKey()))
{
device = entry.getValue();
break;
}
}
if (device == null)
{
Log.i(tag, "device not exists");
return false;
}
if (!usbManager.hasPermission(device))
{
Intent permissionIntent = new Intent(ACTION_USB_PERMISSION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(instance,
0,
permissionIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
usbManager.requestPermission(device, pendingIntent);
if (!usbManager.hasPermission(device))
{
Log.i(tag, "permission denied");
return false;
}
}
// UsbDeviceConnection deviceConnection = usbManager.openDevice(device);
// if (null == deviceConnection)
// {
// Log.i(tag, "fail to open device");
// return false;
// }
return true;
}
public void getDeviceList()
{
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
System.out.println("------------------------->GetDeviceList<-------------------------");
deviceList.forEach((key, value) -> {
System.out.println("------------------------->" + key + "<-------------------------");
System.out.println(value);
System.out.println("<-------------------------" + key + "------------------------->");
});
System.out.println("<-------------------------GetDeviceList------------------------->");
}
}
-
将libusb示例加入到Qt for android工程
将 libusb-1.0.27\android\examples 目录下的 unrooted_android.c和unrooted_android.h拷贝到Qt 项目中, 添加 -
Qt for Android通过JNI调用获取文件描述符并使用libusb打印usb设备信息
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "unrooted_android.h"
#include <QJniObject>
#include <QJniEnvironment>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->btnRefreshPortNames, &QPushButton::clicked,
this, [=]()
{
ui->cbPortNames->clear();
ui->cbPortNames->addItems(getSerialPorts());
});
connect(ui->btnTest, &QPushButton::clicked,
this, &MainWindow::test);
emit ui->btnRefreshPortNames->clicked(); // 借势初始化
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::logger(const QString &text)
{
ui->textEdit->append(text);
}
QList<QString> MainWindow::getSerialPorts()
{
QList<QString> names;
#ifdef Q_OS_ANDROID
QJniObject usbService = QJniObject::getStaticObjectField("android/content/Context",
"USB_SERVICE",
"Ljava/lang/String;");
if (!usbService.isValid())
{
logger("fail to get usb service");
return names;
}
QJniObject activity = QJniObject(QNativeInterface::QAndroidApplication::context());
QJniObject usbManager = activity.callObjectMethod("getSystemService",
"(Ljava/lang/String;)Ljava/lang/Object;",
usbService.object<jstring>());
if (!usbManager.isValid())
{
logger("fail to get usb manager");
return names;
}
QJniObject usbDeviceListHashMap = usbManager.callObjectMethod("getDeviceList",
"()Ljava/util/HashMap;");
QJniObject devListKeySet = usbDeviceListHashMap.callObjectMethod("keySet",
"()Ljava/util/Set;");
QJniObject devListIter = devListKeySet.callObjectMethod("iterator",
"()Ljava/util/Iterator;");
jint devListSize = usbDeviceListHashMap.callMethod<jint>("size", "()I");
QJniObject usbDevObj;
QJniObject usbDevObjIter;
int vid = 0, pid = 0;
QString devName;
for (int i = 0; i < devListSize; ++i)
{
usbDevObjIter = devListIter.callObjectMethod("next",
"()Ljava/lang/Object;");
usbDevObj = usbDeviceListHashMap.callObjectMethod("get",
"(Ljava/lang/Object;)Ljava/lang/Object;",
usbDevObjIter.object());
vid = usbDevObj.callMethod<jint>("getVendorId", "()I");
pid = usbDevObj.callMethod<jint>("getProductId", "()I");
devName = usbDevObj.callMethod<jstring>("getDeviceName", "()Ljava/lang/String;").toString();
logger(QString("Name: %1, VID: %2, PID: %3").arg(devName).arg(vid).arg(pid));
names.append(devName);
}
#else
for (QSerialPortInfo &info : QSerialPortInfo::availablePorts())
{
names.append(info.portName());
}
#endif
return names;
}
void MainWindow::test()
{
QJniObject str = QJniObject::fromString(ui->cbPortNames->currentText());
jboolean res = QJniObject::callStaticMethod<jboolean>(
"usb/USBListActivity",
"requestUSBPermission",
"(Ljava/lang/String;)Z",
str.object<jstring>());
if (!res)
{
logger("permission denied");
return;
}
QJniObject usbService = QJniObject::getStaticObjectField("android/content/Context",
"USB_SERVICE",
"Ljava/lang/String;");
if (!usbService.isValid())
{
logger("fail to get usb service");
return;
}
QJniObject activity = QJniObject(QNativeInterface::QAndroidApplication::context());
QJniObject usbManager = activity.callObjectMethod("getSystemService",
"(Ljava/lang/String;)Ljava/lang/Object;",
usbService.object<jstring>());
if (!usbManager.isValid())
{
logger("fail to get usb manager");
return;
}
QJniObject usbDeviceListHashMap = usbManager.callObjectMethod("getDeviceList",
"()Ljava/util/HashMap;");
QJniObject devListKeySet = usbDeviceListHashMap.callObjectMethod("keySet",
"()Ljava/util/Set;");
QJniObject devListIter = devListKeySet.callObjectMethod("iterator",
"()Ljava/util/Iterator;");
jint devListSize = usbDeviceListHashMap.callMethod<jint>("size", "()I");
QJniObject usbDevObj;
QJniObject usbDevObjIter;
QString devName;
QJniObject selectedUsbDevice;
for (int i = 0; i < devListSize; ++i)
{
usbDevObjIter = devListIter.callObjectMethod("next",
"()Ljava/lang/Object;");
usbDevObj = usbDeviceListHashMap.callObjectMethod("get",
"(Ljava/lang/Object;)Ljava/lang/Object;",
usbDevObjIter.object());
devName = usbDevObj.callMethod<jstring>("getDeviceName", "()Ljava/lang/String;").toString();
if (devName != ui->cbPortNames->currentText())
{
continue;
}
selectedUsbDevice = usbDevObj;
break;
}
if (!selectedUsbDevice.isValid())
{
logger("device not found");
return;
}
QJniObject usbConnection = usbManager.callObjectMethod("openDevice",
"(Landroid/hardware/usb/UsbDevice;)Landroid/hardware/usb/UsbDeviceConnection;",
selectedUsbDevice.object());
if (!usbConnection.isValid())
{
logger("fail to get usb connection");
return;
}
jint fd = usbConnection.callMethod<jint>("getFileDescriptor", "()I");
unrooted_usb_description(fd);
logger("libusb test finished7");
}
4. 手机接入OTG和USB设备
我这里接的是USB转TTL线
5. 测试
打印信息是
D LibUsb : Dev (bus 1, device 4): 1A86 - 7523 speed: 12M
D LibUsb : Product: USB2.0-Serial
D LibUsb : Configuration:
D LibUsb : wTotalLength: 39
D LibUsb : bNumInterfaces: 1
D LibUsb : bConfigurationValue: 1
D LibUsb : iConfiguration: 0
D LibUsb : bmAttributes: 80h
D LibUsb : MaxPower: 48
D LibUsb : Interface:
D LibUsb : bInterfaceNumber: 0
D LibUsb : bAlternateSetting: 0
D LibUsb : bNumEndpoints: 3
D LibUsb : bInterfaceClass: 255
D LibUsb : bInterfaceSubClass: 1
D LibUsb : bInterfaceProtocol: 2
D LibUsb : iInterface: 0
D LibUsb : Endpoint:
D LibUsb : bEndpointAddress: 82h
D LibUsb : bmAttributes: 02h
D LibUsb : wMaxPacketSize: 32
D LibUsb : bInterval: 0
D LibUsb : bRefresh: 0
D LibUsb : bSynchAddress: 0
D LibUsb : Endpoint:
D LibUsb : bEndpointAddress: 02h
D LibUsb : bmAttributes: 02h
D LibUsb : wMaxPacketSize: 32
D LibUsb : bInterval: 0
D LibUsb : bRefresh: 0
D LibUsb : bSynchAddress: 0
D LibUsb : Endpoint:
D LibUsb : bEndpointAddress: 81h
D LibUsb : bmAttributes: 03h
D LibUsb : wMaxPacketSize: 8
D LibUsb : bInterval: 1
D LibUsb : bRefresh: 0
D LibUsb : bSynchAddress: 0
代码
基本代码都提供了, 没必要下载
libusb在Qt for android中的调用