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