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"
10 #include "base/files/file_path.h"
11 #include "base/lazy_instance.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/stl_util.h"
14 #include "extensions/browser/api/api_resource_manager.h"
15 #include "extensions/common/api/serial.h"
17 namespace extensions
{
21 const int kDefaultBufferSize
= 4096;
23 core_api::serial::SendError
ConvertSendErrorFromMojo(
24 device::serial::SendError input
) {
26 case device::serial::SEND_ERROR_NONE
:
27 return core_api::serial::SEND_ERROR_NONE
;
28 case device::serial::SEND_ERROR_DISCONNECTED
:
29 return core_api::serial::SEND_ERROR_DISCONNECTED
;
30 case device::serial::SEND_ERROR_PENDING
:
31 return core_api::serial::SEND_ERROR_PENDING
;
32 case device::serial::SEND_ERROR_TIMEOUT
:
33 return core_api::serial::SEND_ERROR_TIMEOUT
;
34 case device::serial::SEND_ERROR_SYSTEM_ERROR
:
35 return core_api::serial::SEND_ERROR_SYSTEM_ERROR
;
37 return core_api::serial::SEND_ERROR_NONE
;
40 core_api::serial::ReceiveError
ConvertReceiveErrorFromMojo(
41 device::serial::ReceiveError input
) {
43 case device::serial::RECEIVE_ERROR_NONE
:
44 return core_api::serial::RECEIVE_ERROR_NONE
;
45 case device::serial::RECEIVE_ERROR_DISCONNECTED
:
46 return core_api::serial::RECEIVE_ERROR_DISCONNECTED
;
47 case device::serial::RECEIVE_ERROR_TIMEOUT
:
48 return core_api::serial::RECEIVE_ERROR_TIMEOUT
;
49 case device::serial::RECEIVE_ERROR_DEVICE_LOST
:
50 return core_api::serial::RECEIVE_ERROR_DEVICE_LOST
;
51 case device::serial::RECEIVE_ERROR_SYSTEM_ERROR
:
52 return core_api::serial::RECEIVE_ERROR_SYSTEM_ERROR
;
54 return core_api::serial::RECEIVE_ERROR_NONE
;
57 core_api::serial::DataBits
ConvertDataBitsFromMojo(
58 device::serial::DataBits input
) {
60 case device::serial::DATA_BITS_NONE
:
61 return core_api::serial::DATA_BITS_NONE
;
62 case device::serial::DATA_BITS_SEVEN
:
63 return core_api::serial::DATA_BITS_SEVEN
;
64 case device::serial::DATA_BITS_EIGHT
:
65 return core_api::serial::DATA_BITS_EIGHT
;
67 return core_api::serial::DATA_BITS_NONE
;
70 device::serial::DataBits
ConvertDataBitsToMojo(
71 core_api::serial::DataBits input
) {
73 case core_api::serial::DATA_BITS_NONE
:
74 return device::serial::DATA_BITS_NONE
;
75 case core_api::serial::DATA_BITS_SEVEN
:
76 return device::serial::DATA_BITS_SEVEN
;
77 case core_api::serial::DATA_BITS_EIGHT
:
78 return device::serial::DATA_BITS_EIGHT
;
80 return device::serial::DATA_BITS_NONE
;
83 core_api::serial::ParityBit
ConvertParityBitFromMojo(
84 device::serial::ParityBit input
) {
86 case device::serial::PARITY_BIT_NONE
:
87 return core_api::serial::PARITY_BIT_NONE
;
88 case device::serial::PARITY_BIT_ODD
:
89 return core_api::serial::PARITY_BIT_ODD
;
90 case device::serial::PARITY_BIT_NO
:
91 return core_api::serial::PARITY_BIT_NO
;
92 case device::serial::PARITY_BIT_EVEN
:
93 return core_api::serial::PARITY_BIT_EVEN
;
95 return core_api::serial::PARITY_BIT_NONE
;
98 device::serial::ParityBit
ConvertParityBitToMojo(
99 core_api::serial::ParityBit input
) {
101 case core_api::serial::PARITY_BIT_NONE
:
102 return device::serial::PARITY_BIT_NONE
;
103 case core_api::serial::PARITY_BIT_NO
:
104 return device::serial::PARITY_BIT_NO
;
105 case core_api::serial::PARITY_BIT_ODD
:
106 return device::serial::PARITY_BIT_ODD
;
107 case core_api::serial::PARITY_BIT_EVEN
:
108 return device::serial::PARITY_BIT_EVEN
;
110 return device::serial::PARITY_BIT_NONE
;
113 core_api::serial::StopBits
ConvertStopBitsFromMojo(
114 device::serial::StopBits input
) {
116 case device::serial::STOP_BITS_NONE
:
117 return core_api::serial::STOP_BITS_NONE
;
118 case device::serial::STOP_BITS_ONE
:
119 return core_api::serial::STOP_BITS_ONE
;
120 case device::serial::STOP_BITS_TWO
:
121 return core_api::serial::STOP_BITS_TWO
;
123 return core_api::serial::STOP_BITS_NONE
;
126 device::serial::StopBits
ConvertStopBitsToMojo(
127 core_api::serial::StopBits input
) {
129 case core_api::serial::STOP_BITS_NONE
:
130 return device::serial::STOP_BITS_NONE
;
131 case core_api::serial::STOP_BITS_ONE
:
132 return device::serial::STOP_BITS_ONE
;
133 case core_api::serial::STOP_BITS_TWO
:
134 return device::serial::STOP_BITS_TWO
;
136 return device::serial::STOP_BITS_NONE
;
139 class SendBuffer
: public device::ReadOnlyBuffer
{
142 const std::vector
<char>& data
,
143 const base::Callback
<void(int, device::serial::SendError
)>& callback
)
144 : data_(data
), callback_(callback
) {}
145 ~SendBuffer() override
{}
146 const char* GetData() override
{ return vector_as_array(&data_
); }
147 uint32_t GetSize() override
{ return static_cast<uint32_t>(data_
.size()); }
148 void Done(uint32_t bytes_read
) override
{
149 callback_
.Run(bytes_read
, device::serial::SEND_ERROR_NONE
);
151 void DoneWithError(uint32_t bytes_read
, int32_t error
) override
{
152 callback_
.Run(bytes_read
, static_cast<device::serial::SendError
>(error
));
156 const std::vector
<char> data_
;
157 const base::Callback
<void(int, device::serial::SendError
)> callback_
;
160 class ReceiveBuffer
: public device::WritableBuffer
{
163 scoped_refptr
<net::IOBuffer
> buffer
,
165 const base::Callback
<void(int, device::serial::ReceiveError
)>& callback
)
166 : buffer_(buffer
), size_(size
), callback_(callback
) {}
167 ~ReceiveBuffer() override
{}
168 char* GetData() override
{ return buffer_
->data(); }
169 uint32_t GetSize() override
{ return size_
; }
170 void Done(uint32_t bytes_written
) override
{
171 callback_
.Run(bytes_written
, device::serial::RECEIVE_ERROR_NONE
);
173 void DoneWithError(uint32_t bytes_written
, int32_t error
) override
{
174 callback_
.Run(bytes_written
,
175 static_cast<device::serial::ReceiveError
>(error
));
179 scoped_refptr
<net::IOBuffer
> buffer_
;
180 const uint32_t size_
;
181 const base::Callback
<void(int, device::serial::ReceiveError
)> callback_
;
186 static base::LazyInstance
<
187 BrowserContextKeyedAPIFactory
<ApiResourceManager
<SerialConnection
> > >
188 g_factory
= LAZY_INSTANCE_INITIALIZER
;
192 BrowserContextKeyedAPIFactory
<ApiResourceManager
<SerialConnection
> >*
193 ApiResourceManager
<SerialConnection
>::GetFactoryInstance() {
194 return g_factory
.Pointer();
197 SerialConnection::SerialConnection(const std::string
& port
,
198 const std::string
& owner_extension_id
)
199 : ApiResource(owner_extension_id
),
202 buffer_size_(kDefaultBufferSize
),
206 io_handler_(device::SerialIoHandler::Create(
207 content::BrowserThread::GetMessageLoopProxyForThread(
208 content::BrowserThread::FILE),
209 content::BrowserThread::GetMessageLoopProxyForThread(
210 content::BrowserThread::UI
))) {
211 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
214 SerialConnection::~SerialConnection() {
215 io_handler_
->CancelRead(device::serial::RECEIVE_ERROR_DISCONNECTED
);
216 io_handler_
->CancelWrite(device::serial::SEND_ERROR_DISCONNECTED
);
219 bool SerialConnection::IsPersistent() const {
223 void SerialConnection::set_buffer_size(int buffer_size
) {
224 buffer_size_
= buffer_size
;
227 void SerialConnection::set_receive_timeout(int receive_timeout
) {
228 receive_timeout_
= receive_timeout
;
231 void SerialConnection::set_send_timeout(int send_timeout
) {
232 send_timeout_
= send_timeout
;
235 void SerialConnection::set_paused(bool paused
) {
238 io_handler_
->CancelRead(device::serial::RECEIVE_ERROR_NONE
);
242 void SerialConnection::Open(const core_api::serial::ConnectionOptions
& options
,
243 const OpenCompleteCallback
& callback
) {
244 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
245 if (options
.persistent
.get())
246 set_persistent(*options
.persistent
);
247 if (options
.name
.get())
248 set_name(*options
.name
);
249 if (options
.buffer_size
.get())
250 set_buffer_size(*options
.buffer_size
);
251 if (options
.receive_timeout
.get())
252 set_receive_timeout(*options
.receive_timeout
);
253 if (options
.send_timeout
.get())
254 set_send_timeout(*options
.send_timeout
);
255 io_handler_
->Open(port_
, *device::serial::ConnectionOptions::From(options
),
259 bool SerialConnection::Receive(const ReceiveCompleteCallback
& callback
) {
260 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
261 if (!receive_complete_
.is_null())
263 receive_complete_
= callback
;
264 receive_buffer_
= new net::IOBuffer(buffer_size_
);
265 io_handler_
->Read(scoped_ptr
<device::WritableBuffer
>(new ReceiveBuffer(
268 base::Bind(&SerialConnection::OnAsyncReadComplete
, AsWeakPtr()))));
269 receive_timeout_task_
.reset();
270 if (receive_timeout_
> 0) {
271 receive_timeout_task_
.reset(new TimeoutTask(
272 base::Bind(&SerialConnection::OnReceiveTimeout
, AsWeakPtr()),
273 base::TimeDelta::FromMilliseconds(receive_timeout_
)));
278 bool SerialConnection::Send(const std::vector
<char>& data
,
279 const SendCompleteCallback
& callback
) {
280 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
281 if (!send_complete_
.is_null())
283 send_complete_
= callback
;
284 io_handler_
->Write(scoped_ptr
<device::ReadOnlyBuffer
>(new SendBuffer(
285 data
, base::Bind(&SerialConnection::OnAsyncWriteComplete
, AsWeakPtr()))));
286 send_timeout_task_
.reset();
287 if (send_timeout_
> 0) {
288 send_timeout_task_
.reset(new TimeoutTask(
289 base::Bind(&SerialConnection::OnSendTimeout
, AsWeakPtr()),
290 base::TimeDelta::FromMilliseconds(send_timeout_
)));
295 bool SerialConnection::Configure(
296 const core_api::serial::ConnectionOptions
& options
) {
297 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
298 if (options
.persistent
.get())
299 set_persistent(*options
.persistent
);
300 if (options
.name
.get())
301 set_name(*options
.name
);
302 if (options
.buffer_size
.get())
303 set_buffer_size(*options
.buffer_size
);
304 if (options
.receive_timeout
.get())
305 set_receive_timeout(*options
.receive_timeout
);
306 if (options
.send_timeout
.get())
307 set_send_timeout(*options
.send_timeout
);
308 bool success
= io_handler_
->ConfigurePort(
309 *device::serial::ConnectionOptions::From(options
));
310 io_handler_
->CancelRead(device::serial::RECEIVE_ERROR_NONE
);
314 void SerialConnection::SetIoHandlerForTest(
315 scoped_refptr
<device::SerialIoHandler
> handler
) {
316 io_handler_
= handler
;
319 bool SerialConnection::GetInfo(core_api::serial::ConnectionInfo
* info
) const {
320 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
321 info
->paused
= paused_
;
322 info
->persistent
= persistent_
;
324 info
->buffer_size
= buffer_size_
;
325 info
->receive_timeout
= receive_timeout_
;
326 info
->send_timeout
= send_timeout_
;
327 device::serial::ConnectionInfoPtr port_info
= io_handler_
->GetPortInfo();
331 info
->bitrate
.reset(new int(port_info
->bitrate
));
332 info
->data_bits
= ConvertDataBitsFromMojo(port_info
->data_bits
);
333 info
->parity_bit
= ConvertParityBitFromMojo(port_info
->parity_bit
);
334 info
->stop_bits
= ConvertStopBitsFromMojo(port_info
->stop_bits
);
335 info
->cts_flow_control
.reset(new bool(port_info
->cts_flow_control
));
339 bool SerialConnection::Flush() const {
340 return io_handler_
->Flush();
343 bool SerialConnection::GetControlSignals(
344 core_api::serial::DeviceControlSignals
* control_signals
) const {
345 device::serial::DeviceControlSignalsPtr signals
=
346 io_handler_
->GetControlSignals();
350 control_signals
->dcd
= signals
->dcd
;
351 control_signals
->cts
= signals
->cts
;
352 control_signals
->ri
= signals
->ri
;
353 control_signals
->dsr
= signals
->dsr
;
357 bool SerialConnection::SetControlSignals(
358 const core_api::serial::HostControlSignals
& control_signals
) {
359 return io_handler_
->SetControlSignals(
360 *device::serial::HostControlSignals::From(control_signals
));
363 void SerialConnection::OnReceiveTimeout() {
364 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
365 io_handler_
->CancelRead(device::serial::RECEIVE_ERROR_TIMEOUT
);
368 void SerialConnection::OnSendTimeout() {
369 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
370 io_handler_
->CancelWrite(device::serial::SEND_ERROR_TIMEOUT
);
373 void SerialConnection::OnAsyncReadComplete(int bytes_read
,
374 device::serial::ReceiveError error
) {
375 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
376 DCHECK(!receive_complete_
.is_null());
377 ReceiveCompleteCallback callback
= receive_complete_
;
378 receive_complete_
.Reset();
379 receive_timeout_task_
.reset();
380 callback
.Run(std::vector
<char>(receive_buffer_
->data(),
381 receive_buffer_
->data() + bytes_read
),
382 ConvertReceiveErrorFromMojo(error
));
383 receive_buffer_
= NULL
;
386 void SerialConnection::OnAsyncWriteComplete(int bytes_sent
,
387 device::serial::SendError error
) {
388 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
389 DCHECK(!send_complete_
.is_null());
390 SendCompleteCallback callback
= send_complete_
;
391 send_complete_
.Reset();
392 send_timeout_task_
.reset();
393 callback
.Run(bytes_sent
, ConvertSendErrorFromMojo(error
));
396 SerialConnection::TimeoutTask::TimeoutTask(const base::Closure
& closure
,
397 const base::TimeDelta
& delay
)
398 : closure_(closure
), delay_(delay
), weak_factory_(this) {
399 base::MessageLoop::current()->PostDelayedTask(
401 base::Bind(&TimeoutTask::Run
, weak_factory_
.GetWeakPtr()),
405 SerialConnection::TimeoutTask::~TimeoutTask() {
408 void SerialConnection::TimeoutTask::Run() const {
412 } // namespace extensions
417 device::serial::HostControlSignalsPtr
418 TypeConverter
<device::serial::HostControlSignalsPtr
,
419 extensions::core_api::serial::HostControlSignals
>::
420 Convert(const extensions::core_api::serial::HostControlSignals
& input
) {
421 device::serial::HostControlSignalsPtr
output(
422 device::serial::HostControlSignals::New());
423 if (input
.dtr
.get()) {
424 output
->has_dtr
= true;
425 output
->dtr
= *input
.dtr
;
427 if (input
.rts
.get()) {
428 output
->has_rts
= true;
429 output
->rts
= *input
.rts
;
431 return output
.Pass();
435 device::serial::ConnectionOptionsPtr
436 TypeConverter
<device::serial::ConnectionOptionsPtr
,
437 extensions::core_api::serial::ConnectionOptions
>::
438 Convert(const extensions::core_api::serial::ConnectionOptions
& input
) {
439 device::serial::ConnectionOptionsPtr
output(
440 device::serial::ConnectionOptions::New());
441 if (input
.bitrate
.get() && *input
.bitrate
> 0)
442 output
->bitrate
= *input
.bitrate
;
443 output
->data_bits
= extensions::ConvertDataBitsToMojo(input
.data_bits
);
444 output
->parity_bit
= extensions::ConvertParityBitToMojo(input
.parity_bit
);
445 output
->stop_bits
= extensions::ConvertStopBitsToMojo(input
.stop_bits
);
446 if (input
.cts_flow_control
.get()) {
447 output
->has_cts_flow_control
= true;
448 output
->cts_flow_control
= *input
.cts_flow_control
;
450 return output
.Pass();