pythonencodingbinaryserial-portopen-sesame

How to correctly encode triggers in Python and send them to BrainVision through serial port (useful for OpenSesame and PsychoPy)


I would be very grateful for advice about sending EEG triggers/markers to BrainVision Recorder using Python code. I’m using OpenSesame as the stimulus platform. Although OpenSesame doesn’t have built-in support for sending triggers to the port, it can be achieved by using Python code. However, I haven’t found an infallible template that I could use.

The setup for sending triggers in our lab draws on a serial proxy to the parallel port. Thus, from OpenSesame, I connect to the serial port using the following code:

import serial

serialport = serial.Serial(‘COM3’)

I’m sending the triggers in a binary format because Python requires this. For instance, to send the trigger 1, I run the code serialport.write(b’1’). I have succeeded in sending triggers in this way. However, I encounter two problems.

First, the triggers are converted in a way I cannot entirely decipher. For instance, when I run the code serialport.write(b’1’), the trigger displayed in BrainVision Recorder is S 49, not S 1 as I would hope (please see Appendix below).

Second, I cannot send two triggers with the same code one after the other. For instance, if I run serialport.write(b’1’), a trigger appears in BrainVision Recorder, but if I run the same afterwards (no matter how many times), no trigger appears.

I tried to solve these problems by opening the parallel port in addition to the serial port, but the problems persist.

Thank you very much for your attention.

Appendix: Matching between triggers sent from Python and markers shown in BrainVision

The marker printed in BrainVision Recorder is 48 units larger than the last digit present in the original trigger. If more than one digit is present in the trigger, only the last digit is considered.

The list below is code-formatted for convenience, but only the function before the arrow corresponds to actual code.

serialport.write(b’0’) --> ‘S 48’
serialport.write(b’1’) --> ‘S 49’
serialport.write(b’2’) --> ‘S 50’
serialport.write(b’3’) --> ‘S 51’
serialport.write(b’4’) --> ‘S 52’
serialport.write(b’5’) --> ‘S 53’
serialport.write(b’6’) --> ‘S 54’
serialport.write(b’7’) --> ‘S 55’
serialport.write(b’8’) --> ‘S 56’
serialport.write(b’9’) --> ‘S 57’
serialport.write(b’10’) --> ‘S 48’
serialport.write(b’11’) --> ‘S 49’
serialport.write(b’12’) --> ‘S 50’
serialport.write(b’13’) --> ‘S 51’
serialport.write(b’14’) --> ‘S 52’
serialport.write(b’15’) --> ‘S 53’
serialport.write(b’16’) --> ‘S 54’
serialport.write(b’17’) --> ‘S 55’
serialport.write(b’18’) --> ‘S 56’
serialport.write(b’19’) --> ‘S 57’
serialport.write(b’20’) --> ‘S 48’
serialport.write(b’21’) --> ‘S 49’
serialport.write(b’22’) --> ‘S 50’
serialport.write(b’23’) --> ‘S 51’

Furthermore, I can print markers larger than 57 by entering non-numbers in the original trigger, as exemplified below.

serialport.write(b’@’) -->  ‘S 64’
serialport.write(b’]’) --> ‘S 93’
serialport.write(b’a’) --> ‘S 97’
serialport.write(b’m’) --> ‘S 109’
serialport.write(b’z’) --> ‘S 122’

Like with the numbers, only the last item is considered. So, serialport.write(b’@@’) --> S 64.

I have not been able to print markers smaller than 48 or larger than 125.


Solution

  • I first suggested: serialport.write(0x01) in the comments, but that didn't help. Then I suggested: serialport.write(b'\x01') and that seemed to work.

    Now you are interested in using the value 1 as an integer, but require the write to be serialport.write(b'\x01'). Fortunately there are in-built conversions for that:

    def serial_write(int_val):
        as_bytes = int_val.to_bytes(length=1, byteorder="big")
        serialport.write(as_bytes)
    
    serial_write(0x01)
    

    In theory you can write: for i in range(256): serial_write(i) to send all values between 0 and 255 inclusive. (However, I see that you are having trouble sending more that one trigger - but that is a different question).