FTDI Switching Devices

pybarst.ftdi.switch

FTDI Switch

The FTDI switch module controls digital switching devices that are connected to a FTDI digital port. These devices could be the FTDI digital input and output pins themselves, or digital input and output devices connected and controlled by the FTDI digital pins.

class pybarst.ftdi.switch.FTDIPin

Bases: pybarst.ftdi.FTDIDevice

The base for the devices that directly control the states of the pins of the FTDI channels. See PinSettings for details on this type of device.

open_channel(self)

See open_channel() for details.

class pybarst.ftdi.switch.FTDIPinIn

Bases: pybarst.ftdi.switch.FTDIPin

Reads the states of the digital pins on the FTDI channel controlled by FTDIChannel. See PinSettings for details on the device type.

For example:

>>> # create a settings class to read 2 byte slices from the FTDI channel. Only the pins 0 - 3 will be read.
>>> settings = PinSettings(num_bytes=2, bitmask=0x0F, continuous=False, output=False)
>>> # now create the channel
>>> ft = FTDIChannel(channels=[settings], server=server, desc='Birch Board rev1 A')
>>> dev = ft.open_channel(alloc=True)[0]
>>> print dev
<pybarst.ftdi.switch.FTDIPinIn object at 0x0277C830>
>>> # open the channel for this client
dev.open_channel()
>>> # set the global state of the device to active so we can read it
>>> dev.set_state(True)
>>> time, (byte1, byte2) = dev.read()
>>> print 'time: {}, byte1: 0b{:08b}, byte2: 0b{:08b}'.format(time, byte1, byte2)
time: 1.25523419394, byte1: 0b00001011, byte2: 0b00001011
>>> time, (byte1, byte2) = dev.read()
>>> print 'time: {}, byte1: 0b{:08b}, byte2: 0b{:08b}'.format(time, byte1, byte2)
time: 1.25621763275, byte1: 0b00001100, byte2: 0b00001100

In the last read above, it returned 0b00001100, which means that pins 0, and 1 are low and pins 2, and 3 are high. Pins 4 - 7 are not under the control of the device, so they always return 0.

The reason for being able to read more than one byte at once (2 in the example above) is to enable reading the states very quickly, i.e. at the device’s baud rate. E.g. if the baud rate has a clock rate of 1MHz, the bytes are read 2 us apart, vs having to trigger repeatedly which might result in reading them ms apart.

cancel_read(self, flush=False)

See FTDISerializerIn.cancel_read() for details.

This method is only callable when PinSettings.continuous is True.

read(self)

Requests the server to read the pins from the FTDI channel. This method will wait until the server sends data, or an error message, thereby tying up this thread.

If PinSettings.continuous is False, each call triggers the server to read from the device which is then sent to the client. If PinSettings.continuous is True, after the first call to read() the server will continuously read from the device and send the results back to the client. This means that if the client doesn’t call read() frequently enough data will accumulate in the pipe. Also, the data returned might have been acquired before the current read() was called.

To cancel a read request while the read is still waiting, from another thread you must call close_channel_client(), or close_channel_server(), or just delete the server, which will cause this method to return with an error.

A more gentle way of canceling a read request while not currently waiting in read(), is to call set_state() to set it inactive, or cancel_read(), both of which will cause the next read operation to return with an error, but will not delete/close the channel. For the latter method, once read() returned with an error, a further call to read() will cause the reading to start again. See those methods for more details.

Before this method can be called, FTDIPin.open_channel() must be called and the device must be set to active with set_state().

Returns:2-tuple of (time, data). time is the time that the data was read in server time, pybarst.core.server.BarstServer.clock(). data is a list of size PinSettings.num_bytes, where each element corresponds to a bit field of the states of the pins. See class description.
class pybarst.ftdi.switch.FTDIPinOut

Bases: pybarst.ftdi.switch.FTDIPin

Sets the states of the pins on the FTDI channel controlled by FTDIChannel. See PinSettings for details on the device type.

For example:

