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