Commits

gao shuai committed 95f7831

pyusb

  • Participants

Comments (0)

Files changed (7)

pywinusb-0.3.1/README.rst

+*********************************
+Installing and Using pywinusb.hid
+*********************************
+
+.. contents:: **Table of Contents**
+
+Introduction
+============
+
+This project aims to be a simple USB/HID user application space (hence no system 
+drivers needed) 100% python package (without C extensions). Initially targeting 
+simple HID devices management.
+
+The vision for this project is to be something similar to `PySerial` or `PyParallel` 
+but for USB/HID hardware enthusiasts.
+
+Advantages
+----------
+
+ * All python code, using ctypes
+ 
+ * Top level handling of HID events (usage events calling hook function handlers)
+
+Current limitations
+-------------------
+
+Depending on your application you might find these limitations
+
+ * Windows only (so far...)
+ 
+ * Not so fast top level interfacing. But you could still access, directly
+   your raw data reports.
+
+Installation Instructions
+=========================
+
+Windows
+-------
+
+The most convenient way of installing is using `easy_install` or `pip`, I
+recomend to do this once you are familiar with the library as you might loose
+track of the example source files, but you can take a look to the example or
+the source browsing the github repository.
+
+If using a source package (.zip) from PyPi un-zip your file, or get the source
+from the main repository and run the familiar `setup.py install` command line
+is sufficient, setuptools or distribute (for python 3) are required.
+
+
+Other
+-----
+
+So far only Windows OS it's supported.
+
+Using pywinusb.hid
+==================
+
+View the `./examples` directory for some (ok, few right now) scripts. These
+show, for instance, how to use pywinusb.hid to handle events from HID class
+devices usages events.
+
+Gernal purpose instructions can be found on the `main project code page`_.
+
+.. _main project code page: https://github.com/rene-aguirre/pywinusb
+
+Utilities
+---------
+
+More on this later... 
+
+ * The module pywinusb.hid.tools contains a function to check HID class devices
+   capabilities, for now it provides a basic human readable text report (see
+   the hid.core package, run it as main while HID class devices are connected
+   to your system)
+
+Feedback and Contributing
+=========================
+
+Feel free to contact me! use the `main code project page`_, just tell what do
+you think about the project or bring me anything you think might be cool to
+consider.
+
+Any participation it's appreciated, if you are willing to contribute but don't
+have any ideas or spare time, `feel free to donate`_.
+
+.. _main code project page: https://github.com/rene-aguirre/pywinusb
+
+.. _feel free to donate: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4640085
+

pywinusb-0.3.1/TODO.txt

+Pending tasks:
+
+ * Python 3 support.
+
+ * Documentation, need to put local documentation on the project, so far, some
+   usage instructions are given in the google code pywinusb site.
+
+ * More examples, show the full capabilities currently implemented, all is easy
+   just missing the scripts to show it off
+
+    a) Handling composite devices
+
+    b) Handling multiple physical devices
+
+ * Give a more useful output for the hid.tools (something more formal as when
+   running the hid.core.py script)
+
+ * Implement some hid sniffing functionality, this would be great for hacking
+
+ * Add 'usbview' like helpers in order to analize the current usb hardware
+   configuration
+
+ * Start the WinUSB stuff
+

pywinusb-0.3.1/examples/hook_button.py

+#
+"""
+Simple example on how to handle usage control events
+"""
+from time import sleep
+from msvcrt import kbhit
+
+import pywinusb.hid as hid
+
+def test_telephony_hook():
+    """Browse for non system HID class devices, if a telephony page
+    hook usage control is available monitor value change events"""
+    # play with this value (or set it if you know your device capabilities)
+    # this allows to poll the telephony device for the current usage value
+    input_interrupt_transfers = False
+    
+    # get all currently connected HID devices we could filter by doing 
+    # something like hid.HidDeviceFilter(VendorId=0x1234), product Id 
+    # filters (with masks) and other capabilities also available
+    all_devices = hid.HidDeviceFilter().get_devices() 
+
+    if not all_devices:
+        print("No HID class devices attached.")
+    else:
+        # search for our target usage (the hook button)
+        #target pageId, usageId
+        usage_telephony_hook = hid.get_full_usage_id(0xb, 0x20)
+               
+        def hook_pressed(new_value, event_type):
+            "simple usage control handler"
+            # this simple handler is called on 'pressed' events
+            # this means the usage value has changed from '1' to '0'
+            # no need to check the value
+            event_type = event_type #avoid pylint warnings
+            if new_value:
+                print("On Hook!")
+            else:
+                print("Off Hook!")
+        
+        for device in all_devices:
+            try:
+                device.open()
+                
+                # browse input reports
+                all_input_reports = device.find_input_reports()
+                
+                for input_report in all_input_reports:
+                    if usage_telephony_hook in input_report:
+                        #found a telephony device w/ hook button
+                        print("\nMonitoring {0.vendor_name} {0.product_name} "\
+                                "device.\n".format(device))
+                        print("Press any key to exit monitoring " \
+                            "(or remove HID device)...")
+                        
+                        # add event handler (example of other available 
+                        # events: EVT_PRESSED, EVT_RELEASED, EVT_ALL, ...)
+                        device.add_event_handler(usage_telephony_hook, 
+                            hook_pressed, hid.HID_EVT_CHANGED) #level usage
+                        
+                        if input_interrupt_transfers:
+                            # poll the current value (GET_REPORT directive), 
+                            # allow handler to process result
+                            input_report.get()
+                        
+                        while not kbhit() and device.is_plugged():
+                            #just keep the device opened to receive events
+                            sleep(0.5)
+                        return
+            finally:
+                device.close()
+        print("Sorry, no one of the attached HID class devices "\
+            "provide any Telephony Hook button")
+    #
+if __name__ == '__main__':
+    test_telephony_hook()
+

