timinghdlr.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 1999-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Mon Jun 21 13:09:57 1999
00010 // commit: $Id: timinghdlr.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/visx/timinghdlr.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_VISX_TIMINGHDLR_CC_UTC20050626084016_DEFINED
00035 #define GROOVX_VISX_TIMINGHDLR_CC_UTC20050626084016_DEFINED
00036 
00037 #include "timinghdlr.h"
00038 
00039 #include "io/readutils.h"
00040 #include "io/writeutils.h"
00041 
00042 #include "nub/log.h"
00043 #include "nub/objmgr.h"
00044 #include "nub/ref.h"
00045 
00046 #include "tcl/timerscheduler.h"
00047 
00048 #include "rutz/error.h"
00049 #include "rutz/sfmt.h"
00050 #include "rutz/shared_ptr.h"
00051 #include "rutz/stopwatch.h"
00052 
00053 #include "visx/trialevent.h"
00054 
00055 #include <algorithm>
00056 #include <vector>
00057 
00058 #include "rutz/trace.h"
00059 #include "rutz/debug.h"
00060 GVX_DBG_REGISTER
00061 
00063 //
00064 // File scope stuff
00065 //
00067 
00068 namespace
00069 {
00070   const io::version_id TIMINGHDLR_SVID = 1;
00071 }
00072 
00074 //
00075 // TimingHdlr::Impl definition
00076 //
00078 
00079 class TimingHdlr::Impl
00080 {
00081 private:
00082   Impl(const Impl&);
00083   Impl& operator=(const Impl&);
00084 
00085 public:
00086   Impl() :
00087     scheduler(rutz::make_shared(new tcl::timer_scheduler)),
00088     immediateEvents(),
00089     startEvents(),
00090     responseEvents(),
00091     abortEvents(),
00092     timer(),
00093     trial(0)
00094     {}
00095 
00096   rutz::shared_ptr<nub::scheduler> scheduler;
00097 
00098   typedef std::vector<nub::ref<TrialEvent> > EventGroup;
00099 
00100   EventGroup immediateEvents;
00101   EventGroup startEvents;
00102   EventGroup responseEvents;
00103   EventGroup abortEvents;
00104 
00105   mutable rutz::stopwatch timer;
00106 
00107   EventGroup& eventsAt(TimePoint time_point)
00108   {
00109     switch (time_point)
00110       {
00111       case IMMEDIATE:     return immediateEvents;
00112       case FROM_START:    return startEvents;
00113       case FROM_RESPONSE: return responseEvents;
00114       case FROM_ABORT:    return abortEvents;
00115       }
00116 
00117     GVX_ASSERT(false);
00118 
00119     return abortEvents; // but we'll never get here
00120   }
00121 
00122   Trial* trial;
00123 
00124   static void scheduleAll(EventGroup& events,
00125                           rutz::shared_ptr<nub::scheduler> s,
00126                           Trial* trial);
00127   static void cancelAll(EventGroup& events);
00128 };
00129 
00131 //
00132 // TimingHdlr definitions
00133 //
00135 
00136 const TimingHdlr::TimePoint TimingHdlr::IMMEDIATE;
00137 const TimingHdlr::TimePoint TimingHdlr::FROM_START;
00138 const TimingHdlr::TimePoint TimingHdlr::FROM_RESPONSE;
00139 const TimingHdlr::TimePoint TimingHdlr::FROM_ABORT;
00140 
00142 //
00143 // TimingHdlr creator method definitions
00144 //
00146 
00147 TimingHdlr* TimingHdlr::make()
00148 {
00149 GVX_TRACE("TimingHdlr::make");
00150   return new TimingHdlr;
00151 }
00152 
00153 TimingHdlr::TimingHdlr() :
00154   rep(new Impl)
00155 {
00156 GVX_TRACE("TimingHdlr::TimingHdlr");
00157 }
00158 
00159 TimingHdlr::~TimingHdlr() throw()
00160 {
00161 GVX_TRACE("TimingHdlr::~TimingHdlr");
00162 
00163   delete rep;
00164 }
00165 
00166 io::version_id TimingHdlr::class_version_id() const
00167 {
00168 GVX_TRACE("TimingHdlr::class_version_id");
00169   return TIMINGHDLR_SVID;
00170 }
00171 
00172 void TimingHdlr::read_from(io::reader& reader)
00173 {
00174 GVX_TRACE("TimingHdlr::read_from");
00175 
00176   reader.ensure_version_id("TimingHdlr", 1, "Try groovx0.8a4", SRC_POS);
00177 
00178   rep->immediateEvents.clear();
00179   io::read_utils::read_object_seq<TrialEvent>(reader, "immediateEvents",
00180             std::back_inserter(rep->immediateEvents));
00181 
00182   rep->startEvents.clear();
00183   io::read_utils::read_object_seq<TrialEvent>(reader, "startEvents",
00184             std::back_inserter(rep->startEvents));
00185 
00186   rep->responseEvents.clear();
00187   io::read_utils::read_object_seq<TrialEvent>(reader, "responseEvents",
00188             std::back_inserter(rep->responseEvents));
00189 
00190   rep->abortEvents.clear();
00191   io::read_utils::read_object_seq<TrialEvent>(reader, "abortEvents",
00192             std::back_inserter(rep->abortEvents));
00193 }
00194 
00195 void TimingHdlr::write_to(io::writer& writer) const
00196 {
00197 GVX_TRACE("TimingHdlr::write_to");
00198 
00199   writer.ensure_output_version_id("TimingHdlr", TIMINGHDLR_SVID, 1,
00200                               "Try groovx0.8a4", SRC_POS);
00201 
00202   io::write_utils::write_object_seq(writer, "immediateEvents",
00203     rep->immediateEvents.begin(), rep->immediateEvents.end());
00204 
00205   io::write_utils::write_object_seq(writer, "startEvents",
00206     rep->startEvents.begin(), rep->startEvents.end());
00207 
00208   io::write_utils::write_object_seq(writer, "responseEvents",
00209     rep->responseEvents.begin(), rep->responseEvents.end());
00210 
00211   io::write_utils::write_object_seq(writer, "abortEvents",
00212     rep->abortEvents.begin(), rep->abortEvents.end());
00213 }
00214 
00216 // accessors //
00218 
00219 nub::ref<TrialEvent> TimingHdlr::getEvent(TimePoint time_point,
00220                                           unsigned int index) const
00221 {
00222 GVX_TRACE("TimingHdlr::getEvent");
00223   return rep->eventsAt(time_point).at(index);
00224 }
00225 
00226 double TimingHdlr::getElapsedMsec() const
00227 {
00228 GVX_TRACE("TimingHdlr::getElapsedMsec");
00229   return rep->timer.elapsed().msec();
00230 }
00231 
00233 // manipulators //
00235 
00236 unsigned int TimingHdlr::addEvent(nub::ref<TrialEvent> event_item,
00237                                   TimePoint time_point)
00238 {
00239 GVX_TRACE("TimingHdlr::addEvent");
00240 
00241   Impl::EventGroup& events = rep->eventsAt(time_point);
00242   events.push_back(event_item);
00243   return events.size() - 1;
00244 }
00245 
00246 unsigned int TimingHdlr::addEventByName(const char* event_type,
00247                                         TimePoint timepoint, int msec_delay)
00248 {
00249 GVX_TRACE("TimingHdlr::addEventByName");
00250 
00251   nub::ref<TrialEvent> event_item
00252     (nub::obj_mgr::new_typed_obj<TrialEvent>(event_type));
00253 
00254   event_item->setDelay(msec_delay);
00255   return addEvent(event_item, timepoint);
00256 }
00257 
00259 //
00260 // TimingHdlr helper function definitions
00261 //
00263 
00264 namespace
00265 {
00266   bool cmp_delay_less(const nub::ref<TrialEvent>& e1,
00267                       const nub::ref<TrialEvent>& e2)
00268   {
00269     return (e1->getDelay() < e2->getDelay());
00270   }
00271 }
00272 
00273 void TimingHdlr::Impl::scheduleAll(EventGroup& events,
00274                                    rutz::shared_ptr<nub::scheduler> s,
00275                                    Trial* trial)
00276 {
00277 GVX_TRACE("TimingHdlr::Impl::scheduleAll");
00278   GVX_PRECONDITION(trial != 0);
00279 
00280   // In order to ensure that events get scheduled in the proper order,
00281   // even if the whole event loop is getting bogged down, we do two
00282   // things: (1) sort the collection of events according to their
00283   // requested delays, and (2) keep track of the delay at which each
00284   // was actually scheduled, and make sure that the next event is
00285   // scheduled no sooner than that
00286 
00287   std::stable_sort(events.begin(), events.end(), cmp_delay_less);
00288 
00289   unsigned int minimum_delay = 0;
00290 
00291   for (size_t i = 0; i < events.size(); ++i)
00292     {
00293       unsigned int scheduled_delay =
00294         events[i]->schedule(s, *trial, minimum_delay);
00295       minimum_delay = scheduled_delay+1;
00296 
00297       nub::log(rutz::sfmt("scheduled @ %u: %s", scheduled_delay,
00298                           events[i]->unique_name().c_str()));
00299     }
00300 }
00301 
00302 void TimingHdlr::Impl::cancelAll(EventGroup& events)
00303 {
00304 GVX_TRACE("TimingHdlr::Impl::cancelAll");
00305   for (size_t i = 0; i < events.size(); ++i)
00306     {
00307       events[i]->cancel();
00308     }
00309 }
00310 
00312 //
00313 // TimingHdlr action method definitions
00314 //
00316 
00317 void TimingHdlr::thBeginTrial(Trial& trial)
00318 {
00319 GVX_TRACE("TimingHdlr::thBeginTrial");
00320 
00321   rep->timer.restart();
00322 
00323   rep->trial = &trial;
00324 
00325   Impl::cancelAll(rep->responseEvents);
00326   Impl::cancelAll(rep->abortEvents);
00327   Impl::scheduleAll(rep->immediateEvents, rep->scheduler, rep->trial);
00328   Impl::scheduleAll(rep->startEvents, rep->scheduler, rep->trial);
00329 }
00330 
00331 void TimingHdlr::thResponseSeen()
00332 {
00333 GVX_TRACE("TimingHdlr::thResponseSeen");
00334   if (rep->responseEvents.size() > 0)
00335     {
00336       Impl::cancelAll(rep->startEvents);
00337       Impl::scheduleAll(rep->responseEvents, rep->scheduler, rep->trial);
00338     }
00339 }
00340 
00341 void TimingHdlr::thAbortTrial()
00342 {
00343 GVX_TRACE("TimingHdlr::thAbortTrial");
00344   if (rep->abortEvents.size() > 0)
00345     {
00346       Impl::cancelAll(rep->startEvents);
00347       Impl::cancelAll(rep->responseEvents);
00348       Impl::scheduleAll(rep->abortEvents, rep->scheduler, rep->trial);
00349     }
00350 }
00351 
00352 void TimingHdlr::thEndTrial()
00353 {
00354 GVX_TRACE("TimingHdlr::thEndTrial");
00355   Impl::cancelAll(rep->immediateEvents);
00356   Impl::cancelAll(rep->startEvents);
00357   Impl::cancelAll(rep->responseEvents);
00358   Impl::cancelAll(rep->abortEvents);
00359 }
00360 
00361 void TimingHdlr::thHaltExpt()
00362 {
00363 GVX_TRACE("TimingHdlr::thHaltExpt");
00364   Impl::cancelAll(rep->startEvents);
00365   Impl::cancelAll(rep->responseEvents);
00366   Impl::cancelAll(rep->abortEvents);
00367 }
00368 
00369 static const char __attribute__((used)) vcid_groovx_visx_timinghdlr_cc_utc20050626084016[] = "$Id: timinghdlr.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00370 #endif // !GROOVX_VISX_TIMINGHDLR_CC_UTC20050626084016_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:42 2008 by Doxygen version 1.5.5.