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