在 QT 中使用 libusb 检测 MAC 上的 USB 设备
2016-01-27 08:44
627 查看
最近在用 QT 做一个 MAC 上的 Kindle 批注管理软件,遇到的第一个问题就是检测 MAC 上连接的 USB 设备的状态。如果是在 Cocoa 进行开发,会有对应的系统 API 可供使用,但是由于我是在 QT 平台进行的开发,所以无形中加大了一点难度。就在这时,我发现了一个库:libusb
这时就已经在机器上编译安装完成了 libusb
然后我们看到在
listdevs:列出当前所有的 USB 设备
hotplugtest:USB 热插拔测试
dpfp_threaded:操作 U.are.U 4000b 指纹采集仪的 Demo
dpfp:初始化 U.are.U 4000b 指纹采集仪
sam3u_benchmark:测试 Atmel SAM3U USB 主控的同步传输的性能的 Demo
fxload:USB 固件操作
xusb:USB 测试程序
我们以
执行结果:
由于Windows、MAC和Linux的平台不同(主要是编译器、汇编器和连接器的不同),因此二者库的二进制是不兼容的。
Linux下的库有两种:静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
hello.c
main.c
gcc 中
我们执行
创建静态库用ar命令。
静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。
例如:我们将创建的静态库名为hello,则静态库文件名就是libhello.a。在创建和使用静态库时,需要注意这点。
我们执行
只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。
注意,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件,因此,我们在写需要连接的库时,只写名字就可以,如libhello.a的库,只写:
执行程序
我们使用
执行程序
将 libusb 对应的库文件复制到该目录下,因为我所使用的平台是 MAC OS X,所对应的库文件应当是以
并且将 libusb 的头文件
getusbinfo.cpp
main.cpp
最终我们获得了当前 MAC 上的 USB 设备列表
本文的版权归作者 罗远航 所有,采用 Attribution-NonCommercial 3.0 License。任何人可以进行转载、分享,但不可在未经允许的情况下用于商业用途;转载请注明出处。感谢配合!
libusb 介绍
libusb 设计了一系列的外部API 为应用程序所调用,通过这些API应用程序可以操作硬件,从libusb的源代码可以看出,这些API 调用了内核的底层接口,和kernel driver中所用到的函数所实现的功能差不多,只是libusb更加接近USB 规范。使得libusb的使用也比开发内核驱动相对容易的多。(From: 百度百科)0x00 下载 libusb
在 libusb 项目主页(http://libusb.info)我们可以找到最新的源码,下载下来,并且解压。这里我下载的是 libusb-1.0.20.tar.bz2,把它解压出来。0x01 安装 libusb
[code]cd libusb-1.0.20/ ./configure make make install
这时就已经在机器上编译安装完成了 libusb
0x02 运行示例程序
[code]cd examples/ make
然后我们看到在
examples/目录下多了几个可执行程序:
listdevs:列出当前所有的 USB 设备
hotplugtest:USB 热插拔测试
dpfp_threaded:操作 U.are.U 4000b 指纹采集仪的 Demo
dpfp:初始化 U.are.U 4000b 指纹采集仪
sam3u_benchmark:测试 Atmel SAM3U USB 主控的同步传输的性能的 Demo
fxload:USB 固件操作
[code]Usage: fxload [-v] [-V] [-t type] [-d vid:pid] [-p bus,addr] [-s loader] -i firmware -i <path> -- Firmware to upload -s <path> -- Second stage loader -t <type> -- Target type: an21, fx, fx2, fx2lp, fx3 -d <vid:pid> -- Target device, as an USB VID:PID -p <bus,addr> -- Target device, as a libusb bus number and device address path -v -- Increase verbosity -q -- Decrease verbosity (silent mode) -V -- Print program version
xusb:USB 测试程序
[code]usage: /Users/jason/Downloads/libusb-1.0.20/examples/.libs/xusb [-h] [-d] [-i] [-k] [-b file] [-l lang] [-j] [-x] [-s] [-p] [-w] [vid:pid] -h : display usage -d : enable debug output -i : print topology and speed info -j : test composite FTDI based JTAG device -k : test Mass Storage device -b file : dump Mass Storage data to file 'file' -p : test Sony PS3 SixAxis controller -s : test Microsoft Sidewinder Precision Pro (HID) -x : test Microsoft XBox Controller Type S -l lang : language to report errors in (ISO 639-1) -w : force the use of device requests when querying WCID descriptors If only the vid:pid is provided, xusb attempts to run the most appropriate test
我们以
listdevs为例,执行测试程序:
[code]./listdevs
执行结果:
[code]05ac:8406 (bus 20, device 3) path: 7 05ac:828f (bus 20, device 20) path: 3.3 0a5c:4500 (bus 20, device 27) path: 3 05ac:8005 (bus 20, device 0)
链接库
在Windows平台、MAC 平台和Linux平台下都大量存在着库。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于Windows、MAC和Linux的平台不同(主要是编译器、汇编器和连接器的不同),因此二者库的二进制是不兼容的。
Linux下的库有两种:静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
创建静态链接库
0x00 写一个静态链接库
hello.h[code]#ifndef HELLO_H #define HELLO_H void hello(const char *name); #endif
hello.c
[code]#include <stdio.h> void hello(const char *name) { printf("Hello %s!\n", name); }
main.c
[code]#include "hello.h" int main() { hello("world"); return 0; }
0x01 创建目标代码
[code]gcc -c hello.c
gcc 中
-c的编译选项的意思是使用GNU汇编器将源文件转化为目标代码之后就结束,在这种情况下,只调用了C编译器(ccl)和汇编器(as),而连接器(ld)并没有被执行,所以输出的目标文件不会包含作为程序在被装载和执行时所必须的包含信息,但它可以在以后被连接到一个程序。
我们执行
ls命令会看到目录下多了一个
hello.o文件,它就是
hello.c编译的目标代码
0x02 创建静态链接库
[code]ar rcs libhello.a hello.o
创建静态库用ar命令。
静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。
例如:我们将创建的静态库名为hello,则静态库文件名就是libhello.a。在创建和使用静态库时,需要注意这点。
我们执行
ls命令,可以看到目录下多了一个静态链接库
libhello.a
0x03 链接静态链接库
静态库***完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。
注意,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件,因此,我们在写需要连接的库时,只写名字就可以,如libhello.a的库,只写:
-lhello
[code]gcc -o main main.c -L. -lhello
执行程序
[code]./main Hello world!
创建动态链接库
0x00 创建动态链接库
[code]gcc -dynamiclib -o hello.dylib hello.o
我们使用
ls命令可以看到目录下多了
hello.dylib,它就是创建的动态链接库(.dylib是 MAC 系统下的,Windows 下是.dll, Linux 下是.so)
0x00 链接动态链接库
[code]gcc -o main1 main.c -L. -lhello
执行程序
[code]./main1 Hello world!
在 QT 中使用 libusb
0x00 将 libusb 动态链接库加入 QT 项目
我们首先在 QT5 中新建一个项目Testlibusb,然后在项目目录下新建一个目录
lib用来存放 libusb 的库文件。
将 libusb 对应的库文件复制到该目录下,因为我所使用的平台是 MAC OS X,所对应的库文件应当是以
.dylib为扩展名的,我们在 libusb 源码文件夹下的
/libusb/.libs/目录下找到
libusb-1.0.0.dylib然后复制到刚刚创建的目录下
并且将 libusb 的头文件
libusb.h加入到项目中
0x01 修改 QT 项目编译选项
修改 QT 项目中的.pro文件,加入下面几行:
[code]macx: LIBS += -L$$PWD/lib/ -lusb-1.0.0 INCLUDEPATH += $$PWD/. DEPENDPATH += $$PWD/.
0x02 编写 libusb 测试程序
getusbinfo.h[code]#ifndef GETUSBINFO #define GETUSBINFO #include <QString> #include <QObject> #include <QList> #include <QThread> #include <libusb.h> struct STUUSBDevices{ QString idProduct; QString idVendor; QString iManufacturer; QString iSerialNumber; }; class GetUsbInfo : QThread{ public: GetUsbInfo(QObject *parent); ~GetUsbInfo(); int initUsbDevices(); QString getVidPid(libusb_device **devs); void showAllUsbDevices(QList<STUUSBDevices> lst); void setRunStatus(); void run(); bool isStop; }; #endif // GETUSBINFO
getusbinfo.cpp
[code]#include "getusbinfo.h" #include <QThread> #include <QDebug> #include <QString> GetUsbInfo::GetUsbInfo(QObject *parent) : QThread(parent),isStop(false) { } GetUsbInfo::~GetUsbInfo() { qDebug()<<"GetUsbInfo::~GetUsbInfo "<<endl; } int GetUsbInfo::initUsbDevices() { libusb_device **devs; int r; ssize_t cnt; r = libusb_init(NULL); if (r < 0) return r; cnt = libusb_get_device_list(NULL, &devs); if (cnt < 0) return (int) cnt; getVidPid(devs); libusb_free_device_list(devs, 1); libusb_exit(NULL); return 0; } QString GetUsbInfo::getVidPid(libusb_device **devs) { libusb_device *dev; int i = 0; QList<STUUSBDevices> lstUsb; while ((dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { qDebug()<<"failed to get device descriptor"<<stderr; return ""; } printf("%04x:%04x (bus %d, device %d)\n", desc.idVendor, desc.idProduct, libusb_get_bus_number(dev), libusb_get_device_address(dev)); STUUSBDevices stu; stu.idProduct = QString::number(desc.idProduct); stu.idVendor = QString::number(desc.idVendor); stu.iManufacturer = QString::number(desc.iManufacturer); stu.iSerialNumber = QString::number(desc.iSerialNumber); lstUsb.append(stu); } showAllUsbDevices(lstUsb); return QString(lstUsb[0].idProduct); } void GetUsbInfo::showAllUsbDevices(QList<STUUSBDevices> lst) { for(int i=0;i<lst.count();i++) { qDebug()<<"vid: "<<lst.at(i).idVendor<<"\n" <<"pid:"<<lst.at(i).idProduct<<"\n" <<"serNumber:"<<lst.at(i).iSerialNumber<<"\n" <<"Manufacturer:"<<lst.at(i).iManufacturer<<"\n"; } } void GetUsbInfo::setRunStatus() { isStop = true; } void GetUsbInfo::run() { qDebug()<<"GetUsbInfo::run() "<<endl; while (!isStop) { initUsbDevices(); sleep(10); } }
main.cpp
[code]#include "mainwindow.h" #include <QApplication> #include "getusbinfo.h" #include <QLibrary> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); QThread t; GetUsbInfo info(&t); info.initUsbDevices(); return a.exec(); }
0x03 执行 libusb 测试程序
[code]Starting /Users/jason/Project/QTDemos/build-Testlibusb-Desktop_Qt_5_5_1_clang_64bit-Debug/Testlibusb.app/Contents/MacOS/Testlibusb... vid: "1452" pid: "33798" serNumber: "5" Manufacturer: "3" vid: "1452" pid: "33423" serNumber: "0" Manufacturer: "1" vid: "2652" pid: "17664" serNumber: "0" Manufacturer: "1" vid: "1452" pid: "32773" serNumber: "0" Manufacturer: "0"
最终我们获得了当前 MAC 上的 USB 设备列表
本文的版权归作者 罗远航 所有,采用 Attribution-NonCommercial 3.0 License。任何人可以进行转载、分享,但不可在未经允许的情况下用于商业用途;转载请注明出处。感谢配合!
相关文章推荐
- Qt之自定义界面(右下角冒泡)
- Qt之自定义界面(右下角冒泡)
- Qt(11):QT的绘制系统
- qt不能调试
- qt的多语言
- Qt之进程间通信(Windows消息)
- Qt之进程间通信(Windows消息)
- Qt之进程间通信(IPC)
- Qt之进程间通信(IPC)
- QTP之excel操作函数整理
- Qt学习笔记(一)
- Qt之设置窗口背景
- QT JS KindEditor 禁用超链接默认跳转功能
- TegraK1(ubuntu)上添加QtCreator并运行OpenCv
- 【Qt OpenGL】Qt Creator中的3D绘图及动画教程
- windows上 QtCreator调用OpenCv
- QT5使用消息机制及程序发布相关
- QT5自定义菜单
- QT5自定义界面(规则与不规则窗体)
- QT5中XML的解析(QXmlStreamReader)