def open(self, vendor, product, interface, direction, **kwargs): """ """ for k in ('direction',): if k in kwargs: del kwargs[k] try: ftdi = Ftdi() ftdi.open_bitbang(vendor, product, interface, direction=direction, **kwargs) self._ftdi = ftdi except IOError as e: raise GpioException('Unable to open USB port: %s' % str(e)) self._direction = direction
def open(self, vendor, product, interface, direction, **kwargs): """ """ for k in ('direction', ): if k in kwargs: del kwargs[k] try: ftdi = Ftdi() ftdi.open_bitbang(vendor, product, interface, direction=direction, **kwargs) self._ftdi = ftdi except IOError as e: raise GpioException('Unable to open USB port: %s' % str(e)) self._direction = direction
class BitBangController(object): PROGRAM_PIN = 0x20 SOFT_RESET_PIN = 0x40 def __init__(self, idVendor, idProduct, interface): #all pins are in high impedance self.vendor = idVendor self.product = idProduct self.interface = interface self.f = Ftdi() self.f.open_bitbang(idVendor, idProduct, interface) def hiz(self): print "changing pins to high impedance" def is_in_bitbang(self): return self.f.bitbang_enabled def read_pins(self): return self.f.read_pins() def read_program_pin(self): return (self.PROGRAM_PIN & self.f.read_pins() > 0) def soft_reset_high(self): pins = self.f.read_pins() pins |= self.SOFT_RESET_PIN prog_cmd = Array('B', [0x01, pins]) self.f.write_data(prog_cmd) def soft_reset_low(self): pins = self.f.read_pins() pins &= ~(self.SOFT_RESET_PIN) prog_cmd = Array('B', [0x00, pins]) self.f.write_data(prog_cmd) def program_high(self): pins = self.f.read_pins() pins |= self.PROGRAM_PIN prog_cmd = Array('B', [0x01, pins]) self.f.write_data(prog_cmd) def program_low(self): pins = self.f.read_pins() pins &= ~(self.PROGRAM_PIN) prog_cmd = Array('B', [0x00, pins]) self.f.write_data(prog_cmd) def read_soft_reset_pin(self): return (self.SOFT_RESET_PIN & self.f.read_pins() > 0) def set_soft_reset_to_output(self): pin_dir = self.SOFT_RESET_PIN self.f.open_bitbang(self.vendor, self.product, self.interface, direction = pin_dir) def set_program_to_output(self): pin_dir = self.PROGRAM_PIN self.f.open_bitbang(self.vendor, self.product, self.interface, direction = pin_dir) def set_pins_to_input(self): self.f.open_bitbang(self.vendor, self.product, self.interface, direction = 0x00) def set_pins_to_output(self): self.f.open_bitbang(self.vendor, self.product, self.interface, direction = 0xFF) def pins_on(self): prog_cmd = Array('B', [0x01, 0xFF]) self.f.write_data(prog_cmd) def pins_off(self): prog_cmd = Array('B', [0x01, 0x00]) self.f.write_data(prog_cmd)
class HapticStimulator(object): ''' Class to initialise and send commands to sensory stimulator built on FTDI FT2232HL with power trasistors board ("fMRI Pneumatic 5V version") from Politechnika Warszawska ''' def __init__(self, vendorid=VENDORID, productid=PRODUCTID, interface=DEFAULTINTERFACE): ''' Initialises FTDI device as Haptic Stimulator :param vendorid: int or hex NOT string gotten from lsusb for FTDI device :param productid: int or hex NOT string gotten from lsusb for FTDI device :param interface: int - for tested board is always 2''' self.ftdi = Ftdi() self.ftdi.open_bitbang(vendorid, productid, interface, direction=0xFF) # direction FF - all ports output self.lock = threading.RLock() self.ftdi.write_data([0]) # turn off all channels def __del__(self): self.close() def _turn_off(self, chnl): ''' Will turn off selected channel, used by stimulate method on on timer :param chnl: int - number of channel to turn off ''' with self.lock: apins = self.ftdi.read_pins() activation_mask = ~(1 << (chnl - 1)) & 0xFF #select only #needed channel self.ftdi.write_data([apins & activation_mask]) def stimulate(self, chnl, time): ''' Turn on stimulation on channel number chnl for time seconds :param chnl: integer - channel number starting from 1 :param time: float - stimulation length in seconds ''' t = threading.Timer(time, self._turn_off, [chnl]) # we expect #short times ~ seconds #handling timers #should not matter t.daemon = True # timer thread shall end immediately at main # program shutdown, because interface must be # closed by then and every channel turned off by # .close() method. No need to wait for # schedueled stimulation end. t.start() with self.lock: apins = self.ftdi.read_pins() activation_mask = 1 << (chnl - 1) # create byte with bit on # corresponding channel # enabled self.ftdi.write_data([apins | activation_mask]) #add active bit # to other active # channels def bulk_stimulate(self, chnls, times): ''' Enables multiple channels for some time in seconds len(chnls) should be equal to len(times) :param chnls: list of integers - channels to activate :param times: list of floats - activation time lenghts for corresponding channel ''' if len(chnls) != len(times): raise Exception( 'Stimulation channels and times are not the same length!') for c, t in zip(chnls, times): self.stimulate(c, t) def close(self): '''Releasing device''' self.ftdi.write_data([0]) # turn off all channels self.ftdi.usb_dev.reset() # release device
class GPIOController(object): def __init__(self, vendor, product, interface = 0): self.f = Ftdi() self.vendor = vendor self.product = product self.interface = interface self.f.open_bitbang(self.vendor, self.product, self.interface) def read_pins(self): """ Read all pins Args: Nothing Returns (int): All pins """ return self.f.read_pins() def read_pin(self, bit_index): """ Reads the pin specified by bit index: Args: bit_index (int): 0 - 15 Returns (Boolean) True if set False if not set """ bit_mask = 1 << bit_index return (self.f.read_pins() & bit_mask > 0) def enable_pin(self, bit_index, enable): """ write out a single pin Args: bit_index (int): Index of bit to set enable (Boolean): True: Set False: Clear Returns: Nothing """ bit_mask = 1 << bit_index pins = self.f.read_pins() if enable: pins |= bit_mask else: pins &= ~bit_mask self.enable_pins(pins, enable) def enable_pins(self, bit_mask, enable): """ write out multiple pins at one time Args: bit_mask: The set of pins to be set or not set a 0 in a bit setting would set the pin low a 1 in a bit setting would set the pin high Returns: Nothing Example: enable_pins(bit_mask = 0x11) would set pins at address 0 and at address 4 high while the rest would be low """ bit_mask = 0xFF & bit_mask if enable: self.f.write_data(Array('B', [0x01, bit_mask])) else: self.f.write_data(Array('B', [0x00, bit_mask])) def set_pin_direction_mask(self, pins): """ Configure the GPIO direction Args: pins (integer): bitmask of pin direction 1 = output, 0 = input Returns: Nothing Example: Set bit 0 and bit 4 set_pin_direction_mask(0x11) Returns: """ self.f.open_bitbang(self.vendor, self.product, self.interface, direction = pins)
class HapticStimulator(object): ''' Class to initialise and send commands to sensory stimulator built on FTDI FT2232HL with power trasistors board ("fMRI Pneumatic 5V version") from Politechnika Warszawska ''' def __init__(self, vendorid=VENDORID, productid=PRODUCTID, interface=DEFAULTINTERFACE): ''' Initialises FTDI device as Haptic Stimulator :param vendorid: int or hex NOT string gotten from lsusb for FTDI device :param productid: int or hex NOT string gotten from lsusb for FTDI device :param interface: int - for tested board is always 2''' self.ftdi = Ftdi() self.ftdi.open_bitbang(vendorid, productid, interface, direction = 0xFF) # direction FF - all ports output self.lock = threading.RLock() self.ftdi.write_data([0]) # turn off all channels def __del__(self): self.close() def _turn_off(self, chnl): ''' Will turn off selected channel, used by stimulate method on on timer :param chnl: int - number of channel to turn off ''' with self.lock: apins = self.ftdi.read_pins() activation_mask = ~(1 << (chnl-1)) & 0xFF #select only #needed channel self.ftdi.write_data([apins & activation_mask]) def stimulate(self, chnl, time): ''' Turn on stimulation on channel number chnl for time seconds :param chnl: integer - channel number starting from 1 :param time: float - stimulation length in seconds ''' t = threading.Timer(time, self._turn_off, [chnl]) # we expect #short times ~ seconds #handling timers #should not matter t.daemon = True # timer thread shall end immediately at main # program shutdown, because interface must be # closed by then and every channel turned off by # .close() method. No need to wait for # schedueled stimulation end. t.start() with self.lock: apins = self.ftdi.read_pins() activation_mask = 1 << (chnl-1) # create byte with bit on # corresponding channel # enabled self.ftdi.write_data([apins | activation_mask]) #add active bit # to other active # channels def bulk_stimulate(self, chnls, times): ''' Enables multiple channels for some time in seconds len(chnls) should be equal to len(times) :param chnls: list of integers - channels to activate :param times: list of floats - activation time lenghts for corresponding channel ''' if len(chnls) != len(times): raise Exception( 'Stimulation channels and times are not the same length!' ) for c, t in zip(chnls, times): self.stimulate(c, t) def close(self): '''Releasing device''' self.ftdi.write_data([0]) # turn off all channels self.ftdi.usb_dev.reset() # release device
class LaserPointer: """Class for controlling a laser pointer via an FTDI device. This class allows a laser pointer to be controlled by toggling the state of a pin on an FTDI USB Serial device in bitbang mode. Attributes: laser_pin: An integer bitmask with a single bit set corresponding to the pin that the laser pointer is controlled by. See the set of constants defined at the top of this source file. ftdi: An object of type pyftdi.ftdi.Ftdi. """ def __init__(self, ftdi_pid='232r', serial_num=None, laser_pin=PIN_CTS): """Inits LaserPointer object. Initializes a LaserPointer object by constructing an Ftdi object and opening the desired FTDI device. Configures the FTDI device to bitbang mode. Args: ftdi_pid: Product ID string for the FTDI device. serial_num: String containing the serial number of the FTDI device. If None, any serial number will be accepted. laser_pin: Integer bit mask with a single bit set corresponding to the pin on the FTDI device that controls the laser pointer. """ self.laser_pin = laser_pin self.ftdi = Ftdi() self.ftdi.open_bitbang( vendor=Ftdi.VENDOR_IDS['ftdi'], product=Ftdi.PRODUCT_IDS[Ftdi.FTDI_VENDOR][ftdi_pid], serial=serial_num, # serial number of FT232RQ in the laser FTDI cable latency=Ftdi.LATENCY_MAX, # 255ms; reduce if necessary (at cost of higher CPU usage) ) # set laser_pin as output, all others as inputs self.ftdi.set_bitmode(self.laser_pin, Ftdi.BitMode.BITBANG) assert self.ftdi.bitbang_enabled # make sure laser is disabled by default self.set(False) def __del__(self): """Try to make sure laser is disabled on shutdown.""" try: self.set(False) self.ftdi.close() except AttributeError: # happens when no laser was present at construction time pass except Exception as e: # pylint: disable=broad-except print('Got exception while trying to disable laser pointer: ' + str(e)) def set(self, enable): """Sets the state of the laser pointer. Args: enable: Laser pointer will be turned on when True and off when False. """ if enable: self.ftdi.write_data(bytes([0x00])) else: self.ftdi.write_data(bytes([self.laser_pin])) def get(self): """Gets the current state of the laser pointer. This reads the current state from FTDI device and does not rely on any state information in this class. Returns: The current state of the laser pointer as a boolean. """ return (self.ftdi.read_pins() & self.laser_pin) == 0x0