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/files/file.h"
14 #include "base/functional/callback.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 "build/build_config.h"
19 #include "services/device/public/mojom/serial.mojom.h"
23 // Provides a simplified interface for performing asynchronous I/O on serial
24 // devices by hiding platform-specific MessageLoop interfaces. Pending I/O
25 // operations hold a reference to this object until completion so that memory
26 // doesn't disappear out from under the OS.
27 class SerialIoHandler : public base::RefCountedThreadSafe<SerialIoHandler> {
29 // Constructs an instance of some platform-specific subclass.
30 static scoped_refptr<SerialIoHandler> Create(
31 const base::FilePath& port,
32 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
34 SerialIoHandler(const SerialIoHandler&) = delete;
35 SerialIoHandler& operator=(const SerialIoHandler&) = delete;
37 using OpenCompleteCallback = base::OnceCallback<void(bool success)>;
38 using ReadCompleteCallback =
39 base::OnceCallback<void(uint32_t bytes_read, mojom::SerialReceiveError)>;
40 using WriteCompleteCallback =
41 base::OnceCallback<void(uint32_t bytes_written, mojom::SerialSendError)>;
43 // Initiates an asynchronous Open of the device.
44 virtual void Open(const mojom::SerialConnectionOptions& options,
45 OpenCompleteCallback callback);
47 #if BUILDFLAG(IS_CHROMEOS)
48 // Signals that the port has been opened.
50 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
53 // Signals that the permission broker failed to open the port.
55 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
56 const std::string& error_name,
57 const std::string& error_message);
59 // Reports the open error from the permission broker.
60 void ReportPathOpenError(const std::string& error_name,
61 const std::string& error_message);
62 #endif // BUILDFLAG(IS_CHROMEOS)
64 // Performs an async read operation. Behavior is undefined if this is called
65 // while a read is already pending. Otherwise, |callback| will be called
66 // (potentially synchronously) with a result. |buffer| must remain valid until
68 void Read(base::span<uint8_t> buffer, ReadCompleteCallback callback);
70 // Performs an async write operation. Behavior is undefined if this is called
71 // while a write is already pending. Otherwise, |callback| will be called
72 // (potentially synchronously) with a result. |buffer| must remain valid until
74 void Write(base::span<const uint8_t> buffer, WriteCompleteCallback callback);
76 // Indicates whether or not a read is currently pending.
77 bool IsReadPending() const;
79 // Indicates whether or not a write is currently pending.
80 bool IsWritePending() const;
82 // Attempts to cancel a pending read operation.
83 void CancelRead(mojom::SerialReceiveError reason);
85 // Attempts to cancel a pending write operation.
86 void CancelWrite(mojom::SerialSendError reason);
88 // Flushes input and output buffers.
89 virtual void Flush(mojom::SerialPortFlushMode mode) const = 0;
91 // Drains output buffers.
92 virtual void Drain() = 0;
94 // Reads current control signals (DCD, CTS, etc.) into an existing
95 // DeviceControlSignals structure. Returns |true| iff the signals were
97 virtual mojom::SerialPortControlSignalsPtr GetControlSignals() const = 0;
99 // Sets one or more control signals. Returns |true| iff the signals were
100 // successfully set. Flags not present in |control_signals| are unchanged.
101 virtual bool SetControlSignals(
102 const mojom::SerialHostControlSignals& control_signals) = 0;
104 // Performs platform-specific port configuration. Returns |true| iff
105 // configuration was successful.
106 bool ConfigurePort(const mojom::SerialConnectionOptions& options);
108 // Performs a platform-specific port configuration query. Fills values in an
109 // existing ConnectionInfo. Returns |true| iff port configuration was
110 // successfully retrieved.
111 virtual mojom::SerialConnectionInfoPtr GetPortInfo() const = 0;
113 // Initiates an asynchronous close of the port.
114 void Close(base::OnceClosure callback);
117 explicit SerialIoHandler(
118 const base::FilePath& port,
119 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
120 virtual ~SerialIoHandler();
122 // Performs a platform-specific read operation. This must guarantee that
123 // ReadCompleted is called when the underlying async operation is completed
124 // or the SerialIoHandler instance will leak.
125 // NOTE: Implementations of ReadImpl may call ReadCompleted directly.
126 virtual void ReadImpl() = 0;
128 // Performs a platform-specific write operation. This must guarantee that
129 // WriteCompleted is called when the underlying async operation is completed
130 // or the SerialIoHandler instance will leak.
131 // NOTE: Implementations of WriteImpl may call WriteCompleted directly.
132 virtual void WriteImpl() = 0;
134 // Platform-specific read cancelation.
135 virtual void CancelReadImpl() = 0;
137 // Platform-specific write cancelation.
138 virtual void CancelWriteImpl() = 0;
140 // Platform-specific port configuration applies options_ to the device.
141 virtual bool ConfigurePortImpl() = 0;
143 // Performs platform-specific, one-time port configuration on open.
144 virtual bool PostOpen();
146 // Performs platform-specific operations before |file_| is closed.
147 virtual void PreClose();
149 // Called by the implementation to signal that the active read has completed.
150 // WARNING: Calling this method can destroy the SerialIoHandler instance
151 // if the associated I/O operation was the only thing keeping it alive.
152 void ReadCompleted(int bytes_read, mojom::SerialReceiveError error);
154 // Called by the implementation to signal that the active write has completed.
155 // WARNING: Calling this method may destroy the SerialIoHandler instance
156 // if the associated I/O operation was the only thing keeping it alive.
157 void WriteCompleted(int bytes_written, mojom::SerialSendError error);
159 const base::File& file() const { return file_; }
161 base::span<uint8_t> pending_read_buffer() const {
162 return pending_read_buffer_;
165 mojom::SerialReceiveError read_cancel_reason() const {
166 return read_cancel_reason_;
169 bool read_canceled() const { return read_canceled_; }
171 base::span<const uint8_t> pending_write_buffer() const {
172 return pending_write_buffer_;
175 mojom::SerialSendError write_cancel_reason() const {
176 return write_cancel_reason_;
179 bool write_canceled() const { return write_canceled_; }
181 const mojom::SerialConnectionOptions& options() const { return options_; }
183 base::SingleThreadTaskRunner* ui_thread_task_runner() const {
184 return ui_thread_task_runner_.get();
187 const base::FilePath& port() const { return port_; }
189 SEQUENCE_CHECKER(sequence_checker_);
192 friend class base::RefCountedThreadSafe<SerialIoHandler>;
194 void MergeConnectionOptions(const mojom::SerialConnectionOptions& options);
196 // Continues an Open operation on the FILE thread.
197 void StartOpen(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
199 // Finalizes an Open operation (continued from StartOpen) on the IO thread.
200 void FinishOpen(base::File file);
202 // Continues a Close operation on the FILE thread.
203 static void DoClose(base::File port);
205 // File for the opened serial device. This value is only modified from the IO
209 // Currently applied connection options.
210 mojom::SerialConnectionOptions options_;
212 base::span<uint8_t> pending_read_buffer_;
213 ReadCompleteCallback pending_read_callback_;
214 mojom::SerialReceiveError read_cancel_reason_;
217 base::span<const uint8_t> pending_write_buffer_;
218 WriteCompleteCallback pending_write_callback_;
219 mojom::SerialSendError write_cancel_reason_;
220 bool write_canceled_;
222 // Callback to handle the completion of a pending Open() request.
223 OpenCompleteCallback open_complete_;
225 const base::FilePath port_;
227 // On Chrome OS, PermissionBrokerClient should be called on the UI thread.
228 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
231 } // namespace device
233 #endif // SERVICES_DEVICE_SERIAL_SERIAL_IO_HANDLER_H_