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(*params_
->options
.get(),
134 base::Bind(&SerialConnectFunction::OnConnected
, this));
137 void SerialConnectFunction::OnConnected(bool success
) {
145 BrowserThread::PostTask(
148 base::Bind(&SerialConnectFunction::FinishConnect
, this));
151 void SerialConnectFunction::FinishConnect() {
152 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
154 error_
= kErrorConnectFailed
;
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
);
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());
189 void SerialUpdateFunction::Work() {
190 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
192 error_
= kErrorSerialConnectionNotFound
;
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());
212 void SerialDisconnectFunction::Work() {
213 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
215 error_
= kErrorSerialConnectionNotFound
;
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());
235 void SerialSendFunction::AsyncWorkStart() {
236 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
238 error_
= kErrorSerialConnectionNotFound
;
239 AsyncWorkCompleted();
243 if (!connection
->Send(
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());
271 void SerialFlushFunction::Work() {
272 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
274 error_
= kErrorSerialConnectionNotFound
;
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_
);
297 void SerialSetPausedFunction::Work() {
298 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
300 error_
= kErrorSerialConnectionNotFound
;
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());
328 void SerialGetInfoFunction::Work() {
329 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
331 error_
= kErrorSerialConnectionNotFound
;
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() {
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();
359 int connection_id
= *it
;
360 SerialConnection
* connection
= GetSerialConnection(connection_id
);
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());
385 void SerialGetControlSignalsFunction::Work() {
386 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
388 error_
= kErrorSerialConnectionNotFound
;
392 serial::DeviceControlSignals signals
;
393 if (!connection
->GetControlSignals(&signals
)) {
394 error_
= kErrorGetControlSignalsFailed
;
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());
414 void SerialSetControlSignalsFunction::Work() {
415 SerialConnection
* connection
= GetSerialConnection(params_
->connection_id
);
417 error_
= kErrorSerialConnectionNotFound
;
421 bool success
= connection
->SetControlSignals(params_
->signals
);
422 results_
= serial::SetControlSignals::Results::Create(success
);
425 } // namespace core_api
427 } // namespace extensions
432 linked_ptr
<extensions::core_api::serial::DeviceInfo
> TypeConverter
<
433 linked_ptr
<extensions::core_api::serial::DeviceInfo
>,
434 device::serial::DeviceInfoPtr
>::Convert(const device::serial::DeviceInfoPtr
&
436 linked_ptr
<extensions::core_api::serial::DeviceInfo
> info(
437 new extensions::core_api::serial::DeviceInfo
);
438 info
->path
= device
->path
;
439 if (device
->has_vendor_id
)
440 info
->vendor_id
.reset(new int(static_cast<int>(device
->vendor_id
)));
441 if (device
->has_product_id
)
442 info
->product_id
.reset(new int(static_cast<int>(device
->product_id
)));
443 if (device
->display_name
)
444 info
->display_name
.reset(new std::string(device
->display_name
));