Tscope5
timer.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // __ ______
4 // / /_______________ ____ ___ / ____/
5 // / __/ ___/ ___/ __ \/ __ \/ _ \ /___ )
6 // / /_(__ ) /__/ /_/ / /_/ / __/ ____/ /
7 // \__/____/\___/\____/ .___/\___/ /_____/
8 // /_/
9 //
10 /// \file timer.c
11 /// Definitions of timer functions
12 /// \example timer01.c
13 /// \example timer02.c
14 /// \example timer03.c
15 /// \example timer04.c
16 /// \example timer05.c
17 /// \example timer06.c
18 ////////////////////////////////////////////////////////////////////////////////
19 
20 
21 #include "../include/tscope5/timer.h"
22 #include "../include/tscope5/timer_internal.h"
23 #include "../include/tscope5/system_internal.h"
24 
25 #ifdef TS5_WINDOWS
26  #include <windows.h>
27 
28 #elif defined TS5_MACOSX
29  #include <unistd.h>
30  #include <sys/resource.h>
31  #include <sys/types.h>
32 
33 #elif defined TS5_LINUX
34  #include <unistd.h>
35  #include <sys/time.h>
36  #include <sys/resource.h>
37 
38 #endif
39 
40 ////////////////////////////////////////////////////////////////////////////////
41 /// @name Program priority functions
42 /// You can increase your program's priority to get better timing accuracy.
43 //@{
44 ////////////////////////////////////////////////////////////////////////////////
45 
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 /// Set the program's priority
49 /// \param priority Priority.
50 ///
51 /// \return The previous priority.
52 ///
53 /// There are five possible settings:
54 /// - TS5_HIGH_PRIORITY
55 /// - TS5_ABOVE_NORMAL_PRIORITY
56 /// - TS5_NORMAL_PRIORITY
57 /// - TS5_BELOW_NORMAL_PRIORITY
58 /// - TS5_LOW_PRIORITY.
59 ///
60 /// The default priority is TS5_NORMAL_PRIORITY.
61 ////////////////////////////////////////////////////////////////////////////////
62 int ts5_set_priority(int priority)
63 {
64  ts5_check_timer("ts5_set_priority");
65  ts5_log(TS5_LOGLEVEL_4, "ts5_set_priority(%d)\n", priority);
66 
67  int oldval = _ts5_status.timer.priority;
68 
69 
70  #ifdef TS5_WINDOWS
71  HANDLE h;
72  h = GetCurrentProcess();
73 
74  DWORD priorityclass;
75 
76  if (priority == TS5_HIGH_PRIORITY) {
77  priorityclass = HIGH_PRIORITY_CLASS;
78  }
79  else if (priority == TS5_ABOVE_NORMAL_PRIORITY) {
80  priorityclass = ABOVE_NORMAL_PRIORITY_CLASS;
81  }
82  else if (priority == TS5_NORMAL_PRIORITY) {
83  priorityclass = NORMAL_PRIORITY_CLASS;
84  }
85  else if (priority == TS5_BELOW_NORMAL_PRIORITY) {
86  priorityclass = BELOW_NORMAL_PRIORITY_CLASS;
87  }
88  else if (priority == TS5_LOW_PRIORITY) {
89  priorityclass = IDLE_PRIORITY_CLASS;
90  }
91  else {
92  ts5_fatal("ts5_set_priority: unknown priority requested\n");
93  }
94 
95  if (!SetPriorityClass(h, priorityclass)) {
96  ts5_fatal("ts5_set_priority: can't change program priority\n");
97  }
98 
99  #elif defined TS5_MACOSX
100  if (geteuid() != 0) {
101  ts5_fatal("%s: %s, %s\n", "ts5_set_priority", "not running as root",
102  "can't change program priority");
103  }
104 
105  int priorityclass;
106 
107  if (priority == TS5_HIGH_PRIORITY) {
108  priorityclass = -20;
109  }
110  else if (priority == TS5_ABOVE_NORMAL_PRIORITY) {
111  priorityclass = -10;
112  }
113  else if (priority == TS5_NORMAL_PRIORITY) {
114  priorityclass = 0;
115  }
116  else if (priority == TS5_BELOW_NORMAL_PRIORITY) {
117  priorityclass = 10;
118  }
119  else if (priority == TS5_LOW_PRIORITY) {
120  priorityclass = 20;
121  }
122  else {
123  ts5_fatal("ts5_set_priority: unknown priority requested\n");
124  }
125 
126  if (setpriority(PRIO_PGRP, 0, priorityclass)) {
127  ts5_fatal("ts5_set_priority: can't change program priority\n");
128  }
129 
130 
131  #elif defined TS5_LINUX
132  if (geteuid() != 0) {
133  ts5_fatal("%s: %s, %s\n", "ts5_set_priority", "not running as root",
134  "can't change program priority");
135  }
136 
137  ts5_check_timer4("ts5_set_priority");
138 
139  int priorityclass;
140 
141  if (priority == TS5_HIGH_PRIORITY) {
142  priorityclass = -20;
143  }
144  else if (priority == TS5_ABOVE_NORMAL_PRIORITY) {
145  priorityclass = -10;
146  }
147  else if (priority == TS5_NORMAL_PRIORITY) {
148  priorityclass = 0;
149  }
150  else if (priority == TS5_BELOW_NORMAL_PRIORITY) {
151  priorityclass = 10;
152  }
153  else if (priority == TS5_LOW_PRIORITY) {
154  priorityclass = 19;
155  }
156 
157  else {
158  ts5_fatal("ts5_set_priority: unknown priority requested\n");
159  }
160 
161  if (setpriority(PRIO_PGRP, 0, priorityclass)) {
162  ts5_fatal("ts5_set_priority: can't change program priority\n");
163  }
164 
165  #endif
166 
167  _ts5_status.timer.priority = priority;
168 
169  return oldval;
170 }
171 
172 
173 ////////////////////////////////////////////////////////////////////////////////
174 /// Get the program's priority
175 ///
176 /// \return The program's priority.
177 ////////////////////////////////////////////////////////////////////////////////
179 {
180  ts5_check_timer("ts5_get_priority");
181  ts5_log(TS5_LOGLEVEL_4, "ts5_get_priority()\n");
182 
183  return _ts5_status.timer.priority;
184 }
185 
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 //@}
189 ////////////////////////////////////////////////////////////////////////////////
190 
191 
192 ////////////////////////////////////////////////////////////////////////////////
193 /// @name General timing functions
194 /// The general timing functions are mainly used to control stimulus timing.
195 ///
196 /// You can either wait for a given amount of time,
197 /// or until some time in the future.
198 //@{
199 ////////////////////////////////////////////////////////////////////////////////
200 
201 
202 ////////////////////////////////////////////////////////////////////////////////
203 /// Get the number of seconds since the program started.
204 ///
205 /// \return The number of seconds since the program started
206 /// (as a double precision float).
207 ////////////////////////////////////////////////////////////////////////////////
208 double ts5_get_time()
209 {
210  ts5_check_timer("ts5_get_time");
211  ts5_log(TS5_LOGLEVEL_5, "ts5_get_time()\n");
212 
213  return al_get_time();
214 }
215 
216 
217 ////////////////////////////////////////////////////////////////////////////////
218 /// Wait for a number of seconds.
219 ////////////////////////////////////////////////////////////////////////////////
220 void ts5_wait(double waittime)
221 {
222  ts5_check_timer("ts5_wait");
223  ts5_log(TS5_LOGLEVEL_5, "ts5_wait(%f)\n", waittime);
224 
225  // only use up cpu during the last 20 ms.
226  double starttime = al_get_time();
227 
228  if (waittime > 0.02) {
229  while (al_get_time() < starttime + waittime - 0.02) {
231  }
232  }
233 
234  while (al_get_time() < starttime+waittime) {
235 
236  }
237 }
238 
239 
240 ////////////////////////////////////////////////////////////////////////////////
241 /// Wait until a deadline.
242 ////////////////////////////////////////////////////////////////////////////////
243 void ts5_wait_until(double deadline)
244 {
245  ts5_check_timer("ts5_wait_until");
246  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_until(%f)\n", deadline);
247 
248  // only use up cpu during the last 20 ms.
249  double starttime = al_get_time();
250 
251  if (deadline - starttime > 0.02) {
252  while (al_get_time() < deadline - 0.02) {
254  }
255  }
256 
257  while (al_get_time() < deadline) {
258 
259  }
260 }
261 
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 //@}
265 ////////////////////////////////////////////////////////////////////////////////
266 
267 
268 ////////////////////////////////////////////////////////////////////////////////
269 /// @name Response registration
270 /// The response registration functions require you to define
271 /// response buttons first using ts5_define_mouse_button(),
272 /// ts5_define_keyboard_button(), ts5_define_joystick_button(),
273 /// ts5_define_cedrusbox_button() or ts5_define_parport_button().
274 ///
275 /// Each response button will get a response value.
276 /// The first button that is defined will get number 1, etc.
277 ///
278 /// Registration of responses is done asynchronously.
279 /// All button presses that are defined will be buffered
280 /// continuously during the program.
281 ///
282 /// Waiting for a response to a stimulus will typically involve
283 /// flushing all buffered responses that occurred before stimulus onset using
284 /// ts5_flush_responses() and then checking for new responses using
285 /// ts5_check_response(), ts5_wait_for_response(),
286 /// ts5_wait_for_response_timed() or ts5_wait_for_response_until().
287 ///
288 /// The response definition can be altered during the program using
289 /// ts5_hide_response_button() or ts5_remove_response_buttons().
290 //@{
291 ////////////////////////////////////////////////////////////////////////////////
292 
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 /// Temporarily deactivates a response button.
296 ///
297 /// \param button The button that has to be deactivated.
298 ///
299 /// \return The number of active buttons left.
300 ///
301 /// This function also checks whether there are any active response left.
302 /// Aborts if necessary.
303 ///
304 /// Reactivating all defined buttons is possible by calling
305 /// ts5_hide_response_button(0).
306 ////////////////////////////////////////////////////////////////////////////////
308 {
309  ts5_check_timer("ts5_hide_response_button");
310  ts5_check_timer2("ts5_hide_response_button");
311  ts5_log(TS5_LOGLEVEL_3, "ts5_hide_response_button(%d)\n", button);
312 
313  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
314 
315  if (button<0 || button>timer->num_defined_buttons) {
316  ts5_fatal("%s: %s %d, %s %d\n", "ts5_hide_response_button",
317  "button argument is", button,
318  "number of defined buttons is",
319  timer->num_defined_buttons);
320  }
321 
322  // reactivate
323  int found = 1;
324 
325  if (button==0) {
326 
327  int i, j;
328 
329  if (timer->mouse_is_response_device) {
330 
331  for (i=0; i<timer->mouse.num_buttons; i++) {
332 
333  timer->mouse.button_press_active[i] =
334  timer->mouse.button_press_defined[i];
335 
336  timer->mouse.button_release_active[i] =
337  timer->mouse.button_release_defined[i];
338  }
339 
340  timer->mouse.num_active_buttons =
341  timer->mouse.num_defined_buttons;
342  }
343 
344  if (timer->keyboard_is_response_device) {
345 
346  for (i=0; i<timer->keyboard.num_buttons; i++) {
347 
348  timer->keyboard.button_press_active[i] =
349  timer->keyboard.button_press_defined[i];
350 
351  timer->keyboard.button_release_active[i] =
352  timer->keyboard.button_release_defined[i];
353  }
354 
355  timer->keyboard.num_active_buttons =
356  timer->keyboard.num_defined_buttons;
357  }
358 
359  if (timer->joystick_is_response_device) {
360 
361  for (i=0; i<timer->num_joysticks; i++) {
362 
363  for (j=0; j<timer->joystick[i].num_buttons; j++) {
364 
365  timer->joystick[i].button_press_active[j] =
366  timer->joystick[i].button_press_defined[j];
367 
368  timer->joystick[i].button_release_active[j] =
369  timer->joystick[i].button_release_defined[j];
370  }
371  timer->joystick[i].num_active_buttons =
372  timer->joystick[i].num_defined_buttons;
373  }
374  }
375 
376  if (timer->cedrusbox_is_response_device) {
377 
378  for (i=0; i<timer->num_cedrusboxes; i++) {
379 
380  for (j=0; j<timer->cedrusbox[i].num_buttons; j++) {
381 
382  timer->cedrusbox[i].button_press_active[j] =
383  timer->cedrusbox[i].button_press_defined[j];
384 
385  timer->cedrusbox[i].button_release_active[j] =
386  timer->cedrusbox[i].button_release_defined[j];
387  }
388  timer->cedrusbox[i].num_active_buttons =
389  timer->cedrusbox[i].num_defined_buttons;
390  }
391  }
392  timer->num_active_buttons =
393  timer->num_defined_buttons;
394  }
395  else {
396  int i, j;
397  found=0;
398 
399  if (timer->mouse_is_response_device) {
400 
401  for (i=0; i<timer->mouse.num_buttons; i++) {
402 
403  if (button==timer->mouse.button_press_active[i]) {
404  timer->mouse.button_press_active[i] = 0;
405  found = 1;
406  }
407  else if (button==timer->mouse.button_release_active[i]) {
408  timer->mouse.button_release_active[i] = 0;
409  found = 1;
410  }
411 
412  if (found) {
413  timer->mouse.num_active_buttons--;
414  timer->num_active_buttons--;
415  goto end;
416  }
417  }
418  }
419 
420  if (timer->keyboard_is_response_device) {
421 
422  for (i=0; i<timer->keyboard.num_buttons; i++) {
423 
424  if (button==timer->keyboard.button_press_active[i]) {
425  timer->keyboard.button_press_active[i] = 0;
426  found = 1;
427  }
428  else if (button==timer->keyboard.button_release_active[i]) {
429  timer->keyboard.button_release_active[i] = 0;
430  found = 1;
431  }
432 
433  if (found) {
434  timer->keyboard.num_active_buttons--;
435  timer->num_active_buttons--;
436  goto end;
437  }
438  }
439  }
440 
441  if (timer->joystick_is_response_device) {
442 
443  for (i=0; i<timer->num_joysticks; i++) {
444 
445  for (j=0; j<timer->joystick[i].num_buttons; j++) {
446 
447  if (button==timer->joystick[i].button_press_active[j]) {
448  timer->joystick[i].button_press_active[j] = 0;
449  found = 1;
450  }
451  else if (button==timer->joystick[i].button_release_active[j]) {
452  timer->joystick[i].button_release_active[j] = 0;
453  found = 1;
454  }
455 
456  if (found) {
457  timer->joystick[i].num_active_buttons--;
458  timer->num_active_buttons--;
459  goto end;
460  }
461  }
462  }
463  }
464 
465  if (timer->cedrusbox_is_response_device) {
466 
467  for (i=0; i<timer->num_cedrusboxes; i++) {
468 
469  for (j=0; j<timer->cedrusbox[i].num_buttons; j++) {
470 
471  if (button==timer->cedrusbox[i].button_press_active[j]) {
472  timer->cedrusbox[i].button_press_active[j] = 0;
473  found = 1;
474  }
475  else if (button==timer->cedrusbox[i].button_release_active[j]){
476  timer->cedrusbox[i].button_release_active[j] = 0;
477  found = 1;
478  }
479 
480  if (found) {
481  timer->cedrusbox[i].num_active_buttons--;
482  timer->num_active_buttons--;
483  goto end;
484  }
485  }
486  }
487  }
488  }
489 
490  end:
491 
492  if (!found) {
493  ts5_fatal("ts5_hide_response_button: response button %d not found\n", button);
494  }
495 
496  if (timer->num_active_buttons<1) {
497  ts5_fatal("%s: %s\n", "ts5_hide_response_button",
498  "there are no active response buttons left");
499  }
500 
501  return timer->num_active_buttons;
502 }
503 
504 
505 ////////////////////////////////////////////////////////////////////////////////
506 /// Completely removes the response button definition.
507 ////////////////////////////////////////////////////////////////////////////////
509 {
510  ts5_check_timer("ts5_remove_response_buttons");
511  ts5_log(TS5_LOGLEVEL_3, "ts5_remove_response_buttons()\n");
512 
513  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
514 
515  int i, j;
516 
517  // mouse
518  if (timer->mouse_is_response_device) {
519 
520  for (i=0; i<timer->mouse.num_buttons; i++) {
521 
522  timer->mouse.button_press_defined[i] = 0;
523  timer->mouse.button_press_active[i] = 0;
524  timer->mouse.button_release_defined[i] = 0;
525  timer->mouse.button_release_active[i] = 0;
526  }
527 
528  timer->mouse_is_response_device = 0;
529  }
530 
531  // keyboard
532  if (timer->keyboard_is_response_device) {
533 
534  for (i=0; i<timer->keyboard.num_buttons; i++) {
535 
536  timer->keyboard.button_press_defined[i] = 0;
537  timer->keyboard.button_press_active[i] = 0;
538  timer->keyboard.button_release_defined[i] = 0;
539  timer->keyboard.button_release_active[i] = 0;
540  }
541 
542  timer->keyboard_is_response_device = 0;
543  }
544 
545  // joystick
546  if (timer->joystick_is_response_device) {
547 
548  for (i=0; i<timer->num_joysticks; i++) {
549 
550  for (j=0; j<timer->joystick[i].num_buttons; j++) {
551 
552  timer->joystick[i].button_press_defined[j] = 0;
553  timer->joystick[i].button_press_active[j] = 0;
554  timer->joystick[i].button_release_defined[j] = 0;
555  timer->joystick[i].button_release_active[j] = 0;
556  }
557  }
558 
559  timer->joystick_is_response_device = 0;
560  }
561 
562  // joystick
563  if (timer->joystick_is_response_device) {
564 
565  for (i=0; i<timer->num_joysticks; i++) {
566 
567  for (j=0; j<timer->joystick[i].num_buttons; j++) {
568 
569  timer->joystick[i].button_press_defined[j] = 0;
570  timer->joystick[i].button_press_active[j] = 0;
571  timer->joystick[i].button_release_defined[j] = 0;
572  timer->joystick[i].button_release_active[j] = 0;
573  }
574  }
575 
576  timer->joystick_is_response_device = 0;
577  }
578 
579  // cedrusbox
580  if (timer->cedrusbox_is_response_device) {
581 
582  for (i=0; i<timer->num_cedrusboxes; i++) {
583 
584  for (j=0; j<timer->cedrusbox[i].num_buttons; j++) {
585 
586  timer->cedrusbox[i].button_press_defined[j] = 0;
587  timer->cedrusbox[i].button_press_active[j] = 0;
588  timer->cedrusbox[i].button_release_defined[j] = 0;
589  timer->cedrusbox[i].button_release_active[j] = 0;
590  }
591  }
592  timer->cedrusbox_is_response_device = 0;
593  }
594 
595  timer->num_defined_buttons=0;
596  timer->num_active_buttons=0;
597 }
598 
599 
600 ////////////////////////////////////////////////////////////////////////////////
601 /// Flush the response queue.
602 ////////////////////////////////////////////////////////////////////////////////
604 {
605  ts5_check_timer("ts5_flush_responses");
606  ts5_log(TS5_LOGLEVEL_5, "ts5_flush_responses()\n");
607 
608  al_flush_event_queue(_ts5_data.timer.response_queue);
609 }
610 
611 
612 ////////////////////////////////////////////////////////////////////////////////
613 /// Check for a reponse.
614 ///
615 /// \param resptime Variable that will store the response time.
616 /// \param timing_error Variable that will store the timing error
617 /// (works only for cedrusboxes and parallel port boxes).
618 ///
619 /// \return The button that was pressed
620 /// (0 if no button was pressed within the deadline).
621 ///
622 /// This function checks for a response and returns immediately.
623 ////////////////////////////////////////////////////////////////////////////////
624 int ts5_check_response(double *resptime, double *timing_error)
625 {
626  ts5_check_timer("ts5_check_response");
627  ts5_check_timer2("ts5_check_response");
628  ts5_log(TS5_LOGLEVEL_6, "ts5_check_response(%p,%p)\n",
629  resptime, timing_error);
630 
631  int resp=0;
632  ALLEGRO_EVENT event;
633 
634  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
635 
636  if (!al_get_next_event(_ts5_data.timer.response_queue, &event)) {
637 
638  if (resptime!=NULL) {
639  *resptime = al_get_time();
640  }
641  if (timing_error!=NULL) {
642  *timing_error = 0.0;
643  }
644  }
645  else {
646 
647  if (resptime!=NULL) {
648  *resptime = event.any.timestamp;
649  }
650 
651  if (timing_error!=NULL) {
652  *timing_error = 0.0;
653  }
654 
655  int i;
656 
657  // mouse (driver response codes are counted from 1)
658  if (timer->mouse_is_response_device) {
659 
660  if (timer->mouse.num_active_buttons) {
661 
662  if (event.type==ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
663 
664  resp = timer->mouse
665  .button_press_active[event.mouse.button-1];
666  }
667 
668  if (event.type==ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
669  resp = timer->mouse
670  .button_release_active[event.mouse.button-1];
671  }
672  }
673  }
674 
675  // keyboard (driver response codes are counted from 1)
676  if (timer->keyboard_is_response_device) {
677 
678  if (timer->keyboard.num_active_buttons) {
679 
680  if (event.type==ALLEGRO_EVENT_KEY_DOWN) {
681  resp = timer->keyboard
682  .button_press_active[event.keyboard.keycode-1];
683  }
684 
685  if (event.type==ALLEGRO_EVENT_KEY_UP) {
686  resp = timer->keyboard
687  .button_release_active[event.keyboard.keycode-1];
688  }
689  }
690  }
691 
692  // joystick (driver response codes are counted from 0)
693  if (timer->joystick_is_response_device) {
694 
695  for (i=0; i<timer->num_joysticks; i++) {
696 
697  if (timer->joystick[i].num_active_buttons) {
698 
699  if (event.type==ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN) {
700 
701  ALLEGRO_JOYSTICK *stick = al_get_joystick(i);
702 
703  if (event.joystick.id == stick) {
704  resp = timer->joystick[i]
705  .button_press_active[event.joystick.button];
706  }
707  }
708 
709  if (event.type==ALLEGRO_EVENT_JOYSTICK_BUTTON_UP) {
710 
711  ALLEGRO_JOYSTICK *stick = al_get_joystick(i);
712 
713  if (event.joystick.id == stick) {
714  resp = timer->joystick[i]
715  .button_release_active
716  [event.joystick.button];
717  }
718  }
719  }
720  }
721  }
722 
723  // cedrusbox (driver response codes are counted from 0)
724  if (timer->cedrusbox_is_response_device) {
725 
726  for (i=0; i<timer->num_cedrusboxes; i++) {
727 
728  if (timer->cedrusbox[i].num_active_buttons) {
729 
730  if (event.type==TS5_EVENT_CEDRUS_BUTTON_DOWN) {
731 
732  if (event.user.data1 == i) {
733  resp = timer->cedrusbox[i]
734  .button_press_active[event.user.data2];
735  }
736  }
737 
738  if (event.type==TS5_EVENT_CEDRUS_BUTTON_UP) {
739 
740  if (event.user.data1 == i) {
741  resp = timer->cedrusbox[i]
742  .button_release_active[event.user.data2];
743  }
744  }
745 
746  if (resp && timing_error!=NULL) {
747  *timing_error = ((double)event.user.data3)/1000000.0;
748  }
749  }
750  }
751  }
752 
753  // parallel port (driver response codes are counted from 1)
754  if (timer->parport_is_response_device) {
755 
756  for (i=0; i<timer->num_parports; i++) {
757 
758  if (timer->parport[i].num_active_buttons) {
759 
760  if (event.type==TS5_EVENT_PARPORT_BUTTON_DOWN) {
761 
762  if (event.user.data1 == i) {
763  resp = timer->parport[i]
764  .button_press_active[event.user.data2-1];
765  }
766  }
767 
768  if (event.type==TS5_EVENT_PARPORT_BUTTON_UP) {
769 
770  if (event.user.data1 == i) {
771  resp = timer->parport[i]
772  .button_release_active[event.user.data2-1];
773  }
774  }
775 
776  if (resp && timing_error!=NULL) {
777  *timing_error = ((double)event.user.data3)/1000000.0;
778  }
779  }
780  }
781  }
782  }
783 
784  return resp;
785 }
786 
787 
788 ////////////////////////////////////////////////////////////////////////////////
789 /// Wait for a response.
790 ///
791 /// \param resptime Variable that will store the response time.
792 /// \param timing_error Variable that will store the timing error
793 /// (works only for cedrusboxes and parallel port boxes).
794 ///
795 /// \return The button that was pressed.
796 ////////////////////////////////////////////////////////////////////////////////
797 int ts5_wait_for_response(double *resptime, double *timing_error)
798 {
799  ts5_check_timer("ts5_wait_for_response");
800  ts5_check_timer2("ts5_wait_for_response");
801  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_response(%p,%p)\n",
802  resptime, timing_error);
803 
804  int resp=0;
805 
806  while (!resp) {
807  resp = ts5_check_response(resptime, timing_error);
808  }
809 
810  return resp;
811 }
812 
813 
814 ////////////////////////////////////////////////////////////////////////////////
815 /// Wait for a response for a given time.
816 ///
817 /// \param resptime Variable that will store the response time.
818 /// \param timing_error Variable that will store the timing error
819 /// (works only for cedrusboxes and parallel port boxes).
820 /// \param maxtime Maximum time for a response.
821 ///
822 /// \return The button that was pressed
823 /// (0 if no button was pressed within the maximum time).
824 ////////////////////////////////////////////////////////////////////////////////
825 int ts5_wait_for_response_timed(double *resptime, double *timing_error,
826  double maxtime)
827 {
828  ts5_check_timer("ts5_wait_for_response_timed");
829  ts5_check_timer2("ts5_wait_for_response_timed");
830  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_response_timed(%p,%p,%f)\n",
831  resptime, timing_error, maxtime);
832 
833  if (maxtime<0) {
834  ts5_fatal("ts5_wait_for_response_timed: maxtime is negative (%f)\n",
835  maxtime);
836  }
837 
838  int resp=0, deadline=0;
839  double starttime = al_get_time();
840 
841  while (!resp && !deadline) {
842 
843  resp = ts5_check_response(resptime, timing_error);
844 
845  if (al_get_time()-starttime>=maxtime) {
846  deadline=1;
847  }
848  }
849 
850  return resp;
851 }
852 
853 
854 ////////////////////////////////////////////////////////////////////////////////
855 /// Wait for a response until a deadline.
856 ///
857 /// \param resptime Variable that will store the response time.
858 /// \param timing_error Variable that will store the timing error
859 /// (works only for cedrusboxes and parallel port boxes).
860 /// \param deadline Deadline for a response.
861 ///
862 /// \return The button that was pressed
863 /// (0 if no button was pressed within the deadline).
864 ////////////////////////////////////////////////////////////////////////////////
865 int ts5_wait_for_response_until(double *resptime, double *timing_error,
866  double deadline)
867 {
868  ts5_check_timer("ts5_wait_for_response_until");
869  ts5_check_timer2("ts5_wait_for_response_until");
870  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_response_until(%p,%p,%f)\n",
871  resptime, timing_error, deadline);
872 
873  if (deadline<al_get_time()) {
874  ts5_fatal("%s: %s (%f)\n", "ts5_wait_for_response_until",
875  "response deadline is in the past",
876  deadline-al_get_time());
877  }
878 
879  int resp=0, maxtime=0;
880 
881  while (!resp && !maxtime) {
882 
883  resp = ts5_check_response(resptime, timing_error);
884 
885  if (al_get_time()>=deadline) {
886  maxtime=1;
887  }
888  }
889 
890  return resp;
891 }
892 
893 
894 ////////////////////////////////////////////////////////////////////////////////
895 //@}
896 ////////////////////////////////////////////////////////////////////////////////
897 
898 
899 ////////////////////////////////////////////////////////////////////////////////
900 /// @name Trigger input/output
901 /// The trigger input functions require you to define trigger devices
902 /// using ts5_define_parport_trigger_input() or
903 /// ts5_define_serialport_trigger_input().
904 ///
905 /// Registration of trigger input is done asynchronously.
906 /// All triggers received on the parallel and/or serial port(s) will be
907 /// buffered continuously during the program.
908 ///
909 /// Waiting for a trigger is similar to waiting for a reponse.
910 /// Old triggers that were not processed yet can be flushed using
911 /// ts5_flush_triggers().
912 /// One can either wait for a trigger indefinitely, for a given amount of time
913 /// or until some deadline has passed.
914 ///
915 /// The value of the trigger is defined by the computer that sends the trigger.
916 ///
917 /// During the development of the program it is not necessary to connect a
918 /// computer that sends the triggers.
919 /// Trigger input can be simulated using ts5_simulate_parport_trigger_input()
920 /// or ts5_simulate_serialport_trigger_input().
921 ///
922 /// At the end of the program all triggers can be written to a logfile using
923 /// ts5_write_all_triggers().
924 ///
925 /// Trigger output is simple, call ts5_send_parport_trigger() or
926 /// ts5_send_serialport_trigger()
927 /// each time you want to send a trigger.
928 //@{
929 ////////////////////////////////////////////////////////////////////////////////
930 
931 
932 ////////////////////////////////////////////////////////////////////////////////
933 /// Flush the trigger queue.
934 ////////////////////////////////////////////////////////////////////////////////
936 {
937  ts5_check_timer("ts5_flush_triggers");
938  ts5_log(TS5_LOGLEVEL_5, "ts5_flush_triggers()\n");
939 
940  al_flush_event_queue(_ts5_data.timer.trigger_queue);
941 }
942 
943 
944 ////////////////////////////////////////////////////////////////////////////////
945 /// Check for a trigger.
946 ///
947 /// \param trigtime Variable that will store the trigger time.
948 /// \param timing_error Variable that will store the timing error.
949 ///
950 /// \return The value of the trigger
951 ///
952 /// This function checks for a trigger and returns immediately.
953 ////////////////////////////////////////////////////////////////////////////////
954 int ts5_check_trigger(double *trigtime, double *timing_error)
955 {
956  ts5_check_timer("ts5_check_trigger");
957  ts5_check_timer3("ts5_check_trigger");
958  ts5_log(TS5_LOGLEVEL_6, "ts5_check_trigger(%p,%p)\n",
959  trigtime, timing_error);
960 
961  int trigger=0;
962  ALLEGRO_EVENT event;
963 
964  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
965 
966  if (trigtime!=NULL) {
967  *trigtime = al_get_time();
968  }
969  if (timing_error!=NULL) {
970  *timing_error = 0.0;
971  }
972 
973  if (al_get_next_event(_ts5_data.timer.trigger_queue, &event)) {
974 
975  if(timer->parport_is_trigger_device) {
976 
977  int i;
978  for (i=0; i<timer->num_parports; i++) {
979 
980  if (timer->parport[i].is_trigger_input_device) {
981 
982  if (event.type==TS5_EVENT_PARPORT_TRIGGER
983  && event.user.data1 == i) {
984 
985  if (trigtime!=NULL) {
986  *trigtime = event.any.timestamp;
987  }
988 
989  if (timing_error!=NULL) {
990  *timing_error =
991  ((double)event.user.data3)/1000000.0;
992  }
993 
994  trigger = event.user.data2;
995  }
996  }
997  }
998  }
999 
1000  if(timer->serialport_is_trigger_device) {
1001 
1002  int i;
1003  for (i=0; i<timer->num_serialports; i++) {
1004 
1005  if (timer->serialport[i].is_trigger_input_device) {
1006 
1007  if (event.type==TS5_EVENT_SERIALPORT_TRIGGER
1008  && event.user.data1 == i) {
1009 
1010  if (trigtime!=NULL) {
1011  *trigtime = event.any.timestamp;
1012  }
1013 
1014  if (timing_error!=NULL) {
1015  *timing_error =
1016  ((double)event.user.data3)/1000000.0;
1017  }
1018 
1019  trigger = event.user.data2;
1020  }
1021  }
1022  }
1023  }
1024  }
1025 
1026  return trigger;
1027 }
1028 
1029 
1030 ////////////////////////////////////////////////////////////////////////////////
1031 /// Wait for a trigger.
1032 ///
1033 /// \param trigtime Variable that will store the trigger time.
1034 /// \param timing_error Variable that will store the timing error
1035 /// (works only for cedrusboxes and parallel port boxes).
1036 ///
1037 /// \return The button that was pressed.
1038 ////////////////////////////////////////////////////////////////////////////////
1039 int ts5_wait_for_trigger(double *trigtime, double *timing_error)
1040 {
1041  ts5_check_timer("ts5_wait_for_trigger");
1042  ts5_check_timer3("ts5_wait_for_trigger");
1043  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_trigger(%p,%p)\n",
1044  trigtime, timing_error);
1045 
1046  int trigger=0;
1047 
1048  while (!trigger) {
1049  trigger = ts5_check_trigger(trigtime, timing_error);
1050  }
1051 
1052  return trigger;
1053 }
1054 
1055 
1056 ////////////////////////////////////////////////////////////////////////////////
1057 /// Wait for a trigger for a given time.
1058 ///
1059 /// \param trigtime Variable that will store the trigger time.
1060 /// \param timing_error Variable that will store the timing error
1061 /// (works only for cedrusboxes and parallel port boxes).
1062 /// \param maxtime Maximum time for a trigger.
1063 ///
1064 /// \return The button that was pressed
1065 /// (0 if no button was pressed within the maximum time).
1066 ////////////////////////////////////////////////////////////////////////////////
1067 int ts5_wait_for_trigger_timed(double *trigtime, double *timing_error,
1068  double maxtime)
1069 {
1070  ts5_check_timer("ts5_wait_for_trigger_timed");
1071  ts5_check_timer3("ts5_wait_for_trigger_timed");
1072 
1073  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_trigger_timed(%p,%p,%f)\n",
1074  trigtime, timing_error, maxtime);
1075 
1076  if (maxtime<0) {
1077  ts5_fatal("ts5_wait_for_trigger_timed: maxtime is negative (%f)\n",
1078  maxtime);
1079  }
1080 
1081  int trigger=0, deadline=0;
1082  double starttime = al_get_time();
1083 
1084  while (!trigger && !deadline) {
1085 
1086  trigger = ts5_check_trigger(trigtime, timing_error);
1087 
1088  if (al_get_time()-starttime>=maxtime) {
1089  deadline=1;
1090  }
1091  }
1092 
1093  return trigger;
1094 }
1095 
1096 
1097 ////////////////////////////////////////////////////////////////////////////////
1098 /// Wait for a trigger until a deadline.
1099 ///
1100 /// \param trigtime Variable that will store the trigger time.
1101 /// \param timing_error Variable that will store the timing error
1102 /// (works only for cedrusboxes and parallel port boxes).
1103 /// \param deadline Deadline for a trigger.
1104 ///
1105 /// \return The button that was pressed
1106 /// (0 if no button was pressed within the deadline).
1107 ////////////////////////////////////////////////////////////////////////////////
1108 int ts5_wait_for_trigger_until(double *trigtime, double *timing_error,
1109  double deadline)
1110 {
1111  ts5_check_timer("ts5_wait_for_trigger_until");
1112  ts5_check_timer3("ts5_wait_for_trigger_until");
1113  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_trigger_until(%p,%p,%f)\n",
1114  trigtime, timing_error, deadline);
1115 
1116  if (deadline<al_get_time()) {
1117  ts5_fatal("%s: %s (%f)\n", "ts5_wait_for_trigger_until",
1118  "trigger deadline is in the past",
1119  deadline-al_get_time());
1120  }
1121 
1122  int trigger=0, maxtime=0;
1123 
1124  while (!trigger && !maxtime) {
1125 
1126  trigger = ts5_check_trigger(trigtime, timing_error);
1127 
1128  if (al_get_time()>=deadline) {
1129  maxtime=1;
1130  }
1131  }
1132 
1133  return trigger;
1134 }
1135 
1136 
1137 ////////////////////////////////////////////////////////////////////////////////
1138 /// Write all triggers to an output file
1139 ///
1140 /// \param filename Path to the output file
1141 ////////////////////////////////////////////////////////////////////////////////
1142 void ts5_write_all_triggers(char *filename)
1143 {
1144  ts5_check_timer("ts5_write_all_triggers");
1145  ts5_check_timer3("ts5_write_all_triggers");
1146  ts5_log(TS5_LOGLEVEL_5, "ts5_write_all_triggers(%s)\n", filename);
1147 
1148  FILE *fp;
1149  fp = fopen(filename, "a+");
1150  if (!fp) {
1151  ts5_fatal("ts5_write_all_triggers: could not open output file %s\n",
1152  filename);
1153  }
1154 
1155  ALLEGRO_EVENT event;
1156 
1157  while (al_get_next_event(_ts5_data.timer.trigger_log, &event)) {
1158 
1159  fprintf(fp, "%10.8f ", event.any.timestamp);
1160 
1161  double timing_error = ((double)event.user.data3)/1000000.0;
1162  fprintf(fp, "%10.8f ", timing_error);
1163 
1164  if (event.type==TS5_EVENT_PARPORT_TRIGGER) {
1165  fprintf(fp, "PARPORT ");
1166  }
1167  else if (event.type==TS5_EVENT_SERIALPORT_TRIGGER) {
1168  fprintf(fp, "SERIALPORT ");
1169  }
1170  else {
1171  fprintf(fp, "UNKNOWN ");
1172  }
1173 
1174  fprintf(fp, "%d ", (int)event.user.data1+1);
1175  fprintf(fp, "%d ", (int)event.user.data2);
1176  fprintf(fp, "\n");
1177  }
1178 
1179  fclose(fp);
1180 }
1181 
1182 
1183 ////////////////////////////////////////////////////////////////////////////////
1184 //@}
1185 ////////////////////////////////////////////////////////////////////////////////
1186 
1187 
1188 
1189