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