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 = 0;
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->voicekey_is_response_device) {
330 
331  for (i=0; i<timer->voicekey.num_buttons; i++) {
332 
333  timer->voicekey.button_press_active[i] =
334  timer->voicekey.button_press_defined[i];
335 
336  timer->voicekey.button_release_active[i] =
337  timer->voicekey.button_release_defined[i];
338  }
339 
340  timer->voicekey.num_active_buttons =
341  timer->voicekey.num_defined_buttons;
342  }
343 
344  if (timer->mouse_is_response_device) {
345 
346  for (i=0; i<timer->mouse.num_buttons; i++) {
347 
348  timer->mouse.button_press_active[i] =
349  timer->mouse.button_press_defined[i];
350 
351  timer->mouse.button_release_active[i] =
352  timer->mouse.button_release_defined[i];
353  }
354 
355  timer->mouse.num_active_buttons =
356  timer->mouse.num_defined_buttons;
357  }
358 
359  if (timer->keyboard_is_response_device) {
360 
361  for (i=0; i<timer->keyboard.num_buttons; i++) {
362 
363  timer->keyboard.button_press_active[i] =
364  timer->keyboard.button_press_defined[i];
365 
366  timer->keyboard.button_release_active[i] =
367  timer->keyboard.button_release_defined[i];
368  }
369 
370  timer->keyboard.num_active_buttons =
371  timer->keyboard.num_defined_buttons;
372  }
373 
374  if (timer->joystick_is_response_device) {
375 
376  for (i=0; i<timer->num_joysticks; i++) {
377 
378  for (j=0; j<timer->joystick[i].num_buttons; j++) {
379 
380  timer->joystick[i].button_press_active[j] =
381  timer->joystick[i].button_press_defined[j];
382 
383  timer->joystick[i].button_release_active[j] =
384  timer->joystick[i].button_release_defined[j];
385  }
386  timer->joystick[i].num_active_buttons =
387  timer->joystick[i].num_defined_buttons;
388  }
389  }
390 
391  if (timer->cedrusbox_is_response_device) {
392 
393  for (i=0; i<timer->num_cedrusboxes; i++) {
394 
395  for (j=0; j<timer->cedrusbox[i].num_buttons; j++) {
396 
397  timer->cedrusbox[i].button_press_active[j] =
398  timer->cedrusbox[i].button_press_defined[j];
399 
400  timer->cedrusbox[i].button_release_active[j] =
401  timer->cedrusbox[i].button_release_defined[j];
402  }
403  timer->cedrusbox[i].num_active_buttons =
404  timer->cedrusbox[i].num_defined_buttons;
405  }
406  }
407 
408  if (timer->parport_is_response_device) {
409 
410  for (i=0; i<timer->num_parports; i++) {
411 
412  for (j=0; j<timer->parport[i].num_buttons; j++) {
413 
414  timer->parport[i].button_press_active[j] =
415  timer->parport[i].button_press_defined[j];
416 
417  timer->parport[i].button_release_active[j] =
418  timer->parport[i].button_release_defined[j];
419  }
420  timer->parport[i].num_active_buttons =
421  timer->parport[i].num_defined_buttons;
422  }
423  }
424 
425  timer->num_active_buttons =
426  timer->num_defined_buttons;
427  }
428  else {
429  int i, j;
430  found=0;
431 
432  if (timer->voicekey_is_response_device) {
433 
434  for (i=0; i<timer->voicekey.num_buttons; i++) {
435 
436  if (button==timer->voicekey.button_press_active[i]) {
437  timer->voicekey.button_press_active[i] = 0;
438  found = 1;
439  }
440  else if (button==timer->voicekey.button_release_active[i]) {
441  timer->voicekey.button_release_active[i] = 0;
442  found = 1;
443  }
444 
445  if (found) {
446  timer->voicekey.num_active_buttons--;
447  timer->num_active_buttons--;
448  goto end;
449  }
450  }
451  }
452 
453  if (timer->mouse_is_response_device) {
454 
455  for (i=0; i<timer->mouse.num_buttons; i++) {
456 
457  if (button==timer->mouse.button_press_active[i]) {
458  timer->mouse.button_press_active[i] = 0;
459  found = 1;
460  }
461  else if (button==timer->mouse.button_release_active[i]) {
462  timer->mouse.button_release_active[i] = 0;
463  found = 1;
464  }
465 
466  if (found) {
467  timer->mouse.num_active_buttons--;
468  timer->num_active_buttons--;
469  goto end;
470  }
471  }
472  }
473 
474  if (timer->keyboard_is_response_device) {
475 
476  for (i=0; i<timer->keyboard.num_buttons; i++) {
477 
478  if (button==timer->keyboard.button_press_active[i]) {
479  timer->keyboard.button_press_active[i] = 0;
480  found = 1;
481  }
482  else if (button==timer->keyboard.button_release_active[i]) {
483  timer->keyboard.button_release_active[i] = 0;
484  found = 1;
485  }
486 
487  if (found) {
488  timer->keyboard.num_active_buttons--;
489  timer->num_active_buttons--;
490  goto end;
491  }
492  }
493  }
494 
495  if (timer->joystick_is_response_device) {
496 
497  for (i=0; i<timer->num_joysticks; i++) {
498 
499  for (j=0; j<timer->joystick[i].num_buttons; j++) {
500 
501  if (button==timer->joystick[i].button_press_active[j]) {
502  timer->joystick[i].button_press_active[j] = 0;
503  found = 1;
504  }
505  else if (button==timer->joystick[i].button_release_active[j]) {
506  timer->joystick[i].button_release_active[j] = 0;
507  found = 1;
508  }
509 
510  if (found) {
511  timer->joystick[i].num_active_buttons--;
512  timer->num_active_buttons--;
513  goto end;
514  }
515  }
516  }
517  }
518 
519  if (timer->cedrusbox_is_response_device) {
520 
521  for (i=0; i<timer->num_cedrusboxes; i++) {
522 
523  for (j=0; j<timer->cedrusbox[i].num_buttons; j++) {
524 
525  if (button==timer->cedrusbox[i].button_press_active[j]) {
526  timer->cedrusbox[i].button_press_active[j] = 0;
527  found = 1;
528  }
529  else if (button==timer->cedrusbox[i].button_release_active[j]){
530  timer->cedrusbox[i].button_release_active[j] = 0;
531  found = 1;
532  }
533 
534  if (found) {
535  timer->cedrusbox[i].num_active_buttons--;
536  timer->num_active_buttons--;
537  goto end;
538  }
539  }
540  }
541  }
542 
543  if (timer->parport_is_response_device) {
544 
545  for (i=0; i<timer->num_parports; i++) {
546 
547  for (j=0; j<timer->parport[i].num_buttons; j++) {
548 
549  if (button==timer->parport[i].button_press_active[j]) {
550  timer->parport[i].button_press_active[j] = 0;
551  found = 1;
552  }
553  else if (button==timer->parport[i].button_release_active[j]){
554  timer->parport[i].button_release_active[j] = 0;
555  found = 1;
556  }
557 
558  if (found) {
559  timer->parport[i].num_active_buttons--;
560  timer->num_active_buttons--;
561  goto end;
562  }
563  }
564  }
565  }
566  }
567 
568  end:
569 
570  if (!found) {
571  ts5_fatal("ts5_hide_response_button: response button %d not found\n", button);
572  }
573 
574  if (timer->num_active_buttons<1) {
575  ts5_fatal("%s: %s\n", "ts5_hide_response_button",
576  "there are no active response buttons left");
577  }
578 
579  return timer->num_active_buttons;
580 }
581 
582 
583 ////////////////////////////////////////////////////////////////////////////////
584 /// Completely removes the response button definition.
585 ////////////////////////////////////////////////////////////////////////////////
587 {
588  ts5_check_timer("ts5_remove_response_buttons");
589  ts5_log(TS5_LOGLEVEL_3, "ts5_remove_response_buttons()\n");
590 
591  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
592 
593  int i, j;
594 
595  // voicekey
596  if (timer->voicekey_is_response_device) {
597 
598  for (i=0; i<timer->voicekey.num_buttons; i++) {
599 
600  timer->voicekey.button_press_defined[i] = 0;
601  timer->voicekey.button_press_active[i] = 0;
602  timer->voicekey.button_release_defined[i] = 0;
603  timer->voicekey.button_release_active[i] = 0;
604  }
605 
606  timer->voicekey_is_response_device = 0;
607  }
608 
609  // mouse
610  if (timer->mouse_is_response_device) {
611 
612  for (i=0; i<timer->mouse.num_buttons; i++) {
613 
614  timer->mouse.button_press_defined[i] = 0;
615  timer->mouse.button_press_active[i] = 0;
616  timer->mouse.button_release_defined[i] = 0;
617  timer->mouse.button_release_active[i] = 0;
618  }
619 
620  timer->mouse_is_response_device = 0;
621  }
622 
623  // keyboard
624  if (timer->keyboard_is_response_device) {
625 
626  for (i=0; i<timer->keyboard.num_buttons; i++) {
627 
628  timer->keyboard.button_press_defined[i] = 0;
629  timer->keyboard.button_press_active[i] = 0;
630  timer->keyboard.button_release_defined[i] = 0;
631  timer->keyboard.button_release_active[i] = 0;
632  }
633 
634  timer->keyboard_is_response_device = 0;
635  }
636 
637  // joystick
638  if (timer->joystick_is_response_device) {
639 
640  for (i=0; i<timer->num_joysticks; i++) {
641 
642  for (j=0; j<timer->joystick[i].num_buttons; j++) {
643 
644  timer->joystick[i].button_press_defined[j] = 0;
645  timer->joystick[i].button_press_active[j] = 0;
646  timer->joystick[i].button_release_defined[j] = 0;
647  timer->joystick[i].button_release_active[j] = 0;
648  }
649  }
650 
651  timer->joystick_is_response_device = 0;
652  }
653 
654  // joystick
655  if (timer->joystick_is_response_device) {
656 
657  for (i=0; i<timer->num_joysticks; i++) {
658 
659  for (j=0; j<timer->joystick[i].num_buttons; j++) {
660 
661  timer->joystick[i].button_press_defined[j] = 0;
662  timer->joystick[i].button_press_active[j] = 0;
663  timer->joystick[i].button_release_defined[j] = 0;
664  timer->joystick[i].button_release_active[j] = 0;
665  }
666  }
667 
668  timer->joystick_is_response_device = 0;
669  }
670 
671  // cedrusbox
672  if (timer->cedrusbox_is_response_device) {
673 
674  for (i=0; i<timer->num_cedrusboxes; i++) {
675 
676  for (j=0; j<timer->cedrusbox[i].num_buttons; j++) {
677 
678  timer->cedrusbox[i].button_press_defined[j] = 0;
679  timer->cedrusbox[i].button_press_active[j] = 0;
680  timer->cedrusbox[i].button_release_defined[j] = 0;
681  timer->cedrusbox[i].button_release_active[j] = 0;
682  }
683  }
684  timer->cedrusbox_is_response_device = 0;
685  }
686 
687  timer->num_defined_buttons=0;
688  timer->num_active_buttons=0;
689 }
690 
691 
692 ////////////////////////////////////////////////////////////////////////////////
693 /// Flush the response queue.
694 ////////////////////////////////////////////////////////////////////////////////
696 {
697  ts5_check_timer("ts5_flush_responses");
698  ts5_log(TS5_LOGLEVEL_5, "ts5_flush_responses()\n");
699 
700  al_flush_event_queue(_ts5_data.timer.response_queue);
701 }
702 
703 
704 ////////////////////////////////////////////////////////////////////////////////
705 /// Check for a reponse.
706 ///
707 /// \param resptime Variable that will store the response time.
708 /// \param timing_error Variable that will store the timing error
709 /// (works only for cedrusboxes and parallel port boxes).
710 ///
711 /// \return The button that was pressed
712 /// (0 if no button was pressed within the deadline).
713 ///
714 /// This function checks for a response and returns immediately.
715 ////////////////////////////////////////////////////////////////////////////////
716 int ts5_check_response(double *resptime, double *timing_error)
717 {
718  ts5_check_timer("ts5_check_response");
719  ts5_check_timer2("ts5_check_response");
720  ts5_log(TS5_LOGLEVEL_6, "ts5_check_response(%p,%p)\n",
721  resptime, timing_error);
722 
723  int resp=0;
724  ALLEGRO_EVENT event;
725 
726  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
727 
728  if (!al_get_next_event(_ts5_data.timer.response_queue, &event)) {
729 
730  if (resptime!=NULL) {
731  *resptime = al_get_time();
732  }
733  if (timing_error!=NULL) {
734  *timing_error = 0.0;
735  }
736  }
737  else {
738 
739  if (resptime!=NULL) {
740  *resptime = event.any.timestamp;
741  }
742 
743  if (timing_error!=NULL) {
744  *timing_error = 0.0;
745  }
746 
747  int i;
748 
749  // voicekey (driver response codes are counted from 1)
750  if (timer->voicekey_is_response_device) {
751 
752  if (timer->voicekey.num_active_buttons) {
753 
754  if (event.type==TS5_EVENT_VOICEKEY_BUTTON_DOWN) {
755  resp = timer->voicekey
756  .button_press_active[event.user.data2-1];
757  }
758 
759  if (event.type==TS5_EVENT_VOICEKEY_BUTTON_UP) {
760  resp = timer->voicekey
761  .button_release_active[event.user.data2-1];
762  }
763 
764  if (resp && resptime!=NULL) {
765  *resptime = ((double)event.user.data3)/1000000.0;
766  }
767 
768  }
769  }
770 
771  // mouse (driver response codes are counted from 1)
772  if (timer->mouse_is_response_device) {
773 
774  if (timer->mouse.num_active_buttons) {
775 
776  if (event.type==ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
777 
778  resp = timer->mouse
779  .button_press_active[event.mouse.button-1];
780  }
781 
782  if (event.type==ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
783  resp = timer->mouse
784  .button_release_active[event.mouse.button-1];
785  }
786  }
787  }
788 
789  // keyboard (driver response codes are counted from 1)
790  if (timer->keyboard_is_response_device) {
791 
792  if (timer->keyboard.num_active_buttons) {
793 
794  if (event.type==ALLEGRO_EVENT_KEY_DOWN) {
795  resp = timer->keyboard
796  .button_press_active[event.keyboard.keycode-1];
797  }
798 
799  if (event.type==ALLEGRO_EVENT_KEY_UP) {
800  resp = timer->keyboard
801  .button_release_active[event.keyboard.keycode-1];
802  }
803  }
804  }
805 
806  // joystick (driver response codes are counted from 0)
807  if (timer->joystick_is_response_device) {
808 
809  for (i=0; i<timer->num_joysticks; i++) {
810 
811  if (timer->joystick[i].num_active_buttons) {
812 
813  if (event.type==ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN) {
814 
815  ALLEGRO_JOYSTICK *stick = al_get_joystick(i);
816 
817  if (event.joystick.id == stick) {
818  resp = timer->joystick[i]
819  .button_press_active[event.joystick.button];
820  }
821  }
822 
823  if (event.type==ALLEGRO_EVENT_JOYSTICK_BUTTON_UP) {
824 
825  ALLEGRO_JOYSTICK *stick = al_get_joystick(i);
826 
827  if (event.joystick.id == stick) {
828  resp = timer->joystick[i]
829  .button_release_active
830  [event.joystick.button];
831  }
832  }
833  }
834  }
835  }
836 
837  // cedrusbox (driver response codes are counted from 0)
838  if (timer->cedrusbox_is_response_device) {
839 
840  for (i=0; i<timer->num_cedrusboxes; i++) {
841 
842  if (timer->cedrusbox[i].num_active_buttons) {
843 
844  if (event.type==TS5_EVENT_CEDRUSBOX_BUTTON_DOWN) {
845 
846  if (event.user.data1 == i) {
847  resp = timer->cedrusbox[i]
848  .button_press_active[event.user.data2];
849  }
850  }
851 
852  if (event.type==TS5_EVENT_CEDRUSBOX_BUTTON_UP) {
853 
854  if (event.user.data1 == i) {
855  resp = timer->cedrusbox[i]
856  .button_release_active[event.user.data2];
857  }
858  }
859 
860  if (resp && timing_error!=NULL) {
861  *timing_error = ((double)event.user.data3)/1000000.0;
862  }
863  }
864  }
865  }
866 
867  // parallel port (driver response codes are counted from 1)
868  if (timer->parport_is_response_device) {
869 
870  for (i=0; i<timer->num_parports; i++) {
871 
872  if (timer->parport[i].num_active_buttons) {
873 
874  if (event.type==TS5_EVENT_PARPORT_BUTTON_DOWN) {
875 
876  if (event.user.data1 == i) {
877  resp = timer->parport[i]
878  .button_press_active[event.user.data2-1];
879  }
880  }
881 
882  if (event.type==TS5_EVENT_PARPORT_BUTTON_UP) {
883 
884  if (event.user.data1 == i) {
885  resp = timer->parport[i]
886  .button_release_active[event.user.data2-1];
887  }
888  }
889 
890  if (resp && timing_error!=NULL) {
891  *timing_error = ((double)event.user.data3)/1000000.0;
892  }
893  }
894  }
895  }
896  }
897 
898  return resp;
899 }
900 
901 
902 ////////////////////////////////////////////////////////////////////////////////
903 /// Wait for a response.
904 ///
905 /// \param resptime Variable that will store the response time.
906 /// \param timing_error Variable that will store the timing error
907 /// (works only for cedrusboxes and parallel port boxes).
908 ///
909 /// \return The button that was pressed.
910 ////////////////////////////////////////////////////////////////////////////////
911 int ts5_wait_for_response(double *resptime, double *timing_error)
912 {
913  ts5_check_timer("ts5_wait_for_response");
914  ts5_check_timer2("ts5_wait_for_response");
915  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_response(%p,%p)\n",
916  resptime, timing_error);
917 
918  int resp=0;
919 
920  while (!resp) {
921  resp = ts5_check_response(resptime, timing_error);
922  }
923 
924  return resp;
925 }
926 
927 
928 ////////////////////////////////////////////////////////////////////////////////
929 /// Wait for a response for a given time.
930 ///
931 /// \param resptime Variable that will store the response time.
932 /// \param timing_error Variable that will store the timing error
933 /// (works only for cedrusboxes and parallel port boxes).
934 /// \param maxtime Maximum time for a response.
935 ///
936 /// \return The button that was pressed
937 /// (0 if no button was pressed within the maximum time).
938 ////////////////////////////////////////////////////////////////////////////////
939 int ts5_wait_for_response_timed(double *resptime, double *timing_error,
940  double maxtime)
941 {
942  ts5_check_timer("ts5_wait_for_response_timed");
943  ts5_check_timer2("ts5_wait_for_response_timed");
944  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_response_timed(%p,%p,%f)\n",
945  resptime, timing_error, maxtime);
946 
947  if (maxtime<0) {
948  ts5_fatal("ts5_wait_for_response_timed: maxtime is negative (%f)\n",
949  maxtime);
950  }
951 
952  int resp=0, deadline=0;
953  double starttime = al_get_time();
954 
955  while (!resp && !deadline) {
956 
957  resp = ts5_check_response(resptime, timing_error);
958 
959  if (al_get_time()-starttime>=maxtime) {
960  deadline=1;
961  }
962  }
963 
964  return resp;
965 }
966 
967 
968 ////////////////////////////////////////////////////////////////////////////////
969 /// Wait for a response until a deadline.
970 ///
971 /// \param resptime Variable that will store the response time.
972 /// \param timing_error Variable that will store the timing error
973 /// (works only for cedrusboxes and parallel port boxes).
974 /// \param deadline Deadline for a response.
975 ///
976 /// \return The button that was pressed
977 /// (0 if no button was pressed within the deadline).
978 ////////////////////////////////////////////////////////////////////////////////
979 int ts5_wait_for_response_until(double *resptime, double *timing_error,
980  double deadline)
981 {
982  ts5_check_timer("ts5_wait_for_response_until");
983  ts5_check_timer2("ts5_wait_for_response_until");
984  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_response_until(%p,%p,%f)\n",
985  resptime, timing_error, deadline);
986 
987  if (deadline<al_get_time()) {
988  ts5_fatal("%s: %s (%f)\n", "ts5_wait_for_response_until",
989  "response deadline is in the past",
990  deadline-al_get_time());
991  }
992 
993  int resp=0, maxtime=0;
994 
995  while (!resp && !maxtime) {
996 
997  resp = ts5_check_response(resptime, timing_error);
998 
999  if (al_get_time()>=deadline) {
1000  maxtime=1;
1001  }
1002  }
1003 
1004  return resp;
1005 }
1006 
1007 
1008 ////////////////////////////////////////////////////////////////////////////////
1009 //@}
1010 ////////////////////////////////////////////////////////////////////////////////
1011 
1012 
1013 ////////////////////////////////////////////////////////////////////////////////
1014 /// @name Trigger input/output
1015 /// The trigger input functions require you to define trigger devices
1016 /// using ts5_define_parport_trigger_input() or
1017 /// ts5_define_serialport_trigger_input().
1018 ///
1019 /// Registration of trigger input is done asynchronously.
1020 /// All triggers received on the parallel and/or serial port(s) will be
1021 /// buffered continuously during the program.
1022 ///
1023 /// Waiting for a trigger is similar to waiting for a reponse.
1024 /// Old triggers that were not processed yet can be flushed using
1025 /// ts5_flush_triggers().
1026 /// One can either wait for a trigger indefinitely, for a given amount of time
1027 /// or until some deadline has passed.
1028 ///
1029 /// The value of the trigger is defined by the computer that sends the trigger.
1030 ///
1031 /// During the development of the program it is not necessary to connect a
1032 /// computer that sends the triggers.
1033 /// Trigger input can be simulated using ts5_simulate_parport_trigger_input()
1034 /// or ts5_simulate_serialport_trigger_input().
1035 ///
1036 /// At the end of the program all triggers can be written to a logfile using
1037 /// ts5_write_all_triggers().
1038 ///
1039 /// Trigger output is simple, call ts5_send_parport_trigger() or
1040 /// ts5_send_serialport_trigger()
1041 /// each time you want to send a trigger.
1042 //@{
1043 ////////////////////////////////////////////////////////////////////////////////
1044 
1045 
1046 ////////////////////////////////////////////////////////////////////////////////
1047 /// Flush the trigger queue.
1048 ////////////////////////////////////////////////////////////////////////////////
1050 {
1051  ts5_check_timer("ts5_flush_triggers");
1052  ts5_log(TS5_LOGLEVEL_5, "ts5_flush_triggers()\n");
1053 
1054  al_flush_event_queue(_ts5_data.timer.trigger_queue);
1055 }
1056 
1057 
1058 ////////////////////////////////////////////////////////////////////////////////
1059 /// Check for a trigger.
1060 ///
1061 /// \param trigtime Variable that will store the trigger time.
1062 /// \param timing_error Variable that will store the timing error.
1063 ///
1064 /// \return The value of the trigger
1065 ///
1066 /// This function checks for a trigger and returns immediately.
1067 ////////////////////////////////////////////////////////////////////////////////
1068 int ts5_check_trigger(double *trigtime, double *timing_error)
1069 {
1070  ts5_check_timer("ts5_check_trigger");
1071  ts5_check_timer3("ts5_check_trigger");
1072  ts5_log(TS5_LOGLEVEL_6, "ts5_check_trigger(%p,%p)\n",
1073  trigtime, timing_error);
1074 
1075  int trigger=0;
1076  ALLEGRO_EVENT event;
1077 
1078  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
1079 
1080  if (trigtime!=NULL) {
1081  *trigtime = al_get_time();
1082  }
1083  if (timing_error!=NULL) {
1084  *timing_error = 0.0;
1085  }
1086 
1087  if (al_get_next_event(_ts5_data.timer.trigger_queue, &event)) {
1088 
1089  if(timer->cedrusbox_is_trigger_device) {
1090 
1091  int i;
1092  for (i=0; i<timer->num_cedrusboxes; i++) {
1093 
1094  if (timer->cedrusbox[i].is_trigger_input_device) {
1095 
1096  if (event.type==TS5_EVENT_CEDRUSBOX_TRIGGER
1097  && event.user.data1 == i) {
1098 
1099  if (trigtime!=NULL) {
1100  *trigtime = event.any.timestamp;
1101  }
1102 
1103  if (timing_error!=NULL) {
1104  *timing_error =
1105  ((double)event.user.data3)/1000000.0;
1106  }
1107 
1108  trigger = event.user.data2;
1109  }
1110  }
1111  }
1112  }
1113 
1114  if(timer->parport_is_trigger_device) {
1115 
1116  int i;
1117  for (i=0; i<timer->num_parports; i++) {
1118 
1119  if (timer->parport[i].is_trigger_input_device) {
1120 
1121  if (event.type==TS5_EVENT_PARPORT_TRIGGER
1122  && event.user.data1 == i) {
1123 
1124  if (trigtime!=NULL) {
1125  *trigtime = event.any.timestamp;
1126  }
1127 
1128  if (timing_error!=NULL) {
1129  *timing_error =
1130  ((double)event.user.data3)/1000000.0;
1131  }
1132 
1133  trigger = event.user.data2;
1134  }
1135  }
1136  }
1137  }
1138 
1139  if(timer->serialport_is_trigger_device) {
1140 
1141  int i;
1142  for (i=0; i<timer->num_serialports; i++) {
1143 
1144  if (timer->serialport[i].is_trigger_input_device) {
1145 
1146  if (event.type==TS5_EVENT_SERIALPORT_TRIGGER
1147  && event.user.data1 == i) {
1148 
1149  if (trigtime!=NULL) {
1150  *trigtime = event.any.timestamp;
1151  }
1152 
1153  if (timing_error!=NULL) {
1154  *timing_error =
1155  ((double)event.user.data3)/1000000.0;
1156  }
1157 
1158  trigger = event.user.data2;
1159  }
1160  }
1161  }
1162  }
1163  }
1164 
1165  return trigger;
1166 }
1167 
1168 
1169 ////////////////////////////////////////////////////////////////////////////////
1170 /// Wait for a trigger.
1171 ///
1172 /// \param trigtime Variable that will store the trigger time.
1173 /// \param timing_error Variable that will store the timing error
1174 /// (works only for cedrusboxes and parallel port boxes).
1175 ///
1176 /// \return The button that was pressed.
1177 ////////////////////////////////////////////////////////////////////////////////
1178 int ts5_wait_for_trigger(double *trigtime, double *timing_error)
1179 {
1180  ts5_check_timer("ts5_wait_for_trigger");
1181  ts5_check_timer3("ts5_wait_for_trigger");
1182  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_trigger(%p,%p)\n",
1183  trigtime, timing_error);
1184 
1185  int trigger=0;
1186 
1187  while (!trigger) {
1188  trigger = ts5_check_trigger(trigtime, timing_error);
1189  }
1190 
1191  return trigger;
1192 }
1193 
1194 
1195 ////////////////////////////////////////////////////////////////////////////////
1196 /// Wait for a trigger for a given time.
1197 ///
1198 /// \param trigtime Variable that will store the trigger time.
1199 /// \param timing_error Variable that will store the timing error
1200 /// (works only for cedrusboxes and parallel port boxes).
1201 /// \param maxtime Maximum time for a trigger.
1202 ///
1203 /// \return The button that was pressed
1204 /// (0 if no button was pressed within the maximum time).
1205 ////////////////////////////////////////////////////////////////////////////////
1206 int ts5_wait_for_trigger_timed(double *trigtime, double *timing_error,
1207  double maxtime)
1208 {
1209  ts5_check_timer("ts5_wait_for_trigger_timed");
1210  ts5_check_timer3("ts5_wait_for_trigger_timed");
1211 
1212  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_trigger_timed(%p,%p,%f)\n",
1213  trigtime, timing_error, maxtime);
1214 
1215  if (maxtime<0) {
1216  ts5_fatal("ts5_wait_for_trigger_timed: maxtime is negative (%f)\n",
1217  maxtime);
1218  }
1219 
1220  int trigger=0, deadline=0;
1221  double starttime = al_get_time();
1222 
1223  while (!trigger && !deadline) {
1224 
1225  trigger = ts5_check_trigger(trigtime, timing_error);
1226 
1227  if (al_get_time()-starttime>=maxtime) {
1228  deadline=1;
1229  }
1230  }
1231 
1232  return trigger;
1233 }
1234 
1235 
1236 ////////////////////////////////////////////////////////////////////////////////
1237 /// Wait for a trigger until a deadline.
1238 ///
1239 /// \param trigtime Variable that will store the trigger time.
1240 /// \param timing_error Variable that will store the timing error
1241 /// (works only for cedrusboxes and parallel port boxes).
1242 /// \param deadline Deadline for a trigger.
1243 ///
1244 /// \return The button that was pressed
1245 /// (0 if no button was pressed within the deadline).
1246 ////////////////////////////////////////////////////////////////////////////////
1247 int ts5_wait_for_trigger_until(double *trigtime, double *timing_error,
1248  double deadline)
1249 {
1250  ts5_check_timer("ts5_wait_for_trigger_until");
1251  ts5_check_timer3("ts5_wait_for_trigger_until");
1252  ts5_log(TS5_LOGLEVEL_5, "ts5_wait_for_trigger_until(%p,%p,%f)\n",
1253  trigtime, timing_error, deadline);
1254 
1255  if (deadline<al_get_time()) {
1256  ts5_fatal("%s: %s (%f)\n", "ts5_wait_for_trigger_until",
1257  "trigger deadline is in the past",
1258  deadline-al_get_time());
1259  }
1260 
1261  int trigger=0, maxtime=0;
1262 
1263  while (!trigger && !maxtime) {
1264 
1265  trigger = ts5_check_trigger(trigtime, timing_error);
1266 
1267  if (al_get_time()>=deadline) {
1268  maxtime=1;
1269  }
1270  }
1271 
1272  return trigger;
1273 }
1274 
1275 
1276 ////////////////////////////////////////////////////////////////////////////////
1277 /// Write all triggers to an output file
1278 ///
1279 /// \param filename Path to the output file
1280 ////////////////////////////////////////////////////////////////////////////////
1281 void ts5_write_all_triggers(char *filename)
1282 {
1283  ts5_check_timer("ts5_write_all_triggers");
1284  ts5_check_timer3("ts5_write_all_triggers");
1285  ts5_log(TS5_LOGLEVEL_5, "ts5_write_all_triggers(%s)\n", filename);
1286 
1287  FILE *fp;
1288  fp = fopen(filename, "a+");
1289  if (!fp) {
1290  ts5_fatal("ts5_write_all_triggers: could not open output file %s\n",
1291  filename);
1292  }
1293 
1294  ALLEGRO_EVENT event;
1295 
1296  while (al_get_next_event(_ts5_data.timer.trigger_log, &event)) {
1297 
1298  fprintf(fp, "%10.8f ", event.any.timestamp);
1299 
1300  double timing_error = ((double)event.user.data3)/1000000.0;
1301  fprintf(fp, "%10.8f ", timing_error);
1302 
1303  if (event.type==TS5_EVENT_PARPORT_TRIGGER) {
1304  fprintf(fp, "PARPORT ");
1305  }
1306  else if (event.type==TS5_EVENT_SERIALPORT_TRIGGER) {
1307  fprintf(fp, "SERIALPORT ");
1308  }
1309  else if (event.type==TS5_EVENT_CEDRUSBOX_TRIGGER) {
1310  fprintf(fp, "CEDRUSBOX ");
1311  }
1312  else {
1313  fprintf(fp, "UNKNOWN ");
1314  }
1315 
1316  fprintf(fp, "%d ", (int)event.user.data1+1);
1317  fprintf(fp, "%d ", (int)event.user.data2);
1318  fprintf(fp, "\n");
1319  }
1320 
1321  fclose(fp);
1322 }
1323 
1324 
1325 ////////////////////////////////////////////////////////////////////////////////
1326 //@}
1327 ////////////////////////////////////////////////////////////////////////////////
1328 
1329 
1330 
1331 
void ts5_wait_until(double deadline)
Wait until a deadline.
Definition: timer.c:243
int ts5_wait_for_response(double *resptime, double *timing_error)
Wait for a response.
Definition: timer.c:911
void ts5_flush_responses()
Flush the response queue.
Definition: timer.c:695
void ts5_flush_triggers()
Flush the trigger queue.
Definition: timer.c:1049
void ts5_wait(double waittime)
Wait for a number of seconds.
Definition: timer.c:220
int ts5_get_priority()
Get the program&#39;s priority.
Definition: timer.c:178
int ts5_wait_for_trigger_until(double *trigtime, double *timing_error, double deadline)
Wait for a trigger until a deadline.
Definition: timer.c:1247
void ts5_check_timer3(char *calling_function)
Do some checks at the start of each timer function.
void ts5_realtime_clock_nap()
Give up processor time to allow other processes to run.
void ts5_remove_response_buttons()
Completely removes the response button definition.
Definition: timer.c:586
void ts5_check_timer4(char *calling_function)
Do some checks at the start of each timer function.
void ts5_log(const unsigned int level, const char *format,...)
Send info to a logging window.
Definition: system.c:45
int ts5_hide_response_button(int button)
Temporarily deactivates a response button.
Definition: timer.c:307
void ts5_check_timer2(char *calling_function)
Do some checks at the start of each timer function.
int ts5_check_trigger(double *trigtime, double *timing_error)
Check for a trigger.
Definition: timer.c:1068
int ts5_wait_for_trigger(double *trigtime, double *timing_error)
Wait for a trigger.
Definition: timer.c:1178
int ts5_wait_for_response_until(double *resptime, double *timing_error, double deadline)
Wait for a response until a deadline.
Definition: timer.c:979
int ts5_check_response(double *resptime, double *timing_error)
Check for a reponse.
Definition: timer.c:716
void ts5_fatal(const char *format,...)
Exit safely with an error message.
Definition: system.c:529
int ts5_wait_for_response_timed(double *resptime, double *timing_error, double maxtime)
Wait for a response for a given time.
Definition: timer.c:939
int ts5_wait_for_trigger_timed(double *trigtime, double *timing_error, double maxtime)
Wait for a trigger for a given time.
Definition: timer.c:1206
void ts5_write_all_triggers(char *filename)
Write all triggers to an output file.
Definition: timer.c:1281
int ts5_set_priority(int priority)
Set the program&#39;s priority.
Definition: timer.c:62
double ts5_get_time()
Get the number of seconds since the program started.
Definition: timer.c:208
void ts5_check_timer(char *calling_function)
Do some checks at the start of each timer function.