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"
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
{
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.";
45 void SetDefaultScopedPtrValue(scoped_ptr
<T
>& ptr
, const T
& value
) {
47 ptr
.reset(new T(value
));
52 SerialAsyncApiFunction::SerialAsyncApiFunction() : manager_(NULL
) {
55 SerialAsyncApiFunction::~SerialAsyncApiFunction() {
58 bool SerialAsyncApiFunction::PrePrepare() {
59 manager_
= ApiResourceManager
<SerialConnection
>::Get(browser_context());
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);
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_
);
130 void SerialConnectFunction::AsyncWorkStart() {
131 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
132 connection_
= CreateSerialConnection(params_
->path
, extension_
->id());
133 connection_
->Open(base::Bind(&SerialConnectFunction::OnConnected
, this));
136 void SerialConnectFunction::OnConnected(bool success
) {
140 if (!connection_
->Configure(*params_
->options
.get())) {
149 BrowserThread::PostTask(
152 base::Bind(&SerialConnectFunction::FinishConnect
, this));
155 void SerialConnectFunction::FinishConnect() {
156 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
158 error_
= kErrorConnectFailed
;
160 int id
= manager_
->Add(connection_
);
161 serial::ConnectionInfo info
;
162 info
.connection_id
= id
;
163 if (connection_
->GetInfo(&info
)) {
164 serial_event_dispatcher_
->PollConnection(extension_
->id(), id
);
165 results_
= serial::Connect::Results::Create(info
);
167 RemoveSerialConnection(id
);
168 error_
= kErrorConnectFailed
;
171 AsyncWorkCompleted();
174 SerialConnection
* SerialConnectFunction::CreateSerialConnection(
175 const std::string
& port
,
176 const std::string
& extension_id
) const {
177 return new SerialConnection(port
, extension_id
);
180 SerialUpdateFunction::SerialUpdateFunction() {
183 SerialUpdateFunction::~SerialUpdateFunction() {
186 bool SerialUpdateFunction::Prepare() {
187 params_
= serial::Update::Params::Create(*args_
);
188 EXTENSION_FUNCTION_VALIDATE(params_
.get());
193 void SerialUpdateFunction::Work() {
194 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
196 error_
= kErrorSerialConnectionNotFound
;
199 bool success
= connection
->Configure(params_
->options
);
200 results_
= serial::Update::Results::Create(success
);
203 SerialDisconnectFunction::SerialDisconnectFunction() {
206 SerialDisconnectFunction::~SerialDisconnectFunction() {
209 bool SerialDisconnectFunction::Prepare() {
210 params_
= serial::Disconnect::Params::Create(*args_
);
211 EXTENSION_FUNCTION_VALIDATE(params_
.get());
216 void SerialDisconnectFunction::Work() {
217 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
219 error_
= kErrorSerialConnectionNotFound
;
222 RemoveSerialConnection(params_
->connection_id
);
223 results_
= serial::Disconnect::Results::Create(true);
226 SerialSendFunction::SerialSendFunction() {
229 SerialSendFunction::~SerialSendFunction() {
232 bool SerialSendFunction::Prepare() {
233 params_
= serial::Send::Params::Create(*args_
);
234 EXTENSION_FUNCTION_VALIDATE(params_
.get());
239 void SerialSendFunction::AsyncWorkStart() {
240 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
242 error_
= kErrorSerialConnectionNotFound
;
243 AsyncWorkCompleted();
247 if (!connection
->Send(
249 base::Bind(&SerialSendFunction::OnSendComplete
, this))) {
250 OnSendComplete(0, serial::SEND_ERROR_PENDING
);
254 void SerialSendFunction::OnSendComplete(int bytes_sent
,
255 serial::SendError error
) {
256 serial::SendInfo send_info
;
257 send_info
.bytes_sent
= bytes_sent
;
258 send_info
.error
= error
;
259 results_
= serial::Send::Results::Create(send_info
);
260 AsyncWorkCompleted();
263 SerialFlushFunction::SerialFlushFunction() {
266 SerialFlushFunction::~SerialFlushFunction() {
269 bool SerialFlushFunction::Prepare() {
270 params_
= serial::Flush::Params::Create(*args_
);
271 EXTENSION_FUNCTION_VALIDATE(params_
.get());
275 void SerialFlushFunction::Work() {
276 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
278 error_
= kErrorSerialConnectionNotFound
;
282 bool success
= connection
->Flush();
283 results_
= serial::Flush::Results::Create(success
);
286 SerialSetPausedFunction::SerialSetPausedFunction() {
289 SerialSetPausedFunction::~SerialSetPausedFunction() {
292 bool SerialSetPausedFunction::Prepare() {
293 params_
= serial::SetPaused::Params::Create(*args_
);
294 EXTENSION_FUNCTION_VALIDATE(params_
.get());
296 serial_event_dispatcher_
= SerialEventDispatcher::Get(browser_context());
297 DCHECK(serial_event_dispatcher_
);
301 void SerialSetPausedFunction::Work() {
302 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
304 error_
= kErrorSerialConnectionNotFound
;
308 if (params_
->paused
!= connection
->paused()) {
309 connection
->set_paused(params_
->paused
);
310 if (!params_
->paused
) {
311 serial_event_dispatcher_
->PollConnection(extension_
->id(),
312 params_
->connection_id
);
316 results_
= serial::SetPaused::Results::Create();
319 SerialGetInfoFunction::SerialGetInfoFunction() {
322 SerialGetInfoFunction::~SerialGetInfoFunction() {
325 bool SerialGetInfoFunction::Prepare() {
326 params_
= serial::GetInfo::Params::Create(*args_
);
327 EXTENSION_FUNCTION_VALIDATE(params_
.get());
332 void SerialGetInfoFunction::Work() {
333 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
335 error_
= kErrorSerialConnectionNotFound
;
339 serial::ConnectionInfo info
;
340 info
.connection_id
= params_
->connection_id
;
341 connection
->GetInfo(&info
);
342 results_
= serial::GetInfo::Results::Create(info
);
345 SerialGetConnectionsFunction::SerialGetConnectionsFunction() {
348 SerialGetConnectionsFunction::~SerialGetConnectionsFunction() {
351 bool SerialGetConnectionsFunction::Prepare() {
355 void SerialGetConnectionsFunction::Work() {
356 std::vector
<linked_ptr
<serial::ConnectionInfo
> > infos
;
357 const base::hash_set
<int>* connection_ids
=
358 manager_
->GetResourceIds(extension_
->id());
359 if (connection_ids
) {
360 for (base::hash_set
<int>::const_iterator it
= connection_ids
->begin();
361 it
!= connection_ids
->end();
363 int connection_id
= *it
;
364 SerialConnection
* connection
= GetSerialConnection(connection_id
);
366 linked_ptr
<serial::ConnectionInfo
> info(new serial::ConnectionInfo());
367 info
->connection_id
= connection_id
;
368 connection
->GetInfo(info
.get());
369 infos
.push_back(info
);
373 results_
= serial::GetConnections::Results::Create(infos
);
376 SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() {
379 SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() {
382 bool SerialGetControlSignalsFunction::Prepare() {
383 params_
= serial::GetControlSignals::Params::Create(*args_
);
384 EXTENSION_FUNCTION_VALIDATE(params_
.get());
389 void SerialGetControlSignalsFunction::Work() {
390 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
392 error_
= kErrorSerialConnectionNotFound
;
396 serial::DeviceControlSignals signals
;
397 if (!connection
->GetControlSignals(&signals
)) {
398 error_
= kErrorGetControlSignalsFailed
;
402 results_
= serial::GetControlSignals::Results::Create(signals
);
405 SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() {
408 SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() {
411 bool SerialSetControlSignalsFunction::Prepare() {
412 params_
= serial::SetControlSignals::Params::Create(*args_
);
413 EXTENSION_FUNCTION_VALIDATE(params_
.get());
418 void SerialSetControlSignalsFunction::Work() {
419 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
421 error_
= kErrorSerialConnectionNotFound
;
425 bool success
= connection
->SetControlSignals(params_
->signals
);
426 results_
= serial::SetControlSignals::Results::Create(success
);
429 } // namespace core_api
431 } // namespace extensions
436 linked_ptr
<extensions::core_api::serial::DeviceInfo
> TypeConverter
<
437 linked_ptr
<extensions::core_api::serial::DeviceInfo
>,
438 device::serial::DeviceInfoPtr
>::Convert(const device::serial::DeviceInfoPtr
&
440 linked_ptr
<extensions::core_api::serial::DeviceInfo
> info(
441 new extensions::core_api::serial::DeviceInfo
);
442 info
->path
= device
->path
;
443 if (device
->has_vendor_id
)
444 info
->vendor_id
.reset(new int(static_cast<int>(device
->vendor_id
)));
445 if (device
->has_product_id
)
446 info
->product_id
.reset(new int(static_cast<int>(device
->product_id
)));
447 if (device
->display_name
)
448 info
->display_name
.reset(new std::string(device
->display_name
));