Commits

Ben Bass  committed e119a40

updates, refactoring, pyflakes fixes

  • Participants
  • Parent commits 1f9e8c5

Comments (0)

Files changed (12)

File LICENSE

-Copyright (c) 2010 Ben Bass
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-
-
-http://www.opensource.org/licenses/mit-license.php
+Copyright (c) 2010 Ben Bass
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+
+http://www.opensource.org/licenses/mit-license.php

File MANIFEST

-LICENSE
-README
-examples/lcd.py
-examples/led_flash.py
-setup.py
-pylibftdi/__init__.py
+include *.txt
+recursive-include examples *.txt *.py

File README

-pylibftdi
-=========
-
-Copyright (c) 2010 Ben Bass <benbass@codedstructure.net>
-
-All rights reserved.
-
-
-License information
--------------------
-
-See the file "LICENSE" for information terms & conditions
-for usage, and a DISCLAIMER OF ALL WARRANTIES.
-
-All trademarks referenced herein are property of their respective
-holders.
-
-libFTDI itself is developed by Intra2net AG.  No association with
-Intra2net is claimed or implied, but I have found their library
-helpful and had fun with it...
-
-History
--------
-This package is the result of various bits of work using FTDI's
-devices, primarily for controlling external devices.  Some of this
-is documented on the codedstructure blog, codedstructure.blogspot.com
-
-At least two other open-source Python FTDI wrappers exist, and each
-of these may be best for some projects.
-
-ftd2xx - http://pypi.python.org/pypi/ftd2xx
- - ctypes binding to FTDI's own D2XX driver
-pyftdi - http://git.marcansoft.com/?p=pyftdi.git
- - a C extension libftdi binding
-
-pylibftdi exists in the gap between these two projects; ftd2xx uses
-the (closed-source) D2XX driver, but provides a high-level Python
-interface, while pyftdi works with libftdi but is very low-level.
-The aim for pylibftdi is to work with the libftdi, but to provide
-a high-level Pythonic interface.  Various wrappers and utility
-functions are also part of the distribution; following Python's
-batteries included approach, there are various interesting devices
-supported out-of-the-box.
-
-Plans
------
- * Add more examples: SPI devices, knight-rider effects, input devices...
- * Further support for serial usage (as opposed to BitBang)
- * Perhaps add support for D2XX driver, though the name then becomes a
-   slight liability ;)
-
-Changes
--------
-0.4.1
- * fix release issue
-0.4
- * fixed embarrassing bug which caused things not to work on Linux 
-   (is now find_library('ftdi') instead of find_library('libftdi'))
- * lots of error checking, new FtdiError exception. Before it just
-   tended to segfault if things weren't just-so.
- * get_error() is now get_error_string().  It's still early enough
-   to change the API, and if I thought it was get_error_string
-   multiple times when I wrote the error checking code, it probably
-   should be the more natural thing.
-0.3
- * added some examples
- * new Bus class in pylibftdi (though it probably belongs somewhere else)
- * first release on PyPI
-0.2
- * fixed various bugs
- * added ftdi_fn and set_baudrate functions in Driver class
- * changed interface in BitBangDriver to direction/port properties
-   rather than overriding the read/write functions, which are therefore
-   still available as in the Driver class.
-0.1
- * first release. Tested with libftdi 0.18 on Mac OS X 10.6 and Linux
-  (stock EEEPC 701 Xandros Linux, Ubuntu 10.04)
+pylibftdi
+=========
+
+Copyright (c) 2010 Ben Bass <benbass@codedstructure.net>
+
+All rights reserved.
+
+
+License information
+-------------------
+
+See the file "LICENSE" for information terms & conditions
+for usage, and a DISCLAIMER OF ALL WARRANTIES.
+
+All trademarks referenced herein are property of their respective
+holders.
+
+libFTDI itself is developed by Intra2net AG.  No association with
+Intra2net is claimed or implied, but I have found their library
+helpful and had fun with it...
+
+History
+-------
+This package is the result of various bits of work using FTDI's
+devices, primarily for controlling external devices.  Some of this
+is documented on the codedstructure blog, codedstructure.blogspot.com
+
+At least two other open-source Python FTDI wrappers exist, and each
+of these may be best for some projects.
+
+ftd2xx - http://pypi.python.org/pypi/ftd2xx
+ - ctypes binding to FTDI's own D2XX driver
+pyftdi - http://git.marcansoft.com/?p=pyftdi.git
+ - a C extension libftdi binding
+
+pylibftdi exists in the gap between these two projects; ftd2xx uses
+the (closed-source) D2XX driver, but provides a high-level Python
+interface, while pyftdi works with libftdi but is very low-level.
+The aim for pylibftdi is to work with the libftdi, but to provide
+a high-level Pythonic interface.  Various wrappers and utility
+functions are also part of the distribution; following Python's
+batteries included approach, there are various interesting devices
+supported out-of-the-box.
+
+Plans
+-----
+ * Add more examples: SPI devices, knight-rider effects, input devices...
+ * Further support for serial usage (as opposed to BitBang)
+ * Perhaps add support for D2XX driver, though the name then becomes a
+   slight liability ;)
+
+Changes
+-------
+0.4.1
+ * fix release issue
+0.4
+ * fixed embarrassing bug which caused things not to work on Linux 
+   (is now find_library('ftdi') instead of find_library('libftdi'))
+ * lots of error checking, new FtdiError exception. Before it just
+   tended to segfault if things weren't just-so.
+ * get_error() is now get_error_string().  It's still early enough
+   to change the API, and if I thought it was get_error_string
+   multiple times when I wrote the error checking code, it probably
+   should be the more natural thing.
+0.3
+ * added some examples
+ * new Bus class in pylibftdi (though it probably belongs somewhere else)
+ * first release on PyPI
+0.2
+ * fixed various bugs
+ * added ftdi_fn and set_baudrate functions in Driver class
+ * changed interface in BitBangDriver to direction/port properties
+   rather than overriding the read/write functions, which are therefore
+   still available as in the Driver class.
+0.1
+ * first release. Tested with libftdi 0.18 on Mac OS X 10.6 and Linux
+  (stock EEEPC 701 Xandros Linux, Ubuntu 10.04)

