Sending triggers to brainvision EEG system from Psychopy coderview

Hello there!

I am currently trying to get psychopy to send triggers to our brainvision EEG system through a parallel port we have installed on the task presentation computer.
I am having the hardest time getting psychopy to send triggers, as most solutions are in builder view, and we are working with coder view.

According to our device manager and a LTP port testing software, our parallel port’s address seems to be 3FF8.

Accodring to the posts already on discourse I have done/tried the following:

  1. I have downloaded the inpout32 and inpout64 drivers and put these into the same folder as my task script.
  2. I have found a script that allows one to send triggers using a trigger box & a serial port, but as this does not match our current set up, it does not work.
  3. The information at psychopy.parallel - functions for interacting with the parallel port — PsychoPy v2021.2 does not seem to work. When running a script with the recommended code, psychopy opens _inpout.py which crashes here… error

Has anyone had this problem before?
Alternatively, if anyone has an example script of a very simple experiment in psychopy coder that sends triggers to brainvision I would be eternally grateful!

Thanks!

Additional information: Here is the code that I was suggested to use for a serial port.

samplecode-bv

Even after modifying the code in the following way, the same error described in step 3 (above) occurs.

from psychopy import parallel 
port = parallel.ParallelPort(address='3FF8') 

Does anyone have an example of code where they successfully sent triggers via a parallel port?

Here are some notes from my tests to send triggers for a PC with a parallel port to an Actichamp EEG system.

Tools
Parallel port tester http://www.downtowndougbrown.com/2013/06/parallel-port-tester/.
Parellel port tester need InpOut32 or InpOut64 http://www.highrez.co.uk/downloads/inpout32/default.htm.

Test parallel communication
Connect presentation PC to ActiChamp using the parallel port.

On acquisition PC

  • Launch BrainVision Recorder.
  • Open menu "Amplifier > Digital Port Settings… Set “Bits are” to “high active”.

On the presentation PC

  • Run “Parallel Port Testing”.
  • Change port 0 to 7 state.

On the acquisition PC side, in the window “Digital Port Settings” the “Current state” should change accordingly.

The application “Parallel Port Testing” also show the address of the parallel port used.

No need to switch to PsychoPy as long as the communication via the parallel port does not work.

Coding triggers

I haven’t been able to send triggers using the parallel_port_trigger module.

I used the “dportio.dll”.

Here are the code parts I used. It was with OpenSesame but it should also work with PsychoPy.

At the beginning of the experiment.

# Init parallel
try:
    from ctypes import windll
    global io, parallel_port
    io = windll.dlportio # requires dlportio.dll !!!
    parallel_port = 0x378
except:
    print('The parallel port couldn\'t be opened')

Then, whenever necessary, it is necessary to send a signal by setting one or more bits to 1, then setting it to 0.

Note: The trigger signal must be present for at least the duration of one sampling (1 ms for sampling at 1000 Hz, 2 ms for 500 Hz, etc.).

This is done with the following code.

global io, parallel_port
trigger = 1
try:
    io.DlPortWritePortUchar(parallel_port, trigger)
except:
    print('Failed to send trigger!')

Make the script wait some time an then set back the trigger to 0.

global io, parallel_port
trigger = 0
try:
    io.DlPortWritePortUchar(parallel_port, trigger)
except:
    print('Failed to send trigger!')

I’ll try to find some time to access to the EEG system to test the code with PsychoPy.

Hi ypohcysp!

Thanks for the fast reply!
I’ve given your suggestions a try, but have not been successful in using the code you have suggested to send triggers. Actually, the code does not seem to even establish communication with the parallel port.

The first part of what you recommended worked great! Here is what the parallel port tester looks like when I open it and select ours:


As suggested when toggling the D0 port to green, this changes the digital port settings on the acquisition computer.

Sending triggers
As your code requires dlportio.dll, I downloaded this, put it in the same folder as my experiment (as previously done with the inpout drivers), as well as followed the instructions on Download Dlportio.dll for Windows 10, 8.1, 8, 7, Vista and XP on how to download it.

I then copy/pasted your recommended code to the start of my psychopy code, changed the address to 0x3FF8 (which is the address according to the parallel port tester), and ran the code.
code

Although the task does not crash, it always prints ‘The parallel port couldn’t be opened’. Psychopy prints this error if I use ‘3FF8’ as the address as well.

