Table Of Contents

Previous topic

BitsPlusPlus

Next topic

ColorCAL

This Page

Quick links

BitsSharp

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

Attributes

BitsSharp([win, portName, mode, …]) A class to support functions of the Bits# (and most Display++ functions
BitsSharp.mode Get/set the mode of the BitsSharp to one of:
BitsSharp.isAwake() Test whether we have an active connection on the virtual serial
BitsSharp.getInfo() Returns a python dictionary of info about the Bits Sharp box
BitsSharp.checkConfig([level, demoMode, logFile]) Checks whether there is a configuration for this device and
BitsSharp.gammaCorrectFile Get / set the gamma correction file to be used
BitsSharp.temporalDithering Temporal dithering can be set to True or False
BitsSharp.monitorEDID Get / set the EDID file for the monitor.
BitsSharp.beep([freq, dur]) Make a beep of a given frequency and duration
BitsSharp.getVideoLine(lineN, nPixels[, …]) Return the r,g,b values for a number of pixels on a particular
BitsSharp.start() [Not currently implemented] Used to begin event collection by
BitsSharp.stop() [Not currently implemented] Used to stop event collection by

Direct communications with the serial port:

BitsSharp.sendMessage(message[, autoLog]) Send a command to the device (does not wait for a reply or sleep())
BitsSharp.getResponse([length, timeout]) Read the latest response from the serial port

Control the CLUT (Bits++ mode only):

BitsSharp.setContrast(contrast[, LUTrange, …]) Set the contrast of the LUT for ‘bits++’ mode only
BitsSharp.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.
BitsSharp.setLUT([newLUT, gammaCorrect, …]) SetLUT is only really needed for bits++ mode of bits# to set the look-up table (256 values with 14bits each).

Details

class psychopy.hardware.crs.bits.BitsSharp(win=None, portName=None, mode='', checkConfigLevel=1, gammaCorrect='hardware', gamma=None, noComms=False)

A class to support functions of the Bits# (and most Display++ functions

This device uses the CDC (serial port) connection to the Bits box. To use it you must have followed the instructions from CRS Ltd. to get your box into the CDC communication mode.

Typical usage (also see demo in Coder view demos>hardware>BitsBox ):

from psychopy import visual
from psychopy.hardware import crs

# we need to be rendering to framebuffer
win = visual.Window([1024,768], useFBO=True)
bits = crs.BitsSharp(win, mode = 'mono++')
# You can continue using your window as normal and OpenGL shaders
# will convert the output as needed

print(bits.info)
if not bits.OK:
    print('failed to connect to Bits box')
    core.quit()

core.wait(0.1)
# now, you can change modes using
bits.mode = 'mono++' # 'color++', 'mono++', 'bits++', 'status'
Parameters:

win : a PsychoPy Window object, required

portName : the (virtual) serial port to which the device is

