00001
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
00033
00034 #ifndef GROOVX_VISX_TRIALEVENT_CC_UTC20050626084017_DEFINED
00035 #define GROOVX_VISX_TRIALEVENT_CC_UTC20050626084017_DEFINED
00036
00037 #include "visx/trialevent.h"
00038
00039 #include "io/ioproxy.h"
00040 #include "io/outputfile.h"
00041 #include "io/reader.h"
00042 #include "io/readutils.h"
00043 #include "io/writer.h"
00044 #include "io/writeutils.h"
00045
00046 #include "nub/log.h"
00047 #include "nub/ref.h"
00048
00049 #include "tcl/eventloop.h"
00050 #include "tcl/timerscheduler.h"
00051
00052 #include "rutz/algo.h"
00053 #include "rutz/error.h"
00054 #include "rutz/iter.h"
00055 #include "rutz/sfmt.h"
00056 #include "rutz/shared_ptr.h"
00057
00058 #include "visx/trial.h"
00059
00060 #include <fstream>
00061
00062 #include "rutz/trace.h"
00063 #include "rutz/debug.h"
00064 GVX_DBG_REGISTER
00065
00066 using rutz::fstring;
00067
00069
00070
00071
00073
00074 TrialEvent::TrialEvent(unsigned int msec) :
00075 itsTimer(msec, false),
00076 itsRequestedDelay(msec),
00077 itsTrial(0),
00078 itsEstimatedOffset(0.0),
00079 itsTotalOffset(0.0),
00080 itsTotalError(0.0),
00081 itsInvokeCount(0)
00082 {
00083 GVX_TRACE("TrialEvent::TrialEvent");
00084
00085 itsTimer.sig_timeout.connect(this, &TrialEvent::invokeTemplate);
00086 }
00087
00088 TrialEvent::~TrialEvent() throw()
00089 {
00090 GVX_TRACE("TrialEvent::~TrialEvent");
00091
00092 dbg_eval(3, itsTotalOffset);
00093 dbg_eval(3, itsTotalError);
00094 dbg_eval(3, itsInvokeCount);
00095 double averageError =
00096 itsInvokeCount ? itsTotalError/itsInvokeCount : 0.0;
00097 dbg_eval_nl(3, averageError);
00098 }
00099
00100 void TrialEvent::read_from(io::reader& reader)
00101 {
00102 GVX_TRACE("TrialEvent::read_from");
00103
00104 cancel();
00105
00106 reader.read_value("requestedDelay", itsRequestedDelay);
00107 }
00108
00109 void TrialEvent::write_to(io::writer& writer) const
00110 {
00111 GVX_TRACE("TrialEvent::write_to");
00112
00113 writer.write_value("requestedDelay", itsRequestedDelay);
00114 }
00115
00116 unsigned int TrialEvent::schedule(rutz::shared_ptr<nub::scheduler> s,
00117 Trial& trial,
00118 unsigned int minimum_msec)
00119 {
00120 GVX_TRACE("TrialEvent::schedule");
00121
00122
00123 itsTrial = &trial;
00124
00125
00126
00127
00128
00129
00130 unsigned int actual_request = 0;
00131
00132 if (itsRequestedDelay > 0)
00133 actual_request =
00134 rutz::max(int(itsRequestedDelay) + int(itsEstimatedOffset),
00135 int(minimum_msec));
00136
00137 itsTimer.set_delay_msec(actual_request);
00138 itsTimer.schedule(s);
00139
00140 return actual_request;
00141 }
00142
00143 void TrialEvent::cancel()
00144 {
00145 GVX_TRACE("TrialEvent::cancel");
00146 itsTimer.cancel();
00147 }
00148
00149 void TrialEvent::invokeTemplate()
00150 {
00151 GVX_TRACE("TrialEvent::invokeTemplate");
00152
00153 const double msec = itsTimer.elapsed_msec();
00154 const double error = itsTimer.delay_msec() - msec;
00155
00156 nub::logging::add_obj_scope(*this);
00157
00158 nub::log( rutz::sfmt("req %u - %f",
00159 itsRequestedDelay, -itsEstimatedOffset) );
00160
00161 itsTotalOffset += error;
00162 itsTotalError += (itsRequestedDelay - msec);
00163
00164 ++itsInvokeCount;
00165
00166
00167
00168
00169 const double moving_average_ratio =
00170 1.0 / rutz::min(10, itsInvokeCount);
00171
00172 itsEstimatedOffset =
00173 (1.0 - moving_average_ratio) * itsEstimatedOffset +
00174 moving_average_ratio * error;
00175
00176
00177 if ( itsTrial != 0 )
00178 {
00179 invoke(*itsTrial);
00180 }
00181
00182 nub::logging::remove_obj_scope(*this);
00183 }
00184
00185
00186
00187
00188
00189
00190
00191 NullTrialEvent::NullTrialEvent(unsigned int msec) : TrialEvent(msec) {}
00192
00193 NullTrialEvent::~NullTrialEvent() throw() {}
00194
00195 void NullTrialEvent::invoke(Trial&) {}
00196
00197
00198
00199
00200
00201
00202
00203 fstring TrialMemFuncEvent::obj_typename() const
00204 {
00205 return itsTypename;
00206 }
00207
00208 TrialMemFuncEvent* TrialMemFuncEvent::make(CallbackType callback,
00209 const fstring& type,
00210 unsigned int msec)
00211 {
00212 return new TrialMemFuncEvent(callback, type, msec);
00213 }
00214
00215 TrialMemFuncEvent::TrialMemFuncEvent(CallbackType callback,
00216 const fstring& type,
00217 unsigned int msec) :
00218 TrialEvent(msec),
00219 itsCallback(callback),
00220 itsTypename(type)
00221 {}
00222
00223 TrialMemFuncEvent::~TrialMemFuncEvent() throw() {}
00224
00225 void TrialMemFuncEvent::invoke(Trial& trial)
00226 {
00227 GVX_TRACE("TrialMemFuncEvent::invoke");
00228 (trial.*itsCallback)();
00229 }
00230
00231 #define MAKE_EVENT(EventName) \
00232 TrialEvent* make##EventName##Event() \
00233 { \
00234 return TrialMemFuncEvent::make(&Trial::tr##EventName, \
00235 #EventName "Event"); \
00236 }
00237
00238 MAKE_EVENT(AbortTrial);
00239 MAKE_EVENT(Draw);
00240 MAKE_EVENT(Render);
00241 MAKE_EVENT(EndTrial);
00242 MAKE_EVENT(NextNode);
00243 MAKE_EVENT(AllowResponses);
00244 MAKE_EVENT(DenyResponses);
00245 MAKE_EVENT(Undraw);
00246 MAKE_EVENT(RenderBack);
00247 MAKE_EVENT(RenderFront);
00248 MAKE_EVENT(SwapBuffers);
00249 MAKE_EVENT(ClearBuffer);
00250 MAKE_EVENT(FinishDrawing);
00251
00252 #undef MAKE_EVENT
00253
00254
00255
00256
00257
00258
00259
00260 FileWriteEvent::FileWriteEvent(unsigned int msec) :
00261 TrialEvent(msec),
00262 itsFile(output_file::make())
00263 {}
00264
00265 FileWriteEvent::~FileWriteEvent() throw() {}
00266
00267 void FileWriteEvent::invoke(Trial& )
00268 {
00269 if (itsFile->has_stream())
00270 {
00271 itsFile->stream().put(static_cast<char>(itsByte));
00272 itsFile->stream().flush();
00273 nub::log( rutz::sfmt("wrote '%d' to '%s'",
00274 itsByte, itsFile->get_filename().c_str()) );
00275 }
00276 }
00277
00278 void FileWriteEvent::read_from(io::reader& reader)
00279 {
00280 itsFile = dyn_cast<output_file>(reader.read_object("file"));
00281 reader.read_value("byte", itsByte);
00282
00283 reader.read_base_class("TrialEvent",
00284 io::make_proxy<TrialEvent>(this));
00285 }
00286
00287 void FileWriteEvent::write_to(io::writer& writer) const
00288 {
00289 writer.write_object("file", itsFile);
00290 writer.write_value("byte", itsByte);
00291
00292 writer.write_base_class("TrialEvent",
00293 io::make_const_proxy<TrialEvent>(this));
00294 }
00295
00296 int FileWriteEvent::getByte() const
00297 {
00298 return itsByte;
00299 }
00300
00301 void FileWriteEvent::setByte(int b)
00302 {
00303 itsByte = b;
00304 }
00305
00306 nub::ref<output_file> FileWriteEvent::getFile() const
00307 {
00308 return itsFile;
00309 }
00310
00311 void FileWriteEvent::setFile(nub::ref<output_file> file)
00312 {
00313 itsFile = file;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322 GenericEvent::GenericEvent(unsigned int msec) :
00323 TrialEvent(msec),
00324 itsCallback(new tcl::ProcWrapper(tcl::event_loop::interp()))
00325 {}
00326
00327 GenericEvent::~GenericEvent() throw() {}
00328
00329 void GenericEvent::invoke(Trial& )
00330 {
00331 itsCallback->invoke("");
00332 }
00333
00334 void GenericEvent::read_from(io::reader& reader)
00335 {
00336 reader.read_owned_object("callback", itsCallback);
00337
00338 reader.read_base_class("TrialEvent",
00339 io::make_proxy<TrialEvent>(this));
00340 }
00341
00342 void GenericEvent::write_to(io::writer& writer) const
00343 {
00344 writer.write_owned_object("callback", itsCallback);
00345
00346 writer.write_base_class("TrialEvent",
00347 io::make_const_proxy<TrialEvent>(this));
00348 }
00349
00350 fstring GenericEvent::getCallback() const
00351 {
00352 return itsCallback->fullSpec();
00353 }
00354
00355 void GenericEvent::setCallback(const fstring& script)
00356 {
00357 itsCallback->define("", script);
00358 }
00359
00360
00361
00362
00363
00364
00365
00366 MultiEvent::MultiEvent(unsigned int msec) :
00367 TrialEvent(msec),
00368 itsEvents()
00369 {}
00370
00371 MultiEvent::~MultiEvent() throw() {}
00372
00373 void MultiEvent::invoke(Trial& trial)
00374 {
00375 for (unsigned int i = 0; i < itsEvents.size(); ++i)
00376 {
00377 itsEvents[i]->setDelay(0);
00378 itsEvents[i]->invoke(trial);
00379 }
00380 }
00381
00382 void MultiEvent::read_from(io::reader& reader)
00383 {
00384 std::vector<nub::ref<TrialEvent> > newEvents;
00385
00386 io::read_utils::read_object_seq<TrialEvent>
00387 (reader, "events", std::back_inserter(newEvents));
00388
00389 itsEvents.swap(newEvents);
00390
00391 reader.read_base_class("TrialEvent", io::make_proxy<TrialEvent>(this));
00392 }
00393
00394 void MultiEvent::write_to(io::writer& writer) const
00395 {
00396 io::write_utils::write_object_seq(writer, "events",
00397 itsEvents.begin(),
00398 itsEvents.end());
00399
00400 writer.write_base_class("TrialEvent",
00401 io::make_const_proxy<TrialEvent>(this));
00402 }
00403
00404 rutz::fwd_iter<const nub::ref<TrialEvent> >
00405 MultiEvent::getEvents() const
00406 {
00407 GVX_TRACE("MultiEvent::getEvents");
00408
00409 return rutz::fwd_iter<const nub::ref<TrialEvent> >
00410 (itsEvents.begin(), itsEvents.end());
00411 }
00412
00413 unsigned int MultiEvent::addEvent(nub::ref<TrialEvent> event)
00414 {
00415 GVX_TRACE("MultiEvent::addEvent");
00416 itsEvents.push_back(event);
00417 GVX_ASSERT(itsEvents.size() >= 1);
00418 return itsEvents.size() - 1;
00419 }
00420
00421 void MultiEvent::eraseEventAt(unsigned int index)
00422 {
00423 GVX_TRACE("MultiEvent::eraseEventAt");
00424 if (index >= itsEvents.size())
00425 throw rutz::error("index out of bounds", SRC_POS);
00426
00427 itsEvents.erase(itsEvents.begin() + index);
00428 }
00429
00430 void MultiEvent::clearEvents()
00431 {
00432 GVX_TRACE("MultiEvent::clearEvents");
00433 itsEvents.clear();
00434 }
00435
00436 static const char __attribute__((used)) vcid_groovx_visx_trialevent_cc_utc20050626084017[] = "$Id: trialevent.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00437 #endif // !GROOVX_VISX_TRIALEVENT_CC_UTC20050626084017_DEFINED