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::MessageLoopProxy
> file_thread_message_loop
,
16 scoped_refptr
<base::MessageLoopProxy
> ui_thread_message_loop
)
17 : file_thread_message_loop_(file_thread_message_loop
),
18 ui_thread_message_loop_(ui_thread_message_loop
) {
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_message_loop_
.get());
39 DCHECK(ui_thread_message_loop_
.get());
40 MergeConnectionOptions(options
);
41 RequestAccess(port
, file_thread_message_loop_
, ui_thread_message_loop_
);
44 void SerialIoHandler::RequestAccess(
45 const std::string
& port
,
46 scoped_refptr
<base::MessageLoopProxy
> file_message_loop
,
47 scoped_refptr
<base::MessageLoopProxy
> ui_message_loop
) {
48 OnRequestAccessComplete(port
, true /* success */);
51 void SerialIoHandler::OnRequestAccessComplete(const std::string
& port
,
53 DCHECK(CalledOnValidThread());
55 DCHECK(file_thread_message_loop_
.get());
56 file_thread_message_loop_
->PostTask(
58 base::Bind(&SerialIoHandler::StartOpen
,
61 base::MessageLoopProxy::current()));
64 DCHECK(!open_complete_
.is_null());
65 OpenCompleteCallback callback
= open_complete_
;
66 open_complete_
.Reset();
72 void SerialIoHandler::MergeConnectionOptions(
73 const serial::ConnectionOptions
& options
) {
74 if (options
.bitrate
) {
75 options_
.bitrate
= options
.bitrate
;
77 if (options
.data_bits
!= serial::DATA_BITS_NONE
) {
78 options_
.data_bits
= options
.data_bits
;
80 if (options
.parity_bit
!= serial::PARITY_BIT_NONE
) {
81 options_
.parity_bit
= options
.parity_bit
;
83 if (options
.stop_bits
!= serial::STOP_BITS_NONE
) {
84 options_
.stop_bits
= options
.stop_bits
;
86 if (options
.has_cts_flow_control
) {
87 DCHECK(options_
.has_cts_flow_control
);
88 options_
.cts_flow_control
= options
.cts_flow_control
;
92 void SerialIoHandler::StartOpen(
93 const std::string
& port
,
94 scoped_refptr
<base::MessageLoopProxy
> io_message_loop
) {
95 DCHECK(!open_complete_
.is_null());
96 DCHECK(file_thread_message_loop_
->RunsTasksOnCurrentThread());
97 DCHECK(!file_
.IsValid());
98 // It's the responsibility of the API wrapper around SerialIoHandler to
99 // validate the supplied path against the set of valid port names, and
100 // it is a reasonable assumption that serial port names are ASCII.
101 DCHECK(base::IsStringASCII(port
));
102 base::FilePath
path(base::FilePath::FromUTF8Unsafe(MaybeFixUpPortName(port
)));
103 int flags
= base::File::FLAG_OPEN
| base::File::FLAG_READ
|
104 base::File::FLAG_EXCLUSIVE_READ
| base::File::FLAG_WRITE
|
105 base::File::FLAG_EXCLUSIVE_WRITE
| base::File::FLAG_ASYNC
|
106 base::File::FLAG_TERMINAL_DEVICE
;
107 base::File
file(path
, flags
);
108 io_message_loop
->PostTask(
110 base::Bind(&SerialIoHandler::FinishOpen
, this, Passed(file
.Pass())));
113 void SerialIoHandler::FinishOpen(base::File file
) {
114 DCHECK(CalledOnValidThread());
115 DCHECK(!open_complete_
.is_null());
116 OpenCompleteCallback callback
= open_complete_
;
117 open_complete_
.Reset();
119 if (!file
.IsValid()) {
120 LOG(ERROR
) << "Failed to open serial port: "
121 << base::File::ErrorToString(file
.error_details());
128 bool success
= PostOpen() && ConfigurePortImpl();
133 callback
.Run(success
);
136 bool SerialIoHandler::PostOpen() {
140 void SerialIoHandler::Close() {
141 if (file_
.IsValid()) {
142 DCHECK(file_thread_message_loop_
.get());
143 file_thread_message_loop_
->PostTask(
144 FROM_HERE
, base::Bind(&SerialIoHandler::DoClose
, Passed(file_
.Pass())));
149 void SerialIoHandler::DoClose(base::File port
) {
150 // port closed by destructor.
153 void SerialIoHandler::Read(scoped_ptr
<WritableBuffer
> buffer
) {
154 DCHECK(CalledOnValidThread());
155 DCHECK(!IsReadPending());
156 pending_read_buffer_
= buffer
.Pass();
157 read_canceled_
= false;
162 void SerialIoHandler::Write(scoped_ptr
<ReadOnlyBuffer
> buffer
) {
163 DCHECK(CalledOnValidThread());
164 DCHECK(!IsWritePending());
165 pending_write_buffer_
= buffer
.Pass();
166 write_canceled_
= false;
171 void SerialIoHandler::ReadCompleted(int bytes_read
,
172 serial::ReceiveError error
) {
173 DCHECK(CalledOnValidThread());
174 DCHECK(IsReadPending());
175 scoped_ptr
<WritableBuffer
> pending_read_buffer
= pending_read_buffer_
.Pass();
176 if (error
== serial::RECEIVE_ERROR_NONE
) {
177 pending_read_buffer
->Done(bytes_read
);
179 pending_read_buffer
->DoneWithError(bytes_read
, error
);
184 void SerialIoHandler::WriteCompleted(int bytes_written
,
185 serial::SendError error
) {
186 DCHECK(CalledOnValidThread());
187 DCHECK(IsWritePending());
188 scoped_ptr
<ReadOnlyBuffer
> pending_write_buffer
=
189 pending_write_buffer_
.Pass();
190 if (error
== serial::SEND_ERROR_NONE
) {
191 pending_write_buffer
->Done(bytes_written
);
193 pending_write_buffer
->DoneWithError(bytes_written
, error
);
198 bool SerialIoHandler::IsReadPending() const {
199 DCHECK(CalledOnValidThread());
200 return pending_read_buffer_
!= NULL
;
203 bool SerialIoHandler::IsWritePending() const {
204 DCHECK(CalledOnValidThread());
205 return pending_write_buffer_
!= NULL
;
208 void SerialIoHandler::CancelRead(serial::ReceiveError reason
) {
209 DCHECK(CalledOnValidThread());
210 if (IsReadPending() && !read_canceled_
) {
211 read_canceled_
= true;
212 read_cancel_reason_
= reason
;
217 void SerialIoHandler::CancelWrite(serial::SendError reason
) {
218 DCHECK(CalledOnValidThread());
219 if (IsWritePending() && !write_canceled_
) {
220 write_canceled_
= true;
221 write_cancel_reason_
= reason
;
226 bool SerialIoHandler::ConfigurePort(const serial::ConnectionOptions
& options
) {
227 MergeConnectionOptions(options
);
228 return ConfigurePortImpl();
231 void SerialIoHandler::QueueReadCompleted(int bytes_read
,
232 serial::ReceiveError error
) {
233 base::MessageLoop::current()->PostTask(
235 base::Bind(&SerialIoHandler::ReadCompleted
, this, bytes_read
, error
));
238 void SerialIoHandler::QueueWriteCompleted(int bytes_written
,
239 serial::SendError error
) {
240 base::MessageLoop::current()->PostTask(
242 base::Bind(&SerialIoHandler::WriteCompleted
, this, bytes_written
, error
));
245 } // namespace device