1 // Copyright 2012 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 #include "chrome/browser/extensions/api/serial/serial_connection.h"
9 #include "base/files/file_path.h"
10 #include "base/lazy_instance.h"
11 #include "base/strings/string_util.h"
12 #include "chrome/common/extensions/api/serial.h"
13 #include "extensions/browser/api/api_resource_manager.h"
15 namespace extensions
{
19 const int kDefaultBufferSize
= 4096;
22 static base::LazyInstance
<
23 BrowserContextKeyedAPIFactory
<ApiResourceManager
<SerialConnection
> > >
24 g_factory
= LAZY_INSTANCE_INITIALIZER
;
28 BrowserContextKeyedAPIFactory
<ApiResourceManager
<SerialConnection
> >*
29 ApiResourceManager
<SerialConnection
>::GetFactoryInstance() {
30 return g_factory
.Pointer();
33 SerialConnection::SerialConnection(const std::string
& port
,
34 const std::string
& owner_extension_id
)
35 : ApiResource(owner_extension_id
),
38 buffer_size_(kDefaultBufferSize
),
42 io_handler_(SerialIoHandler::Create()) {
43 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
46 SerialConnection::~SerialConnection() {
47 DCHECK(open_complete_
.is_null());
48 io_handler_
->CancelRead(api::serial::RECEIVE_ERROR_DISCONNECTED
);
49 io_handler_
->CancelWrite(api::serial::SEND_ERROR_DISCONNECTED
);
53 bool SerialConnection::IsPersistent() const { return persistent(); }
55 void SerialConnection::set_buffer_size(int buffer_size
) {
56 buffer_size_
= buffer_size
;
59 void SerialConnection::set_receive_timeout(int receive_timeout
) {
60 receive_timeout_
= receive_timeout
;
63 void SerialConnection::set_send_timeout(int send_timeout
) {
64 send_timeout_
= send_timeout
;
67 void SerialConnection::set_paused(bool paused
) {
70 io_handler_
->CancelRead(api::serial::RECEIVE_ERROR_NONE
);
74 void SerialConnection::Open(const OpenCompleteCallback
& callback
) {
75 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
76 DCHECK(open_complete_
.is_null());
77 open_complete_
= callback
;
78 BrowserThread::PostTask(
81 base::Bind(&SerialConnection::StartOpen
, base::Unretained(this)));
84 void SerialConnection::Close() {
85 DCHECK(open_complete_
.is_null());
86 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
87 if (file_
.IsValid()) {
88 BrowserThread::PostTask(
91 base::Bind(&SerialConnection::DoClose
, Passed(file_
.Pass())));
95 bool SerialConnection::Receive(const ReceiveCompleteCallback
& callback
) {
96 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
97 if (!receive_complete_
.is_null())
99 receive_complete_
= callback
;
100 io_handler_
->Read(buffer_size_
);
101 receive_timeout_task_
.reset();
102 if (receive_timeout_
> 0) {
103 receive_timeout_task_
.reset(new TimeoutTask(
104 base::Bind(&SerialConnection::OnReceiveTimeout
, AsWeakPtr()),
105 base::TimeDelta::FromMilliseconds(receive_timeout_
)));
110 bool SerialConnection::Send(const std::string
& data
,
111 const SendCompleteCallback
& callback
) {
112 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
113 if (!send_complete_
.is_null())
115 send_complete_
= callback
;
116 io_handler_
->Write(data
);
117 send_timeout_task_
.reset();
118 if (send_timeout_
> 0) {
119 send_timeout_task_
.reset(new TimeoutTask(
120 base::Bind(&SerialConnection::OnSendTimeout
, AsWeakPtr()),
121 base::TimeDelta::FromMilliseconds(send_timeout_
)));
126 bool SerialConnection::Configure(
127 const api::serial::ConnectionOptions
& options
) {
128 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
129 if (options
.persistent
.get())
130 set_persistent(*options
.persistent
);
131 if (options
.name
.get())
132 set_name(*options
.name
);
133 if (options
.buffer_size
.get())
134 set_buffer_size(*options
.buffer_size
);
135 if (options
.receive_timeout
.get())
136 set_receive_timeout(*options
.receive_timeout
);
137 if (options
.send_timeout
.get())
138 set_send_timeout(*options
.send_timeout
);
139 bool success
= ConfigurePort(options
);
140 io_handler_
->CancelRead(api::serial::RECEIVE_ERROR_NONE
);
144 void SerialConnection::SetIoHandlerForTest(
145 scoped_refptr
<SerialIoHandler
> handler
) {
146 io_handler_
= handler
;
149 bool SerialConnection::GetInfo(api::serial::ConnectionInfo
* info
) const {
150 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
151 info
->paused
= paused_
;
152 info
->persistent
= persistent_
;
154 info
->buffer_size
= buffer_size_
;
155 info
->receive_timeout
= receive_timeout_
;
156 info
->send_timeout
= send_timeout_
;
157 return GetPortInfo(info
);
160 void SerialConnection::StartOpen() {
161 DCHECK(!open_complete_
.is_null());
162 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
163 DCHECK(!file_
.IsValid());
164 // It's the responsibility of the API wrapper around SerialConnection to
165 // validate the supplied path against the set of valid port names, and
166 // it is a reasonable assumption that serial port names are ASCII.
167 DCHECK(IsStringASCII(port_
));
169 base::FilePath::FromUTF8Unsafe(MaybeFixUpPortName(port_
)));
170 int flags
= base::File::FLAG_OPEN
| base::File::FLAG_READ
|
171 base::File::FLAG_EXCLUSIVE_READ
| base::File::FLAG_WRITE
|
172 base::File::FLAG_EXCLUSIVE_WRITE
| base::File::FLAG_ASYNC
|
173 base::File::FLAG_TERMINAL_DEVICE
;
174 base::File
file(path
, flags
);
175 BrowserThread::PostTask(
178 base::Bind(&SerialConnection::FinishOpen
, base::Unretained(this),
179 Passed(file
.Pass())));
182 void SerialConnection::FinishOpen(base::File file
) {
183 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
184 DCHECK(!open_complete_
.is_null());
185 DCHECK(!file_
.IsValid());
186 OpenCompleteCallback callback
= open_complete_
;
187 open_complete_
.Reset();
189 if (!file
.IsValid()) {
194 // TODO(rvargas): crbug.com/351073. This is wrong. io_handler_ keeps a copy of
195 // the handler that is not in sync with this one.
197 io_handler_
->Initialize(
198 file_
.GetPlatformFile(),
199 base::Bind(&SerialConnection::OnAsyncReadComplete
, AsWeakPtr()),
200 base::Bind(&SerialConnection::OnAsyncWriteComplete
, AsWeakPtr()));
202 bool success
= PostOpen();
207 callback
.Run(success
);
211 void SerialConnection::DoClose(base::File port
) {
212 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
213 // port closed by destructor.
216 void SerialConnection::OnReceiveTimeout() {
217 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
218 io_handler_
->CancelRead(api::serial::RECEIVE_ERROR_TIMEOUT
);
221 void SerialConnection::OnSendTimeout() {
222 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
223 io_handler_
->CancelWrite(api::serial::SEND_ERROR_TIMEOUT
);
226 void SerialConnection::OnAsyncReadComplete(const std::string
& data
,
227 api::serial::ReceiveError error
) {
228 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
229 DCHECK(!receive_complete_
.is_null());
230 ReceiveCompleteCallback callback
= receive_complete_
;
231 receive_complete_
.Reset();
232 receive_timeout_task_
.reset();
233 callback
.Run(data
, error
);
236 void SerialConnection::OnAsyncWriteComplete(int bytes_sent
,
237 api::serial::SendError error
) {
238 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
239 DCHECK(!send_complete_
.is_null());
240 SendCompleteCallback callback
= send_complete_
;
241 send_complete_
.Reset();
242 send_timeout_task_
.reset();
243 callback
.Run(bytes_sent
, error
);
246 SerialConnection::TimeoutTask::TimeoutTask(const base::Closure
& closure
,
247 const base::TimeDelta
& delay
)
248 : weak_factory_(this), closure_(closure
), delay_(delay
) {
249 base::MessageLoop::current()->PostDelayedTask(
251 base::Bind(&TimeoutTask::Run
, weak_factory_
.GetWeakPtr()),
255 SerialConnection::TimeoutTask::~TimeoutTask() {}
257 void SerialConnection::TimeoutTask::Run() const { closure_
.Run(); }
259 } // namespace extensions