connected. If None then PsychoPy will search available serial ports and test communication (on OSX, the first match of /dev/tty.usbmodemfa* will be used and on linux /dev/ttyS0 will be used

mode : ‘bits++’, ‘color++’, ‘mono++’, ‘status’

checkConfigLevel : integer

Allows you to specify how much checking of the device is done to ensure a valid identity look-up table. If you specify one level and it fails then the check will be escalated to the next level (e.g. if we check level 1 and find that it fails we try to find a new LUT):

  • 0 don’t check at all
  • 1 check that the graphics driver and OS version haven’t
    changed since last LUT calibration
  • 2 check that the current LUT calibration still provides
    identity (requires switch to status mode)
  • 3 search for a new identity look-up table (requires
    switch to status mode)
gammaCorrect : string governing how gamma correction is performed
‘hardware’: use the gamma correction file stored on the

hardware

‘FBO’: gamma correct using shaders when rendering the FBO

to back buffer

‘bitsMode’: in bits++ mode there is a user-controlled LUT

that we can use for gamma correction

noComms : bool

If True then don’t try to communicate with the device at all (passive mode). This can be useful if you want to debug the system without actually having a Bits# connected.

Clock()

Reads the internal clock of the Bits box but note there will be a delay in reading the value back for return values see getRTBoxResponses()

RTBoxAddKeys(map)

Add key mappings to an existing map. RTBox events can be mapped to a number of physical events on Bits# They can be mapped to digital input lines, triggers and CB6 IR input channels. The format for map is a list of tuples with each tuple containing the name of the RTBox button to be mapped and its source eg (‘btn1’,’Din1’) maps physical input Din1 to logical button btn1. RTBox has four logical buttons (btn1-4) and three auxiliary events (light, pulse and trigger) Buttons/events can be mapped to multiple physical inputs and stay mapped until reset.

RTBoxCalibrate(N=1)

Used to assess error between host clock and Bits# button press time stamps.

RTBoxClear()

Flushes the serial input buffer Its good to do this before and after data collection. This just calls flush()so is a wrapper for RTBox.

RTBoxDisable()

Disables the detection of RTBox events. This is useful to stop the Bits# from reporting key presses When you no longer need them.

RTBoxEnable(mode=None, map=None)

Sets up the RT Box with preset or bespoke mappings and enables event detection. RTBox events can be mapped to a number of physical events on Bits# They can be mapped to digital input lines, tigers and CB6 IR input channels.

The format for map is a list of tuples with each tuple containing the name of the RT Box button to be mapped and its source eg (‘btn1’,’Din0’) maps physical input Din0 to logical button btn1.

Note the lowest number button event is Btn1

RTBox has four logical buttons (btn1-4) and three auxiliary events (light, pulse and trigger) Buttons/events can be mapped to multiple physical inputs and stay mapped until reset.

Mode is a list of string or list of strings that contains keywords to determine present mappings and modes for RT Box.

Preset mappings are:
CB6 for the CRS CB6 IR response box. IO for a three button box connected to Din0-2 IO6 for a six button box connected to Din0-5

Bespoke Mappings over write preset ones.

If mode includes ‘Down’ button events will be detected when pressed. If mode includes ‘Up’ button events will be detected when released. You can detect both types of event but note that pulse, light and trigger events dont have an ‘Up’ mode.

If Trigger is included in mode the trigger
event will be mapped to the trigIn connector.
RTBoxKeysPressed(N=1)

Check to see if (at least) the appropriate number of RTbox style key presses have been made

RTBoxResetKeys()

Resets the key mappings to no mapping. Has the effect of disabling RTBox input

RTBoxSetKeys(map)

Set key mappings: first reset existing then add new ones. Does not reset any event that is not in the new list.

RTBox events can be mapped to a number of physical events on Bits# They can be mapped to digital input lines, triggers and CB6 IR input channels. The format for map is a list of tuples with each tuple containing the name of the RTBox button to be mapped and its source eg (‘btn1’,’Din1’) maps physical input Din1 to logical button btn1.

RTBox has four logical buttons (btn1-4) and three auxiliary events (light, pulse and trigger) Buttons/events can be mapped to multiple physical inputs and stay mapped until reset.

RTBoxWait()

Waits until (at least) one of RTBox style key presses have been made Pauses program execution in mean time.

RTBoxWaitN(N=1)

Waits until (at least) the appropriate number of RTBox style key presses have been made Pauses program execution in mean time.

beep(freq=800, dur=1)

Make a beep of a given frequency and duration

checkConfig(level=1, demoMode=False, logFile='')

Checks whether there is a configuration for this device and whether it’s correct

Params:

level: integer

0: do nothing

1: check that we have a config file and that the graphics

card and operating system match that specified in the file. Then assume identity LUT is correct

2: switch the box to status mode and check that the

identity LUT is currently working

3: force a fresh search for the identity LUT

driverFor = []
flush()

Flushes the serial input buffer Its good to do this before and after data collection, And generally quite often.

gammaCorrectFile

Get / set the gamma correction file to be used (as stored on the device)

getAllRTBoxResponses()

Read all of the RTBox style key presses on the input buffer.

Returns a list of dict like objects with three members ‘button’, ‘dir’ and ‘time’

‘button’ is a number from 1 to 9 to indicate the event that was detected. 1-4 are the ‘btn1-btn4’ events, 5 and 6 are the ‘light’ and ‘pulse’ events, 7 is the ‘trigger’ event, 9 is a requested timestamp event (see Clock()).

‘dir’ is the direction of the event eg ‘up’ or ‘down’, trigger is described as ‘on’ when low.

‘dir’ is set to ‘time’ if a requested timestamp event has been detected.

‘time’ is the timestamp associated with the event.

Values can be read as a structure eg:
res= getAllRTBoxResponses() res[0].dir, res[0].button, rest[0].time
or dictionary
res[0][‘dir’], res[0][‘button’], res[0][‘time’]

Note even if only 1 key press was found a list of dict / objects is returned

getAllStatusEvents()

Returns the whole status event list

Returns a list of dictionary like objects with the following entries source, input, direction, time.

source = the general source of the event - e.g. DIN for Digital input, IR for CB6 IR response box events

input = the individual input in the source. direction = ‘up’ or ‘down’ time = time stamp.

mode specifies which directions of events are captured. e.g ‘up’ will only report up events.

The data can be accessed as value[i][‘time’] or value[i].time

getAllStatusValues()

Returns the whole status values list.

Returns a list of dict like objects with the following entries sample, time, trigIn, DIN[10], DWORD, IR[6], ADC[6]

sample is the sample ID number. time is the time stamp. trigIn is the value of the trigger input. DIN is a list of 10 digital input values. DWORD represents the digital inputs as a single decimal value. IR is a list of 10 infra-red (IR) input values. ADC is a list of 6 analog input values.

These can be accessed as value[i][‘sample’] or value[i].sample, values[i].ADC[j].

getAnalog(N=0)

Pulls out the values of the analog inputs for the Nth status entry.

Returns a dictionary with a list of 6 floats (ADC) and a time stamp (time).

getDigital(N=0)

Pulls out the values of the digital inputs for the Nth status entry.

Returns a dictionary with a list of 10 ints that are 1 or 0 (DIN) and a time stamp (time)

getDigitalWord(N=0)

Pulls out the values of the digital inputs for the Nth status entry.

Returns a dictionary with a 10 bit word representing the binary values of those inputs (DWORD) and a time stamp (time).

getIRBox(N=0)

Pulls out the values of the CB6 IR response box inputs for the Nth status entry.

Returns a dictionary with a list of 6 ints that are 1 or 0 (IR) and a time stamp (time).

getInfo()

Returns a python dictionary of info about the Bits Sharp box

getPackets()

Returns the number of packets available for trigger pulses.

getRTBoxResponse()

checks for one RTBox style key presses on the input buffer then reads it.

Returns a dict like object with three members ‘button’, ‘dir’ and ‘time’

‘button’ is a number from 1 to 9 to indicate the event that was detected. 1-4 are the ‘btn1-btn4’ events, 5 and 6 are the ‘light’ and ‘pulse’ events, 7 is the ‘trigger’ event, 9 is a requested timestamp event (see Clock()).

‘dir’ is the direction of the event eg ‘up’ or ‘down’, trigger is described as ‘on’ when low.

‘dir’ is set to ‘time’ if a requested timestamp event has been detected.

‘time’ is the timestamp associated with the event.

Value can be read as a structure, eg:
res= getRTBoxResponse() res.dir, res.button, rest.time
or dictionary
res[‘dir’], res[‘button’], res[‘time’]
getRTBoxResponses(N=1)

checks for (at least) an appropriate number of RTBox style key presses on the input buffer then reads them.

Returns a list of dict like objects with three members ‘button’, ‘dir’ and ‘time’

‘button’ is a number from 1 to 9 to indicate the event that was detected. 1-4 are the ‘btn1-btn4’ events, 5 and 6 are the ‘light’ and ‘pulse’ events, 7 is the ‘trigger’ event, 9 is a requested timestamp event (see Clock()).

‘dir’ is the direction of the event eg ‘up’ or ‘down’, trigger is described as ‘on’ when low.

‘dir’ is set to ‘time’ if a requested timestamp event has been detected.

‘time’ is the timestamp associated with the event.

Values can be read as a list of structures eg:
res= getRTBoxResponses(3) res[0].dir, res[0].button, rest[0].time
or dictionaries
res[0][‘dir’], res[0][‘button’], res[0][‘time’]

Note even if only 1 key press was requested a list of dict / objects is returned

getResponse(length=1, timeout=0.1)

Read the latest response from the serial port

Params:
length determines whether we expect:

1: a single-line reply (use readline()) 2: a multiline reply (use readlines() which requires timeout) -1: may not be any EOL character; just read whatever chars are

there
getStatus(N=0)

Pulls out the Nth entry in the statusValues list.

Returns a dict like object with the following entries sample, time, trigIn, DIN[10], DWORD, IR[6], ADC[6]

sample is the sample ID number. time is the time stamp. trigIn is the value of the trigger input. DIN is a list of 10 digital input values. DWORD represents the digital inputs as a single decimal value. IR is a list of 10 infra-red (IR) input values. ADC is a list of 6 analog input values.

These can be accessed as value[‘sample’] or value.sample, values.ADC[j].

getStatusEvent(N=0)

pulls out the Nth event from the status event list

Returns a dictionary like object with the following entries source, input, direction, time.

source = the general source of the event - e.g. DIN for Digital input, IR for IT response box.

input = the individual input in the source. direction = ‘up’ or ‘down’ time = time stamp.

mode specifies which directions of events are captured, e.g ‘up’ will only report up events.

The data can be accessed as value[‘time’] or value.time

getTrigIn(N=0)

Pulls out the values of the trigger input for the Nth status entry.

Returns dictionary with a 0 or 1 (trigIn) and a time stamp (time)

getVideoLine(lineN, nPixels, timeout=10.0, nAttempts=10)

Return the r,g,b values for a number of pixels on a particular video line

Parameters:
  • lineN – the line number you want to read
  • nPixels – the number of pixels you want to read
  • nAttempts – the first time you call this function it has to get to status mode. In this case it sometimes takes a few attempts to make the call work
Returns:

an Nx3 numpy array of uint8 values

isAwake()

Test whether we have an active connection on the virtual serial port

isOpen
longName = ''
mode

Get/set the mode of the BitsSharp to one of: “bits++” “mono++” (not currently working?) “color++” (not currently working?) “status” “storage” “auto”

monitorEDID

Get / set the EDID file for the monitor. The edid files will be located in the EDID subdirectory of the flash disk. The file “automatic.edid” will be the file read from the connected monitor.

name = 'CRS Bits#'
next()
pause()

Pause for a default period for this device

pollStatus(time=0.0001)

Reads the status reports from the Bits# for the specified usually short time period. The script will wait for this time to lapse so not ideal for time critical applications.

If time is less than 0.01 polling will continue until at least 1 data entry has been recorded.

If you don’t want to wait while this does its job use startStatusLog and stopStatusLog instead.

Fills the statusValues list with all the status values read during the time period.

Fills the statusEvents list with just those status values that are likely to be meaningful events.

statusValues and statusEvents will end up containing dict like objects of the following style: sample, time, trigIn, DIN[10], DWORD, IR[6], ADC[6]

They can be accessed as statusValues[i][‘sample’] or stautsValues[i].sample, statusValues[x].ADC[j].

Note: Starts and stops logging for itself.

primeClock()

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

read(timeout=0.1)

Get the current waiting characters from the serial port if there are any

reset()

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#.

resetClock()

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

sendAnalog(AOUT1=0, AOUT2=0)

sends a single analog output pulse uses up 1 win flip. pulse will continue until next win flip called. Actions are always 1 frame behind the request.

May conflict with trigger and goggle settings.

sendMessage(message, autoLog=True)

Send a command to the device (does not wait for a reply or sleep())

sendTrigger(triggers=0, onTime=0, duration=0, mask=65535)

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.

setAnalog(AOUT1=0, AOUT2=0)

Sets up Analog outputs in Bits# AOUT1 and AOUT2 are the two analog values required.

setContrast(contrast, LUTrange=1.0, gammaCorrect=None)

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

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)

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=False, LUTrange=1.0, contrast=None)

