Ben Bass avatar Ben Bass committed eea1286

multiple device support - tidyup

Comments (0)

Files changed (6)

 pylibftdi changes
 =================
 
+0.7
+ * support multiple attached devices
+ * new API - separation between driver and device
 0.6
  * same source now works on both Python2.6+ and Python3.
 0.5
 All rights reserved.
 """
 
-from pylibftdi import BitBangDriver, Bus
+from pylibftdi import BitBangDevice, Bus
 
 
 class LCD(object):
 
 def display(string):
     "Display the given string on an attached LCD"
-    with BitBangDriver() as bb:
+    with BitBangDevice() as bb:
 
         # These LCDs are quite slow - and the actual baudrate
         # is 16x this in bitbang mode...

examples/list_devices.py

+
+
+from pylibftdi import Driver
+
+
+for device in Driver().list_devices():
+    print("%s:%s:%s"%(device))

pylibftdi/__init__.py

 __AUTHOR__ = "Ben Bass"
 
 
-__ALL__ = ['Driver', 'Device', 'BitBangDriver', 'Bus', 'FtdiError',
+__ALL__ = ['Driver', 'Device', 'BitBangDevice', 'Bus', 'FtdiError',
            'ALL_OUTPUTS', 'ALL_INPUTS', 'BB_OUTPUT', 'BB_INPUT']
 
 from pylibftdi import _base, driver, util, bitbang
 FtdiError = _base.FtdiError
 Bus = util.Bus
 Driver = driver.Driver
-Driver = driver.Device
-BitBangDriver = bitbang.BitBangDriver
+BitBangDevice = bitbang.BitBangDevice
 
 ALL_OUTPUTS = bitbang.ALL_OUTPUTS
 ALL_INPUTS = bitbang.ALL_INPUTS
 BB_OUTPUT = bitbang.BB_OUTPUT
 BB_INPUT = bitbang.BB_INPUT
 
+
+# LEGACY SUPPORT
+
+#__ALL__.append('BitBangDriver')
+#Driver = driver.Device
+#BitBangDriver = bitbang.BitBangDevice

pylibftdi/bitbang.py

 """
 
 from pylibftdi.driver import Device
-from ctypes import byref 
 
 ALL_OUTPUTS = 0xFF
 ALL_INPUTS = 0x00
 BB_OUTPUT = 1
 BB_INPUT = 0
 
-class BitBangDriver(Device):
+class BitBangDevice(Device):
     """
     simple subclass to support bit-bang mode
 
      port: 8 bit IO port, as defined by direction.
     """
     def __init__(self, direction = ALL_OUTPUTS):
-        super(BitBangDriver, self).__init__(mode = 'b')
+        super(BitBangDevice, self).__init__(mode = 'b')
         self.direction = direction
         self._latch = 0
 
         "open connection to a FTDI device"
         # in case someone sets the direction before we are open()ed,
         # we intercept this call...
-        super(BitBangDriver, self).open()
+        super(BitBangDevice, self).open()
         if self._direction:
             self.direction = self._direction
         return self
         # the coercion to bytearray here is to make this work
         # transparently between Python2 and Python3 - equivalent
         # of ord() for Python2, a time-wasting do-nothing on Python3
-        result = bytearray(super(BitBangDriver, self).read(1))[0]
+        result = bytearray(super(BitBangDevice, self).read(1))[0]
         # replace the 'output' bits with current value of _latch -
         # the last written value. This makes read-modify-write
         # operations (e.g. 'drv.port |= 0x10') work as expected
     @port.setter
     def port(self, value):
         self._latch = value
-        return super(BitBangDriver, self).write(chr(value))
+        return super(BitBangDevice, self).write(chr(value))
 

pylibftdi/driver.py

                     create_string_buffer, Structure, pointer, POINTER)
 from ctypes.util import find_library
 
-from pylibftdi._base import ParrotEgg, DeadParrot, FtdiError
-
+from pylibftdi._base import FtdiError
 
 class UsbDevList(Structure):
     _fields_ = [('next', c_void_p),
                 ('usb_dev', c_void_p)]
 