The last thing I tried, is following the Method 1 and 2 steps for troubleshooting with dlportio.dll at: www.dlldownloader.com/dlportio-dll. This did not solve the problem as the same message is always printed in psychopy.

Were you able to try the code out on psychopy on your system? If so, did it work?
What am I doing wrong?

Thanks again for all your help with this!

Alexa

Hy Alexa,

I was able to access our EEG device and was able to test sending triggers with PsychoPy.

The presentation machine it a DELL running with Windows 7 32 bits. I installed this machine 5 years ago and I can’t remember all the details. This machine run in test mode. Perhaps the test mode is used to bypass the autorisation required for i/o drivers.

Here is the code I used.

# psychopy-trigger-to-brainrecorder.py
# Sending triggers from PsychoPy to BrainRecorder
# with parallel port, ddportio
# Joël Brogniart - 20200220

import psychopy, sys, time
global io, parallel_port

try:
    from ctypes import windll
    io = windll.dlportio # requires dlportio.dll !!!
    parallel_port = 0x378
except:
    print('The parallel port couldn\'t be opened')

ledOn = 0
try:
    io.DlPortWritePortUchar(parallel_port, ledOn)
except:
    print('Failed to send trigger!')
#
time.sleep(1)
ledOn = 1
for x in range(7):
    try:
        io.DlPortWritePortUchar(parallel_port, ledOn)
    except:
        print('Failed to send trigger!')
    print("ledOn: {:#010b}".format(ledOn))
    time.sleep(1)
    ledOn = ledOn << 1
for x in range(9):
    try:
        io.DlPortWritePortUchar(parallel_port, ledOn)
    except:
        print('Failed to send trigger!')
    print("ledOn: {:#010b}".format(ledOn))
    time.sleep(1)
    ledOn = ledOn >> 1

Is there a dlportio.dll in the directory where the application ParallelPortTester is located? Could you test the script with a copy of the ddl in the script directory?

What is your Windows version?

Have you seen the thread https://groups.google.com/forum/#!topic/psychopy-users/hbIO2wHK1KU?

Hi @ypohcysp!

Thanks for the quick response!
Sadly, this also did not work on my set up. After copy/pasting the code you have suggested above into a script, and running it, I got the following message:

To answer your questions…

  • There is a dlportio.dll in the directory where the application ParallelPortTester is now. What is the advantage of also having the file here?
  • I have tested the script with a copy of the same dlportio.dll in the same directory and this still lead to the same error message above.
  • My windows version is 10, 64bit, running on an HP z2 desktop.

I have done through the thread you suggested, and I had actually followed many of the steps suggested. These suggestions seem to pertain more so to the inpout32 and 64 drivers as opposed to the dlportio.dll. Nevertheless, I am still confused and have not been successful in getting psychopy to communicate with the parallel port.

Do you have any further suggestions?
Thank you once again,
Alexa

Ooops I forgot to add an exit in case of failure to find a parallel port in my script.

My level of knowledge about how drivers work under Windows is not high enough for me to be able to help you further. And I have no Windows 10 machine with a parallel port to test.

When the driver is not found in the areas dedicated to them in Windows, the program searches in its own directory (or vice versa). So putting it in the same place as the script can help to find it.

As I remember, inpout32 and 64 are newer than dlportio. It’s not enough to just copy them into the dedicated directories, I also believe that you have to modify some stuff in the registry and that the installation script is supposed to take care of that.

Hi @ypohcysp!

I will go back to the instructions and try again, I must be missing something…
Thanks again for all your help!

Does anyone else have a step by step solution to get a parallel port to communicate with a brain vision eeg system?

Alexa

Hi,
For my MEG experiment the script sends trigger without problems. Though I’m not familiar with brain vision EEG system, maybe my setup for the parallel port could help?
Put both inpout32.dll and inpoutx64.dll in the project folder (so that you don’t have to worry about the version of PsychoPy). So the folder structure looks like:

├── constants.py
├── experiment.py
├── inpout32.dll
└── inpoutx64.dll

psychopy.parallel worked for me, so my script looks like:

# setup the port
port = parallel.ParallelPort(0x3FF8)  # don't quote it
# set all pins low before experiment
port.setData(0)

# run the experimnt
for trial in trials:
    # send trigger
    port.setData(1)
    # keep sending the trigger for a bit
    core.wait(0.003)
    # reset the port
    port.setData(0)

    # do something...

Hope that helps!

Hi @yh-luo and @ypohcysp!

