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_connection.h"
      6 
      7 #include <string>
      8 
      9 #include "base/files/file_path.h"
     10 #include "base/lazy_instance.h"
     11 #include "extensions/browser/api/api_resource_manager.h"
     12 #include "extensions/common/api/serial.h"
     13 
     14 namespace extensions {
     15 
     16 namespace {
     17 
     18 const int kDefaultBufferSize = 4096;
     19 
     20 core_api::serial::SendError ConvertSendErrorFromMojo(
     21     device::serial::SendError input) {
     22   switch (input) {
     23     case device::serial::SEND_ERROR_NONE:
     24       return core_api::serial::SEND_ERROR_NONE;
     25     case device::serial::SEND_ERROR_DISCONNECTED:
     26       return core_api::serial::SEND_ERROR_DISCONNECTED;
     27     case device::serial::SEND_ERROR_PENDING:
     28       return core_api::serial::SEND_ERROR_PENDING;
     29     case device::serial::SEND_ERROR_TIMEOUT:
     30       return core_api::serial::SEND_ERROR_TIMEOUT;
     31     case device::serial::SEND_ERROR_SYSTEM_ERROR:
     32       return core_api::serial::SEND_ERROR_SYSTEM_ERROR;
     33   }
     34   return core_api::serial::SEND_ERROR_NONE;
     35 }
     36 
     37 core_api::serial::ReceiveError ConvertReceiveErrorFromMojo(
     38     device::serial::ReceiveError input) {
     39   switch (input) {
     40     case device::serial::RECEIVE_ERROR_NONE:
     41       return core_api::serial::RECEIVE_ERROR_NONE;
     42     case device::serial::RECEIVE_ERROR_DISCONNECTED:
     43       return core_api::serial::RECEIVE_ERROR_DISCONNECTED;
     44     case device::serial::RECEIVE_ERROR_TIMEOUT:
     45       return core_api::serial::RECEIVE_ERROR_TIMEOUT;
     46     case device::serial::RECEIVE_ERROR_DEVICE_LOST:
     47       return core_api::serial::RECEIVE_ERROR_DEVICE_LOST;
     48     case device::serial::RECEIVE_ERROR_SYSTEM_ERROR:
     49       return core_api::serial::RECEIVE_ERROR_SYSTEM_ERROR;
     50   }
     51   return core_api::serial::RECEIVE_ERROR_NONE;
     52 }
     53 
     54 core_api::serial::DataBits ConvertDataBitsFromMojo(
     55     device::serial::DataBits input) {
     56   switch (input) {
     57     case device::serial::DATA_BITS_NONE:
     58       return core_api::serial::DATA_BITS_NONE;
     59     case device::serial::DATA_BITS_SEVEN:
     60       return core_api::serial::DATA_BITS_SEVEN;
     61     case device::serial::DATA_BITS_EIGHT:
     62       return core_api::serial::DATA_BITS_EIGHT;
     63   }
     64   return core_api::serial::DATA_BITS_NONE;
     65 }
     66 
     67 device::serial::DataBits ConvertDataBitsToMojo(
     68     core_api::serial::DataBits input) {
     69   switch (input) {
     70     case core_api::serial::DATA_BITS_NONE:
     71       return device::serial::DATA_BITS_NONE;
     72     case core_api::serial::DATA_BITS_SEVEN:
     73       return device::serial::DATA_BITS_SEVEN;
     74     case core_api::serial::DATA_BITS_EIGHT:
     75       return device::serial::DATA_BITS_EIGHT;
     76   }
     77   return device::serial::DATA_BITS_NONE;
     78 }
     79 
     80 core_api::serial::ParityBit ConvertParityBitFromMojo(
     81     device::serial::ParityBit input) {
     82   switch (input) {
     83     case device::serial::PARITY_BIT_NONE:
     84       return core_api::serial::PARITY_BIT_NONE;
     85     case device::serial::PARITY_BIT_ODD:
     86       return core_api::serial::PARITY_BIT_ODD;
     87     case device::serial::PARITY_BIT_NO:
     88       return core_api::serial::PARITY_BIT_NO;
     89     case device::serial::PARITY_BIT_EVEN:
     90       return core_api::serial::PARITY_BIT_EVEN;
     91   }
     92   return core_api::serial::PARITY_BIT_NONE;
     93 }
     94 
     95 device::serial::ParityBit ConvertParityBitToMojo(
     96     core_api::serial::ParityBit input) {
     97   switch (input) {
     98     case core_api::serial::PARITY_BIT_NONE:
     99       return device::serial::PARITY_BIT_NONE;
    100     case core_api::serial::PARITY_BIT_NO:
    101       return device::serial::PARITY_BIT_NO;
    102     case core_api::serial::PARITY_BIT_ODD:
    103       return device::serial::PARITY_BIT_ODD;
    104     case core_api::serial::PARITY_BIT_EVEN:
    105       return device::serial::PARITY_BIT_EVEN;
    106   }
    107   return device::serial::PARITY_BIT_NONE;
    108 }
    109 
    110 core_api::serial::StopBits ConvertStopBitsFromMojo(
    111     device::serial::StopBits input) {
    112   switch (input) {
    113     case device::serial::STOP_BITS_NONE:
    114       return core_api::serial::STOP_BITS_NONE;
    115     case device::serial::STOP_BITS_ONE:
    116       return core_api::serial::STOP_BITS_ONE;
    117     case device::serial::STOP_BITS_TWO:
    118       return core_api::serial::STOP_BITS_TWO;
    119   }
    120   return core_api::serial::STOP_BITS_NONE;
    121 }
    122 
    123 device::serial::StopBits ConvertStopBitsToMojo(
    124     core_api::serial::StopBits input) {
    125   switch (input) {
    126     case core_api::serial::STOP_BITS_NONE:
    127       return device::serial::STOP_BITS_NONE;
    128     case core_api::serial::STOP_BITS_ONE:
    129       return device::serial::STOP_BITS_ONE;
    130     case core_api::serial::STOP_BITS_TWO:
    131       return device::serial::STOP_BITS_TWO;
    132   }
    133   return device::serial::STOP_BITS_NONE;
    134 }
    135 
    136 class SendBuffer : public device::ReadOnlyBuffer {
    137  public:
    138   SendBuffer(
    139       const std::string& data,
    140       const base::Callback<void(int, device::serial::SendError)>& callback)
    141       : data_(data), callback_(callback) {}
    142   virtual ~SendBuffer() {}
    143   virtual const char* GetData() OVERRIDE { return data_.c_str(); }
    144   virtual uint32_t GetSize() OVERRIDE {
    145     return static_cast<uint32_t>(data_.size());
    146   }
    147   virtual void Done(uint32_t bytes_read) OVERRIDE {
    148     callback_.Run(bytes_read, device::serial::SEND_ERROR_NONE);
    149   }
    150   virtual void DoneWithError(uint32_t bytes_read, int32_t error) OVERRIDE {
    151     callback_.Run(bytes_read, static_cast<device::serial::SendError>(error));
    152   }
    153 
    154  private:
    155   const std::string data_;
    156   const base::Callback<void(int, device::serial::SendError)> callback_;
    157 };
    158 
    159 class ReceiveBuffer : public device::WritableBuffer {
    160  public:
    161   ReceiveBuffer(
    162       scoped_refptr<net::IOBuffer> buffer,
    163       uint32_t size,
    164       const base::Callback<void(int, device::serial::ReceiveError)>& callback)
    165       : buffer_(buffer), size_(size), callback_(callback) {}
    166   virtual ~ReceiveBuffer() {}
    167   virtual char* GetData() OVERRIDE { return buffer_->data(); }
    168   virtual uint32_t GetSize() OVERRIDE { return size_; }
    169   virtual void Done(uint32_t bytes_written) OVERRIDE {
    170     callback_.Run(bytes_written, device::serial::RECEIVE_ERROR_NONE);
    171   }
    172   virtual void DoneWithError(uint32_t bytes_written, int32_t error) OVERRIDE {
    173     callback_.Run(bytes_written,
    174                   static_cast<device::serial::ReceiveError>(error));
    175   }
    176 
    177  private:
    178   scoped_refptr<net::IOBuffer> buffer_;
    179   const uint32_t size_;
    180   const base::Callback<void(int, device::serial::ReceiveError)> callback_;
    181 };
    182 
    183 }  // namespace
    184 
    185 static base::LazyInstance<
    186     BrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> > >
    187     g_factory = LAZY_INSTANCE_INITIALIZER;
    188 
    189 // static
    190 template <>
    191 BrowserContextKeyedAPIFactory<ApiResourceManager<SerialConnection> >*
    192 ApiResourceManager<SerialConnection>::GetFactoryInstance() {
    193   return g_factory.Pointer();
    194 }
    195 
    196 SerialConnection::SerialConnection(const std::string& port,
    197                                    const std::string& owner_extension_id)
    198     : ApiResource(owner_extension_id),
    199       port_(port),
    200       persistent_(false),
    201       buffer_size_(kDefaultBufferSize),
    202       receive_timeout_(0),
    203       send_timeout_(0),
    204       paused_(false),
    205       io_handler_(device::SerialIoHandler::Create(
    206           content::BrowserThread::GetMessageLoopProxyForThread(
    207               content::BrowserThread::FILE))) {
    208   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    209 }
    210 
    211 SerialConnection::~SerialConnection() {
    212   io_handler_->CancelRead(device::serial::RECEIVE_ERROR_DISCONNECTED);
    213   io_handler_->CancelWrite(device::serial::SEND_ERROR_DISCONNECTED);
    214 }
    215 
    216 bool SerialConnection::IsPersistent() const {
    217   return persistent();
    218 }
    219 
    220 void SerialConnection::set_buffer_size(int buffer_size) {
    221   buffer_size_ = buffer_size;
    222 }
    223 
    224 void SerialConnection::set_receive_timeout(int receive_timeout) {
    225   receive_timeout_ = receive_timeout;
    226 }
    227 
    228 void SerialConnection::set_send_timeout(int send_timeout) {
    229   send_timeout_ = send_timeout;
    230 }
    231 
    232 void SerialConnection::set_paused(bool paused) {
    233   paused_ = paused;
    234   if (paused) {
    235     io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE);
    236   }
    237 }
    238 
    239 void SerialConnection::Open(const OpenCompleteCallback& callback) {
    240   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    241   io_handler_->Open(port_, callback);
    242 }
    243 
    244 bool SerialConnection::Receive(const ReceiveCompleteCallback& callback) {
    245   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    246   if (!receive_complete_.is_null())
    247     return false;
    248   receive_complete_ = callback;
    249   receive_buffer_ = new net::IOBuffer(buffer_size_);
    250   io_handler_->Read(scoped_ptr<device::WritableBuffer>(new ReceiveBuffer(
    251       receive_buffer_,
    252       buffer_size_,
    253       base::Bind(&SerialConnection::OnAsyncReadComplete, AsWeakPtr()))));
    254   receive_timeout_task_.reset();
    255   if (receive_timeout_ > 0) {
    256     receive_timeout_task_.reset(new TimeoutTask(
    257         base::Bind(&SerialConnection::OnReceiveTimeout, AsWeakPtr()),
    258         base::TimeDelta::FromMilliseconds(receive_timeout_)));
    259   }
    260   return true;
    261 }
    262 
    263 bool SerialConnection::Send(const std::string& data,
    264                             const SendCompleteCallback& callback) {
    265   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    266   if (!send_complete_.is_null())
    267     return false;
    268   send_complete_ = callback;
    269   io_handler_->Write(scoped_ptr<device::ReadOnlyBuffer>(new SendBuffer(
    270       data, base::Bind(&SerialConnection::OnAsyncWriteComplete, AsWeakPtr()))));
    271   send_timeout_task_.reset();
    272   if (send_timeout_ > 0) {
    273     send_timeout_task_.reset(new TimeoutTask(
    274         base::Bind(&SerialConnection::OnSendTimeout, AsWeakPtr()),
    275         base::TimeDelta::FromMilliseconds(send_timeout_)));
    276   }
    277   return true;
    278 }
    279 
    280 bool SerialConnection::Configure(
    281     const core_api::serial::ConnectionOptions& options) {
    282   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    283   if (options.persistent.get())
    284     set_persistent(*options.persistent);
    285   if (options.name.get())
    286     set_name(*options.name);
    287   if (options.buffer_size.get())
    288     set_buffer_size(*options.buffer_size);
    289   if (options.receive_timeout.get())
    290     set_receive_timeout(*options.receive_timeout);
    291   if (options.send_timeout.get())
    292     set_send_timeout(*options.send_timeout);
    293   bool success = io_handler_->ConfigurePort(
    294       *device::serial::ConnectionOptions::From(options));
    295   io_handler_->CancelRead(device::serial::RECEIVE_ERROR_NONE);
    296   return success;
    297 }
    298 
    299 void SerialConnection::SetIoHandlerForTest(
    300     scoped_refptr<device::SerialIoHandler> handler) {
    301   io_handler_ = handler;
    302 }
    303 
    304 bool SerialConnection::GetInfo(core_api::serial::ConnectionInfo* info) const {
    305   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    306   info->paused = paused_;
    307   info->persistent = persistent_;
    308   info->name = name_;
    309   info->buffer_size = buffer_size_;
    310   info->receive_timeout = receive_timeout_;
    311   info->send_timeout = send_timeout_;
    312   device::serial::ConnectionInfoPtr port_info = io_handler_->GetPortInfo();
    313   if (!port_info)
    314     return false;
    315 
    316   info->bitrate.reset(new int(port_info->bitrate));
    317   info->data_bits = ConvertDataBitsFromMojo(port_info->data_bits);
    318   info->parity_bit = ConvertParityBitFromMojo(port_info->parity_bit);
    319   info->stop_bits = ConvertStopBitsFromMojo(port_info->stop_bits);
    320   info->cts_flow_control.reset(new bool(port_info->cts_flow_control));
    321   return true;
    322 }
    323 
    324 bool SerialConnection::Flush() const {
    325   return io_handler_->Flush();
    326 }
    327 
    328 bool SerialConnection::GetControlSignals(
    329     core_api::serial::DeviceControlSignals* control_signals) const {
    330   device::serial::DeviceControlSignalsPtr signals =
    331       io_handler_->GetControlSignals();
    332   if (!signals)
    333     return false;
    334 
    335   control_signals->dcd = signals->dcd;
    336   control_signals->cts = signals->cts;
    337   control_signals->ri = signals->ri;
    338   control_signals->dsr = signals->dsr;
    339   return true;
    340 }
    341 
    342 bool SerialConnection::SetControlSignals(
    343     const core_api::serial::HostControlSignals& control_signals) {
    344   return io_handler_->SetControlSignals(
    345       *device::serial::HostControlSignals::From(control_signals));
    346 }
    347 
    348 void SerialConnection::OnReceiveTimeout() {
    349   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    350   io_handler_->CancelRead(device::serial::RECEIVE_ERROR_TIMEOUT);
    351 }
    352 
    353 void SerialConnection::OnSendTimeout() {
    354   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    355   io_handler_->CancelWrite(device::serial::SEND_ERROR_TIMEOUT);
    356 }
    357 
    358 void SerialConnection::OnAsyncReadComplete(int bytes_read,
    359                                            device::serial::ReceiveError error) {
    360   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    361   DCHECK(!receive_complete_.is_null());
    362   ReceiveCompleteCallback callback = receive_complete_;
    363   receive_complete_.Reset();
    364   receive_timeout_task_.reset();
    365   callback.Run(std::string(receive_buffer_->data(), bytes_read),
    366                ConvertReceiveErrorFromMojo(error));
    367   receive_buffer_ = NULL;
    368 }
    369 
    370 void SerialConnection::OnAsyncWriteComplete(int bytes_sent,
    371                                             device::serial::SendError error) {
    372   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    373   DCHECK(!send_complete_.is_null());
    374   SendCompleteCallback callback = send_complete_;
    375   send_complete_.Reset();
    376   send_timeout_task_.reset();
    377   callback.Run(bytes_sent, ConvertSendErrorFromMojo(error));
    378 }
    379 
    380 SerialConnection::TimeoutTask::TimeoutTask(const base::Closure& closure,
    381                                            const base::TimeDelta& delay)
    382     : weak_factory_(this), closure_(closure), delay_(delay) {
    383   base::MessageLoop::current()->PostDelayedTask(
    384       FROM_HERE,
    385       base::Bind(&TimeoutTask::Run, weak_factory_.GetWeakPtr()),
    386       delay_);
    387 }
    388 
    389 SerialConnection::TimeoutTask::~TimeoutTask() {
    390 }
    391 
    392 void SerialConnection::TimeoutTask::Run() const {
    393   closure_.Run();
    394 }
    395 
    396 }  // namespace extensions
    397 
    398 namespace mojo {
    399 
    400 // static
    401 device::serial::HostControlSignalsPtr
    402 TypeConverter<device::serial::HostControlSignalsPtr,
    403               extensions::core_api::serial::HostControlSignals>::
    404     Convert(const extensions::core_api::serial::HostControlSignals& input) {
    405   device::serial::HostControlSignalsPtr output(
    406       device::serial::HostControlSignals::New());
    407   if (input.dtr.get()) {
    408     output->has_dtr = true;
    409     output->dtr = *input.dtr;
    410   }
    411   if (input.rts.get()) {
    412     output->has_rts = true;
    413     output->rts = *input.rts;
    414   }
    415   return output.Pass();
    416 }
    417 
    418 // static
    419 device::serial::ConnectionOptionsPtr
    420 TypeConverter<device::serial::ConnectionOptionsPtr,
    421               extensions::core_api::serial::ConnectionOptions>::
    422     Convert(const extensions::core_api::serial::ConnectionOptions& input) {
    423   device::serial::ConnectionOptionsPtr output(
    424       device::serial::ConnectionOptions::New());
    425   if (input.bitrate.get() && *input.bitrate > 0)
    426     output->bitrate = *input.bitrate;
    427   output->data_bits = extensions::ConvertDataBitsToMojo(input.data_bits);
    428   output->parity_bit = extensions::ConvertParityBitToMojo(input.parity_bit);
    429   output->stop_bits = extensions::ConvertStopBitsToMojo(input.stop_bits);
    430   if (input.cts_flow_control.get()) {
    431     output->has_cts_flow_control = true;
    432     output->cts_flow_control = *input.cts_flow_control;
    433   }
    434   return output.Pass();
    435 }
    436 
    437 }  // namespace mojo
    438