visca.cpp

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