1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file.
4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "device/serial/serial_io_handler.h"
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/bind.h"
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/files/file_path.h"
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/message_loop/message_loop.h"
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/string_util.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace device {
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SerialIoHandler::SerialIoHandler(
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<base::MessageLoopProxy> file_thread_message_loop)
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : file_thread_message_loop_(file_thread_message_loop) {
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
19116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSerialIoHandler::~SerialIoHandler() {
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  Close();
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::Open(const std::string& port,
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           const OpenCompleteCallback& callback) {
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(open_complete_.is_null());
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  open_complete_ = callback;
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(file_thread_message_loop_.get());
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  file_thread_message_loop_->PostTask(
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&SerialIoHandler::StartOpen,
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 this,
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 port,
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 base::MessageLoopProxy::current()));
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::StartOpen(
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::string& port,
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<base::MessageLoopProxy> io_message_loop) {
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!open_complete_.is_null());
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(file_thread_message_loop_->RunsTasksOnCurrentThread());
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!file_.IsValid());
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // It's the responsibility of the API wrapper around SerialIoHandler to
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // validate the supplied path against the set of valid port names, and
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // it is a reasonable assumption that serial port names are ASCII.
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(base::IsStringASCII(port));
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::FilePath path(base::FilePath::FromUTF8Unsafe(MaybeFixUpPortName(port)));
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              base::File::FLAG_EXCLUSIVE_READ | base::File::FLAG_WRITE |
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              base::File::FLAG_EXCLUSIVE_WRITE | base::File::FLAG_ASYNC |
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              base::File::FLAG_TERMINAL_DEVICE;
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::File file(path, flags);
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  io_message_loop->PostTask(
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&SerialIoHandler::FinishOpen, this, Passed(file.Pass())));
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::FinishOpen(base::File file) {
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!open_complete_.is_null());
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  OpenCompleteCallback callback = open_complete_;
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  open_complete_.Reset();
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!file.IsValid()) {
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    callback.Run(false);
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  file_ = file.Pass();
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool success = PostOpen();
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!success)
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Close();
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  callback.Run(success);
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialIoHandler::PostOpen() {
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::Close() {
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (file_.IsValid()) {
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(file_thread_message_loop_.get());
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    file_thread_message_loop_->PostTask(
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        FROM_HERE, base::Bind(&SerialIoHandler::DoClose, Passed(file_.Pass())));
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// static
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::DoClose(base::File port) {
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // port closed by destructor.
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void SerialIoHandler::Read(scoped_ptr<WritableBuffer> buffer) {
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!IsReadPending());
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  pending_read_buffer_ = buffer.Pass();
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  read_canceled_ = false;
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  AddRef();
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ReadImpl();
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void SerialIoHandler::Write(scoped_ptr<ReadOnlyBuffer> buffer) {
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!IsWritePending());
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  pending_write_buffer_ = buffer.Pass();
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  write_canceled_ = false;
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  AddRef();
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  WriteImpl();
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::ReadCompleted(int bytes_read,
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                    serial::ReceiveError error) {
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(IsReadPending());
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<WritableBuffer> pending_read_buffer = pending_read_buffer_.Pass();
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (error == serial::RECEIVE_ERROR_NONE) {
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_read_buffer->Done(bytes_read);
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_read_buffer->DoneWithError(bytes_read, error);
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  Release();
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::WriteCompleted(int bytes_written,
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     serial::SendError error) {
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(IsWritePending());
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<ReadOnlyBuffer> pending_write_buffer =
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      pending_write_buffer_.Pass();
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (error == serial::SEND_ERROR_NONE) {
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_write_buffer->Done(bytes_written);
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_write_buffer->DoneWithError(bytes_written, error);
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  Release();
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialIoHandler::IsReadPending() const {
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return pending_read_buffer_ != NULL;
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialIoHandler::IsWritePending() const {
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return pending_write_buffer_ != NULL;
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::CancelRead(serial::ReceiveError reason) {
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (IsReadPending() && !read_canceled_) {
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    read_canceled_ = true;
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    read_cancel_reason_ = reason;
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CancelReadImpl();
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::CancelWrite(serial::SendError reason) {
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (IsWritePending() && !write_canceled_) {
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    write_canceled_ = true;
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    write_cancel_reason_ = reason;
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CancelWriteImpl();
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::QueueReadCompleted(int bytes_read,
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                         serial::ReceiveError error) {
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::MessageLoop::current()->PostTask(
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&SerialIoHandler::ReadCompleted, this, bytes_read, error));
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandler::QueueWriteCompleted(int bytes_written,
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          serial::SendError error) {
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::MessageLoop::current()->PostTask(
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&SerialIoHandler::WriteCompleted, this, bytes_written, error));
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace device
183