Pemrograman dengan PyUSB 1.0

Dari penerjemah :
Ini adalah terjemahan dari manual Programming with PyUSB 1.0
Panduan ini ditulis oleh pengembang PyUSB, tetapi dengan cepat menjalankan komit, saya percaya walac adalah penulis utama.

Biarkan saya memperkenalkan diri


PyUSB 1.0 adalah pustaka Python yang menyediakan akses mudah ke USB . PyUSB menyediakan berbagai fungsi:

  • 100% ditulis dengan Python:
    Tidak seperti versi 0.x yang ditulis dalam C, versi 1.0 ditulis dengan Python. Ini memungkinkan programmer Python tanpa pengalaman C untuk lebih memahami cara kerja PyUSB.
  • Netralitas Platform:
    Versi 1.0 termasuk skema backend front-end. Ini mengisolasi API dari detail implementasi khusus sistem. Antarmuka IBackend menghubungkan dua lapisan ini. PyUSB hadir dengan backend bawaan untuk libusb 0.1, libusb 1.0, dan OpenUSB. Anda dapat menulis sendiri backend Anda jika Anda mau.
  • Portabilitas:
    PyUSB harus berjalan pada platform apa pun dengan Python> = 2.4, ctypes , dan setidaknya salah satu backend bawaan bawaan yang didukung.
  • Kesederhanaan:
    Interaksi dengan perangkat USB tidak pernah semudah ini! USB adalah protokol yang kompleks, dan PyUSB memiliki pengaturan awal yang baik untuk konfigurasi yang paling umum.
  • Dukungan gear isochronous:
    PyUSB mendukung transfer isochronous jika backend yang mendasarinya mendukungnya.

Meskipun PyUSB membuat pemrograman USB tidak terlalu menyakitkan, tutorial ini mengasumsikan bahwa Anda memiliki pengetahuan minimal tentang protokol USB. Jika Anda tidak tahu apa-apa tentang USB, saya sarankan buku Lengkap USB Jan Axelson yang sangat baik .

Cukup bicara, ayo tulis kodenya!


Siapa itu siapa?


Untuk memulai, mari berikan deskripsi modul PyUSB. Semua modul PyUSB berada di bawah usb , dengan modul-modul berikut:
ModulDeskripsi
intiModul USB utama.
utilFungsi bantu.
kontrolPermintaan manajemen standar.
warisanLapisan kompatibilitas versi 0.x.
backendSubpackage yang berisi backend bawaan.

Misalnya, untuk mengimpor modul inti , masukkan berikut ini:

>>> import usb.core >>> dev = usb.core.find() 

Baiklah, mari kita mulai


Berikut ini adalah program sederhana yang mengirimkan string 'tes' ke sumber data pertama yang ditemukan (endpoint OUT):

  import usb.core import usb.util #    dev = usb.core.find(idVendor=0xfffe, idProduct=0x0001) #   ? if dev is None: raise ValueError('Device not found') #   .  ,   #    dev.set_configuration() #    cfg = dev.get_active_configuration() intf = cfg[(0,0)] ep = usb.util.find_descriptor( intf, #     custom_match = \ lambda e: \ usb.util.endpoint_direction(e.bEndpointAddress) == \ usb.util.ENDPOINT_OUT) assert ep is not None #   ep.write('test') 

Dua baris pertama mengimpor modul paket PyUSB. usb.core adalah modul utama, dan usb.util berisi fungsi pembantu. Perintah berikut mencari perangkat kita dan mengembalikan instance objek jika ditemukan. Jika tidak, kembalikan Tidak Ada . Selanjutnya, kita atur konfigurasi yang akan kita gunakan. Catatan: tidak adanya argumen berarti bahwa konfigurasi yang diinginkan diatur secara default. Seperti yang akan Anda lihat, banyak fitur PyUSB memiliki pengaturan default untuk perangkat paling umum. Dalam hal ini, konfigurasi pertama yang ditemukan diatur.

Kemudian, kami mencari titik akhir di mana kami tertarik. Kami mencarinya di dalam antarmuka pertama yang kami miliki. Setelah kami menemukan titik ini, kami mengirim data ke sana.

Jika kita mengetahui alamat titik akhir sebelumnya, kita cukup memanggil fungsi tulis dari objek perangkat:

 dev.write(1, 'test') 

