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