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