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