Add ICU message format support
[chromium-blink-merge.git] / extensions / browser / api / webcam_private / visca_webcam.cc
blob738d0447e78901c0e5be17b38e79defe5f05f175
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"
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/public/browser/browser_thread.h"
11 using content::BrowserThread;
13 namespace {
15 // Message terminator:
16 const char VISCA_TERMINATOR = 0xFF;
18 // Response types:
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};
88 } // namespace
90 namespace extensions {
92 ViscaWebcam::ViscaWebcam(const std::string& path,
93 const std::string& extension_id)
94 : path_(path),
95 extension_id_(extension_id),
96 pan_(0),
97 tilt_(0),
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(),
108 open_callback));
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,
134 bool success) {
135 if (!success) {
136 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
137 base::Bind(open_callback, false));
138 } else {
139 Send(kSetAddressCommand,
140 base::Bind(&ViscaWebcam::OnAddressSetCompleted,
141 weak_ptr_factory_.GetWeakPtr(), open_callback));
145 void ViscaWebcam::OnAddressSetCompleted(
146 const OpenCompleteCallback& open_callback,
147 bool success,
148 const std::vector<char>& response) {
149 if (!success) {
150 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
151 base::Bind(open_callback, false));
152 } else {
153 Send(kClearAllCommand,
154 base::Bind(&ViscaWebcam::OnClearAllCompleted,
155 weak_ptr_factory_.GetWeakPtr(), open_callback));
159 void ViscaWebcam::OnClearAllCompleted(const OpenCompleteCallback& open_callback,
160 bool success,
161 const std::vector<char>& response) {
162 if (!success) {
163 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
164 base::Bind(open_callback, false));
165 } else {
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|.
169 int value;
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,
187 int bytes_sent,
188 api::serial::SendError error) {
189 if (error == api::serial::SEND_ERROR_NONE) {
190 ReceiveLoop(callback);
191 } else {
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(),
200 callback));
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));
214 } else {
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);
224 } else {
225 base::MessageLoop::current()->PostTask(
226 FROM_HERE, base::Bind(&ViscaWebcam::ReceiveLoop,
227 weak_ptr_factory_.GetWeakPtr(), callback));
230 } else {
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,
239 int* value,
240 bool success,
241 const std::vector<char>& response) {
242 // TODO(xdai): Error handling according to |response|.
243 if (!success)
244 return;
246 switch (type) {
247 case COMMAND:
248 break;
249 case INQUIRY_PAN:
250 pan_ = ((int(response[2]) & 0x0F) << 12) +
251 ((int(response[3]) & 0x0F) << 8) +
252 ((int(response[4]) & 0x0F) << 4) + (int(response[5]) & 0x0F);
253 *value = pan_;
254 break;
255 case INQUIRY_TILT:
256 tilt_ = ((int(response[6]) & 0x0F) << 12) +
257 ((int(response[7]) & 0x0F) << 8) +
258 ((int(response[8]) & 0x0F) << 4) + (int(response[9]) & 0x0F);
259 *value = tilt_;
260 break;
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);
268 break;
269 case INQUIRY_ZOOM:
270 *value = ((int(response[2]) & 0x0F) << 12) +
271 ((int(response[3]) & 0x0F) << 8) +
272 ((int(response[4]) & 0x0F) << 4) + (int(response[5]) & 0x0F);
273 break;
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) {
288 int value;
289 // pan and tilt are always reset together in Visca Webcams.
290 if (pan || tilt) {
291 Send(kResetPanTiltCommand,
292 base::Bind(&ViscaWebcam::OnCommandCompleted,
293 weak_ptr_factory_.GetWeakPtr(), COMMAND, &value));
295 if (zoom) {
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));
305 return true;
308 bool ViscaWebcam::GetTilt(int* value) {
309 Send(kGetPanTiltCommand,
310 base::Bind(&ViscaWebcam::OnCommandCompleted,
311 weak_ptr_factory_.GetWeakPtr(), INQUIRY_TILT, value));
312 return true;
315 bool ViscaWebcam::GetZoom(int* value) {
316 Send(kGetZoomCommand,
317 base::Bind(&ViscaWebcam::OnCommandCompleted,
318 weak_ptr_factory_.GetWeakPtr(), INQUIRY_ZOOM, value));
319 return true;
322 bool ViscaWebcam::SetPan(int value) {
323 pan_ = 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));
335 return true;
338 bool ViscaWebcam::SetTilt(int value) {
339 tilt_ = 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));
351 return true;
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));
362 return true;
365 bool ViscaWebcam::SetPanDirection(PanDirection direction) {
366 std::vector<char> command = kPTStopCommand;
367 switch (direction) {
368 case PAN_STOP:
369 break;
370 case PAN_RIGHT:
371 command = kPTRightCommand;
372 break;
373 case PAN_LEFT:
374 command = kPTLeftCommand;
375 break;
377 Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
378 weak_ptr_factory_.GetWeakPtr(), COMMAND, &pan_));
379 return true;
382 bool ViscaWebcam::SetTiltDirection(TiltDirection direction) {
383 std::vector<char> command = kPTStopCommand;
384 switch (direction) {
385 case TILT_STOP:
386 break;
387 case TILT_UP:
388 command = kPTUpCommand;
389 break;
390 case TILT_DOWN:
391 command = kPTDownCommand;
392 break;
394 Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
395 weak_ptr_factory_.GetWeakPtr(), COMMAND, &tilt_));
396 return true;
399 } // namespace extensions