psychopy.org | Reference | Downloads | Github

Triggering parallel port on a given stimulus from a .csv file list

Hi guys, in my PsychoPy experiment, I’ve got a “trials” loop in which a new random stimulus from a csv file is showed each loop until every one of the file has been showed once.
When the stimulus file “red_cross_shock.png” is used, I would like to trigger a parallel port that is controlling an experimental shocking device (https://www.digitimer.com/pdf/digitimer/ds7a.pdf).
I have never used an exterior device on PsychoPy and do not know how the handling of a parallel port works. Here is my corresponding code, I added a condition testing if the used stimulus was “red_cross_shock.png” (from what I’ve understood, this information is stored in the ‘stimuli2’ variable) and triggered the port accordingly (see ‘p_port updates’ part of the 'Start Routine “trials” ’ part) :

set up handler to look after randomisation of conditions etc

trials_loop = data.TrialHandler(nReps=1, method='random', 
    extraInfo=expInfo, originPath=-1,
    trialList=data.importConditions('conditions.csv'),
    seed=None, name='trials_loop')
thisExp.addLoop(trials_loop)  # add the loop to the experiment
thisTrials_loop = trials_loop.trialList[0]  # so we can initialise stimuli with some values
# abbreviate parameter names if possible (e.g. rgb = thisTrials_loop.rgb)
if thisTrials_loop != None:
    for paramName in thisTrials_loop:
        exec('{} = thisTrials_loop[paramName]'.format(paramName))

for thisTrials_loop in trials_loop:
    currentLoop = trials_loop
    # abbreviate parameter names if possible (e.g. rgb = thisTrials_loop.rgb)
    if thisTrials_loop != None:
        for paramName in thisTrials_loop:
            exec('{} = thisTrials_loop[paramName]'.format(paramName))
    
    # ------Prepare to start Routine "trials"-------
    t = 0
    trialsClock.reset()  # clock
    frameN = -1
    continueRoutine = True
    routineTimer.add(2.000000)
    p_port.setData(255)
    # update component parameters for each repeat
    stimuli2.setImage(Stimulus)
    # keep track of which components have finished
    trialsComponents = [stimuli2, p_port]
    for thisComponent in trialsComponents:
        thisComponent.tStart = None
        thisComponent.tStop = None
        thisComponent.tStartRefresh = None
        thisComponent.tStopRefresh = None
        if hasattr(thisComponent, 'status'):
            thisComponent.status = NOT_STARTED
    
    # -------Start Routine "trials"-------
    while continueRoutine and routineTimer.getTime() > 0:
        # get current time
        t = trialsClock.getTime()
        frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
        # update/draw components on each frame
            
        # *stimuli2* updates
        if t >= 1 and stimuli2.status == NOT_STARTED:
            # keep track of start time/frame for later
            stimuli2.tStart = t  # not accounting for scr refresh
            stimuli2.frameNStart = frameN  # exact frame index
            win.timeOnFlip(stimuli2, 'tStartRefresh')  # time at next scr refresh
            stimuli2.setAutoDraw(True)
        frameRemains = 1 + 1- win.monitorFramePeriod * 0.75  # most of one frame period left
        if stimuli2.status == STARTED and t >= frameRemains:
            # keep track of stop time/frame for later
            stimuli2.tStop = t  # not accounting for scr refresh
            stimuli2.frameNStop = frameN  # exact frame index
            win.timeOnFlip(stimuli2, 'tStopRefresh')  # time at next scr refresh
            stimuli2.setAutoDraw(False)
            
        # *p_port* updates
        if t >= 1 and stimuli2 == "red_cross_shock.png" and p_port.status == NOT_STARTED:
            # keep track of start time/frame for later
            p_port.tStart = t  # not accounting for scr refresh
            p_port.frameNStart = frameN  # exact frame index
            win.timeOnFlip(p_port, 'tStartRefresh')  # time at next scr refresh
            p_port.status = STARTED
            win.callOnFlip(p_port.setData, int(4))
        frameRemains = 1 + 1- win.monitorFramePeriod * 0.75  # most of one frame period left
        if p_port.status == STARTED and t >= frameRemains:
            # keep track of stop time/frame for later
            p_port.tStop = t  # not accounting for scr refresh
            p_port.frameNStop = frameN  # exact frame index
            win.timeOnFlip(p_port, 'tStopRefresh')  # time at next scr refresh
            p_port.status = FINISHED
            win.callOnFlip(p_port.setData, int(255))
        
        # check for quit (typically the Esc key)
        if endExpNow or keyboard.Keyboard().getKeys(keyList=["escape"]):
            core.quit()
        
        # check if all components have finished
        if not continueRoutine:  # a component has requested a forced-end of Routine
            break
        continueRoutine = False  # will revert to True if at least one component still running
        for thisComponent in trialsComponents:
            if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
                continueRoutine = True
                break  # at least one component has not yet finished
        
        # refresh the screen
        if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
            win.flip()
    
    # -------Ending Routine "trials"-------
    for thisComponent in trialsComponents:
        if hasattr(thisComponent, "setAutoDraw"):
            thisComponent.setAutoDraw(False)
    trials_loop.addData('stimuli2.started', stimuli2.tStartRefresh)
    trials_loop.addData('stimuli2.stopped', stimuli2.tStopRefresh)
    if p_port.status == STARTED:
        win.callOnFlip(p_port.setData, int(0))
    trials_loop.addData('p_port.started', p_port.tStart)
    trials_loop.addData('p_port.stopped', p_port.tStop)
    thisExp.nextEntry()
    
# completed 1 repeats of 'trials_loop'

I this a way of doing it or am I not doing this right ?

Thank you for your asnwers.