# BitsPlusPlus¶

Control a CRS Bits# device. See typical usage in the class summary (and in the menu demos>hardware>BitsBox of PsychoPy’s Coder view).

Important: See note on BitsPlusPlusIdentityLUT

## Attributes¶

 BitsPlusPlus(win[, contrast, gamma, …]) The main class to control a Bits++ box. This is usually a class added within the window object and is typically accessed from there. e.g.:: from psychopy import visual from psychopy.hardware import crs win = visual.Window([800,600]) bits = crs.BitsPlusPlus(win, mode=’bits++’) # use bits++ to reduce the whole screen contrast by 50%: bits.setContrast(0.5). BitsPlusPlus.setContrast(contrast[, …]) Set the contrast of the LUT for ‘bits++’ mode only :Parameters: contrast : float in the range 0:1 The contrast for the range being set LUTrange : float or array If a float is given then this is the fraction of the LUT to be used. If an array of floats is given, these will specify the start / stop points as fractions of the LUT. If an array of ints (0-255) is given these determine the start stop indices of the LUT .. rubric:: Examples. BitsPlusPlus.setGamma(newGamma) Set the LUT to have the requested gamma value Currently also resets the LUT to be a linear contrast ramp spanning its full range. BitsPlusPlus.setLUT([newLUT, gammaCorrect, …]) Sets the LUT to a specific range of values in ‘bits++’ mode only Note that, if you leave gammaCorrect=True then any LUT values you supply will automatically be gamma corrected. The LUT will take effect on the next Window.flip() Examples: bitsBox.setLUT() builds a LUT using bitsBox.contrast and bitsBox.gamma bitsBox.setLUT(newLUT=some256x1array) (NB array should be float 0.0:1.0) Builds a luminance LUT using newLUT for each gun (actually array can be 256x1 or 1x256) bitsBox.setLUT(newLUT=some256x3array) (NB array should be float 0.0:1.0) Allows you to use a different LUT on each gun (NB by using BitsBox.setContr() and BitsBox.setGamma() users may not need this function).

## Details¶

class psychopy.hardware.crs.bits.BitsPlusPlus(win, contrast=1.0, gamma=None, nEntries=256, mode='bits++', rampType='configFile', frameRate=None)[source]

The main class to control a Bits++ box. This is usually a class added within the window object and is typically accessed from there. e.g.:

from psychopy import visual
from psychopy.hardware import crs
win = visual.Window([800,600])
bits = crs.BitsPlusPlus(win, mode='bits++')
# use bits++ to reduce the whole screen contrast by 50%:
bits.setContrast(0.5)

Parameters
contrast :

The contrast to be applied to the LUT. See BitsPlusPlus.setLUT() and BitsPlusPlus.setContrast() for flexibility on setting just a section of the LUT to a different value

gamma :

The value used to correct the gamma in the LUT

nEntries256

[DEPRECATED feature]

mode‘bits++’ (or ‘mono++’ or ‘color++’)

Note that, unlike the Bits#, this only affects the way the window is rendered, it does not switch the state of the Bits++ device itself (because unlike the Bits# have no way to communicate with it). The mono++ and color++ are only supported in PsychoPy 1.82.00 onwards. Even then they suffer from not having gamma correction applied on Bits++ (unlike Bits# which can apply a gamma table in the device hardware).

rampType‘configFile’, None or an integer

if ‘configFile’ then we’ll look for a valid config in the userPrefs folder if an integer then this will be used during win.setGamma(rampType=rampType):

frameRate : an estimate the frameRate of the monitor. If None frame rate will be calculated.

_Goggles()[source]

(private) Used to set control the goggles. Should not be needed by user if attached to a psychopy.visual.Window

_ResetClock()[source]

(private) Used to reset Bits hardware clock. Should not be needed by user if attached to a psychopy.visual.Window since this will automatically draw the reset code as part of the screen refresh.

_drawLUTtoScreen()[source]

(private) Used to set the LUT in ‘bits++’ mode. Should not be needed by user if attached to a psychopy.visual.Window since this will automatically draw the LUT as part of the screen refresh.

_drawTrigtoScreen(sendStr=None)[source]

(private) Used to send a trigger pulse. Should not be needed by user if attached to a psychopy.visual.Window since this will automatically draw the trigger code as part of the screen refresh.

_protectTrigger()[source]

If Goggles (or analog) outputs are used when the digital triggers are off we need to make a set of blank triggers first. But the user might have set up triggers in waiting for a later time. So this will protect them.

