Home | History | Annotate | Download | only in serial
      1 // Copyright (c) 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 "base/values.h"
      8 #include "chrome/browser/extensions/extension_system.h"
      9 #include "chrome/browser/extensions/api/serial/serial_connection.h"
     10 #include "chrome/browser/extensions/api/serial/serial_port_enumerator.h"
     11 #include "content/public/browser/browser_thread.h"
     12 
     13 using content::BrowserThread;
     14 
     15 namespace extensions {
     16 
     17 const char kConnectionIdKey[] = "connectionId";
     18 const char kDataKey[] = "data";
     19 const char kBytesReadKey[] = "bytesRead";
     20 const char kBytesWrittenKey[] = "bytesWritten";
     21 const char kBitrateKey[] = "bitrate";
     22 const char kSuccessKey[] = "success";
     23 const char kDcdKey[] = "dcd";
     24 const char kCtsKey[] = "cts";
     25 
     26 const char kErrorGetControlSignalsFailed[] = "Failed to get control signals.";
     27 const char kErrorSetControlSignalsFailed[] = "Failed to set control signals.";
     28 const char kSerialReadInvalidBytesToRead[] = "Number of bytes to read must "
     29     "be a positive number less than 1,048,576.";
     30 
     31 SerialAsyncApiFunction::SerialAsyncApiFunction()
     32     : manager_(NULL) {
     33 }
     34 
     35 SerialAsyncApiFunction::~SerialAsyncApiFunction() {
     36 }
     37 
     38 bool SerialAsyncApiFunction::PrePrepare() {
     39   manager_ = ApiResourceManager<SerialConnection>::Get(profile());
     40   DCHECK(manager_);
     41   return true;
     42 }
     43 
     44 SerialConnection* SerialAsyncApiFunction::GetSerialConnection(
     45     int api_resource_id) {
     46   return manager_->Get(extension_->id(), api_resource_id);
     47 }
     48 
     49 void SerialAsyncApiFunction::RemoveSerialConnection(int api_resource_id) {
     50   manager_->Remove(extension_->id(), api_resource_id);
     51 }
     52 
     53 SerialGetPortsFunction::SerialGetPortsFunction() {}
     54 
     55 bool SerialGetPortsFunction::Prepare() {
     56   set_work_thread_id(BrowserThread::FILE);
     57   return true;
     58 }
     59 
     60 void SerialGetPortsFunction::Work() {
     61   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     62 
     63   base::ListValue* ports = new base::ListValue();
     64   SerialPortEnumerator::StringSet port_names =
     65       SerialPortEnumerator::GenerateValidSerialPortNames();
     66   SerialPortEnumerator::StringSet::const_iterator i = port_names.begin();
     67   while (i != port_names.end()) {
     68     ports->Append(Value::CreateStringValue(*i++));
     69   }
     70 
     71   SetResult(ports);
     72 }
     73 
     74 bool SerialGetPortsFunction::Respond() {
     75   return true;
     76 }
     77 
     78 // It's a fool's errand to come up with a default bitrate, because we don't get
     79 // to control both sides of the communication. Unless the other side has
     80 // implemented auto-bitrate detection (rare), if we pick the wrong rate, then
     81 // you're gonna have a bad time. Close doesn't count.
     82 //
     83 // But we'd like to pick something that has a chance of working, and 9600 is a
     84 // good balance between popularity and speed. So 9600 it is.
     85 SerialOpenFunction::SerialOpenFunction()
     86     : bitrate_(9600) {
     87 }
     88 
     89 SerialOpenFunction::~SerialOpenFunction() {
     90 }
     91 
     92 bool SerialOpenFunction::Prepare() {
     93   set_work_thread_id(BrowserThread::FILE);
     94 
     95   params_ = api::serial::Open::Params::Create(*args_);
     96   EXTENSION_FUNCTION_VALIDATE(params_.get());
     97 
     98   if (params_->options.get()) {
     99     scoped_ptr<base::DictionaryValue> options = params_->options->ToValue();
    100     if (options->HasKey(kBitrateKey))
    101       EXTENSION_FUNCTION_VALIDATE(options->GetInteger(kBitrateKey, &bitrate_));
    102   }
    103 
    104   return true;
    105 }
    106 
    107 void SerialOpenFunction::AsyncWorkStart() {
    108   Work();
    109 }
    110 
    111 void SerialOpenFunction::Work() {
    112   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    113   const SerialPortEnumerator::StringSet name_set(
    114     SerialPortEnumerator::GenerateValidSerialPortNames());
    115   if (DoesPortExist(params_->port)) {
    116     SerialConnection* serial_connection = CreateSerialConnection(
    117       params_->port,
    118       bitrate_,
    119       extension_->id());
    120     CHECK(serial_connection);
    121     int id = manager_->Add(serial_connection);
    122     CHECK(id);
    123 
    124     bool open_result = serial_connection->Open();
    125     if (!open_result) {
    126       serial_connection->Close();
    127       RemoveSerialConnection(id);
    128       id = -1;
    129     }
    130 
    131     base::DictionaryValue* result = new base::DictionaryValue();
    132     result->SetInteger(kConnectionIdKey, id);
    133     SetResult(result);
    134     AsyncWorkCompleted();
    135   } else {
    136     base::DictionaryValue* result = new base::DictionaryValue();
    137     result->SetInteger(kConnectionIdKey, -1);
    138     SetResult(result);
    139     AsyncWorkCompleted();
    140   }
    141 }
    142 
    143 SerialConnection* SerialOpenFunction::CreateSerialConnection(
    144     const std::string& port,
    145     int bitrate,
    146     const std::string& owner_extension_id) {
    147   return new SerialConnection(port, bitrate, owner_extension_id);
    148 }
    149 
    150 bool SerialOpenFunction::DoesPortExist(const std::string& port) {
    151   const SerialPortEnumerator::StringSet name_set(
    152     SerialPortEnumerator::GenerateValidSerialPortNames());
    153   return SerialPortEnumerator::DoesPortExist(name_set, params_->port);
    154 }
    155 
    156 bool SerialOpenFunction::Respond() {
    157   return true;
    158 }
    159 
    160 SerialCloseFunction::SerialCloseFunction() {
    161 }
    162 
    163 SerialCloseFunction::~SerialCloseFunction() {
    164 }
    165 
    166 bool SerialCloseFunction::Prepare() {
    167   set_work_thread_id(BrowserThread::FILE);
    168 
    169   params_ = api::serial::Close::Params::Create(*args_);
    170   EXTENSION_FUNCTION_VALIDATE(params_.get());
    171 
    172   return true;
    173 }
    174 
    175 void SerialCloseFunction::Work() {
    176   bool close_result = false;
    177   SerialConnection* serial_connection = GetSerialConnection(
    178       params_->connection_id);
    179   if (serial_connection) {
    180     serial_connection->Close();
    181     RemoveSerialConnection(params_->connection_id);
    182     close_result = true;
    183   }
    184 
    185   SetResult(Value::CreateBooleanValue(close_result));
    186 }
    187 
    188 bool SerialCloseFunction::Respond() {
    189   return true;
    190 }
    191 
    192 SerialReadFunction::SerialReadFunction() {
    193 }
    194 
    195 SerialReadFunction::~SerialReadFunction() {
    196 }
    197 
    198 bool SerialReadFunction::Prepare() {
    199   set_work_thread_id(BrowserThread::FILE);
    200 
    201   params_ = api::serial::Read::Params::Create(*args_);
    202   EXTENSION_FUNCTION_VALIDATE(params_.get());
    203   if (params_->bytes_to_read <= 0 || params_->bytes_to_read >= 1024 * 1024) {
    204     error_ = kSerialReadInvalidBytesToRead;
    205     return false;
    206   }
    207 
    208   return true;
    209 }
    210 
    211 void SerialReadFunction::Work() {
    212   int bytes_read = -1;
    213   scoped_refptr<net::IOBufferWithSize> io_buffer(
    214       new net::IOBufferWithSize(params_->bytes_to_read));
    215   SerialConnection* serial_connection(GetSerialConnection(
    216       params_->connection_id));
    217 
    218   if (serial_connection)
    219     bytes_read = serial_connection->Read(io_buffer);
    220 
    221   base::DictionaryValue* result = new base::DictionaryValue();
    222 
    223   // The API is defined to require a 'data' value, so we will always
    224   // create a BinaryValue, even if it's zero-length.
    225   if (bytes_read < 0)
    226     bytes_read = 0;
    227   result->SetInteger(kBytesReadKey, bytes_read);
    228   result->Set(kDataKey, base::BinaryValue::CreateWithCopiedBuffer(
    229       io_buffer->data(), bytes_read));
    230   SetResult(result);
    231 }
    232 
    233 bool SerialReadFunction::Respond() {
    234   return true;
    235 }
    236 
    237 SerialWriteFunction::SerialWriteFunction()
    238     : io_buffer_(NULL), io_buffer_size_(0) {
    239 }
    240 
    241 SerialWriteFunction::~SerialWriteFunction() {
    242 }
    243 
    244 bool SerialWriteFunction::Prepare() {
    245   set_work_thread_id(BrowserThread::FILE);
    246 
    247   params_ = api::serial::Write::Params::Create(*args_);
    248   EXTENSION_FUNCTION_VALIDATE(params_.get());
    249 
    250   io_buffer_size_ = params_->data.size();
    251   io_buffer_ = new net::WrappedIOBuffer(params_->data.data());
    252 
    253   return true;
    254 }
    255 
    256 void SerialWriteFunction::Work() {
    257   int bytes_written = -1;
    258   SerialConnection* serial_connection = GetSerialConnection(
    259       params_->connection_id);
    260   if (serial_connection)
    261     bytes_written = serial_connection->Write(io_buffer_, io_buffer_size_);
    262   else
    263     error_ = kSerialConnectionNotFoundError;
    264 
    265   base::DictionaryValue* result = new base::DictionaryValue();
    266   result->SetInteger(kBytesWrittenKey, bytes_written);
    267   SetResult(result);
    268 }
    269 
    270 bool SerialWriteFunction::Respond() {
    271   return true;
    272 }
    273 
    274 SerialFlushFunction::SerialFlushFunction() {
    275 }
    276 
    277 SerialFlushFunction::~SerialFlushFunction() {
    278 }
    279 
    280 bool SerialFlushFunction::Prepare() {
    281   set_work_thread_id(BrowserThread::FILE);
    282 
    283   params_ = api::serial::Flush::Params::Create(*args_);
    284   EXTENSION_FUNCTION_VALIDATE(params_.get());
    285   return true;
    286 }
    287 
    288 void SerialFlushFunction::Work() {
    289   bool flush_result = false;
    290   SerialConnection* serial_connection = GetSerialConnection(
    291       params_->connection_id);
    292   if (serial_connection) {
    293     serial_connection->Flush();
    294     flush_result = true;
    295   }
    296 
    297   SetResult(Value::CreateBooleanValue(flush_result));
    298 }
    299 
    300 bool SerialFlushFunction::Respond() {
    301   return true;
    302 }
    303 
    304 SerialGetControlSignalsFunction::SerialGetControlSignalsFunction()
    305     : api_response_(false) {
    306 }
    307 
    308 SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() {
    309 }
    310 
    311 bool SerialGetControlSignalsFunction::Prepare() {
    312   set_work_thread_id(BrowserThread::FILE);
    313 
    314   params_ = api::serial::GetControlSignals::Params::Create(*args_);
    315   EXTENSION_FUNCTION_VALIDATE(params_.get());
    316 
    317   return true;
    318 }
    319 
    320 void SerialGetControlSignalsFunction::Work() {
    321   base::DictionaryValue *result = new base::DictionaryValue();
    322   SerialConnection* serial_connection = GetSerialConnection(
    323       params_->connection_id);
    324   if (serial_connection) {
    325     SerialConnection::ControlSignals control_signals = { 0 };
    326     if (serial_connection->GetControlSignals(control_signals)) {
    327       api_response_ = true;
    328       result->SetBoolean(kDcdKey, control_signals.dcd);
    329       result->SetBoolean(kCtsKey, control_signals.cts);
    330     } else {
    331       error_ = kErrorGetControlSignalsFailed;
    332     }
    333   } else {
    334     error_ = kSerialConnectionNotFoundError;
    335     result->SetBoolean(kSuccessKey, false);
    336   }
    337 
    338   SetResult(result);
    339 }
    340 
    341 bool SerialGetControlSignalsFunction::Respond() {
    342   return api_response_;
    343 }
    344 
    345 SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() {
    346 }
    347 
    348 SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() {
    349 }
    350 
    351 bool SerialSetControlSignalsFunction::Prepare() {
    352   set_work_thread_id(BrowserThread::FILE);
    353 
    354   params_ = api::serial::SetControlSignals::Params::Create(*args_);
    355   EXTENSION_FUNCTION_VALIDATE(params_.get());
    356 
    357   return true;
    358 }
    359 
    360 void SerialSetControlSignalsFunction::Work() {
    361   SerialConnection* serial_connection = GetSerialConnection(
    362       params_->connection_id);
    363   if (serial_connection) {
    364     SerialConnection::ControlSignals control_signals = { 0 };
    365     control_signals.should_set_dtr = params_->options.dtr.get() != NULL;
    366     if (control_signals.should_set_dtr)
    367       control_signals.dtr = *(params_->options.dtr);
    368     control_signals.should_set_rts = params_->options.rts.get() != NULL;
    369     if (control_signals.should_set_rts)
    370       control_signals.rts = *(params_->options.rts);
    371     if (serial_connection->SetControlSignals(control_signals)) {
    372       SetResult(Value::CreateBooleanValue(true));
    373     } else {
    374       error_ = kErrorSetControlSignalsFailed;
    375       SetResult(Value::CreateBooleanValue(false));
    376     }
    377   } else {
    378     error_ = kSerialConnectionNotFoundError;
    379     SetResult(Value::CreateBooleanValue(false));
    380   }
    381 }
    382 
    383 bool SerialSetControlSignalsFunction::Respond() {
    384   return true;
    385 }
    386 
    387 }  // namespace extensions
    388