>>> # create a settings class to write 1 byte to the pins of the FTDI channel. Only the pins 4 - 7 will be set by this device.
>>> settings = PinSettings(bitmask=0xF0, init_val=0b01100000, output=True)
>>> # now create the channel
>>> ft = FTDIChannel(channels=[settings], server=server, desc='Birch Board rev1 A')
>>> dev = ft.open_channel(alloc=True)[0]
>>> print dev
<pybarst.ftdi.switch.FTDIPinOut object at 0x0277C830>
>>> # open the channel for this client
>>> dev.open_channel()
>>> # set the global state of the device to active so we can write
>>> dev.set_state(True)
# now set pins 4, and 5 to high
>>> print dev.write(buff_mask=0xFF, buffer=[0b00110000])
0.0107669098094
write(self, data=[], buff_mask=None, buffer=[])

Tells the server to update the states of some digital pins on the FTDI channel.

Before this method can be called, FTDIPin.open_channel() must be called and the device must be set to active with set_state().

There are two parameters by which data can be written, data, or alternatively buff_mask combined with buffer. In each case, you can specify which of the pins this device controls should be changed, as well as the exact values they should take. The total number of bytes written cannot exceed PinSettings.num_bytes.

Parameters:
data: list

data is a list of 3-tuples to be written. Each tuple has 3 elements: (repeat, value, mask).

repeat: int

The number of times this data point will be replicated, i.e. if it’s 5, the byte will be written 5 times in succession.

value: 8-bit int

The bit-mask to set the pins controlled by this device. I.e. 0b01001000 will set pins 3 and 6 to high and the remaining low.

mask: 8-bit int

Indicates which pins to leave untouched (0), or update according to value (1). For example, if value is 0b01001000 and mask is 0b01110000, then pins 0 - 3, and 7 will remain unchanged, while pins 4, and 5 will be set low and pin 6 will be set high.

data defaults to an empty list, [].

buffer: list

The elements in the list are 8-bit integers which will be written in order at the channel’s chan_baudrate according to the buff_mask mask. The buff_mask parameter functions similarly to the data ‘s, mask parameter. Only pins which have a high value in buff_mask will be changed by the values in buffer, the others will remain the same.

Each element in buffer is similar to data ‘s, value parameter. A high value for the corresponding pin will set the pin high, and low otherwise.

buff_mask: 8-bit int

The mask which controls which pin’s state will be changed by the elements in buffer. E.g. a value of 0b01000001 means that only pin 0, and pin 6 can be changed by buffer, all the other pins will remain unchanged no matter their value in buffer.

Returns:

float. The server time, pybarst.core.server.BarstServer.clock(), when the data was written.

Note

Pins not controlled by this channel, will never be changed, no matter what their values were set here.

For example:

>>> # create a output device which controls pins 4 - 7. Initialize
>>> # them to 0b01100000 (pins 5, 6 high, pins 4, 7 low).
>>> write = PinSettings(bitmask=0xF0, init_val=0b01100000, output=True)
>>> # create a reading device which will read the same pins
>>> # controlled by the output device
>>> read = PinSettings(bitmask=0xF0)
>>> ft = FTDIChannel(channels=[read, write], server=server, desc='Birch Board rev1 A')
>>> read, write = ft.open_channel(alloc=True)
>>> print read, write
<pybarst.ftdi.switch.FTDIPinIn object at 0x0277C830> <pybarst.ftdi.switch.FTDIPinOut object at 0x0277C930>
>>> # open and activate all the channels
>>> read.open_channel()
>>> read.set_state(True)
>>> write.open_channel()
>>> write.set_state(True)
>>> # read the current value, which should be the initialized one
>>> t, (val, ) = read.read()
>>> print 'read: {}, 0b{:08b}'.format(t, val)
read: 1.34129473928, 0b01100000
>>> # set the states of the pins
>>> print 'wrote: {}, 0b00110000'.format(write.write(buff_mask=0xFF, buffer=[0b00110000]))
wrote: 1.3422974773, 0b00110000
>>> t, (val, ) = read.read()
>>> print 'read: {}, 0b{:08b}'.format(t, val)
read: 1.34305835919, 0b00110000
>>> print 'wrote: {}, 0b10010000'.format(write.write(buff_mask=0xFF, buffer=[0b10010000]))
wrote: 1.34394612316, 0b10010000
>>> t, (val, ) = read.read()
>>> print 'read: {}, 0b{:08b}'.format(t, val)
read: 1.34467744028, 0b10010000
>>> # using the mask, only pins 6 and 7 will be changed, the other
>>> # pins will remain unchanged since they are 0 in buff_mask
>>> print 'wrote: {}, 0b00110000'.format(write.write(buff_mask=0b11000000, buffer=[0b11000000]))
wrote: 1.34564691796, 0b00110000
>>> t, (val, ) = read.read()
>>> print 'read: {}, 0b{:08b}'.format(t, val)
read: 1.34642093973, 0b11010000
class pybarst.ftdi.switch.FTDISerializer

