Fawkes API  Fawkes Development Version
visca.cpp
00001 
00002 /***************************************************************************
00003  *  visca.cpp - Controller for Visca cams
00004  *
00005  *  Created: Wed Jun 08 12:08:17 2005 (FireVision)
00006  *  Copyright  2005-2009  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include "visca.h"
00025 
00026 #include <core/exceptions/system.h>
00027 
00028 #include <sys/ioctl.h>
00029 #include <termios.h>
00030 #include <fcntl.h>
00031 #include <unistd.h>
00032 #include <cerrno>
00033 #include <cstring>
00034 #include <cstdlib>
00035 
00036 /** @class ViscaException "visca.h"
00037  * Visca exception.
00038  */
00039 
00040 /** Constructor.
00041  * @param msg message of exception.
00042  */
00043 ViscaException::ViscaException(const char *msg)
00044   : Exception(msg)
00045 {}
00046 
00047 
00048 /** Constructor with errno.
00049  * @param msg message prefix
00050  * @param _errno errno for additional error information.
00051  */
00052 ViscaException::ViscaException(const char *msg, const int _errno)
00053   : Exception(_errno, msg)
00054 {}
00055 
00056 /** @class ViscaInquiryRunningException "visca.h"
00057  * Visca inquire running exception.
00058  */
00059 
00060 /** Constructor. */
00061 ViscaInquiryRunningException::ViscaInquiryRunningException()
00062   : ViscaException("Inquiry already running")
00063 {}
00064 
00065 
00066 /** Automatic white balance. */
00067 const unsigned int Visca::VISCA_WHITEBLANCE_AUTO      = VISCA_WB_AUTO;
00068 /** Indoor white balance preset. */
00069 const unsigned int Visca::VISCA_WHITEBALANCE_INDOOR   = VISCA_WB_INDOOR;
00070 /** Outdoor white balance preset. */
00071 const unsigned int Visca::VISCA_WHITEBALANCE_OUTDOOR  = VISCA_WB_OUTDOOR;
00072 /** One push white balance preset. */
00073 const unsigned int Visca::VISCA_WHITEBALANCE_ONE_PUSH = VISCA_WB_ONE_PUSH;
00074 /** ATW white balance preset. */
00075 const unsigned int Visca::VISCA_WHITEBALANCE_ATW      = VISCA_WB_ATW;
00076 /** Manual white balance. */
00077 const unsigned int Visca::VISCA_WHITEBALANCE_MANUAL   = VISCA_WB_MANUAL;
00078 
00079 /** Non-blocking pan/tilt item. */
00080 const unsigned int Visca::NONBLOCKING_PANTILT   = 0;
00081 /** Non-blocking zoom item. */
00082 const unsigned int Visca::NONBLOCKING_ZOOM      = 1;
00083 /** Number of non-blocking items. */
00084 const unsigned int Visca::NONBLOCKING_NUM       = 2;
00085 
00086 /** Number of non-blocking items. */
00087 const unsigned int Visca::MAX_PAN_SPEED         = 0x18;
00088 
00089 /** Number of non-blocking items. */
00090 const unsigned int Visca::MAX_TILT_SPEED        = 0x14;
00091 
00092 
00093 /** @class Visca "visca.h"
00094  * Visca control protocol implementation over a serial line.
00095  * @author Tim Niemueller
00096  */
00097 
00098 
00099 /** Constructor.
00100  * @param device_file serial device file (e.g. /dev/ttyUSB0)
00101  * @param def_timeout_ms default timeout for read operations applied if no explicit
00102  * timeout is given.
00103  * @param blocking if true, setting the pan/tilt values will only cause sending the
00104  * request, you need to call process() when there is time to process and handle
00105  * incoming messages.
00106  */
00107 Visca::Visca(const char *device_file, unsigned int def_timeout_ms, bool blocking)
00108 {
00109   __inquire            = VISCA_RUNINQ_NONE;
00110   __device_file        = strdup(device_file);
00111   __blocking           = blocking;
00112   __opened             = false;
00113   __default_timeout_ms = def_timeout_ms;
00114   __pan_speed          = MAX_PAN_SPEED;
00115   __tilt_speed         = MAX_TILT_SPEED;
00116 
00117   for (unsigned int i = 0; i < NONBLOCKING_NUM; ++i) {
00118     __nonblocking_sockets[i] = 0;
00119     __nonblocking_running[i] = false;
00120   }
00121 
00122   open();
00123 
00124   set_address();
00125   clear();
00126 }
00127 
00128 
00129 /** Destructor. */
00130 Visca::~Visca()
00131 {
00132   close();
00133   free(__device_file);
00134 }
00135 
00136 
00137 /** Open serial port. */
00138 void
00139 Visca::open() {
00140 
00141   struct termios param;
00142 
00143   __fd = ::open(__device_file, O_RDWR | O_NONBLOCK);
00144   if (! __fd) {
00145     throw ViscaException("Cannot open device", errno);
00146   }
00147 
00148   if (tcgetattr(__fd, &param) == -1) {
00149     ViscaException ve("Getting the port parameters failed", errno);
00150     ::close(__fd);
00151     throw ve;
00152   }
00153 
00154   cfsetospeed(&param, B9600);
00155   cfsetispeed(&param, B9600);
00156 
00157   param.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
00158   param.c_cflag |= CREAD;
00159   param.c_cflag |= CLOCAL;
00160   //param.c_cflag |= CRTSCTS;
00161   
00162   param.c_cc[VMIN] = 1;
00163   param.c_cc[VTIME] = 0;
00164     
00165   param.c_iflag |= IGNBRK;
00166   param.c_iflag &= ~PARMRK;
00167   param.c_iflag &= ~ISTRIP;
00168   param.c_iflag &= ~INLCR;
00169   param.c_iflag &= ~IGNCR;
00170   param.c_iflag &= ~ICRNL;
00171   param.c_iflag &= ~IXON;
00172   param.c_iflag &= ~IXOFF;
00173     
00174   param.c_lflag &= ~ECHO;
00175     
00176   // hand shake
00177   param.c_lflag |= IEXTEN;
00178   param.c_oflag &= ~OPOST;  //enable raw output
00179     
00180   //tcflow (__fd, TCOON);
00181   //tcflow (__fd, TCION);
00182 
00183   // number of data bits: 8
00184   param.c_cflag &= ~CS5 & ~CS6 & ~CS7 & ~CS8;
00185 
00186   param.c_cflag |= CS8;
00187     
00188   // parity: none
00189   param.c_cflag &=~(PARENB & PARODD);
00190     
00191   // stop bits: 1
00192   param.c_cflag &= ~CSTOPB;
00193 
00194   if (tcsetattr(__fd, TCSANOW, &param) != 0) {
00195     ViscaException ve("Setting the port parameters failed", errno);
00196     ::close(__fd);
00197     throw ve;
00198   }
00199 
00200   __opened = true;
00201   // Choose first camera by default
00202   __sender    = VISCA_BUS_0;
00203   __recipient = VISCA_BUS_1;
00204 
00205 #ifdef TIMETRACKER_VISCA
00206   __tt = new TimeTracker();
00207   __ttc_pantilt_get_send = __tt->addClass("getPanTilt: send");
00208   __ttc_pantilt_get_read = __tt->addClass("getPanTilt: read");
00209   __ttc_pantilt_get_handle = __tt->addClass("getPanTilt: handling responses");
00210   __ttc_pantilt_get_interpret = __tt->addClass("getPanTilt: interpreting");
00211 #endif
00212 }
00213 
00214 
00215 /** Close port. */
00216 void
00217 Visca::close()
00218 {
00219   if (__opened) {
00220     __opened = false;
00221     ::close(__fd);
00222   }
00223 }
00224 
00225 
00226 /** Set addresses of cameras. */
00227 void
00228 Visca::set_address()
00229 {
00230   unsigned char recp_backup = __recipient;
00231   __recipient = VISCA_BUS_BROADCAST;
00232   __obuffer[1] = 0x30;
00233   __obuffer[2] = 0x01;
00234   __obuffer_length = 2;
00235 
00236   try {
00237     send();
00238     recv();
00239   } catch (ViscaException &e) {
00240     __recipient = recp_backup;
00241     throw;
00242   }
00243 
00244   __recipient = recp_backup;
00245 }
00246 
00247 
00248 /** Clear command buffers. */
00249 void
00250 Visca::clear()
00251 {
00252   if (!__opened)  throw ViscaException("Serial port not open");
00253 
00254   __obuffer[1] = 0x01;
00255   __obuffer[2] = 0x00;
00256   __obuffer[3] = 0x01;
00257   __obuffer_length = 3;
00258 
00259   try {
00260     send();
00261     recv();
00262   } catch (ViscaException &e) {
00263     e.append("clear() failed");
00264     throw;
00265   }
00266 }
00267 
00268 
00269 /** Send outbound queue. */
00270 void
00271 Visca::send()
00272 {
00273   if (!__opened)  throw ViscaException("Serial port not open");
00274 
00275   // Set first bit to 1
00276   __obuffer[0] =  0x80;
00277   __obuffer[0] |= (__sender << 4);
00278   __obuffer[0] |= __recipient;
00279 
00280   __obuffer[++__obuffer_length] = VISCA_TERMINATOR;
00281   ++__obuffer_length;
00282 
00283   int written = write(__fd, __obuffer, __obuffer_length);
00284   //printf("Visca sent: ");
00285   //for (int i = 0; i < __obuffer_length; ++i) {
00286   //  printf("%02X", __obuffer[i]);
00287   //}
00288   //printf("\n");
00289   if (written < __obuffer_length) {
00290     throw ViscaException("Not all bytes send");
00291   }
00292 }
00293 
00294 
00295 /** Check data availability.
00296  * @return true if data is available, false otherwise
00297  */
00298 bool
00299 Visca::data_available()
00300 {
00301   int num_bytes = 0;
00302   ioctl(__fd, FIONREAD, &num_bytes);
00303   return (num_bytes > 0);
00304 }
00305 
00306 
00307 /** Receive data.
00308  * @param timeout_ms read timeout in miliseconds
00309  */
00310 void
00311 Visca::recv(unsigned int timeout_ms)
00312 {
00313   if (timeout_ms == 0xFFFFFFFF) timeout_ms = __default_timeout_ms;
00314   try {
00315     recv_packet(timeout_ms);
00316   } catch (ViscaException &e) {
00317     e.append("Receiving failed, recv_packet() call failed");
00318     throw;
00319   }
00320 
00321   // Get type of message
00322   unsigned char type = __ibuffer[1] & 0xF0;
00323   while (type == VISCA_RESPONSE_ACK) {
00324     try {
00325       recv_packet(timeout_ms);
00326     } catch (ViscaException &e) {
00327       e.append("Receiving failed, recv_packet() call 2 failed");
00328       throw;
00329     }
00330     type = __ibuffer[1] & 0xF0;
00331   }
00332 
00333   switch (type) {
00334   case VISCA_RESPONSE_CLEAR:
00335   case VISCA_RESPONSE_ADDRESS:
00336   case VISCA_RESPONSE_COMPLETED:
00337   case VISCA_RESPONSE_ERROR:
00338     break;
00339   default:
00340     throw fawkes::Exception("Receiving failed, unexpected packet type %u received",
00341                             type);
00342   }
00343 }
00344 
00345 
00346 /** Receive ACK packet.
00347  * @param socket contains the socket that the ACK was received on upon return
00348  */
00349 void
00350 Visca::recv_ack(unsigned int *socket)
00351 {
00352   try {
00353     recv_packet(__default_timeout_ms);
00354   } catch (ViscaException &e) {
00355     throw ViscaException("recv_ack(): recv_packet() failed");
00356   }
00357 
00358   // Get type of message
00359   unsigned char type = __ibuffer[1] & 0xF0;
00360   while (type != VISCA_RESPONSE_ACK) {
00361 
00362     try {
00363       handle_response();
00364       recv_packet(__default_timeout_ms);
00365     } catch (ViscaException &e) {
00366       e.append("Handling message of type %u failed", type);
00367       throw;
00368     }
00369     type = __ibuffer[1] & 0xF0;
00370   }
00371 
00372   // Got an ack now
00373   if (socket != NULL) {
00374     *socket = __ibuffer[1] & 0x0F;
00375   }
00376 
00377 }
00378 
00379 
00380 /** Send non-blocking.
00381  * Does a non-blocking send.
00382  * @param socket the socket that was used to send the request.
00383  */
00384 void
00385 Visca::send_nonblocking(unsigned int *socket)
00386 {
00387   try {
00388     send();
00389     recv_ack(socket);
00390   } catch (ViscaException &e) {
00391     e.append("Non-blocking send failed!");
00392     throw;
00393   }
00394 }
00395 
00396 
00397 /** Finish a non-blocking operation.
00398  * @param socket socket that the non-blocking operation was sent to
00399  */
00400 void
00401 Visca::finish_nonblocking( unsigned int socket )
00402 {
00403   for (unsigned int i = 0; i < NONBLOCKING_NUM; ++i) {
00404     if (__nonblocking_sockets[i] == socket) {
00405       __nonblocking_sockets[i] = 0;
00406       __nonblocking_running[i] = false;
00407       return;
00408     }
00409   }
00410 
00411   throw ViscaException("finish_nonblocking() failed: socket not found");
00412 }
00413 
00414 
00415 /** Check if a non-blocking operation has been finished.
00416  * @param item the non-blocking item to check
00417  * @return true if the non-blocking operation has been finished, false otherwise
00418  */
00419 bool
00420 Visca::is_nonblocking_finished(unsigned int item) const
00421 {
00422   if (item >= NONBLOCKING_NUM) {
00423     throw ViscaException("Invalid item number");
00424   }
00425   return ! __nonblocking_running[item];
00426 }
00427 
00428 
00429 /** Send and wait for reply, blocking.
00430  */
00431 void
00432 Visca::send_with_reply()
00433 {
00434   try {
00435     send();
00436     recv();
00437   } catch (ViscaException &e) {
00438     e.append("Sending with reply failed");
00439     throw;
00440   }
00441 }
00442 
00443 
00444 /** Receive a packet.
00445  * @param timeout_ms read timeout in miliseconds
00446  */
00447 void
00448 Visca::recv_packet(unsigned int timeout_ms)
00449 {
00450   // wait for message
00451   timeval timeout = {0, timeout_ms * 1000};
00452 
00453   fd_set read_fds;
00454   FD_ZERO(&read_fds);
00455   FD_SET(__fd, &read_fds);
00456 
00457   int rv = 0;
00458   rv = select(__fd + 1, &read_fds, NULL, NULL, &timeout);
00459 
00460   if ( rv == -1 ) {
00461     throw fawkes::Exception(errno, "Select on FD failed");
00462   } else if ( rv == 0 ) {
00463     throw fawkes::TimeoutException("Timeout reached while waiting for incoming data");
00464   }
00465 
00466   // get octets one by one
00467   if (read(__fd, __ibuffer, 1) != 1) {
00468     throw fawkes::Exception(errno, "Visca reading packet byte failed");
00469   }
00470 
00471   int pos = 0;
00472   while (__ibuffer[pos] != VISCA_TERMINATOR) {
00473     if (read(__fd, &__ibuffer[++pos], 1) != 1) {
00474       throw fawkes::Exception(errno, "Visca reading packet byte failed");
00475     }
00476     usleep(0);
00477   }
00478   __ibuffer_length = pos + 1;
00479   //printf("Visca read: ");
00480   //for (int i = 0; i < __ibuffer_length; ++i) {
00481   //  printf("%02X", __ibuffer[i]);
00482   //}
00483   //printf("\n");
00484 }
00485 
00486 
00487 
00488 /** Handle incoming response.  */
00489 void
00490 Visca::handle_response()
00491 {
00492   unsigned int type = __ibuffer[1] & 0xF0;
00493   unsigned int socket = __ibuffer[1] & 0x0F;
00494 
00495   if (socket == 0) {
00496     // This is an inquire response, do NOT handle!
00497     //throw ViscaException("handle_response(): Received an inquire response, can't handle");
00498     return;
00499   }
00500 
00501   if ( type == VISCA_RESPONSE_COMPLETED ) {
00502     // Command has been finished
00503     try {
00504       finish_nonblocking( __ibuffer[1] & 0x0F );
00505     } catch (ViscaException &e) {
00506       // Ignore, happens sometimes without effect
00507       // e.append("handle_response() failed, could not finish non-blocking");
00508       // throw;
00509     }
00510   } else if ( type == VISCA_RESPONSE_ERROR ) {
00511     finish_nonblocking( __ibuffer[1] & 0x0F );
00512     //throw ViscaException("handle_response(): got an error message from camera");
00513   } else {
00514     // ignore
00515     //ViscaException ve("Got unknown/unhandled response type");
00516     //ve.append("Received message of type %u", type);
00517     //throw ve;
00518   }
00519 
00520 }
00521 
00522 
00523 /** Cancel a running command.
00524  * @param socket socket that the command was send on
00525  */
00526 void
00527 Visca::cancel_command( unsigned int socket )
00528 {
00529   unsigned char cancel_socket = socket & 0x0000000F;
00530 
00531   __obuffer[1] = VISCA_CANCEL | cancel_socket;
00532   __obuffer_length = 1;
00533 
00534   try {
00535     send_with_reply();
00536   } catch (ViscaException &e) {
00537     e.append("cancel_command() failed");
00538     throw;
00539   }
00540 
00541   if (  ((__ibuffer[1] & 0xF0) == VISCA_RESPONSE_ERROR) &&
00542         ((__ibuffer[1] & 0x0F) == cancel_socket) &&
00543         ((__ibuffer[2] == VISCA_ERROR_CANCELLED)) ) {
00544     return;
00545   } else {
00546     throw ViscaException("Command could not be cancelled");
00547   }
00548 }
00549 
00550 
00551 /** Process incoming data. */
00552 void
00553 Visca::process()
00554 {
00555 
00556   __inquire = VISCA_RUNINQ_NONE;
00557 
00558   while (data_available()) {
00559     try {
00560       recv();
00561       handle_response();
00562     } catch (ViscaException &e) {
00563       // Ignore this error
00564       return;
00565     }
00566   }
00567 }
00568 
00569 
00570 /** Set pan tilt.
00571  * @param pan pan
00572  * @param tilt tilt
00573  */
00574 void
00575 Visca::set_pan_tilt(int pan, int tilt)
00576 {
00577   
00578   // we do not to check for blocking, could not be called at
00579   // the same time if blocking...
00580   /*
00581   if ( __nonblocking_running[ NONBLOCKING_PANTILT] ) {
00582     cout << "Cancelling old setPanTilt" << endl;
00583     if (cancel_command( __nonblocking_sockets[ NONBLOCKING_PANTILT ] ) != VISCA_SUCCESS) {
00584       cout << "Visca: Could not cancel old non-blocking pan/tilt command. Not setting new pan/tilt." << endl;
00585       return VISCA_E_CANCEL;
00586     }
00587     __nonblocking_running[ NONBLOCKING_PANTILT ] = false;
00588   }
00589   */
00590 
00591   unsigned short int tilt_val = 0 + tilt;
00592   unsigned short int pan_val  = 0 + pan;
00593 
00594   __obuffer[1] = VISCA_COMMAND;
00595   __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
00596   __obuffer[3] = VISCA_PT_ABSOLUTE_POSITION;
00597   __obuffer[4] = __pan_speed;
00598   __obuffer[5] = __tilt_speed;
00599 
00600   // pan
00601   __obuffer[6] = (pan_val & 0xf000) >> 12;
00602   __obuffer[7] = (pan_val & 0x0f00) >>  8;
00603   __obuffer[8] = (pan_val & 0x00f0) >>  4;
00604   __obuffer[9] = (pan_val & 0x000f);
00605   // tilt
00606   __obuffer[10] = (tilt_val & 0xf000) >> 12;
00607   __obuffer[11] = (tilt_val & 0x0f00) >> 8;
00608   __obuffer[12] = (tilt_val & 0x00f0) >> 4;
00609   __obuffer[13] = (tilt_val & 0x000f);
00610 
00611   __obuffer_length = 13;
00612 
00613   try {
00614     if (! __blocking) {
00615       __nonblocking_running[ NONBLOCKING_PANTILT ] = true;
00616       send_nonblocking( &(__nonblocking_sockets[ NONBLOCKING_PANTILT ]) );
00617     } else {
00618       send_with_reply();
00619     }
00620   } catch (ViscaException &e) {
00621     e.append("setPanTilt() failed");
00622     throw;
00623   }
00624 }
00625 
00626 
00627 /** Set pan/tilt speed.
00628  * @param pan_speed a value between 0 and MAX_PAN_SPEED
00629  * @param tilt_speed a value between 0 and MAX_TILT_SPEED
00630  * @exception Exception thrown if desired pan or tilt speed is too high
00631  */
00632 void
00633 Visca::set_pan_tilt_speed(unsigned char pan_speed, unsigned char tilt_speed)
00634 {
00635   if (pan_speed > MAX_PAN_SPEED) {
00636     throw fawkes::Exception("Pan speed too hight, max: %u  des: %u", MAX_PAN_SPEED, pan_speed);
00637   }
00638   if (tilt_speed > MAX_TILT_SPEED) {
00639     throw fawkes::Exception("Tilt speed too hight, max: %u  des: %u", MAX_TILT_SPEED, tilt_speed);
00640   }
00641 
00642   __pan_speed  = pan_speed;
00643   __tilt_speed = tilt_speed;
00644 }
00645 
00646 
00647 /** Get pan/tilt speed.
00648  * @param pan_speed upon return contains pan speed index
00649  * @param tilt_speed upon return contains tilt speed index
00650  */
00651 void
00652 Visca::get_pan_tilt_speed(unsigned char &pan_speed, unsigned char &tilt_speed)
00653 {
00654   pan_speed  = __pan_speed;
00655   tilt_speed = __tilt_speed;
00656 }
00657 
00658 /** Initiate a pan/tilt request, but do not wait for the reply. */
00659 void
00660 Visca::start_get_pan_tilt()
00661 {
00662 
00663   if ( __inquire )  throw ViscaInquiryRunningException();
00664 
00665   __inquire = VISCA_RUNINQ_PANTILT;
00666 
00667   __obuffer[1] = VISCA_INQUIRY;
00668   __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
00669   __obuffer[3] = VISCA_PT_POSITION_INQ;
00670   __obuffer_length = 3;
00671 
00672   try {
00673     send();
00674   } catch (ViscaException &e) {
00675     e.append("startGetPanTilt() failed");
00676     throw;
00677   }
00678 }
00679 
00680 
00681 /** Get pan and tilt values.
00682  * If you used startGetPanTilt() to initiate the query the result is
00683  * received and returned, otherwise a request is sent and the method blocks
00684  * until the answer has been received.
00685  * @param pan contains pan upon return
00686  * @param tilt contains tilt upon return
00687  */
00688 void
00689 Visca::get_pan_tilt(int &pan, int &tilt)
00690 {
00691 
00692   if ( __inquire ) {
00693     if ( __inquire != VISCA_RUNINQ_PANTILT ) {
00694       throw ViscaException("Inquiry running, but it is not a pan/tilt inquiry");
00695     } else {
00696 #ifdef TIMETRACKER_VISCA
00697       __tt->ping_start( __ttc_pantilt_get_read );
00698 #endif
00699       try {
00700         recv();
00701       } catch (ViscaException &e) {
00702         // Ignore
00703       }
00704 #ifdef TIMETRACKER_VISCA
00705       __tt->ping_end( __ttc_pantilt_get_read );
00706 #endif
00707     }
00708   } else {
00709 
00710     __obuffer[1] = VISCA_INQUIRY;
00711     __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
00712     __obuffer[3] = VISCA_PT_POSITION_INQ;
00713     __obuffer_length = 3;
00714 
00715     try {
00716 #ifdef TIMETRACKER_VISCA
00717       __tt->ping_start( __ttc_pantilt_get_send );
00718       send();
00719       __tt->ping_end( __ttc_pantilt_get_send );
00720       __tt->ping_start( __ttc_pantilt_get_read );
00721       recv();
00722       __tt->ping_end( __ttc_pantilt_get_read );
00723 #else
00724       send_with_reply();
00725 #endif
00726     } catch (ViscaException &e) {
00727       // Ignore
00728     }
00729   }
00730 
00731 #ifdef TIMETRACKER_VISCA
00732   __tt->ping_start( __ttc_pantilt_get_handle );
00733 #endif
00734 
00735   while (__ibuffer[1] != VISCA_RESPONSE_COMPLETED) {
00736     // inquire return from socket 0, so this may occur if there
00737     // are other responses waiting, handle them...
00738     try {
00739       handle_response();
00740       recv();
00741     } catch (ViscaException &e) {
00742       // Ignore
00743     }
00744   }
00745 
00746 #ifdef TIMETRACKER_VISCA
00747   __tt->ping_end( __ttc_pantilt_get_handle );
00748   __tt->ping_start( __ttc_pantilt_get_interpret );
00749 #endif
00750 
00751 
00752   // Extract information from __ibuffer
00753   if ( __ibuffer[1] == VISCA_RESPONSE_COMPLETED ) {
00754     unsigned short int pan_val = 0;
00755     unsigned short int tilt_val = 0;
00756 
00757     pan_val |= (__ibuffer[2] & 0x0F) << 12;
00758     pan_val |= (__ibuffer[3] & 0x0F) << 8;
00759     pan_val |= (__ibuffer[4] & 0x0F) << 4;
00760     pan_val |= (__ibuffer[5] & 0x0F);
00761 
00762     tilt_val |= (__ibuffer[6] & 0x0F) << 12;
00763     tilt_val |= (__ibuffer[7] & 0x0F) << 8;
00764     tilt_val |= (__ibuffer[8] & 0x0F) << 4;
00765     tilt_val |= (__ibuffer[9] & 0x0F);
00766 
00767     if (pan_val < 0x8000) {
00768       // The value must be positive
00769       pan = pan_val;
00770     } else {
00771       // negative value
00772       pan = pan_val - 0xFFFF;
00773     }
00774 
00775     if (tilt_val < 0x8000) {
00776       // The value must be positive
00777       tilt = tilt_val;
00778     } else {
00779       // negative value
00780       tilt = tilt_val - 0xFFFF;
00781     }
00782 
00783   } else {
00784     throw ViscaException("getPanTilt(): Wrong response received");
00785   }
00786 #ifdef TIMETRACKER_VISCA
00787   __tt->ping_end( __ttc_pantilt_get_interpret );
00788   __tt->print_to_stdout();
00789 #endif
00790 
00791   __inquire = VISCA_RUNINQ_NONE;
00792 }
00793 
00794 
00795 /** Reset pan/tilt limit. */
00796 void
00797 Visca::reset_pan_tilt_limit()
00798 {
00799   __obuffer[1] = VISCA_COMMAND;
00800   __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
00801   __obuffer[3] = VISCA_PT_LIMITSET;
00802   __obuffer[3] = VISCA_PT_LIMITSET_CLEAR;
00803   __obuffer[4] = VISCA_PT_LIMITSET_SET_UR;
00804   __obuffer[5] = 0x07;
00805   __obuffer[6] = 0x0F;
00806   __obuffer[7] = 0x0F;
00807   __obuffer[8] = 0x0F;
00808   __obuffer[9] = 0x07;
00809   __obuffer[10] = 0x0F;
00810   __obuffer[11] = 0x0F;
00811   __obuffer[12] = 0x0F;
00812   __obuffer_length = 12;
00813 
00814   try {
00815     send_with_reply();
00816 
00817     __obuffer[4] = VISCA_PT_LIMITSET_SET_DL;
00818 
00819     send_with_reply();
00820   } catch (ViscaException &e) {
00821     e.append("resetPanTiltLimit() failed");
00822     throw;
00823   }
00824 }
00825 
00826 
00827 /** Set pan tilt limit.
00828  * @param pan_left most left pan value
00829  * @param pan_right most right pan value
00830  * @param tilt_up most up tilt value
00831  * @param tilt_down most down tilt value
00832  */
00833 void
00834 Visca::set_pan_tilt_limit(int pan_left, int pan_right, int tilt_up, int tilt_down)
00835 {
00836   try {
00837     __obuffer[1] = VISCA_COMMAND;
00838     __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
00839     __obuffer[3] = VISCA_PT_LIMITSET;
00840     __obuffer[3] = VISCA_PT_LIMITSET_SET;
00841     __obuffer[4] = VISCA_PT_LIMITSET_SET_UR;
00842     // pan
00843     __obuffer[5] = (pan_right & 0xf000) >> 12;
00844     __obuffer[6] = (pan_right & 0x0f00) >>  8;
00845     __obuffer[7] = (pan_right & 0x00f0) >>  4;
00846     __obuffer[8] = (pan_right & 0x000f);
00847     // tilt
00848     __obuffer[9] = (tilt_up & 0xf000) >> 12;
00849     __obuffer[10] = (tilt_up & 0x0f00) >>  8;
00850     __obuffer[11] = (tilt_up & 0x00f0) >>  4;
00851     __obuffer[12] = (tilt_up & 0x000f);
00852 
00853     __obuffer_length = 12;
00854 
00855     send_with_reply();
00856 
00857     __obuffer[4] = VISCA_PT_LIMITSET_SET_DL;
00858     // pan
00859     __obuffer[5] = (pan_left & 0xf000) >> 12;
00860     __obuffer[6] = (pan_left & 0x0f00) >>  8;
00861     __obuffer[7] = (pan_left & 0x00f0) >>  4;
00862     __obuffer[8] = (pan_left & 0x000f);
00863     // tilt
00864     __obuffer[9] = (tilt_down & 0xf000) >> 12;
00865     __obuffer[10] = (tilt_down & 0x0f00) >>  8;
00866     __obuffer[11] = (tilt_down & 0x00f0) >>  4;
00867     __obuffer[12] = (tilt_down & 0x000f);
00868 
00869     send_with_reply();
00870   } catch (ViscaException &e) {
00871     e.append("setPanTiltLimit() failed");
00872     throw;
00873   }
00874 }
00875 
00876 
00877 /** Reset pan/tilt. */
00878 void
00879 Visca::reset_pan_tilt()
00880 {
00881   __obuffer[1] = VISCA_COMMAND;
00882   __obuffer[2] = VISCA_CATEGORY_PAN_TILTER;
00883   __obuffer[3] = VISCA_PT_HOME;
00884   __obuffer_length = 3;
00885 
00886   try {
00887     send_with_reply();
00888   } catch (ViscaException &e) {
00889     e.append("resetPanTilt() failed");
00890     throw;
00891   }
00892 }
00893 
00894 
00895 /** Reset zoom. */
00896 void
00897 Visca::reset_zoom()
00898 {
00899   __obuffer[1] = VISCA_COMMAND;
00900   __obuffer[2] = VISCA_CATEGORY_CAMERA1;
00901   __obuffer[3] = VISCA_ZOOM;
00902   __obuffer[4] = VISCA_ZOOM_STOP;
00903   __obuffer_length = 4;
00904 
00905   try {
00906     send_with_reply();
00907   } catch (ViscaException &e) {
00908     e.append("resetZoom() failed");
00909     throw;
00910   }
00911 }
00912 
00913 
00914 /** Set zoom speed in tele.
00915  * @param speed speed
00916  */
00917 void
00918 Visca::set_zoom_speed_tele(unsigned int speed)
00919 {
00920   __obuffer[1] = VISCA_COMMAND;
00921   __obuffer[2] = VISCA_CATEGORY_CAMERA1;
00922   __obuffer[3] = VISCA_ZOOM;
00923   __obuffer[4] = VISCA_ZOOM_TELE_SPEED;
00924   // zoom speed
00925   __obuffer[5] = (speed & 0x000f) | 0x0020;
00926   __obuffer_length = 5;
00927 
00928   try {
00929     send_with_reply();
00930   } catch (ViscaException &e) {
00931     e.append("setZoomSpeedTele() failed");
00932     throw;
00933   }
00934 }
00935 
00936 
00937 /** Set zoom speed in wide angle.
00938  * @param speed speed
00939  */
00940 void
00941 Visca::set_zoom_speed_wide(unsigned int speed)
00942 {
00943   __obuffer[1] = VISCA_COMMAND;
00944   __obuffer[2] = VISCA_CATEGORY_CAMERA1;
00945   __obuffer[3] = VISCA_ZOOM;
00946   __obuffer[4] = VISCA_ZOOM_WIDE_SPEED;
00947   // zoom speed
00948   __obuffer[5] = (speed & 0x000f) | 0x0020;
00949   __obuffer_length = 5;
00950 
00951   try {
00952     send_with_reply();
00953   } catch (ViscaException &e) {
00954     e.append("setZoomSpeedWide() failed");
00955     throw;
00956   }
00957 }
00958 
00959 
00960 /** Set zoom.
00961  * @param zoom zoom value
00962  */
00963 void
00964 Visca::set_zoom(unsigned int zoom)
00965 {
00966   __obuffer[1] = VISCA_COMMAND;
00967   __obuffer[2] = VISCA_CATEGORY_CAMERA1;
00968   __obuffer[3] = VISCA_ZOOM_VALUE;
00969   // zoom
00970   __obuffer[4] = (zoom & 0xf000) >> 12;
00971   __obuffer[5] = (zoom & 0x0f00) >>  8;
00972   __obuffer[6] = (zoom & 0x00f0) >>  4;
00973   __obuffer[7] = (zoom & 0x000f);
00974 
00975   __obuffer_length = 7;
00976 
00977   try {
00978     send_with_reply();
00979   } catch (ViscaException &e) {
00980     e.append("setZoom() failed");
00981     throw;
00982   }
00983 }
00984 
00985 
00986 /** Get zoom.
00987  * @param zoom contains zoom upon return.
00988  */
00989 void
00990 Visca::get_zoom(unsigned int *zoom)
00991 {
00992   __obuffer[1] = VISCA_INQUIRY;
00993   __obuffer[2] = VISCA_CATEGORY_CAMERA1;
00994   __obuffer[3] = VISCA_ZOOM_VALUE;
00995   __obuffer_length = 3;
00996 
00997   try {
00998     send_with_reply();
00999   } catch (ViscaException &e) {
01000     e.append("getZoom() failed");
01001     throw;
01002   }
01003 
01004   // Extract information from __ibuffer
01005   if ( __ibuffer[1] == VISCA_RESPONSE_COMPLETED ) {
01006     unsigned short int zoom_val = 0;
01007 
01008     zoom_val |= (__ibuffer[2] & 0x0F) << 12;
01009     zoom_val |= (__ibuffer[3] & 0x0F) << 8;
01010     zoom_val |= (__ibuffer[4] & 0x0F) << 4;
01011     zoom_val |= (__ibuffer[5] & 0x0F);
01012 
01013     *zoom = zoom_val;
01014   } else {
01015     throw ViscaException("getZoom(): zoom inquiry failed, response code not VISCA_RESPONSE_COMPLETED");
01016   }
01017 
01018 }
01019 
01020 
01021 /** Enable or disable digital zoome.
01022  * @param enabled true to enable digital zoom, false to disable
01023  */
01024 void
01025 Visca::set_zoom_digital_enabled(bool enabled)
01026 {
01027   __obuffer[1] = VISCA_COMMAND;
01028   __obuffer[2] = VISCA_CATEGORY_CAMERA1;
01029   __obuffer[3] = VISCA_DZOOM;
01030   if (enabled) {
01031     __obuffer[4] = VISCA_DZOOM_ON;
01032   } else {
01033     __obuffer[4] = VISCA_DZOOM_OFF;
01034   }
01035   __obuffer_length = 4;
01036 
01037   try {
01038     send_with_reply();
01039   } catch (ViscaException &e) {
01040     e.append("setZoomDigitalEnabled() failed");
01041     throw;
01042   }
01043 }
01044 
01045 
01046 /** Apply effect.
01047  * @param filter filter
01048  */
01049 void
01050 Visca::apply_effect(unsigned char filter)
01051 {
01052   __obuffer[1] = VISCA_COMMAND;
01053   __obuffer[2] = VISCA_CATEGORY_CAMERA1;
01054   __obuffer[3] = VISCA_PICTURE_EFFECT;
01055   __obuffer[4] = filter;
01056   __obuffer_length = 4;
01057 
01058   try {
01059     send_with_reply();
01060   } catch (ViscaException &e) {
01061     e.append("applyEffect() failed");
01062     throw;
01063   }
01064 }
01065 
01066 
01067 /** Reset effects. */
01068 void
01069 Visca::reset_effect()
01070 {
01071   try {
01072     apply_effect(VISCA_PICTURE_EFFECT_OFF);
01073   } catch (ViscaException &e) {
01074     e.append("resetEffect() failed");
01075     throw;
01076   }
01077 }
01078 
01079 
01080 /** Apply pastel effect. */
01081 void
01082 Visca::apply_effect_pastel()
01083 {
01084   try {
01085     apply_effect(VISCA_PICTURE_EFFECT_PASTEL);
01086   } catch (ViscaException &e) {
01087     e.append("applyEffectPastel() failed");
01088     throw;
01089   }
01090 }
01091 
01092 
01093 /** Apply negative art effect. */
01094 void
01095 Visca::apply_effect_neg_art()
01096 {
01097   try {
01098     apply_effect(VISCA_PICTURE_EFFECT_NEGATIVE);
01099   } catch (ViscaException &e) {
01100     e.append("applyEffectNegArt() failed");
01101     throw;
01102   }
01103 }
01104 
01105 
01106 /** Apply sepia effect. */
01107 void
01108 Visca::apply_effect_sepia()
01109 {
01110   try {
01111     apply_effect(VISCA_PICTURE_EFFECT_SEPIA);
01112   } catch (ViscaException &e) {
01113     e.append("applyEffectSepia() failed");
01114     throw;
01115   }
01116 }
01117 
01118 
01119 /**Apply B/W effect */
01120 void
01121 Visca::apply_effect_bnw()
01122 {
01123   try {
01124     apply_effect(VISCA_PICTURE_EFFECT_BW);
01125   } catch (ViscaException &e) {
01126     e.append("applyEffectBnW() failed");
01127     throw;
01128   }
01129 }
01130 
01131 
01132 /** Apply solarize effect. */
01133 void
01134 Visca::apply_effect_solarize()
01135 {
01136   try {
01137     apply_effect(VISCA_PICTURE_EFFECT_SOLARIZE);
01138   } catch (ViscaException &e) {
01139     e.append("applyEffectSolarize() failed");
01140     throw;
01141   }
01142 }
01143 
01144 
01145 /** Apply mosaic effect. */
01146 void
01147 Visca::apply_effect_mosaic()
01148 {
01149   try {
01150     apply_effect(VISCA_PICTURE_EFFECT_MOSAIC);
01151   } catch (ViscaException &e) {
01152     e.append("applyEffectMosaic() failed");
01153     throw;
01154   }
01155 }
01156 
01157 
01158 /** Apply slim effect. */
01159 void
01160 Visca::apply_effect_slim()
01161 {
01162   try {
01163     apply_effect(VISCA_PICTURE_EFFECT_SLIM);
01164   } catch (ViscaException &e) {
01165     e.append("applyEffectSlim() failed");
01166     throw;
01167   }
01168 }
01169 
01170 
01171 /** Apply stretch effect. */
01172 void
01173 Visca::apply_effect_stretch()
01174 {
01175   try {
01176     apply_effect(VISCA_PICTURE_EFFECT_STRETCH);
01177   } catch (ViscaException &e) {
01178     e.append("applyEffectStretch() failed");
01179     throw;
01180   }
01181 }
01182 
01183 
01184 /** Get white balance mode.
01185  * @return white balance mode
01186  */
01187 unsigned int
01188 Visca::get_white_balance_mode()
01189 {
01190   __obuffer[1] = VISCA_INQUIRY;
01191   __obuffer[2] = VISCA_CATEGORY_CAMERA1;
01192   __obuffer[3] = VISCA_WB;
01193   __obuffer_length = 3;
01194 
01195   try {
01196     send_with_reply();
01197   } catch (ViscaException &e) {
01198     e.append("getWhiteBalanceMode() failed");
01199     throw;
01200   }
01201 
01202   while (__ibuffer[1] != VISCA_RESPONSE_COMPLETED) {
01203     // inquire return from socket 0, so this may occur if there
01204     // are other responses waiting, handle them...
01205     try {
01206       handle_response();
01207       recv();
01208     } catch (ViscaException &e) {
01209       e.append("getWhiteBalanceMode() failed");
01210       throw;
01211     }
01212   }
01213 
01214   // Extract information from __ibuffer
01215   if ( __ibuffer[1] == VISCA_RESPONSE_COMPLETED ) {
01216     return __ibuffer[2];
01217   } else {
01218     throw ViscaException("Did not get 'request completed' response");
01219   }
01220 
01221 }
01222