Tscope5
system.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // __ ______
4 // / /_______________ ____ ___ / ____/
5 // / __/ ___/ ___/ __ \/ __ \/ _ \ /___ )
6 // / /_(__ ) /__/ /_/ / /_/ / __/ ____/ /
7 // \__/____/\___/\____/ .___/\___/ /_____/
8 // /_/
9 //
10 /// \file system.c
11 /// Definitions of system functions
12 /// \example system01.c
13 /// \example system02.c
14 ////////////////////////////////////////////////////////////////////////////////
15 
16 #include "../include/tscope5/system.h"
17 #include "../include/tscope5/display.h"
18 #include "../include/tscope5/system_internal.h"
19 
20 
21 ////////////////////////////////////////////////////////////////////////////////
22 /// @name Logging functions
23 /// Tscope5 automatically sends information about its status
24 /// to a logging window and a file called tscope5.log.
25 ///
26 /// With the functions below you control the amount of information
27 /// that is logged.
28 /// It is also possible to send your own log messages.
29 //@{
30 ////////////////////////////////////////////////////////////////////////////////
31 
32 
33 ////////////////////////////////////////////////////////////////////////////////
34 /// Send info to a logging window.
35 ///
36 /// \param level The importance of this message
37 /// (TS5_LOGLEVEL_0 - TS5_LOGLEVEL_6). Smaller values are more important.
38 /// \param format Printf-style format string that contains the log message.
39 ///
40 /// The log message is printed in a separate text log window.
41 ///
42 /// Messages with a level above the level specified
43 /// with ts5_set_log_level are omitted.
44 ////////////////////////////////////////////////////////////////////////////////
45 void ts5_log(const unsigned int level, const char *format, ...)
46 {
48  ts5_install_tscope5("ts5_log");
49  }
50 
51  if (level <= _ts5_status.loglevel) {
52 
54  _ts5_data.textlog = fopen("tscope5.log", "w+");
55  if (!_ts5_data.textlog) {
56  ts5_fatal("ts5_log: could not open log file\n");
57  }
59  }
60 
61  char outbuf[TS5_MAX_CHAR];
62  va_list args;
63  va_start(args, format);
64  vsnprintf(outbuf, TS5_MAX_CHAR*sizeof(char), format, args);
65  va_end(args);
66 
67  double logtime = al_get_time();
68  fprintf(stdout, "%8.3f: %s", logtime, outbuf);
69  //fflush(stdout);
70  fprintf(_ts5_data.textlog, "%8.3f: %s", logtime, outbuf);
71  }
72 }
73 
74 
75 ////////////////////////////////////////////////////////////////////////////////
76 /// Set log level
77 ///
78 /// \param loglevel How much stuff is logged.
79 ///
80 /// \return The previous log level.
81 ///
82 /// This parameter function controls what information
83 /// is printed to the log window.
84 ///
85 /// There are six possible settings:
86 /// - TS5_LOGLEVEL_0: no debugging info.
87 /// - TS5_LOGLEVEL_1: report when Tscope5 subsystems are loaded.
88 /// - TS5_LOGLEVEL_2: report when memory is allocated/freed.
89 /// - TS5_LOGLEVEL_3: report when response buttons are defined.
90 /// - TS5_LOGLEVEL_4: report when parameter are set or queried.
91 /// - TS5_LOGLEVEL_5: report each function call.
92 /// - TS5_LOGLEVEL_6: report internal check and coordinate functions.
93 ///
94 /// If other values are passed to this function the program is aborted.
95 ///
96 /// The default loglevel is TS5_LOGLEVEL_3.
97 ////////////////////////////////////////////////////////////////////////////////
98 int ts5_set_log_level(const unsigned int loglevel)
99 {
101  ts5_install_tscope5("ts5_set_log_level");
102  }
103 
104  ts5_log(TS5_LOGLEVEL_4, "ts5_set_log_level(%d)\n", loglevel);
105 
106  int retval;
107  retval = _ts5_status.loglevel;
108 
109  if (loglevel <= TS5_LOGLEVEL_6) {
110  _ts5_status.loglevel = loglevel;
111 
112  ts5_log(TS5_LOGLEVEL_4, "%s: %s %d to %d\n", "ts5_set_log_level",
113  "changed loglevel from", retval, loglevel);
114  }
115  else {
116  ts5_fatal("ts5_log: requested loglevel not supported.");
117  }
118 
119  return retval;
120 }
121 
122 
123 ////////////////////////////////////////////////////////////////////////////////
124 /// Get log level
125 ///
126 /// \return The log level.
127 ////////////////////////////////////////////////////////////////////////////////
129 {
131  ts5_install_tscope5("ts5_get_log_level");
132  }
133 
134  ts5_log(TS5_LOGLEVEL_4, "ts5_get_log_level\n");
135 
136  return _ts5_status.loglevel;
137 }
138 
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// Write the status of all Tscope5 subsystem to the log window.
142 ///
143 /// Information is printed about:
144 /// - The display adapter(s) of the computer and the available fullscreen modes.
145 /// - The displays opened by Tscope5.
146 /// - The graphics parameters.
147 ////////////////////////////////////////////////////////////////////////////////
149 {
150  char line[]="==================================================\n";
151  int i;
152 
153  // display adapters + supported fullscreen modes
154 
155  ts5_log(TS5_LOGLEVEL_0, "\n");
156  ts5_log(TS5_LOGLEVEL_0, line);
157  ts5_log(TS5_LOGLEVEL_0, "tscope5 status:\n");
158  ts5_log(TS5_LOGLEVEL_0, "\n");
159 
160  ts5_log(TS5_LOGLEVEL_0, "Loglevel: %d\n", _ts5_status.loglevel);
161  ts5_log(TS5_LOGLEVEL_0, "Number of display adapters: %d\n",
162  _ts5_status.num_display_adapters);
163 
164  for (i = 0; i < _ts5_status.num_display_adapters; i++) {
165 
166  ts5_log(TS5_LOGLEVEL_0, "%s %d: w: %d (%d:%d), h: %d (%d:%d)\n",
167  "Display adapter", i+1,
168  _ts5_status.display_adapter[i].w,
169  _ts5_status.display_adapter[i].x1,
170  _ts5_status.display_adapter[i].x2,
171  _ts5_status.display_adapter[i].h,
172  _ts5_status.display_adapter[i].y1,
173  _ts5_status.display_adapter[i].y2);
174  }
175 
176  ts5_log(TS5_LOGLEVEL_0, "\n");
177 
178  int oldadapter = ts5_nextdisplay.adapter;
179  ALLEGRO_DISPLAY_MODE *mode;
180  mode = (ALLEGRO_DISPLAY_MODE *)al_malloc(sizeof(ALLEGRO_DISPLAY_MODE));
181 
182  for (i = 0; i < _ts5_status.num_display_adapters; i++) {
183 
184  al_set_new_display_adapter(i);
185  int oldrate = al_get_new_display_refresh_rate();
186  int oldflags = al_get_new_display_flags();
187  al_set_new_display_refresh_rate(0);
188  al_set_new_display_flags(0);
189 
190  int nmodes = al_get_num_display_modes();
191 
192  int j;
193  for (j=0; j<nmodes; j++) {
194 
195  mode = al_get_display_mode(j, mode);
196  ts5_log(TS5_LOGLEVEL_0,
197  "adapter %d mode %2d: w=%4d, h=%4d, format=%d, rate=%d\n",
198  i+1, j+1, mode->width, mode->height,
199  mode->format, mode->refresh_rate);
200  }
201 
202  al_set_new_display_refresh_rate(oldrate);
203  al_set_new_display_flags(oldflags);
204  }
205 
206  ts5_log(TS5_LOGLEVEL_0, "\n");
207  al_set_new_display_adapter(oldadapter);
208  al_free(mode);
209 
210  // display settings + settings for next display
211  ts5_log(TS5_LOGLEVEL_0, line);
212  ts5_log(TS5_LOGLEVEL_0, "Parameters for next display:\n");
213 
214  ts5_log(TS5_LOGLEVEL_0, "\tAdapter %d\n",
215  ts5_nextdisplay.adapter+1);
216 
217  ts5_log(TS5_LOGLEVEL_0, "\tw=%d, h=%d\n",
219 
220  ts5_log(TS5_LOGLEVEL_0, "\tx=%d, y=%d\n",
222 
223  ts5_log(TS5_LOGLEVEL_0, "\tRefreshrate=%d\n",
224  ts5_nextdisplay.refreshrate);
225 
226  ts5_log(TS5_LOGLEVEL_0, "\tDisplay mode=%d\n",
227  ts5_nextdisplay.display_mode);
228 
229  ts5_log(TS5_LOGLEVEL_0, "\tVsync mode=%d\n",
230  ts5_nextdisplay.vsync_mode);
231 
232  ts5_log(TS5_LOGLEVEL_0, "\n");
233 
234  ts5_log(TS5_LOGLEVEL_0, "Number of displays: %d\n",
235  _ts5_status.num_displays);
236 
237  ts5_log(TS5_LOGLEVEL_0, "Active display: %d\n",
238  _ts5_status.active_display);
239 
240  for (i = 0; i < _ts5_status.num_displays; i++) {
241 
242  ts5_log(TS5_LOGLEVEL_0,
243  "%s %d: %s %d, w=%d, h=%d, x=%d, y=%d, %s=%d, %s=%d, %s=%d\n",
244  "Display", i+1,
245  "Adapter", _ts5_status.display[i].adapter+1,
246  _ts5_status.display[i].w, _ts5_status.display[i].h,
247  _ts5_status.display[i].x, _ts5_status.display[i].y,
248  "Refreshrate", _ts5_status.display[i].refreshrate,
249  "Dispay mode", _ts5_status.display[i].display_mode,
250  "Vsync mode", _ts5_status.display[i].vsync_mode);
251  }
252 
253  ts5_log(TS5_LOGLEVEL_0, "\n");
254 
255  // graphics parameters
256  float r, g, b, a;
257  ts5_log(TS5_LOGLEVEL_0, line);
258 
259  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
260  "Coordinate system", _ts5_status.graphics.coordinate_system);
261 
262  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
263  "Coordinate scale", _ts5_status.graphics.coordinate_scale);
264 
265  ts5_log(TS5_LOGLEVEL_0, "%s: %d x %d\n",
266  "Target bitmap size",
267  _ts5_status.graphics.target_width,
268  _ts5_status.graphics.target_height);
269 
270  al_unmap_rgba_f(_ts5_status.graphics.foreground_color, &r, &g, &b, &a);
271  ts5_log(TS5_LOGLEVEL_0, "%s: r: %f g: %f b: %f alpha: %f\n",
272  "Foreground color", r, g, b, a);
273 
274  al_unmap_rgba_f(_ts5_status.graphics.background_color, &r, &g, &b, &a);
275  ts5_log(TS5_LOGLEVEL_0, "%s: r: %f g: %f b: %f alpha: %f\n",
276  "Background color", r, g, b, a);
277 
278  ts5_log(TS5_LOGLEVEL_0, "%s: %f\n",
279  "Line drawing thickness", _ts5_status.graphics.drawing_thickness);
280 
281  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
282  "Fill mode", _ts5_status.graphics.fill_mode);
283 
284  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
285  "Font type", _ts5_status.graphics.font_type);
286 
287  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
288  "Font style", _ts5_status.graphics.font_style);
289 
290  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
291  "Font size", _ts5_status.graphics.font_size);
292 
293  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
294  "Font number", _ts5_status.graphics.font_index);
295 
296  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
297  "Text alignment", _ts5_status.graphics.text_alignment);
298 
299  ts5_log(TS5_LOGLEVEL_0, "\n");
300 
301  // timer
302  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
303 
304  ts5_log(TS5_LOGLEVEL_0, line);
305 
306  ts5_log(TS5_LOGLEVEL_0, "Program priority: %+d\n",
307  timer->priority);
308 
309  ts5_log(TS5_LOGLEVEL_0, "Number of defined response buttons: %d\n",
310  timer->num_defined_buttons);
311 
312  ts5_log(TS5_LOGLEVEL_0, "Number of active response buttons: %d\n",
313  timer->num_active_buttons);
314 
315  ts5_log(TS5_LOGLEVEL_0, "Mouse is response device: %d\n",
316  timer->mouse_is_response_device);
317 
318  if (timer->mouse_is_response_device) {
319 
320  for (i=0; i<timer->mouse.num_buttons; i++) {
321 
322  if (timer->mouse.button_press_active[i]!=0) {
323  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
324  "Mouse button press", i+1, "has response value",
325  timer->mouse.button_press_defined[i]);
326  }
327 
328  if (timer->mouse.button_release_active[i]!=0) {
329  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
330  "Mouse button release", i+1, "has response value",
331  timer->mouse.button_release_defined[i]);
332  }
333  }
334  }
335 
336  ts5_log(TS5_LOGLEVEL_0, "Keyboard is response device: %d\n",
337  timer->keyboard_is_response_device);
338 
339  if (timer->keyboard_is_response_device) {
340 
341  for (i=0; i<timer->keyboard.num_buttons; i++) {
342 
343  if (timer->keyboard.button_press_active[i]!=0) {
344  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
345  "Keyboard button press", i+1, "has response value",
346  timer->keyboard.button_press_defined[i]);
347  }
348 
349  if (timer->keyboard.button_release_active[i]!=0) {
350  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
351  "Keyboard button release", i+1, "has response value",
352  timer->keyboard.button_release_defined[i]);
353  }
354  }
355  }
356 
357  ts5_log(TS5_LOGLEVEL_0, "Number of joysticks: %d\n",
358  timer->num_joysticks);
359 
360  ts5_log(TS5_LOGLEVEL_0, "Joystick is response device: %d\n",
361  timer->joystick_is_response_device);
362 
363  if (timer->joystick_is_response_device) {
364 
365  for (i=0; i<timer->num_joysticks; i++) {
366  int j;
367 
368  for (j=0; j<timer->joystick[i].num_buttons; j++) {
369 
370  if (timer->joystick[i].button_press_active[j]!=0) {
371  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
372  "Joystick", i+1, "button press", j+1,
373  "has response value",
374  timer->joystick[i].button_press_defined[j]);
375  }
376 
377  if (timer->joystick[i].button_release_active[j]!=0) {
378  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
379  "Joystick", i+1, "button release", j+1,
380  "has response value",
381  timer->joystick[i].button_release_defined[j]);
382  }
383  }
384  }
385  }
386 
387  ts5_log(TS5_LOGLEVEL_0, "Number of cedrusboxes: %d\n",
388  timer->num_cedrusboxes);
389 
390  ts5_log(TS5_LOGLEVEL_0, "Cedrusbox is response device: %d\n",
391  timer->cedrusbox_is_response_device);
392 
393  if (timer->cedrusbox_is_response_device) {
394 
395  for (i=0; i<timer->num_cedrusboxes; i++) {
396 
397  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
398  "Cedrusbox", i+1,
399  "is mapped to serial device",
400  timer->cedrusbox[i].port_num+1);
401 
402  ts5_log(TS5_LOGLEVEL_0, "Cedrusbox %d is type %d\n",
403  i+1, timer->cedrusbox[i].type);
404 
405  int j;
406  for (j=0; j<timer->cedrusbox[i].num_buttons; j++) {
407 
408  if (timer->cedrusbox[i].button_press_active[j]!=0) {
409  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
410  "Cedrusbox", i+1, "button press", j+1,
411  "has response value",
412  timer->cedrusbox[i].button_press_defined[j]);
413  }
414 
415  if (timer->cedrusbox[i].button_release_active[j]!=0) {
416  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
417  "Cedrusbox", i+1, "button release", j+1,
418  "has response value",
419  timer->cedrusbox[i].button_release_defined[j]);
420  }
421  }
422  }
423  }
424 
425  ts5_log(TS5_LOGLEVEL_0, "Number of parallel ports: %d\n",
426  timer->num_parports);
427 
428  ts5_log(TS5_LOGLEVEL_0, "Parallel port is response device: %d\n",
429  timer->parport_is_response_device);
430 
431  if (timer->parport_is_response_device) {
432 
433  for (i=0; i<timer->num_parports; i++) {
434 
435  int j;
436  for (j=0; j<timer->parport[i].num_buttons; j++) {
437 
438  if (timer->parport[i].button_press_active[j]!=0) {
439  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
440  "Parallel box", i+1, "button press", j+1,
441  "has response value",
442  timer->parport[i].button_press_defined[j]);
443  }
444 
445  if (timer->cedrusbox[i].button_release_active[j]!=0) {
446  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
447  "Parallel box", i+1, "button release", j+1,
448  "has response value",
449  timer->parport[i].button_release_defined[j]);
450  }
451  }
452  }
453  }
454 
455  ts5_log(TS5_LOGLEVEL_0, "\n");
456 
457 
458  // audio parameters
459 
460  ts5_log(TS5_LOGLEVEL_0, line);
461 
462  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
463  "Number of audio channels", _ts5_status.audio.channels);
464 
465  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
466  "Sample rate", _ts5_status.audio.frequency);
467 
468  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
469  "Sample format", _ts5_status.audio.depth);
470 
471  ts5_log(TS5_LOGLEVEL_0, "%s: %f\n",
472  "Audio Gain", _ts5_status.audio.gain);
473 
474 
475  ts5_log(TS5_LOGLEVEL_0, "\n");
476  ts5_log(TS5_LOGLEVEL_0, line);
477 }
478 
479 
480 ////////////////////////////////////////////////////////////////////////////////
481 //@}
482 ////////////////////////////////////////////////////////////////////////////////
483 
484 
485 ////////////////////////////////////////////////////////////////////////////////
486 /// @name Error exit
487 /// During an experiment lots of unexpected things can happen.
488 /// (e.g. you forgot to copy stimulus bitmaps to the experiment computer).
489 ///
490 /// It is a good habit to check for such unexpected events and exit your
491 /// program safely before an ugly crash happens.
492 //@{
493 ////////////////////////////////////////////////////////////////////////////////
494 
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 /// Exit safely with an error message.
498 ///
499 /// \param format Printf-style format string that contains the error message.
500 ///
501 /// Closes Tscope5, all subsystems and the log window.
502 ///
503 /// A message box appears with the error message supplied by the user.
504 ///
505 /// This function can be called before Tscope5 is installed.
506 ////////////////////////////////////////////////////////////////////////////////
507 void ts5_fatal(const char *format, ...)
508 {
509  ts5_log(TS5_LOGLEVEL_1, "ts5_fatal\n");
510 
511  char outbuf[TS5_MAX_CHAR];
512  va_list args;
513  va_start(args, format);
514  vsnprintf(outbuf, TS5_MAX_CHAR*sizeof(char), format, args);
515  va_end(args);
516 
517  fprintf(stdout, "Tscope5 error: %s", outbuf);
518 
519  if (_ts5_status.num_displays>0) {
520 
521  if (_ts5_status.display[_ts5_status.active_display].display_mode
522  == TS5_FULLSCREEN_WINDOW) {
523 
524  al_toggle_display_flag(
525  _ts5_data.display[_ts5_status.active_display],
526  ALLEGRO_FULLSCREEN_WINDOW, 0);
527 
528  _ts5_status.display[_ts5_status.active_display].display_mode
529  = TS5_WINDOWED;
530  }
531 
532  al_show_native_message_box(
533  _ts5_data.display[_ts5_status.active_display],
534  "Tscope5 error", "Tscope5 error", outbuf, NULL,
535  ALLEGRO_MESSAGEBOX_ERROR);
536  }
537  else {
538  al_show_native_message_box(NULL, "Tscope5 error", "Tscope5 error",
539  outbuf, NULL, ALLEGRO_MESSAGEBOX_ERROR);
540  }
541  exit(1);
542 }
543 
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 //@}
547 ////////////////////////////////////////////////////////////////////////////////