Issue reading parallel port pin for button box

Hello there! I’m trying to run an experiment using PsychoPy that uses a button box connected to the stimulus computer via parallel port, but unfortunately we are unable to grab these responses.

System: Windows 7, 64-bit
PsychoPy Version: 1.85.2
Standalone install?: Yes

What have we tried?

  1. Ensuring that 32-bit Python was installed alongside 32-bit PsychoPy.
  2. Ensuring that the inpout32.dll driver is installed through the highrez link.
  3. Placing the inpout32.dll driver into the working directory of the program.
  4. Checking that we have the right parallel port address (LPT2, which is 0x3048 for us).
  5. Testing on Presentation: Presentation can hear the button responses just fine.
  6. Using the newer ParallelPort functions rather than legacy setPortAddress functions.

What else are we trying?

  1. @ulrikeh - our problem seems similar to yours, in that the issue was also inability to read the pins but other programs work fine. The pyparallel solution you found set the control register bit 5 to 0, to force operating in output mode. I’m confused because the built-in parallel functions should also do this? (parallel/_inpout32.py, line 43-44). We don’t have the simpleio driver required for pyparallel so unfortunately I can’t try using those functions.
  2. I’m thinking about the Device Manager interrupt options and whether those mean anything to the parallel port operation. Right now, it’s currently set to “Never use an interrupt”, but on our other system where PsychoPy works, it’s set to “Use any interrupt assigned to the port”. I’m not 100% sure on what the implications here are, although just trying to switch it over didn’t fix the issue.

I’m running out of ideas on how to fix this issue, so any help would be greatly appreciated! Let me know if I’m missing any info.

I fixed it! In case anyone else runs into this issue, here’s what happened. Edit3: I’m adding some more info that I’ve put elsewhere in this forum on parallel ports, so that this post can act as a troubleshooting start point for anyone who finds it.

The control register
In a parallel port, bit 5 of the control register (located at the parallel port’s base address + 2) will control the directional flow of the data. If this bit is flipped, then you may be unable to read any changes. Setting this bit does seem to be included in the PsychoPy parallel class port instantiation, but I think it’s set to 0 whereas we needed it set to 1.

image

Pin 7 on the control register would correspond to bit 5, which is the PS/2 data direction control. (Recall that pins 2-9 map onto data bits 0-7.) Some supplemental reading:

  • Page 4 of this PDF about the Control Register bit 5 (PS/2 Data direction)
  • Lines 52-57 of the PParallelInpOut class source code, where this bit is flipped when instantiating a parallel port
  • This website’s thorough write-up on parallel ports. Look for discussion on “control bit 5”.

Flow bit fixes

Original solution: I used the ctypes/windll function library that underlies parallel port reading with the InpOut32.dll driver in PsychoPy to read and flip this bit accordingly. Now that I think about it, the PsychoPy parallel class should be able to read this bit if we use it to read the control register address… Will report back on that.

Edit1 | Second realization: Also, there was a similar issue reported here where the fix came from using the pyparallel class instead. Their fix and our fix are fundamentally the same: pyparallel has a function that allows you to set the data direction, which is flipping bit 5 of the control register.

Edit2 | Third realization, 2 years later: I’ll note that the parallel class in PsychoPy also specifically flips data flow bits upon port instantiation, see snippet here. I modified the PsychoPy code in our version to prevent this from happening… Maybe I should make a pull request to make the change if I get un-lazy. :slight_smile:

Test code

For checking then flipping:

port_address = 0x3048 # hex address of parallel port
ctrl_port = parallel.ParallelPort(port_address+2) # ctrl port found at +2
if ctrl_port.readPin(7) is 0:
        ctrl_port.setPin(7,1)

For checking, flipping, then seeing if button responses are registered assuming that the button response is mapped to pin 10:

from psychopy import parallel

# instantiate ports
port = parallel.ParallelPort(0x4FF8)
ctrl_port = parallel.ParallelPort(0x4FF8+2)

# check if direction bit is set to 0 in the control register, if so flip it
if ctrl_port.readPin(7) == 0: 
   ctrl_port.setPin(7, 1)

# check whether a button has been pressed
pressed = False
while not pressed:
   response = port.readPin(10) # returns 1 if pressed, 0 if not
   if response:
      print("Hooray! Button response registered.")
      pressed = True

Read the button box documentation
We were using a RESPONSEPixx/MRI button box (4-button handheld). No one documented how the system was installed, and it turned out that a parallel port adapter provided by the company was not used, thus mapping the button responses onto unexpected pins. For us, the red button was being mapped onto pin 1 (i.e., strobe of the control register).

Hope this helps someone out there!

1 Like

Hello! thanks so much for sharing your solution - I’m pleased you fixed it! so that we know when to reference this post please could you tell us what type of button box you are using? (or maybe it is a custom one?)

Thanks!
Becca

Hi Becca - it’s the RESPONSEPixx/MRI button box (4-button handheld). I knew it wasn’t an issue with hardware or connections since sending triggers worked fine through NeurObs Presentation software.

Hello,

Thanks a lot for your explanations :slight_smile:

It seems some of the issue were fixed. Notably it seems that psychopy is doing the +2 automatically.

Here is the code that worked for us:

% start experiment
from psychopy import parallel


port_address = 0xA010 # hex address of parallel port
ctrl_port = parallel.ParallelPort(port_address) 


% each frame 
ctrl_port.setData(255)
%end routine
ctrl_port.setData(0)

For some reason, setPin was not working hence we used setData that worked.