_restoreTrigger()[source]

Restores the triggers to previous settings

_setHeaders(frameRate)[source]

Sets up the TLock header codes and some flags that are common to operating all CRS devices

_setupShaders()[source]

creates and stores the shader programs needed for mono++ and color++ modes

getPackets()[source]

Returns the number of packets available for trigger pulses.

primeClock()[source]

Primes the clock to reset at the next screen flip - note only 1 clock reset signal will be issued but if the frame(s) after the reset frame is dropped the reset will be re-issued thus keeping timing good.

Resets continute to be issued on each video frame until the next win.flip so you need to have regular win.flips for this function to work properly.

Example

bits.primeClock() drawImage while not response

#do some processing bits.win.flip()

Will get a clock reset signal ready but wont issue it until the first win.flip in the loop.

reset()[source]

Deprecated: This was used on the old Bits++ to power-cycle the box. It required the compiled dll, which only worked on windows and doesn’t work with Bits# or Display++.

resetClock()[source]

Issues a clock reset code using 1 screen flip if the next frame(s) is dropped the reset will be re-issued thus keeping timing good.

Resets continute to be issued on each video frame until the next win.flip so you need to have regular win.flips for this function to work properly.

Example

bits.resetClock() drawImage() bits.win.flip()

Will issue clock resets while the image is being drawn then display the inmage and allow the clock to continue formt he same frame.

Example

bits.resetClock() bits.RTBoxWait() bits.win.flip()

Will issue clock resets until a button is presses.

sendTrigger(triggers=0, onTime=0, duration=0, mask=65535)[source]

Sends a single trigger using up 1 win.flip. The trigger will be sent on the following frame.

The triggers will continue until after the next win.flip.

Actions are always 1 frame after the request.

May do odd things if Goggles and Analog are also in use.

Example:

bits.sendTrigger(0b0000000010, 2.0, 4.0)
bits.win.flip()


Will send a 4ms puilse on DOUT1 2ms after the start of the frame. Due to the following win.flip() the pulse should last for 1 frame only.

Triggers will continue until stopTrigger is called.

setContrast(contrast, LUTrange=1.0, gammaCorrect=None)[source]

Set the contrast of the LUT for ‘bits++’ mode only :Parameters:

contrastfloat in the range 0:1

The contrast for the range being set

LUTrangefloat or array

If a float is given then this is the fraction of the LUT to be used. If an array of floats is given, these will specify the start / stop points as fractions of the LUT. If an array of ints (0-255) is given these determine the start stop indices of the LUT

Examples

setContrast(1.0,0.5)

will set the central 50% of the LUT so that a stimulus with contr=0.5 will actually be drawn with contrast 1.0

setContrast(1.0,[0.25,0.5]) setContrast(1.0,[63,127])

will set the lower-middle quarter of the LUT (which might be useful in LUT animation paradigms)

setGamma(newGamma)[source]

Set the LUT to have the requested gamma value Currently also resets the LUT to be a linear contrast ramp spanning its full range. May change this to read the current LUT, undo previous gamma and then apply new one?

setLUT(newLUT=None, gammaCorrect=True, LUTrange=1.0)[source]

Sets the LUT to a specific range of values in ‘bits++’ mode only Note that, if you leave gammaCorrect=True then any LUT values you supply will automatically be gamma corrected. The LUT will take effect on the next Window.flip() Examples:

bitsBox.setLUT()

builds a LUT using bitsBox.contrast and bitsBox.gamma

bitsBox.setLUT(newLUT=some256x1array)

(NB array should be float 0.0:1.0) Builds a luminance LUT using newLUT for each gun (actually array can be 256x1 or 1x256)

bitsBox.setLUT(newLUT=some256x3array)

(NB array should be float 0.0:1.0) Allows you to use a different LUT on each gun

(NB by using BitsBox.setContr() and BitsBox.setGamma() users may not need this function)

setTrigger(triggers=0, onTime=0, duration=0, mask=65535)[source]

Quick way to set up triggers.

Triggers is a binary word that determines which triggers will be turned on.

onTime specifies the start time of the trigger within the frame (in S with 100uS resolution)

Duration specifies how long the trigger will last. (in S with 100uS resolution).

Note that mask only protects the digital output lines set by other activities in the Bits. Not other triggers.

Example::

bits.setTrigger(0b0000000010, 2.0, 4.0, 0b0111111111) bits.startTrigger()

Will issue a 4ms long high-going pulse, 2ms after the start of each frame on DOUT1 while protecting the value of DOUT 9.