SetLUT is only really needed for bits++ mode of bits# to set the look-up table (256 values with 14bits each).

For the BitsPlusPlus device the deafult is to perform gamma correction here but on the BitsSharp it seems better to have the device perform that itself as the last step so gamma correction is off here by default.

If no contrast has yet been set (it isn’t needed for other modes) then it will be set to 1 here.

setRTBoxMode(mode=['CB6', 'Down', 'Trigger'])
setStatusEventParams(DINBase=1023, IRBase=63, TrigInBase=0, mode=['up', 'down'])

Sets the parameters used to determine if a status value represents a reportable event.

DIN_base = a 10 bit binary word specifying the expected starting values of the 10 digital input lines

IR_base = a 6 bit binary word specifying the expected starting values of the 6 CB6 IR buttons

Trig_base = the starting value of the Trigger input

mode = a list of event types to monitor can be ‘up’ or ‘down’ typically ‘down’ corresponds to a button press or when the input is being pulled down to zero volts.

setTrigger(triggers=0, onTime=0, duration=0, mask=65535)
Overaload of Bits# and Display++
Sets up Tigger pulses while preserving the analog outut settings.

Note that mask only protects the digital output lines

setTriggerList(triggerList=None, mask=65535)
Overaload of Bits# and Display++
Sets up Tigger pulses via the list method while preserving the analog outut settings.

Note that mask only protectes the digital output lines from internal interference from Display++

start()

[Not currently implemented] Used to begin event collection by the device.

Not really needed as other members now do this.

startAnalog()

will start sending analog signals on the next win flip and continue until stopped.

startGoggles(left=0, right=1)
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.

startStatusLog(time=60)

Start logging data from the Bits#

Starts data logging in its own tread

startTrigger()

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

stop()

[Not currently implemented] Used to stop event collection by the device.

Not really needed as other members now do this.

stopAnalog()

will stop sending analogs signals at the next win flip

stopGoggles()

Stop the stereo goggles from toggeling

stopStatusLog()

Stop logging data from the Bits# and extracts the raw information and events. Waits for _statusLog to finish properly so can introduce a timing delay

stopTrigger()

Stop sending triggers at the next win flip

syncClocks(t)

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

temporalDithering

Temporal dithering can be set to True or False

win

The window that this box is attached to