Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Supported by

Fails to save SMI data with triggers

edited May 21 in PyGaze

Hi all,

I'm running a combined EEG (actiChamp) - ET (SMI RED250 mobile) experiment using OpenSesame 3.2.7. In my experiment, I send triggers both to the EEG and SMI. However, at the end of the experiment, the eye data fails to be saved with the following error:

Unexpected error
item-stack: 

exception type: Exception

exception message: Error in libsmi.SMItracker.close: failed to save data; unknown error with decimal code 204; please refer to the iViewX SDK Manual

time: Tue May 21 17:08:26 2019

Traceback:

 File "C:\Program Files (x86)\OpenSesame\lib\site-packages\libqtopensesame\misc\process.py", line 157, in run

   exp.run()

 File "C:\Program Files (x86)\OpenSesame\lib\site-packages\libopensesame\experiment.py", line 463, in run

   self.end()

 File "C:\Program Files (x86)\OpenSesame\lib\site-packages\libopensesame\experiment.py", line 536, in end

   self.cleanup()

 File "C:\Program Files (x86)\OpenSesame\lib\site-packages\libopensesame\experiment.py", line 522, in cleanup

   func()

 File "C:\Program Files (x86)\OpenSesame\share\opensesame_plugins\pygaze_init\pygaze_init.py", line 82, in close

   self.experiment.pygaze_eyetracker.close()

 File "C:\Program Files (x86)\OpenSesame\lib\site-packages\pygaze\_eyetracker\libsmi.py", line 416, in close

   raise Exception("Error in libsmi.SMItracker.close: failed to save data; %s" % err)

Exception: Error in libsmi.SMItracker.close: failed to save data; unknown error with decimal code 204; please refer to the iViewX SDK Manual

According to the iViewX SDK Manual, the decimal code 204 refers to "ERR_IVIEWX_ACCESS_INCOMPLETE", which means that the LPT signal recording is still in progress. This error is returned under the function intiV SetupLptRecording( constchar∗portName, intenableRecording ). This function specifically says, "Enables or disables the LPT signal recording functionality. When enabling the LPT port signal recording the LPT port name has to be specified. The LPT ports available for recording can be queried by using the iV_GetAvailableLptPorts API function. The function must not be called during a running recording."

I'm not sure if this is the problem, but if it is, does anyone know how to close/disable the LPT signal recording from within OpenSesame (if it's possible at all)? Or what is the real problem here?

Your help will be very helpful!

p.s. I'm desperate


Cheers,

intan