Di sini kita menulis string 'test' di breakpoint di alamat 1 . Semua fungsi ini akan dibahas lebih baik di bagian berikut.

Apa yang salah


Setiap fungsi di PyUSB melempar pengecualian jika terjadi kesalahan. Selain pengecualian Python standar , PyUSB mendefinisikan usb.core.USBError untuk kesalahan terkait USB.

Anda juga dapat menggunakan fungsi log PyUSB. Ini menggunakan modul logging . Untuk menggunakannya, tentukan variabel lingkungan PYUSB_DEBUG dengan salah satu level logging berikut: kritis , kesalahan , peringatan , info atau debug .

Secara default, pesan dikirim ke sys.stderr . Jika mau, Anda dapat mengalihkan pesan log ke file dengan mendefinisikan variabel lingkungan PYUSB_LOG_FILENAME . Jika nilainya adalah jalur yang benar ke file, pesan akan ditulis di sana, jika tidak maka akan dikirim ke sys.stderr .

Dimana kamu


Fungsi find () dalam modul inti digunakan untuk menemukan dan memberi nomor perangkat yang terpasang pada sistem. Misalnya, katakanlah perangkat kita memiliki ID vendor dengan nilai 0xfffe dan ID produk 0x0001. Jika kami perlu menemukan perangkat ini, kami akan melakukan ini:

 import usb.core dev = usb.core.find(idVendor=0xfffe, idProduct=0x0001) if dev is None: raise ValueError('Our device is not connected') 

Itu saja, fungsinya akan mengembalikan objek usb.core.Device yang mewakili perangkat kita. Jika perangkat tidak ditemukan, itu akan mengembalikan Tidak Ada . Bahkan, Anda bisa menggunakan bidang apa saja dari kelas Device Descriptor yang Anda inginkan. Misalnya, bagaimana jika kita ingin mencari tahu apakah ada printer USB yang terhubung ke sistem? Sangat mudah:

 #      ,   if usb.core.find(bDeviceClass=7) is None: raise ValueError('No printer found') 

7 adalah kode untuk kelas printer sesuai dengan spesifikasi USB. Oh, tunggu, bagaimana jika saya ingin memberi nomor semua printer yang tersedia? Tidak masalah:

 #     ... printers = usb.core.find(find_all=True, bDeviceClass=7) # Python 2, Python 3,     import sys sys.stdout.write('There are ' + len(printers) + ' in the system\n.') 

Apa yang terjadi Nah, waktu untuk sedikit penjelasan ... find memiliki parameter bernama find_all dan default ke False. Ketika itu salah [1] , find akan mengembalikan perangkat pertama yang cocok dengan kriteria yang ditentukan (kami akan segera membicarakannya). Jika Anda memberikan nilai sebenarnya ke parameter, find malah akan mengembalikan daftar semua perangkat yang cocok dengan kriteria. Itu saja! Sederhana bukan?

Apakah kita sudah selesai? Tidak! Saya belum memberi tahu semuanya: banyak perangkat yang benar-benar memasukkan informasi kelas mereka di Antarmuka Deskriptor daripada Descriptor Perangkat. Jadi untuk benar-benar menemukan semua printer yang terhubung ke sistem, kita harus melalui semua konfigurasi, serta semua antarmuka, dan memeriksa apakah salah satu antarmuka diatur ke bInterfaceClass 7. Jika Anda seorang programmer seperti saya, Anda mungkin bertanya-tanya: apakah ada cara yang lebih mudah untuk menerapkannya? Jawab: ya, benar. Untuk memulai, mari kita lihat kode yang sudah jadi untuk menemukan semua printer yang terhubung:

 import usb.core import usb.util import sys class find_class(object): def __init__(self, class_): self._class = class_ def __call__(self, device): #  ,   if device.bDeviceClass == self._class: return True # ,   ,   # ,     for cfg in device: # find_descriptor:  ? intf = usb.util.find_descriptor( cfg, bInterfaceClass=self._class ) if intf is not None: return True return False printers = usb.core.find(find_all=1, custom_match=find_class(7)) 

