Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / serial / serial_api.cc
blobde70d1ad1395362af81382c84cbf883cc6b10d8b
1 // Copyright 2014 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/serial/serial_api.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/values.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "device/serial/serial_device_enumerator.h"
13 #include "extensions/browser/api/serial/serial_connection.h"
14 #include "extensions/browser/api/serial/serial_event_dispatcher.h"
15 #include "extensions/common/api/serial.h"
17 using content::BrowserThread;
19 namespace extensions {
21 namespace api {
23 namespace {
25 // It's a fool's errand to come up with a default bitrate, because we don't get
26 // to control both sides of the communication. Unless the other side has
27 // implemented auto-bitrate detection (rare), if we pick the wrong rate, then
28 // you're gonna have a bad time. Close doesn't count.
30 // But we'd like to pick something that has a chance of working, and 9600 is a
31 // good balance between popularity and speed. So 9600 it is.
32 const int kDefaultBufferSize = 4096;
33 const int kDefaultBitrate = 9600;
34 const serial::DataBits kDefaultDataBits = serial::DATA_BITS_EIGHT;
35 const serial::ParityBit kDefaultParityBit = serial::PARITY_BIT_NO;
36 const serial::StopBits kDefaultStopBits = serial::STOP_BITS_ONE;
37 const int kDefaultReceiveTimeout = 0;
38 const int kDefaultSendTimeout = 0;
40 const char kErrorConnectFailed[] = "Failed to connect to the port.";
41 const char kErrorSerialConnectionNotFound[] = "Serial connection not found.";
42 const char kErrorGetControlSignalsFailed[] = "Failed to get control signals.";
44 template <class T>
45 void SetDefaultScopedPtrValue(scoped_ptr<T>& ptr, const T& value) {
46 if (!ptr.get())
47 ptr.reset(new T(value));
50 } // namespace
52 SerialAsyncApiFunction::SerialAsyncApiFunction() : manager_(NULL) {
55 SerialAsyncApiFunction::~SerialAsyncApiFunction() {
58 bool SerialAsyncApiFunction::PrePrepare() {
59 manager_ = ApiResourceManager<SerialConnection>::Get(browser_context());
60 DCHECK(manager_);
61 return true;
64 bool SerialAsyncApiFunction::Respond() {
65 return error_.empty();
68 SerialConnection* SerialAsyncApiFunction::GetSerialConnection(
69 int api_resource_id) {
70 return manager_->Get(extension_->id(), api_resource_id);
73 void SerialAsyncApiFunction::RemoveSerialConnection(int api_resource_id) {
74 manager_->Remove(extension_->id(), api_resource_id);
77 SerialGetDevicesFunction::SerialGetDevicesFunction() {
80 bool SerialGetDevicesFunction::Prepare() {
81 set_work_thread_id(BrowserThread::FILE);
82 return true;
85 void SerialGetDevicesFunction::Work() {
86 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
88 scoped_ptr<device::SerialDeviceEnumerator> enumerator =
89 device::SerialDeviceEnumerator::Create();
90 mojo::Array<device::serial::DeviceInfoPtr> devices = enumerator->GetDevices();
91 results_ = serial::GetDevices::Results::Create(
92 devices.To<std::vector<linked_ptr<serial::DeviceInfo> > >());
95 SerialConnectFunction::SerialConnectFunction() {
98 SerialConnectFunction::~SerialConnectFunction() {
101 bool SerialConnectFunction::Prepare() {
102 params_ = serial::Connect::Params::Create(*args_);
103 EXTENSION_FUNCTION_VALIDATE(params_.get());
105 // Fill in any omitted options to ensure a known initial configuration.
106 if (!params_->options.get())
107 params_->options.reset(new serial::ConnectionOptions());
108 serial::ConnectionOptions* options = params_->options.get();
110 SetDefaultScopedPtrValue(options->persistent, false);
111 SetDefaultScopedPtrValue(options->buffer_size, kDefaultBufferSize);
112 SetDefaultScopedPtrValue(options->bitrate, kDefaultBitrate);
113 SetDefaultScopedPtrValue(options->cts_flow_control, false);
114 SetDefaultScopedPtrValue(options->receive_timeout, kDefaultReceiveTimeout);
115 SetDefaultScopedPtrValue(options->send_timeout, kDefaultSendTimeout);
117 if (options->data_bits == serial::DATA_BITS_NONE)
118 options->data_bits = kDefaultDataBits;
119 if (options->parity_bit == serial::PARITY_BIT_NONE)
120 options->parity_bit = kDefaultParityBit;
121 if (options->stop_bits == serial::STOP_BITS_NONE)
122 options->stop_bits = kDefaultStopBits;
124 serial_event_dispatcher_ = SerialEventDispatcher::Get(browser_context());
125 DCHECK(serial_event_dispatcher_);
127 return true;
130 void SerialConnectFunction::AsyncWorkStart() {
131 DCHECK_CURRENTLY_ON(BrowserThread::IO);
132 connection_ = CreateSerialConnection(params_->path, extension_->id());
133 connection_->Open(*params_->options.get(),
134 base::Bind(&SerialConnectFunction::OnConnected, this));
137 void SerialConnectFunction::OnConnected(bool success) {
138 DCHECK(connection_);
140 if (!success) {
141 delete connection_;
142 connection_ = NULL;
145 BrowserThread::PostTask(
146 BrowserThread::IO,
147 FROM_HERE,
148 base::Bind(&SerialConnectFunction::FinishConnect, this));
151 void SerialConnectFunction::FinishConnect() {
152 DCHECK_CURRENTLY_ON(BrowserThread::IO);
153 if (!connection_) {
154 error_ = kErrorConnectFailed;
155 } else {
156 int id = manager_->Add(connection_);
157 serial::ConnectionInfo info;
158 info.connection_id = id;
159 if (connection_->GetInfo(&info)) {
160 serial_event_dispatcher_->PollConnection(extension_->id(), id);
161 results_ = serial::Connect::Results::Create(info);
162 } else {
163 RemoveSerialConnection(id);
164 error_ = kErrorConnectFailed;
167 AsyncWorkCompleted();
170 SerialConnection* SerialConnectFunction::CreateSerialConnection(
171 const std::string& port,
172 const std::string& extension_id) const {
173 return new SerialConnection(port, extension_id);
176 SerialUpdateFunction::SerialUpdateFunction() {
179 SerialUpdateFunction::~SerialUpdateFunction() {
182 bool SerialUpdateFunction::Prepare() {
183 params_ = serial::Update::Params::Create(*args_);
184 EXTENSION_FUNCTION_VALIDATE(params_.get());
186 return true;
189 void SerialUpdateFunction::Work() {
190 SerialConnection* connection = GetSerialConnection(params_->connection_id);
191 if (!connection) {
192 error_ = kErrorSerialConnectionNotFound;
193 return;
195 bool success = connection->Configure(params_->options);
196 results_ = serial::Update::Results::Create(success);
199 SerialDisconnectFunction::SerialDisconnectFunction() {
202 SerialDisconnectFunction::~SerialDisconnectFunction() {
205 bool SerialDisconnectFunction::Prepare() {
206 params_ = serial::Disconnect::Params::Create(*args_);
207 EXTENSION_FUNCTION_VALIDATE(params_.get());
209 return true;
212 void SerialDisconnectFunction::Work() {
213 SerialConnection* connection = GetSerialConnection(params_->connection_id);
214 if (!connection) {
215 error_ = kErrorSerialConnectionNotFound;
216 return;
218 RemoveSerialConnection(params_->connection_id);
219 results_ = serial::Disconnect::Results::Create(true);
222 SerialSendFunction::SerialSendFunction() {
225 SerialSendFunction::~SerialSendFunction() {
228 bool SerialSendFunction::Prepare() {
229 params_ = serial::Send::Params::Create(*args_);
230 EXTENSION_FUNCTION_VALIDATE(params_.get());
232 return true;
235 void SerialSendFunction::AsyncWorkStart() {
236 SerialConnection* connection = GetSerialConnection(params_->connection_id);
237 if (!connection) {
238 error_ = kErrorSerialConnectionNotFound;
239 AsyncWorkCompleted();
240 return;
243 if (!connection->Send(
244 params_->data,
245 base::Bind(&SerialSendFunction::OnSendComplete, this))) {
246 OnSendComplete(0, serial::SEND_ERROR_PENDING);
250 void SerialSendFunction::OnSendComplete(int bytes_sent,
251 serial::SendError error) {
252 serial::SendInfo send_info;
253 send_info.bytes_sent = bytes_sent;
254 send_info.error = error;
255 results_ = serial::Send::Results::Create(send_info);
256 AsyncWorkCompleted();
259 SerialFlushFunction::SerialFlushFunction() {
262 SerialFlushFunction::~SerialFlushFunction() {
265 bool SerialFlushFunction::Prepare() {
266 params_ = serial::Flush::Params::Create(*args_);
267 EXTENSION_FUNCTION_VALIDATE(params_.get());
268 return true;
271 void SerialFlushFunction::Work() {
272 SerialConnection* connection = GetSerialConnection(params_->connection_id);
273 if (!connection) {
274 error_ = kErrorSerialConnectionNotFound;
275 return;
278 bool success = connection->Flush();
279 results_ = serial::Flush::Results::Create(success);
282 SerialSetPausedFunction::SerialSetPausedFunction() {
285 SerialSetPausedFunction::~SerialSetPausedFunction() {
288 bool SerialSetPausedFunction::Prepare() {
289 params_ = serial::SetPaused::Params::Create(*args_);
290 EXTENSION_FUNCTION_VALIDATE(params_.get());
292 serial_event_dispatcher_ = SerialEventDispatcher::Get(browser_context());
293 DCHECK(serial_event_dispatcher_);
294 return true;
297 void SerialSetPausedFunction::Work() {
298 SerialConnection* connection = GetSerialConnection(params_->connection_id);
299 if (!connection) {
300 error_ = kErrorSerialConnectionNotFound;
301 return;
304 if (params_->paused != connection->paused()) {
305 connection->set_paused(params_->paused);
306 if (!params_->paused) {
307 serial_event_dispatcher_->PollConnection(extension_->id(),
308 params_->connection_id);
312 results_ = serial::SetPaused::Results::Create();
315 SerialGetInfoFunction::SerialGetInfoFunction() {
318 SerialGetInfoFunction::~SerialGetInfoFunction() {
321 bool SerialGetInfoFunction::Prepare() {
322 params_ = serial::GetInfo::Params::Create(*args_);
323 EXTENSION_FUNCTION_VALIDATE(params_.get());
325 return true;
328 void SerialGetInfoFunction::Work() {
329 SerialConnection* connection = GetSerialConnection(params_->connection_id);
330 if (!connection) {
331 error_ = kErrorSerialConnectionNotFound;
332 return;
335 serial::ConnectionInfo info;
336 info.connection_id = params_->connection_id;
337 connection->GetInfo(&info);
338 results_ = serial::GetInfo::Results::Create(info);
341 SerialGetConnectionsFunction::SerialGetConnectionsFunction() {
344 SerialGetConnectionsFunction::~SerialGetConnectionsFunction() {
347 bool SerialGetConnectionsFunction::Prepare() {
348 return true;
351 void SerialGetConnectionsFunction::Work() {
352 std::vector<linked_ptr<serial::ConnectionInfo> > infos;
353 const base::hash_set<int>* connection_ids =
354 manager_->GetResourceIds(extension_->id());
355 if (connection_ids) {
356 for (base::hash_set<int>::const_iterator it = connection_ids->begin();
357 it != connection_ids->end();
358 ++it) {
359 int connection_id = *it;
360 SerialConnection* connection = GetSerialConnection(connection_id);
361 if (connection) {
362 linked_ptr<serial::ConnectionInfo> info(new serial::ConnectionInfo());
363 info->connection_id = connection_id;
364 connection->GetInfo(info.get());
365 infos.push_back(info);
369 results_ = serial::GetConnections::Results::Create(infos);
372 SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() {
375 SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() {
378 bool SerialGetControlSignalsFunction::Prepare() {
379 params_ = serial::GetControlSignals::Params::Create(*args_);
380 EXTENSION_FUNCTION_VALIDATE(params_.get());
382 return true;
385 void SerialGetControlSignalsFunction::Work() {
386 SerialConnection* connection = GetSerialConnection(params_->connection_id);
387 if (!connection) {
388 error_ = kErrorSerialConnectionNotFound;
389 return;
392 serial::DeviceControlSignals signals;
393 if (!connection->GetControlSignals(&signals)) {
394 error_ = kErrorGetControlSignalsFailed;
395 return;
398 results_ = serial::GetControlSignals::Results::Create(signals);
401 SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() {
404 SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() {
407 bool SerialSetControlSignalsFunction::Prepare() {
408 params_ = serial::SetControlSignals::Params::Create(*args_);
409 EXTENSION_FUNCTION_VALIDATE(params_.get());
411 return true;
414 void SerialSetControlSignalsFunction::Work() {
415 SerialConnection* connection = GetSerialConnection(params_->connection_id);
416 if (!connection) {
417 error_ = kErrorSerialConnectionNotFound;
418 return;
421 bool success = connection->SetControlSignals(params_->signals);
422 results_ = serial::SetControlSignals::Results::Create(success);
425 SerialSetBreakFunction::SerialSetBreakFunction() {
428 SerialSetBreakFunction::~SerialSetBreakFunction() {
431 bool SerialSetBreakFunction::Prepare() {
432 params_ = serial::SetBreak::Params::Create(*args_);
433 EXTENSION_FUNCTION_VALIDATE(params_.get());
435 return true;
438 void SerialSetBreakFunction::Work() {
439 SerialConnection* connection = GetSerialConnection(params_->connection_id);
440 if (!connection) {
441 error_ = kErrorSerialConnectionNotFound;
442 return;
444 bool success = connection->SetBreak();
445 results_ = serial::SetBreak::Results::Create(success);
448 SerialClearBreakFunction::SerialClearBreakFunction() {
451 SerialClearBreakFunction::~SerialClearBreakFunction() {
454 bool SerialClearBreakFunction::Prepare() {
455 params_ = serial::ClearBreak::Params::Create(*args_);
456 EXTENSION_FUNCTION_VALIDATE(params_.get());
458 return true;
461 void SerialClearBreakFunction::Work() {
462 SerialConnection* connection = GetSerialConnection(params_->connection_id);
463 if (!connection) {
464 error_ = kErrorSerialConnectionNotFound;
465 return;
468 bool success = connection->ClearBreak();
469 results_ = serial::ClearBreak::Results::Create(success);
472 } // namespace api
474 } // namespace extensions
476 namespace mojo {
478 // static
479 linked_ptr<extensions::api::serial::DeviceInfo> TypeConverter<
480 linked_ptr<extensions::api::serial::DeviceInfo>,
481 device::serial::DeviceInfoPtr>::Convert(const device::serial::DeviceInfoPtr&
482 device) {
483 linked_ptr<extensions::api::serial::DeviceInfo> info(
484 new extensions::api::serial::DeviceInfo);
485 info->path = device->path;
486 if (device->has_vendor_id)
487 info->vendor_id.reset(new int(static_cast<int>(device->vendor_id)));
488 if (device->has_product_id)
489 info->product_id.reset(new int(static_cast<int>(device->product_id)));
490 if (device->display_name)
491 info->display_name.reset(new std::string(device->display_name));
492 return info;
495 } // namespace mojo