Comments

  • Hi Intan,

    I don't have hands-on experience with the SMI, so I'm kind of groping in the dark here. Have you managed to successfully collect data with the SMI with OpenSesame before? I.e. should it work in principle?

    > According to the iViewX SDK Manual, the decimal code 204 refers to "ERR_IVIEWX_ACCESS_INCOMPLETE", which means that the LPT signal recording is still in progress.

    If that's correct, one thing that comes to mind is that there may not be enough time between the moment that the recording is stopped (by pygaze_stop_recording), and the moment that the experiment ends (and the connection to the eye tracker is closed, where things go wrong).

    What is the structure of your experiment? If you add, say, a goodbye screen at the very end of the experiment that stays on for a few seconds before the experiment actually ends, does that solve the issue?

    Cheers!

    Sebastiaan

    There's much bigger issues in the world, I know. But I first have to take care of the world I know.
    cogsci.nl/smathot

  • Hei Sebastiaan,

    thank you for your response! I did data collection with SMI and OpenSesame before, but without triggers and it was fine. Now I want to send triggers both to the EEG and ET. However, it keeps giving me the aforementioned error message.

    Roughly speaking, the structure of my experiment is that after the pygaze_stop_recording item, there is a feedback item to show them their final scores. Between these two items, I put an inline script to explicitly close the port using s.close() (s = serial.Serial('COM1')). Even after closing the connection to the port explicitly I still get this error...

    Is it a problem to put a feedback item at the very end of the experiment? Should I use a sketchpad item instead??

    Cheersies,

    intan

  • > thank you for your response! I did data collection with SMI and OpenSesame before, but without triggers and it was fine. Now I want to send triggers both to the EEG and ET. However, it keeps giving me the aforementioned error message.

    I initially assumed that you'd send a message to the SMI log file, and the separately send a trigger to the EEG recording device through the parallel port. So that the two triggers are completely independent of each other, in other words.

    But now that I read the error message again, it seems that the SMI library is also involved in sending triggers to the EEG. So that the two triggers are *not* independent of each other, in other words.

    Could you clarify how this works?

    > Is it a problem to put a feedback item at the very end of the experiment? Should I use a sketchpad item instead??

    No that's totally fine!

    There's much bigger issues in the world, I know. But I first have to take care of the world I know.
    cogsci.nl/smathot

  • Why is the SMI library involved in sending triggers to the EEG?

    Your initial assumption is correct - that's how I (was supposed to) program the experiment. The experiment should send triggers that are split by a serial-to-parallel box to the EEG and ET independently. To initialise the triggers, I do the following.

    import serial
    
    #Initialise serial port
    s = serial.Serial('COM1')
    
    #Turn off the display of the serial-to-parallel box
    s.write('D000')
    
    #Set the trigger functions
    #for the EEG system
    def trigA(trig):
       s.write(trig)
       clock.sleep(10)
       s.write('A000')
       clock.sleep(10)
    
    #for the eyetracking system
    def trigB(trig):
       s.write(trig)
       clock.sleep(25)
       s.write('B000')
       clock.sleep(25)
    

    so I use code A for EEG and code B for ET (that's how the serial-to-LPT box works). For instance, trig = 'A015' and trig = 'B015'. That's why I do not see why the triggers aren't independent. Can you explain to me, maybe I've done something wrong here (i.e., I thought I made it work in a way it's supposed to when it's something completely different)?

    I also thought the problem was that libsmi was still actively sending triggers when the experiment was over (given that error)? If need be, I can try to attach the experiment.

    Thank you for your help!

    intan

  • edited June 9

    Hi Intan,

    Ah, I think I understand now. So it seems that are (at least) two ways to send information to the SMI log file:

    • The first is to use the eyetracker.log() function, which in turn uses the iViewXAPI Python library.
    • The second is to send triggers to the parallel port, in much the same way as you would to an EEG recording device.

    I suspect that PyGaze doesn't properly handle the second case, and that's where the error comes from. (Ping @Edwin )

    But I also don't think it's necessary to use the parallel port, which is essentially a historical artifact that I wouldn't use for anything unless it's strictly necessary. Is there any reason why you wouldn't use the eyetracker.log() function to send trigger messages to the SMI device, and then use the serial-to-LPT box only for the EEG?

    Cheers!

    Sebastiaan

    There's much bigger issues in the world, I know. But I first have to take care of the world I know.
    cogsci.nl/smathot

  • Hei Sebastiaan,

    So, the idea is to send triggers for each phase to the EEG but to send triggers at least at the start and end of the experiment to SMI such that we can synchronise the EEG and ET data. Why do we need to do this? Because the SMI eyetracker is quite unreliable and sometimes it freezes in the middle of the experiment :( To make sure we know during which phase we lose the data, we need the ET triggers. Is synchronisation possible with eyetracker.log() together with EEG triggers? I have used eyetracker.log() for each phase as well. If it's possible to sync with the EEG triggers, maybe I will just use eyetracker.log().

    Cheersies,

    intan

  • Just thinking that this may be useful: I thought maybe it was a good idea to add something like iViewXAPI.iV_SetupLptRecording("LPT name", 0) within the SMItracker.close() function in libsmi to disable the signal recording to the port after an experiment has ended. I am not sure if this can be a solution, but it seems that this is what the SDK manual suggests. (ping @Edwin )

    Other than that, just to reiterate, if eyetracker.log() can be used to sync with the EEG triggers, I will use this (faster) solution in the meantime. :)

  • > Just thinking that this may be useful: I thought maybe it was a good idea to add something likeiViewXAPI.iV_SetupLptRecording("LPT name", 0) within the SMItracker.close() function in libsmi to disable the signal recording to the port after an experiment has ended.

    Perhaps you can already add this to the Run phase od an inline_script at the very end of the experiment? Perhaps that will resolve the whole issue.

    > Other than that, just to reiterate, if eyetracker.log() can be used to sync with the EEG triggers, I will use this (faster) solution in the meantime. :)

    I think (but I say this without actually knowing how the SMI API works) that sending log messages through the API (i.e. with eyetracker.log()) and sending triggers through the parallel port are two different ways to accomplish the same thing. So yes, I think you can safely use eyetracker.log() instead. The added advantage will be that you can then send more informative log messages than just single-byte trigger codes.

    There's much bigger issues in the world, I know. But I first have to take care of the world I know.
    cogsci.nl/smathot

  • Perhaps you can already add this to the Run phase od an inline_script at the very end of the experiment? Perhaps that will resolve the whole issue.

    I indeed did this already, but it didn't resolve the issue.

    In fact, it seems to me that the error message may be misleading. I tried to just connect to the SMI computer and send log messages using eyetracker.log(), but it threw the same error. The stimulus PC (where I run OpenSesame) is a different computer from the SMI computer and they are connected via an ethernet cable. Is the problem maybe then they don't know where to save the the .idf files (i.e., ET data)? Do I have to define the file path where I want to save my .idf files?

    Cheersies,

    intan

  • > I indeed did this already, but it didn't resolve the issue.

    Yes, I figured you would've tried that ;-)

    > The stimulus PC (where I run OpenSesame) is a different computer from the SMI computer and they are connected via an ethernet cable. Is the problem maybe then they don't know where to save the the .idf files (i.e., ET data)? Do I have to define the file path where I want to save my .idf files?

    Hmm, it could be, actually. It's so difficult to debug without actually having access to the computer (or even an other SMI device). But yes, looking at the code, it seems that if you don't specify a logfile, pygaze will try to save the output data to a file called 'automatic', without specifying a path. More specifically, 'automatic' will be the first argument to iViewXAPI.iV_SaveData().

    What happens if you specify, in the pygaze_init item, a full path to a log file where you know that you have write access? Something like c:\my writable folder\output.idf.

    There's much bigger issues in the world, I know. But I first have to take care of the world I know.
    cogsci.nl/smathot

  • Hi all,

    Interesting problem! My thoughts:

    I'd be quite hestiant to add iViewXAPI.iV_SetupLptRecording("LPT name", 0) to the close function, for starters because it would require knowing the LPT name (which we don't, and should thus be user-specified), but more importantly because it doesn't seem to work. (Adding it in an inline_script like you did should have had the same effect, but didn't.) On top of that, with SMI being bunk, I don't think it's wise to further edit code that is essentially there for legacy purposes (i.e. until all SMI trackers have broken down). Of practical note: I can't debug anything, due to no longer having access to an SMI tracker. Sorry :(

    Despite that, we should still try to figure out what's going on in your situation, and whether we can resolve it!

    I think @sebastiaan's suggestion of simply using eyetracker.log should do just fine. The log function was intended for this exact purpose (including triggers in your data file), so should do the trick. Suggested code for your trigger sending in inline_scripts:

    # Send the eyetracker tigger
    eyetracker.log(trig)
    # Send the EEG trigger
    trigA(trig)
    

    This has the added benefit of not having your triggers come in at different times too, which is what your current code does. (There's a minimum of 20 ms delay between the triggers if you're using trigA followed by trigB.)

    Good luck!

    Edwin

  • Just noted your additional messages, on `eyetracker.log` throwing the same error. There are a few things you should keep in mind when using a second computer to record your data:

    1. Make sure that you specify the correct IP address for the computer that's running iViewX. This IP is a keyword argument in the SMI initialiser ( https://github.com/esdalmaijer/PyGaze/blob/master/pygaze/_eyetracker/libsmi.py#L127 ), and is used when a connection is opened ( https://github.com/esdalmaijer/PyGaze/blob/master/pygaze/_eyetracker/libsmi.py#L208 ).
    2. The logfile is also user-definable, again through a keyword in the initialiser. ( https://github.com/esdalmaijer/PyGaze/blob/master/pygaze/_eyetracker/libsmi.py#L128 ) The logger is set here: https://github.com/esdalmaijer/PyGaze/blob/master/pygaze/_eyetracker/libsmi.py#L194
    3. Another point where the logfile comes up is when closing the connection. Its name is "self.outputfile" (see https://github.com/esdalmaijer/PyGaze/blob/master/pygaze/_eyetracker/libsmi.py#L167 ), and is used in here: https://github.com/esdalmaijer/PyGaze/blob/master/pygaze/_eyetracker/libsmi.py#L413
    4. I've no clue what the error ""ERR_IVIEWX_ACCESS_INCOMPLETE" means. Does the manual not expand on it? If only there was still a helpdesk at SMI :(
  • Hi Sebastiaan,

    What happens if you specify, in the pygaze_init item, a full path to a log file where you know that you have write access? Something like c:\my writable folder\output.idf.

    I tried this already as well, but it still did not work. It spewed another error telling me that it failed to set up a log file. :/

    Hi @Edwin ,

    thank you for your comprehensive response! I have changed the IP address of the iViewX computer and defined the log file. The problem is, it seems that it cannot save the .idf file because, despite this error, I still get the OpenSesame .txt and SMILOG .txt files. I just cannot obtain (or save) the .idf file although I tried what Sebastiaan suggested above.

    Here I attach a screenshot from the iViewX SDK manual about the "ERR_IVIEWX_ACCESS_INCOMPLETE".

    Genuinely appreciate your help!


  • UPDATE:

    I have been successful in connecting the stimulus PC with the eyetracker PC. In the end, there are 3 outputs from one run of an experiment: the OpenSesame .txt file, the SMILOG .txt file, and the .idf file (for the eye data). The .txt files are stored automatically in the same folder as the experiment in the stimulus PC. The .idf file is saved in the eyetracker PC. I did make some changes in the libsmi.py library to make my experiment work. What I did was as follow.

    Define different IP addresses (one for iViewX computer, one for the stimulus computer):

    # line 208
    # the first ip refers to the iViewX ip address already initialised above
    res = iViewXAPI.iV_Connect(c_char_p(ip), c_int(sendport), c_char_p('169.254.181.139'), c_int(receiveport))
    
    

    Define the file path (folder into which data is saved) for .idf file. The slicing refers to how I identify each participant:

    # line 167
    # customise the idf output file
    self.outputfile = "C:/Users/iView X/Desktop/logfiles/Intan/" + logfile[35::] + ".idf"
    
    
    # it seems like you can also customise the participant ID in the idf file here
    # line 169
    self.participant = logfile[35::]
    

    I still don't understand why the error message says "recording in progress", but perhaps because previously the file path for the idf data was not clearly defined, the access to iViewX was considered incomplete.

    Thanks again all for the inspiration to solve this problem! It is ineed unnecessary to add

  • That's pretty impressive, and thank you for sharing!

    Just to clarify the solution for me. You're saying that the second IP address (169.254.181.139) is the stimulus computer, i.e. the computer that OpenSesame is running on, right? So basically, you're telling iViewX at which address to reach OpenSesame?

    There's much bigger issues in the world, I know. But I first have to take care of the world I know.
    cogsci.nl/smathot

Sign In or Register to comment.