Home | History | Annotate | Download | only in serial
      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 
     17 using content::BrowserThread;
     18 
     19 namespace extensions {
     20 
     21 namespace core_api {
     22 
     23 namespace {
     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.
     32 const int kDefaultBufferSize = 4096;
     33 const int kDefaultBitrate = 9600;
     34 const serial::DataBits kDefaultDataBits = serial::DATA_BITS_EIGHT;
     35 const serial::ParityBit kDefaultParityBit = serial::PARITY_BIT_NO;
     36 const serial::StopBits kDefaultStopBits = serial::STOP_BITS_ONE;
     37 const int kDefaultReceiveTimeout = 0;
     38 const int kDefaultSendTimeout = 0;
     39 
     40 const char kErrorConnectFailed[] = "Failed to connect to the port.";
     41 const char kErrorSerialConnectionNotFound[] = "Serial connection not found.";
     42 const char kErrorGetControlSignalsFailed[] = "Failed to get control signals.";
     43 
     44 template <class T>
     45 void SetDefaultScopedPtrValue(scoped_ptr<T>& ptr, const T& value) {
     46   if (!ptr.get())
     47     ptr.reset(new T(value));
     48 }
     49 
     50 }  // namespace
     51 
     52 SerialAsyncApiFunction::SerialAsyncApiFunction() : manager_(NULL) {
     53 }
     54 
     55 SerialAsyncApiFunction::~SerialAsyncApiFunction() {
     56 }
     57 
     58 bool SerialAsyncApiFunction::PrePrepare() {
     59   manager_ = ApiResourceManager<SerialConnection>::Get(browser_context());
     60   DCHECK(manager_);
     61   return true;
     62 }
     63 
     64 bool SerialAsyncApiFunction::Respond() {
     65   return error_.empty();
     66 }
     67 
     68 SerialConnection* SerialAsyncApiFunction::GetSerialConnection(
     69     int api_resource_id) {
     70   return manager_->Get(extension_->id(), api_resource_id);
     71 }
     72 
     73 void SerialAsyncApiFunction::RemoveSerialConnection(int api_resource_id) {
     74   manager_->Remove(extension_->id(), api_resource_id);
     75 }
     76 
     77 SerialGetDevicesFunction::SerialGetDevicesFunction() {
     78 }
     79 
     80 bool SerialGetDevicesFunction::Prepare() {
     81   set_work_thread_id(BrowserThread::FILE);
     82   return true;
     83 }
     84 
     85 void 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 
     95 SerialConnectFunction::SerialConnectFunction() {
     96 }
     97 
     98 SerialConnectFunction::~SerialConnectFunction() {
     99 }
    100 
    101 bool 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 
    130 void 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 
    136 void 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 
    155 void 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 
    174 SerialConnection* SerialConnectFunction::CreateSerialConnection(
    175     const std::string& port,
    176     const std::string& extension_id) const {
    177   return new SerialConnection(port, extension_id);
    178 }
    179 
    180 SerialUpdateFunction::SerialUpdateFunction() {
    181 }
    182 
    183 SerialUpdateFunction::~SerialUpdateFunction() {
    184 }
    185 
    186 bool SerialUpdateFunction::Prepare() {
    187   params_ = serial::Update::Params::Create(*args_);
    188   EXTENSION_FUNCTION_VALIDATE(params_.get());
    189 
    190   return true;
    191 }
    192 
    193 void 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 
    203 SerialDisconnectFunction::SerialDisconnectFunction() {
    204 }
    205 
    206 SerialDisconnectFunction::~SerialDisconnectFunction() {
    207 }
    208 
    209 bool SerialDisconnectFunction::Prepare() {
    210   params_ = serial::Disconnect::Params::Create(*args_);
    211   EXTENSION_FUNCTION_VALIDATE(params_.get());
    212 
    213   return true;
    214 }
    215 
    216 void 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 
    226 SerialSendFunction::SerialSendFunction() {
    227 }
    228 
    229 SerialSendFunction::~SerialSendFunction() {
    230 }
    231 
    232 bool SerialSendFunction::Prepare() {
    233   params_ = serial::Send::Params::Create(*args_);
    234   EXTENSION_FUNCTION_VALIDATE(params_.get());
    235 
    236   return true;
    237 }
    238 
    239 void 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 
    254 void 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 
    263 SerialFlushFunction::SerialFlushFunction() {
    264 }
    265 
    266 SerialFlushFunction::~SerialFlushFunction() {
    267 }
    268 
    269 bool SerialFlushFunction::Prepare() {
    270   params_ = serial::Flush::Params::Create(*args_);
    271   EXTENSION_FUNCTION_VALIDATE(params_.get());
    272   return true;
    273 }
    274 
    275 void 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 
    286 SerialSetPausedFunction::SerialSetPausedFunction() {
    287 }
    288 
    289 SerialSetPausedFunction::~SerialSetPausedFunction() {
    290 }
    291 
    292 bool 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 
    301 void 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 
    319 SerialGetInfoFunction::SerialGetInfoFunction() {
    320 }
    321 
    322 SerialGetInfoFunction::~SerialGetInfoFunction() {
    323 }
    324 
    325 bool SerialGetInfoFunction::Prepare() {
    326   params_ = serial::GetInfo::Params::Create(*args_);
    327   EXTENSION_FUNCTION_VALIDATE(params_.get());
    328 
    329   return true;
    330 }
    331 
    332 void 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 
    345 SerialGetConnectionsFunction::SerialGetConnectionsFunction() {
    346 }
    347 
    348 SerialGetConnectionsFunction::~SerialGetConnectionsFunction() {
    349 }
    350 
    351 bool SerialGetConnectionsFunction::Prepare() {
    352   return true;
    353 }
    354 
    355 void 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 
    376 SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() {
    377 }
    378 
    379 SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() {
    380 }
    381 
    382 bool SerialGetControlSignalsFunction::Prepare() {
    383   params_ = serial::GetControlSignals::Params::Create(*args_);
    384   EXTENSION_FUNCTION_VALIDATE(params_.get());
    385 
    386   return true;
    387 }
    388 
    389 void 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 
    405 SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() {
    406 }
    407 
    408 SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() {
    409 }
    410 
    411 bool SerialSetControlSignalsFunction::Prepare() {
    412   params_ = serial::SetControlSignals::Params::Create(*args_);
    413   EXTENSION_FUNCTION_VALIDATE(params_.get());
    414 
    415   return true;
    416 }
    417 
    418 void 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 
    433 namespace mojo {
    434 
    435 // static
    436 linked_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