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