Tscope5
parport_internal.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // __ ______
4 // / /_______________ ____ ___ / ____/
5 // / __/ ___/ ___/ __ \/ __ \/ _ \ /___ )
6 // / /_(__ ) /__/ /_/ / /_/ / __/ ____/ /
7 // \__/____/\___/\____/ .___/\___/ /_____/
8 // /_/
9 //
10 /// \file parport_internal.c
11 /// Definitions of internal parallel port functions.
12 ////////////////////////////////////////////////////////////////////////////////
13 
14 #include "../include/tscope5/parport_internal.h"
15 #include "../include/tscope5/system_internal.h"
16 #include "../include/tscope5/timer_internal.h"
17 
18 /// Is the parport subsystem installed?
20 
21 #ifdef TS5_WINDOWS
22  #include <windows.h>
23  HINSTANCE hLib;
24  typedef short (_stdcall *inbptr)(short portaddr);
25  typedef short (_stdcall *outbptr)(short portaddr, short value);
26  inbptr inb;
27  outbptr outb;
28 
29 #elif defined TS5_LINUX
30  #include <unistd.h>
31  #include <sys/io.h>
32 
33 #endif
34 
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 /// Do some checks at the start of each parport function.
38 ///
39 /// \param calling_function Name the function that calls for
40 /// this check or installation.
41 ///
42 /// Checks whether Tscope5 is installed. If not, Tscope5 is installed.
43 /// Then checks whether the parport subsystem is installed.
44 /// If so, aborts with an error message.
45 ////////////////////////////////////////////////////////////////////////////////
46 void ts5_check_parport(char *calling_function)
47 {
48  ts5_log(TS5_LOGLEVEL_6, "%s: ts5_check_parport\n", calling_function);
49 
51  ts5_install_tscope5(calling_function);
52  }
53 
55  ts5_fatal("%s: parport subsystem is already running. ",
56  "This function has to be called before the (automatic) ",
57  "installation of the parallel port system.\n",
58  calling_function);
59  }
60 }
61 
62 
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 /// Do some checks at the start of each parport function.
66 ///
67 /// \param calling_function Name the function that calls for
68 /// this check or installation.
69 ///
70 /// Checks whether the parport subsystem is installed.
71 /// If not, the parport subsystem is installed.
72 ////////////////////////////////////////////////////////////////////////////////
73 void ts5_check_parport2(char *calling_function)
74 {
75  ts5_log(TS5_LOGLEVEL_6, "%s: ts5_check_parport2\n", calling_function);
76 
78  ts5_install_parport(calling_function);
79  }
80 }
81 
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 /// Install the parport subsystem.
85 ///
86 /// \param calling_function Name the function that calls for
87 /// this check or installation.
88 ///
89 /// This function is called automatically if necessary.
90 ////////////////////////////////////////////////////////////////////////////////
91 void ts5_install_parport(char *calling_function)
92 {
94  ts5_install_timer(calling_function);
95  }
96 
98 
100  ts5_log(TS5_LOGLEVEL_1, "%s: Installing Tscope5 parport\n",
101  calling_function);
102 
103  int i;
104 
105  #ifdef TS5_MACOSX
106  ts5_fatal("%s: parallel port boxes not supported on Mac OS X\n",
107  calling_function);
108 
109  #endif
110 
111  #ifdef TS5_WINDOWS
112  if (!(hLib = LoadLibrary("inpout32.dll"))) {
113  ts5_fatal("%s: could not load inpout32.dll\n",
114  calling_function);
115  }
116 
117  if (!(inb = (inbptr)GetProcAddress(hLib, "Inp32"))) {
118  ts5_fatal("%s: could not get address for Inp32\n",
119  calling_function);
120  }
121 
122  if (!(outb = (outbptr)GetProcAddress(hLib, "Out32"))) {
123  ts5_fatal("%s: could not get address for Out32\n",
124  calling_function);
125  }
126 
127  for (i=0; i<_ts5_status.timer.num_parports; i++) {
128  outb(_ts5_status.timer.parport_control_register[i], 0);
129  }
130 
131  #endif
132 
133  #ifdef TS5_LINUX
134  if (geteuid() != 0) {
135  ts5_fatal("%s: only root can open the parallel port.",
136  calling_function);
137  }
138 
139  if (ioperm(TS5_PARPORT_1_DATA, 3, 1)) {
140  ts5_fatal("%s: error opening parallell port 1.",
141  calling_function );
142  }
143 
144  if (ioperm(TS5_PARPORT_2_DATA, 3, 1)) {
145  ts5_fatal("%s: error opening parallell port 2.",
146  calling_function);
147  }
148 
149  if (ioperm(TS5_PARPORT_3_DATA, 3, 1)) {
150  ts5_fatal("%s: error opening parallell port 3.",
151  calling_function);
152  }
153 
154  for (i=0; i<_ts5_status.timer.num_parports; i++) {
155  outb(0, _ts5_status.timer.parport_control_register[i]);
156  }
157 
158  #endif
159 
160  // unitialize event source
161  al_init_user_event_source(
162  &_ts5_data.timer.parport_response_event_source);
163 
164  al_init_user_event_source(
165  &_ts5_data.timer.parport_trigger_event_source);
166 
167  // register event source
168  al_register_event_source(_ts5_data.timer.response_queue,
169  &_ts5_data.timer.parport_response_event_source);
170 
171  al_register_event_source(_ts5_data.timer.trigger_queue,
172  &_ts5_data.timer.parport_trigger_event_source);
173 
174  al_register_event_source(_ts5_data.timer.trigger_log,
175  &_ts5_data.timer.parport_trigger_event_source);
176 
177  // initialize thread for parport
178  _ts5_data.timer.parport_thread =
179  al_create_thread(ts5_parport_threadfunc, NULL);
180 
181  al_start_thread(_ts5_data.timer.parport_thread);
182 
183  // assign response codes
184  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
185 
186  timer->num_parports = 3;
187  timer->parport =
188  (TS5_PARPORT_STATUS *)al_malloc(sizeof(TS5_PARPORT_STATUS)*
189  timer->num_parports);
190 
191  for (i=0; i<timer->num_parports; i++) {
192 
193  timer->parport[i].num_buttons = 5;
194  timer->parport[i].num_defined_buttons = 0;
195  timer->parport[i].num_active_buttons = 0;
196  timer->parport[i].button_debounce_time = 0.0;
197 
198  timer->parport[i].status_register_current_state =
199  (int *)al_malloc(sizeof(int)
200  * timer->parport[i].num_buttons);
201 
202  timer->parport[i].status_register_previous_state =
203  (int *)al_malloc(sizeof(int)
204  * timer->parport[i].num_buttons);
205 
206  timer->parport[i].status_register_last_state_toggle_time =
207  (double *)al_malloc(sizeof(double)
208  * timer->parport[i].num_buttons);
209 
210  timer->parport[i].button_press_defined =
211  (int *)al_malloc(sizeof(int)
212  * timer->parport[i].num_buttons);
213 
214  timer->parport[i].button_press_active =
215  (int *)al_malloc(sizeof(int)
216  * timer->parport[i].num_buttons);
217 
218  timer->parport[i].button_release_defined =
219  (int *)al_malloc(sizeof(int)
220  * timer->parport[i].num_buttons);
221 
222  timer->parport[i].button_release_active =
223  (int *)al_malloc(sizeof(int)
224  * timer->parport[i].num_buttons);
225 
226  int j;
227  for (j=0; j<timer->parport[i].num_buttons; j++) {
228  timer->parport[i].status_register_current_state[j] = 0;
229  timer->parport[i].status_register_previous_state[j] = 0;
230 
231  timer->parport[i].status_register_last_state_toggle_time[j] =
232  al_get_time();
233 
234  timer->parport[i].button_press_defined[j] = 0;
235  timer->parport[i].button_press_active[j] = 0;
236  timer->parport[i].button_release_defined[j] = 0;
237  timer->parport[i].button_release_active[j] = 0;
238  }
239 
240  timer->parport[i].is_trigger_input_device = 0;
241  timer->parport[i].is_trigger_output_device = 0;
242  timer->parport[i].trigger_debounce_time = 0.0;
243 
244  timer->parport[i].simulate_trigger_input = 0;
245  timer->parport[i].trigger_simulation_interval = 2.0;
246 
247  timer->parport[i].last_trigger_simulation =
248  al_get_time();
249 
250  timer->parport[i].data_register_current_state = 0;
251  timer->parport[i].data_register_previous_state = 0;
252  timer->parport[i].trigger_output_time = 0.002;
253  }
254 
255  atexit(ts5_uninstall_parport);
256  }
257 }
258 
259 
260 ////////////////////////////////////////////////////////////////////////////////
261 /// Uninstall the parport subsystem.
262 ///
263 /// This function is called automatically at the end of the program.
264 ////////////////////////////////////////////////////////////////////////////////
266 {
268 
269  int i;
270 
271  ts5_log(TS5_LOGLEVEL_1, "Uninstalling Tscope5 parport\n");
272 
273  // remove thread
274  al_join_thread(_ts5_data.timer.parport_thread, NULL);
275  al_destroy_thread(_ts5_data.timer.parport_thread);
276 
277  // unregister event source
278  al_unregister_event_source(_ts5_data.timer.response_queue,
279  &_ts5_data.timer.parport_response_event_source);
280 
281  al_unregister_event_source(_ts5_data.timer.trigger_queue,
282  &_ts5_data.timer.parport_trigger_event_source);
283 
284  al_unregister_event_source(_ts5_data.timer.trigger_log,
285  &_ts5_data.timer.parport_trigger_event_source);
286 
287  // remove event source
288  al_destroy_user_event_source(
289  &_ts5_data.timer.parport_response_event_source);
290 
291  al_destroy_user_event_source(
292  &_ts5_data.timer.parport_trigger_event_source);
293 
294  #ifdef TS5_WINDOWS
295  for (i=0; i<_ts5_status.timer.num_parports; i++) {
296  outb(_ts5_status.timer.parport_control_register[i], 0);
297  }
298 
299  FreeLibrary(hLib);
300 
301  #endif
302 
303  #ifdef TS5_LINUX
304  for (i=0; i<_ts5_status.timer.num_parports; i++) {
305  outb(0, _ts5_status.timer.parport_control_register[i]);
306  }
307 
308  if (geteuid() != 0) {
309  ts5_fatal("%s: %s\n",
310  "ts5_uninstall_parport",
311  "only root can close the parallel port");
312  }
313 
314  if (ioperm(TS5_PARPORT_1_DATA, 3, 0)) {
315  ts5_fatal("%s: %s\n",
316  "ts5_uninstall_parport",
317  "error closing parallell port 1");
318  }
319 
320  if (ioperm(TS5_PARPORT_2_DATA, 3, 0)) {
321  ts5_fatal("%s: %s\n",
322  "ts5_uninstall_parport",
323  "error closing parallell port 2");
324  }
325 
326  if (ioperm(TS5_PARPORT_3_DATA, 3, 0)) {
327  ts5_fatal("%s: %s\n",
328  "ts5_uninstall_parport",
329  "error closing parallell port 3");
330  }
331 
332  #endif
333 
334  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
335 
336  for (i=0; i<timer->num_parports; i++) {
337 
338  al_free(timer->parport[i].status_register_current_state);
339  timer->parport[i].status_register_current_state = NULL;
340 
341  al_free(timer->parport[i].status_register_previous_state);
342  timer->parport[i].status_register_previous_state = NULL;
343 
344  al_free(timer->parport[i].status_register_last_state_toggle_time);
345  timer->parport[i].status_register_last_state_toggle_time = NULL;
346 
347  al_free(timer->parport[i].button_press_defined);
348  timer->parport[i].button_press_defined = NULL;
349 
350  al_free(timer->parport[i].button_press_active);
351  timer->parport[i].button_press_active = NULL;
352 
353  al_free(timer->parport[i].button_release_defined);
354  timer->parport[i].button_release_defined = NULL;
355 
356  al_free(timer->parport[i].button_release_active);
357  timer->parport[i].button_release_active = NULL;
358  }
359 
360  al_free(timer->parport);
361  timer->parport=NULL;
362 
363  timer->num_parports = 0;
364  timer->parport_is_response_device = 0;
365 
367  }
368 }
369 
370 
371 ////////////////////////////////////////////////////////////////////////////////
372 /// Set the DATA register of the parallel port to input mode.
373 ///
374 /// \param calling_function Name the function that calls
375 /// for this check or installation.
376 /// \param device Number of the parallel port.
377 ////////////////////////////////////////////////////////////////////////////////
378 void ts5_set_parport_trigger_input(char *calling_function, int device)
379 {
380  ts5_check_parport2(calling_function);
381 
382  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
383 
384  if (!timer->parport[device-1].is_trigger_input_device) {
385 
386  if (device<1 || device>timer->num_parports) {
387  ts5_fatal("%s: %s %d, %s %d\n",
388  calling_function,
389  "device argument is", device,
390  "number of parallel ports is", timer->num_parports);
391  }
392 
393  if (timer->parport[device-1].num_defined_buttons) {
394  ts5_fatal("%s: %s %d %s\n", calling_function, "parallel port",
395  device, "is already defined as an response device");
396  }
397 
398  if (timer->parport[device-1].is_trigger_output_device) {
399  ts5_fatal("%s: %s %d %s\n", calling_function, "parallel port",
400  device, "is already defined as a trigger output device");
401  }
402 
403  timer->parport_is_trigger_device = 1;
404  timer->parport[device-1].is_trigger_input_device = 1;
405 
406  #ifdef TS5_WINDOWS
407  outb(_ts5_status.timer.parport_control_register[device-1], 32);
408 
409  #elif defined TS5_LINUX
410  outb(32, _ts5_status.timer.parport_control_register[device-1]);
411 
412  #endif
413 
414  }
415 }
416 
417 
418 ////////////////////////////////////////////////////////////////////////////////
419 /// Set the DATA register of the parallel port to output mode.
420 ///
421 /// \param calling_function Name the function that calls
422 /// for this check or installation.
423 /// \param device Number of the parallel port.
424 ////////////////////////////////////////////////////////////////////////////////
425 void ts5_set_parport_trigger_output(char *calling_function, int device)
426 {
427  ts5_check_parport2(calling_function);
428  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
429 
430  if (!timer->parport[device-1].is_trigger_output_device) {
431 
432  if (device<1 || device>timer->num_parports) {
433  ts5_fatal("%s: %s %d, %s %d\n", calling_function,
434  "device argument is", device,
435  "number of parallel ports is", timer->num_parports);
436  }
437 
438  if (timer->parport[device-1].num_defined_buttons) {
439  ts5_fatal("%s: %s %d %s\n", calling_function, "parallel port",
440  device, "is already defined as an response device");
441  }
442 
443  if (timer->parport[device-1].is_trigger_input_device) {
444  ts5_fatal("%s: %s %d %s\n", calling_function, "parallel port",
445  device, "is already defined as a trigger input device");
446  }
447 
448  timer->parport_is_trigger_device = 1;
449  timer->parport[device-1].is_trigger_output_device = 1;
450 
451  #ifdef TS5_WINDOWS
452  outb(_ts5_status.timer.parport_control_register[device-1], 0);
453 
454  #elif defined TS5_LINUX
455  outb(0, _ts5_status.timer.parport_control_register[device-1]);
456 
457  #endif
458 
459  }
460 }
461 
462 
463 ////////////////////////////////////////////////////////////////////////////////
464 /// Parallel port thread function.
465 ///
466 /// \warning This is an internal function, no checks are performed.
467 ////////////////////////////////////////////////////////////////////////////////
469 {
470  ALLEGRO_EVENT parport_event;
471  double previous_time;
472  double current_time = al_get_time();
473 
474  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
475 
476  while (!al_get_thread_should_stop(_ts5_data.timer.parport_thread)) {
477 
478  int i;
479  for (i=0; i<timer->num_parports; i++) {
480 
481 
482  // monitor STATUS register for responses
483  short input = 0;
484 
485  #ifndef TS5_MACOSX
486  input = inb(_ts5_status.timer.parport_status_register[i]);
487 
488  #endif
489 
490  timer->parport[i].status_register_current_state[0] =
491  (input & 8) >> 3;
492 
493  timer->parport[i].status_register_current_state[1] =
494  (input & 16) >> 4;
495 
496  timer->parport[i].status_register_current_state[2] =
497  (input & 32) >> 5;
498 
499  timer->parport[i].status_register_current_state[3] =
500  (input & 64) >> 6;
501 
502  timer->parport[i].status_register_current_state[4] =
503  (input & 128) >> 7;
504 
505  int button = 0;
506  int action = 0;
507 
508  int j;
509  for (j=0; j<timer->parport[i].num_buttons; j++) {
510 
511  if (timer->parport[i].status_register_current_state[j] !=
512  timer->parport[i].status_register_previous_state[j]) {
513 
514  if (current_time - timer->parport[i]
515  .status_register_last_state_toggle_time[j] >
516  timer->parport[i].button_debounce_time) {
517 
518  button = j+1;
519  action = timer->parport[i]
520  .status_register_current_state[j];
521 
522  timer->parport[i].status_register_previous_state[j] =
523  timer->parport[i].status_register_current_state[j];
524 
525  timer->parport[i]
526  .status_register_last_state_toggle_time[j] = current_time;
527  }
528  }
529  }
530 
531  if (button) {
532 
533  if (action==0) {
534  parport_event.user.type = TS5_EVENT_PARPORT_BUTTON_UP;
535  }
536 
537  if (action==1) {
538  parport_event.user.type = TS5_EVENT_PARPORT_BUTTON_DOWN;
539  }
540 
541  parport_event.user.data1 = i;
542  parport_event.user.data2 = button;
543  parport_event.user.data3 =
544  (intptr_t)((current_time-previous_time)*1000000.0);
545 
546  al_emit_user_event(
547  &_ts5_data.timer.parport_response_event_source,
548  &parport_event, NULL);
549  }
550 
551 
552  // monitor DATA register for triggers
553  input = 0;
554 
555  #ifndef TS5_MACOSX
556  input = inb(_ts5_status.timer.parport_data_register[i]);
557 
558  #endif
559 
560  timer->parport[i].data_register_current_state = input;
561 
562  if (timer->parport[i].is_trigger_input_device &&
563  timer->parport[i].data_register_current_state &&
564  timer->parport[i].data_register_current_state !=
565  timer->parport[i].data_register_previous_state) {
566 
567  if (current_time
568  - timer->parport[i].data_register_last_state_toggle_time
569  > timer->parport[i].trigger_debounce_time) {
570 
571  parport_event.user.type = TS5_EVENT_PARPORT_TRIGGER;
572 
573  parport_event.user.data1 = i;
574 
575  parport_event.user.data2 =
576  (int)timer->parport[i].data_register_current_state;
577 
578  parport_event.user.data3 =
579  (intptr_t)((current_time-previous_time)*1000000.0);
580 
581  al_emit_user_event(
582  &_ts5_data.timer.parport_trigger_event_source,
583  &parport_event, NULL);
584 
585  timer->parport[i].data_register_previous_state =
586  timer->parport[i].data_register_current_state;
587 
588  timer->parport[i].data_register_last_state_toggle_time =
589  current_time;
590  }
591  }
592 
593  // simulate triggers
594  if (timer->parport[i].simulate_trigger_input) {
595 
596  if (current_time - timer->parport[i].last_trigger_simulation
597  >= timer->parport[i].trigger_simulation_interval) {
598 
599  parport_event.user.type = TS5_EVENT_PARPORT_TRIGGER;
600 
601  parport_event.user.data1 = i;
602 
603  parport_event.user.data2 =
604  timer->parport[i].simulate_trigger_input;
605 
606  parport_event.user.data3 =
607  (intptr_t)((current_time-previous_time)*1000000.0);
608 
609  al_emit_user_event(
610  &_ts5_data.timer.parport_trigger_event_source,
611  &parport_event, NULL);
612 
613  timer->parport[i].last_trigger_simulation = current_time;
614  }
615  }
616  }
617  previous_time = current_time;
618  current_time = al_get_time();
619  }
620 
621  return NULL;
622 }
623 
624 
int _ts5_is_tscope5_installed
Is Tscope5 installed?
int _ts5_is_parport_installed
Is the parport subsystem installed?
void ts5_check_parport2(char *calling_function)
Do some checks at the start of each parport function.
void ts5_set_parport_trigger_output(char *calling_function, int device)
Set the DATA register of the parallel port to output mode.
int _ts5_is_timer_installed
Is the timer subsystem installed?
void * ts5_parport_threadfunc()
Parallel port thread function.
void ts5_install_parport(char *calling_function)
Install the parport subsystem.
void ts5_check_parport(char *calling_function)
Do some checks at the start of each parport function.
void ts5_install_timer(char *calling_function)
Install the timer subsystem.
void ts5_log(const unsigned int level, const char *format,...)
Send info to a logging window.
Definition: system.c:45
void ts5_set_parport_trigger_input(char *calling_function, int device)
Set the DATA register of the parallel port to input mode.
void ts5_install_tscope5(char *calling_function)
Install Tscope5.
void ts5_fatal(const char *format,...)
Exit safely with an error message.
Definition: system.c:529
void ts5_uninstall_parport()
Uninstall the parport subsystem.