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 "device/serial/serial_io_handler.h"
8 #include "base/files/file_path.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_util.h"
14 SerialIoHandler::SerialIoHandler(
15 scoped_refptr
<base::SingleThreadTaskRunner
> file_thread_task_runner
,
16 scoped_refptr
<base::SingleThreadTaskRunner
> ui_thread_task_runner
)
17 : file_thread_task_runner_(file_thread_task_runner
),
18 ui_thread_task_runner_(ui_thread_task_runner
) {
19 options_
.bitrate
= 9600;
20 options_
.data_bits
= serial::DATA_BITS_EIGHT
;
21 options_
.parity_bit
= serial::PARITY_BIT_NO
;
22 options_
.stop_bits
= serial::STOP_BITS_ONE
;
23 options_
.cts_flow_control
= false;
24 options_
.has_cts_flow_control
= true;
27 SerialIoHandler::~SerialIoHandler() {
28 DCHECK(CalledOnValidThread());
32 void SerialIoHandler::Open(const std::string
& port
,
33 const serial::ConnectionOptions
& options
,
34 const OpenCompleteCallback
& callback
) {
35 DCHECK(CalledOnValidThread());
36 DCHECK(open_complete_
.is_null());
37 open_complete_
= callback
;
38 DCHECK(file_thread_task_runner_
.get());
39 DCHECK(ui_thread_task_runner_
.get());
40 MergeConnectionOptions(options
);
41 RequestAccess(port
, file_thread_task_runner_
, ui_thread_task_runner_
);
44 void SerialIoHandler::RequestAccess(
45 const std::string
& port
,
46 scoped_refptr
<base::SingleThreadTaskRunner
> file_task_runner
,
47 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
) {
48 OnRequestAccessComplete(port
, true /* success */);
51 void SerialIoHandler::OnRequestAccessComplete(const std::string
& port
,
53 DCHECK(CalledOnValidThread());
55 DCHECK(file_thread_task_runner_
.get());
56 file_thread_task_runner_
->PostTask(
57 FROM_HERE
, base::Bind(&SerialIoHandler::StartOpen
, this, port
,
58 base::ThreadTaskRunnerHandle::Get()));
61 DCHECK(!open_complete_
.is_null());
62 OpenCompleteCallback callback
= open_complete_
;
63 open_complete_
.Reset();
69 void SerialIoHandler::MergeConnectionOptions(
70 const serial::ConnectionOptions
& options
) {
71 if (options
.bitrate
) {
72 options_
.bitrate
= options
.bitrate
;
74 if (options
.data_bits
!= serial::DATA_BITS_NONE
) {
75 options_
.data_bits
= options
.data_bits
;
77 if (options
.parity_bit
!= serial::PARITY_BIT_NONE
) {
78 options_
.parity_bit
= options
.parity_bit
;
80 if (options
.stop_bits
!= serial::STOP_BITS_NONE
) {
81 options_
.stop_bits
= options
.stop_bits
;
83 if (options
.has_cts_flow_control
) {
84 DCHECK(options_
.has_cts_flow_control
);
85 options_
.cts_flow_control
= options
.cts_flow_control
;
89 void SerialIoHandler::StartOpen(
90 const std::string
& port
,
91 scoped_refptr
<base::SingleThreadTaskRunner
> io_task_runner
) {
92 DCHECK(!open_complete_
.is_null());
93 DCHECK(file_thread_task_runner_
->RunsTasksOnCurrentThread());
94 DCHECK(!file_
.IsValid());
95 // It's the responsibility of the API wrapper around SerialIoHandler to
96 // validate the supplied path against the set of valid port names, and
97 // it is a reasonable assumption that serial port names are ASCII.
98 DCHECK(base::IsStringASCII(port
));
99 base::FilePath
path(base::FilePath::FromUTF8Unsafe(MaybeFixUpPortName(port
)));
100 int flags
= base::File::FLAG_OPEN
| base::File::FLAG_READ
|
101 base::File::FLAG_EXCLUSIVE_READ
| base::File::FLAG_WRITE
|
102 base::File::FLAG_EXCLUSIVE_WRITE
| base::File::FLAG_ASYNC
|
103 base::File::FLAG_TERMINAL_DEVICE
;
104 base::File
file(path
, flags
);
105 io_task_runner
->PostTask(FROM_HERE
, base::Bind(&SerialIoHandler::FinishOpen
,
106 this, Passed(file
.Pass())));
109 void SerialIoHandler::FinishOpen(base::File file
) {
110 DCHECK(CalledOnValidThread());
111 DCHECK(!open_complete_
.is_null());
112 OpenCompleteCallback callback
= open_complete_
;
113 open_complete_
.Reset();
115 if (!file
.IsValid()) {
116 LOG(ERROR
) << "Failed to open serial port: "
117 << base::File::ErrorToString(file
.error_details());
124 bool success
= PostOpen() && ConfigurePortImpl();
129 callback
.Run(success
);
132 bool SerialIoHandler::PostOpen() {
136 void SerialIoHandler::Close() {
137 if (file_
.IsValid()) {
138 DCHECK(file_thread_task_runner_
.get());
139 file_thread_task_runner_
->PostTask(
140 FROM_HERE
, base::Bind(&SerialIoHandler::DoClose
, Passed(file_
.Pass())));
145 void SerialIoHandler::DoClose(base::File port
) {
146 // port closed by destructor.
149 void SerialIoHandler::Read(scoped_ptr
<WritableBuffer
> buffer
) {
150 DCHECK(CalledOnValidThread());
151 DCHECK(!IsReadPending());
152 pending_read_buffer_
= buffer
.Pass();
153 read_canceled_
= false;
158 void SerialIoHandler::Write(scoped_ptr
<ReadOnlyBuffer
> buffer
) {
159 DCHECK(CalledOnValidThread());
160 DCHECK(!IsWritePending());
161 pending_write_buffer_
= buffer
.Pass();
162 write_canceled_
= false;
167 void SerialIoHandler::ReadCompleted(int bytes_read
,
168 serial::ReceiveError error
) {
169 DCHECK(CalledOnValidThread());
170 DCHECK(IsReadPending());
171 scoped_ptr
<WritableBuffer
> pending_read_buffer
= pending_read_buffer_
.Pass();
172 if (error
== serial::RECEIVE_ERROR_NONE
) {
173 pending_read_buffer
->Done(bytes_read
);
175 pending_read_buffer
->DoneWithError(bytes_read
, error
);
180 void SerialIoHandler::WriteCompleted(int bytes_written
,
181 serial::SendError error
) {
182 DCHECK(CalledOnValidThread());
183 DCHECK(IsWritePending());
184 scoped_ptr
<ReadOnlyBuffer
> pending_write_buffer
=
185 pending_write_buffer_
.Pass();
186 if (error
== serial::SEND_ERROR_NONE
) {
187 pending_write_buffer
->Done(bytes_written
);
189 pending_write_buffer
->DoneWithError(bytes_written
, error
);
194 bool SerialIoHandler::IsReadPending() const {
195 DCHECK(CalledOnValidThread());
196 return pending_read_buffer_
!= NULL
;
199 bool SerialIoHandler::IsWritePending() const {
200 DCHECK(CalledOnValidThread());
201 return pending_write_buffer_
!= NULL
;
204 void SerialIoHandler::CancelRead(serial::ReceiveError reason
) {
205 DCHECK(CalledOnValidThread());
206 if (IsReadPending() && !read_canceled_
) {
207 read_canceled_
= true;
208 read_cancel_reason_
= reason
;
213 void SerialIoHandler::CancelWrite(serial::SendError reason
) {
214 DCHECK(CalledOnValidThread());
215 if (IsWritePending() && !write_canceled_
) {
216 write_canceled_
= true;
217 write_cancel_reason_
= reason
;
222 bool SerialIoHandler::ConfigurePort(const serial::ConnectionOptions
& options
) {
223 MergeConnectionOptions(options
);
224 return ConfigurePortImpl();
227 void SerialIoHandler::QueueReadCompleted(int bytes_read
,
228 serial::ReceiveError error
) {
229 base::MessageLoop::current()->PostTask(
231 base::Bind(&SerialIoHandler::ReadCompleted
, this, bytes_read
, error
));
234 void SerialIoHandler::QueueWriteCompleted(int bytes_written
,
235 serial::SendError error
) {
236 base::MessageLoop::current()->PostTask(
238 base::Bind(&SerialIoHandler::WriteCompleted
, this, bytes_written
, error
));
241 } // namespace device