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 #ifndef DEVICE_SERIAL_SERIAL_IO_HANDLER_H_
6 #define DEVICE_SERIAL_SERIAL_IO_HANDLER_H_
12 #include "base/callback.h"
13 #include "base/files/file.h"
14 #include "base/macros.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/sequence_checker.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "build/build_config.h"
20 #include "device/serial/buffer.h"
21 #include "services/device/public/mojom/serial.mojom.h"
25 // Provides a simplified interface for performing asynchronous I/O on serial
26 // devices by hiding platform-specific MessageLoop interfaces. Pending I/O
27 // operations hold a reference to this object until completion so that memory
28 // doesn't disappear out from under the OS.
29 class SerialIoHandler : public base::RefCountedThreadSafe<SerialIoHandler> {
31 // Constructs an instance of some platform-specific subclass.
32 static scoped_refptr<SerialIoHandler> Create(
33 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
35 typedef base::OnceCallback<void(bool success)> OpenCompleteCallback;
37 // Initiates an asynchronous Open of the device.
38 virtual void Open(const std::string& port,
39 const mojom::SerialConnectionOptions& options,
40 OpenCompleteCallback callback);
42 #if defined(OS_CHROMEOS)
43 // Signals that the port has been opened.
45 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
48 // Signals that the permission broker failed to open the port.
50 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
51 const std::string& error_name,
52 const std::string& error_message);
54 // Reports the open error from the permission broker.
55 void ReportPathOpenError(const std::string& error_name,
56 const std::string& error_message);
57 #endif // defined(OS_CHROMEOS)
59 // Performs an async Read operation. Behavior is undefined if this is called
60 // while a Read is already pending. Otherwise, the Done or DoneWithError
61 // method on |buffer| will eventually be called with a result.
62 void Read(std::unique_ptr<WritableBuffer> buffer);
64 // Performs an async Write operation. Behavior is undefined if this is called
65 // while a Write is already pending. Otherwise, the Done or DoneWithError
66 // method on |buffer| will eventually be called with a result.
67 void Write(std::unique_ptr<ReadOnlyBuffer> buffer);
69 // Indicates whether or not a read is currently pending.
70 bool IsReadPending() const;
72 // Indicates whether or not a write is currently pending.
73 bool IsWritePending() const;
75 // Attempts to cancel a pending read operation.
76 void CancelRead(mojom::SerialReceiveError reason);
78 // Attempts to cancel a pending write operation.
79 void CancelWrite(mojom::SerialSendError reason);
81 // Flushes input and output buffers.
82 virtual bool Flush() const = 0;
84 // Reads current control signals (DCD, CTS, etc.) into an existing
85 // DeviceControlSignals structure. Returns |true| iff the signals were
87 virtual mojom::SerialDeviceControlSignalsPtr GetControlSignals() const = 0;
89 // Sets one or more control signals (DTR and/or RTS). Returns |true| iff
90 // the signals were successfully set. Unininitialized flags in the
91 // HostControlSignals structure are left unchanged.
92 virtual bool SetControlSignals(
93 const mojom::SerialHostControlSignals& control_signals) = 0;
95 // Performs platform-specific port configuration. Returns |true| iff
96 // configuration was successful.
97 bool ConfigurePort(const mojom::SerialConnectionOptions& options);
99 // Performs a platform-specific port configuration query. Fills values in an
100 // existing ConnectionInfo. Returns |true| iff port configuration was
101 // successfully retrieved.
102 virtual mojom::SerialConnectionInfoPtr GetPortInfo() const = 0;
104 // Initiates a BREAK signal. Places the transmission line in a break state
105 // until the |ClearBreak| is called.
106 virtual bool SetBreak() = 0;
108 // Terminates the BREAK signal. Places the transmission line in a nonbreak
110 virtual bool ClearBreak() = 0;
113 explicit SerialIoHandler(
114 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
115 virtual ~SerialIoHandler();
117 // Performs a platform-specific read operation. This must guarantee that
118 // ReadCompleted is called when the underlying async operation is completed
119 // or the SerialIoHandler instance will leak.
120 // NOTE: Implementations of ReadImpl should never call ReadCompleted directly.
121 // Use QueueReadCompleted instead to avoid reentrancy.
122 virtual void ReadImpl() = 0;
124 // Performs a platform-specific write operation. This must guarantee that
125 // WriteCompleted is called when the underlying async operation is completed
126 // or the SerialIoHandler instance will leak.
127 // NOTE: Implementations of WriteImpl should never call WriteCompleted
128 // directly. Use QueueWriteCompleted instead to avoid reentrancy.
129 virtual void WriteImpl() = 0;
131 // Platform-specific read cancelation.
132 virtual void CancelReadImpl() = 0;
134 // Platform-specific write cancelation.
135 virtual void CancelWriteImpl() = 0;
137 // Platform-specific port configuration applies options_ to the device.
138 virtual bool ConfigurePortImpl() = 0;
140 // Performs platform-specific, one-time port configuration on open.
141 virtual bool PostOpen();
143 // Called by the implementation to signal that the active read has completed.
144 // WARNING: Calling this method can destroy the SerialIoHandler instance
145 // if the associated I/O operation was the only thing keeping it alive.
146 void ReadCompleted(int bytes_read, mojom::SerialReceiveError error);
148 // Called by the implementation to signal that the active write has completed.
149 // WARNING: Calling this method may destroy the SerialIoHandler instance
150 // if the associated I/O operation was the only thing keeping it alive.
151 void WriteCompleted(int bytes_written, mojom::SerialSendError error);
153 // Queues a ReadCompleted call on the current thread. This is used to allow
154 // ReadImpl to immediately signal completion with 0 bytes and an error,
155 // without being reentrant.
156 void QueueReadCompleted(int bytes_read, mojom::SerialReceiveError error);
158 // Queues a WriteCompleted call on the current thread. This is used to allow
159 // WriteImpl to immediately signal completion with 0 bytes and an error,
160 // without being reentrant.
161 void QueueWriteCompleted(int bytes_written, mojom::SerialSendError error);
163 const base::File& file() const { return file_; }
165 char* pending_read_buffer() const {
166 return pending_read_buffer_ ? pending_read_buffer_->GetData() : NULL;
169 uint32_t pending_read_buffer_len() const {
170 return pending_read_buffer_ ? pending_read_buffer_->GetSize() : 0;
173 mojom::SerialReceiveError read_cancel_reason() const {
174 return read_cancel_reason_;
177 bool read_canceled() const { return read_canceled_; }
179 const uint8_t* pending_write_buffer() const {
180 return pending_write_buffer_ ? pending_write_buffer_->GetData() : NULL;
183 uint32_t pending_write_buffer_len() const {
184 return pending_write_buffer_ ? pending_write_buffer_->GetSize() : 0;
187 mojom::SerialSendError write_cancel_reason() const {
188 return write_cancel_reason_;
191 bool write_canceled() const { return write_canceled_; }
193 const mojom::SerialConnectionOptions& options() const { return options_; }
195 // Possibly fixes up a serial port path name in a platform-specific manner.
196 static std::string MaybeFixUpPortName(const std::string& port_name);
198 base::SingleThreadTaskRunner* ui_thread_task_runner() const {
199 return ui_thread_task_runner_.get();
202 const std::string& port() const { return port_; }
204 SEQUENCE_CHECKER(sequence_checker_);
207 friend class base::RefCountedThreadSafe<SerialIoHandler>;
209 void MergeConnectionOptions(const mojom::SerialConnectionOptions& options);
211 // Continues an Open operation on the FILE thread.
212 void StartOpen(const std::string& port,
213 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
215 // Finalizes an Open operation (continued from StartOpen) on the IO thread.
216 void FinishOpen(base::File file);
220 // Continues a Close operation on the FILE thread.
221 static void DoClose(base::File port);
223 // File for the opened serial device. This value is only modified from the IO
227 // Currently applied connection options.
228 mojom::SerialConnectionOptions options_;
230 std::unique_ptr<WritableBuffer> pending_read_buffer_;
231 mojom::SerialReceiveError read_cancel_reason_;
234 std::unique_ptr<ReadOnlyBuffer> pending_write_buffer_;
235 mojom::SerialSendError write_cancel_reason_;
236 bool write_canceled_;
238 // Callback to handle the completion of a pending Open() request.
239 OpenCompleteCallback open_complete_;
241 // On Chrome OS, PermissionBrokerClient should be called on the UI thread.
242 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
246 DISALLOW_COPY_AND_ASSIGN(SerialIoHandler);
249 } // namespace device
251 #endif // DEVICE_SERIAL_SERIAL_IO_HANDLER_H_