Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / api / serial / serial_connection.cc
blobef25885941b28f9cf5f611ca9d260f2d3aae2c82
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 #include "extensions/browser/api/serial/serial_connection.h"
7 #include <string>
8 #include <vector>
10 #include "base/files/file_path.h"
11 #include "base/lazy_instance.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/stl_util.h"
14 #include "extensions/browser/api/api_resource_manager.h"
15 #include "extensions/common/api/serial.h"
17 namespace extensions {
19 namespace {
21 const int kDefaultBufferSize = 4096;
23 core_api::serial::SendError ConvertSendErrorFromMojo(
24 device::serial::SendError input) {
25 switch (input) {
26 case device::serial::SEND_ERROR_NONE:
27 return core_api::serial::SEND_ERROR_NONE;
28 case device::serial::SEND_ERROR_DISCONNECTED:
29 return core_api::serial::SEND_ERROR_DISCONNECTED;
30 case device::serial::SEND_ERROR_PENDING:
31 return core_api::serial::SEND_ERROR_PENDING;
32 case device::serial::SEND_ERROR_TIMEOUT:
33 return core_api::serial::SEND_ERROR_TIMEOUT;
34 case device::serial::SEND_ERROR_SYSTEM_ERROR:
35 return core_api::serial::SEND_ERROR_SYSTEM_ERROR;
37 return core_api::serial::SEND_ERROR_NONE;
40 core_api::serial::ReceiveError ConvertReceiveErrorFromMojo(
41 device::serial::ReceiveError input) {
42 switch (input) {
43 case device::serial::RECEIVE_ERROR_NONE:
44 return core_api::serial::RECEIVE_ERROR_NONE;
45 case device::serial::RECEIVE_ERROR_DISCONNECTED:
46 return core_api::serial::RECEIVE_ERROR_DISCONNECTED;
47 case device::serial::RECEIVE_ERROR_TIMEOUT:
48 return core_api::serial::RECEIVE_ERROR_TIMEOUT;
49 case device::serial::RECEIVE_ERROR_DEVICE_LOST:
50 return core_api::serial::RECEIVE_ERROR_DEVICE_LOST;
51 case device::serial::RECEIVE_ERROR_SYSTEM_ERROR:
52 return core_api::serial::RECEIVE_ERROR_SYSTEM_ERROR;
54 return core_api::serial::RECEIVE_ERROR_NONE;
57 core_api::serial::DataBits ConvertDataBitsFromMojo(
58 device::serial::DataBits input) {
59 switch (input) {
60 case device::serial::DATA_BITS_NONE:
61 return core_api::serial::DATA_BITS_NONE;
62 case device::serial::DATA_BITS_SEVEN:
63 return core_api::serial::DATA_BITS_SEVEN;
64 case device::serial::DATA_BITS_EIGHT:
65 return core_api::serial::DATA_BITS_EIGHT;
67 return core_api::serial::DATA_BITS_NONE;
70 device::serial::DataBits ConvertDataBitsToMojo(
71 core_api::serial::DataBits input) {
72 switch (input) {
73 case core_api::serial::DATA_BITS_NONE:
74 return device::serial::DATA_BITS_NONE;
75 case core_api::serial::DATA_BITS_SEVEN:
76 return device::serial::DATA_BITS_SEVEN;
77 case core_api::serial::DATA_BITS_EIGHT:
78 return device::serial::DATA_BITS_EIGHT;
80 return device::serial::DATA_BITS_NONE;
83 core_api::serial::ParityBit ConvertParityBitFromMojo(
84 device::serial::ParityBit input) {
85 switch (input) {
86 case device::serial::PARITY_BIT_NONE:
87 return core_api::serial::PARITY_BIT_NONE;
88 case device::serial::PARITY_BIT_ODD:
89 return core_api::serial::PARITY_BIT_ODD;
90 case device::serial::PARITY_BIT_NO:
91 return core_api::serial::PARITY_BIT_NO;
92 case device::serial::PARITY_BIT_EVEN:
93 return core_api::serial::PARITY_BIT_EVEN;
95 return core_api::serial::PARITY_BIT_NONE;
98 device::serial::ParityBit ConvertParityBitToMojo(
99 core_api::serial::ParityBit input) {
100 switch (input) {
101 case core_api::serial::PARITY_BIT_NONE:
102 return device::serial::PARITY_BIT_NONE;
103 case core_api::serial::PARITY_BIT_NO:
104 return device::serial::PARITY_BIT_NO;
105 case core_api::serial::PARITY_BIT_ODD:
106 return device::serial::PARITY_BIT_ODD;
107 case core_api::serial::PARITY_BIT_EVEN:
108 return device::serial::PARITY_BIT_EVEN;
110 return device::serial::PARITY_BIT_NONE;
113 core_api::serial::StopBits ConvertStopBitsFromMojo(
114 device::serial::StopBits input) {
115 switch (input) {
116 case device::serial::STOP_BITS_NONE:
117 return core_api::serial::STOP_BITS_NONE;
118 case device::serial::STOP_BITS_ONE:
119 return core_api::serial::STOP_BITS_ONE;
120 case device::serial::STOP_BITS_TWO:
121 return core_api::serial::STOP_BITS_TWO;
123 return core_api::serial::STOP_BITS_NONE;
126 device::serial::StopBits ConvertStopBitsToMojo(
127 core_api::serial::StopBits input) {
128 switch (input) {
129 case core_api::serial::STOP_BITS_NONE:
130 return device::serial::STOP_BITS_NONE;
131 case core_api::serial::STOP_BITS_ONE:
132 return device::serial::STOP_BITS_ONE;
133 case core_api::serial::STOP_BITS_TWO:
134 return device::serial::STOP_BITS_TWO;
136 return device::serial::STOP_BITS_NONE;
139 class SendBuffer : public device::ReadOnlyBuffer {
140 public:
141 SendBuffer(
142 const std::vector<char>& data,
143 const base::Callback<void(int, device::serial::SendError)>& callback)
144 : data_(data), callback_(callback) {}
145 ~SendBuffer() override {}
146 const char* GetData() override { return vector_as_array(&data_); }
147 uint32_t GetSize() override { return static_cast<uint32_t>(data_.size()); }
148 void Done(uint32_t bytes_read) override {
149 callback_.Run(bytes_read, device::serial::SEND_ERROR_NONE);
151 void DoneWithError(uint32_t bytes_read, int32_t error) override {
152 callback_.Run(bytes_read, static_cast<device::serial::SendError>(error));
155 private:
156 const std::vector<char> data_;
157 const base::Callback<void(int, device::serial::SendError)> callback_;
160 class ReceiveBuffer : public device::WritableBuffer {
161 public:
162 ReceiveBuffer(
163 scoped_refptr<net::IOBuffer> buffer,
164 uint32_t size,
165 const base::Callback<void(int, device::serial::ReceiveError)>& callback)
166 : buffer_(buffer), size_(size), callback_(callback) {}
167 ~ReceiveBuffer() override {}
168 char* GetData() override { return buffer_->data(); }
169 uint32_t GetSize() override { return size_; }
170 void Done(uint32_t bytes_written) override {
171 callback_.Run(bytes_written, device::serial::RECEIVE_ERROR_NONE);
173 void DoneWithError(uint32_t bytes_written, int32_t error) override {
174 callback_.Run(bytes_written,
175 static_cast<device::serial::ReceiveError>(error));
178 private:
179 scoped_refptr<net::IOBuffer> buffer_;
180 const uint32_t size_;
181 const base::Callback<void(int, device::serial::ReceiveError)> callback_;
184 } // namespace
186 static base::LazyInstance<
187 BrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> > >
188 g_factory = LAZY_INSTANCE_INITIALIZER;
190 // static
191 template <>
192 BrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> >*
193 ApiResourceManager<SerialConnection>::GetFactoryInstance() {
194 return g_factory.Pointer();
197 SerialConnection::SerialConnection(const std::string& port,
198 const std::string& owner_extension_id)
199 : ApiResource(owner_extension_id),
200 port_(port),
201 persistent_(false),
202 buffer_size_(kDefaultBufferSize),
203 receive_timeout_(0),
204 send_timeout_(0),
205 paused_(false),
206 io_handler_(device::SerialIoHandler::Create(
207 content::BrowserThread::GetMessageLoopProxyForThread(
208 content::BrowserThread::FILE),
209 content::BrowserThread::GetMessageLoopProxyForThread(
210 content::BrowserThread::UI))) {
211 DCHECK_CURRENTLY_ON(BrowserThread::IO);
214 SerialConnection::~SerialConnection() {
215 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_DISCONNECTED);
216 io_handler_->CancelWrite(device::serial::SEND_ERROR_DISCONNECTED);
219 bool SerialConnection::IsPersistent() const {
220 return persistent();
223 void SerialConnection::set_buffer_size(int buffer_size) {
224 buffer_size_ = buffer_size;
227 void SerialConnection::set_receive_timeout(int receive_timeout) {
228 receive_timeout_ = receive_timeout;
231 void SerialConnection::set_send_timeout(int send_timeout) {
232 send_timeout_ = send_timeout;
235 void SerialConnection::set_paused(bool paused) {
236 paused_ = paused;
237 if (paused) {
238 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE);
242 void SerialConnection::Open(const core_api::serial::ConnectionOptions& options,
243 const OpenCompleteCallback& callback) {
244 DCHECK_CURRENTLY_ON(BrowserThread::IO);
245 if (options.persistent.get())
246 set_persistent(*options.persistent);
247 if (options.name.get())
248 set_name(*options.name);
249 if (options.buffer_size.get())
250 set_buffer_size(*options.buffer_size);
251 if (options.receive_timeout.get())
252 set_receive_timeout(*options.receive_timeout);
253 if (options.send_timeout.get())
254 set_send_timeout(*options.send_timeout);
255 io_handler_->Open(port_, *device::serial::ConnectionOptions::From(options),
256 callback);
259 bool SerialConnection::Receive(const ReceiveCompleteCallback& callback) {
260 DCHECK_CURRENTLY_ON(BrowserThread::IO);
261 if (!receive_complete_.is_null())
262 return false;
263 receive_complete_ = callback;
264 receive_buffer_ = new net::IOBuffer(buffer_size_);
265 io_handler_->Read(scoped_ptr<device::WritableBuffer>(new ReceiveBuffer(
266 receive_buffer_,
267 buffer_size_,
268 base::Bind(&SerialConnection::OnAsyncReadComplete, AsWeakPtr()))));
269 receive_timeout_task_.reset();
270 if (receive_timeout_ > 0) {
271 receive_timeout_task_.reset(new TimeoutTask(
272 base::Bind(&SerialConnection::OnReceiveTimeout, AsWeakPtr()),
273 base::TimeDelta::FromMilliseconds(receive_timeout_)));
275 return true;
278 bool SerialConnection::Send(const std::vector<char>& data,
279 const SendCompleteCallback& callback) {
280 DCHECK_CURRENTLY_ON(BrowserThread::IO);
281 if (!send_complete_.is_null())
282 return false;
283 send_complete_ = callback;
284 io_handler_->Write(scoped_ptr<device::ReadOnlyBuffer>(new SendBuffer(
285 data, base::Bind(&SerialConnection::OnAsyncWriteComplete, AsWeakPtr()))));
286 send_timeout_task_.reset();
287 if (send_timeout_ > 0) {
288 send_timeout_task_.reset(new TimeoutTask(
289 base::Bind(&SerialConnection::OnSendTimeout, AsWeakPtr()),
290 base::TimeDelta::FromMilliseconds(send_timeout_)));
292 return true;
295 bool SerialConnection::Configure(
296 const core_api::serial::ConnectionOptions& options) {
297 DCHECK_CURRENTLY_ON(BrowserThread::IO);
298 if (options.persistent.get())
299 set_persistent(*options.persistent);
300 if (options.name.get())
301 set_name(*options.name);
302 if (options.buffer_size.get())
303 set_buffer_size(*options.buffer_size);
304 if (options.receive_timeout.get())
305 set_receive_timeout(*options.receive_timeout);
306 if (options.send_timeout.get())
307 set_send_timeout(*options.send_timeout);
308 bool success = io_handler_->ConfigurePort(
309 *device::serial::ConnectionOptions::From(options));
310 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE);
311 return success;
314 void SerialConnection::SetIoHandlerForTest(
315 scoped_refptr<device::SerialIoHandler> handler) {
316 io_handler_ = handler;
319 bool SerialConnection::GetInfo(core_api::serial::ConnectionInfo* info) const {
320 DCHECK_CURRENTLY_ON(BrowserThread::IO);
321 info->paused = paused_;
322 info->persistent = persistent_;
323 info->name = name_;
324 info->buffer_size = buffer_size_;
325 info->receive_timeout = receive_timeout_;
326 info->send_timeout = send_timeout_;
327 device::serial::ConnectionInfoPtr port_info = io_handler_->GetPortInfo();
328 if (!port_info)
329 return false;
331 info->bitrate.reset(new int(port_info->bitrate));
332 info->data_bits = ConvertDataBitsFromMojo(port_info->data_bits);
333 info->parity_bit = ConvertParityBitFromMojo(port_info->parity_bit);
334 info->stop_bits = ConvertStopBitsFromMojo(port_info->stop_bits);
335 info->cts_flow_control.reset(new bool(port_info->cts_flow_control));
336 return true;
339 bool SerialConnection::Flush() const {
340 return io_handler_->Flush();
343 bool SerialConnection::GetControlSignals(
344 core_api::serial::DeviceControlSignals* control_signals) const {
345 device::serial::DeviceControlSignalsPtr signals =
346 io_handler_->GetControlSignals();
347 if (!signals)
348 return false;
350 control_signals->dcd = signals->dcd;
351 control_signals->cts = signals->cts;
352 control_signals->ri = signals->ri;
353 control_signals->dsr = signals->dsr;
354 return true;
357 bool SerialConnection::SetControlSignals(
358 const core_api::serial::HostControlSignals& control_signals) {
359 return io_handler_->SetControlSignals(
360 *device::serial::HostControlSignals::From(control_signals));
363 void SerialConnection::OnReceiveTimeout() {
364 DCHECK_CURRENTLY_ON(BrowserThread::IO);
365 io_handler_->CancelRead(device::serial::RECEIVE_ERROR_TIMEOUT);
368 void SerialConnection::OnSendTimeout() {
369 DCHECK_CURRENTLY_ON(BrowserThread::IO);
370 io_handler_->CancelWrite(device::serial::SEND_ERROR_TIMEOUT);
373 void SerialConnection::OnAsyncReadComplete(int bytes_read,
374 device::serial::ReceiveError error) {
375 DCHECK_CURRENTLY_ON(BrowserThread::IO);
376 DCHECK(!receive_complete_.is_null());
377 ReceiveCompleteCallback callback = receive_complete_;
378 receive_complete_.Reset();
379 receive_timeout_task_.reset();
380 callback.Run(std::vector<char>(receive_buffer_->data(),
381 receive_buffer_->data() + bytes_read),
382 ConvertReceiveErrorFromMojo(error));
383 receive_buffer_ = NULL;
386 void SerialConnection::OnAsyncWriteComplete(int bytes_sent,
387 device::serial::SendError error) {
388 DCHECK_CURRENTLY_ON(BrowserThread::IO);
389 DCHECK(!send_complete_.is_null());
390 SendCompleteCallback callback = send_complete_;
391 send_complete_.Reset();
392 send_timeout_task_.reset();
393 callback.Run(bytes_sent, ConvertSendErrorFromMojo(error));
396 SerialConnection::TimeoutTask::TimeoutTask(const base::Closure& closure,
397 const base::TimeDelta& delay)
398 : closure_(closure), delay_(delay), weak_factory_(this) {
399 base::MessageLoop::current()->PostDelayedTask(
400 FROM_HERE,
401 base::Bind(&TimeoutTask::Run, weak_factory_.GetWeakPtr()),
402 delay_);
405 SerialConnection::TimeoutTask::~TimeoutTask() {
408 void SerialConnection::TimeoutTask::Run() const {
409 closure_.Run();
412 } // namespace extensions
414 namespace mojo {
416 // static
417 device::serial::HostControlSignalsPtr
418 TypeConverter<device::serial::HostControlSignalsPtr,
419 extensions::core_api::serial::HostControlSignals>::
420 Convert(const extensions::core_api::serial::HostControlSignals& input) {
421 device::serial::HostControlSignalsPtr output(
422 device::serial::HostControlSignals::New());
423 if (input.dtr.get()) {
424 output->has_dtr = true;
425 output->dtr = *input.dtr;
427 if (input.rts.get()) {
428 output->has_rts = true;
429 output->rts = *input.rts;
431 return output.Pass();
434 // static
435 device::serial::ConnectionOptionsPtr
436 TypeConverter<device::serial::ConnectionOptionsPtr,
437 extensions::core_api::serial::ConnectionOptions>::
438 Convert(const extensions::core_api::serial::ConnectionOptions& input) {
439 device::serial::ConnectionOptionsPtr output(
440 device::serial::ConnectionOptions::New());
441 if (input.bitrate.get() && *input.bitrate > 0)
442 output->bitrate = *input.bitrate;
443 output->data_bits = extensions::ConvertDataBitsToMojo(input.data_bits);
444 output->parity_bit = extensions::ConvertParityBitToMojo(input.parity_bit);
445 output->stop_bits = extensions::ConvertStopBitsToMojo(input.stop_bits);
446 if (input.cts_flow_control.get()) {
447 output->has_cts_flow_control = true;
448 output->cts_flow_control = *input.cts_flow_control;
450 return output.Pass();
453 } // namespace mojo