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
. SeePinSettings
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. IfPinSettings.continuous
is True, after the first call toread()
the server will continuously read from the device and send the results back to the client. This means that if the client doesn’t callread()
frequently enough data will accumulate in the pipe. Also, the data returned might have been acquired before the currentread()
was called.To cancel a read request while the read is still waiting, from another thread you must call
close_channel_client()
, orclose_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 callset_state()
to set it inactive, orcancel_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, onceread()
returned with an error, a further call toread()
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 withset_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 sizePinSettings.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
. SeePinSettings
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 withset_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
. SeeSerializerSettings
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 toread()
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 toread()
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. IfSerializerSettings.continuous
is True, after the first call toread()
the server will continuously read from the device and send the results back to the client. This means that if the client doesn’t callread()
frequently enough data will accumulate in the pipe. Also, the data returned might have been acquired before the currentread()
was called.To cancel a read request while the read is still waiting, from another thread you must call
close_channel_client()
, orclose_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 callset_state()
to set it inactive, orcancel_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, onceread()
returned with an error, a further call toread()
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 withset_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
. SeeSerializerSettings
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 withset_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 aFTDIPinIn
orFTDIPinOut
indevices
, depending on the value of theoutput
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’schan_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
andFTDIPinOut
device can control the same pin, in which case the pin will function as output, but theFTDIPinIn
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 toFTDIPin.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 aFTDIPinIn
will be created by theFTDIChannel
.
-
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 toFTDIPin.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’schan_baudrate
.
-
output
¶ output: ‘int’
If the active pins of this device are inputs or outputs. If True, a
FTDIPinOut
will be created, otherwise aFTDIPinIn
will be created by theFTDIChannel
.
-
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 aFTDISerializerIn
orFTDISerializerOut
indevices
, depending on the value of theoutput
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 toFTDISerializerIn.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 aFTDISerializerIn
will be created by theFTDIChannel
.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 toFTDISerializerIn.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 aFTDISerializerIn
will be created by theFTDIChannel
.