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.
4
5#ifndef DEVICE_SERIAL_SERIAL_IO_HANDLER_H_
6#define DEVICE_SERIAL_SERIAL_IO_HANDLER_H_
7
8#include "base/callback.h"
9#include "base/files/file.h"
10#include "base/memory/ref_counted.h"
11#include "base/message_loop/message_loop_proxy.h"
12#include "base/threading/non_thread_safe.h"
13#include "device/serial/buffer.h"
14#include "device/serial/serial.mojom.h"
15
16namespace device {
17
18// Provides a simplified interface for performing asynchronous I/O on serial
19// devices by hiding platform-specific MessageLoop interfaces. Pending I/O
20// operations hold a reference to this object until completion so that memory
21// doesn't disappear out from under the OS.
22class SerialIoHandler : public base::NonThreadSafe,
23                        public base::RefCounted<SerialIoHandler> {
24 public:
25  // Constructs an instance of some platform-specific subclass.
26  static scoped_refptr<SerialIoHandler> Create(
27      scoped_refptr<base::MessageLoopProxy> file_thread_message_loop);
28
29  typedef base::Callback<void(bool success)> OpenCompleteCallback;
30
31  // Initiates an asynchronous Open of the device.
32  virtual void Open(const std::string& port,
33                    const OpenCompleteCallback& callback);
34
35  // Performs an async Read operation. Behavior is undefined if this is called
36  // while a Read is already pending. Otherwise, the Done or DoneWithError
37  // method on |buffer| will eventually be called with a result.
38  void Read(scoped_ptr<WritableBuffer> buffer);
39
40  // Performs an async Write operation. Behavior is undefined if this is called
41  // while a Write is already pending. Otherwise, the Done or DoneWithError
42  // method on |buffer| will eventually be called with a result.
43  void Write(scoped_ptr<ReadOnlyBuffer> buffer);
44
45  // Indicates whether or not a read is currently pending.
46  bool IsReadPending() const;
47
48  // Indicates whether or not a write is currently pending.
49  bool IsWritePending() const;
50
51  // Attempts to cancel a pending read operation.
52  void CancelRead(serial::ReceiveError reason);
53
54  // Attempts to cancel a pending write operation.
55  void CancelWrite(serial::SendError reason);
56
57  // Flushes input and output buffers.
58  virtual bool Flush() const = 0;
59
60  // Reads current control signals (DCD, CTS, etc.) into an existing
61  // DeviceControlSignals structure. Returns |true| iff the signals were
62  // successfully read.
63  virtual serial::DeviceControlSignalsPtr GetControlSignals() const = 0;
64
65  // Sets one or more control signals (DTR and/or RTS). Returns |true| iff
66  // the signals were successfully set. Unininitialized flags in the
67  // HostControlSignals structure are left unchanged.
68  virtual bool SetControlSignals(
69      const serial::HostControlSignals& control_signals) = 0;
70
71  // Performs platform-specific port configuration. Returns |true| iff
72  // configuration was successful.
73  virtual bool ConfigurePort(const serial::ConnectionOptions& options) = 0;
74
75  // Performs a platform-specific port configuration query. Fills values in an
76  // existing ConnectionInfo. Returns |true| iff port configuration was
77  // successfully retrieved.
78  virtual serial::ConnectionInfoPtr GetPortInfo() const = 0;
79
80 protected:
81  explicit SerialIoHandler(
82      scoped_refptr<base::MessageLoopProxy> file_thread_message_loop);
83  virtual ~SerialIoHandler();
84
85  // Performs a platform-specific read operation. This must guarantee that
86  // ReadCompleted is called when the underlying async operation is completed
87  // or the SerialIoHandler instance will leak.
88  // NOTE: Implementations of ReadImpl should never call ReadCompleted directly.
89  // Use QueueReadCompleted instead to avoid reentrancy.
90  virtual void ReadImpl() = 0;
91
92  // Performs a platform-specific write operation. This must guarantee that
93  // WriteCompleted is called when the underlying async operation is completed
94  // or the SerialIoHandler instance will leak.
95  // NOTE: Implementations of Writempl should never call WriteCompleted
96  // directly. Use QueueWriteCompleted instead to avoid reentrancy.
97  virtual void WriteImpl() = 0;
98
99  // Platform-specific read cancelation.
100  virtual void CancelReadImpl() = 0;
101
102  // Platform-specific write cancelation.
103  virtual void CancelWriteImpl() = 0;
104
105  // Performs platform-specific, one-time port configuration on open.
106  virtual bool PostOpen();
107
108  // Called by the implementation to signal that the active read has completed.
109  // WARNING: Calling this method can destroy the SerialIoHandler instance
110  // if the associated I/O operation was the only thing keeping it alive.
111  void ReadCompleted(int bytes_read, serial::ReceiveError error);
112
113  // Called by the implementation to signal that the active write has completed.
114  // WARNING: Calling this method may destroy the SerialIoHandler instance
115  // if the associated I/O operation was the only thing keeping it alive.
116  void WriteCompleted(int bytes_written, serial::SendError error);
117
118  // Queues a ReadCompleted call on the current thread. This is used to allow
119  // ReadImpl to immediately signal completion with 0 bytes and an error,
120  // without being reentrant.
121  void QueueReadCompleted(int bytes_read, serial::ReceiveError error);
122
123  // Queues a WriteCompleted call on the current thread. This is used to allow
124  // WriteImpl to immediately signal completion with 0 bytes and an error,
125  // without being reentrant.
126  void QueueWriteCompleted(int bytes_written, serial::SendError error);
127
128  const base::File& file() const { return file_; }
129
130  char* pending_read_buffer() const {
131    return pending_read_buffer_ ? pending_read_buffer_->GetData() : NULL;
132  }
133
134  uint32_t pending_read_buffer_len() const {
135    return pending_read_buffer_ ? pending_read_buffer_->GetSize() : 0;
136  }
137
138  serial::ReceiveError read_cancel_reason() const {
139    return read_cancel_reason_;
140  }
141
142  bool read_canceled() const { return read_canceled_; }
143
144  const char* pending_write_buffer() const {
145    return pending_write_buffer_ ? pending_write_buffer_->GetData() : NULL;
146  }
147
148  uint32_t pending_write_buffer_len() const {
149    return pending_write_buffer_ ? pending_write_buffer_->GetSize() : 0;
150  }
151
152  serial::SendError write_cancel_reason() const { return write_cancel_reason_; }
153
154  bool write_canceled() const { return write_canceled_; }
155
156  // Possibly fixes up a serial port path name in a platform-specific manner.
157  static std::string MaybeFixUpPortName(const std::string& port_name);
158
159 private:
160  friend class base::RefCounted<SerialIoHandler>;
161
162  // Continues an Open operation on the FILE thread.
163  void StartOpen(const std::string& port,
164                 scoped_refptr<base::MessageLoopProxy> io_message_loop);
165
166  // Finalizes an Open operation (continued from StartOpen) on the IO thread.
167  void FinishOpen(base::File file);
168
169  void Close();
170
171  // Continues a Close operation on the FILE thread.
172  static void DoClose(base::File port);
173
174  // File for the opened serial device. This value is only modified from the IO
175  // thread.
176  base::File file_;
177
178  scoped_ptr<WritableBuffer> pending_read_buffer_;
179  serial::ReceiveError read_cancel_reason_;
180  bool read_canceled_;
181
182  scoped_ptr<ReadOnlyBuffer> pending_write_buffer_;
183  serial::SendError write_cancel_reason_;
184  bool write_canceled_;
185
186  // Callback to handle the completion of a pending Open() request.
187  OpenCompleteCallback open_complete_;
188
189  scoped_refptr<base::MessageLoopProxy> file_thread_message_loop_;
190
191  DISALLOW_COPY_AND_ASSIGN(SerialIoHandler);
192};
193
194}  // namespace device
195
196#endif  // DEVICE_SERIAL_SERIAL_IO_HANDLER_H_
197