setTriggerList(triggerList=None, mask=65535)[source]

Sets up Trigger pulses in Bits++ using the fine grained method that can control every trigger line at 100uS intervals.

TriggerList should contain 1 entry for every 100uS packet (see getPackets) the binary word in each entry specifies which trigger line will be active during that time slot.

Note that mask only protects the digital output lines set by other activities in the Bits. Not other triggers.

Example:

packet = [0]*self._NumberPackets
packet[0] = 0b0000000010
bits.setTriggerList(packet)


Will sens a 100us pulse on DOUT1 at the start of the frame.

Example 2:

packet = [0]*self._NumberPackets
packet[10] = 0b0000000010
packet[20] = 0b0000000001
bits.setTriggerList(packet)
bits.startTrigger()


Will sens a 100us pulse on DOUT1 1000us after the start of the frame and a second 100us pusle on DOUT0 2000us after the start of the frame.

Triggers will continue until stopTrigger is called.

startGoggles(left=0, right=1)[source]

Starts CRS stereo goggles. Note if you are using FE-1 goggles you should start this before connecting the goggles.

Left is the state of the left shutter on the first frame to be presented 0, False or ‘closed’=closed; 1, True or ‘open’ = open,

right is the state of the right shutter on the first frame to be presented 0, False or ‘closed’=closed; 1, True or ‘open’ = open

Note you can set the goggles to be both open or both closed on the same frame.

The system will always toggle the state of each lens so as to not damage FE-1 goggles.

Example:

bits.startGoggles(0,1)
bits.win.flip()
while not response
bits.win.flip()
#do some processing
bits.stopGoggles()
bits.win.flip()


Starts toggling the goggles with the right eye open in sync with the first win.flip() within the loop. The open eye will alternate.

Example:

bits.startGoggles(1,1)
bits.win.flip()
while not response:
bits.win.flip()
#do some processing
bits.stopGoggles()
bits.win.flip()


Starts toggling the goggle with both eyes open in sync with the first win.flip() within the loop. Eyes will alternate between both open and both closed.

Note it is safe to leave the goggles toggling forever, ie to never call stopGoggles().

startTrigger()[source]

Start sending triggers on the next win flip and continue until stopped by stopTrigger Triggers start 1 frame after the frame on which the first trigger is sent.

Example:

bits.setTrigger(0b0000000010, 2.0, 4.0, 0b0111111111)
bits.startTrigger()
while imageOn:
#do some processing
continue
bits.stopTrigger()
bits.win.flip()

stopGoggles()[source]

Stop the stereo goggles from toggling

Example:

bits.startGoggles(0,1)
bits.win.flip()
while not response:
bits.win.flip()
#do some processing
bits.stopGoggles()
bits.win.flip()


Starts toggling the goggles with the right eye open in sync with the first win.flip(0) within the loop. The open eye will alternate.

Note it is safer to leave the goggles toggling forever, ie to never call stopGoggles().

stopTrigger()[source]

Stop sending triggers at the next win flip

Example:

bits.setTrigger(0b0000000010, 2.0, 4.0, 0b0111111111)
bits.startTrigger()
while imageOn:
#do some processing
continue
bits.stopTrigger()
bits.win.flip()

syncClocks(t)[source]

Synchronise the Bits/RTBox Clock with the host clock Given by t.

## Finding the identity LUT¶

For the Bits++ (and related) devices to work correctly it is essential that the graphics card is not altering in any way the values being passed to the monitor (e.g. by gamma correcting). It turns out that finding the ‘identity’ LUT, where exactly the same values come out as were put in, is not trivial. The obvious LUT would have something like 0/255, 1/255, 2/255… in entry locations 0,1,2… but unfortunately most graphics cards on most operating systems are ‘broken’ in one way or another, with rounding errors and incorrect start points etc.

PsychoPy provides a few of the common variants of LUT and that can be chosen when you initialise the device using the parameter rampType. If no rampType is specified then PsychoPy will choose one for you:

from psychopy import visual
from psychopy.hardware import crs

win = visual.Window([1024,768], useFBO=True) #we need to be rendering to framebuffer
bits = crs.BitsPlusPlus(win, mode = 'bits++', rampType = 1)


The Bits# is capable of reporting back the pixels in a line and this can be used to test that a particular LUT is indeed providing identity values. If you have previously connected a BitsSharp device and used it with PsychoPy then a file will have been stored with a LUT that has been tested with that device. In this case set rampType = “configFile” for PsychoPy to use it if such a file is found.