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 "device/serial/serial_io_handler.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/files/file_path.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/strings/string_util.h"
     11 
     12 namespace device {
     13 
     14 SerialIoHandler::SerialIoHandler(
     15     scoped_refptr<base::MessageLoopProxy> file_thread_message_loop)
     16     : file_thread_message_loop_(file_thread_message_loop) {
     17 }
     18 
     19 SerialIoHandler::~SerialIoHandler() {
     20   DCHECK(CalledOnValidThread());
     21   Close();
     22 }
     23 
     24 void SerialIoHandler::Open(const std::string& port,
     25                            const OpenCompleteCallback& callback) {
     26   DCHECK(CalledOnValidThread());
     27   DCHECK(open_complete_.is_null());
     28   open_complete_ = callback;
     29   DCHECK(file_thread_message_loop_.get());
     30   file_thread_message_loop_->PostTask(
     31       FROM_HERE,
     32       base::Bind(&SerialIoHandler::StartOpen,
     33                  this,
     34                  port,
     35                  base::MessageLoopProxy::current()));
     36 }
     37 
     38 void SerialIoHandler::StartOpen(
     39     const std::string& port,
     40     scoped_refptr<base::MessageLoopProxy> io_message_loop) {
     41   DCHECK(!open_complete_.is_null());
     42   DCHECK(file_thread_message_loop_->RunsTasksOnCurrentThread());
     43   DCHECK(!file_.IsValid());
     44   // It's the responsibility of the API wrapper around SerialIoHandler to
     45   // validate the supplied path against the set of valid port names, and
     46   // it is a reasonable assumption that serial port names are ASCII.
     47   DCHECK(base::IsStringASCII(port));
     48   base::FilePath path(base::FilePath::FromUTF8Unsafe(MaybeFixUpPortName(port)));
     49   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
     50               base::File::FLAG_EXCLUSIVE_READ | base::File::FLAG_WRITE |
     51               base::File::FLAG_EXCLUSIVE_WRITE | base::File::FLAG_ASYNC |
     52               base::File::FLAG_TERMINAL_DEVICE;
     53   base::File file(path, flags);
     54   io_message_loop->PostTask(
     55       FROM_HERE,
     56       base::Bind(&SerialIoHandler::FinishOpen, this, Passed(file.Pass())));
     57 }
     58 
     59 void SerialIoHandler::FinishOpen(base::File file) {
     60   DCHECK(CalledOnValidThread());
     61   DCHECK(!open_complete_.is_null());
     62   OpenCompleteCallback callback = open_complete_;
     63   open_complete_.Reset();
     64 
     65   if (!file.IsValid()) {
     66     callback.Run(false);
     67     return;
     68   }
     69 
     70   file_ = file.Pass();
     71 
     72   bool success = PostOpen();
     73   if (!success)
     74     Close();
     75   callback.Run(success);
     76 }
     77 
     78 bool SerialIoHandler::PostOpen() {
     79   return true;
     80 }
     81 
     82 void SerialIoHandler::Close() {
     83   if (file_.IsValid()) {
     84     DCHECK(file_thread_message_loop_.get());
     85     file_thread_message_loop_->PostTask(
     86         FROM_HERE, base::Bind(&SerialIoHandler::DoClose, Passed(file_.Pass())));
     87   }
     88 }
     89 
     90 // static
     91 void SerialIoHandler::DoClose(base::File port) {
     92   // port closed by destructor.
     93 }
     94 
     95 void SerialIoHandler::Read(scoped_ptr<WritableBuffer> buffer) {
     96   DCHECK(CalledOnValidThread());
     97   DCHECK(!IsReadPending());
     98   pending_read_buffer_ = buffer.Pass();
     99   read_canceled_ = false;
    100   AddRef();
    101   ReadImpl();
    102 }
    103 
    104 void SerialIoHandler::Write(scoped_ptr<ReadOnlyBuffer> buffer) {
    105   DCHECK(CalledOnValidThread());
    106   DCHECK(!IsWritePending());
    107   pending_write_buffer_ = buffer.Pass();
    108   write_canceled_ = false;
    109   AddRef();
    110   WriteImpl();
    111 }
    112 
    113 void SerialIoHandler::ReadCompleted(int bytes_read,
    114                                     serial::ReceiveError error) {
    115   DCHECK(CalledOnValidThread());
    116   DCHECK(IsReadPending());
    117   scoped_ptr<WritableBuffer> pending_read_buffer = pending_read_buffer_.Pass();
    118   if (error == serial::RECEIVE_ERROR_NONE) {
    119     pending_read_buffer->Done(bytes_read);
    120   } else {
    121     pending_read_buffer->DoneWithError(bytes_read, error);
    122   }
    123   Release();
    124 }
    125 
    126 void SerialIoHandler::WriteCompleted(int bytes_written,
    127                                      serial::SendError error) {
    128   DCHECK(CalledOnValidThread());
    129   DCHECK(IsWritePending());
    130   scoped_ptr<ReadOnlyBuffer> pending_write_buffer =
    131       pending_write_buffer_.Pass();
    132   if (error == serial::SEND_ERROR_NONE) {
    133     pending_write_buffer->Done(bytes_written);
    134   } else {
    135     pending_write_buffer->DoneWithError(bytes_written, error);
    136   }
    137   Release();
    138 }
    139 
    140 bool SerialIoHandler::IsReadPending() const {
    141   DCHECK(CalledOnValidThread());
    142   return pending_read_buffer_ != NULL;
    143 }
    144 
    145 bool SerialIoHandler::IsWritePending() const {
    146   DCHECK(CalledOnValidThread());
    147   return pending_write_buffer_ != NULL;
    148 }
    149 
    150 void SerialIoHandler::CancelRead(serial::ReceiveError reason) {
    151   DCHECK(CalledOnValidThread());
    152   if (IsReadPending() && !read_canceled_) {
    153     read_canceled_ = true;
    154     read_cancel_reason_ = reason;
    155     CancelReadImpl();
    156   }
    157 }
    158 
    159 void SerialIoHandler::CancelWrite(serial::SendError reason) {
    160   DCHECK(CalledOnValidThread());
    161   if (IsWritePending() && !write_canceled_) {
    162     write_canceled_ = true;
    163     write_cancel_reason_ = reason;
    164     CancelWriteImpl();
    165   }
    166 }
    167 
    168 void SerialIoHandler::QueueReadCompleted(int bytes_read,
    169                                          serial::ReceiveError error) {
    170   base::MessageLoop::current()->PostTask(
    171       FROM_HERE,
    172       base::Bind(&SerialIoHandler::ReadCompleted, this, bytes_read, error));
    173 }
    174 
    175 void SerialIoHandler::QueueWriteCompleted(int bytes_written,
    176                                           serial::SendError error) {
    177   base::MessageLoop::current()->PostTask(
    178       FROM_HERE,
    179       base::Bind(&SerialIoHandler::WriteCompleted, this, bytes_written, error));
    180 }
    181 
    182 }  // namespace device
    183