Parameter custom_match menerima objek yang dipanggil yang menerima objek perangkat. Ini harus mengembalikan true untuk perangkat yang sesuai dan false untuk yang tidak pantas. Anda juga dapat menggabungkan custom_match dengan bidang perangkat jika Anda ingin:

 #   ,    : printers = usb.core.find(find_all=1, custom_match=find_class(7), idVendor=0xfffe) 

Di sini kami tertarik pada printer dari pemasok 0xfffe.

Jelaskan diri Anda


Oke, kami menemukan perangkat kami, tetapi sebelum berinteraksi dengannya, kami ingin tahu lebih banyak tentangnya. Anda tahu, konfigurasi, antarmuka, titik akhir, jenis aliran data ...
Jika Anda memiliki perangkat, Anda dapat mengakses bidang keterangan perangkat sebagai properti objek:

 >>> dev.bLength >>> dev.bNumConfigurations >>> dev.bDeviceClass >>> # ... 

Untuk mengakses konfigurasi yang tersedia di perangkat, Anda dapat mengulangi perangkat:

 for cfg in dev: sys.stdout.write(str(cfg.bConfigurationValue) + '\n') 

Dengan cara yang sama, Anda dapat mengulangi konfigurasi untuk mengakses antarmuka, serta mengulangi antarmuka untuk mengakses titik kontrol mereka. Setiap jenis objek memiliki bidang deskriptor yang sesuai sebagai atribut. Lihatlah sebuah contoh:

 for cfg in dev: sys.stdout.write(str(cfg.bConfigurationValue) + '\n') for intf in cfg: sys.stdout.write('\t' + \ str(intf.bInterfaceNumber) + \ ',' + \ str(intf.bAlternateSetting) + \ '\n') for ep in intf: sys.stdout.write('\t\t' + \ str(ep.bEndpointAddress) + \ '\n') 

Anda juga dapat menggunakan indeks untuk akses acak ke deskriptor, seperti di sini:

 >>> #      >>> cfg = dev[1] >>> #      >>> intf = cfg[(0,0)] >>> #    >>> ep = intf[2] 

Seperti yang Anda lihat indeks dihitung dari 0. Tapi tunggu! Ada sesuatu yang aneh dalam cara saya mendapatkan akses ke antarmuka ... Ya, Anda benar, indeks untuk Konfigurasi mengambil serangkaian dua nilai, di mana yang pertama adalah indeks Antarmuka, dan yang kedua adalah pengaturan alternatif. Secara umum, untuk mengakses antarmuka pertama, tetapi dengan pengaturan kedua, kita akan menulis cfg [(0,1)] .

Sekarang adalah waktu untuk mempelajari cara yang ampuh untuk mencari deskriptor - fungsi find_descriptor yang bermanfaat. Kami telah melihatnya dalam contoh pencarian printer. find_descriptor bekerja hampir sama dengan find , dengan dua pengecualian:

  • find_descriptor menerima sebagai parameter pertama deskriptor sumber yang akan Anda cari.
  • Tidak ada parameter backend di dalamnya [2] .

Misalnya, jika kami memiliki deskriptor konfigurasi cfg , dan kami ingin menemukan semua pengaturan alternatif untuk antarmuka 1, kami akan melakukan ini:

 import usb.util alt = usb.util.find_descriptor(cfg, find_all=True, bInterfaceNumber=1) 

Perhatikan bahwa find_descriptor ada di modul usb.util . Ini juga menerima parameter custom_match yang dijelaskan sebelumnya.

Kami menangani beberapa perangkat yang identik

Terkadang Anda dapat memiliki dua perangkat identik yang terhubung ke komputer. Bagaimana Anda bisa membedakan mereka? Objek perangkat datang dengan dua atribut tambahan yang bukan bagian dari spesifikasi USB, tetapi sangat berguna: atribut bus dan alamat . Pertama-tama, perlu dikatakan bahwa atribut-atribut ini berasal dari backend, dan backend mungkin tidak mendukung mereka - dalam hal ini mereka diatur ke None . Namun, atribut ini mewakili jumlah dan alamat bus perangkat dan, seperti yang Anda duga, dapat digunakan untuk membedakan antara dua perangkat dengan nilai atribut idVendor dan idProduct yang sama.

Bagaimana saya harus bekerja?


