#ifndef SERVICES_DEVICE_SERIAL_SERIAL_IO_HANDLER_H_
#define SERVICES_DEVICE_SERIAL_SERIAL_IO_HANDLER_H_
#include <stdint.h>
#include <memory>
#include <string>
#include "base/files/file.h"
#include "base/functional/callback.h"
#include "base/memory/raw_span.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "services/device/public/mojom/serial.mojom.h"
namespace device {
class SerialIoHandler : public base::RefCountedThreadSafe<SerialIoHandler> {
public:
static scoped_refptr<SerialIoHandler> Create(
const base::FilePath& port,
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
SerialIoHandler(const SerialIoHandler&) = delete;
SerialIoHandler& operator=(const SerialIoHandler&) = delete;
using OpenCompleteCallback = base::OnceCallback<void(bool success)>;
using ReadCompleteCallback =
base::OnceCallback<void(uint32_t bytes_read, mojom::SerialReceiveError)>;
using WriteCompleteCallback =
base::OnceCallback<void(uint32_t bytes_written, mojom::SerialSendError)>;
virtual void Open(const mojom::SerialConnectionOptions& options,
OpenCompleteCallback callback);
#if BUILDFLAG(IS_CHROMEOS)
void OnPathOpened(
scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
base::ScopedFD fd);
void OnPathOpenError(
scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
const std::string& error_name,
const std::string& error_message);
void ReportPathOpenError(const std::string& error_name,
const std::string& error_message);
#endif
void Read(base::span<uint8_t> buffer, ReadCompleteCallback callback);
void Write(base::span<const uint8_t> buffer, WriteCompleteCallback callback);
bool IsReadPending() const;
bool IsWritePending() const;
void CancelRead(mojom::SerialReceiveError reason);
void CancelWrite(mojom::SerialSendError reason);
virtual void Flush(mojom::SerialPortFlushMode mode) const = 0;
virtual void Drain() = 0;
virtual mojom::SerialPortControlSignalsPtr GetControlSignals() const = 0;
virtual bool SetControlSignals(
const mojom::SerialHostControlSignals& control_signals) = 0;
bool ConfigurePort(const mojom::SerialConnectionOptions& options);
virtual mojom::SerialConnectionInfoPtr GetPortInfo() const = 0;
void Close(base::OnceClosure callback);
protected:
explicit SerialIoHandler(
const base::FilePath& port,
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
virtual ~SerialIoHandler();
virtual void ReadImpl() = 0;
virtual void WriteImpl() = 0;
virtual void CancelReadImpl() = 0;
virtual void CancelWriteImpl() = 0;
virtual bool ConfigurePortImpl() = 0;
virtual bool PostOpen();
virtual void PreClose();
void ReadCompleted(int bytes_read, mojom::SerialReceiveError error);
void WriteCompleted(int bytes_written, mojom::SerialSendError error);
const base::File& file() const { return file_; }
base::span<uint8_t> pending_read_buffer() const {
return pending_read_buffer_;
}
mojom::SerialReceiveError read_cancel_reason() const {
return read_cancel_reason_;
}
bool read_canceled() const { return read_canceled_; }
base::span<const uint8_t> pending_write_buffer() const {
return pending_write_buffer_;
}
mojom::SerialSendError write_cancel_reason() const {
return write_cancel_reason_;
}
bool write_canceled() const { return write_canceled_; }
const mojom::SerialConnectionOptions& options() const { return options_; }
base::SingleThreadTaskRunner* ui_thread_task_runner() const {
return ui_thread_task_runner_.get();
}
const base::FilePath& port() const { return port_; }
SEQUENCE_CHECKER(sequence_checker_);
private:
friend class base::RefCountedThreadSafe<SerialIoHandler>;
void MergeConnectionOptions(const mojom::SerialConnectionOptions& options);
void StartOpen(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
void FinishOpen(base::File file);
static void DoClose(base::File port);
base::File file_;
mojom::SerialConnectionOptions options_;
base::raw_span<uint8_t> pending_read_buffer_;
ReadCompleteCallback pending_read_callback_;
mojom::SerialReceiveError read_cancel_reason_;
bool read_canceled_;
base::raw_span<const uint8_t> pending_write_buffer_;
WriteCompleteCallback pending_write_callback_;
mojom::SerialSendError write_cancel_reason_;
bool write_canceled_;
OpenCompleteCallback open_complete_;
const base::FilePath port_;
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
};
}
#endif