Bases: pybarst.ftdi.FTDIDevice

The base for the serial to parallel type devices. See SerializerSettings for details on this type of device.

open_channel(self)

See open_channel() for details.

class pybarst.ftdi.switch.FTDISerializerIn

Bases: pybarst.ftdi.switch.FTDISerializer

Controls a serial to parallel (74HC589) input device connected to the FTDIChannel. See SerializerSettings for details on this device type.

For example:

>>> # create a settings class for the input device which has 2 74HC589
>>> # connected in a daisy chain fashion.
>>> settings = SerializerSettings(clock_bit=2, data_bit=3, latch_bit=6, num_boards=2, output=False)
>>> # now create the channel
>>> ft = FTDIChannel(channels=[settings], server=server, desc='Birch Board rev1 A')
>>> dev = ft.open_channel(alloc=True)[0]
>>> print dev
<pybarst.ftdi.switch.FTDISerializerIn object at 0x05288D30>
>>> # open the channel for this client
>>> dev.open_channel()
>>> # set the global state of the device to active so we can read it
>>> dev.set_state(True)
>>> print dev.read()
(7.350556310186866, [True, False, True, True, False, True, True, True, True, True, False, True, True, True, True, False])
>>> print dev.read()
(18.6506180676803, [True, False, False, True, False, True, False, True, True, False, True, True, True, True, False, False])
cancel_read(self, flush=False)

See cancel_read() for details.

This method is only callable when SerializerSettings.continuous is True.

Note

When flush is False, the server will continue sending data that has already been queued, but it will not add new data to the queue. After the last valid read, read() will return with an error indicating there’s no new data coming. After that error, a further call to read() will cause a new read request and data will start coming again.

If flush is True, the server will discard all data waiting to be sent, and the client will not receive the final error message when calling read(). Instead, a subsequent call to read() will cause a new read request to be sent to the server and data will start coming again.

read(self)

Requests the server to read from the serial to parallel input device. This method will wait until the server sends data or an error message, thereby tying up this thread.

If SerializerSettings.continuous is False, each call triggers the server to read from the device which is then sent to the client. If SerializerSettings.continuous is True, after the first call to read() the server will continuously read from the device and send the results back to the client. This means that if the client doesn’t call read() frequently enough data will accumulate in the pipe. Also, the data returned might have been acquired before the current read() was called.

To cancel a read request while the read is still waiting, from another thread you must call close_channel_client(), or close_channel_server(), or just delete the server, which will cause this method to return with an error.

A more gentle way of canceling a read request while not currently waiting in read(), is to call set_state() to set it inactive, or cancel_read(), both of which will cause the next read operation to return with an error, but will not delete/close the channel. For the latter method, once read() returned with an error, a further call to read() will cause the reading to start again. See those methods for more details.

Before this method can be called, FTDISerializer.open_channel() must be called and the device must be set to active with set_state().

Returns:2-tuple of (time, data). time is the time that the data was read in server time, pybarst.core.server.BarstServer.clock(). data is a list of size 8 * SerializerSettings.num_boards, where each element corresponds (True / False) to the state of the corresponding pin on the 75HC589.

The order in the list is for the lowest element, 0, to represent the closest (farthest)? port in the device.

class pybarst.ftdi.switch.FTDISerializerOut

Bases: pybarst.ftdi.switch.FTDISerializer

Controls a serial to parallel (74HC595) output device connected to the FTDIChannel. See SerializerSettings for details on that device type.

For example:

>>> # create a settings class for the output device which has 2 74HC595
>>> # connected in a daisy chain fashion.
>>> settings = SerializerSettings(clock_bit=2, data_bit=3, latch_bit=6, num_boards=2, output=True)
>>> # now create the channel
>>> ft = FTDIChannel(channels=[settings], server=server, desc='Birch Board rev1 A')
>>> dev = ft.open_channel(alloc=True)[0]
>>> print dev
<pybarst.ftdi.switch.FTDISerializerOut object at 0x0277C830>
>>> # open the channel for this client
>>> dev.open_channel()
>>> # set the global state of the device to active so we can write
>>> dev.set_state(True)
>>> # set the states of pins 0, 5, 15, 8 of the 595 to high, and the
>>> # pins 3, 9 to low. The states of the other pins remain unchanged.
>>> dev.write(set_high=[0, 5, 15, 8], set_low=[3, 9])
0.01900274788
# now set pins 2, 1 to high and pins 5, 14 to low.
>>> print dev.write(set_high=[2, 1], set_low=[5, 14])
0.0191407167483
write(self, set_high=[], set_low=[])

