00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Psycho/EyeTrackerEyeLink.H"
00039
00040 #include "Component/OptionManager.H"
00041 #include "GUI/GUIOpts.H"
00042 #include "Psycho/PsychoOpts.H"
00043 #include "Util/sformat.H"
00044 #include "Component/EventLog.H"
00045 #include "Psycho/PsychoDisplay.H"
00046 #include <SDL/SDL.h>
00047 #include "Raster/Raster.H"
00048
00049 #ifdef HAVE_EYELINK
00050 #include <eyelink/eyelink.h>
00051 #include <eyelink/sdl_expt.h>
00052 #include <eyelink/sdl_text_support.h>
00053 ALLF_DATA evt;
00054 #endif
00055
00056 SDL_Color target_background_color = { 0, 0, 0};
00057 SDL_Color target_foreground_color = { 192, 192, 192 };
00058
00059
00060 EyeTrackerEyeLink::EyeTrackerEyeLink(OptionManager& mgr,
00061 const std::string& descrName,
00062 const std::string& tagName) :
00063 EyeTracker(mgr, descrName, tagName),
00064 itsEDFfname(&OPT_EyeTrackerEDFfname, this),
00065 itsDims(&OPT_SDLdisplayDims, this)
00066 { }
00067
00068
00069 EyeTrackerEyeLink::~EyeTrackerEyeLink()
00070 { }
00071
00072
00073 void EyeTrackerEyeLink::start1()
00074 {
00075 #ifndef HAVE_EYELINK
00076 LFATAL("Proprietary EyeLink developer API not installed");
00077 #else
00078
00079 if (open_eyelink_connection(0))
00080 LFATAL("Cannot open link to EyeLink tracker - make sure your "
00081 "hostname resolves to 100.1.1.2 (check /etc/hosts)");
00082
00083
00084 set_offline_mode();
00085 flush_getkey_queue();
00086
00087
00088 openSDL();
00089
00090
00091 DISPLAYINFO di;
00092 di.width = itsDims.getVal().w(); di.height = itsDims.getVal().h();
00093 di.left = 0; di.top = 0; di.right = di.width-1; di.bottom = di.height-1;
00094 di.bits = 24; di.palsize = 0; di.pages = 0; di.refresh = 60.0F;
00095 di.winnt = 0;
00096
00097 set_calibration_colors(&target_foreground_color, &target_background_color);
00098
00099
00100 if (itsEDFfname.getVal().empty() == false)
00101 {
00102 if (open_data_file((char *)(itsEDFfname.getVal().c_str())) != 0)
00103 LFATAL("Cannot open EDF file '%s'", itsEDFfname.getVal().c_str());
00104
00105 eyecmd_printf(const_cast<char*>("add_file_preamble_text 'RECORDED BY iLab code' "));
00106 }
00107
00108
00109 eyemsg_printf(const_cast<char*>("DISPLAY_COORDS %ld %ld %ld %ld"),
00110 di.left, di.top, di.right, di.bottom);
00111
00112
00113
00114
00115 eyecmd_printf(const_cast<char*>("select_parser_configuration 0"));
00116
00117
00118 eyecmd_printf(const_cast<char*>("file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,"
00119 "BLINK,MESSAGE,BUTTON"));
00120 eyecmd_printf(const_cast<char*>("file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS"));
00121
00122
00123 eyecmd_printf(const_cast<char*>("link_event_filter = LEFT,RIGHT,FIXATION,FIXUPDATE,SACCADE,BLINK,BUTTON"));
00124 eyecmd_printf(const_cast<char*>("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS"));
00125
00126
00127 eyecmd_printf(const_cast<char*>("button_function 5 'accept_target_fixation'"));
00128
00129
00130 eyecmd_printf(const_cast<char*>("heuristic_filter = 1 2"));
00131 eyelink_wait_for_mode_ready(500);
00132
00133
00134 if (!eyelink_is_connected() || break_pressed())
00135 LFATAL("Connection to EyeLink broken or aborted");
00136
00137
00138
00139
00140
00141 eyemsg_printf(const_cast<char*>("TRIAL_VAR_LABELS CONDITION"));
00142
00143
00144
00145
00146
00147
00148 EyeTracker::start1();
00149 #endif
00150 }
00151
00152
00153 void EyeTrackerEyeLink::openSDL()
00154 {
00155 #ifdef HAVE_EYELINK
00156
00157 DISPLAYINFO di;
00158 di.width = itsDims.getVal().w(); di.height = itsDims.getVal().h();
00159 di.left = 0; di.top = 0; di.right = di.width-1; di.bottom = di.height-1;
00160 di.bits = 24; di.palsize = 0; di.pages = 0; di.refresh = 60.0F;
00161 di.winnt = 0;
00162
00163
00164 if (init_expt_graphics(NULL, &di))
00165 LFATAL("Cannot open display");
00166
00167
00168 get_display_information(&di);
00169 LINFO("DISPLAYINFO: [%dx%d}: (%d,%d)-(%d,%d) %dbpp %.1fHz",
00170 int(di.width), int(di.height), int(di.left), int(di.top),
00171 int(di.right), int(di.bottom), int(di.bits), di.refresh);
00172 if (di.palsize) LFATAL("Paletized color modes not supported");
00173
00174
00175 set_target_size(10, 2);
00176 set_calibration_colors(&target_foreground_color, &target_background_color);
00177 set_cal_sounds(const_cast<char*>(""), const_cast<char*>(""), const_cast<char*>(""));
00178 set_dcorr_sounds(const_cast<char*>(""), const_cast<char*>("off"), const_cast<char*>("off"));
00179
00180
00181 eyecmd_printf(const_cast<char*>("calibration_type = HV9"));
00182
00183
00184 eyecmd_printf(const_cast<char*>("screen_pixel_coords = %ld %ld %ld %ld"),
00185 di.left, di.top, di.right, di.bottom);
00186
00187 if (di.refresh > 40.0F)
00188 eyemsg_printf(const_cast<char*>("FRAMERATE %1.2f Hz."), di.refresh);
00189 #endif
00190 }
00191
00192
00193 void EyeTrackerEyeLink::stop1()
00194 {
00195 #ifndef HAVE_EYELINK
00196 LFATAL("Proprietary EyeLink developer API not installed");
00197 #else
00198 set_offline_mode();
00199 pump_delay(500);
00200
00201
00202 if (itsEDFfname.getVal().empty() == false)
00203 eyecmd_printf(const_cast<char*>("close_data_file"));
00204
00205
00206
00207 close_expt_graphics();
00208
00209
00210 if (itsEDFfname.getVal().empty() == false)
00211 {
00212 LINFO("Transferring EDF file to '%s'", itsEDFfname.getVal().c_str());
00213 receive_data_file((char *)itsEDFfname.getVal().c_str(),
00214 (char *)itsEDFfname.getVal().c_str(), 0);
00215 }
00216
00217
00218 close_eyelink_connection();
00219
00220 EyeTracker::stop1();
00221 #endif
00222 }
00223
00224
00225 void EyeTrackerEyeLink::calibrate(nub::soft_ref<PsychoDisplay> d)
00226 {
00227 #ifndef HAVE_EYELINK
00228 LFATAL("Proprietary EyeLink developer API not installed");
00229 #else
00230
00231 if(!d->getModelParamString("PsychoDisplayFixationIcon").empty()){
00232 Image< PixRGB<byte> > fixicon =
00233 Raster::ReadRGB(d->getModelParamString("PsychoDisplayFixationIcon"));
00234 SDL_Surface *img = d->makeBlittableSurface(fixicon, false,
00235 PixRGB<byte>(target_background_color.r, target_background_color.g, target_background_color.b));
00236 set_cal_target_surface(img);
00237 }
00238
00239
00240 do_tracker_setup();
00241
00242
00243 char message[256];
00244 eyelink_cal_message(message);
00245 eyemsg_printf(message);
00246 #endif
00247 }
00248
00249
00250 void EyeTrackerEyeLink::calibrate2(nub::soft_ref<PsychoDisplay> d)
00251 {
00252 #ifndef HAVE_EYELINK
00253 LFATAL("Proprietary EyeLink developer API not installed");
00254 #else
00255
00256 if(!d->getModelParamString("PsychoDisplayFixationIcon").empty()){
00257 Image< PixRGB<byte> > fixicon =
00258 Raster::ReadRGB(d->getModelParamString("PsychoDisplayFixationIcon"));
00259 SDL_Surface *img = d->makeBlittableSurface(fixicon, false,
00260 PixRGB<byte>(target_background_color.r, target_background_color.g, target_background_color.b));
00261 set_cal_target_surface(img);
00262 }
00263
00264
00265 do_tracker_setup();
00266
00267
00268
00269
00270
00271
00272 char message[256];
00273 eyelink_cal_message(message);
00274 eyemsg_printf(message);
00275 #endif
00276 }
00277
00278
00279 void EyeTrackerEyeLink::setBackgroundColor(nub::soft_ref<PsychoDisplay> d)
00280 {
00281 #ifndef HAVE_EYELINK
00282 LFATAL("Proprietary EyeLink developer API not installed");
00283 #else
00284 SDL_Color bgcolor = { d->getGrey().red(), d->getGrey().green(), d->getGrey().blue()};
00285 SDL_Color fgcolor = { 192, 192, 192};
00286
00287 set_calibration_colors(&fgcolor, &bgcolor);
00288 LINFO("RGB: %i %i %i", d->getGrey().red(), d->getGrey().green(), d->getGrey().blue());
00289 #endif
00290 }
00291
00292
00293 void EyeTrackerEyeLink::manualDriftCorrection(Point2D<double> eyepos,
00294 Point2D<double> targetpos)
00295 {
00296 #ifndef HAVE_EYELINK
00297 LFATAL("Proprietary EyeLink developer API not installed");
00298 #else
00299 char message[256];
00300 eyecmd_printf(const_cast<char*>("drift_correction %ld %ld %ld %ld"),
00301 targetpos.i-eyepos.i, targetpos.j-eyepos.j,
00302 targetpos.i, targetpos.j);
00303
00304
00305 eyelink_cal_message(message);
00306 eyemsg_printf(message);
00307 #endif
00308 }
00309
00310
00311 void EyeTrackerEyeLink::recalibrate(nub::soft_ref<PsychoDisplay> d,int repeats)
00312 {
00313 #ifndef HAVE_EYELINK
00314 LFATAL("Proprietary EyeLink developer API not installed");
00315 #else
00316
00317 if(!d->getModelParamString("PsychoDisplayFixationIcon").empty()){
00318 Image< PixRGB<byte> > fixicon =
00319 Raster::ReadRGB(d->getModelParamString("PsychoDisplayFixationIcon"));
00320 SDL_Surface *img = d->makeBlittableSurface(fixicon, false,
00321 PixRGB<byte>(target_background_color.r, target_background_color.g, target_background_color.b));
00322 set_cal_target_surface(img);
00323 }
00324
00325 do_drift_correct(d->getWidth()/2, d->getHeight()/2, 1, 1);
00326
00327
00328 char message[256];
00329 eyelink_cal_message(message);
00330 eyemsg_printf(message);
00331
00332
00333 set_offline_mode();
00334 #endif
00335 }
00336
00337
00338 void EyeTrackerEyeLink::closeSDL()
00339 {
00340 #ifdef HAVE_EYELINK
00341 close_expt_graphics();
00342 #endif
00343 }
00344
00345
00346
00347 void EyeTrackerEyeLink::startTracking()
00348 {
00349 #ifndef HAVE_EYELINK
00350 LFATAL("Proprietary EyeLink developer API not installed");
00351 #else
00352
00353 eyecmd_printf(const_cast<char*>("record_status_message 'Recording [%d]...' "), getSession());
00354
00355
00356 eyecmd_printf(const_cast<char*>("fixation_update_interval = 50"));
00357 eyecmd_printf(const_cast<char*>("fixation_update_accumulate = 50"));
00358
00359
00360
00361 eyemsg_printf(const_cast<char*>("TRIALID EYETRACK"));
00362
00363
00364
00365
00366
00367 eyemsg_printf(const_cast<char*>("!V TRIAL_VAR_DATA EYETRACKING"));
00368
00369
00370 if (itsEventLog.isValid())
00371 itsEventLog->pushEvent(sformat("Eye Tracker Time = %d", int(current_msec())));
00372
00373
00374 if (start_recording(1, 1, 1, 1))
00375 LFATAL("Error trying to start recording");
00376 #endif
00377 }
00378
00379
00380 void EyeTrackerEyeLink::stopTracking()
00381 {
00382 #ifndef HAVE_EYELINK
00383 LFATAL("Proprietary EyeLink developer API not installed");
00384 #else
00385
00386 eyemsg_printf(const_cast<char*>("TRIAL_RESULT 1"));
00387
00388
00389 stop_recording();
00390
00391
00392 eyecmd_printf(const_cast<char*>("fixation_update_interval = 0"));
00393 eyecmd_printf(const_cast<char*>("fixation_update_accumulate = 0"));
00394
00395 set_offline_mode();
00396 #endif
00397 }
00398
00399
00400 bool EyeTrackerEyeLink::isFixating()
00401 {
00402 LFATAL("Unimplemented for now");
00403 return false;
00404 }
00405
00406
00407 bool EyeTrackerEyeLink::isSaccade()
00408 {
00409 LFATAL("Unimplemented for now");
00410 return false;
00411 }
00412
00413
00414 Point2D<int> EyeTrackerEyeLink::getEyePos() const
00415 {
00416 #ifndef HAVE_EYELINK
00417 LFATAL("Proprietary EyeLink developer API not installed");
00418 return Point2D<int>(-1,-1);
00419 #else
00420
00421 eyelink_newest_float_sample(&evt);
00422
00423
00424 if(evt.fs.gx[RIGHT_EYE]!=MISSING_DATA &&
00425 evt.fs.gy[RIGHT_EYE]!=MISSING_DATA && evt.fs.pa[RIGHT_EYE]>0){
00426 return Point2D<int>((int)evt.fs.gx[RIGHT_EYE], (int)evt.fs.gy[RIGHT_EYE]);
00427 } else {
00428 return Point2D<int>(-1, -1);
00429 }
00430 #endif
00431 }
00432
00433
00434 Point2D<int> EyeTrackerEyeLink::getFixationPos() const
00435 {
00436 #ifndef HAVE_EYELINK
00437 LFATAL("Proprietary EyeLink developer API not installed");
00438 return Point2D<int>(-1,-1);
00439 #else
00440 int i, x, y;
00441
00442 while (1) {
00443 i = eyelink_get_next_data(NULL);
00444 if (i == FIXUPDATE) {
00445 eyelink_get_float_data(&evt);
00446 x = (int)evt.fe.gavx;
00447 y = (int)evt.fe.gavy;
00448
00449 break;
00450 }
00451 }
00452
00453 return Point2D<int>(x, y);
00454 #endif
00455 }
00456
00457
00458 CalibrationTransform::Data EyeTrackerEyeLink::getCalibrationSet(nub::soft_ref<PsychoDisplay> d) const
00459 {
00460 LINFO("\n getting calibration set...");
00461 CalibrationTransform::Data dummy;
00462 dummy.addData(Point2D<double>(-1.0,-1.0),Point2D<double>(-1.0,-1.0));
00463 return dummy;
00464 }
00465
00466
00467
00468
00469
00470
00471
00472