File pylibftdi/__init__.py

 rather than a problem with the libftdi library.
 """
 
-__VERSION__ = "0.4.1"
+__VERSION__ = "0.5"
 __AUTHOR__ = "Ben Bass"
 
 
 __ALL__ = ['Driver', 'BitBangDriver', 'Bus', 'ALL_OUTPUTS', 'ALL_INPUTS']
 
-import functools
-from ctypes import *
-from ctypes.util import find_library
-
-class Refuser(object):
-    def __getattribute__(self, key):
-        # perhaps we should produce an appropriate quote at random...
-        raise TypeError(object.__getattribute__(self, 'message'))
-    def __setattr__(self, key, val):
-        raise TypeError(object.__getattribute__(self, 'message'))
-    def __call__(self, *o, **kw):
-        raise TypeError(object.__getattribute__(self, 'message'))
-
-class ParrotEgg(Refuser):
-    message = "This object is not yet... (missing open()?)"
-
-class DeadParrot(Refuser):
-    message = "This object is no more!"
-
-class FtdiError(Exception):
-    pass
-
-class Driver(object):
-    def __init__(self):
-        self.ctx = None
-        self.fdll = ParrotEgg()
-        self.opened = False
-        # ftdi_usb_open_dev initialises the device baudrate
-        # to 9600, which certainly seems to be a de-facto
-        # standard for serial devices.
-        self._baudrate = 9600
-
-    def open(self):
-        "open connection to a FTDI device"
-        if self.opened:
-            return self
-        # TODO: provide parameter to select required device
-        # (if multiple are attached)
-        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
-        # 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.
-        # sizeof(struct ftdi_context) seems to be 112 on x86_64, 84 on i386
-        # provide a generous 1K buffer for (hopefully) all possibles...
-        self.ctx = create_string_buffer(1024)
-        if fdll.ftdi_init(byref(self.ctx)) != 0:
-            raise FtdiError(fdll.ftdi_get_error_string(byref(self.ctx)))
-        if fdll.ftdi_usb_open(byref(self.ctx), 0x0403, 0x6001) != 0:
-            fdll.ftdi_deinit(byref(self.ctx))
-            raise FtdiError(fdll.ftdi_get_error_string(byref(self.ctx)))
-        # only at this point do we allow other things to access fdll.
-        # (so if exception is thrown above, there is no access).
-        self.fdll = fdll
-        self.opened = True
-        return self
-
-    def close(self):
-        "close our connection, free resources"
-        self.opened = False
-        if self.fdll.ftdi_usb_close(byref(self.ctx)) == 0:
-            self.fdll.ftdi_deinit(byref(self.ctx))
-        self.fdll = DeadParrot()
-
-    @property
-    def baudrate(self):
-        return self._baudrate
-    @baudrate.setter
-    def baudrate(self, value):
-        result = self.fdll.ftdi_set_baudrate(byref(self.ctx), value)
-        if result == 0:
-            self._baudrate = value
-
-    def read(self, length):
-        "read a string of upto length bytes from the FTDI device"
-        buf = create_string_buffer(length)
-        rlen = self.fdll.ftdi_read_data(byref(self.ctx), byref(buf), length)
-        if rlen == -1:
-            raise FtdiError(self.get_error_string())
-        return buf.raw[:rlen]
-
-    def write(self, data):
-        "write given data string to the FTDI device"
-        buf = create_string_buffer(data)
-        written = self.fdll.ftdi_write_data(byref(self.ctx),
-                                            byref(buf), len(data))
-        if written == -1:
-            raise FtdiError(self.get_error_string())
-        return written
-
-    def get_error_string(self):
-        "return error string from libftdi driver"
-        return self.fdll.ftdi_get_error_string(byref(self.ctx))
-
-    @property
-    def ftdi_fn(self):
-        """
-        this allows the vast majority of libftdi functions
-        which are called with a pointer to a ftdi_context
-        struct as the first parameter to be called here
-        in a nicely encapsulated way:
-        >>> with FtdiDriver() as drv:
-        >>>     # set 8 bit data, 2 stop bits, no parity
-        >>>     drv.ftdi_fn.ftdi_set_line_property(8, 2, 0)
-        >>>     ...
-        """
-        # note this class is constructed on each call, so this
-        # won't be particularly quick.  It does ensure that the
-        # fdll and ctx objects in the closure are up-to-date, though.
-        class FtdiForwarder(object):
-            def __getattr__(innerself, key):
-                 return functools.partial(getattr(self.fdll, key),
-                                          byref(self.ctx))
-        return FtdiForwarder()
-
-    def __enter__(self):
-        "support for context manager"
-        return self.open()
-
-    def __exit__(self, exc_type, exc_val, tb):
-        "support for context manager"
-        self.close()
-
-ALL_OUTPUTS = 0xFF
-ALL_INPUTS = 0x00
-
-class BitBangDriver(Driver):
-    """
-    simple subclass to support bit-bang mode
-    
-    Only uses async mode at the moment.
-    
-    Adds two read/write properties to the base class:
-     direction: 8 bit input(0)/output(1) direction control.
-     port: 8 bit IO port, as defined by direction.
-    """
-    def __init__(self, direction = ALL_OUTPUTS):
-        super(BitBangDriver, self).__init__()
-        self.direction = direction
-        self._latch = 0
-
-    def open(self):
-        # in case someone sets the direction before we are open()ed,
-        # we intercept this call...
-        super(BitBangDriver, self).open()
-        if self._direction:
-            self.direction = self._direction
-        return self
-
-    @property
-    def direction(self):
-        return self._direction
-    @direction.setter
-    def direction(self, dir):
-        assert 0 <= dir <= 255, 'invalid direction bitmask'
-        self._direction = dir
-        if self.opened:
-            self.fdll.ftdi_set_bitmode(byref(self.ctx), dir, 0x01)
-
-    @property
-    def port(self):
-        result = ord(super(BitBangDriver, 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
-        result = (result & ~self._direction) | (self._latch & self._direction)
-        return result
-    @port.setter
-    def port(self, value):
-        self._latch = value
-        return super(BitBangDriver, self).write(chr(value))
-
-
-class Bus(object):
-    """
-    This class is a descriptor for a bus of a given width starting
-    at a given offset (0 = LSB).  Thet driver which does the actual
-    reading and writing is assumed to be a BitBangDriver instance
-    in the 'driver' attribute of the object to which this is attached.
-    """
-    def __init__(self, offset, width=1):
-        self.offset = offset
-        self.width = width
-        self._mask = ((1<<width)-1)
-
-    def __get__(self, obj, type):
-        val = obj.driver.port
-        return (val >> offset) & self._mask
-
-    def __set__(self, obj, value):
-        value = value & self._mask
-        # in a multi-threaded environment, would
-        # want to ensure following was locked, eg
-        # by acquiring a driver lock
-        val = obj.driver.port
-        val &= ~(self._mask << self.offset)
-        val |= value << self.offset
-        obj.driver.port = val
+from pylibftdi.util import Bus
+from pylibftdi.driver import Driver
+from pylibftdi.bitbang import BitBangDriver, ALL_OUTPUTS, ALL_INPUTS

File pylibftdi/_base.py

+
+
+__ALL__ = ['Refuser', 'ParrotEgg', 'DeadParrot', 'FtdiError']
+
+class Refuser(object):
+    def __getattribute__(self, key):
+        # perhaps we should produce an appropriate quote at random...
+        raise TypeError(object.__getattribute__(self, 'message'))
+    def __setattr__(self, key, val):
+        raise TypeError(object.__getattribute__(self, 'message'))
+    def __call__(self, *o, **kw):
+        raise TypeError(object.__getattribute__(self, 'message'))
+
+class ParrotEgg(Refuser):
+    message = "This object is not yet... (missing open()?)"
+
+class DeadParrot(Refuser):
+    message = "This object is no more!"
+
+class FtdiError(Exception):
+    pass
+
+
+

File pylibftdi/bitbang.py

+
+from pylibftdi.driver import Driver
+from ctypes import byref 
+
+ALL_OUTPUTS = 0xFF
+ALL_INPUTS = 0x00
+BB_OUTPUT = 1
+BB_INPUT = 0
+
+class BitBangDriver(Driver):
+    """
+    simple subclass to support bit-bang mode
+    
+    Only uses async mode at the moment.
+    
+    Adds two read/write properties to the base class:
+     direction: 8 bit input(0)/output(1) direction control.
+     port: 8 bit IO port, as defined by direction.
+    """
+    def __init__(self, direction = ALL_OUTPUTS):
+        super(BitBangDriver, self).__init__()
+        self.direction = direction
+        self._latch = 0
+
+    def open(self):
+        # in case someone sets the direction before we are open()ed,
+        # we intercept this call...
+        super(BitBangDriver, self).open()
+        if self._direction:
+            self.direction = self._direction
+        return self
+
+    # direction property - 8 bit value determining whether an IO line
+    # is output (if set to 1) or input (set to 0)
+    @property
+    def direction(self):
+        return self._direction
+    @direction.setter
+    def direction(self, dir):
+        assert 0 <= dir <= 255, 'invalid direction bitmask'
+        self._direction = dir
+        if self.opened:
+            self.fdll.ftdi_set_bitmode(byref(self.ctx), dir, 0x01)
+
+    # port property - 8 bit read/write value
+    @property
+    def port(self):
+        result = ord(super(BitBangDriver, 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
+        result = (result & ~self._direction) | (self._latch & self._direction)
+        return result
+    @port.setter
+    def port(self, value):
+        self._latch = value
+        return super(BitBangDriver, self).write(chr(value))
+

File pylibftdi/driver.py

+
+
+import functools
+# be disciplined so pyflakes can check us...
+from ctypes import (CDLL, byref, c_char_p, create_string_buffer)
+from ctypes.util import find_library
+
+from pylibftdi.base import ParrotEgg, DeadParrot, FtdiError
+
+class Driver(object):
+    def __init__(self):
+        self.ctx = None
+        self.fdll = ParrotEgg()
+        self.opened = False
+        # ftdi_usb_open_dev initialises the device baudrate
+        # to 9600, which certainly seems to be a de-facto
+        # standard for serial devices.
+        self._baudrate = 9600
+
+    def open(self):
+        "open connection to a FTDI device"
+        if self.opened:
+            return self
+        # TODO: provide parameter to select required device
+        # (if multiple are attached)
+        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
+        # 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.
+        # sizeof(struct ftdi_context) seems to be 112 on x86_64, 84 on i386
+        # provide a generous 1K buffer for (hopefully) all possibles...
+        self.ctx = create_string_buffer(1024)
+        if fdll.ftdi_init(byref(self.ctx)) != 0:
+            raise FtdiError(fdll.ftdi_get_error_string(byref(self.ctx)))
+        if fdll.ftdi_usb_open(byref(self.ctx), 0x0403, 0x6001) != 0:
+            fdll.ftdi_deinit(byref(self.ctx))
+            raise FtdiError(fdll.ftdi_get_error_string(byref(self.ctx)))
+        # only at this point do we allow other things to access fdll.
+        # (so if exception is thrown above, there is no access).
+        self.fdll = fdll
+        self.opened = True
+        return self
+
+    def close(self):
+        "close our connection, free resources"
+        self.opened = False
+        if self.fdll.ftdi_usb_close(byref(self.ctx)) == 0:
+            self.fdll.ftdi_deinit(byref(self.ctx))
+        self.fdll = DeadParrot()
+
+    @property
+    def baudrate(self):
+        return self._baudrate
+    @baudrate.setter
+    def baudrate(self, value):
+        result = self.fdll.ftdi_set_baudrate(byref(self.ctx), value)
+        if result == 0:
+            self._baudrate = value
+
+    def read(self, length):
+        "read a string of upto length bytes from the FTDI device"
+        buf = create_string_buffer(length)
+        rlen = self.fdll.ftdi_read_data(byref(self.ctx), byref(buf), length)
+        if rlen == -1:
+            raise FtdiError(self.get_error_string())
+        return buf.raw[:rlen]
+
+    def write(self, data):
+        "write given data string to the FTDI device"
+        buf = create_string_buffer(data)
+        written = self.fdll.ftdi_write_data(byref(self.ctx),
+                                            byref(buf), len(data))
+        if written == -1:
+            raise FtdiError(self.get_error_string())
+        return written
+
+    def get_error_string(self):
+        "return error string from libftdi driver"
+        return self.fdll.ftdi_get_error_string(byref(self.ctx))
+
+    @property
+    def ftdi_fn(self):
+        """
+        this allows the vast majority of libftdi functions
+        which are called with a pointer to a ftdi_context
+        struct as the first parameter to be called here
+        in a nicely encapsulated way:
+        >>> with FtdiDriver() as drv:
+        >>>     # set 8 bit data, 2 stop bits, no parity
+        >>>     drv.ftdi_fn.ftdi_set_line_property(8, 2, 0)
+        >>>     ...
+        """
+        # note this class is constructed on each call, so this
+        # won't be particularly quick.  It does ensure that the
+        # fdll and ctx objects in the closure are up-to-date, though.
+        class FtdiForwarder(object):
+            def __getattr__(innerself, key):
+                 return functools.partial(getattr(self.fdll, key),
+                                          byref(self.ctx))
+        return FtdiForwarder()
+
+    def __enter__(self):
+        "support for context manager"
+        return self.open()
+
+    def __exit__(self, exc_type, exc_val, tb):
+        "support for context manager"
+        self.close()
+

File pylibftdi/util.py

+class Bus(object):
+    """
+    This class is a descriptor for a bus of a given width starting
+    at a given offset (0 = LSB).  Thet driver which does the actual
+    reading and writing is assumed to be a BitBangDriver instance
+    in the 'driver' attribute of the object to which this is attached.
+    """
+    def __init__(self, offset, width=1):
+        self.offset = offset
+        self.width = width
+        self._mask = ((1<<width)-1)
+
+    def __get__(self, obj, type):
+        val = obj.driver.port
+        return (val >> self.offset) & self._mask
+
+    def __set__(self, obj, value):
+        value = value & self._mask
+        # in a multi-threaded environment, would
+        # want to ensure following was locked, eg
+        # by acquiring a driver lock
+        val = obj.driver.port
+        val &= ~(self._mask << self.offset)
+        val |= value << self.offset
+        obj.driver.port = val
+
 
 setup(
     name="pylibftdi",
-    version="0.4.1",
+    version="0.5",
     description="Pythonic interface to FTDI devices using libftdi",
     author="Ben Bass",
     author_email="benbass@codedstructure.net",