Tells the server to update the states of some pins on the 74HC595. Indices not listed in set_high or set_low remain unchanged.

Before this method can be called, FTDISerializer.open_channel() must be called and the device must be set to active with set_state().

Parameters:
set_high: list

A list of the pin indices to set to high. Each element in the list must be less than 8 * SerializerSettings.num_boards. The indices start at 0. Defaults to [].

set_low: list

A list of the pin indices to set to low. Each element in the list must be less than 8 * SerializerSettings.num_boards. The indices start at 0. Defaults to [].

Returns:

float. The server time, pybarst.core.server.BarstServer.clock(), when the data was written.

class pybarst.ftdi.switch.PinSettings(bitmask, num_bytes=1, init_val=0, continuous=False, output=False, **kwargs)

Bases: pybarst.ftdi.FTDISettings

The settings class for reading and writing directly to the FTDI digital pins. Each FTDI channel has digital pins which can be set as output or input and can then be read from or written to independently.

When an instance of this class is passed to a FTDIChannel in the channels parameter, it will create a FTDIPinIn or FTDIPinOut in devices, depending on the value of the output parameter.

Parameters:
num_bytes: unsigned short

The number of bytes that will be read from the USB bus for each read request at the chan_baudrate of the channel. When the device is an output device, this determines the maximum number of bytes that can be written at once with the channel’s chan_baudrate.

bitmask: unsigned char

A bit-mask of the pins that are active for this device, either as input or output depending on the pin type. The high bits will be the active pins for this device. E.g. if it’s 0b01000100 and this is a output device, it means that pins 2, and 6 are output pins and are controlled by this device. The other pins will not be under the device’s control.

Note

Both a FTDIPinIn and FTDIPinOut device can control the same pin, in which case the pin will function as output, but the FTDIPinIn will also be able to read that pin.

init_val: unsigned char

If this is an output device, it sets the initial values (high/low) of the device’s active pins, otherwise it’s ignored. For example if pins 1, and 5 are under control of the device, and the value is 0b01001011, then pin 1 will be initialized to high and pin 5 to low.

continuous: bool

Whether, when reading, we should continuously read and send data back to the client. This is only used for a input device (output is False). When True, a single call to FTDIPin.read() after the device is activated will start the server reading the device continuously and sending the data back to this client. This will result in a potentially higher sampling rate of the device. If it’s False, each call to FTDIPin.read() will trigger a new read resulting in a possibly slower reading rate.

output: bool

If the active pins of this device are inputs or outputs. If True, a FTDIPinOut will be created, otherwise a FTDIPinIn will be created by the FTDIChannel.

bitmask

bitmask: ‘unsigned char’

The pins that are active for this device, either as input or output depending on the pin type. The high bits will be the active pins for this device.

continuous

continuous: ‘int’

Whether, when reading, the server should continuously read and send data back to the client. This is only used for a input device (output is False). When True, a single call to FTDIPin.read() after the device is activated will start the server reading the device continuously and sending the data back to this client. This will result in a high sampling rate of the device. If it’s False, each call to FTDIPin.read() will trigger a new read resulting in a possibly slower reading rate.

init_val

init_val: ‘unsigned char’

If this is an output device, what the initial values (high/low) of the active pins will be.

num_bytes

num_bytes: ‘unsigned short’

The number of bytes that will be read from the USB bus for each read request. The bytes will be read at the chan_baudrate of the channel. When the device is an output device, this determines the maximum number of bytes that can be written at once with the channel’s chan_baudrate.

output

output: ‘int’

If the active pins of this device are inputs or outputs. If True, a FTDIPinOut will be created, otherwise a FTDIPinIn will be created by the FTDIChannel.

class pybarst.ftdi.switch.SerializerSettings(clock_bit, data_bit, latch_bit, num_boards=1, clock_size=1, continuous=False, output=False, **kwargs)

Bases: pybarst.ftdi.FTDISettings

