Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
visca.cpp
1 
2 /***************************************************************************
3  * visca.cpp - Controller for Visca cams
4  *
5  * Created: Wed Jun 08 12:08:17 2005 (FireVision)
6  * Copyright 2005-2009 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include "visca.h"
25 
26 #include <core/exceptions/system.h>
27 
28 #include <sys/ioctl.h>
29 #include <termios.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <cerrno>
33 #include <cstring>
34 #include <cstdlib>
35 
36 /** @class ViscaException "visca.h"
37  * Visca exception.
38  */
39 
40 /** Constructor.
41  * @param msg message of exception.
42  */
44  : Exception(msg)
45 {}
46 
47 
48 /** Constructor with errno.
49  * @param msg message prefix
50  * @param _errno errno for additional error information.
51  */
52 ViscaException::ViscaException(const char *msg, const int _errno)
53  : Exception(_errno, msg)
54 {}
55 
56 /** @class ViscaInquiryRunningException "visca.h"
57  * Visca inquire running exception.
58  */
59 
60 /** Constructor. */
62  : ViscaException("Inquiry already running")
63 {}
64 
65 
66 /** Automatic white balance. */
67 const unsigned int Visca::VISCA_WHITEBLANCE_AUTO = VISCA_WB_AUTO;
68 /** Indoor white balance preset. */
69 const unsigned int Visca::VISCA_WHITEBALANCE_INDOOR = VISCA_WB_INDOOR;
70 /** Outdoor white balance preset. */
71 const unsigned int Visca::VISCA_WHITEBALANCE_OUTDOOR = VISCA_WB_OUTDOOR;
72 /** One push white balance preset. */
73 const unsigned int Visca::VISCA_WHITEBALANCE_ONE_PUSH = VISCA_WB_ONE_PUSH;
74 /** ATW white balance preset. */
75 const unsigned int Visca::VISCA_WHITEBALANCE_ATW = VISCA_WB_ATW;
76 /** Manual white balance. */
77 const unsigned int Visca::VISCA_WHITEBALANCE_MANUAL = VISCA_WB_MANUAL;
78 
79 /** Non-blocking pan/tilt item. */
80 const unsigned int Visca::NONBLOCKING_PANTILT = 0;
81 /** Non-blocking zoom item. */
82 const unsigned int Visca::NONBLOCKING_ZOOM = 1;
83 /** Number of non-blocking items. */
84 const unsigned int Visca::NONBLOCKING_NUM = 2;
85 
86 /** Number of non-blocking items. */
87 const unsigned int Visca::MAX_PAN_SPEED = 0x18;
88 
89 /** Number of non-blocking items. */
90 const unsigned int Visca::MAX_TILT_SPEED = 0x14;
91 
92 
93 /** @class Visca "visca.h"
94  * Visca control protocol implementation over a serial line.
95  * @author Tim Niemueller
96  */
97 
98 
99 /** Constructor.
100  * @param device_file serial device file (e.g. /dev/ttyUSB0)
101  * @param def_timeout_ms default timeout for read operations applied if no explicit
102  * timeout is given.
103  * @param blocking if true, setting the pan/tilt values will only cause sending the
104  * request, you need to call process() when there is time to process and handle
105  * incoming messages.
106  */
107 Visca::Visca(const char *device_file, unsigned int def_timeout_ms, bool blocking)
108 {
109  __inquire = VISCA_RUNINQ_NONE;
110  __device_file = strdup(device_file);
111  __blocking = blocking;
112  __opened = false;
113  __default_timeout_ms = def_timeout_ms;
114  __pan_speed = MAX_PAN_SPEED;
115  __tilt_speed = MAX_TILT_SPEED;
116 
117  for (unsigned int i = 0; i < NONBLOCKING_NUM; ++i) {
118  __nonblocking_sockets[i] = 0;
119  __nonblocking_running[i] = false;
120  }
121 
122  open();
123 
124  set_address();
125  clear();
126 }
127 
128 
129 /** Destructor. */
131 {
132  close();
133  free(__device_file);
134 }
135 
136 
137 /** Open serial port. */
138 void
140 
141  struct termios param;
142 
143  __fd = ::open(__device_file, O_RDWR | O_NONBLOCK);
144  if (! __fd) {
145  throw ViscaException("Cannot open device", errno);
146  }
147 
148  if (tcgetattr(__fd, &param) == -1) {
149  ViscaException ve("Getting the port parameters failed", errno);
150  ::close(__fd);
151  throw ve;
152  }
153 
154  cfsetospeed(&param, B9600);
155  cfsetispeed(&param, B9600);
156 
157  param.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
158  param.c_cflag |= CREAD;
159  param.c_cflag |= CLOCAL;
160  //param.c_cflag |= CRTSCTS;
161 
162  param.c_cc[VMIN] = 1;
163  param.c_cc[VTIME] = 0;
164 
165  param.c_iflag |= IGNBRK;
166  param.c_iflag &= ~PARMRK;
167  param.c_iflag &= ~ISTRIP;
168  param.c_iflag &= ~INLCR;
169  param.c_iflag &= ~IGNCR;
170  param.c_iflag &= ~ICRNL;
171  param.c_iflag &= ~IXON;
172  param.c_iflag &= ~IXOFF;
173 
174  param.c_lflag &= ~ECHO;
175 
176  // hand shake
177  param.c_lflag |= IEXTEN;
178  param.c_oflag &= ~OPOST; //enable raw output
179 
180  //tcflow (__fd, TCOON);
181  //tcflow (__fd, TCION);
182 
183  // number of data bits: 8
184  param.c_cflag &= ~CS5 & ~CS6 & ~CS7 & ~CS8;
185 
186  param.c_cflag |= CS8;
187 
188  // parity: none
189  param.c_cflag &=~(PARENB & PARODD);
190 
191  // stop bits: 1
192  param.c_cflag &= ~CSTOPB;
193 
194  if (tcsetattr(__fd, TCSANOW, &param) != 0) {
195  ViscaException ve("Setting the port parameters failed", errno);
196  ::close(__fd);
197  throw ve;
198  }
199 
200  __opened = true;
201  // Choose first camera by default
202  __sender = VISCA_BUS_0;
203  __recipient = VISCA_BUS_1;
204 
205 #ifdef TIMETRACKER_VISCA
206  __tt = new TimeTracker();
207  __ttc_pantilt_get_send = __tt->addClass("getPanTilt: send");
208  __ttc_pantilt_get_read = __tt->addClass("getPanTilt: read");
209  __ttc_pantilt_get_handle = __tt->addClass("getPanTilt: handling responses");
210  __ttc_pantilt_get_interpret = __tt->addClass("getPanTilt: interpreting");
211 #endif
212 }
213 
214 
215 /** Close port. */
216 void
218 {
219  if (__opened) {
220  __opened = false;
221  ::close(__fd);
222  }
223 }
224 
225 
226 /** Set addresses of cameras. */
227 void
229 {
230  unsigned char recp_backup = __recipient;
231  __recipient = VISCA_BUS_BROADCAST;
232  __obuffer[1] = 0x30;
233  __obuffer[2] = 0x01;
234  __obuffer_length = 2;
235 
236  try {
237  send();
238  recv();
239  } catch (ViscaException &e) {
240  __recipient = recp_backup;
241  throw;
242  }
243 
244  __recipient = recp_backup;
245 }
246 
247 
248 /** Clear command buffers. */
249 void
251 {
252  if (!__opened) throw ViscaException("Serial port not open");
253 
254  __obuffer[1] = 0x01;
255  __obuffer[2] = 0x00;
256  __obuffer[3] = 0x01;
257  __obuffer_length = 3;
258 
259  try {
260  send();
261  recv();
262  } catch (ViscaException &e) {
263  e.append("clear() failed");
264  throw;
265  }
266 }
267 
268 
269 /** Send outbound queue. */
270 void
272 {
273  if (!__opened) throw ViscaException("Serial port not open");
274 
275  // Set first bit to 1
276  __obuffer[0] = 0x80;
277  __obuffer[0] |= (__sender << 4);
278  __obuffer[0] |= __recipient;
279 
280  __obuffer[++__obuffer_length] = VISCA_TERMINATOR;
281  ++__obuffer_length;
282 
283  int written = write(__fd, __obuffer, __obuffer_length);
284  //printf("Visca sent: ");
285  //for (int i = 0; i < __obuffer_length; ++i) {
286  // printf("%02X", __obuffer[i]);
287  //}
288  //printf("\n");
289  if (written < __obuffer_length) {
290  throw ViscaException("Not all bytes send");
291  }
292 }
293 
294 
295 /** Check data availability.
296  * @return true if data is available, false otherwise
297  */
298 bool
300 {
301  int num_bytes = 0;
302  ioctl(__fd, FIONREAD, &num_bytes);
303  return (num_bytes > 0);
304 }
305 
306 
307 /** Receive data.
308  * @param timeout_ms read timeout in miliseconds
309  */
310 void
311 Visca::recv(unsigned int timeout_ms)
312 {
313  if (timeout_ms == 0xFFFFFFFF) timeout_ms = __default_timeout_ms;
314  try {
315  recv_packet(timeout_ms);
316  } catch (ViscaException &e) {
317  e.append("Receiving failed, recv_packet() call failed");
318  throw;
319  }
320 
321  // Get type of message
322  unsigned char type = __ibuffer[1] & 0xF0;
323  while (type == VISCA_RESPONSE_ACK) {
324  try {
325  recv_packet(timeout_ms);
326  } catch (ViscaException &e) {
327  e.append("Receiving failed, recv_packet() call 2 failed");
328  throw;
329  }
330  type = __ibuffer[1] & 0xF0;
331  }
332 
333  switch (type) {
334  case VISCA_RESPONSE_CLEAR:
335  case VISCA_RESPONSE_ADDRESS:
336  case VISCA_RESPONSE_COMPLETED:
337  case VISCA_RESPONSE_ERROR:
338  break;
339  default:
340  throw fawkes::Exception("Receiving failed, unexpected packet type %u received",
341  type);
342  }
343 }
344 
345 
346 /** Receive ACK packet.
347  * @param socket contains the socket that the ACK was received on upon return
348  */
349 void
350 Visca::recv_ack(unsigned int *socket)
351 {
352  try {
353  recv_packet(__default_timeout_ms);
354  } catch (ViscaException &e) {
355  throw ViscaException("recv_ack(): recv_packet() failed");
356  }
357 
358  // Get type of message
359  unsigned char type = __ibuffer[1] & 0xF0;
360  while (type != VISCA_RESPONSE_ACK) {
361 
362  try {
363  handle_response();
364  recv_packet(__default_timeout_ms);
365  } catch (ViscaException &e) {
366  e.append("Handling message of type %u failed", type);
367  throw;
368  }
369  type = __ibuffer[1] & 0xF0;
370  }
371 
372  // Got an ack now
373  if (socket != NULL) {
374  *socket = __ibuffer[1] & 0x0F;
375  }
376 
377 }
378 
379 
380 /** Send non-blocking.
381  * Does a non-blocking send.
382  * @param socket the socket that was used to send the request.
383  */
384 void
385 Visca::send_nonblocking(unsigned int *socket)
386 {
387  try {
388  send();
389  recv_ack(socket);
390  } catch (ViscaException &e) {
391  e.append("Non-blocking send failed!");
392  throw;
393  }
394 }
395 
396 
397 /** Finish a non-blocking operation.
398  * @param socket socket that the non-blocking operation was sent to
399  */
400 void
401 Visca::finish_nonblocking( unsigned int socket )
402 {
403  for (unsigned int i = 0; i < NONBLOCKING_NUM; ++i) {
404  if (__nonblocking_sockets[i] == socket) {
405  __nonblocking_sockets[i] = 0;
406  __nonblocking_running[i] = false;
407  return;
408  }
409  }
410 
411  throw ViscaException("finish_nonblocking() failed: socket not found");
412 }
413 
414 
415 /** Check if a non-blocking operation has been finished.
416  * @param item the non-blocking item to check
417  * @return true if the non-blocking operation has been finished, false otherwise
418  */
419 bool
420 Visca::is_nonblocking_finished(unsigned int item) const
421 {
422  if (item >= NONBLOCKING_NUM) {
423  throw ViscaException("Invalid item number");
424  }
425  return ! __nonblocking_running[item];
426 }
427 
428 
429 /** Send and wait for reply, blocking.
430  */
431 void
433 {
434  try {
435  send();
436  recv();
437  } catch (ViscaException &e) {
438  e.append("Sending with reply failed");
439  throw;
440  }
441 }
442 
443 
444 /** Receive a packet.
445  * @param timeout_ms read timeout in miliseconds
446  */
447 void
448 Visca::recv_packet(unsigned int timeout_ms)
449 {
450  // wait for message
451  timeval timeout = {0, timeout_ms * 1000};
452 
453  fd_set read_fds;
454  FD_ZERO(&read_fds);
455  FD_SET(__fd, &read_fds);
456 
457  int rv = 0;
458  rv = select(__fd + 1, &read_fds, NULL, NULL, &timeout);
459 
460  if ( rv == -1 ) {
461  throw fawkes::Exception(errno, "Select on FD failed");
462  } else if ( rv == 0 ) {
463  throw fawkes::TimeoutException("Timeout reached while waiting for incoming data");
464  }
465 
466  // get octets one by one
467  if (read(__fd, __ibuffer, 1) != 1) {
468  throw fawkes::Exception(errno, "Visca reading packet byte failed");
469  }
470 
471  int pos = 0;
472  while (__ibuffer[pos] != VISCA_TERMINATOR) {
473  if (read(__fd, &__ibuffer[++pos], 1) != 1) {
474  throw fawkes::Exception(errno, "Visca reading packet byte failed");
475  }
476  usleep(0);
477  }
478  __ibuffer_length = pos + 1;
479  //printf("Visca read: ");
480  //for (int i = 0; i < __ibuffer_length; ++i) {
481  // printf("%02X", __ibuffer[i]);
482  //}
483  //printf("\n");
484 }
485 
486 
487 
488 /** Handle incoming response. */
489 void
490 Visca::handle_response()
491 {
492  unsigned int type = __ibuffer[1] & 0xF0;
493  unsigned int socket = __ibuffer[1] & 0x0F;
494 
495  if (socket == 0) {
496  // This is an inquire response, do NOT handle!
497  //throw ViscaException("handle_response(): Received an inquire response, can't handle");
498  return;
499  }
500 
501  if ( type == VISCA_RESPONSE_COMPLETED ) {
502  // Command has been finished
503  try {
504  finish_nonblocking( __ibuffer[1] & 0x0F );
505  } catch (ViscaException &e) {
506  // Ignore, happens sometimes without effect
507  // e.append("handle_response() failed, could not finish non-blocking");
508  // throw;
509  }
510  } else if ( type == VISCA_RESPONSE_ERROR ) {
511  finish_nonblocking( __ibuffer[1] & 0x0F );
512  //throw ViscaException("handle_response(): got an error message from camera");
513  } else {
514  // ignore
515  //ViscaException ve("Got unknown/unhandled response type");
516  //ve.append("Received message of type %u", type);
517  //throw ve;
518  }
519 
520 }
521 
522 
523 /** Cancel a running command.
524  * @param socket socket that the command was send on
525  */
526 void
527 Visca::cancel_command( unsigned int socket )
528 {
529  unsigned char cancel_socket = socket & 0x0000000F;
530 
531  __obuffer[1] = VISCA_CANCEL | cancel_socket;
532  __obuffer_length = 1;
533 
534  try {
535  send_with_reply();
536  } catch (ViscaException &e) {
537  e.append("cancel_command() failed");
538  throw;
539  }
540 
541  if ( ((__ibuffer[1] & 0xF0) == VISCA_RESPONSE_ERROR) &&
542  ((__ibuffer[1] & 0x0F) == cancel_socket) &&
543  ((__ibuffer[2] == VISCA_ERROR_CANCELLED)) ) {
544  return;
545  } else {
546  throw ViscaException("Command could not be cancelled");
547  }
548 }
549 
550 
551 /** Process incoming data. */
552 void
554 {
555 
556  __inquire = VISCA_RUNINQ_NONE;
557 
558  while (data_available()) {
559  try {
560  recv();
561  handle_response();
562  } catch (ViscaException &e) {
563  // Ignore this error
564  return;
565  }
566  }
567 }
568 
569 
570 /** Set pan tilt.
571  * @param pan pan
572  * @param tilt tilt
573  */
574 void
575 Visca::set_pan_tilt(int pan, int tilt)
576 {
577 
578  // we do not to check for blocking, could not be called at
579  // the same time if blocking...
580  /*
581  if ( __nonblocking_running[ NONBLOCKING_PANTILT] ) {
582  cout << "Cancelling old setPanTilt" << endl;
583  if (cancel_command( __nonblocking_sockets[ NONBLOCKING_PANTILT ] ) != VISCA_SUCCESS) {
584  cout << "Visca: Could not cancel old non-blocking pan/tilt command. Not setting new pan/tilt." << endl;
585  return VISCA_E_CANCEL;
586  }
587  __nonblocking_running[ NONBLOCKING_PANTILT ] = false;
588  }
589  */
590 
591  unsigned short int tilt_val = 0 + tilt;
592  unsigned short int pan_val = 0 + pan;
593 
594  __obuffer[1] = VISCA_COMMAND;
595  __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
596  __obuffer[3] = VISCA_PT_ABSOLUTE_POSITION;
597  __obuffer[4] = __pan_speed;
598  __obuffer[5] = __tilt_speed;
599 
600  // pan
601  __obuffer[6] = (pan_val & 0xf000) >> 12;
602  __obuffer[7] = (pan_val & 0x0f00) >> 8;
603  __obuffer[8] = (pan_val & 0x00f0) >> 4;
604  __obuffer[9] = (pan_val & 0x000f);
605  // tilt
606  __obuffer[10] = (tilt_val & 0xf000) >> 12;
607  __obuffer[11] = (tilt_val & 0x0f00) >> 8;
608  __obuffer[12] = (tilt_val & 0x00f0) >> 4;
609  __obuffer[13] = (tilt_val & 0x000f);
610 
611  __obuffer_length = 13;
612 
613  try {
614  if (! __blocking) {
615  __nonblocking_running[ NONBLOCKING_PANTILT ] = true;
616  send_nonblocking( &(__nonblocking_sockets[ NONBLOCKING_PANTILT ]) );
617  } else {
618  send_with_reply();
619  }
620  } catch (ViscaException &e) {
621  e.append("setPanTilt() failed");
622  throw;
623  }
624 }
625 
626 
627 /** Set pan/tilt speed.
628  * @param pan_speed a value between 0 and MAX_PAN_SPEED
629  * @param tilt_speed a value between 0 and MAX_TILT_SPEED
630  * @exception Exception thrown if desired pan or tilt speed is too high
631  */
632 void
633 Visca::set_pan_tilt_speed(unsigned char pan_speed, unsigned char tilt_speed)
634 {
635  if (pan_speed > MAX_PAN_SPEED) {
636  throw fawkes::Exception("Pan speed too hight, max: %u des: %u", MAX_PAN_SPEED, pan_speed);
637  }
638  if (tilt_speed > MAX_TILT_SPEED) {
639  throw fawkes::Exception("Tilt speed too hight, max: %u des: %u", MAX_TILT_SPEED, tilt_speed);
640  }
641 
642  __pan_speed = pan_speed;
643  __tilt_speed = tilt_speed;
644 }
645 
646 
647 /** Get pan/tilt speed.
648  * @param pan_speed upon return contains pan speed index
649  * @param tilt_speed upon return contains tilt speed index
650  */
651 void
652 Visca::get_pan_tilt_speed(unsigned char &pan_speed, unsigned char &tilt_speed)
653 {
654  pan_speed = __pan_speed;
655  tilt_speed = __tilt_speed;
656 }
657 
658 /** Initiate a pan/tilt request, but do not wait for the reply. */
659 void
661 {
662 
663  if ( __inquire ) throw ViscaInquiryRunningException();
664 
665  __inquire = VISCA_RUNINQ_PANTILT;
666 
667  __obuffer[1] = VISCA_INQUIRY;
668  __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
669  __obuffer[3] = VISCA_PT_POSITION_INQ;
670  __obuffer_length = 3;
671 
672  try {
673  send();
674  } catch (ViscaException &e) {
675  e.append("startGetPanTilt() failed");
676  throw;
677  }
678 }
679 
680 
681 /** Get pan and tilt values.
682  * If you used startGetPanTilt() to initiate the query the result is
683  * received and returned, otherwise a request is sent and the method blocks
684  * until the answer has been received.
685  * @param pan contains pan upon return
686  * @param tilt contains tilt upon return
687  */
688 void
689 Visca::get_pan_tilt(int &pan, int &tilt)
690 {
691 
692  if ( __inquire ) {
693  if ( __inquire != VISCA_RUNINQ_PANTILT ) {
694  throw ViscaException("Inquiry running, but it is not a pan/tilt inquiry");
695  } else {
696 #ifdef TIMETRACKER_VISCA
697  __tt->ping_start( __ttc_pantilt_get_read );
698 #endif
699  try {
700  recv();
701  } catch (ViscaException &e) {
702  // Ignore
703  }
704 #ifdef TIMETRACKER_VISCA
705  __tt->ping_end( __ttc_pantilt_get_read );
706 #endif
707  }
708  } else {
709 
710  __obuffer[1] = VISCA_INQUIRY;
711  __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
712  __obuffer[3] = VISCA_PT_POSITION_INQ;
713  __obuffer_length = 3;
714 
715  try {
716 #ifdef TIMETRACKER_VISCA
717  __tt->ping_start( __ttc_pantilt_get_send );
718  send();
719  __tt->ping_end( __ttc_pantilt_get_send );
720  __tt->ping_start( __ttc_pantilt_get_read );
721  recv();
722  __tt->ping_end( __ttc_pantilt_get_read );
723 #else
724  send_with_reply();
725 #endif
726  } catch (ViscaException &e) {
727  // Ignore
728  }
729  }
730 
731 #ifdef TIMETRACKER_VISCA
732  __tt->ping_start( __ttc_pantilt_get_handle );
733 #endif
734 
735  while (__ibuffer[1] != VISCA_RESPONSE_COMPLETED) {
736  // inquire return from socket 0, so this may occur if there
737  // are other responses waiting, handle them...
738  try {
739  handle_response();
740  recv();
741  } catch (ViscaException &e) {
742  // Ignore
743  }
744  }
745 
746 #ifdef TIMETRACKER_VISCA
747  __tt->ping_end( __ttc_pantilt_get_handle );
748  __tt->ping_start( __ttc_pantilt_get_interpret );
749 #endif
750 
751 
752  // Extract information from __ibuffer
753  if ( __ibuffer[1] == VISCA_RESPONSE_COMPLETED ) {
754  unsigned short int pan_val = 0;
755  unsigned short int tilt_val = 0;
756 
757  pan_val |= (__ibuffer[2] & 0x0F) << 12;
758  pan_val |= (__ibuffer[3] & 0x0F) << 8;
759  pan_val |= (__ibuffer[4] & 0x0F) << 4;
760  pan_val |= (__ibuffer[5] & 0x0F);
761 
762  tilt_val |= (__ibuffer[6] & 0x0F) << 12;
763  tilt_val |= (__ibuffer[7] & 0x0F) << 8;
764  tilt_val |= (__ibuffer[8] & 0x0F) << 4;
765  tilt_val |= (__ibuffer[9] & 0x0F);
766 
767  if (pan_val < 0x8000) {
768  // The value must be positive
769  pan = pan_val;
770  } else {
771  // negative value
772  pan = pan_val - 0xFFFF;
773  }
774 
775  if (tilt_val < 0x8000) {
776  // The value must be positive
777  tilt = tilt_val;
778  } else {
779  // negative value
780  tilt = tilt_val - 0xFFFF;
781  }
782 
783  } else {
784  throw ViscaException("getPanTilt(): Wrong response received");
785  }
786 #ifdef TIMETRACKER_VISCA
787  __tt->ping_end( __ttc_pantilt_get_interpret );
788  __tt->print_to_stdout();
789 #endif
790 
791  __inquire = VISCA_RUNINQ_NONE;
792 }
793 
794 
795 /** Reset pan/tilt limit. */
796 void
798 {
799  __obuffer[1] = VISCA_COMMAND;
800  __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
801  __obuffer[3] = VISCA_PT_LIMITSET;
802  __obuffer[3] = VISCA_PT_LIMITSET_CLEAR;
803  __obuffer[4] = VISCA_PT_LIMITSET_SET_UR;
804  __obuffer[5] = 0x07;
805  __obuffer[6] = 0x0F;
806  __obuffer[7] = 0x0F;
807  __obuffer[8] = 0x0F;
808  __obuffer[9] = 0x07;
809  __obuffer[10] = 0x0F;
810  __obuffer[11] = 0x0F;
811  __obuffer[12] = 0x0F;
812  __obuffer_length = 12;
813 
814  try {
815  send_with_reply();
816 
817  __obuffer[4] = VISCA_PT_LIMITSET_SET_DL;
818 
819  send_with_reply();
820  } catch (ViscaException &e) {
821  e.append("resetPanTiltLimit() failed");
822  throw;
823  }
824 }
825 
826 
827 /** Set pan tilt limit.
828  * @param pan_left most left pan value
829  * @param pan_right most right pan value
830  * @param tilt_up most up tilt value
831  * @param tilt_down most down tilt value
832  */
833 void
834 Visca::set_pan_tilt_limit(int pan_left, int pan_right, int tilt_up, int tilt_down)
835 {
836  try {
837  __obuffer[1] = VISCA_COMMAND;
838  __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
839  __obuffer[3] = VISCA_PT_LIMITSET;
840  __obuffer[3] = VISCA_PT_LIMITSET_SET;
841  __obuffer[4] = VISCA_PT_LIMITSET_SET_UR;
842  // pan
843  __obuffer[5] = (pan_right & 0xf000) >> 12;
844  __obuffer[6] = (pan_right & 0x0f00) >> 8;
845  __obuffer[7] = (pan_right & 0x00f0) >> 4;
846  __obuffer[8] = (pan_right & 0x000f);
847  // tilt
848  __obuffer[9] = (tilt_up & 0xf000) >> 12;
849  __obuffer[10] = (tilt_up & 0x0f00) >> 8;
850  __obuffer[11] = (tilt_up & 0x00f0) >> 4;
851  __obuffer[12] = (tilt_up & 0x000f);
852 
853  __obuffer_length = 12;
854 
855  send_with_reply();
856 
857  __obuffer[4] = VISCA_PT_LIMITSET_SET_DL;
858  // pan
859  __obuffer[5] = (pan_left & 0xf000) >> 12;
860  __obuffer[6] = (pan_left & 0x0f00) >> 8;
861  __obuffer[7] = (pan_left & 0x00f0) >> 4;
862  __obuffer[8] = (pan_left & 0x000f);
863  // tilt
864  __obuffer[9] = (tilt_down & 0xf000) >> 12;
865  __obuffer[10] = (tilt_down & 0x0f00) >> 8;
866  __obuffer[11] = (tilt_down & 0x00f0) >> 4;
867  __obuffer[12] = (tilt_down & 0x000f);
868 
869  send_with_reply();
870  } catch (ViscaException &e) {
871  e.append("setPanTiltLimit() failed");
872  throw;
873  }
874 }
875 
876 
877 /** Reset pan/tilt. */
878 void
880 {
881  __obuffer[1] = VISCA_COMMAND;
882  __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
883  __obuffer[3] = VISCA_PT_HOME;
884  __obuffer_length = 3;
885 
886  try {
887  send_with_reply();
888  } catch (ViscaException &e) {
889  e.append("resetPanTilt() failed");
890  throw;
891  }
892 }
893 
894 
895 /** Reset zoom. */
896 void
898 {
899  __obuffer[1] = VISCA_COMMAND;
900  __obuffer[2] = VISCA_CATEGORY_CAMERA1;
901  __obuffer[3] = VISCA_ZOOM;
902  __obuffer[4] = VISCA_ZOOM_STOP;
903  __obuffer_length = 4;
904 
905  try {
906  send_with_reply();
907  } catch (ViscaException &e) {
908  e.append("resetZoom() failed");
909  throw;
910  }
911 }
912 
913 
914 /** Set zoom speed in tele.
915  * @param speed speed
916  */
917 void
918 Visca::set_zoom_speed_tele(unsigned int speed)
919 {
920  __obuffer[1] = VISCA_COMMAND;
921  __obuffer[2] = VISCA_CATEGORY_CAMERA1;
922  __obuffer[3] = VISCA_ZOOM;
923  __obuffer[4] = VISCA_ZOOM_TELE_SPEED;
924  // zoom speed
925  __obuffer[5] = (speed & 0x000f) | 0x0020;
926  __obuffer_length = 5;
927 
928  try {
929  send_with_reply();
930  } catch (ViscaException &e) {
931  e.append("setZoomSpeedTele() failed");
932  throw;
933  }
934 }
935 
936 
937 /** Set zoom speed in wide angle.
938  * @param speed speed
939  */
940 void
941 Visca::set_zoom_speed_wide(unsigned int speed)
942 {
943  __obuffer[1] = VISCA_COMMAND;
944  __obuffer[2] = VISCA_CATEGORY_CAMERA1;
945  __obuffer[3] = VISCA_ZOOM;
946  __obuffer[4] = VISCA_ZOOM_WIDE_SPEED;
947  // zoom speed
948  __obuffer[5] = (speed & 0x000f) | 0x0020;
949  __obuffer_length = 5;
950 
951  try {
952  send_with_reply();
953  } catch (ViscaException &e) {
954  e.append("setZoomSpeedWide() failed");
955  throw;
956  }
957 }
958 
959 
960 /** Set zoom.
961  * @param zoom zoom value
962  */
963 void
964 Visca::set_zoom(unsigned int zoom)
965 {
966  __obuffer[1] = VISCA_COMMAND;
967  __obuffer[2] = VISCA_CATEGORY_CAMERA1;
968  __obuffer[3] = VISCA_ZOOM_VALUE;
969  // zoom
970  __obuffer[4] = (zoom & 0xf000) >> 12;
971  __obuffer[5] = (zoom & 0x0f00) >> 8;
972  __obuffer[6] = (zoom & 0x00f0) >> 4;
973  __obuffer[7] = (zoom & 0x000f);
974 
975  __obuffer_length = 7;
976 
977  try {
978  send_with_reply();
979  } catch (ViscaException &e) {
980  e.append("setZoom() failed");
981  throw;
982  }
983 }
984 
985 
986 /** Get zoom.
987  * @param zoom contains zoom upon return.
988  */
989 void
990 Visca::get_zoom(unsigned int *zoom)
991 {
992  __obuffer[1] = VISCA_INQUIRY;
993  __obuffer[2] = VISCA_CATEGORY_CAMERA1;
994  __obuffer[3] = VISCA_ZOOM_VALUE;
995  __obuffer_length = 3;
996 
997  try {
998  send_with_reply();
999  } catch (ViscaException &e) {
1000  e.append("getZoom() failed");
1001  throw;
1002  }
1003 
1004  // Extract information from __ibuffer
1005  if ( __ibuffer[1] == VISCA_RESPONSE_COMPLETED ) {
1006  unsigned short int zoom_val = 0;
1007 
1008  zoom_val |= (__ibuffer[2] & 0x0F) << 12;
1009  zoom_val |= (__ibuffer[3] & 0x0F) << 8;
1010  zoom_val |= (__ibuffer[4] & 0x0F) << 4;
1011  zoom_val |= (__ibuffer[5] & 0x0F);
1012 
1013  *zoom = zoom_val;
1014  } else {
1015  throw ViscaException("getZoom(): zoom inquiry failed, response code not VISCA_RESPONSE_COMPLETED");
1016  }
1017 
1018 }
1019 
1020 
1021 /** Enable or disable digital zoome.
1022  * @param enabled true to enable digital zoom, false to disable
1023  */
1024 void
1026 {
1027  __obuffer[1] = VISCA_COMMAND;
1028  __obuffer[2] = VISCA_CATEGORY_CAMERA1;
1029  __obuffer[3] = VISCA_DZOOM;
1030  if (enabled) {
1031  __obuffer[4] = VISCA_DZOOM_ON;
1032  } else {
1033  __obuffer[4] = VISCA_DZOOM_OFF;
1034  }
1035  __obuffer_length = 4;
1036 
1037  try {
1038  send_with_reply();
1039  } catch (ViscaException &e) {
1040  e.append("setZoomDigitalEnabled() failed");
1041  throw;
1042  }
1043 }
1044 
1045 
1046 /** Apply effect.
1047  * @param filter filter
1048  */
1049 void
1050 Visca::apply_effect(unsigned char filter)
1051 {
1052  __obuffer[1] = VISCA_COMMAND;
1053  __obuffer[2] = VISCA_CATEGORY_CAMERA1;
1054  __obuffer[3] = VISCA_PICTURE_EFFECT;
1055  __obuffer[4] = filter;
1056  __obuffer_length = 4;
1057 
1058  try {
1059  send_with_reply();
1060  } catch (ViscaException &e) {
1061  e.append("applyEffect() failed");
1062  throw;
1063  }
1064 }
1065 
1066 
1067 /** Reset effects. */
1068 void
1070 {
1071  try {
1072  apply_effect(VISCA_PICTURE_EFFECT_OFF);
1073  } catch (ViscaException &e) {
1074  e.append("resetEffect() failed");
1075  throw;
1076  }
1077 }
1078 
1079 
1080 /** Apply pastel effect. */
1081 void
1083 {
1084  try {
1085  apply_effect(VISCA_PICTURE_EFFECT_PASTEL);
1086  } catch (ViscaException &e) {
1087  e.append("applyEffectPastel() failed");
1088  throw;
1089  }
1090 }
1091 
1092 
1093 /** Apply negative art effect. */
1094 void
1096 {
1097  try {
1098  apply_effect(VISCA_PICTURE_EFFECT_NEGATIVE);
1099  } catch (ViscaException &e) {
1100  e.append("applyEffectNegArt() failed");
1101  throw;
1102  }
1103 }
1104 
1105 
1106 /** Apply sepia effect. */
1107 void
1109 {
1110  try {
1111  apply_effect(VISCA_PICTURE_EFFECT_SEPIA);
1112  } catch (ViscaException &e) {
1113  e.append("applyEffectSepia() failed");
1114  throw;
1115  }
1116 }
1117 
1118 
1119 /**Apply B/W effect */
1120 void
1122 {
1123  try {
1124  apply_effect(VISCA_PICTURE_EFFECT_BW);
1125  } catch (ViscaException &e) {
1126  e.append("applyEffectBnW() failed");
1127  throw;
1128  }
1129 }
1130 
1131 
1132 /** Apply solarize effect. */
1133 void
1135 {
1136  try {
1137  apply_effect(VISCA_PICTURE_EFFECT_SOLARIZE);
1138  } catch (ViscaException &e) {
1139  e.append("applyEffectSolarize() failed");
1140  throw;
1141  }
1142 }
1143 
1144 
1145 /** Apply mosaic effect. */
1146 void
1148 {
1149  try {
1150  apply_effect(VISCA_PICTURE_EFFECT_MOSAIC);
1151  } catch (ViscaException &e) {
1152  e.append("applyEffectMosaic() failed");
1153  throw;
1154  }
1155 }
1156 
1157 
1158 /** Apply slim effect. */
1159 void
1161 {
1162  try {
1163  apply_effect(VISCA_PICTURE_EFFECT_SLIM);
1164  } catch (ViscaException &e) {
1165  e.append("applyEffectSlim() failed");
1166  throw;
1167  }
1168 }
1169 
1170 
1171 /** Apply stretch effect. */
1172 void
1174 {
1175  try {
1176  apply_effect(VISCA_PICTURE_EFFECT_STRETCH);
1177  } catch (ViscaException &e) {
1178  e.append("applyEffectStretch() failed");
1179  throw;
1180  }
1181 }
1182 
1183 
1184 /** Get white balance mode.
1185  * @return white balance mode
1186  */
1187 unsigned int
1189 {
1190  __obuffer[1] = VISCA_INQUIRY;
1191  __obuffer[2] = VISCA_CATEGORY_CAMERA1;
1192  __obuffer[3] = VISCA_WB;
1193  __obuffer_length = 3;
1194 
1195  try {
1196  send_with_reply();
1197  } catch (ViscaException &e) {
1198  e.append("getWhiteBalanceMode() failed");
1199  throw;
1200  }
1201 
1202  while (__ibuffer[1] != VISCA_RESPONSE_COMPLETED) {
1203  // inquire return from socket 0, so this may occur if there
1204  // are other responses waiting, handle them...
1205  try {
1206  handle_response();
1207  recv();
1208  } catch (ViscaException &e) {
1209  e.append("getWhiteBalanceMode() failed");
1210  throw;
1211  }
1212  }
1213 
1214  // Extract information from __ibuffer
1215  if ( __ibuffer[1] == VISCA_RESPONSE_COMPLETED ) {
1216  return __ibuffer[2];
1217  } else {
1218  throw ViscaException("Did not get 'request completed' response");
1219  }
1220 
1221 }
1222 
void apply_effect_slim()
Apply slim effect.
Definition: visca.cpp:1160
void apply_effect_mosaic()
Apply mosaic effect.
Definition: visca.cpp:1147
static const unsigned int VISCA_WHITEBALANCE_ATW
ATW white balance preset.
Definition: visca.h:58
bool is_nonblocking_finished(unsigned int item) const
Check if a non-blocking operation has been finished.
Definition: visca.cpp:420
void set_pan_tilt_limit(int pan_left, int pan_right, int tilt_up, int tilt_down)
Set pan tilt limit.
Definition: visca.cpp:834
static const unsigned int NONBLOCKING_PANTILT
Non-blocking pan/tilt item.
Definition: visca.h:61
void set_pan_tilt(int pan, int tilt)
Set pan tilt.
Definition: visca.cpp:575
void cancel_command(unsigned int socket)
Cancel a running command.
Definition: visca.cpp:527
void apply_effect_solarize()
Apply solarize effect.
Definition: visca.cpp:1134
void set_address()
Set addresses of cameras.
Definition: visca.cpp:228
static const unsigned int MAX_TILT_SPEED
Number of non-blocking items.
Definition: visca.h:66
void start_get_pan_tilt()
Query for pan/tilt but do not wait until finished This will send an inquire to the camera that asks f...
Definition: visca.cpp:660
static const unsigned int VISCA_WHITEBALANCE_MANUAL
Manual white balance.
Definition: visca.h:59
void apply_effect_pastel()
Apply pastel effect.
Definition: visca.cpp:1082
void clear()
Clear command buffers.
Definition: visca.cpp:250
void set_pan_tilt_speed(unsigned char pan_speed, unsigned char tilt_speed)
Set pan/tilt speed.
Definition: visca.cpp:633
The current system call has timed out before completion.
Definition: system.h:46
static const unsigned int NONBLOCKING_ZOOM
Non-blocking zoom item.
Definition: visca.h:62
void set_zoom_speed_wide(unsigned int speed)
Set zoom speed in wide angle.
Definition: visca.cpp:941
Visca inquire running exception.
Definition: visca.h:44
void set_zoom_speed_tele(unsigned int speed)
Set zoom speed in tele.
Definition: visca.cpp:918
void reset_effect()
Reset effects.
Definition: visca.cpp:1069
void send_with_reply()
Send and wait for reply, blocking.
Definition: visca.cpp:432
static const unsigned int VISCA_WHITEBALANCE_INDOOR
Indoor white balance preset.
Definition: visca.h:55
virtual ~Visca()
Destructor.
Definition: visca.cpp:130
static const unsigned int NONBLOCKING_NUM
Number of non-blocking items.
Definition: visca.h:63
void reset_pan_tilt_limit()
Reset pan/tilt limit.
Definition: visca.cpp:797
ViscaInquiryRunningException()
Constructor.
Definition: visca.cpp:61
static const unsigned int VISCA_WHITEBALANCE_OUTDOOR
Outdoor white balance preset.
Definition: visca.h:56
void recv_ack(unsigned int *socket=NULL)
Receive ACK packet.
Definition: visca.cpp:350
void open()
Open serial port.
Definition: visca.cpp:139
void reset_zoom()
Reset zoom.
Definition: visca.cpp:897
Base class for exceptions in Fawkes.
Definition: exception.h:36
void set_zoom_digital_enabled(bool enabled)
Enable or disable digital zoome.
Definition: visca.cpp:1025
void apply_effect_stretch()
Apply stretch effect.
Definition: visca.cpp:1173
void get_pan_tilt(int &pan, int &tilt)
Get pan and tilt values.
Definition: visca.cpp:689
void apply_effect(unsigned char effect)
Apply effect.
Definition: visca.cpp:1050
static const unsigned int VISCA_WHITEBLANCE_AUTO
Automatic white balance.
Definition: visca.h:54
Visca exception.
Definition: visca.h:37
void reset_pan_tilt()
Reset pan/tilt.
Definition: visca.cpp:879
bool data_available()
Check data availability.
Definition: visca.cpp:299
static const unsigned int MAX_PAN_SPEED
Number of non-blocking items.
Definition: visca.h:65
void apply_effect_neg_art()
Apply negative art effect.
Definition: visca.cpp:1095
void apply_effect_sepia()
Apply sepia effect.
Definition: visca.cpp:1108
void get_zoom(unsigned int *zoom)
Get zoom.
Definition: visca.cpp:990
void recv(unsigned int timeout_ms=0xFFFFFFFF)
Receive data.
Definition: visca.cpp:311
void close()
Close port.
Definition: visca.cpp:217
unsigned int get_white_balance_mode()
Get white balance mode.
Definition: visca.cpp:1188
ViscaException(const char *msg)
Constructor.
Definition: visca.cpp:43
void get_pan_tilt_speed(unsigned char &pan_speed, unsigned char &tilt_speed)
Get pan/tilt speed.
Definition: visca.cpp:652
void set_zoom(unsigned int zoom)
Set zoom.
Definition: visca.cpp:964
void apply_effect_bnw()
Apply B/W effect.
Definition: visca.cpp:1121
Visca(const char *device_file, unsigned int def_timeout_ms=10, bool blocking=true)
Constructor.
Definition: visca.cpp:107
void send()
Send outbound queue.
Definition: visca.cpp:271
static const unsigned int VISCA_WHITEBALANCE_ONE_PUSH
One push white balance preset.
Definition: visca.h:57
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:341
void send_nonblocking(unsigned int *socket=NULL)
Send non-blocking.
Definition: visca.cpp:385
void process()
Process incoming data.
Definition: visca.cpp:553