Setelah tersambung, perangkat USB harus dikonfigurasikan menggunakan beberapa kueri standar. Ketika saya mulai mempelajari spesifikasi USB , saya berkecil hati oleh deskriptor, konfigurasi, antarmuka, pengaturan alternatif, jenis transfer dan semua itu ... Dan yang terburuk, Anda tidak bisa mengabaikannya: perangkat tidak bekerja tanpa mengatur konfigurasi, walaupun itu salah satu! PyUSB berusaha membuat hidup Anda sesederhana mungkin. Misalnya, setelah menerima objek perangkat Anda, pertama-tama, sebelum berinteraksi dengannya, Anda perlu mengirim permintaan konfigurasi set_configuration . Parameter konfigurasi untuk kueri ini yang menarik minat Anda adalah bConfigurationValue . Sebagian besar perangkat tidak memiliki lebih dari satu konfigurasi, dan melacak nilai konfigurasi yang digunakan adalah menjengkelkan (walaupun sebagian besar kode yang saya lihat hanya hardcoded ini). Oleh karena itu, di PyUSB, Anda cukup mengirim permintaan set_configuration tanpa argumen. Dalam hal ini, ia akan menginstal konfigurasi pertama yang ditemukan (jika perangkat Anda hanya memiliki satu, Anda tidak perlu khawatir tentang nilai konfigurasi sama sekali). Misalnya, Anda memiliki perangkat dengan satu deskriptor konfigurasi, dan bidang bConfigurationValue-nya adalah 5 [3] , kueri selanjutnya akan bekerja sama:

 >>> dev.set_configuration(5) #  >>> dev.set_configuration() #  ,   5 -  #  >>> cfg = util.find_descriptor(dev, bConfigurationValue=5) >>> cfg.set() #  >>> cfg = util.find_descriptor(dev, bConfigurationValue=5) >>> dev.set_configuration(cfg) 

Wow! Anda dapat menggunakan objek Konfigurasi sebagai parameter untuk set_configuration ! Ya, ia juga memiliki metode yang ditetapkan untuk mengkonfigurasi dirinya dalam konfigurasi saat ini.

Opsi lain yang perlu atau tidak perlu Anda konfigurasi adalah opsi untuk mengubah antarmuka. Setiap perangkat hanya dapat memiliki satu konfigurasi yang diaktifkan pada satu waktu, dan setiap konfigurasi dapat memiliki lebih dari satu antarmuka, dan Anda dapat menggunakan semua antarmuka secara bersamaan. Anda lebih memahami konsep ini jika Anda menganggap antarmuka sebagai perangkat logis. Sebagai contoh, mari kita bayangkan sebuah printer multifungsi, yang sekaligus adalah printer dan pemindai. Agar tidak menyulitkan (atau setidaknya membuatnya sesederhana mungkin), mari kita asumsikan bahwa dia hanya memiliki satu konfigurasi. Karena kami memiliki printer dan pemindai, konfigurasi memiliki 2 antarmuka: satu untuk printer dan satu untuk pemindai. Perangkat dengan lebih dari satu antarmuka disebut perangkat komposit. Ketika Anda menghubungkan printer multifungsi Anda ke komputer Anda, Sistem Operasi akan memuat dua driver yang berbeda: satu untuk setiap perangkat periferal "logis" yang Anda miliki [4] .

Bagaimana dengan pengaturan antarmuka alternatif? Untung kamu bertanya. Antarmuka memiliki satu atau beberapa pengaturan alternatif. Antarmuka dengan hanya satu pengaturan alternatif dianggap tidak memiliki pengaturan alternatif [5] . Pengaturan alternatif untuk antarmuka sebagai konfigurasi untuk perangkat, yaitu, untuk setiap antarmuka Anda hanya dapat memiliki satu pengaturan alternatif aktif. Misalnya, spesifikasi USB menyarankan bahwa perangkat tidak dapat memiliki pos pemeriksaan isochronous dalam konfigurasi alternatif utamanya [6] , sehingga perangkat streaming harus memiliki setidaknya dua pengaturan alternatif, dengan pengaturan kedua memiliki pos pemeriksaan isochronous. Tetapi, tidak seperti konfigurasi, antarmuka dengan hanya satu konfigurasi alternatif tidak perlu dikonfigurasi [7] . Anda memilih pengaturan antarmuka alternatif menggunakan fungsi set_interface_altsetting :

 >>> dev.set_interface_altsetting(interface = 0, alternate_setting = 0) 

