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 12namespace device { 13 14SerialIoHandler::SerialIoHandler( 15 scoped_refptr<base::MessageLoopProxy> file_thread_message_loop) 16 : file_thread_message_loop_(file_thread_message_loop) { 17} 18 19SerialIoHandler::~SerialIoHandler() { 20 DCHECK(CalledOnValidThread()); 21 Close(); 22} 23 24void 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 38void 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 59void 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 78bool SerialIoHandler::PostOpen() { 79 return true; 80} 81 82void 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 91void SerialIoHandler::DoClose(base::File port) { 92 // port closed by destructor. 93} 94 95void 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 104void 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 113void 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 126void 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 140bool SerialIoHandler::IsReadPending() const { 141 DCHECK(CalledOnValidThread()); 142 return pending_read_buffer_ != NULL; 143} 144 145bool SerialIoHandler::IsWritePending() const { 146 DCHECK(CalledOnValidThread()); 147 return pending_write_buffer_ != NULL; 148} 149 150void 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 159void 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 168void 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 175void 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