00001 /*!@file Psycho/EyeTrackerUDP.C Eye tracker in Doug Munoz' lab using 00002 UDP packets for communication */ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00006 // by the University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: David J. Bert <dberg@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Psycho/EyeTrackerUDP.C $ 00036 00037 #ifndef PSYCHO_EYETRACKERUDP_C_DEFINED 00038 #define PSYCHO_EYETRACKERUDP_C_DEFINED 00039 00040 #include "Psycho/EyeTrackerUDP.H" 00041 00042 #include "Component/ModelOptionDef.H" 00043 #include "Psycho/PsychoOpts.H" 00044 #include "Component/OptionManager.H" 00045 #include "Util/Timer.H" 00046 #include "Util/sformat.H" 00047 00048 #include <sys/time.h> 00049 00050 // ###################################################################### 00051 EyeTrackerUDP::EyeTrackerUDP(OptionManager& mgr, 00052 const std::string& descrName, 00053 const std::string& tagName) : 00054 EyeTracker(mgr, descrName, tagName), //base init 00055 startMsg(NULL), stopMsg(NULL), //msg init 00056 isConnected(false), isFix(false), isSac(false),//state init 00057 sockfd(0), myInfo(NULL), hostInfo(NULL) //socket init 00058 { 00059 startMsg = new char[2]; 00060 startMsg[0] = (char)1; 00061 startMsg[1] = '\0'; 00062 00063 stopMsg = new char[2]; 00064 stopMsg[0] = (char)2; 00065 stopMsg[1] = '\0'; 00066 } 00067 00068 // ###################################################################### 00069 EyeTrackerUDP::~EyeTrackerUDP() 00070 { 00071 delete startMsg; 00072 delete stopMsg; 00073 } 00074 00075 // ###################################################################### 00076 void EyeTrackerUDP::start1() 00077 { 00078 // start our udp listner 00079 FD_ZERO(&master); // clear the master and temp sets 00080 FD_ZERO(&read_fs); // clear the master and temp sets 00081 00082 //setup the type of socket to request 00083 struct addrinfo hints; 00084 memset(&hints, 0, sizeof hints); 00085 hints.ai_family = AF_UNSPEC;//ipv4 or ipv6 00086 hints.ai_socktype = SOCK_DGRAM;//UDP 00087 hints.ai_flags = AI_PASSIVE; // use my IP 00088 00089 //get some info about our own adress 00090 int rv; 00091 if ((rv = getaddrinfo(NULL, "9999", 00092 &hints, &myInfo)) < 0) 00093 { 00094 std::string ts = sformat("getaddrinfo: %s", gai_strerror(rv)); 00095 LINFO("%s", ts.c_str()); 00096 freeaddrinfo(myInfo); 00097 LFATAL("Fatal Error"); 00098 } 00099 00100 // loop through all the results and bind to the first we can 00101 for(; myInfo != NULL; myInfo = myInfo->ai_next) 00102 { 00103 if ((sockfd = socket(myInfo->ai_family, myInfo->ai_socktype, 00104 myInfo->ai_protocol)) == -1) 00105 { 00106 LINFO("Error::Socket"); 00107 continue; 00108 } 00109 00110 //bind our socket 00111 int bindr; 00112 if ((bindr = bind(sockfd, myInfo->ai_addr, myInfo->ai_addrlen)) < 0) 00113 { 00114 close(sockfd); 00115 LINFO("Error::Listener bind"); 00116 continue; 00117 } 00118 else break; 00119 } 00120 00121 if (myInfo == NULL) 00122 { 00123 LINFO("Error: Failed to bind socket"); 00124 freeaddrinfo(myInfo); 00125 LFATAL("Fatal Error"); 00126 } 00127 00128 if (hostInfo == NULL) 00129 LINFO("No host. Getting host from packets"); 00130 00131 // add the socket to the master set 00132 FD_SET(sockfd, &master); 00133 isConnected = true; 00134 LINFO("Socket creation succesful"); 00135 00136 //call our base start 00137 EyeTracker::start1(); 00138 } 00139 00140 // ###################################################################### 00141 void EyeTrackerUDP::start2() 00142 { 00143 Timer itsTimer; //our timout period 00144 00145 //wait for a code from host before we move on 00146 LINFO("Waiting for a UDP packet to complete start " 00147 "(timeout after 60 seconds)"); 00148 00149 while(true) 00150 { 00151 if (checkForData()) 00152 { 00153 LINFO("Recieved start signal from host"); 00154 break; 00155 } 00156 00157 if (itsTimer.getSecs() > 60.0) 00158 { 00159 LINFO("Timed out after 60 seconds. Finishing start without start " 00160 "signal from host"); 00161 break; 00162 } 00163 } 00164 clearEyeStatus(); 00165 } 00166 00167 // ###################################################################### 00168 void EyeTrackerUDP::stop1() 00169 { 00170 usleep(50000); 00171 FD_CLR(sockfd, &master); // remove from master set 00172 close(sockfd); 00173 //free our server info 00174 if (hostInfo!=myInfo) 00175 freeaddrinfo(hostInfo); 00176 freeaddrinfo(myInfo); 00177 hostInfo = NULL; 00178 myInfo = NULL; 00179 } 00180 00181 // ###################################################################### 00182 void EyeTrackerUDP::startTracking() 00183 { 00184 sendMessage(startMsg); 00185 } 00186 00187 // ###################################################################### 00188 void EyeTrackerUDP::stopTracking() 00189 { 00190 sendMessage(stopMsg); 00191 } 00192 00193 // ###################################################################### 00194 bool EyeTrackerUDP::isFixating() 00195 { 00196 //if true, a call by another state checking function set the isFix 00197 //state and we don't need to check again. Just flip the state and 00198 //return true. If false, check to see if any data is available and 00199 //then check our state again. 00200 if (isFix) 00201 { 00202 isFix = false; 00203 return true; 00204 } 00205 else 00206 { 00207 checkForData(); 00208 if (isFix) 00209 { 00210 isFix = false; 00211 return true; 00212 } 00213 } 00214 return false; 00215 } 00216 00217 // ###################################################################### 00218 bool EyeTrackerUDP::isSaccade() 00219 { 00220 //if true, a call by another state checking function set the isSac 00221 //state and we don't need to check again. Just flip the state and 00222 //return true. If false, check to see if any data is available and 00223 //then check our state again. 00224 if (isSac) 00225 { 00226 isSac = false; 00227 return true; 00228 } 00229 else 00230 { 00231 checkForData(); 00232 if (isSac) 00233 { 00234 isSac = false; 00235 return true; 00236 } 00237 } 00238 return false; 00239 } 00240 00241 // ###################################################################### 00242 void EyeTrackerUDP::clearEyeStatus() 00243 { 00244 while (checkForData()) ; //gobble up any data that has been sent 00245 resetEyeFlags(); //set all of our eye status flags to false 00246 } 00247 00248 // ###################################################################### 00249 bool EyeTrackerUDP::checkForData() 00250 { 00251 int numbytes = 0; 00252 if (isConnected) 00253 { 00254 struct timeval tm; 00255 tm.tv_sec = 0; 00256 tm.tv_usec = 0; 00257 00258 read_fs = master; // copy master 00259 select(sockfd+1, &read_fs, NULL, NULL, &tm); 00260 00261 if (FD_ISSET(sockfd, &read_fs)) 00262 { 00263 //ready to read 00264 lasthost_addrlen = sizeof lasthost_addr; 00265 unsigned char msgBuffer[BUFSIZE]; 00266 00267 if ( (numbytes = recvfrom(sockfd, msgBuffer, BUFSIZE-1 , 0, 00268 &lasthost_addr, 00269 &lasthost_addrlen)) <= 0) 00270 { 00271 // got error or connection closed by client 00272 if (numbytes == 0) 00273 { 00274 // connection closed 00275 pushEvent("Error::socket closed"); 00276 LFATAL("The connection closed"); 00277 } 00278 else 00279 pushEvent("Error::recieve"); 00280 } 00281 else 00282 { 00283 pushEvent("Received Trigger"); 00284 setEyeFlags(msgBuffer[0]); 00285 } 00286 }//end FS_SET == true 00287 } 00288 else 00289 { 00290 pushEvent("Must be conncted to listen"); 00291 LFATAL("Must be connected to listen"); 00292 } 00293 00294 return (bool)numbytes; 00295 } 00296 00297 // ###################################################################### 00298 Point2D<int> EyeTrackerUDP::getEyePos() const 00299 { 00300 LFATAL("Unavailable on UDP tracker, sorry."); 00301 return Point2D<int>(0, 0); 00302 } 00303 00304 // ###################################################################### 00305 Point2D<int> EyeTrackerUDP::getFixationPos() const 00306 { 00307 LFATAL("Unavailable on TIL tracker, sorry."); 00308 return Point2D<int>(0, 0); 00309 } 00310 00311 //####################################################################### 00312 //!Get the calibration set 00313 CalibrationTransform::Data EyeTrackerUDP::getCalibrationSet(nub::soft_ref<PsychoDisplay> d) const 00314 { 00315 CalibrationTransform::Data dummy; 00316 dummy.addData(Point2D<double>(-1.0,-1.0),Point2D<double>(-1.0,-1.0)); 00317 return dummy; 00318 } 00319 00320 00321 // ###################################################################### 00322 void EyeTrackerUDP::sendMessage(const char* msg) 00323 { 00324 //send some packets 00325 if (isConnected) 00326 { 00327 //return a status code to sender 00328 int check = 0; 00329 (hostInfo != NULL)? 00330 check = sendto(sockfd, msg, strlen(msg), 0, 00331 hostInfo->ai_addr, hostInfo->ai_addrlen) 00332 :check = sendto(sockfd, msg, strlen(msg), 0, 00333 &lasthost_addr, lasthost_addrlen); 00334 00335 (check < 0)? 00336 pushEvent("Error::Sending"): 00337 pushEvent( std::string("Listener::Sent '" + 00338 std::string(msg) + "'")); 00339 } 00340 else 00341 { 00342 pushEvent("Must be Connected to send a message"); 00343 LFATAL("Must be conncted to send a message"); 00344 } 00345 } 00346 00347 // ###################################################################### 00348 void EyeTrackerUDP::pushEvent(const std::string& ev) 00349 { 00350 if (itsEventLog.isValid()) 00351 itsEventLog->pushEvent(ev); 00352 } 00353 00354 // ###################################################################### 00355 void EyeTrackerUDP::setEyeFlags(const unsigned char msg) 00356 { 00357 switch (msg) 00358 { 00359 case FIXCODE : 00360 isFix = true; 00361 break; 00362 case SACCODE : 00363 isSac = true; 00364 break; 00365 } 00366 } 00367 00368 // ###################################################################### 00369 void EyeTrackerUDP::resetEyeFlags() 00370 { 00371 isFix = false; 00372 isSac = false; 00373 } 00374 00375 // ###################################################################### 00376 /* So things look consistent in everyone's emacs... */ 00377 /* Local Variables: */ 00378 /* mode: c++ */ 00379 /* indent-tabs-mode: nil */ 00380 /* End: */ 00381 00382 #endif // PSYCHO_EYETRACKERUDP_C_DEFINED