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_api.h"
6
7#include <algorithm>
8#include <vector>
9
10#include "base/values.h"
11#include "content/public/browser/browser_thread.h"
12#include "device/serial/serial_device_enumerator.h"
13#include "extensions/browser/api/serial/serial_connection.h"
14#include "extensions/browser/api/serial/serial_event_dispatcher.h"
15#include "extensions/common/api/serial.h"
16
17using content::BrowserThread;
18
19namespace extensions {
20
21namespace core_api {
22
23namespace {
24
25// It's a fool's errand to come up with a default bitrate, because we don't get
26// to control both sides of the communication. Unless the other side has
27// implemented auto-bitrate detection (rare), if we pick the wrong rate, then
28// you're gonna have a bad time. Close doesn't count.
29//
30// But we'd like to pick something that has a chance of working, and 9600 is a
31// good balance between popularity and speed. So 9600 it is.
32const int kDefaultBufferSize = 4096;
33const int kDefaultBitrate = 9600;
34const serial::DataBits kDefaultDataBits = serial::DATA_BITS_EIGHT;
35const serial::ParityBit kDefaultParityBit = serial::PARITY_BIT_NO;
36const serial::StopBits kDefaultStopBits = serial::STOP_BITS_ONE;
37const int kDefaultReceiveTimeout = 0;
38const int kDefaultSendTimeout = 0;
39
40const char kErrorConnectFailed[] = "Failed to connect to the port.";
41const char kErrorSerialConnectionNotFound[] = "Serial connection not found.";
42const char kErrorGetControlSignalsFailed[] = "Failed to get control signals.";
43
44template <class T>
45void SetDefaultScopedPtrValue(scoped_ptr<T>& ptr, const T& value) {
46  if (!ptr.get())
47    ptr.reset(new T(value));
48}
49
50}  // namespace
51
52SerialAsyncApiFunction::SerialAsyncApiFunction() : manager_(NULL) {
53}
54
55SerialAsyncApiFunction::~SerialAsyncApiFunction() {
56}
57
58bool SerialAsyncApiFunction::PrePrepare() {
59  manager_ = ApiResourceManager<SerialConnection>::Get(browser_context());
60  DCHECK(manager_);
61  return true;
62}
63
64bool SerialAsyncApiFunction::Respond() {
65  return error_.empty();
66}
67
68SerialConnection* SerialAsyncApiFunction::GetSerialConnection(
69    int api_resource_id) {
70  return manager_->Get(extension_->id(), api_resource_id);
71}
72
73void SerialAsyncApiFunction::RemoveSerialConnection(int api_resource_id) {
74  manager_->Remove(extension_->id(), api_resource_id);
75}
76
77SerialGetDevicesFunction::SerialGetDevicesFunction() {
78}
79
80bool SerialGetDevicesFunction::Prepare() {
81  set_work_thread_id(BrowserThread::FILE);
82  return true;
83}
84
85void SerialGetDevicesFunction::Work() {
86  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
87
88  scoped_ptr<device::SerialDeviceEnumerator> enumerator =
89      device::SerialDeviceEnumerator::Create();
90  mojo::Array<device::serial::DeviceInfoPtr> devices = enumerator->GetDevices();
91  results_ = serial::GetDevices::Results::Create(
92      devices.To<std::vector<linked_ptr<serial::DeviceInfo> > >());
93}
94
95SerialConnectFunction::SerialConnectFunction() {
96}
97
98SerialConnectFunction::~SerialConnectFunction() {
99}
100
101bool SerialConnectFunction::Prepare() {
102  params_ = serial::Connect::Params::Create(*args_);
103  EXTENSION_FUNCTION_VALIDATE(params_.get());
104
105  // Fill in any omitted options to ensure a known initial configuration.
106  if (!params_->options.get())
107    params_->options.reset(new serial::ConnectionOptions());
108  serial::ConnectionOptions* options = params_->options.get();
109
110  SetDefaultScopedPtrValue(options->persistent, false);
111  SetDefaultScopedPtrValue(options->buffer_size, kDefaultBufferSize);
112  SetDefaultScopedPtrValue(options->bitrate, kDefaultBitrate);
113  SetDefaultScopedPtrValue(options->cts_flow_control, false);
114  SetDefaultScopedPtrValue(options->receive_timeout, kDefaultReceiveTimeout);
115  SetDefaultScopedPtrValue(options->send_timeout, kDefaultSendTimeout);
116
117  if (options->data_bits == serial::DATA_BITS_NONE)
118    options->data_bits = kDefaultDataBits;
119  if (options->parity_bit == serial::PARITY_BIT_NONE)
120    options->parity_bit = kDefaultParityBit;
121  if (options->stop_bits == serial::STOP_BITS_NONE)
122    options->stop_bits = kDefaultStopBits;
123
124  serial_event_dispatcher_ = SerialEventDispatcher::Get(browser_context());
125  DCHECK(serial_event_dispatcher_);
126
127  return true;
128}
129
130void SerialConnectFunction::AsyncWorkStart() {
131  DCHECK_CURRENTLY_ON(BrowserThread::IO);
132  connection_ = CreateSerialConnection(params_->path, extension_->id());
133  connection_->Open(base::Bind(&SerialConnectFunction::OnConnected, this));
134}
135
136void SerialConnectFunction::OnConnected(bool success) {
137  DCHECK(connection_);
138
139  if (success) {
140    if (!connection_->Configure(*params_->options.get())) {
141      delete connection_;
142      connection_ = NULL;
143    }
144  } else {
145    delete connection_;
146    connection_ = NULL;
147  }
148
149  BrowserThread::PostTask(
150      BrowserThread::IO,
151      FROM_HERE,
152      base::Bind(&SerialConnectFunction::FinishConnect, this));
153}
154
155void SerialConnectFunction::FinishConnect() {
156  DCHECK_CURRENTLY_ON(BrowserThread::IO);
157  if (!connection_) {
158    error_ = kErrorConnectFailed;
159  } else {
160    int id = manager_->Add(connection_);
161    serial::ConnectionInfo info;
162    info.connection_id = id;
163    if (connection_->GetInfo(&info)) {
164      serial_event_dispatcher_->PollConnection(extension_->id(), id);
165      results_ = serial::Connect::Results::Create(info);
166    } else {
167      RemoveSerialConnection(id);
168      error_ = kErrorConnectFailed;
169    }
170  }
171  AsyncWorkCompleted();
172}
173
174SerialConnection* SerialConnectFunction::CreateSerialConnection(
175    const std::string& port,
176    const std::string& extension_id) const {
177  return new SerialConnection(port, extension_id);
178}
179
180SerialUpdateFunction::SerialUpdateFunction() {
181}
182
183SerialUpdateFunction::~SerialUpdateFunction() {
184}
185
186bool SerialUpdateFunction::Prepare() {
187  params_ = serial::Update::Params::Create(*args_);
188  EXTENSION_FUNCTION_VALIDATE(params_.get());
189
190  return true;
191}
192
193void SerialUpdateFunction::Work() {
194  SerialConnection* connection = GetSerialConnection(params_->connection_id);
195  if (!connection) {
196    error_ = kErrorSerialConnectionNotFound;
197    return;
198  }
199  bool success = connection->Configure(params_->options);
200  results_ = serial::Update::Results::Create(success);
201}
202
203SerialDisconnectFunction::SerialDisconnectFunction() {
204}
205
206SerialDisconnectFunction::~SerialDisconnectFunction() {
207}
208
209bool SerialDisconnectFunction::Prepare() {
210  params_ = serial::Disconnect::Params::Create(*args_);
211  EXTENSION_FUNCTION_VALIDATE(params_.get());
212
213  return true;
214}
215
216void SerialDisconnectFunction::Work() {
217  SerialConnection* connection = GetSerialConnection(params_->connection_id);
218  if (!connection) {
219    error_ = kErrorSerialConnectionNotFound;
220    return;
221  }
222  RemoveSerialConnection(params_->connection_id);
223  results_ = serial::Disconnect::Results::Create(true);
224}
225
226SerialSendFunction::SerialSendFunction() {
227}
228
229SerialSendFunction::~SerialSendFunction() {
230}
231
232bool SerialSendFunction::Prepare() {
233  params_ = serial::Send::Params::Create(*args_);
234  EXTENSION_FUNCTION_VALIDATE(params_.get());
235
236  return true;
237}
238
239void SerialSendFunction::AsyncWorkStart() {
240  SerialConnection* connection = GetSerialConnection(params_->connection_id);
241  if (!connection) {
242    error_ = kErrorSerialConnectionNotFound;
243    AsyncWorkCompleted();
244    return;
245  }
246
247  if (!connection->Send(
248          params_->data,
249          base::Bind(&SerialSendFunction::OnSendComplete, this))) {
250    OnSendComplete(0, serial::SEND_ERROR_PENDING);
251  }
252}
253
254void SerialSendFunction::OnSendComplete(int bytes_sent,
255                                        serial::SendError error) {
256  serial::SendInfo send_info;
257  send_info.bytes_sent = bytes_sent;
258  send_info.error = error;
259  results_ = serial::Send::Results::Create(send_info);
260  AsyncWorkCompleted();
261}
262
263SerialFlushFunction::SerialFlushFunction() {
264}
265
266SerialFlushFunction::~SerialFlushFunction() {
267}
268
269bool SerialFlushFunction::Prepare() {
270  params_ = serial::Flush::Params::Create(*args_);
271  EXTENSION_FUNCTION_VALIDATE(params_.get());
272  return true;
273}
274
275void SerialFlushFunction::Work() {
276  SerialConnection* connection = GetSerialConnection(params_->connection_id);
277  if (!connection) {
278    error_ = kErrorSerialConnectionNotFound;
279    return;
280  }
281
282  bool success = connection->Flush();
283  results_ = serial::Flush::Results::Create(success);
284}
285
286SerialSetPausedFunction::SerialSetPausedFunction() {
287}
288
289SerialSetPausedFunction::~SerialSetPausedFunction() {
290}
291
292bool SerialSetPausedFunction::Prepare() {
293  params_ = serial::SetPaused::Params::Create(*args_);
294  EXTENSION_FUNCTION_VALIDATE(params_.get());
295
296  serial_event_dispatcher_ = SerialEventDispatcher::Get(browser_context());
297  DCHECK(serial_event_dispatcher_);
298  return true;
299}
300
301void SerialSetPausedFunction::Work() {
302  SerialConnection* connection = GetSerialConnection(params_->connection_id);
303  if (!connection) {
304    error_ = kErrorSerialConnectionNotFound;
305    return;
306  }
307
308  if (params_->paused != connection->paused()) {
309    connection->set_paused(params_->paused);
310    if (!params_->paused) {
311      serial_event_dispatcher_->PollConnection(extension_->id(),
312                                               params_->connection_id);
313    }
314  }
315
316  results_ = serial::SetPaused::Results::Create();
317}
318
319SerialGetInfoFunction::SerialGetInfoFunction() {
320}
321
322SerialGetInfoFunction::~SerialGetInfoFunction() {
323}
324
325bool SerialGetInfoFunction::Prepare() {
326  params_ = serial::GetInfo::Params::Create(*args_);
327  EXTENSION_FUNCTION_VALIDATE(params_.get());
328
329  return true;
330}
331
332void SerialGetInfoFunction::Work() {
333  SerialConnection* connection = GetSerialConnection(params_->connection_id);
334  if (!connection) {
335    error_ = kErrorSerialConnectionNotFound;
336    return;
337  }
338
339  serial::ConnectionInfo info;
340  info.connection_id = params_->connection_id;
341  connection->GetInfo(&info);
342  results_ = serial::GetInfo::Results::Create(info);
343}
344
345SerialGetConnectionsFunction::SerialGetConnectionsFunction() {
346}
347
348SerialGetConnectionsFunction::~SerialGetConnectionsFunction() {
349}
350
351bool SerialGetConnectionsFunction::Prepare() {
352  return true;
353}
354
355void SerialGetConnectionsFunction::Work() {
356  std::vector<linked_ptr<serial::ConnectionInfo> > infos;
357  const base::hash_set<int>* connection_ids =
358      manager_->GetResourceIds(extension_->id());
359  if (connection_ids) {
360    for (base::hash_set<int>::const_iterator it = connection_ids->begin();
361         it != connection_ids->end();
362         ++it) {
363      int connection_id = *it;
364      SerialConnection* connection = GetSerialConnection(connection_id);
365      if (connection) {
366        linked_ptr<serial::ConnectionInfo> info(new serial::ConnectionInfo());
367        info->connection_id = connection_id;
368        connection->GetInfo(info.get());
369        infos.push_back(info);
370      }
371    }
372  }
373  results_ = serial::GetConnections::Results::Create(infos);
374}
375
376SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() {
377}
378
379SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() {
380}
381
382bool SerialGetControlSignalsFunction::Prepare() {
383  params_ = serial::GetControlSignals::Params::Create(*args_);
384  EXTENSION_FUNCTION_VALIDATE(params_.get());
385
386  return true;
387}
388
389void SerialGetControlSignalsFunction::Work() {
390  SerialConnection* connection = GetSerialConnection(params_->connection_id);
391  if (!connection) {
392    error_ = kErrorSerialConnectionNotFound;
393    return;
394  }
395
396  serial::DeviceControlSignals signals;
397  if (!connection->GetControlSignals(&signals)) {
398    error_ = kErrorGetControlSignalsFailed;
399    return;
400  }
401
402  results_ = serial::GetControlSignals::Results::Create(signals);
403}
404
405SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() {
406}
407
408SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() {
409}
410
411bool SerialSetControlSignalsFunction::Prepare() {
412  params_ = serial::SetControlSignals::Params::Create(*args_);
413  EXTENSION_FUNCTION_VALIDATE(params_.get());
414
415  return true;
416}
417
418void SerialSetControlSignalsFunction::Work() {
419  SerialConnection* connection = GetSerialConnection(params_->connection_id);
420  if (!connection) {
421    error_ = kErrorSerialConnectionNotFound;
422    return;
423  }
424
425  bool success = connection->SetControlSignals(params_->signals);
426  results_ = serial::SetControlSignals::Results::Create(success);
427}
428
429}  // namespace core_api
430
431}  // namespace extensions
432
433namespace mojo {
434
435// static
436linked_ptr<extensions::core_api::serial::DeviceInfo> TypeConverter<
437    linked_ptr<extensions::core_api::serial::DeviceInfo>,
438    device::serial::DeviceInfoPtr>::Convert(const device::serial::DeviceInfoPtr&
439                                                device) {
440  linked_ptr<extensions::core_api::serial::DeviceInfo> info(
441      new extensions::core_api::serial::DeviceInfo);
442  info->path = device->path;
443  if (device->has_vendor_id)
444    info->vendor_id.reset(new int(static_cast<int>(device->vendor_id)));
445  if (device->has_product_id)
446    info->product_id.reset(new int(static_cast<int>(device->product_id)));
447  if (device->display_name)
448    info->display_name.reset(new std::string(device->display_name));
449  return info;
450}
451
452}  // namespace mojo
453