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