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