1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/webcam_private/visca_webcam.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/public/browser/browser_thread.h"
11 using content::BrowserThread
;
15 // Message terminator:
16 const char VISCA_TERMINATOR
= 0xFF;
19 const char VISCA_RESPONSE_NETWORK_CHANGE
= 0x38;
20 const char VISCA_RESPONSE_ACK
= 0x40;
21 const char VISCA_RESPONSE_ERROR
= 0x60;
23 // Pan-Tilt-Zoom movement comands from http://www.manualslib.com/manual/...
24 // 557364/Cisco-Precisionhd-1080p12x.html?page=31#manual
26 // Reset the address of each device in the VISCA chain (broadcast). This is used
27 // when resetting the VISCA network.
28 const std::vector
<char> kSetAddressCommand
= {0x88, 0x30, 0x01, 0xFF};
30 // Clear all of the devices, halting any pending commands in the VISCA chain
31 // (broadcast). This is used when resetting the VISCA network.
32 const std::vector
<char> kClearAllCommand
= {0x88, 0x01, 0x00, 0x01, 0xFF};
34 // Clear the command buffer in the target device and cancel the command
35 // currently being executed. Command: {0x8X, 0x01, 0x00, 0x01, 0xFF}, X = 1 to
36 // 7: target device address.
37 const std::vector
<char> kClearCommand
= {0x81, 0x01, 0x00, 0x01, 0xFF};
39 // Command: {0x8X, 0x09, 0x06, 0x12, 0xFF}, X = 1 to 7: target device address.
40 // Response: {0xY0, 0x50, 0x0p, 0x0q, 0x0r, 0x0s, 0x0t, 0x0u, 0x0v, 0x0w, 0xFF},
41 // Y = socket number; pqrs: pan position; tuvw: tilt position.
42 const std::vector
<char> kGetPanTiltCommand
= {0x81, 0x09, 0x06, 0x12, 0xFF};
44 // Command: {0x8X, 0x01, 0x06, 0x20, 0x0p, 0x0t, 0x0q, 0x0r, 0x0s, 0x0u, 0x0v,
45 // 0x0w, 0x0y, 0x0z, 0xFF}, X = 1 to 7: target device address; p = pan speed;
46 // t = tilt speed; qrsu = pan position; vwyz = tilt position.
47 const std::vector
<char> kSetPanTiltCommand
= {0x81, 0x01, 0x06, 0x02, 0x05,
48 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF};
50 // Command: {0x8X, 0x01, 0x06, 0x05, 0xFF}, X = 1 to 7: target device address.
51 const std::vector
<char> kResetPanTiltCommand
= {0x81, 0x01, 0x06, 0x05, 0xFF};
53 // Command: {0x8X, 0x09, 0x04, 0x47, 0xFF}, X = 1 to 7: target device address.
54 // Response: {0xY0, 0x50, 0x0p, 0x0q, 0x0r, 0x0s, 0xFF}, Y = socket number;
55 // pqrs: zoom position.
56 const std::vector
<char> kGetZoomCommand
= {0x81, 0x09, 0x04, 0x47, 0xFF};
58 // Command: {0x8X, 0x01, 0x04, 0x47, 0x0p, 0x0q, 0x0r, 0x0s, 0xFF}, X = 1 to 7:
59 // target device address; pqrs: zoom position;
60 const std::vector
<char> kSetZoomCommand
=
61 {0x81, 0x01, 0x04, 0x47, 0x00, 0x00, 0x00, 0x00, 0xFF};
63 // Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x03, 0x01, 0xFF}, X = 1 to 7:
64 // target device address; p: pan speed; t: tilt speed.
65 const std::vector
<char> kPTUpCommand
=
66 {0x81, 0x01, 0x06, 0x01, 0x05, 0x05, 0x03, 0x01, 0xFF};
68 // Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x03, 0x02, 0xFF}, X = 1 to 7:
69 // target device address; p: pan speed; t: tilt speed.
70 const std::vector
<char> kPTDownCommand
=
71 {0x81, 0x01, 0x06, 0x01, 0x05, 0x05, 0x03, 0x02, 0xFF};
73 // Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x0, 0x03, 0xFF}, X = 1 to 7:
74 // target device address; p: pan speed; t: tilt speed.
75 const std::vector
<char> kPTLeftCommand
=
76 {0x81, 0x01, 0x06, 0x01, 0x05, 0x05, 0x01, 0x03, 0xFF};
78 // Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x02, 0x03, 0xFF}, X = 1 to 7:
79 // target device address; p: pan speed; t: tilt speed.
80 const std::vector
<char> kPTRightCommand
=
81 {0x81, 0x01, 0x06, 0x01, 0x05, 0x05, 0x02, 0x03, 0xFF};
83 // Command: {0x8X, 0x01, 0x06, 0x01, 0x03, 0x03, 0x03, 0x03, 0xFF}, X = 1 to 7:
84 // target device address.
85 const std::vector
<char> kPTStopCommand
=
86 {0x81, 0x01, 0x06, 0x01, 0x03, 0x03, 0x03, 0x03, 0xFF};
90 namespace extensions
{
92 ViscaWebcam::ViscaWebcam(const std::string
& path
,
93 const std::string
& extension_id
)
95 extension_id_(extension_id
),
98 weak_ptr_factory_(this) {
101 ViscaWebcam::~ViscaWebcam() {
104 void ViscaWebcam::Open(const OpenCompleteCallback
& open_callback
) {
105 BrowserThread::PostTask(
106 BrowserThread::IO
, FROM_HERE
,
107 base::Bind(&ViscaWebcam::OpenOnIOThread
, weak_ptr_factory_
.GetWeakPtr(),
111 void ViscaWebcam::OpenOnIOThread(const OpenCompleteCallback
& open_callback
) {
112 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
114 api::serial::ConnectionOptions options
;
116 // Set the receive buffer size to receive the response data 1 by 1.
117 options
.buffer_size
.reset(new int(1));
118 options
.persistent
.reset(new bool(false));
119 options
.bitrate
.reset(new int(9600));
120 options
.cts_flow_control
.reset(new bool(false));
121 options
.receive_timeout
.reset(new int(0));
122 options
.send_timeout
.reset(new int(0));
123 options
.data_bits
= api::serial::DATA_BITS_EIGHT
;
124 options
.parity_bit
= api::serial::PARITY_BIT_NO
;
125 options
.stop_bits
= api::serial::STOP_BITS_ONE
;
127 serial_connection_
.reset(new SerialConnection(path_
, extension_id_
));
128 serial_connection_
->Open(
129 options
, base::Bind(&ViscaWebcam::OnConnected
,
130 weak_ptr_factory_
.GetWeakPtr(), open_callback
));
133 void ViscaWebcam::OnConnected(const OpenCompleteCallback
& open_callback
,
136 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
137 base::Bind(open_callback
, false));
139 Send(kSetAddressCommand
,
140 base::Bind(&ViscaWebcam::OnAddressSetCompleted
,
141 weak_ptr_factory_
.GetWeakPtr(), open_callback
));
145 void ViscaWebcam::OnAddressSetCompleted(
146 const OpenCompleteCallback
& open_callback
,
148 const std::vector
<char>& response
) {
150 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
151 base::Bind(open_callback
, false));
153 Send(kClearAllCommand
,
154 base::Bind(&ViscaWebcam::OnClearAllCompleted
,
155 weak_ptr_factory_
.GetWeakPtr(), open_callback
));
159 void ViscaWebcam::OnClearAllCompleted(const OpenCompleteCallback
& open_callback
,
161 const std::vector
<char>& response
) {
163 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
164 base::Bind(open_callback
, false));
166 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
167 base::Bind(open_callback
, true));
168 // Get the current pan and tilt position to initilize |pan| and |tilt|.
170 Send(kGetPanTiltCommand
,
171 base::Bind(&ViscaWebcam::OnCommandCompleted
,
172 weak_ptr_factory_
.GetWeakPtr(), INQUIRY_PAN_TILT
, &value
));
176 void ViscaWebcam::Send(const std::vector
<char>& command
,
177 const CommandCompleteCallback
& callback
) {
178 if (!commands_
.empty() ||
179 !serial_connection_
->Send(
180 command
, base::Bind(&ViscaWebcam::OnSendCompleted
,
181 weak_ptr_factory_
.GetWeakPtr(), callback
))) {
182 commands_
.push_back(std::make_pair(command
, callback
));
186 void ViscaWebcam::OnSendCompleted(const CommandCompleteCallback
& callback
,
188 api::serial::SendError error
) {
189 if (error
== api::serial::SEND_ERROR_NONE
) {
190 ReceiveLoop(callback
);
192 const std::vector
<char> response
;
193 callback
.Run(false, response
);
197 void ViscaWebcam::ReceiveLoop(const CommandCompleteCallback
& callback
) {
198 serial_connection_
->Receive(base::Bind(&ViscaWebcam::OnReceiveCompleted
,
199 weak_ptr_factory_
.GetWeakPtr(),
203 void ViscaWebcam::OnReceiveCompleted(const CommandCompleteCallback
& callback
,
204 const std::vector
<char>& data
,
205 api::serial::ReceiveError error
) {
206 data_buffer_
.insert(data_buffer_
.end(), data
.begin(), data
.end());
208 if (error
== api::serial::RECEIVE_ERROR_NONE
) {
209 // Loop until encounter the terminator.
210 if (int(data_buffer_
.back()) != VISCA_TERMINATOR
) {
211 base::MessageLoop::current()->PostTask(
212 FROM_HERE
, base::Bind(&ViscaWebcam::ReceiveLoop
,
213 weak_ptr_factory_
.GetWeakPtr(), callback
));
215 // Clear |data_buffer_|.
216 std::vector
<char> response
;
217 response
.swap(data_buffer_
);
219 if ((int(response
[1]) & 0xF0) == VISCA_RESPONSE_ERROR
) {
220 callback
.Run(false, response
);
221 } else if ((int(response
[1]) & 0xF0) != VISCA_RESPONSE_ACK
&&
222 (int(response
[1]) & 0xFF) != VISCA_RESPONSE_NETWORK_CHANGE
) {
223 callback
.Run(true, response
);
225 base::MessageLoop::current()->PostTask(
226 FROM_HERE
, base::Bind(&ViscaWebcam::ReceiveLoop
,
227 weak_ptr_factory_
.GetWeakPtr(), callback
));
231 // Clear |data_buffer_|.
232 std::vector
<char> response
;
233 response
.swap(data_buffer_
);
234 callback
.Run(false, response
);
238 void ViscaWebcam::OnCommandCompleted(CommandType type
,
241 const std::vector
<char>& response
) {
242 // TODO(xdai): Error handling according to |response|.
250 pan_
= ((int(response
[2]) & 0x0F) << 12) +
251 ((int(response
[3]) & 0x0F) << 8) +
252 ((int(response
[4]) & 0x0F) << 4) + (int(response
[5]) & 0x0F);
256 tilt_
= ((int(response
[6]) & 0x0F) << 12) +
257 ((int(response
[7]) & 0x0F) << 8) +
258 ((int(response
[8]) & 0x0F) << 4) + (int(response
[9]) & 0x0F);
261 case INQUIRY_PAN_TILT
:
262 pan_
= ((int(response
[2]) & 0x0F) << 12) +
263 ((int(response
[3]) & 0x0F) << 8) +
264 ((int(response
[4]) & 0x0F) << 4) + (int(response
[5]) & 0x0F);
265 tilt_
= ((int(response
[6]) & 0x0F) << 12) +
266 ((int(response
[7]) & 0x0F) << 8) +
267 ((int(response
[8]) & 0x0F) << 4) + (int(response
[9]) & 0x0F);
270 *value
= ((int(response
[2]) & 0x0F) << 12) +
271 ((int(response
[3]) & 0x0F) << 8) +
272 ((int(response
[4]) & 0x0F) << 4) + (int(response
[5]) & 0x0F);
276 // If there are pending commands, process the next one.
277 if (!commands_
.empty()) {
278 const std::vector
<char> command
= commands_
.front().first
;
279 const CommandCompleteCallback callback
= commands_
.front().second
;
280 commands_
.pop_front();
281 serial_connection_
->Send(
282 command
, base::Bind(&ViscaWebcam::OnSendCompleted
,
283 weak_ptr_factory_
.GetWeakPtr(), callback
));
287 void ViscaWebcam::Reset(bool pan
, bool tilt
, bool zoom
) {
289 // pan and tilt are always reset together in Visca Webcams.
291 Send(kResetPanTiltCommand
,
292 base::Bind(&ViscaWebcam::OnCommandCompleted
,
293 weak_ptr_factory_
.GetWeakPtr(), COMMAND
, &value
));
296 const int default_zoom
= 1;
297 SetZoom(default_zoom
);
301 bool ViscaWebcam::GetPan(int* value
) {
302 Send(kGetPanTiltCommand
,
303 base::Bind(&ViscaWebcam::OnCommandCompleted
,
304 weak_ptr_factory_
.GetWeakPtr(), INQUIRY_PAN
, value
));
308 bool ViscaWebcam::GetTilt(int* value
) {
309 Send(kGetPanTiltCommand
,
310 base::Bind(&ViscaWebcam::OnCommandCompleted
,
311 weak_ptr_factory_
.GetWeakPtr(), INQUIRY_TILT
, value
));
315 bool ViscaWebcam::GetZoom(int* value
) {
316 Send(kGetZoomCommand
,
317 base::Bind(&ViscaWebcam::OnCommandCompleted
,
318 weak_ptr_factory_
.GetWeakPtr(), INQUIRY_ZOOM
, value
));
322 bool ViscaWebcam::SetPan(int value
) {
324 std::vector
<char> command
= kSetPanTiltCommand
;
325 command
[6] |= ((pan_
& 0xF000) >> 12);
326 command
[7] |= ((pan_
& 0x0F00) >> 8);
327 command
[8] |= ((pan_
& 0x00F0) >> 4);
328 command
[9] |= (pan_
& 0x000F);
329 command
[10] |= ((tilt_
& 0xF000) >> 12);
330 command
[11] |= ((tilt_
& 0x0F00) >> 8);
331 command
[12] |= ((tilt_
& 0x00F0) >> 4);
332 command
[13] |= (tilt_
& 0x000F);
333 Send(command
, base::Bind(&ViscaWebcam::OnCommandCompleted
,
334 weak_ptr_factory_
.GetWeakPtr(), COMMAND
, &value
));
338 bool ViscaWebcam::SetTilt(int value
) {
340 std::vector
<char> command
= kSetPanTiltCommand
;
341 command
[6] |= ((pan_
& 0xF000) >> 12);
342 command
[7] |= ((pan_
& 0x0F00) >> 8);
343 command
[8] |= ((pan_
& 0x00F0) >> 4);
344 command
[9] |= (pan_
& 0x000F);
345 command
[10] |= ((tilt_
& 0xF000) >> 12);
346 command
[11] |= ((tilt_
& 0x0F00) >> 8);
347 command
[12] |= ((tilt_
& 0x00F0) >> 4);
348 command
[13] |= (tilt_
& 0x000F);
349 Send(command
, base::Bind(&ViscaWebcam::OnCommandCompleted
,
350 weak_ptr_factory_
.GetWeakPtr(), COMMAND
, &value
));
354 bool ViscaWebcam::SetZoom(int value
) {
355 std::vector
<char> command
= kSetZoomCommand
;
356 command
[4] |= ((value
& 0xF000) >> 12);
357 command
[5] |= ((value
& 0x0F00) >> 8);
358 command
[6] |= ((value
& 0x00F0) >> 4);
359 command
[7] |= (value
& 0x000F);
360 Send(command
, base::Bind(&ViscaWebcam::OnCommandCompleted
,
361 weak_ptr_factory_
.GetWeakPtr(), COMMAND
, &value
));
365 bool ViscaWebcam::SetPanDirection(PanDirection direction
) {
366 std::vector
<char> command
= kPTStopCommand
;
371 command
= kPTRightCommand
;
374 command
= kPTLeftCommand
;
377 Send(command
, base::Bind(&ViscaWebcam::OnCommandCompleted
,
378 weak_ptr_factory_
.GetWeakPtr(), COMMAND
, &pan_
));
382 bool ViscaWebcam::SetTiltDirection(TiltDirection direction
) {
383 std::vector
<char> command
= kPTStopCommand
;
388 command
= kPTUpCommand
;
391 command
= kPTDownCommand
;
394 Send(command
, base::Bind(&ViscaWebcam::OnCommandCompleted
,
395 weak_ptr_factory_
.GetWeakPtr(), COMMAND
, &tilt_
));
399 } // namespace extensions