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_connection.h"
9 #include "base/files/file_path.h"
10 #include "base/lazy_instance.h"
11 #include "base/message_loop/message_loop.h"
12 #include "extensions/browser/api/api_resource_manager.h"
13 #include "extensions/common/api/serial.h"
15 namespace extensions
{
19 const int kDefaultBufferSize
= 4096;
21 core_api::serial::SendError
ConvertSendErrorFromMojo(
22 device::serial::SendError input
) {
24 case device::serial::SEND_ERROR_NONE
:
25 return core_api::serial::SEND_ERROR_NONE
;
26 case device::serial::SEND_ERROR_DISCONNECTED
:
27 return core_api::serial::SEND_ERROR_DISCONNECTED
;
28 case device::serial::SEND_ERROR_PENDING
:
29 return core_api::serial::SEND_ERROR_PENDING
;
30 case device::serial::SEND_ERROR_TIMEOUT
:
31 return core_api::serial::SEND_ERROR_TIMEOUT
;
32 case device::serial::SEND_ERROR_SYSTEM_ERROR
:
33 return core_api::serial::SEND_ERROR_SYSTEM_ERROR
;
35 return core_api::serial::SEND_ERROR_NONE
;
38 core_api::serial::ReceiveError
ConvertReceiveErrorFromMojo(
39 device::serial::ReceiveError input
) {
41 case device::serial::RECEIVE_ERROR_NONE
:
42 return core_api::serial::RECEIVE_ERROR_NONE
;
43 case device::serial::RECEIVE_ERROR_DISCONNECTED
:
44 return core_api::serial::RECEIVE_ERROR_DISCONNECTED
;
45 case device::serial::RECEIVE_ERROR_TIMEOUT
:
46 return core_api::serial::RECEIVE_ERROR_TIMEOUT
;
47 case device::serial::RECEIVE_ERROR_DEVICE_LOST
:
48 return core_api::serial::RECEIVE_ERROR_DEVICE_LOST
;
49 case device::serial::RECEIVE_ERROR_SYSTEM_ERROR
:
50 return core_api::serial::RECEIVE_ERROR_SYSTEM_ERROR
;
52 return core_api::serial::RECEIVE_ERROR_NONE
;
55 core_api::serial::DataBits
ConvertDataBitsFromMojo(
56 device::serial::DataBits input
) {
58 case device::serial::DATA_BITS_NONE
:
59 return core_api::serial::DATA_BITS_NONE
;
60 case device::serial::DATA_BITS_SEVEN
:
61 return core_api::serial::DATA_BITS_SEVEN
;
62 case device::serial::DATA_BITS_EIGHT
:
63 return core_api::serial::DATA_BITS_EIGHT
;
65 return core_api::serial::DATA_BITS_NONE
;
68 device::serial::DataBits
ConvertDataBitsToMojo(
69 core_api::serial::DataBits input
) {
71 case core_api::serial::DATA_BITS_NONE
:
72 return device::serial::DATA_BITS_NONE
;
73 case core_api::serial::DATA_BITS_SEVEN
:
74 return device::serial::DATA_BITS_SEVEN
;
75 case core_api::serial::DATA_BITS_EIGHT
:
76 return device::serial::DATA_BITS_EIGHT
;
78 return device::serial::DATA_BITS_NONE
;
81 core_api::serial::ParityBit
ConvertParityBitFromMojo(
82 device::serial::ParityBit input
) {
84 case device::serial::PARITY_BIT_NONE
:
85 return core_api::serial::PARITY_BIT_NONE
;
86 case device::serial::PARITY_BIT_ODD
:
87 return core_api::serial::PARITY_BIT_ODD
;
88 case device::serial::PARITY_BIT_NO
:
89 return core_api::serial::PARITY_BIT_NO
;
90 case device::serial::PARITY_BIT_EVEN
:
91 return core_api::serial::PARITY_BIT_EVEN
;
93 return core_api::serial::PARITY_BIT_NONE
;
96 device::serial::ParityBit
ConvertParityBitToMojo(
97 core_api::serial::ParityBit input
) {
99 case core_api::serial::PARITY_BIT_NONE
:
100 return device::serial::PARITY_BIT_NONE
;
101 case core_api::serial::PARITY_BIT_NO
:
102 return device::serial::PARITY_BIT_NO
;
103 case core_api::serial::PARITY_BIT_ODD
:
104 return device::serial::PARITY_BIT_ODD
;
105 case core_api::serial::PARITY_BIT_EVEN
:
106 return device::serial::PARITY_BIT_EVEN
;
108 return device::serial::PARITY_BIT_NONE
;
111 core_api::serial::StopBits
ConvertStopBitsFromMojo(
112 device::serial::StopBits input
) {
114 case device::serial::STOP_BITS_NONE
:
115 return core_api::serial::STOP_BITS_NONE
;
116 case device::serial::STOP_BITS_ONE
:
117 return core_api::serial::STOP_BITS_ONE
;
118 case device::serial::STOP_BITS_TWO
:
119 return core_api::serial::STOP_BITS_TWO
;
121 return core_api::serial::STOP_BITS_NONE
;
124 device::serial::StopBits
ConvertStopBitsToMojo(
125 core_api::serial::StopBits input
) {
127 case core_api::serial::STOP_BITS_NONE
:
128 return device::serial::STOP_BITS_NONE
;
129 case core_api::serial::STOP_BITS_ONE
:
130 return device::serial::STOP_BITS_ONE
;
131 case core_api::serial::STOP_BITS_TWO
:
132 return device::serial::STOP_BITS_TWO
;
134 return device::serial::STOP_BITS_NONE
;
137 class SendBuffer
: public device::ReadOnlyBuffer
{
140 const std::string
& data
,
141 const base::Callback
<void(int, device::serial::SendError
)>& callback
)
142 : data_(data
), callback_(callback
) {}
143 ~SendBuffer() override
{}
144 const char* GetData() override
{ return data_
.c_str(); }
145 uint32_t GetSize() override
{ return static_cast<uint32_t>(data_
.size()); }
146 void Done(uint32_t bytes_read
) override
{
147 callback_
.Run(bytes_read
, device::serial::SEND_ERROR_NONE
);
149 void DoneWithError(uint32_t bytes_read
, int32_t error
) override
{
150 callback_
.Run(bytes_read
, static_cast<device::serial::SendError
>(error
));
154 const std::string data_
;
155 const base::Callback
<void(int, device::serial::SendError
)> callback_
;
158 class ReceiveBuffer
: public device::WritableBuffer
{
161 scoped_refptr
<net::IOBuffer
> buffer
,
163 const base::Callback
<void(int, device::serial::ReceiveError
)>& callback
)
164 : buffer_(buffer
), size_(size
), callback_(callback
) {}
165 ~ReceiveBuffer() override
{}
166 char* GetData() override
{ return buffer_
->data(); }
167 uint32_t GetSize() override
{ return size_
; }
168 void Done(uint32_t bytes_written
) override
{
169 callback_
.Run(bytes_written
, device::serial::RECEIVE_ERROR_NONE
);
171 void DoneWithError(uint32_t bytes_written
, int32_t error
) override
{
172 callback_
.Run(bytes_written
,
173 static_cast<device::serial::ReceiveError
>(error
));
177 scoped_refptr
<net::IOBuffer
> buffer_
;
178 const uint32_t size_
;
179 const base::Callback
<void(int, device::serial::ReceiveError
)> callback_
;
184 static base::LazyInstance
<
185 BrowserContextKeyedAPIFactory
<ApiResourceManager
<SerialConnection
> > >
186 g_factory
= LAZY_INSTANCE_INITIALIZER
;
190 BrowserContextKeyedAPIFactory
<ApiResourceManager
<SerialConnection
> >*
191 ApiResourceManager
<SerialConnection
>::GetFactoryInstance() {
192 return g_factory
.Pointer();
195 SerialConnection::SerialConnection(const std::string
& port
,
196 const std::string
& owner_extension_id
)
197 : ApiResource(owner_extension_id
),
200 buffer_size_(kDefaultBufferSize
),
204 io_handler_(device::SerialIoHandler::Create(
205 content::BrowserThread::GetMessageLoopProxyForThread(
206 content::BrowserThread::FILE),
207 content::BrowserThread::GetMessageLoopProxyForThread(
208 content::BrowserThread::UI
))) {
209 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
212 SerialConnection::~SerialConnection() {
213 io_handler_
->CancelRead(device::serial::RECEIVE_ERROR_DISCONNECTED
);
214 io_handler_
->CancelWrite(device::serial::SEND_ERROR_DISCONNECTED
);
217 bool SerialConnection::IsPersistent() const {
221 void SerialConnection::set_buffer_size(int buffer_size
) {
222 buffer_size_
= buffer_size
;
225 void SerialConnection::set_receive_timeout(int receive_timeout
) {
226 receive_timeout_
= receive_timeout
;
229 void SerialConnection::set_send_timeout(int send_timeout
) {
230 send_timeout_
= send_timeout
;
233 void SerialConnection::set_paused(bool paused
) {
236 io_handler_
->CancelRead(device::serial::RECEIVE_ERROR_NONE
);
240 void SerialConnection::Open(const OpenCompleteCallback
& callback
) {
241 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
242 io_handler_
->Open(port_
, callback
);
245 bool SerialConnection::Receive(const ReceiveCompleteCallback
& callback
) {
246 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
247 if (!receive_complete_
.is_null())
249 receive_complete_
= callback
;
250 receive_buffer_
= new net::IOBuffer(buffer_size_
);
251 io_handler_
->Read(scoped_ptr
<device::WritableBuffer
>(new ReceiveBuffer(
254 base::Bind(&SerialConnection::OnAsyncReadComplete
, AsWeakPtr()))));
255 receive_timeout_task_
.reset();
256 if (receive_timeout_
> 0) {
257 receive_timeout_task_
.reset(new TimeoutTask(
258 base::Bind(&SerialConnection::OnReceiveTimeout
, AsWeakPtr()),
259 base::TimeDelta::FromMilliseconds(receive_timeout_
)));
264 bool SerialConnection::Send(const std::string
& data
,
265 const SendCompleteCallback
& callback
) {
266 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
267 if (!send_complete_
.is_null())
269 send_complete_
= callback
;
270 io_handler_
->Write(scoped_ptr
<device::ReadOnlyBuffer
>(new SendBuffer(
271 data
, base::Bind(&SerialConnection::OnAsyncWriteComplete
, AsWeakPtr()))));
272 send_timeout_task_
.reset();
273 if (send_timeout_
> 0) {
274 send_timeout_task_
.reset(new TimeoutTask(
275 base::Bind(&SerialConnection::OnSendTimeout
, AsWeakPtr()),
276 base::TimeDelta::FromMilliseconds(send_timeout_
)));
281 bool SerialConnection::Configure(
282 const core_api::serial::ConnectionOptions
& options
) {
283 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
284 if (options
.persistent
.get())
285 set_persistent(*options
.persistent
);
286 if (options
.name
.get())
287 set_name(*options
.name
);
288 if (options
.buffer_size
.get())
289 set_buffer_size(*options
.buffer_size
);
290 if (options
.receive_timeout
.get())
291 set_receive_timeout(*options
.receive_timeout
);
292 if (options
.send_timeout
.get())
293 set_send_timeout(*options
.send_timeout
);
294 bool success
= io_handler_
->ConfigurePort(
295 *device::serial::ConnectionOptions::From(options
));
296 io_handler_
->CancelRead(device::serial::RECEIVE_ERROR_NONE
);
300 void SerialConnection::SetIoHandlerForTest(
301 scoped_refptr
<device::SerialIoHandler
> handler
) {
302 io_handler_
= handler
;
305 bool SerialConnection::GetInfo(core_api::serial::ConnectionInfo
* info
) const {
306 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
307 info
->paused
= paused_
;
308 info
->persistent
= persistent_
;
310 info
->buffer_size
= buffer_size_
;
311 info
->receive_timeout
= receive_timeout_
;
312 info
->send_timeout
= send_timeout_
;
313 device::serial::ConnectionInfoPtr port_info
= io_handler_
->GetPortInfo();
317 info
->bitrate
.reset(new int(port_info
->bitrate
));
318 info
->data_bits
= ConvertDataBitsFromMojo(port_info
->data_bits
);
319 info
->parity_bit
= ConvertParityBitFromMojo(port_info
->parity_bit
);
320 info
->stop_bits
= ConvertStopBitsFromMojo(port_info
->stop_bits
);
321 info
->cts_flow_control
.reset(new bool(port_info
->cts_flow_control
));
325 bool SerialConnection::Flush() const {
326 return io_handler_
->Flush();
329 bool SerialConnection::GetControlSignals(
330 core_api::serial::DeviceControlSignals
* control_signals
) const {
331 device::serial::DeviceControlSignalsPtr signals
=
332 io_handler_
->GetControlSignals();
336 control_signals
->dcd
= signals
->dcd
;
337 control_signals
->cts
= signals
->cts
;
338 control_signals
->ri
= signals
->ri
;
339 control_signals
->dsr
= signals
->dsr
;
343 bool SerialConnection::SetControlSignals(
344 const core_api::serial::HostControlSignals
& control_signals
) {
345 return io_handler_
->SetControlSignals(
346 *device::serial::HostControlSignals::From(control_signals
));
349 void SerialConnection::OnReceiveTimeout() {
350 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
351 io_handler_
->CancelRead(device::serial::RECEIVE_ERROR_TIMEOUT
);
354 void SerialConnection::OnSendTimeout() {
355 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
356 io_handler_
->CancelWrite(device::serial::SEND_ERROR_TIMEOUT
);
359 void SerialConnection::OnAsyncReadComplete(int bytes_read
,
360 device::serial::ReceiveError error
) {
361 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
362 DCHECK(!receive_complete_
.is_null());
363 ReceiveCompleteCallback callback
= receive_complete_
;
364 receive_complete_
.Reset();
365 receive_timeout_task_
.reset();
366 callback
.Run(std::string(receive_buffer_
->data(), bytes_read
),
367 ConvertReceiveErrorFromMojo(error
));
368 receive_buffer_
= NULL
;
371 void SerialConnection::OnAsyncWriteComplete(int bytes_sent
,
372 device::serial::SendError error
) {
373 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
374 DCHECK(!send_complete_
.is_null());
375 SendCompleteCallback callback
= send_complete_
;
376 send_complete_
.Reset();
377 send_timeout_task_
.reset();
378 callback
.Run(bytes_sent
, ConvertSendErrorFromMojo(error
));
381 SerialConnection::TimeoutTask::TimeoutTask(const base::Closure
& closure
,
382 const base::TimeDelta
& delay
)
383 : weak_factory_(this), closure_(closure
), delay_(delay
) {
384 base::MessageLoop::current()->PostDelayedTask(
386 base::Bind(&TimeoutTask::Run
, weak_factory_
.GetWeakPtr()),
390 SerialConnection::TimeoutTask::~TimeoutTask() {
393 void SerialConnection::TimeoutTask::Run() const {
397 } // namespace extensions
402 device::serial::HostControlSignalsPtr
403 TypeConverter
<device::serial::HostControlSignalsPtr
,
404 extensions::core_api::serial::HostControlSignals
>::
405 Convert(const extensions::core_api::serial::HostControlSignals
& input
) {
406 device::serial::HostControlSignalsPtr
output(
407 device::serial::HostControlSignals::New());
408 if (input
.dtr
.get()) {
409 output
->has_dtr
= true;
410 output
->dtr
= *input
.dtr
;
412 if (input
.rts
.get()) {
413 output
->has_rts
= true;
414 output
->rts
= *input
.rts
;
416 return output
.Pass();
420 device::serial::ConnectionOptionsPtr
421 TypeConverter
<device::serial::ConnectionOptionsPtr
,
422 extensions::core_api::serial::ConnectionOptions
>::
423 Convert(const extensions::core_api::serial::ConnectionOptions
& input
) {
424 device::serial::ConnectionOptionsPtr
output(
425 device::serial::ConnectionOptions::New());
426 if (input
.bitrate
.get() && *input
.bitrate
> 0)
427 output
->bitrate
= *input
.bitrate
;
428 output
->data_bits
= extensions::ConvertDataBitsToMojo(input
.data_bits
);
429 output
->parity_bit
= extensions::ConvertParityBitToMojo(input
.parity_bit
);
430 output
->stop_bits
= extensions::ConvertStopBitsToMojo(input
.stop_bits
);
431 if (input
.cts_flow_control
.get()) {
432 output
->has_cts_flow_control
= true;
433 output
->cts_flow_control
= *input
.cts_flow_control
;
435 return output
.Pass();