OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/extensions/api/serial/serial_connection.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/files/file_path.h" | |
10 #include "base/lazy_instance.h" | |
11 #include "chrome/common/extensions/api/serial.h" | |
12 #include "extensions/browser/api/api_resource_manager.h" | |
13 | |
14 namespace extensions { | |
15 | |
16 namespace { | |
17 | |
18 const int kDefaultBufferSize = 4096; | |
19 | |
20 api::serial::SendError ConvertSendErrorFromMojo( | |
21 device::serial::SendError input) { | |
22 switch (input) { | |
23 case device::serial::SEND_ERROR_NONE: | |
24 return api::serial::SEND_ERROR_NONE; | |
25 case device::serial::SEND_ERROR_DISCONNECTED: | |
26 return api::serial::SEND_ERROR_DISCONNECTED; | |
27 case device::serial::SEND_ERROR_PENDING: | |
28 return api::serial::SEND_ERROR_PENDING; | |
29 case device::serial::SEND_ERROR_TIMEOUT: | |
30 return api::serial::SEND_ERROR_TIMEOUT; | |
31 case device::serial::SEND_ERROR_SYSTEM_ERROR: | |
32 return api::serial::SEND_ERROR_SYSTEM_ERROR; | |
33 } | |
34 return api::serial::SEND_ERROR_NONE; | |
35 } | |
36 | |
37 api::serial::ReceiveError ConvertReceiveErrorFromMojo( | |
38 device::serial::ReceiveError input) { | |
39 switch (input) { | |
40 case device::serial::RECEIVE_ERROR_NONE: | |
41 return api::serial::RECEIVE_ERROR_NONE; | |
42 case device::serial::RECEIVE_ERROR_DISCONNECTED: | |
43 return api::serial::RECEIVE_ERROR_DISCONNECTED; | |
44 case device::serial::RECEIVE_ERROR_TIMEOUT: | |
45 return api::serial::RECEIVE_ERROR_TIMEOUT; | |
46 case device::serial::RECEIVE_ERROR_DEVICE_LOST: | |
47 return api::serial::RECEIVE_ERROR_DEVICE_LOST; | |
48 case device::serial::RECEIVE_ERROR_SYSTEM_ERROR: | |
49 return api::serial::RECEIVE_ERROR_SYSTEM_ERROR; | |
50 } | |
51 return api::serial::RECEIVE_ERROR_NONE; | |
52 } | |
53 | |
54 api::serial::DataBits ConvertDataBitsFromMojo(device::serial::DataBits input) { | |
55 switch (input) { | |
56 case device::serial::DATA_BITS_NONE: | |
57 return api::serial::DATA_BITS_NONE; | |
58 case device::serial::DATA_BITS_SEVEN: | |
59 return api::serial::DATA_BITS_SEVEN; | |
60 case device::serial::DATA_BITS_EIGHT: | |
61 return api::serial::DATA_BITS_EIGHT; | |
62 } | |
63 return api::serial::DATA_BITS_NONE; | |
64 } | |
65 | |
66 device::serial::DataBits ConvertDataBitsToMojo(api::serial::DataBits input) { | |
67 switch (input) { | |
68 case api::serial::DATA_BITS_NONE: | |
69 return device::serial::DATA_BITS_NONE; | |
70 case api::serial::DATA_BITS_SEVEN: | |
71 return device::serial::DATA_BITS_SEVEN; | |
72 case api::serial::DATA_BITS_EIGHT: | |
73 return device::serial::DATA_BITS_EIGHT; | |
74 } | |
75 return device::serial::DATA_BITS_NONE; | |
76 } | |
77 | |
78 api::serial::ParityBit ConvertParityBitFromMojo( | |
79 device::serial::ParityBit input) { | |
80 switch (input) { | |
81 case device::serial::PARITY_BIT_NONE: | |
82 return api::serial::PARITY_BIT_NONE; | |
83 case device::serial::PARITY_BIT_ODD: | |
84 return api::serial::PARITY_BIT_ODD; | |
85 case device::serial::PARITY_BIT_NO: | |
86 return api::serial::PARITY_BIT_NO; | |
87 case device::serial::PARITY_BIT_EVEN: | |
88 return api::serial::PARITY_BIT_EVEN; | |
89 } | |
90 return api::serial::PARITY_BIT_NONE; | |
91 } | |
92 | |
93 device::serial::ParityBit ConvertParityBitToMojo(api::serial::ParityBit input) { | |
94 switch (input) { | |
95 case api::serial::PARITY_BIT_NONE: | |
96 return device::serial::PARITY_BIT_NONE; | |
97 case api::serial::PARITY_BIT_NO: | |
98 return device::serial::PARITY_BIT_NO; | |
99 case api::serial::PARITY_BIT_ODD: | |
100 return device::serial::PARITY_BIT_ODD; | |
101 case api::serial::PARITY_BIT_EVEN: | |
102 return device::serial::PARITY_BIT_EVEN; | |
103 } | |
104 return device::serial::PARITY_BIT_NONE; | |
105 } | |
106 | |
107 api::serial::StopBits ConvertStopBitsFromMojo(device::serial::StopBits input) { | |
108 switch (input) { | |
109 case device::serial::STOP_BITS_NONE: | |
110 return api::serial::STOP_BITS_NONE; | |
111 case device::serial::STOP_BITS_ONE: | |
112 return api::serial::STOP_BITS_ONE; | |
113 case device::serial::STOP_BITS_TWO: | |
114 return api::serial::STOP_BITS_TWO; | |
115 } | |
116 return api::serial::STOP_BITS_NONE; | |
117 } | |
118 | |
119 device::serial::StopBits ConvertStopBitsToMojo(api::serial::StopBits input) { | |
120 switch (input) { | |
121 case api::serial::STOP_BITS_NONE: | |
122 return device::serial::STOP_BITS_NONE; | |
123 case api::serial::STOP_BITS_ONE: | |
124 return device::serial::STOP_BITS_ONE; | |
125 case api::serial::STOP_BITS_TWO: | |
126 return device::serial::STOP_BITS_TWO; | |
127 } | |
128 return device::serial::STOP_BITS_NONE; | |
129 } | |
130 | |
131 } // namespace | |
132 | |
133 static base::LazyInstance< | |
134 BrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> > > | |
135 g_factory = LAZY_INSTANCE_INITIALIZER; | |
136 | |
137 // static | |
138 template <> | |
139 BrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> >* | |
140 ApiResourceManager<SerialConnection>::GetFactoryInstance() { | |
141 return g_factory.Pointer(); | |
142 } | |
143 | |
144 SerialConnection::SerialConnection(const std::string& port, | |
145 const std::string& owner_extension_id) | |
146 : ApiResource(owner_extension_id), | |
147 port_(port), | |
148 persistent_(false), | |
149 buffer_size_(kDefaultBufferSize), | |
150 receive_timeout_(0), | |
151 send_timeout_(0), | |
152 paused_(false), | |
153 io_handler_(device::SerialIoHandler::Create()) { | |
154 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
155 io_handler_->Initialize( | |
156 base::Bind(&SerialConnection::OnAsyncReadComplete, AsWeakPtr()), | |
157 base::Bind(&SerialConnection::OnAsyncWriteComplete, AsWeakPtr()), | |
158 content::BrowserThread::GetMessageLoopProxyForThread( | |
159 content::BrowserThread::FILE)); | |
160 } | |
161 | |
162 SerialConnection::~SerialConnection() { | |
163 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_DISCONNECTED); | |
164 io_handler_->CancelWrite(device::serial::SEND_ERROR_DISCONNECTED); | |
165 } | |
166 | |
167 bool SerialConnection::IsPersistent() const { return persistent(); } | |
168 | |
169 void SerialConnection::set_buffer_size(int buffer_size) { | |
170 buffer_size_ = buffer_size; | |
171 } | |
172 | |
173 void SerialConnection::set_receive_timeout(int receive_timeout) { | |
174 receive_timeout_ = receive_timeout; | |
175 } | |
176 | |
177 void SerialConnection::set_send_timeout(int send_timeout) { | |
178 send_timeout_ = send_timeout; | |
179 } | |
180 | |
181 void SerialConnection::set_paused(bool paused) { | |
182 paused_ = paused; | |
183 if (paused) { | |
184 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE); | |
185 } | |
186 } | |
187 | |
188 void SerialConnection::Open(const OpenCompleteCallback& callback) { | |
189 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
190 io_handler_->Open(port_, callback); | |
191 } | |
192 | |
193 bool SerialConnection::Receive(const ReceiveCompleteCallback& callback) { | |
194 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
195 if (!receive_complete_.is_null()) | |
196 return false; | |
197 receive_complete_ = callback; | |
198 io_handler_->Read(buffer_size_); | |
199 receive_timeout_task_.reset(); | |
200 if (receive_timeout_ > 0) { | |
201 receive_timeout_task_.reset(new TimeoutTask( | |
202 base::Bind(&SerialConnection::OnReceiveTimeout, AsWeakPtr()), | |
203 base::TimeDelta::FromMilliseconds(receive_timeout_))); | |
204 } | |
205 return true; | |
206 } | |
207 | |
208 bool SerialConnection::Send(const std::string& data, | |
209 const SendCompleteCallback& callback) { | |
210 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
211 if (!send_complete_.is_null()) | |
212 return false; | |
213 send_complete_ = callback; | |
214 io_handler_->Write(data); | |
215 send_timeout_task_.reset(); | |
216 if (send_timeout_ > 0) { | |
217 send_timeout_task_.reset(new TimeoutTask( | |
218 base::Bind(&SerialConnection::OnSendTimeout, AsWeakPtr()), | |
219 base::TimeDelta::FromMilliseconds(send_timeout_))); | |
220 } | |
221 return true; | |
222 } | |
223 | |
224 bool SerialConnection::Configure( | |
225 const api::serial::ConnectionOptions& options) { | |
226 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
227 if (options.persistent.get()) | |
228 set_persistent(*options.persistent); | |
229 if (options.name.get()) | |
230 set_name(*options.name); | |
231 if (options.buffer_size.get()) | |
232 set_buffer_size(*options.buffer_size); | |
233 if (options.receive_timeout.get()) | |
234 set_receive_timeout(*options.receive_timeout); | |
235 if (options.send_timeout.get()) | |
236 set_send_timeout(*options.send_timeout); | |
237 bool success = io_handler_->ConfigurePort( | |
238 *device::serial::ConnectionOptions::From(options)); | |
239 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE); | |
240 return success; | |
241 } | |
242 | |
243 void SerialConnection::SetIoHandlerForTest( | |
244 scoped_refptr<device::SerialIoHandler> handler) { | |
245 io_handler_ = handler; | |
246 io_handler_->Initialize( | |
247 base::Bind(&SerialConnection::OnAsyncReadComplete, AsWeakPtr()), | |
248 base::Bind(&SerialConnection::OnAsyncWriteComplete, AsWeakPtr()), | |
249 content::BrowserThread::GetMessageLoopProxyForThread( | |
250 content::BrowserThread::FILE)); | |
251 } | |
252 | |
253 bool SerialConnection::GetInfo(api::serial::ConnectionInfo* info) const { | |
254 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
255 info->paused = paused_; | |
256 info->persistent = persistent_; | |
257 info->name = name_; | |
258 info->buffer_size = buffer_size_; | |
259 info->receive_timeout = receive_timeout_; | |
260 info->send_timeout = send_timeout_; | |
261 device::serial::ConnectionInfoPtr port_info = io_handler_->GetPortInfo(); | |
262 if (!port_info) | |
263 return false; | |
264 | |
265 info->bitrate.reset(new int(port_info->bitrate)); | |
266 info->data_bits = ConvertDataBitsFromMojo(port_info->data_bits); | |
267 info->parity_bit = ConvertParityBitFromMojo(port_info->parity_bit); | |
268 info->stop_bits = ConvertStopBitsFromMojo(port_info->stop_bits); | |
269 info->cts_flow_control.reset(new bool(port_info->cts_flow_control)); | |
270 return true; | |
271 } | |
272 | |
273 bool SerialConnection::Flush() const { | |
274 return io_handler_->Flush(); | |
275 } | |
276 | |
277 bool SerialConnection::GetControlSignals( | |
278 api::serial::DeviceControlSignals* control_signals) const { | |
279 device::serial::DeviceControlSignalsPtr signals = | |
280 io_handler_->GetControlSignals(); | |
281 if (!signals) | |
282 return false; | |
283 | |
284 control_signals->dcd = signals->dcd; | |
285 control_signals->cts = signals->cts; | |
286 control_signals->ri = signals->ri; | |
287 control_signals->dsr = signals->dsr; | |
288 return true; | |
289 } | |
290 | |
291 bool SerialConnection::SetControlSignals( | |
292 const api::serial::HostControlSignals& control_signals) { | |
293 return io_handler_->SetControlSignals( | |
294 *device::serial::HostControlSignals::From(control_signals)); | |
295 } | |
296 | |
297 void SerialConnection::OnReceiveTimeout() { | |
298 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
299 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_TIMEOUT); | |
300 } | |
301 | |
302 void SerialConnection::OnSendTimeout() { | |
303 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
304 io_handler_->CancelWrite(device::serial::SEND_ERROR_TIMEOUT); | |
305 } | |
306 | |
307 void SerialConnection::OnAsyncReadComplete(const std::string& data, | |
308 device::serial::ReceiveError error) { | |
309 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
310 DCHECK(!receive_complete_.is_null()); | |
311 ReceiveCompleteCallback callback = receive_complete_; | |
312 receive_complete_.Reset(); | |
313 receive_timeout_task_.reset(); | |
314 callback.Run(data, ConvertReceiveErrorFromMojo(error)); | |
315 } | |
316 | |
317 void SerialConnection::OnAsyncWriteComplete(int bytes_sent, | |
318 device::serial::SendError error) { | |
319 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
320 DCHECK(!send_complete_.is_null()); | |
321 SendCompleteCallback callback = send_complete_; | |
322 send_complete_.Reset(); | |
323 send_timeout_task_.reset(); | |
324 callback.Run(bytes_sent, ConvertSendErrorFromMojo(error)); | |
325 } | |
326 | |
327 SerialConnection::TimeoutTask::TimeoutTask(const base::Closure& closure, | |
328 const base::TimeDelta& delay) | |
329 : weak_factory_(this), closure_(closure), delay_(delay) { | |
330 base::MessageLoop::current()->PostDelayedTask( | |
331 FROM_HERE, | |
332 base::Bind(&TimeoutTask::Run, weak_factory_.GetWeakPtr()), | |
333 delay_); | |
334 } | |
335 | |
336 SerialConnection::TimeoutTask::~TimeoutTask() {} | |
337 | |
338 void SerialConnection::TimeoutTask::Run() const { closure_.Run(); } | |
339 | |
340 } // namespace extensions | |
341 | |
342 namespace mojo { | |
343 | |
344 // static | |
345 device::serial::HostControlSignalsPtr | |
346 TypeConverter<device::serial::HostControlSignalsPtr, | |
347 extensions::api::serial::HostControlSignals>:: | |
348 ConvertFrom(const extensions::api::serial::HostControlSignals& input) { | |
349 device::serial::HostControlSignalsPtr output( | |
350 device::serial::HostControlSignals::New()); | |
351 if (input.dtr.get()) { | |
352 output->has_dtr = true; | |
353 output->dtr = *input.dtr; | |
354 } | |
355 if (input.rts.get()) { | |
356 output->has_rts = true; | |
357 output->rts = *input.rts; | |
358 } | |
359 return output.Pass(); | |
360 } | |
361 | |
362 // static | |
363 device::serial::ConnectionOptionsPtr | |
364 TypeConverter<device::serial::ConnectionOptionsPtr, | |
365 extensions::api::serial::ConnectionOptions>:: | |
366 ConvertFrom(const extensions::api::serial::ConnectionOptions& input) { | |
367 device::serial::ConnectionOptionsPtr output( | |
368 device::serial::ConnectionOptions::New()); | |
369 if (input.bitrate.get() && *input.bitrate > 0) | |
370 output->bitrate = *input.bitrate; | |
371 output->data_bits = extensions::ConvertDataBitsToMojo(input.data_bits); | |
372 output->parity_bit = extensions::ConvertParityBitToMojo(input.parity_bit); | |
373 output->stop_bits = extensions::ConvertStopBitsToMojo(input.stop_bits); | |
374 if (input.cts_flow_control.get()) { | |
375 output->has_cts_flow_control = true; | |
376 output->cts_flow_control = *input.cts_flow_control; | |
377 } | |
378 return output.Pass(); | |
379 } | |
380 | |
381 } // namespace mojo | |
OLD | NEW |