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