pywinusb-0.3.1/examples/pnp_sample.py

+#
+"""
+Plug and Play example
+
+This script requires wxPython, but it could be easily (really!) changed
+to work with any GUI working on windows, just make you you pass your frame window
+handler to the HidPnPWindowMixin.__init__ initialization function.
+
+A hook will be inserted on the message handler so the window could be used as
+a target for PnP events, for now this are HID class wise, this means you'll have
+to test if your device 'plug' status has changed.
+"""
+
+import wx
+import pywinusb.hid as hid
+
+# feel free to test
+target_vendor_id = 0x1234
+target_product_id = 0x0001
+
+class MyFrame(wx.Frame,hid.HidPnPWindowMixin):
+    # a device so we could easily discriminate wich devices to look at
+    my_hid_target = hid.HidDeviceFilter(vendor_id = target_vendor_id, product_id = target_product_id)
+    
+    def __init__(self,parent):
+        wx.Frame.__init__(self,parent,-1,
+                "Re-plug your USB HID device, watch the command window!...")
+        hid.HidPnPWindowMixin.__init__(self, self.GetHandle())
+        wx.EVT_CLOSE(self, self.on_close)
+        self.device = None #no hid device... yet
+        
+        # kick the pnp engine
+        self.on_hid_pnp()
+        
+    def on_hid_pnp(self, hid_event = None):
+        """This function will be called on per class event changes, so we need
+        to test if our device has being connected or is just gone"""
+        if hid_event:
+            print("Hey, a hid device just %s!" % hid_event)
+            
+        if hid_event == "connected":
+            # test if our device is available
+            if self.device:
+                # see, at this point we could detect multiple devices!
+                # but... we only want just one
+                pass
+            else:
+                self.test_for_connection()
+        elif hid_event == "disconnected":
+            # the hid object is automatically closed on disconnection we just
+            # test if still is plugged (important as the object might be
+            # closing)
+            if self.device and not self.device.is_plugged():
+                self.device = None
+                print("you removed my hid device!")
+        else:
+            # poll for devices
+            self.test_for_connection()
+        # update ui
+        if old_Device != self.device:
+            self.UpdateUsbStatus(False)
+        
+    def test_for_connection(self):
+        all_items =  MyFrame.my_hid_target.get_devices()
+        if all_items:
+            # at this point, what we decided to be a valid hid target is
+            # already plugged
+            if len(all_items) == 1:
+                # this is easy, we only have a single hid device
+                self.device = all_items[0]
+            else:
+                # at this point you might have multiple scenarios
+                grouped_items = MyFrame.my_hid_target.get_devices_by_parent()
+                print("%d devices now connected" % len(grouped_items))
+                if len(grouped_items) > 1:
+                    # 1) Really you have multiple devices connected so, make
+                    # your rules, how do you help your user to handle multiple
+                    # devices?
+                    # maybe you here will find out wich is the new device, and
+                    # tag this device so is easily identified (i.e. the WiiMote
+                    # uses LEDs), or just your GUI shows some arbitrary
+                    # identification for the user (device 2 connected)
+                    pass
+                else:
+                    # 2) We have a single physical device, but the descriptors
+                    # might might cause the OS to report is as multiple devices
+                    # (collections maybe) so, what would be your target device?
+                    # if you designed the device firmware, you already know the
+                    # answer...  otherwise one approach might be to browse the
+                    # hid usages for a particular target...  anyway, this could
+                    # be complex, especially handling multiple physical devices
+                    # that are reported as multiple hid paths (objects)...
+                    # so...  I recommend you creating a proxy class that is
+                    # able to handle all your 'per parent id' grouped devices,
+                    # (like a single .open() able to handle your buch of
+                    # HidDevice() items
+                    pass
+                # but... we just arbitrarly select the first hid object path
+                # (how creative!)
+                self.device = all_items[0]
+        if self.device:
+            self.device.open()
+            print("got my device: %s!" % repr(self.device))
+        else:
+            print("saddly my device is not here... yet :-( ")
+
+    def on_close(self, event):
+        event.Skip()
+        if self.device:
+            self.device.close()
+            
+if __name__ == "__main__":
+    app = wx.App(False)
+    frame = MyFrame(None)
+    frame.Show()
+    app.MainLoop()
+