Peringatan

Spesifikasi USB mengatakan bahwa perangkat diizinkan untuk mengembalikan kesalahan jika menerima permintaan SET_INTERFACE untuk antarmuka yang tidak memiliki pengaturan alternatif tambahan. Jadi jika Anda tidak yakin bahwa antarmuka memiliki lebih dari satu pengaturan alternatif atau bahwa ia menerima permintaan SET_INTERFACE, metode paling aman adalah memanggil set_interface_altsetting di dalam blok coba-kecuali, seperti di sini:

 try: dev.set_interface_altsetting(...) except USBError: pass 

Anda juga dapat menggunakan objek Antarmuka sebagai parameter fungsi, antarmuka dan parameter pengaturan_pilihan secara otomatis diwarisi dari bidang bInterfaceNumber dan bAlternateSetting . Contoh:

 >>> intf = find_descriptor(...) >>> dev.set_interface_altsetting(intf) >>> intf.set_altsetting() # !        

Peringatan

Objek antarmuka harus milik deskriptor konfigurasi aktif.

Bicaralah padaku sayang


Dan sekarang saatnya bagi kita untuk memahami cara berinteraksi dengan perangkat USB. USB memiliki empat jenis aliran data: transfer massal, transfer interupsi, transfer isochronous, dan transfer kontrol. Saya tidak berencana untuk menjelaskan tujuan dari setiap utas dan perbedaan di antara mereka. Oleh karena itu, saya berasumsi bahwa Anda memiliki setidaknya pengetahuan dasar aliran data USB.

Aliran data kontrol adalah satu-satunya aliran yang strukturnya dijelaskan dalam spesifikasi, sisanya hanya mengirim dan menerima data mentah dari sudut pandang USB. Oleh karena itu, Anda memiliki berbagai fungsi untuk bekerja dengan aliran kontrol, dan sisa aliran diproses oleh fungsi yang sama.

Anda dapat mengakses aliran data kontrol menggunakan metode ctrl_transfer . Ini digunakan baik untuk aliran keluar (keluar) dan masuk (IN). Arah aliran ditentukan oleh parameter bmRequestType .

Parameter ctrl_transfer hampir bersamaan dengan struktur permintaan kontrol. Berikut ini adalah contoh cara mengatur aliran data kontrol. [8] :

 >>> msg = 'test' >>> assert dev.ctrl_transfer(0x40, CTRL_LOOPBACK_WRITE, 0, 0, msg) == len(msg) >>> ret = dev.ctrl_transfer(0xC0, CTRL_LOOPBACK_READ, 0, 0, len(msg)) >>> sret = ''.join([chr(x) for x in ret]) >>> assert sret == msg 

Contoh ini mengasumsikan bahwa perangkat kami mencakup dua permintaan kontrol pengguna yang bertindak seperti pipa loopback. Apa yang Anda tulis dengan pesan CTRL_LOOPBACK_WRITE , Anda dapat membaca dengan pesan CTRL_LOOPBACK_READ .

Empat parameter pertama - bmRequestType , bmRequest , wValue dan wIndex - adalah bidang struktur standar aliran kontrol. Parameter kelima adalah data yang ditransfer untuk aliran data keluar atau jumlah data yang sedang dibaca dalam aliran masuk. Data yang dikirim dapat berupa jenis urutan apa pun, yang dapat dimasukkan sebagai parameter ke input metode __init__ untuk array . Jika tidak ada data yang ditransfer, parameter harus diatur ke Tidak ada (atau 0 jika aliran data masuk). Ada parameter opsional lain yang menunjukkan batas waktu operasi. Jika Anda tidak lulus, batas waktu default akan digunakan (lebih lanjut tentang ini nanti). Dalam aliran data keluar, nilai kembali adalah jumlah byte yang sebenarnya dikirim ke perangkat. Dalam aliran masuk, nilai kembali adalah array dengan data dibaca.

Untuk aliran lain, Anda dapat menggunakan metode menulis dan membaca , masing-masing, untuk menulis dan membaca data. Anda tidak perlu khawatir tentang jenis aliran - ini secara otomatis terdeteksi oleh alamat pos pemeriksaan. Berikut adalah contoh loopback kami, asalkan kami memiliki pipa loopback di breakpoint 1:

 >>> msg = 'test' >>> assert len(dev.write(1, msg, 100)) == len(msg) >>> ret = dev.read(0x81, len(msg), 100) >>> sret = ''.join([chr(x) for x in ret]) >>> assert sret == msg 