I FIGURED IT OUT!
Here are the steps I followed to get psychopy to send triggers via a parallel port to a BrainVision EEG system.

  1. Download the inpout32.dll driver from the following website:http://www.highrez.co.uk/downloads/inpout32/ by clicking on " Binaries only - x86 & x64 DLLs and libs" under Downloads.
    This file is needed to give Windows access to the parallel port installed in the display computer.

  2. Unzip the folder, and run “InstallDriver” which is found in the Win32 folder by clicking on the driver. When properly installed, you should get a confirmation message saying it’s done!
    For me, unlike described in other posts, it did not seem to matter if I had the 32 or 64 bit Python and Psychopy applications downloaded. The inpout32.dll suggested in step 1 seems to be compatible with both (at least for Windows 10).

  3. Copy the inpout.dll file found in the Win32 folder to the following locations:
    ** Note: it’s possible that it is not required to place the file in all these locations. However, I did just to be safe!

  • C:/Program Files/Psychopy3
  • C:/Program Files/Psychopy3/DLLs
  • C:/Program Files(x86)/Psychopy3
  • C:/Program Files/Psychopy3/DLLs
  • The folder where your psychopy script is saved.

I previously had not noticed that there was a DLLs folder within each psychopy3 folder. Once I added the driver to these folders, it solved my problem.

  1. To get the parallel port address, I followed the steps suggested above by @ypohcysp. Here they are:
  • download the parallel port tester from: http://www.downtowndougbrown.com/2013/06/parallel-port-tester/
  • Open parallel port tester, and choose the parallel port you have installed on the display computer (bottom right corner). This should display the correct address to be used in your Psychopy code. (e.g. mine is a PCIe with address: 0x3FF8)
    This is the same address that shows up in device manager, if you are more familiar with that method of finding the address.
  • If you launch BrainVision Recorder on the acquisition computer, go to Amplifier > Digital Port Settings, you will have the parallel port installed on the display computer show up. By turning some pins from low to high (pins 2-9) you should see the pins change in the BrainVision recorder too. This confirms that the parallel port is indeed installed correctly and working ‘manually’.
  1. Add code to your task!
    If you are like me, you did not know much about how parallel ports work. They work by sending out bits out from their individual pins (yes, the little pins you see when you look into it). it can only send data out of pins 2 to 9. By looking at the Digital port settings and/or the parallel port tester, you will see what bits each pin is going to set out when set to high (or ‘active’). Importantly, once a pin has sent out a trigger and thus, is set to high, it needs to be set back to low before it can send anything else out of that pin again.
    Now the following code should make sense…
# goes at the start of your script.
from psychopy import parallel, core
port = parallel.ParallelPort(address=0x3FF8) # imports function for parallel port communication and finds the port at the address specified.

# example trigger 
        port.setData( int("00000001", 2) ) # send S 1; the 0's and 1's here reffer to if each pin is set to high(1) or low(0), which will consequently send out the trigger associated with the number that results from the pins set to high. Here my first pin (pin2) is set to send out 1 so sends out S1.     
        core.wait(0.2) # need to wait before setting pin back to low in order to ensure the trigger is sent
        port.setData(0) # set all pins back to low(0) 

If you want to make sure your triggers are being sent at the exact time the stimulus appears (which is often the case!) you here is another example I recently used in an oddball task:

if trialList[t] == 'regular': 
                trig = "00000100"    # S 4
            elif trialList[t] == 'oddball':
                trig ="00000011"    # S 3
            else: 
                print('trigger for new trial not sent!')
                
            newTrial.draw()  
            win.callOnFlip(port.setData, int(trig, 2) )
            win.flip()
            core.wait(stimTime) # this serves both as my stimulus display time and my core.wait before resetting my pins to low.
            port.setData(0)

That’s pretty much it!
If you have any questions, let me know!

Alexa

2 Likes

My EEG recorder isn’t BrainVision . After I followed your previous steps, Amplifier shows SynAmps2/RT here and my EEG mark does not show up on the computer where it was recorded. Do you know what the cause is? I really need help.

Hey there - I encountered an issue awhile ago where no data would emit from the parallel port because the control register in the pport that dictates whether it’s sending or receiving information was flipped. Check out my post here. Hope that somehow helps! Good luck!

Also see: https://github.com/pablobernabeu/EEG-tools-and-tips/blob/main/OpenSesame_inline_script_to_send_EEG_triggers_via_serial_port