Tscope5
cedrusbox_internal.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // __ ______
4 // / /_______________ ____ ___ / ____/
5 // / __/ ___/ ___/ __ \/ __ \/ _ \ /___ )
6 // / /_(__ ) /__/ /_/ / /_/ / __/ ____/ /
7 // \__/____/\___/\____/ .___/\___/ /_____/
8 // /_/
9 //
10 /// \file cedrusbox_internal.c
11 /// Definitions of internal cedrusbox functions
12 ////////////////////////////////////////////////////////////////////////////////
13 
14 #include "../include/tscope5/cedrusbox.h"
15 #include "../include/tscope5/cedrusbox_internal.h"
16 #include "../include/tscope5/system_internal.h"
17 #include "../include/tscope5/timer_internal.h"
18 
19 /// Is the cedrusbox subsystem installed?
21 
22 #ifdef TS5_WINDOWS
24 
25 #else
27 
28 #endif
29 
30 
31 ////////////////////////////////////////////////////////////////////////////////
32 /// Do some checks at the start of each cedrusbox function.
33 ///
34 /// \param calling_function Name the function that calls for
35 /// this check or installation.
36 ///
37 /// Checks whether the cedrusbox subsystem is installed.
38 /// If not, the cedrusbox subsystem is installed.
39 ////////////////////////////////////////////////////////////////////////////////
40 void ts5_check_cedrusbox(char *calling_function)
41 {
42  ts5_log(TS5_LOGLEVEL_6, "%s: ts5_check_cedrusbox\n", calling_function);
44  ts5_install_cedrusbox(calling_function);
45  }
46 }
47 
48 
49 ////////////////////////////////////////////////////////////////////////////////
50 /// Install the cedrusbox subsystem.
51 ///
52 /// \param calling_function Name the function that calls for
53 /// this check or installation.
54 ///
55 /// This function is called automatically if necessary.
56 ////////////////////////////////////////////////////////////////////////////////
57 void ts5_install_cedrusbox(char *calling_function)
58 {
60  ts5_install_timer(calling_function);
61  }
62 
64 
66  ts5_log(TS5_LOGLEVEL_1, "%s: Installing Tscope5 cedrusbox\n",
67  calling_function);
68  }
69  else {
70  goto cedrusbox_is_installed;
71  }
72 
73  // scan the serial ports for possible cedrusboxes
74  // this is OS-dependent
75  int num_serial_devices=0;
76 
77  #ifdef TS5_WINDOWS
78  num_serial_devices = ts5_install_cedrusbox_windows(calling_function);
79 
80  #else
81  num_serial_devices = ts5_install_cedrusbox_posix(calling_function);
82 
83  #endif
84 
85  // are the serial devices we found cedrusboxes?
86  int i;
87  int device_type[TS5_CEDRUSBOX_MAXPORT];
88 
89  for (i=0; i<num_serial_devices; i++) {
90 
91  char serial_buff[TS5_MAX_CHAR];
92 
93  // flush
95 
96  // set xid mode
97  ts5_write_cedrusbox(i, "c10", 3);
98 
99  // get the device ID
101  ts5_write_cedrusbox(i, "_d2", 3);
102  ts5_read_cedrusbox(i, serial_buff, 6);
103  device_type[i] = serial_buff[0] - 47; // lumina 1, SV1 2, RBX 3
104 
105  if (device_type[i]==3) {
107  ts5_write_cedrusbox(i, "_d3", 6);
108  ts5_read_cedrusbox(i, serial_buff, 1);
109  device_type[i] += serial_buff[0] - 49;
110  }
111 
112  switch (device_type[i]) {
113 
114  case TS5_CEDRUSBOX_LUMINA:
115  sprintf(serial_buff, "lumina");
116  break;
117 
118  case TS5_CEDRUSBOX_SV1:
119  sprintf(serial_buff, "sv1");
120  break;
121 
122  case TS5_CEDRUSBOX_RB530:
123  sprintf(serial_buff, "rb530");
124  break;
125 
126  case TS5_CEDRUSBOX_RB730:
127  sprintf(serial_buff, "rb730");
128  break;
129 
130  case TS5_CEDRUSBOX_RB830:
131  sprintf(serial_buff, "rb830");
132  break;
133 
134  case TS5_CEDRUSBOX_RB834:
135  sprintf(serial_buff, "rb834");
136  break;
137 
138  default:
139 
140  device_type[i] = TS5_CEDRUSBOX_NODEVICE;
141 
142  #ifdef TS5_WINDOWS
143  if (!CloseHandle(_ts5_cedrusbox_handle[i])) {
144  ts5_log(TS5_LOGLEVEL_1, "%s: %s\n", calling_function,
145  "could not remove unknown device");
146  }
147 
148  #else
149  tcdrain(_ts5_cedrusbox_fd[i]);
150  tcsetattr(_ts5_cedrusbox_fd[i], TCSANOW,
151  &_ts5_cedrusbox_oldoptions[i]);
152 
153  if (close(_ts5_cedrusbox_fd[i]) == -1) {
154  ts5_log(TS5_LOGLEVEL_1, "%s: %s\n", calling_function,
155  "could not remove unknown device");
156  }
157  #endif
158 
159  continue;
160  }
161 
162  ts5_log(TS5_LOGLEVEL_1,"%s: cedrusbox ID %d (%s)\n",
163  calling_function, device_type[i], serial_buff);
164 
165  // get firmware revision
166  char minor, major;
168  ts5_write_cedrusbox(i, "_d4", 3);
169  ts5_read_cedrusbox(i, serial_buff, 6);
170  major = serial_buff[0];
171 
173  ts5_write_cedrusbox(i, "_d5", 3);
174  ts5_read_cedrusbox(i, serial_buff, 6);
175  minor = serial_buff[0];
176  ts5_log(TS5_LOGLEVEL_1,"%s: cedrusbox firmware revision: %c.%c\n",
177  calling_function, major, minor);
178 
179  // reset timers
181  ts5_write_cedrusbox(i, "e1", 2);
182 
183  // if we get here mark it as a cedrusbox
184  _ts5_status.timer.num_cedrusboxes++;
185  }
186 
187  // abort if we could not detect any cedrusboxes
188  if (!_ts5_status.timer.num_cedrusboxes) {
189  ts5_fatal("%s: could not install Tscope5 cedrusboxes\n",
190  calling_function);
191  }
192 
193  // initialize event source
194  al_init_user_event_source(&_ts5_data.timer.cedrusbox_response_event_source);
195 
196  // register event source
197  al_register_event_source(_ts5_data.timer.response_queue,
198  &_ts5_data.timer.cedrusbox_response_event_source);
199 
200  // initialize thread
201  _ts5_data.timer.cedrusbox_thread =
202  al_create_thread(ts5_cedrusbox_threadfunc, NULL);
203 
204  al_start_thread(_ts5_data.timer.cedrusbox_thread);
205  _ts5_data.timer.cedrusbox_thread_is_paused = 0;
206 
207  // assign response codes
208  _ts5_status.timer.cedrusbox =
209  (TS5_CEDRUSBOX_STATUS *)
210  al_malloc(sizeof(TS5_CEDRUSBOX_STATUS)
211  * _ts5_status.timer.num_cedrusboxes);
212 
213  int j=0;
214  for (i=0; i<num_serial_devices; i++) {
215 
216  if (device_type[i]==TS5_CEDRUSBOX_NODEVICE) {
217  continue;
218  }
219 
220  _ts5_status.timer.cedrusbox[j].port_num = i;
221  _ts5_status.timer.cedrusbox[j].type = device_type[i];
222 
223  switch (_ts5_status.timer.cedrusbox[j].type) {
224 
225  case TS5_CEDRUSBOX_LUMINA:
226  _ts5_status.timer.cedrusbox[j].num_buttons = 4;
227  break;
228 
229  case TS5_CEDRUSBOX_SV1:
230  _ts5_status.timer.cedrusbox[j].num_buttons = 1;
231  break;
232 
233  case TS5_CEDRUSBOX_RB530:
234  _ts5_status.timer.cedrusbox[j].num_buttons = 5;
235  break;
236 
237  case TS5_CEDRUSBOX_RB730:
238  _ts5_status.timer.cedrusbox[j].num_buttons = 7;
239  break;
240 
241  case TS5_CEDRUSBOX_RB830:
242  _ts5_status.timer.cedrusbox[j].num_buttons = 8;
243  break;
244 
245  case TS5_CEDRUSBOX_RB834:
246  _ts5_status.timer.cedrusbox[j].num_buttons = 8;
247  break;
248 
249  default:
250  ts5_fatal("%s: unknown cedrus device type\n", calling_function);
251  }
252 
253  _ts5_status.timer.cedrusbox[j].num_defined_buttons = 0;
254  _ts5_status.timer.cedrusbox[j].num_active_buttons = 0;
255 
256  _ts5_status.timer.cedrusbox[j].button_press_defined =
257  (int *)al_malloc(sizeof(int)
258  * _ts5_status.timer.cedrusbox[j].num_buttons);
259 
260  _ts5_status.timer.cedrusbox[j].button_press_active =
261  (int *)al_malloc(sizeof(int)
262  * _ts5_status.timer.cedrusbox[j].num_buttons);
263 
264  _ts5_status.timer.cedrusbox[j].button_release_defined =
265  (int *)al_malloc(sizeof(int)
266  * _ts5_status.timer.cedrusbox[j].num_buttons);
267 
268  _ts5_status.timer.cedrusbox[j].button_release_active =
269  (int *)al_malloc(sizeof(int)
270  * _ts5_status.timer.cedrusbox[j].num_buttons);
271 
272  int k;
273  for (k=0; k<_ts5_status.timer.cedrusbox[j].num_buttons; k++) {
274  _ts5_status.timer.cedrusbox[j].button_press_defined[k] = 0;
275  _ts5_status.timer.cedrusbox[j].button_press_active[k] = 0;
276  _ts5_status.timer.cedrusbox[j].button_release_defined[k] = 0;
277  _ts5_status.timer.cedrusbox[j].button_release_active[k] = 0;
278  }
279  j++;
280  }
281  atexit(ts5_uninstall_cedrusbox);
282 
283  cedrusbox_is_installed:
284  ;
285 
286 }
287 
288 
289 ////////////////////////////////////////////////////////////////////////////////
290 /// Uninstall the cedrusbox subsystem.
291 ///
292 /// This function is called automatically at the end of the program.
293 ////////////////////////////////////////////////////////////////////////////////
295 {
297  goto cedrusbox_is_uninstalled;
298  }
299 
300  ts5_log(TS5_LOGLEVEL_1, "Uninstalling Tscope5 cedrusbox\n");
301 
302  int i;
303 
304  // reset voice keys
305  for (i=0; i<_ts5_status.timer.num_cedrusboxes; i++) {
306 
308 
309  if (_ts5_status.timer.cedrusbox[i].type==TS5_CEDRUSBOX_SV1) {
310 
312  TS5_CEDRUSBOX_LOCKINGLEVEL, TS5_CEDRUSBOX_LOCK);
313 
314  ts5_cedrusbox_set_parameter(i, TS5_CEDRUSBOX_MIN_TRESHOLD, 0);
315  ts5_cedrusbox_set_parameter(i, TS5_CEDRUSBOX_MAX_TRESHOLD, 255);
316  ts5_cedrusbox_set_parameter(i, TS5_CEDRUSBOX_TRESHOLD, 128);
317  ts5_cedrusbox_set_parameter(i, TS5_CEDRUSBOX_MIN_RISE_DELAY, 0);
318  ts5_cedrusbox_set_parameter(i, TS5_CEDRUSBOX_MAX_RISE_DELAY, 100);
319  ts5_cedrusbox_set_parameter(i, TS5_CEDRUSBOX_RISE_DELAY, 0);
320  ts5_cedrusbox_set_parameter(i, TS5_CEDRUSBOX_DROP_DELAY, 0);
321 
323  TS5_CEDRUSBOX_LOCKINGLEVEL, TS5_CEDRUSBOX_UNLOCK);
324 
325  }
326  }
327 
328  // remove thread
329  al_join_thread(_ts5_data.timer.cedrusbox_thread, NULL);
330  al_destroy_thread(_ts5_data.timer.cedrusbox_thread);
331 
332  // unregister event source
333  al_unregister_event_source(_ts5_data.timer.response_queue,
334  &_ts5_data.timer.cedrusbox_response_event_source);
335 
336  // remove event source
337  al_destroy_user_event_source(
338  &_ts5_data.timer.cedrusbox_response_event_source);
339 
340  // close devices
341  #ifdef TS5_WINDOWS
343 
344  #else
346 
347  #endif
348 
349  // remove button definitions
350  for (i=0; i<_ts5_status.timer.num_cedrusboxes; i++) {
351 
352  // free data structure
353  for (i=0; i<_ts5_status.timer.num_cedrusboxes; i++) {
354 
355  al_free(_ts5_status.timer.cedrusbox[i].button_press_defined);
356  _ts5_status.timer.cedrusbox[i].button_press_defined = NULL;
357 
358  al_free(_ts5_status.timer.cedrusbox[i].button_press_active);
359  _ts5_status.timer.cedrusbox[i].button_press_active = NULL;
360 
361  al_free(_ts5_status.timer.cedrusbox[i].button_release_defined);
362  _ts5_status.timer.cedrusbox[i].button_release_defined = NULL;
363 
364  al_free(_ts5_status.timer.cedrusbox[i].button_release_active);
365  _ts5_status.timer.cedrusbox[i].button_release_active = NULL;
366  }
367 
368  al_free(_ts5_status.timer.cedrusbox);
369  _ts5_status.timer.cedrusbox=NULL;
370  _ts5_status.timer.num_cedrusboxes = 0;
371  _ts5_status.timer.cedrusbox_is_response_device = 0;
372 
374  }
375 
376  cedrusbox_is_uninstalled:
377  ;
378 }
379 
380 
381 ////////////////////////////////////////////////////////////////////////////////
382 /// Read text from a cedrusbox.
383 ///
384 /// \param port Port number the cedrusbox is attached to.
385 /// \param buff Character buffer.
386 /// \param bytes_to_read Number of bytes to be written.
387 ///
388 /// \return Length of the string that is sent to the port.
389 ///
390 /// \warning This is an internal function, no checks are performed.
391 ////////////////////////////////////////////////////////////////////////////////
392 unsigned int ts5_read_cedrusbox(int port, char *buff,
393  unsigned long bytes_to_read)
394 {
395  ts5_log(TS5_LOGLEVEL_5, "ts5_read_cedrusbox(%d,%s,%lu)\n",
396  port, buff, bytes_to_read);
397 
398  unsigned int retval;
399 
400  #ifdef TS5_WINDOWS
401  retval = ts5_read_cedrusbox_windows(port, buff, bytes_to_read);
402 
403  #else
404  retval = ts5_read_cedrusbox_posix(port, buff, bytes_to_read);
405 
406  #endif
407 
408  return retval;
409 }
410 
411 
412 ////////////////////////////////////////////////////////////////////////////////
413 /// Write text to a cedrusbox.
414 ///
415 /// \param port Port number the cedrusbox is attached to.
416 /// \param buff Character buffer.
417 /// \param bytes_to_write Number of bytes to be written.
418 ///
419 /// \return Length of the string that is read.
420 ///
421 /// \warning This is an internal function, no checks are performed.
422 ////////////////////////////////////////////////////////////////////////////////
423 unsigned int ts5_write_cedrusbox(int port, char *buff,
424  unsigned long bytes_to_write)
425 {
426  ts5_log(TS5_LOGLEVEL_5, "ts5_write_cedrusbox(%d,%s,%lu)\n",
427  port, buff, bytes_to_write);
428 
429  unsigned int retval;
430 
431  #ifdef TS5_WINDOWS
432  retval = ts5_write_cedrusbox_windows(port, buff, bytes_to_write);
433 
434  #else
435  retval = ts5_write_cedrusbox_posix(port, buff, bytes_to_write);
436 
437  #endif
438 
439  return retval;
440 }
441 
442 
443 ////////////////////////////////////////////////////////////////////////////////
444 /// Flush the output of a cedrusbox.
445 ///
446 /// \param port Port number the cedrusbox is attached to.
447 ///
448 /// \warning This is an internal function, no checks are performed.
449 ////////////////////////////////////////////////////////////////////////////////
450 void ts5_fflush_cedrusbox(int port)
451 {
452  ts5_log(TS5_LOGLEVEL_5, "ts5_fflush_cedrusbox(%d)\n", port);
453 
454  #ifdef TS5_WINDOWS
456 
457  #else
459 
460  #endif
461 }
462 
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 /// Cedrusbox thread function.
466 ///
467 /// \warning This is an internal function, no checks are performed.
468 ////////////////////////////////////////////////////////////////////////////////
470 {
471  ALLEGRO_EVENT cedrusbox_event;
472  double looptime = al_get_time();
473  double now;
474 
475  while (!al_get_thread_should_stop(_ts5_data.timer.cedrusbox_thread)) {
476 
477  now = al_get_time();
478 
479  char serial_buff[6] = {0};
480 
481  int i;
482  for (i=0; i<_ts5_status.timer.num_cedrusboxes; i++) {
483 
484  unsigned int num_bytes =
485  ts5_read_cedrusbox(_ts5_status.timer.cedrusbox[i].port_num,
486  serial_buff, 6);
487 
488  if (num_bytes==6 && serial_buff[0]=='k') {
489 
490  int action = ((unsigned char)(serial_buff[1]) & 16) >> 4;
491 
492  if (action==0) {
493  cedrusbox_event.user.type = TS5_EVENT_CEDRUS_BUTTON_UP;
494  }
495 
496  if (action==1) {
497  cedrusbox_event.user.type = TS5_EVENT_CEDRUS_BUTTON_DOWN;
498  }
499 
500  cedrusbox_event.user.data1 = i;
501 
502  cedrusbox_event.user.data2 =
503  ((unsigned char)serial_buff[1] >> 5) - 1;
504 
505  cedrusbox_event.user.data3 =
506  (intptr_t)((now-looptime)*1000000.0);
507 
508  al_emit_user_event(
509  &_ts5_data.timer.cedrusbox_response_event_source,
510  &cedrusbox_event, NULL);
511  }
512  }
513  looptime = now;
514  }
515 
516  return NULL;
517 }
518