Parameter pertama dan ketiga sama untuk kedua metode - masing-masing adalah alamat pos pemeriksaan dan batas waktu. Parameter kedua adalah data yang dikirimkan (tulis) atau jumlah byte untuk dibaca (baca). Data yang dikembalikan akan berupa instance dari objek array untuk metode baca , atau jumlah byte yang ditulis untuk metode tulis .

Dengan versi beta 2, alih-alih jumlah byte, Anda dapat meneruskan membaca atau ctrl_transfer objek array yang datanya akan dibaca. Dalam hal ini, jumlah byte yang akan dibaca akan menjadi panjang array dikalikan nilai array.itemsize .

Dalam ctrl_transfer , parameter batas waktu adalah opsional. Ketika batas waktu dihilangkan, properti Device.default_timeout digunakan sebagai batas waktu operasional.

Kendalikan diri Anda


Selain fungsi aliran data, modul usb.control menyediakan fungsi yang mencakup permintaan kontrol USB standar, dan modul usb.util memiliki fungsi get_string yang nyaman yang secara khusus menampilkan deskriptor garis.

Topik tambahan


Di belakang setiap abstraksi besar adalah realisasi yang hebat


Sebelumnya, hanya ada libusb . Kemudian datang libusb 1.0 dan kami memiliki libusb 0.1 dan 1.0. Setelah itu, kami menciptakan OpenUSB dan sekarang kami tinggal di Menara Babel dari Perpustakaan USB [9] . Bagaimana PyUSB menangani ini? Nah, PyUSB adalah perpustakaan yang demokratis, Anda dapat memilih perpustakaan mana yang Anda inginkan. Bahkan, Anda dapat menulis perpustakaan USB Anda sendiri dari awal dan memberi tahu PyUSB untuk menggunakannya.

Fungsi find memiliki parameter lain, yang tidak saya ceritakan. Ini adalah parameter backend . Jika Anda tidak mentransfernya, salah satu backend bawaan akan digunakan. Backend adalah objek yang diwarisi dari usb.backend.IBackend , yang bertanggung jawab untuk memperkenalkan sampah USB khusus sistem operasi. Seperti yang mungkin sudah Anda duga, libusb 0.1, libusb 1.0, dan OpenUSB bawaan adalah backend.

Anda dapat menulis backend Anda sendiri dan menggunakannya. Hanya mewarisi dari IBackend dan aktifkan metode yang diperlukan. Anda mungkin perlu melihat dokumentasi usb.backend untuk memahami bagaimana ini dilakukan.

Jangan egois


Python memiliki apa yang kita sebut manajemen memori otomatis . Ini berarti bahwa mesin virtual akan memutuskan kapan untuk membongkar objek dari memori. Di bawah tenda, PyUSB mengelola semua sumber daya tingkat rendah yang perlu Anda kerjakan (menyetujui antarmuka, menyesuaikan perangkat, dll.) Dan sebagian besar pengguna tidak perlu khawatir tentang hal ini. Tetapi, karena sifat alami dari penghancuran objek secara otomatis oleh Python, pengguna tidak dapat memprediksi kapan sumber daya yang dialokasikan akan dirilis. Beberapa aplikasi perlu mengalokasikan dan membebaskan sumber daya secara deterministik. Untuk aplikasi seperti itu, modul usb.util menyediakan fungsi untuk berinteraksi dengan manajemen sumber daya.

Jika Anda ingin meminta dan melepaskan antarmuka secara manual, Anda dapat menggunakan fungsi claim_interface dan release_interface .Fungsi claim_interface akan meminta antarmuka yang ditentukan jika perangkat belum melakukannya. Jika perangkat sudah meminta antarmuka, itu tidak melakukan apa-apa. Release_interface juga akan merilis antarmuka yang ditentukan, jika diminta. Jika antarmuka tidak diminta, itu tidak melakukan apa-apa. Anda dapat menggunakan kueri antarmuka manual untuk menyelesaikan masalah pemilihan konfigurasi yang dijelaskan dalam dokumentasi libusb . Jika Anda ingin membebaskan semua sumber daya yang dialokasikan oleh objek perangkat (termasuk antarmuka yang diminta), Anda dapat menggunakan fungsi dispose_resources

