EEG trigger labels from serial port to BV Recorder only go up to 191, then start again at 128

Win10 edu
PsychoPy-2024.2.1post4 Builder
Standard Standalone Installation
Not running online

Hi, I am simply trying to send 156 unique numerical stimulus trigger labels from a pc running Psychopy, through a brain vision trigger box serial usb port to another pc (through actiChamp) recording eeg data in Brainvision Recorder. The labels should be read out of an excel Stim file referenced in Builder. I am not using any code components, becuase the gui should be able to handle this, and it does, up through Stim# 191, then when Psychopy sends 192 to Recorder, it shows up as 128, 193 shows up as 129, etc. The TriggerTest in Recorder works fine and goes up to 255. Anyone recognize this problem? (aside: trigger # 0, or 256 never shows up. Does that mean that with 8 bytes I can actually only ever get 255 unique labels?). Thanks!

Hello

I do not know your serial port but could it be that the Baud rate is set to a wrong rate? 2000000 is a rather untypical baud rate.

Best wishes Jens

Whoops, I meant 256 unique trigger labels

Thanks Jens, 200000 seems to be the correct baud rate for this set up.

Hello @jsargent

On our system I can only get values up to 127. Trigger #0 cannot show up because it means that all lines are pulled to 0.

For an explanation of why chr() does not work as intended, see ascii - What's the point of chr(128) .. chr(255) in Python? - Stack Overflow

You could edit the py-file that the Builder writes from

serialPort.write(bytes('128','utf8'))

to

serialPort.write(bytes(bytearray([128])))

and run the py-file for your experiment.

Best wishes, Jens

Thanks again Jens. Editing my py-file currently exceeds my know-how, but rather than pursue that, since I need 256 unique trigger labels (not 156, I messed up original post) and best case, I’ll always be missing one (with one byte), I’ll probably have to edit the event field in the EEGset in eeglab (matlab) anyway. So that’s where I’m headed now, but I may well return to this path.
Best, Jesse

Hello

You could send a combination of two triggers briefly following each other, e.g. 1 + 1, 1 + 2, 1 + 3 …, 2 + 1, 2 + 2, 2 + 3 …

Best wishes Jens

Thanks Jens, that is a good idea, but I can identify the individual trial stimuli in eeglab even with bad labels just by matching up sequentially with psychopy behavioral data file. My main issue at this point is that I cannot make average ERPs across trial types/classes using the eeglab gui because I have repeat trigger labels when they get above 191 (and drop by 64 units creating a duplicate of 128, then 129, etc.).

I did look at my py-file as you suggested, where I think I found (some of) the relevant python code. I tried to make your suggestion work to no avail. I could get it to send trigger label 192 to Recorder, but not when pulling the labels from my “ConditionsBlock1” excel file. Here’s what builder is generating, trying to send numeric trigger labels from that excel file, column labeled Crap:

if serialPort is starting this frame…

            if serialPort.status == NOT_STARTED and StudyPtrn_2.status == STARTED:
                # keep track of start time/frame for later
                serialPort.frameNStart = frameN  # exact frame index
                serialPort.tStart = t  # local t and not account for scr refresh
                serialPort.tStartRefresh = tThisFlipGlobal  # on global time
                win.timeOnFlip(serialPort, 'tStartRefresh')  # time at next scr refresh
                # add timestamp to datafile
                thisExp.timestampOnFlip(win, 'serialPort.started')
                # update status
                serialPort.status = STARTED
                win.callOnFlip(serialPort.write, bytes(chr(Crap), 'utf8'))
                serialPort.status = STARTED

Hello @jsargent

So you tried?

win.callOnFlip(serialPort.write(bytes(bytearray([Crap]))))

Although your code looks a little different than I expected

Compare your code

win.callOnFlip(**serialPort.write,** bytes(chr(Crap), 'utf8'))

with my example from above

win.callOnFlip(**serialPort.write(**bytes('128','utf8')))

Copy & paste error on my side?

See here for an explanation of the behavior of the serial port triggers Strange trigger values with MMBT-S interface - #4 by jon

I have no idea why you can send trigger values up to 192?

Best wishes Jens

For BrainProducts specifically there are also online documentation options as below:

Writing simple triggers to the serial port:

Communicate via the Remote Control Server

Do also check, if the trigger values are coming from a conditions file, the format of the values once they’ve been read in. Sending [128] is very different to sending ["128"] which is one of the reasons for the PsychoPy code to use chr or bytearray so check whether you need to do any format conversions first

Thanks Jens, so I replaced:
win.callOnFlip(serialPort.write, bytes(chr(Crap), ‘utf8’))

with literally this:
win.callOnFlip(serialPort.write(bytes(bytearray([Crap]))))

and got this error message:
File “C:\Programs…window.py”, line 1325, in flip
callentry[‘function’](*callEntry[‘args’], **callEntry[‘kwargs’])
TypeError: ‘int’ object is not callable

Maybe it is a format conversion issue as Jon suggested? (Thanks Jon!) Other than making sure the cells in excel are “General” (I think because this is what I could get to work at all, I think I tried “numeric”…, and replaced “chr” with other things I found in examples online, “str” etc., and tried different combos) I’m not sure how to make sure format is synching well everywhere. Is there some idiot proof way I can find out what format is being “sent” (I assume Jon means from Psychopy, through the triggerbox, to BV recorder?), and then get (literal) suggestions on how to edit my code accordingly? I am familiar with the “Writing simple triggers to the serial port” doc, thanks. Best, Jesse

Hello @jsargent

Sorry. I did not test the command with a variable but with a constant. Try this

win.callOnFlip(serialPort.write, bytes(bytearray([Crap])))

or

win.callOnFlip(serialPort.write, bytearray([Crap]))

Best wishes Jens