-def Follower(x):
-    class _(object):
-        def __getattr__(self, key):
-            obj = getattr(x,key)
-            if callable(obj):
-                class _fn(object):
-                    def __getattr__(s1, key):
-                        return getattr(obj, key)
-                    def __setattr__(s1, key, value):
-                        return setattr(obj, key, value)
-                    def __delattr__(s1, key):
-                        return delattr(obj, key)
-                    def __call__(s1, *o, **k):
-                        print "%s(%s,%s)"%(obj.__name__,o,k),
-                        res = obj(*o, **k)
-                        print "-> %s"%res
-                        return res
-                return _fn()
-            else:
-                return obj
-        def __setattr__(self, key, value):
-            return setattr(x,key,value)
-        def __delattr__(self, key):
-            return delattr(x,key)
-    return _()
-    
 
-class FtdiEnumerate(object):
+class Driver(object):
+    """
+    This is where it all happens...
+    We load the libftdi library, and use it.
+    """
+
+    _instance = None
+    _need_init = True
+
+    def __new__(cls, *o, **k):
+        # make this a singleton. There is only a single
+        # reference to the dynamic library.
+        if Driver._instance is None:
+            Driver._instance = object.__new__(cls)
+        return Driver._instance
+
     def __init__(self):
-        self.ctx = None
+        if self._need_init:
+            ftdi_lib = find_library('ftdi')
+            if ftdi_lib is None:
+                raise FtdiError('libftdi library not found')
+            fdll = CDLL(ftdi_lib)
+            # most args/return types are fine with the implicit
+            # int/void* which ctypes uses, but some need setting here
+            fdll.ftdi_get_error_string.restype = c_char_p
+            fdll.ftdi_new.restype = c_void_p
+            fdll.ftdi_free.argtypes = (c_void_p,)
+            fdll.ftdi_usb_get_strings.argtypes = (c_void_p, c_void_p,
+                                                  c_char_p, c_int,
+                                                  c_char_p, c_int,
+                                                  c_char_p, c_int)
+            self.fdll = fdll
+        self._need_init = False
 
     def list_devices(self):
         """
         # (*next/*usb_device) of usb_devices, each of which can
         # be passed to ftdi_usb_get_strings() to get info about
         # them.
+        # this will contain the device info to return
+        devices = []
         manuf = create_string_buffer(128)
         desc = create_string_buffer(128)
         serial = create_string_buffer(128)
-        ctx = create_string_buffer(1024)
-        fdll.ftdi_init(byref(ctx))
-        usbdevlist = POINTER(UsbDevList)
-        devlistptrtype = pointer(usbdevlist)
-        dev_list_ptr = devlistptrtype()
-        res = fdll.ftdi_usb_find_all(byref(ctx), byref(dev_list_ptr), 0x0403, 0x6001)
-        if res < 0:
-            fdll.ftdi_deinit(byref(self.ctx))
-            raise ftdierror(fdll.ftdi_get_error_string(byref(self.ctx)))
-        # we'll add the info here.
-        devices = []
-        # take a copy of the dev_list for subsequent list_free
-        dev_list_base = pointer(dev_list_ptr.contents)
-        # traverse the linked list...
-        try:
-            while dev_list_ptr:
-                fdll.ftdi_usb_get_strings(byref(ctx), dev_list_ptr.contents.usb_dev,
-                        manuf,127, desc,127, serial,127)
-                devices.append((manuf.value, desc.value, serial.value))
-                # step to next in linked-list if not 
-                dev_list_ptr = cast(dev_list_ptr.contents.next, devlistptrtype)
-        finally:
-           fdll.ftdi_list_free(dev_list_base)
-        return devices
-
-class Driver(object):
-    """
-    This is where it all happens...
-    We load the libftdi library, and use it.
-    """
-
-    instance = None
-
-    def __init__(self):
-        ftdi_lib = find_library('ftdi')
-        if ftdi_lib is None:
-            raise FtdiError('libftdi library not found')
-        fdll = Follower(CDLL(ftdi_lib))
-        # most args/return types are fine with the implicit
-        # int/void* which ctypes uses, but some need setting here
-        fdll.ftdi_get_error_string.restype = c_char_p
-        fdll.ftdi_usb_get_strings.argtypes = (c_void_p, c_void_p,
-                                              c_char_p, c_int,
-                                              c_char_p, c_int,
-                                              c_char_p, c_int)
-        self.fdll = fdll
-        Driver.instance = self
-
-    def list_devices(self):
-        """
-        return a list of triples (manufacturer, description, serial#)
-        for each attached device, e.g.:
-        [('ftdi', 'um245r', 'fte00p4l'),
-         ('ftdi', 'um232r usb <-> serial', 'fte4ffvq')]
-
-        the serial number can be used to open specific devices
-        """
-        # ftdi_usb_find_all sets dev_list_ptr to a linked list
-        # (*next/*usb_device) of usb_devices, each of which can
-        # be passed to ftdi_usb_get_strings() to get info about
-        # them.
-        manuf = create_string_buffer(128)
-        desc = create_string_buffer(128)
-        serial = create_string_buffer(128)
-        ctx = create_string_buffer(1024)
-        self.fdll.ftdi_init(byref(ctx))
         devlistptrtype = POINTER(UsbDevList)
         dev_list_ptr = devlistptrtype()
-        res = self.fdll.ftdi_usb_find_all(byref(ctx), byref(dev_list_ptr), 0x0403, 0x6001)
-        if res < 0:
-            self.fdll.ftdi_deinit(byref(self.ctx))
-            raise ftdierror(self.fdll.ftdi_get_error_string(byref(self.ctx)))
-        # we'll add the info here.
-        devices = []
-        # take a copy of the dev_list for subsequent list_free
-        dev_list_base = pointer(dev_list_ptr.contents)
-        # traverse the linked list...
+
+        ctx = self.fdll.ftdi_new()
         try:
-            while dev_list_ptr:
-                self.fdll.ftdi_usb_get_strings(byref(ctx), dev_list_ptr.contents.usb_dev,
-                        manuf,127, desc,127, serial,127)
-                devices.append((manuf.value, desc.value, serial.value))
-                # step to next in linked-list if not 
-                dev_list_ptr = cast(dev_list_ptr.contents.next, devlistptrtype)
+            res = self.fdll.ftdi_usb_find_all(ctx, byref(dev_list_ptr), 0x0403, 0x6001)
+            if res < 0:
+                raise FtdiError(self.fdll.ftdi_get_error_string(ctx))
+            elif res > 0:
+                # take a copy of the dev_list for subsequent list_free
+                dev_list_base = pointer(dev_list_ptr.contents)
+                # traverse the linked list...
+                try:
+                    while dev_list_ptr:
+                        self.fdll.ftdi_usb_get_strings(ctx, dev_list_ptr.contents.usb_dev,
+                                manuf,127, desc,127, serial,127)
+                        devices.append((manuf.value, desc.value, serial.value))
+                        # step to next in linked-list if not
+                        dev_list_ptr = cast(dev_list_ptr.contents.next, devlistptrtype)
+                finally:
+                    self.fdll.ftdi_list_free(dev_list_base)
         finally:
-           self.fdll.ftdi_list_free(dev_list_base)
+            self.fdll.ftdi_free(ctx)
         return devices
 
 class Device(object):
     def __init__(self, mode="b", encoding="latin1"):
-        if Driver.instance is None:
-            # initialise it...
-            Driver()
-        self.ctx = self.fdll.ftdi_new()
-        if self.ctx == 0:
-            raise FtdiError("could not create new FTDI context")
+        self.driver = Driver()
+        self.fdll = self.driver.fdll
         self.opened = False
         # mode can be either 'b' for binary, or 't' for text.
         # if set to text, the values returned from read() will
         # standard for serial devices.
         self._baudrate = 9600
 
-    fdll = property(lambda self: Driver.instance.fdll)
+    def __del__(self):
+        "tell driver to free the ftdi_context resource"
+        if self.opened:
+            self.close()
 
     def open(self, device_id=None):
         """open connection to a FTDI device
         """
         if self.opened:
             return
+        # create context for this device
+        self.ctx = self.fdll.ftdi_new()
+        if self.ctx == 0:
+            raise FtdiError("could not create new FTDI context")
         # Try to open the device.  If this fails, reset things to how
         # they were, but we can't use self.close as that assumes things
         # have already been setup.
             open_args.extend([0, c_char_p(device_id.encode('latin1'))])
             res = self.fdll.ftdi_usb_open_desc(*tuple(open_args))
         if res != 0:
-            try:
-                raise FtdiError(self.fdll.ftdi_get_error_string(self.ctx))
-            finally:
-                self.fdll.ftdi_free(self.ctx)
-                self.ctx = None
+            raise FtdiError(self.fdll.ftdi_get_error_string(self.ctx))
         self.opened = True
 
     def close(self):
         "close our connection, free resources"
+        if self.opened:
+            self.fdll.ftdi_free(self.ctx)
         self.opened = False
-        if self.fdll.ftdi_usb_close(self.ctx) == 0:
-            self.fdll.ftdi_deinit(self.ctx)
 
     @property
     def baudrate(self):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.