. Ini membebaskan semua sumber daya yang dialokasikan dan menempatkan objek perangkat (tetapi tidak dalam perangkat keras perangkat itu sendiri) ke keadaan di mana ia dikembalikan setelah menggunakan fungsi find .

Definisi perpustakaan manual


Secara umum, backend adalah pembungkus di atas pustaka bersama yang mengimplementasikan API untuk mengakses USB. Secara default, backend menggunakan fungsi ctypes find_library () . Di Linux dan Sistem Operasi mirip Unix lainnya, find_library mencoba menjalankan program eksternal (seperti / sbin / ldconfig , gcc dan objdump ) untuk menemukan file perpustakaan.

Pada sistem di mana program ini hilang dan / atau cache perpustakaan dinonaktifkan, fungsi ini tidak dapat digunakan. Untuk mengatasi keterbatasan, PyUSB memungkinkan Anda untuk mengirimkan fungsi kustom find_library () ke backend.

Contoh skenario seperti itu adalah:

 >>> import usb.core >>> import usb.backend.libusb1 >>> >>> backend = usb.backend.libusb1.get_backend(find_library=lambda x: "/usr/lib/libusb-1.0.so") >>> dev = usb.core.find(..., backend=backend) 

Perhatikan bahwa find_library adalah argumen ke fungsi get_backend () di mana Anda menyediakan fungsi yang bertanggung jawab untuk menemukan perpustakaan yang tepat untuk backend.

Aturan sekolah lama


Jika Anda menulis aplikasi menggunakan API PyUSB lama (0. sesuatu-di sana), Anda mungkin bertanya pada diri sendiri apakah Anda perlu memperbarui kode Anda untuk menggunakan API baru. Ya, Anda harus melakukannya, tetapi itu tidak perlu. PyUSB 1.0 hadir dengan modul kompatibilitas usb.legacy . Ini termasuk API lama berdasarkan API baru. "Yah, haruskah saya mengganti jalur usb impor saya dengan impor usb.legacy sebagai usb agar aplikasi saya berfungsi?", Anda bertanya. Jawabannya adalah ya, itu akan berhasil, tetapi itu tidak perlu. Jika Anda menjalankan aplikasi Anda tidak berubah, itu akan berfungsi karena jalur impor usb mengimpor semua simbol publik dari usb.legacy. Jika Anda menemukan masalah - kemungkinan besar Anda telah menemukan bug.

Tolong bantu saya


Jika Anda butuh bantuan, jangan kirimi saya email , ada milis untuk ini. Instruksi berlangganan dapat ditemukan di situs web PyUSB .

[1] Ketika saya menulis Benar atau Salah (dengan huruf kapital), maksud saya nilai yang sesuai dari bahasa Python. Dan ketika saya mengatakan true (true) atau false (false), maksud saya setiap ekspresi Python yang dianggap benar atau salah. (Kesamaan ini terjadi dalam aslinya dan membantu untuk memahami konsep benar dan salah dalam terjemahan. - Catatan. ) :

[2] Lihat dokumentasi backend khusus.

[3] Spesifikasi USB tidak memaksakan nilai spesifik pada nilai konfigurasi. Hal yang sama berlaku untuk nomor antarmuka dan pengaturan alternatif.

[4] Sebenarnya, semuanya sedikit lebih rumit, tapi ini hanya penjelasan untuk kita.

[5] Saya tahu ini terdengar aneh.

[6] Ini karena jika tidak ada bandwidth untuk aliran data isochronous selama konfigurasi perangkat, itu dapat berhasil dinomori.

[7] Ini tidak terjadi untuk konfigurasi karena perangkat dibiarkan dalam keadaan tidak terkonfigurasi.

[8] Di PyUSB, data kontrol mengalirkan titik kontrol akses 0. Sangat sangat sangat jarang, perangkat memiliki titik kontrol kontrol alternatif (saya belum pernah bertemu dengan perangkat seperti itu).

[9] Ini hanya lelucon, jangan menganggapnya serius. Pilihan bagus lebih baik daripada tidak ada pilihan.

Source: https://habr.com/ru/post/id430528/


All Articles