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