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 "device/serial/serial_connection_factory.h"
6
7#include "base/bind.h"
8#include "base/location.h"
9#include "device/serial/serial_connection.h"
10#include "device/serial/serial_io_handler.h"
11
12namespace device {
13namespace {
14
15void FillDefaultConnectionOptions(serial::ConnectionOptions* options) {
16  if (!options->bitrate)
17    options->bitrate = 9600;
18  if (options->data_bits == serial::DATA_BITS_NONE)
19    options->data_bits = serial::DATA_BITS_EIGHT;
20  if (options->stop_bits == serial::STOP_BITS_NONE)
21    options->stop_bits = serial::STOP_BITS_ONE;
22  if (options->parity_bit == serial::PARITY_BIT_NONE)
23    options->parity_bit = serial::PARITY_BIT_NO;
24  if (!options->has_cts_flow_control) {
25    options->has_cts_flow_control = true;
26    options->cts_flow_control = false;
27  }
28}
29
30}  // namespace
31
32class SerialConnectionFactory::ConnectTask
33    : public base::RefCountedThreadSafe<SerialConnectionFactory::ConnectTask> {
34 public:
35  ConnectTask(scoped_refptr<SerialConnectionFactory> factory,
36              const std::string& path,
37              serial::ConnectionOptionsPtr options,
38              mojo::InterfaceRequest<serial::Connection> connection_request,
39              mojo::InterfaceRequest<serial::DataSink> sink,
40              mojo::InterfaceRequest<serial::DataSource> source);
41  void Run();
42
43 private:
44  friend class base::RefCountedThreadSafe<SerialConnectionFactory::ConnectTask>;
45  virtual ~ConnectTask();
46  void Connect();
47  void OnConnected(bool success);
48
49  scoped_refptr<SerialConnectionFactory> factory_;
50  const std::string path_;
51  serial::ConnectionOptionsPtr options_;
52  mojo::InterfaceRequest<serial::Connection> connection_request_;
53  mojo::InterfaceRequest<serial::DataSink> sink_;
54  mojo::InterfaceRequest<serial::DataSource> source_;
55  scoped_refptr<SerialIoHandler> io_handler_;
56
57  DISALLOW_COPY_AND_ASSIGN(ConnectTask);
58};
59
60SerialConnectionFactory::SerialConnectionFactory(
61    const IoHandlerFactory& io_handler_factory,
62    scoped_refptr<base::MessageLoopProxy> connect_message_loop)
63    : io_handler_factory_(io_handler_factory),
64      connect_message_loop_(connect_message_loop) {
65}
66
67void SerialConnectionFactory::CreateConnection(
68    const std::string& path,
69    serial::ConnectionOptionsPtr options,
70    mojo::InterfaceRequest<serial::Connection> connection_request,
71    mojo::InterfaceRequest<serial::DataSink> sink,
72    mojo::InterfaceRequest<serial::DataSource> source) {
73  scoped_refptr<ConnectTask> task(new ConnectTask(this,
74                                                  path,
75                                                  options.Pass(),
76                                                  connection_request.Pass(),
77                                                  sink.Pass(),
78                                                  source.Pass()));
79  task->Run();
80}
81
82SerialConnectionFactory::~SerialConnectionFactory() {
83}
84
85SerialConnectionFactory::ConnectTask::ConnectTask(
86    scoped_refptr<SerialConnectionFactory> factory,
87    const std::string& path,
88    serial::ConnectionOptionsPtr options,
89    mojo::InterfaceRequest<serial::Connection> connection_request,
90    mojo::InterfaceRequest<serial::DataSink> sink,
91    mojo::InterfaceRequest<serial::DataSource> source)
92    : factory_(factory),
93      path_(path),
94      options_(options.Pass()),
95      connection_request_(connection_request.Pass()),
96      sink_(sink.Pass()),
97      source_(source.Pass()) {
98}
99
100void SerialConnectionFactory::ConnectTask::Run() {
101  factory_->connect_message_loop_->PostTask(
102      FROM_HERE,
103      base::Bind(&SerialConnectionFactory::ConnectTask::Connect, this));
104}
105
106SerialConnectionFactory::ConnectTask::~ConnectTask() {
107}
108
109void SerialConnectionFactory::ConnectTask::Connect() {
110  io_handler_ = factory_->io_handler_factory_.Run();
111  io_handler_->Open(
112      path_,
113      base::Bind(&SerialConnectionFactory::ConnectTask::OnConnected, this));
114}
115
116void SerialConnectionFactory::ConnectTask::OnConnected(bool success) {
117  DCHECK(io_handler_.get());
118  if (!success)
119    return;
120  if (!options_)
121    options_ = serial::ConnectionOptions::New();
122  FillDefaultConnectionOptions(options_.get());
123  if (!io_handler_->ConfigurePort(*options_))
124    return;
125  mojo::BindToRequest(
126      new SerialConnection(io_handler_, sink_.Pass(), source_.Pass()),
127      &connection_request_);
128}
129
130}  // namespace device
131