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_status.timer.parport_base_address[0], 3, 1)) {
140  ts5_fatal("%s: error opening parallell port 1.",
141  calling_function );
142  }
143 
144  if (ioperm(_ts5_status.timer.parport_base_address[1], 3, 1)) {
145  ts5_fatal("%s: error opening parallell port 2.",
146  calling_function);
147  }
148 
149  if (ioperm(_ts5_status.timer.parport_base_address[2], 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  // initialize 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_BASE, 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_BASE, 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_BASE, 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  timer->parport_is_trigger_device = 0;
366 
368  }
369 }
370 
371 
372 ////////////////////////////////////////////////////////////////////////////////
373 /// Set the DATA register of the parallel port to input mode.
374 ///
375 /// \param calling_function Name the function that calls
376 /// for this check or installation.
377 /// \param device Number of the parallel port.
378 ////////////////////////////////////////////////////////////////////////////////
379 void ts5_set_parport_trigger_input(char *calling_function, int device)
380 {
381  ts5_check_parport2(calling_function);
382 
383  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
384 
385  if (!timer->parport[device-1].is_trigger_input_device) {
386 
387  if (device<1 || device>timer->num_parports) {
388  ts5_fatal("%s: %s %d, %s %d\n",
389  calling_function,
390  "device argument is", device,
391  "number of parallel ports is", timer->num_parports);
392  }
393 
394  if (timer->parport[device-1].num_defined_buttons) {
395  ts5_fatal("%s: %s %d %s\n", calling_function, "parallel port",
396  device, "is already defined as an response device");
397  }
398 
399  if (timer->parport[device-1].is_trigger_output_device) {
400  ts5_fatal("%s: %s %d %s\n", calling_function, "parallel port",
401  device, "is already defined as a trigger output device");
402  }
403 
404  timer->parport_is_trigger_device = 1;
405  timer->parport[device-1].is_trigger_input_device = 1;
406 
407  #ifdef TS5_WINDOWS
408  outb(_ts5_status.timer.parport_control_register[device-1], 32);
409 
410  #elif defined TS5_LINUX
411  outb(32, _ts5_status.timer.parport_control_register[device-1]);
412 
413  #endif
414 
415  }
416 }
417 
418 
419 ////////////////////////////////////////////////////////////////////////////////
420 /// Set the DATA register of the parallel port to output mode.
421 ///
422 /// \param calling_function Name the function that calls
423 /// for this check or installation.
424 /// \param device Number of the parallel port.
425 ////////////////////////////////////////////////////////////////////////////////
426 void ts5_set_parport_trigger_output(char *calling_function, int device)
427 {
428  ts5_check_parport2(calling_function);
429  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
430 
431  if (!timer->parport[device-1].is_trigger_output_device) {
432 
433  if (device<1 || device>timer->num_parports) {
434  ts5_fatal("%s: %s %d, %s %d\n", calling_function,
435  "device argument is", device,
436  "number of parallel ports is", timer->num_parports);
437  }
438 
439  if (timer->parport[device-1].num_defined_buttons) {
440  ts5_fatal("%s: %s %d %s\n", calling_function, "parallel port",
441  device, "is already defined as an response device");
442  }
443 
444  if (timer->parport[device-1].is_trigger_input_device) {
445  ts5_fatal("%s: %s %d %s\n", calling_function, "parallel port",
446  device, "is already defined as a trigger input device");
447  }
448 
449  timer->parport_is_trigger_device = 1;
450  timer->parport[device-1].is_trigger_output_device = 1;
451 
452  #ifdef TS5_WINDOWS
453  outb(_ts5_status.timer.parport_control_register[device-1], 0);
454 
455  #elif defined TS5_LINUX
456  outb(0, _ts5_status.timer.parport_control_register[device-1]);
457 
458  #endif
459 
460  }
461 }
462 
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 /// Parallel port thread function.
466 ///
467 /// \warning This is an internal function, no checks are performed.
468 ////////////////////////////////////////////////////////////////////////////////
470 {
471  ALLEGRO_EVENT parport_event;
472  double previous_time;
473  double current_time = al_get_time();
474 
475  TS5_TIMER_STATUS *timer = &_ts5_status.timer;
476 
477  while (!al_get_thread_should_stop(_ts5_data.timer.parport_thread)) {
478 
479  int i;
480  for (i=0; i<timer->num_parports; i++) {
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:533
void ts5_uninstall_parport()
Uninstall the parport subsystem.