The settings for a serial to parallel type output / input device connected to the the FTDI channel. Examples are the 74HC595 for output and 74HC589 for input.

These devices are controlled as serial devices by the controlling system but read / write as parallel ports. They are controlled by 3 digital lines; a clock line, a latch line, and a data line. The clock line is used to clock in / out the data and the latch line is used to perform a read / write from the pins of the device. To control such a device, you only need to indicate which pins on the FTDI digital port are connected to the clock, latch and data lines.

Although these devices are controlled without only 3 digital lines, each of these device typically controls 8 digital input or output lines. Therefore, with only 3 lines connected to the FTDI port, once can control many more digital ports.

When an instance of this class is passed to a FTDIChannel in the channels parameter, it will create a FTDISerializerIn or FTDISerializerOut in devices, depending on the value of the output parameter.

Parameters:
clock_bit: unsigned char

The pin to which the clock line of the serial to parallel device is connected at the FTDI channel. Typically between 0 - 7.

data_bit: unsigned char

The pin to which the data line of the serial to parallel device is connected at the FTDI channel. Typically between 0 - 7.

latch_bit: unsigned char

The pin to which the latch line of the serial to parallel device is connected at the FTDI channel. Typically between 0 - 7.

num_boards: int

The number of serial to parallel boards in a daisy chain fashion that are connected. You can connect many of these serial to parallel boards in series, so that with only 3 lines you can control many digital pins, even though each such device only controls 8 pins directly. It is assumed by the software that each such device controls 8 lines.

Defaults to 1.

clock_size: int

The number of clock cycles of the FTDI channel with pre-set baud rate to use for a single clock cycle communication with the device. The FTDI channel uses a pre-computed baud rate according to all the devices connected to the channel. E.g. if it computes to 1 MHz, each clock length is 1 us. If this is too fast for the device, we can increase the value, e.g. in the case above, a value of 2 for this parameter will result of 2 us clock lengths.

Defaults to 1, which satisfies the typical requirements if these devices.

continuous: bool

Whether, when reading, we should continuously read and send data back to the client. This is only used for a input device (output is False). When True, a single call to FTDISerializerIn.read() after the device is activated will start the server reading the device continuously and sending the data back to this client. This will result in a high sampling rate of the device. If it’s False, each call to FTDISerializerIn.read() will trigger a new read resulting in a much slower reading rate.

Defaults to False.

output: bool

If the device connected is output device (74HC595) or a input device (74HC589). If True, a FTDISerializerOut will be created, otherwise a FTDISerializerIn will be created by the FTDIChannel.

Defaults to False.

clock_bit

clock_bit: ‘unsigned char’

The pin to which the clock line of the serial to parallel device is connected at the FTDI channel. Typically between 0 - 7.

clock_size

clock_size: ‘DWORD’

The number of clock cycles of the FTDI channel with pre-set baud rate to use for a single clock cycle communication with the device. The FTDI channel uses a pre-computed baud rate according to all the devices connected to the channel. E.g. if it computes to 1 MHz, each clock length is 1 us. If this is too fast for the device, we can increase the value, e.g. in the case above, a value of 2 for this parameter will result of 2 us clock lengths.

continuous

continuous: ‘int’

Whether, when reading, the server should continuously read and send data back to the client. This is only used for a input device (output is False). When True, a single call to FTDISerializerIn.read() after the device is activated will start the server reading the device continuously and sending the data back to this client. This will result in a high sampling rate of the device. If it’s False, each call to FTDISerializerIn.read() will trigger a new read resulting in a possibly slower reading rate.

data_bit

data_bit: ‘unsigned char’

The pin to which the data line of the serial to parallel device is connected at the FTDI channel. Typically between 0 - 7.

latch_bit

latch_bit: ‘unsigned char’

The pin to which the latch line of the serial to parallel device is connected at the FTDI channel. Typically between 0 - 7.

num_boards

num_boards: ‘DWORD’

The number of serial to parallel boards in a daisy chain fashion that are connected. You can connect many of these serial to parallel boards in series, so that with only 3 lines you can control many digital pins, even though each such device only controls 8 pins directly. It is assumed by the software that each such device controls 8 lines.

output

output: ‘int’

If the device connected is output device (74HC595) or a input device (74HC589). If True, a FTDISerializerOut will be created, otherwise a FTDISerializerIn will be created by the FTDIChannel.