1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "services/device/serial/serial_port_impl.h"
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/task/single_thread_task_runner.h"
13 #include "services/device/serial/serial_io_handler.h"
18 void SerialPortImpl::Open(
19 const base::FilePath& path,
20 mojom::SerialConnectionOptionsPtr options,
21 mojo::PendingRemote<mojom::SerialPortClient> client,
22 mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
23 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
24 OpenCallback callback) {
25 // This SerialPortImpl is owned by |receiver_| and |watcher_| and will
26 // self-destruct on close.
27 auto* port = new SerialPortImpl(
28 device::SerialIoHandler::Create(path, std::move(ui_task_runner)),
29 std::move(client), std::move(watcher));
30 port->OpenPort(*options, std::move(callback));
34 void SerialPortImpl::OpenForTesting(
35 scoped_refptr<SerialIoHandler> io_handler,
36 mojom::SerialConnectionOptionsPtr options,
37 mojo::PendingRemote<mojom::SerialPortClient> client,
38 mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
39 OpenCallback callback) {
40 // This SerialPortImpl is owned by |receiver| and |watcher| and will
41 // self-destruct on close.
42 auto* port = new SerialPortImpl(std::move(io_handler), std::move(client),
44 port->OpenPort(*options, std::move(callback));
47 SerialPortImpl::SerialPortImpl(
48 scoped_refptr<SerialIoHandler> io_handler,
49 mojo::PendingRemote<mojom::SerialPortClient> client,
50 mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher)
51 : io_handler_(std::move(io_handler)),
52 client_(std::move(client)),
53 watcher_(std::move(watcher)),
54 in_stream_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
55 out_stream_watcher_(FROM_HERE,
56 mojo::SimpleWatcher::ArmingPolicy::MANUAL) {
57 if (watcher_.is_bound()) {
58 watcher_.set_disconnect_handler(base::BindOnce(
59 [](SerialPortImpl* self) { delete self; }, base::Unretained(this)));
63 SerialPortImpl::~SerialPortImpl() {
64 // Cancel I/O operations so that |io_handler_| drops its self-reference.
65 io_handler_->Close(base::DoNothing());
68 void SerialPortImpl::OpenPort(const mojom::SerialConnectionOptions& options,
69 OpenCallback callback) {
71 options, base::BindOnce(&SerialPortImpl::PortOpened,
72 weak_factory_.GetWeakPtr(), std::move(callback)));
75 void SerialPortImpl::PortOpened(OpenCallback callback, bool success) {
76 mojo::PendingRemote<SerialPort> port;
78 port = receiver_.BindNewPipeAndPassRemote();
79 receiver_.set_disconnect_handler(base::BindOnce(
80 [](SerialPortImpl* self) { delete self; }, base::Unretained(this)));
83 std::move(callback).Run(std::move(port));
89 void SerialPortImpl::StartWriting(mojo::ScopedDataPipeConsumerHandle consumer) {
91 receiver_.ReportBadMessage("Data pipe consumer still open.");
95 in_stream_watcher_.Cancel();
96 in_stream_ = std::move(consumer);
97 in_stream_watcher_.Watch(
99 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
100 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
101 base::BindRepeating(&SerialPortImpl::WriteToPort,
102 weak_factory_.GetWeakPtr()));
103 in_stream_watcher_.ArmOrNotify();
106 void SerialPortImpl::StartReading(mojo::ScopedDataPipeProducerHandle producer) {
108 receiver_.ReportBadMessage("Data pipe producer still open.");
112 out_stream_watcher_.Cancel();
113 out_stream_ = std::move(producer);
114 out_stream_watcher_.Watch(
116 MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
117 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
118 base::BindRepeating(&SerialPortImpl::ReadFromPortAndWriteOut,
119 weak_factory_.GetWeakPtr()));
120 out_stream_watcher_.ArmOrNotify();
123 void SerialPortImpl::Flush(mojom::SerialPortFlushMode mode,
124 FlushCallback callback) {
126 case mojom::SerialPortFlushMode::kReceiveAndTransmit:
127 // Do nothing. This case exists to support the chrome.serial.flush()
130 case mojom::SerialPortFlushMode::kReceive:
131 io_handler_->CancelRead(mojom::SerialReceiveError::NONE);
133 case mojom::SerialPortFlushMode::kTransmit:
134 io_handler_->CancelWrite(mojom::SerialSendError::NONE);
138 io_handler_->Flush(mode);
141 case mojom::SerialPortFlushMode::kReceiveAndTransmit:
142 // Do nothing. This case exists to support the chrome.serial.flush()
145 case mojom::SerialPortFlushMode::kReceive:
146 if (io_handler_->IsReadPending()) {
147 // Delay closing |out_stream_| because |io_handler_| still holds a
148 // pointer into the shared memory owned by the pipe.
149 read_flush_callback_ = std::move(callback);
153 out_stream_watcher_.Cancel();
156 case mojom::SerialPortFlushMode::kTransmit:
157 if (io_handler_->IsWritePending()) {
158 // Delay closing |in_stream_| because |io_handler_| still holds a
159 // pointer into the shared memory owned by the pipe.
160 write_flush_callback_ = std::move(callback);
164 in_stream_watcher_.Cancel();
169 std::move(callback).Run();
172 void SerialPortImpl::Drain(DrainCallback callback) {
174 std::move(callback).Run();
178 drain_callback_ = std::move(callback);
181 void SerialPortImpl::GetControlSignals(GetControlSignalsCallback callback) {
182 std::move(callback).Run(io_handler_->GetControlSignals());
185 void SerialPortImpl::SetControlSignals(
186 mojom::SerialHostControlSignalsPtr signals,
187 SetControlSignalsCallback callback) {
188 std::move(callback).Run(io_handler_->SetControlSignals(*signals));
191 void SerialPortImpl::ConfigurePort(mojom::SerialConnectionOptionsPtr options,
192 ConfigurePortCallback callback) {
193 std::move(callback).Run(io_handler_->ConfigurePort(*options));
194 // Cancel pending reading as the new configure options are applied.
195 io_handler_->CancelRead(mojom::SerialReceiveError::NONE);
198 void SerialPortImpl::GetPortInfo(GetPortInfoCallback callback) {
199 std::move(callback).Run(io_handler_->GetPortInfo());
202 void SerialPortImpl::Close(bool flush, CloseCallback callback) {
204 io_handler_->Flush(mojom::SerialPortFlushMode::kReceiveAndTransmit);
207 io_handler_->Close(base::BindOnce(&SerialPortImpl::PortClosed,
208 weak_factory_.GetWeakPtr(),
209 std::move(callback)));
212 void SerialPortImpl::WriteToPort(MojoResult result,
213 const mojo::HandleSignalsState& state) {
217 if (result == MOJO_RESULT_OK) {
219 result = in_stream_->BeginReadData(&buffer, &num_bytes,
220 MOJO_WRITE_DATA_FLAG_NONE);
222 if (result == MOJO_RESULT_OK) {
224 base::make_span(reinterpret_cast<const uint8_t*>(buffer), num_bytes),
225 base::BindOnce(&SerialPortImpl::OnWriteToPortCompleted,
226 weak_factory_.GetWeakPtr(), num_bytes));
229 if (result == MOJO_RESULT_SHOULD_WAIT) {
230 // If there is no space to write, wait for more space.
231 in_stream_watcher_.ArmOrNotify();
234 if (result == MOJO_RESULT_FAILED_PRECONDITION ||
235 result == MOJO_RESULT_CANCELLED) {
236 // The |in_stream_| has been closed.
237 in_stream_watcher_.Cancel();
240 if (drain_callback_) {
241 io_handler_->Drain();
242 std::move(drain_callback_).Run();
246 // The code should not reach other cases.
250 void SerialPortImpl::OnWriteToPortCompleted(uint32_t bytes_expected,
252 mojom::SerialSendError error) {
254 in_stream_->EndReadData(bytes_sent);
256 if (error != mojom::SerialSendError::NONE) {
257 in_stream_watcher_.Cancel();
260 client_->OnSendError(error);
265 in_stream_watcher_.ArmOrNotify();
268 void SerialPortImpl::ReadFromPortAndWriteOut(
270 const mojo::HandleSignalsState& state) {
273 if (result == MOJO_RESULT_OK) {
275 result = out_stream_->BeginWriteData(&buffer, &num_bytes,
276 MOJO_WRITE_DATA_FLAG_NONE);
278 if (result == MOJO_RESULT_OK) {
280 base::make_span(reinterpret_cast<uint8_t*>(buffer), num_bytes),
281 base::BindOnce(&SerialPortImpl::WriteToOutStream,
282 weak_factory_.GetWeakPtr()));
285 if (result == MOJO_RESULT_SHOULD_WAIT) {
286 // If there is no space to write, wait for more space.
287 out_stream_watcher_.ArmOrNotify();
290 if (result == MOJO_RESULT_FAILED_PRECONDITION ||
291 result == MOJO_RESULT_CANCELLED) {
292 // The |out_stream_| has been closed.
293 out_stream_watcher_.Cancel();
297 // The code should not reach other cases.
298 NOTREACHED() << "Unexpected Mojo result: " << result;
301 void SerialPortImpl::WriteToOutStream(uint32_t bytes_read,
302 mojom::SerialReceiveError error) {
304 out_stream_->EndWriteData(bytes_read);
306 if (error != mojom::SerialReceiveError::NONE) {
307 out_stream_watcher_.Cancel();
310 client_->OnReadError(error);
311 if (read_flush_callback_)
312 std::move(read_flush_callback_).Run();
316 if (read_flush_callback_) {
317 std::move(read_flush_callback_).Run();
318 out_stream_watcher_.Cancel();
323 out_stream_watcher_.ArmOrNotify();
326 void SerialPortImpl::PortClosed(CloseCallback callback) {
327 std::move(callback).Run();
331 } // namespace device