1 // Copyright 2014 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 #ifndef SERVICES_DEVICE_SERIAL_SERIAL_IO_HANDLER_H_
6 #define SERVICES_DEVICE_SERIAL_SERIAL_IO_HANDLER_H_
13 #include "base/callback.h"
14 #include "base/files/file.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/sequence_checker.h"
17 #include "base/task/single_thread_task_runner.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "build/build_config.h"
20 #include "services/device/public/mojom/serial.mojom.h"
24 // Provides a simplified interface for performing asynchronous I/O on serial
25 // devices by hiding platform-specific MessageLoop interfaces. Pending I/O
26 // operations hold a reference to this object until completion so that memory
27 // doesn't disappear out from under the OS.
28 class SerialIoHandler : public base::RefCountedThreadSafe<SerialIoHandler> {
30 // Constructs an instance of some platform-specific subclass.
31 static scoped_refptr<SerialIoHandler> Create(
32 const base::FilePath& port,
33 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
35 SerialIoHandler(const SerialIoHandler&) = delete;
36 SerialIoHandler& operator=(const SerialIoHandler&) = delete;
38 using OpenCompleteCallback = base::OnceCallback<void(bool success)>;
39 using ReadCompleteCallback =
40 base::OnceCallback<void(uint32_t bytes_read, mojom::SerialReceiveError)>;
41 using WriteCompleteCallback =
42 base::OnceCallback<void(uint32_t bytes_written, mojom::SerialSendError)>;
44 // Initiates an asynchronous Open of the device.
45 virtual void Open(const mojom::SerialConnectionOptions& options,
46 OpenCompleteCallback callback);
48 #if BUILDFLAG(IS_CHROMEOS)
49 // Signals that the port has been opened.
51 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
54 // Signals that the permission broker failed to open the port.
56 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
57 const std::string& error_name,
58 const std::string& error_message);
60 // Reports the open error from the permission broker.
61 void ReportPathOpenError(const std::string& error_name,
62 const std::string& error_message);
63 #endif // BUILDFLAG(IS_CHROMEOS)
65 // Performs an async read operation. Behavior is undefined if this is called
66 // while a read is already pending. Otherwise, |callback| will be called
67 // (potentially synchronously) with a result. |buffer| must remain valid until
69 void Read(base::span<uint8_t> buffer, ReadCompleteCallback callback);
71 // Performs an async write operation. Behavior is undefined if this is called
72 // while a write is already pending. Otherwise, |callback| will be called
73 // (potentially synchronously) with a result. |buffer| must remain valid until
75 void Write(base::span<const uint8_t> buffer, WriteCompleteCallback callback);
77 // Indicates whether or not a read is currently pending.
78 bool IsReadPending() const;
80 // Indicates whether or not a write is currently pending.
81 bool IsWritePending() const;
83 // Attempts to cancel a pending read operation.
84 void CancelRead(mojom::SerialReceiveError reason);
86 // Attempts to cancel a pending write operation.
87 void CancelWrite(mojom::SerialSendError reason);
89 // Flushes input and output buffers.
90 virtual void Flush(mojom::SerialPortFlushMode mode) const = 0;
92 // Drains output buffers.
93 virtual void Drain() = 0;
95 // Reads current control signals (DCD, CTS, etc.) into an existing
96 // DeviceControlSignals structure. Returns |true| iff the signals were
98 virtual mojom::SerialPortControlSignalsPtr GetControlSignals() const = 0;
100 // Sets one or more control signals. Returns |true| iff the signals were
101 // successfully set. Flags not present in |control_signals| are unchanged.
102 virtual bool SetControlSignals(
103 const mojom::SerialHostControlSignals& control_signals) = 0;
105 // Performs platform-specific port configuration. Returns |true| iff
106 // configuration was successful.
107 bool ConfigurePort(const mojom::SerialConnectionOptions& options);
109 // Performs a platform-specific port configuration query. Fills values in an
110 // existing ConnectionInfo. Returns |true| iff port configuration was
111 // successfully retrieved.
112 virtual mojom::SerialConnectionInfoPtr GetPortInfo() const = 0;
114 // Initiates an asynchronous close of the port.
115 void Close(base::OnceClosure callback);
118 explicit SerialIoHandler(
119 const base::FilePath& port,
120 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
121 virtual ~SerialIoHandler();
123 // Performs a platform-specific read operation. This must guarantee that
124 // ReadCompleted is called when the underlying async operation is completed
125 // or the SerialIoHandler instance will leak.
126 // NOTE: Implementations of ReadImpl may call ReadCompleted directly.
127 virtual void ReadImpl() = 0;
129 // Performs a platform-specific write operation. This must guarantee that
130 // WriteCompleted is called when the underlying async operation is completed
131 // or the SerialIoHandler instance will leak.
132 // NOTE: Implementations of WriteImpl may call WriteCompleted directly.
133 virtual void WriteImpl() = 0;
135 // Platform-specific read cancelation.
136 virtual void CancelReadImpl() = 0;
138 // Platform-specific write cancelation.
139 virtual void CancelWriteImpl() = 0;
141 // Platform-specific port configuration applies options_ to the device.
142 virtual bool ConfigurePortImpl() = 0;
144 // Performs platform-specific, one-time port configuration on open.
145 virtual bool PostOpen();
147 // Performs platform-specific operations before |file_| is closed.
148 virtual void PreClose();
150 // Called by the implementation to signal that the active read has completed.
151 // WARNING: Calling this method can destroy the SerialIoHandler instance
152 // if the associated I/O operation was the only thing keeping it alive.
153 void ReadCompleted(int bytes_read, mojom::SerialReceiveError error);
155 // Called by the implementation to signal that the active write has completed.
156 // WARNING: Calling this method may destroy the SerialIoHandler instance
157 // if the associated I/O operation was the only thing keeping it alive.
158 void WriteCompleted(int bytes_written, mojom::SerialSendError error);
160 const base::File& file() const { return file_; }
162 base::span<uint8_t> pending_read_buffer() const {
163 return pending_read_buffer_;
166 mojom::SerialReceiveError read_cancel_reason() const {
167 return read_cancel_reason_;
170 bool read_canceled() const { return read_canceled_; }
172 base::span<const uint8_t> pending_write_buffer() const {
173 return pending_write_buffer_;
176 mojom::SerialSendError write_cancel_reason() const {
177 return write_cancel_reason_;
180 bool write_canceled() const { return write_canceled_; }
182 const mojom::SerialConnectionOptions& options() const { return options_; }
184 base::SingleThreadTaskRunner* ui_thread_task_runner() const {
185 return ui_thread_task_runner_.get();
188 const base::FilePath& port() const { return port_; }
190 SEQUENCE_CHECKER(sequence_checker_);
193 friend class base::RefCountedThreadSafe<SerialIoHandler>;
195 void MergeConnectionOptions(const mojom::SerialConnectionOptions& options);
197 // Continues an Open operation on the FILE thread.
198 void StartOpen(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
200 // Finalizes an Open operation (continued from StartOpen) on the IO thread.
201 void FinishOpen(base::File file);
203 // Continues a Close operation on the FILE thread.
204 static void DoClose(base::File port);
206 // File for the opened serial device. This value is only modified from the IO
210 // Currently applied connection options.
211 mojom::SerialConnectionOptions options_;
213 base::span<uint8_t> pending_read_buffer_;
214 ReadCompleteCallback pending_read_callback_;
215 mojom::SerialReceiveError read_cancel_reason_;
218 base::span<const uint8_t> pending_write_buffer_;
219 WriteCompleteCallback pending_write_callback_;
220 mojom::SerialSendError write_cancel_reason_;
221 bool write_canceled_;
223 // Callback to handle the completion of a pending Open() request.
224 OpenCompleteCallback open_complete_;
226 const base::FilePath port_;
228 // On Chrome OS, PermissionBrokerClient should be called on the UI thread.
229 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
232 } // namespace device
234 #endif // SERVICES_DEVICE_SERIAL_SERIAL_IO_HANDLER_H_