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 
302  // audio parameters
303  ts5_log(TS5_LOGLEVEL_0, line);
304 
305  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
306  "Number of audio channels", _ts5_status.audio.channels);
307 
308  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
309  "Sample rate", _ts5_status.audio.samplerate);
310 
311  ts5_log(TS5_LOGLEVEL_0, "%s: %d\n",
312  "Sample format", _ts5_status.audio.depth);
313 
314  ts5_log(TS5_LOGLEVEL_0, "%s: %f\n",
315  "Audio Gain", _ts5_status.audio.gain);
316 
317 
318  // timer
319  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
320 
321  ts5_log(TS5_LOGLEVEL_0, line);
322 
323  ts5_log(TS5_LOGLEVEL_0, "Program priority: %+d\n",
324  timer->priority);
325 
326  ts5_log(TS5_LOGLEVEL_0, "Number of defined response buttons: %d\n",
327  timer->num_defined_buttons);
328 
329  ts5_log(TS5_LOGLEVEL_0, "Number of active response buttons: %d\n",
330  timer->num_active_buttons);
331 
332  ts5_log(TS5_LOGLEVEL_0, "Voicekey is response device: %d\n",
333  timer->voicekey_is_response_device);
334 
335  if (timer->voicekey_is_response_device) {
336 
337  for (i=0; i<timer->voicekey.num_buttons; i++) {
338 
339  if (timer->voicekey.button_press_active[i]!=0) {
340  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
341  "Voice key button press", i+1, "has response value",
342  timer->voicekey.button_press_defined[i]);
343  }
344 
345  if (timer->voicekey.button_release_active[i]!=0) {
346  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
347  "Voice key button release", i+1, "has response value",
348  timer->voicekey.button_release_defined[i]);
349  }
350  }
351  }
352 
353  ts5_log(TS5_LOGLEVEL_0, "Mouse is response device: %d\n",
354  timer->mouse_is_response_device);
355 
356  if (timer->mouse_is_response_device) {
357 
358  for (i=0; i<timer->mouse.num_buttons; i++) {
359 
360  if (timer->mouse.button_press_active[i]!=0) {
361  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
362  "Mouse button press", i+1, "has response value",
363  timer->mouse.button_press_defined[i]);
364  }
365 
366  if (timer->mouse.button_release_active[i]!=0) {
367  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
368  "Mouse button release", i+1, "has response value",
369  timer->mouse.button_release_defined[i]);
370  }
371  }
372  }
373 
374  ts5_log(TS5_LOGLEVEL_0, "Keyboard is response device: %d\n",
375  timer->keyboard_is_response_device);
376 
377  if (timer->keyboard_is_response_device) {
378 
379  for (i=0; i<timer->keyboard.num_buttons; i++) {
380 
381  if (timer->keyboard.button_press_active[i]!=0) {
382  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
383  "Keyboard button press", i+1, "has response value",
384  timer->keyboard.button_press_defined[i]);
385  }
386 
387  if (timer->keyboard.button_release_active[i]!=0) {
388  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
389  "Keyboard button release", i+1, "has response value",
390  timer->keyboard.button_release_defined[i]);
391  }
392  }
393  }
394 
395  ts5_log(TS5_LOGLEVEL_0, "Number of joysticks: %d\n",
396  timer->num_joysticks);
397 
398  ts5_log(TS5_LOGLEVEL_0, "Joystick is response device: %d\n",
399  timer->joystick_is_response_device);
400 
401  if (timer->joystick_is_response_device) {
402 
403  for (i=0; i<timer->num_joysticks; i++) {
404  int j;
405 
406  for (j=0; j<timer->joystick[i].num_buttons; j++) {
407 
408  if (timer->joystick[i].button_press_active[j]!=0) {
409  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
410  "Joystick", i+1, "button press", j+1,
411  "has response value",
412  timer->joystick[i].button_press_defined[j]);
413  }
414 
415  if (timer->joystick[i].button_release_active[j]!=0) {
416  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
417  "Joystick", i+1, "button release", j+1,
418  "has response value",
419  timer->joystick[i].button_release_defined[j]);
420  }
421  }
422  }
423  }
424 
425  ts5_log(TS5_LOGLEVEL_0, "Number of cedrusboxes: %d\n",
426  timer->num_cedrusboxes);
427 
428  ts5_log(TS5_LOGLEVEL_0, "Cedrusbox is response device: %d\n",
429  timer->cedrusbox_is_response_device);
430 
431  if (timer->cedrusbox_is_response_device) {
432 
433  for (i=0; i<timer->num_cedrusboxes; i++) {
434 
435  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d\n",
436  "Cedrusbox", i+1,
437  "is mapped to serial device",
438  timer->cedrusbox[i].port_num+1);
439 
440  ts5_log(TS5_LOGLEVEL_0, "Cedrusbox %d is type %d\n",
441  i+1, timer->cedrusbox[i].type);
442 
443  int j;
444  for (j=0; j<timer->cedrusbox[i].num_buttons; j++) {
445 
446  if (timer->cedrusbox[i].button_press_active[j]!=0) {
447  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
448  "Cedrusbox", i+1, "button press", j+1,
449  "has response value",
450  timer->cedrusbox[i].button_press_defined[j]);
451  }
452 
453  if (timer->cedrusbox[i].button_release_active[j]!=0) {
454  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
455  "Cedrusbox", i+1, "button release", j+1,
456  "has response value",
457  timer->cedrusbox[i].button_release_defined[j]);
458  }
459  }
460  }
461  }
462 
463  ts5_log(TS5_LOGLEVEL_0, "Number of parallel ports: %d\n",
464  timer->num_parports);
465 
466  ts5_log(TS5_LOGLEVEL_0, "Parallel port is response device: %d\n",
467  timer->parport_is_response_device);
468 
469  if (timer->parport_is_response_device) {
470 
471  for (i=0; i<timer->num_parports; i++) {
472 
473  int j;
474  for (j=0; j<timer->parport[i].num_buttons; j++) {
475 
476  if (timer->parport[i].button_press_active[j]!=0) {
477  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
478  "Parallel box", i+1, "button press", j+1,
479  "has response value",
480  timer->parport[i].button_press_defined[j]);
481  }
482 
483  if (timer->cedrusbox[i].button_release_active[j]!=0) {
484  ts5_log(TS5_LOGLEVEL_0, "%s %d %s %d %s %d\n",
485  "Parallel box", i+1, "button release", j+1,
486  "has response value",
487  timer->parport[i].button_release_defined[j]);
488  }
489  }
490  }
491  }
492 
493  ts5_log(TS5_LOGLEVEL_0, "\n");
494 
495 
496 
497  ts5_log(TS5_LOGLEVEL_0, "\n");
498  ts5_log(TS5_LOGLEVEL_0, line);
499 }
500 
501 
502 ////////////////////////////////////////////////////////////////////////////////
503 //@}
504 ////////////////////////////////////////////////////////////////////////////////
505 
506 
507 ////////////////////////////////////////////////////////////////////////////////
508 /// @name Error exit
509 /// During an experiment lots of unexpected things can happen.
510 /// (e.g. you forgot to copy stimulus bitmaps to the experiment computer).
511 ///
512 /// It is a good habit to check for such unexpected events and exit your
513 /// program safely before an ugly crash happens.
514 //@{
515 ////////////////////////////////////////////////////////////////////////////////
516 
517 
518 ////////////////////////////////////////////////////////////////////////////////
519 /// Exit safely with an error message.
520 ///
521 /// \param format Printf-style format string that contains the error message.
522 ///
523 /// Closes Tscope5, all subsystems and the log window.
524 ///
525 /// A message box appears with the error message supplied by the user.
526 ///
527 /// This function can be called before Tscope5 is installed.
528 ////////////////////////////////////////////////////////////////////////////////
529 void ts5_fatal(const char *format, ...)
530 {
531  ts5_log(TS5_LOGLEVEL_1, "ts5_fatal\n");
532 
533  char outbuf[TS5_MAX_CHAR];
534  va_list args;
535  va_start(args, format);
536  vsnprintf(outbuf, TS5_MAX_CHAR*sizeof(char), format, args);
537  va_end(args);
538 
539  fprintf(stdout, "Tscope5 error: %s", outbuf);
540 
541  #ifndef TS5_RASPBERRYPI
542  if (_ts5_status.num_displays>0) {
543 
544  if (_ts5_status.display[_ts5_status.active_display].display_mode
545  == TS5_FULLSCREEN_WINDOW) {
546 
547  al_toggle_display_flag(
548  _ts5_data.display[_ts5_status.active_display],
549  ALLEGRO_FULLSCREEN_WINDOW, 0);
550 
551  _ts5_status.display[_ts5_status.active_display].display_mode
552  = TS5_WINDOWED;
553  }
554 
555  al_show_native_message_box(
556  _ts5_data.display[_ts5_status.active_display],
557  "Tscope5 error", "Tscope5 error", outbuf, NULL,
558  ALLEGRO_MESSAGEBOX_ERROR);
559  }
560  else {
561  al_show_native_message_box(NULL, "Tscope5 error", "Tscope5 error",
562  outbuf, NULL, ALLEGRO_MESSAGEBOX_ERROR);
563  }
564 
565  #endif
566 
567  exit(1);
568 }
569 
570 
571 ////////////////////////////////////////////////////////////////////////////////
572 //@}
573 ////////////////////////////////////////////////////////////////////////////////
int _ts5_is_tscope5_installed
Is Tscope5 installed?
int ts5_get_log_level()
Get log level.
Definition: system.c:128
TS5_DISPLAY_STATUS ts5_nextdisplay
Settings for the next display that will be opened.
void ts5_log(const unsigned int level, const char *format,...)
Send info to a logging window.
Definition: system.c:45
int ts5_set_log_level(const unsigned int loglevel)
Set log level.
Definition: system.c:98
void ts5_install_tscope5(char *calling_function)
Install Tscope5.
void ts5_print_status()
Write the status of all Tscope5 subsystem to the log window.
Definition: system.c:148
int _ts5_is_textlog_installed
Is text log installed?
void ts5_fatal(const char *format,...)
Exit safely with an error message.
Definition: system.c:529