pywinusb-0.3.1/examples/raw_data.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+"""
+Handling raw data inputs example
+"""
+from time import sleep
+from msvcrt import kbhit
+
+import pywinusb.hid as hid
+
+def sample_handler(data):
+    print("Raw data: {0}".format(data))
+
+def raw_test():
+    # simple test
+    # browse devices...
+    all_hids = hid.find_all_hid_devices()
+    if all_hids:
+        while True:
+            print("Choose a device to monitor raw input reports:\n")
+            print("0 => Exit")
+            for index, device in enumerate(all_hids):
+                device_name = unicode("{0.vendor_name} {0.product_name}" \
+                        "(vID=0x{1:04x}, pID=0x{2:04x})"\
+                        "".format(device, device.vendor_id, device.product_id))
+                print("{0} => {1}".format(index+1, device_name))
+            print("\n\tDevice ('0' to '%d', '0' to exit?) " \
+                    "[press enter after number]:" % len(all_hids))
+            index_option = raw_input()
+            if index_option.isdigit() and int(index_option) <= len(all_hids):
+                # invalid
+                break;
+        int_option = int(index_option)
+        if int_option:
+            device = all_hids[int_option-1]
+            try:
+                device.open()
+
+                #set custom raw data handler
+                device.set_raw_data_handler(sample_handler)
+
+                print("\nWaiting for data...\nPress any (system keyboard) key to stop...")
+                while not kbhit() and device.is_plugged():
+                    #just keep the device opened to receive events
+                    sleep(0.5)
+                return
+            finally:
+                device.close()
+    else:
+        print("There's not any non system HID class device available")
+#
+if __name__ == '__main__':
+    # first be kind with local encodings
+    import sys
+    if sys.version_info >= (3,):
+        # as is, don't handle unicodes
+        unicode = str
+        raw_input = input
+    else:
+        # allow to show encoded strings
+        import codecs
+        sys.stdout = codecs.getwriter('mbcs')(sys.stdout)
+    raw_test()
+

pywinusb-0.3.1/examples/simple_feature.py

+#!/usr/bin/env python
+# -*- coding: latin-1 -*-
+
+"""
+Simple example on how to poll feature reports usages
+"""
+import pywinusb.hid as hid
+
+def read_values(target_usage):
+    """read feature report values"""
+    # browse all devices
+    all_devices = hid.HidDeviceFilter().get_devices()
+    
+    if not all_devices:
+        print("Can't find any non system HID device connected")
+    else:
+        # search for our target usage
+        usage_found = False
+        for device in all_devices:
+            try:
+                device.open()
+                # browse feature reports
+                for report in device.find_feature_reports():
+                    if target_usage in report:
+                        # we found our usage
+                        report.get()
+                        # print result
+                        print("The value:", list(report[target_usage]))
+                        print("All the report: {0}".format(report.get_raw_data()))
+                        usage_found = True
+            finally:
+                device.close()
+        if not usage_found:
+            print("The target device was found, but the requested usage does not exist!\n")
+    #
+if __name__ == '__main__':
+    target_usage = hid.get_full_usage_id(0xff00, 0x02) # generic vendor page, usage_id = 2
+    # go for it!
+    read_values(target_usage)
+

pywinusb-0.3.1/examples/simple_send.py

+#
+"""
+Simple example on how to send simple reports based on usages
+"""
+import pywinusb.hid as hid
+
+def click_signal(target_usage, target_vendor_id):
+    """This function will find a particular target_usage over output reports on
+    target_vendor_id related devices, then it will flip the signal to simulate
+    a 'click' event"""
+    # usually you'll find and open the target device, here we'll browse for the
+    # current connected devices
+    all_devices = hid.HidDeviceFilter(vendor_id = target_vendor_id).get_devices()
+    
+    if not all_devices:
+        print("Can't find target device (vendor_id = 0x%04x)!" % target_vendor_id)
+    else:
+        # search for our target usage
+        # target pageId, usageId
+             
+        for device in all_devices:
+            try:
+                device.open()
+                # browse output reports, we could search over feature reports also,
+                # changing find_output_reports() to find_feature_reports()
+                for report in device.find_output_reports():
+                    if target_usage in report:
+                        # found out target!
+                        report[target_usage] = 1 # yes, changing values is that easy
+                        # at this point you could change different usages at a time...
+                        # and finally send the prepared output report
+                        report.send()               
+                        # now toggle back the signal
+                        report[target_usage] = 0
+                        report.send()
+                        print("\nUsage clicked!\n")
+                        return
+            finally:
+                device.close()
+        print("The target device was found, but the requested usage does not exist!\n")
+    #
+if __name__ == '__main__':
+    target_vendor_id = 0x1234 # just an example, change it to the actual vendor_id
+    target_usage = hid.get_full_usage_id(0xffa0, 0x02) # generic vendor page, usage_id = 2
+    # go for it!
+    click_signal(target_usage, target_vendor_id)
+