日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

libusb开发指南

發布時間:2023/12/15 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libusb开发指南 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

libusb學習筆記

ubuntu版本:ubuntu-gnome-16.04-desktop-amd64,gnome版
libusb版本 :2016-10-01: v1.0.21
作者:wang baoli
E-mail: baoliw@foxmail.com

libusb學習網站:

website:http://libusb.info/
API:http://libusb.sourceforge.net/api-1.0/
download:https://github.com/libusb/libusb
mailing list:http://mailing-list.libusb.info
libusb test demo:https://github.com/crazybaoli/libusb-test

1. 編譯及安裝

下載libusb源碼,進入目錄,shell下依次執行下列命令。

1.1 執行:./configure

提示:configure: error: “udev support requested but libudev not installed”
解決:

sudo apt-get install libudev-dev

1.2 執行:make

提示:‘aclocal-1.14’ is missing on your system.
解決:

  • sudo apt-get install automake
  • sudo apt-get install libtool
  • sudo autoreconf -ivf
  • make
  • 1.3 安裝:make install

    執行:sudo make install
    libusb-1.0.a 和 libusb-1.0.so 被安裝到 /usr/local/lib/ 目錄
    libusb.h 被安裝到 /usr/local/include/libusb-1.0/ 目錄

    注:在這以后可以直接執行:./configure && make && make install

    2. 源碼學習

    libusb采用的linux技術:sysfs、libudev、netlink、pipe、thread、hotplug

    2.1 目錄分析

    tests/

    關于libusb的四個壓力測試,不涉USB打開操作及具體的數據傳輸。

    android/

    用于生成Android版本的libusb庫、test和examples。進入android/jni/,執行ndk_build即可。在android/README中有以下描述:

  • Download the latest NDK from: http://developer.android.com/tools/sdk/ndk/index.html
  • Extract the NDK.
  • Open a shell and make sure there exist an NDK global variable, set to the directory where you extracted the NDK.
  • Change directory to libusb’s “android/jni”
  • Run “ndk-build”.
  • The libusb library, examples and tests can then be found in:“android/libs/$ARCH”
  • doc/

    用于生成軟件接口文檔。編譯完工程后,打開doc/doxygen.cfg,將PROJECT_LOGO = libusb.png修改為PROJECT_LOGO = ,否則產生文檔時會提示 libusb.png不存在,修改完成后在doc/目錄下執行:doxygen doxygen.cfg即可生成html格式文檔,或者執行make docs。
    注:Ubuntu需要提前安裝doxygen。

    libusb/

    libusb的核心代碼。
    1)os/目錄是是平臺相關的代碼,支持:darwin、haiku、linux、windows、sunos、netbsd、openbsd等七種平臺,即Linux, OS X, Windows, Windows CE, Android, OpenBSD/NetBSD, Haiku。
    2)libusb-1.0.def DLL中導出函數的聲明的一種方式:采用模塊定義(.def) 文件聲明,.def文件為鏈接器提供了有關被鏈接程序的導出、屬性及其他方面的信息。
    3)libusb-1.0.rc 用于windows,產生 .res文件。

    msvc/

    微軟VC編譯環境,目錄下均是windows平臺環境相關文件。

    m4/

    linux編譯相關。m4 是一種宏處理器,它掃描用戶輸入的文本并將其輸出,期間如果遇到宏就將其展開后輸出。

    Xcode/

    apple平臺相關文件。Xcode是蘋果的集成開發環境(IDE),開發者可用其構建適用于蘋果iPad、iPhone以及Mac設備的應用程序。在應用程序的創建、測試、優化以及提交至App Store的過程中,Xcode為開發者提供了用以管理整個開發工作流的工具。

    examples/

    libusb的測試demo,進入目錄后執行make即可生成可執行文件進行測試。

    1)getopt/

    getopt現在已經是C函數庫的一部分,沒有編譯使用,刪除此目錄不會有影響。

    2)hotplugtest.c

    熱插拔測試demo

    3)listdevs.c

    獲取系統當前的usb設備列表,并打印出VID、PID、bus和device編號

    4)testlibusb.c

    打印usb設備列表的詳細信息:包括設備描述符、配置、接口、端點描述符

    5)dpfp.c

    一款指紋識別器的應用程序:URU4000B fingerprint scanner 應用程序,將采集到的指紋圖像保存為文件。系統采用異步傳輸的方式,使用了control、interrupt、bulk三種傳輸方式。不僅使用了libusb_control_transfer等同步接口傳輸,也使用了libusb_submit_transfer的異步傳輸方式。

    6)dpfp_threaded.c

    與dpfp.c功能一致,代碼也大部分相同,唯一不同在于dpfp.c將libusb_handle_events 放在 main loop中,而dpfp_threaded.c 將libusb_handle_events 放在一個線程當中。

    7)sam3u_benchmark.c

    Atmel SAM3U isochronous(等時傳輸)性能測試。程序不斷接收來自SAM3U iso端點的數據,當按下CTRL-C時,計算花費時間和傳輸的總數據量。

    8)xusb.c

    一個綜合的USB測試程序,包括:HID設備(xbox、PS3和Joystick)、Mass Storage,涉及中斷、批量和控制傳輸。其中Mass Storage可以使用普通的U盤進行測試,只需修改VID和PID即可,可以實現的功能有:讀取描述符、查詢U盤信息、讀取U盤容量、讀取U盤數據(因為沒有使用文件系統,讀取出來的數據是原始二進制數據)。
    關于Mass Storage中涉及的SCSI命令,參考: USB Mass Stroage - SCSI指令格式詳解。

    9)fxload.c和ezusb.c

    EZ-USB的固件下載程序,可實現下載固件(image)到Cypress EZ-USB microcontrollers,ezusb系列芯片使用端點0和廠商特定命令將數據寫到片上SRAM,并且也支持寫數據到CPUCS register或者eeprom。
    程序使用控制傳輸方式進行指令和數據的傳輸,libusb_control_transfer()的形參bmRequestType使用LIBUSB_REQUEST_TYPE_VENDOR(廠商自定義請求)。程序支持五種下載類型(Target type): an21, fx, fx2, fx2lp, fx3,支持四種固件(image)類型:“Intel HEX”, “Cypress 8051 IIC”, “Cypress 8051 BIX”, “Cypress IMG format”。

    10)other

    ChangeLog:代碼修改日志。2008-05-25: v0.9.0 release,目前最新版2016-10-01: v1.0.21
    INSTALL:編譯、安裝方法。編譯器選項,如: ./configure CC=c99 CFLAGS=-g LIBS=-lposix
    PORTING:移植libusb到其他未支持平臺的方法。

    注:

  • Atmel SAM3U:基于ARM Cortex M3內核的MCU,支持usb high speed。
  • 關于ezusb的介紹:
    http://www.linux-usb.org/ezusb/
    http://www.cypress.com/
    EZ-USB FX是CYPRESS公司出品的一種帶有USB功能的8051兼容系列,封裝采用PQFP。這一系列芯片的最大不同之處在于使用不同的方式存儲固件,EZ-USB FX可以在一個串行EEPROM中存儲固件,也可以在主機上存儲固件。當設備連接主機后,這些固件通過USB總線傳輸到芯片中。這樣做最大的好處就是固件容易升級,不需要替換芯片或使用特殊的程序,只要在主機上更新固件即可。
    CY7C61083A是一款FX2LP芯片,支持full/high speed,應用:MP3、讀卡器、照相機等等
  • 2.2 權限問題

    當open USB時需要提供root權限,這同打開串口一樣,對底層硬件操作都需要root權限。

    2.3 函數調用圖

    如果能繪制出函數調用關系圖會更有利于分析代碼。可以采用callfraph,但有些具有特殊返回值的函數不能被識別,并且不能跨文件尋找調用關系(可能是我沒有正確的使用)。可以直接采用dot語言手動繪圖。

    2.4 log

    2.4.1 修改log輸出

    libusb 日志默認輸出到stderr,如果我們想輸出libusb 的log至syslog,有以下兩種方法:
    方法1:./configure --enable-system-log
    修改結果會反饋在./config.h中,增加了USE_SYSTEM_LOGGING_FACILITY宏
    查看syslog:cat /var/log/syslog

    Nov 22 09:51:07 ubuntu libusb-test: libusb: error [_get_usbfs_fd] libusb couldn’t open USB device /dev/bus/usb/002/018: Permission denied.

    方法2:./configure CFLAGS=-DUSE_SYSTEM_LOGGING_FACILITY=1
    或者:CFLAGS=-DUSE_SYSTEM_LOGGING_FACILITY=1 ./configure
    修改結果反饋在./Makefile文件中,使CFLAGS = -DUSE_SYSTEM_LOGGING_FACILITY=1,這會覆蓋原來的cflags 。
    當然,也可在執行./configure后,直接修改Makefile中的cflags選項。
    推薦采用方法1.
    注:可以使用 ./configur --help 來獲取–enable-system-log類似的選項

    2.4.2 設置debug level

    using libusb_set_debug() or the LIBUSB_DEBUG environment variable

    除了可以使用libusb_set_debug()函數,也可以通過環境變量LIBUSB_DEBUG 來設置debug level。

    2.5 open

    USB設備文件對應路徑為:“/dev/bus/usb/xxx/xxx”,使用了udev文件系統。
    libusb通過打開設備文件:/dev/bus/usb/bus編號/device地址 來打開USB,stm32 USB device 對應/dev/bus/usb/002/020。可以使用lsusb來查看bus和device地址。
    libusb優先使用udev文件系統打開usb設備,其次選擇usbfs文件系統:/proc/bus/usb/來打開usb設備。Linux2.6采用了usbfs文件系統:/proc/bus/usb,在Ubuntu16.4上沒有usbfs。
    分析代碼可知:

    static const char *find_usbfs_path(void) {const char *path = "/dev/bus/usb";const char *ret = NULL;if (check_usb_vfs(path)) {ret = path;} else {path = "/proc/bus/usb";if (check_usb_vfs(path))ret = path;}/* look for /dev/usbdev*.* if the normal places fail */if (ret == NULL) {struct dirent *entry;DIR *dir;path = "/dev";dir = opendir(path);if (dir != NULL) {while ((entry = readdir(dir)) != NULL) {if (_is_usbdev_entry(entry, NULL, NULL)) {/* found one; that's enough */ret = path;usbdev_names = 1;break;}}closedir(dir);}}#if defined(USE_UDEV)if (ret == NULL)ret = "/dev/bus/usb"; #endifif (ret != NULL)usbi_dbg("found usbfs at %s", ret);return ret; }

    stm32設備在linux sysfs文件系統的路徑: /sys/bus/usb/devices/2-2.1,由內核向用戶空間導出設備的數據結構及屬性,可以修改和訪問。libusb中有大量通過sysfs來獲得usb設備屬性的用法,如獲取usb 速度:
    speed = (DEVICE_CTX(dev), sysfs_dir, "speed");
    我們也可以使用 cat /sys/bus/usb/devices/2-2.1/speed 來獲取usb速度。
    由于目錄/sys/bus/usb/devices/經常被使用,在libusb源碼中有以下宏定義:
    #define SYSFS_DEVICE_PATH "/sys/bus/usb/devices"

    2.6 結構體亂序初始化

    linux結構體可以采用亂序初始化,即用成員變量前加(.)符號,如定義linux_usbfs_backend 結構體變量時就采用了這種方法:

    const struct usbi_os_backend linux_usbfs_backend = {.name = "Linux usbfs",.caps = .init = op_init,.exit = op_exit,.get_device_list = NULL,..... }

    亂序初始化是C99標準新加的,比較直觀的一種初始化方式。相比順序初始化而言,亂序初始化就如其名,成員可以不按照順序初始化,而且可以只初始化部分成員,擴展性較好。linux內核中采用這種方式初始化struct。

    2.7 數據傳輸

    libusb的數據傳輸通過向內核提交URB來實現:
    ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
    而非使用read、write等讀寫函數。

    2.8 hotplug

    libusb的熱插拔事件有兩種:arrived 、left。
    hotplug事件的底層支持機制:udev或者netlink,udev的熱插拔機制是基于netlink實現。
    libusb對于產生的熱插拔消息在handle_events()中進行處理,然后調用用戶注冊的回調函數。
    libusb內部專門開辟了一個線程來監聽是否有USB設備插拔,并通過netlink或是udev兩種方式來實現監聽hotplug。優先采取udev方式,當系統不支持udev時,便采用netlink方式。其實udev的熱插拔機制也是基于netlink實現。
    實現原理:
    當libusb在熱插拔監聽線程(linux_udev_event_thread_main or linux_netlink_event_thread_main)中接收到內核的hotplug消息,libusb首先將消息添加到ctx->hotplug_msgs中,然后在通過管道(ctx->event_pipe)將hotplug事件發送出去。在用戶創建的monitor線程里,調用libusb_handle_events()進行事件處理,具體做法是調用poll監聽管道,一旦ctx->event_pipe[0]可讀,便讀取hotplug_msgs,經過usbi_hotplug_match_cb()函數判斷VID、PID以及device class符合后再調用用戶的回調函數。
    注:同一個進程中也可以使用管道進行通信。

    2.9 LIST

    libusb實現了循環雙向鏈表,并且只有前向和后向指針,無數據成員,實現方法上也很獨特。應用時作為其它數據結構的成員,可通過list_entry宏來獲得這個數據結構指針。

    struct list_head {struct list_head *prev, *next; };

    void list_init(struct list_head *entry)
    初始化一個鏈表

    void list_add_tail(struct list_head *entry, struct list_head *head)
    list_add_tail和list_add都是形成雙向循環鏈表,只是實現上有一點不同而已。
    將節點entry添加到鏈表head的尾部,使head->prev指向entry,(head->next固定指向了鏈表中的第二個節點)

    void list_add(struct list_head *entry, struct list_head *head)
    將節點entry添加到鏈表head的尾部,使head->next指向entry,(head->prev固定指向了鏈表中的第二個節點)

    void list_del(struct list_head *entry)
    刪除一個鏈表

    list_empty(entry)
    判斷鏈表是否為空

    list_entry(ptr, type, member)
    取得包含ptr所指結構體的對象的指針:返回type類型指針,這個type類型指針指向的對象包含這個節點。

    ptr:list_head 結構體指針
    type:包含member成員的數據類型
    member:type數據類型里的成員,member為list_head類型

    list_for_each_entry(pos, head, member, type)
    遍歷head鏈表中的每個節點(entry),pos指向每次遍歷的結果。pos為type類型結構體指針,這個結構體包含list_head 結構體成員。

    pos:一個包含member成員的結構體指針
    head:list head
    member:pos指針指向的結構體里的list_head 結構體成員
    type:pos的數據類型

    2.10 獲取USB設備列表

    用戶使用ssize_t libusb_get_device_list(libusb_context *ctx, libusb_device ***list)函數即可獲得系統當前所有的USB設備。
    libusb將接入的usb設備都保存在ctx->usb_devs鏈表中,libusb_get_device_list函數便是通過它來取得設備列表。
    libusb通過三種途徑來維護ctx->usb_devs鏈表(這里主要指添加設備)。

  • 調用libusb_init初始化時,libusb調用linux_scan_devices獲取系統當前所有usb設備,并將其添加到ctx->usb_devs鏈表。
  • 在hotplug監聽線程中,如果有設備插入,便將其添加到ctx->usb_devs鏈表。
  • 用戶調用libusb_get_device_list時,再一次查看是否有新設備插入,如果有便將其添加到ctx->usb_devs鏈表。
  • 2.11 控制傳輸

    用戶可以使用libusb_control_transfer() 進行控制傳輸。
    控制傳輸既可以在系統枚舉階段進行,也可以在打開USB設備后進行傳輸,如在xusb.c中便有很多地方用到了控制傳輸:獲取HID設備的報告描述符等。

    2.12 頭文件說明

    (1)宏定義_MSC_VER

    _MSC_VER是微軟的預編譯控制,由于vc++不支持stdbool.h,所以有某些頭文件有以下代碼以便支持bool變量。

    #if !defined(_MSC_VER) #include <stdbool.h> #else #define __attribute__(x) #if !defined(bool) #define bool int #endif #if !defined(true) #define true (1 == 1) #endif #if !defined(false) #define false (!true) #endif #if defined(_PREFAST_) #pragma warning(disable:28193) #endif #endif

    (2) C++支持

    為了在C++代碼支持libusb庫,在頭文件中可見以下代碼:

    #ifdef __cplusplus extern "C" { #endif// 代碼#ifdef __cplusplus } #endif

    (3)條件編譯的使用

    #if, #elif, #else, #endif #if defined()和#if !defined()

    2.13 其它

    宏定義_WIN32

    VC 有 3 個預處理常量,分別是 _WIN32、_WIN64、WIN32,WIN32和_WIN32 可以用來判斷是否 Windows 系統(對于跨平臺程序),而 _WIN64 用來判斷編譯環境是 x86 還是 x64。

    3. libusb測試demo

    github:https://github.com/crazybaoli/libusb-test

    • 支持bulk/interrupt endpoint 數據讀寫
    • 支持hotplug
    • 支持命令行參數
    • 支持快捷發送數據
    • 支持將收到的數據保存為文件
    • 支持lsusb功能,可列出系統所有usb設備
    • 支持打印顯示特定usb設備(VID:PID)的描述符

    總結

    以上是生活随笔為你收集整理的libusb开发指南的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。