#ifndef EXTENSIONS_BROWSER_API_SERIAL_SERIAL_CONNECTION_H_
#define EXTENSIONS_BROWSER_API_SERIAL_SERIAL_CONNECTION_H_
#include <memory>
#include <string>
#include <vector>
#include "base/cancelable_callback.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/api/api_resource.h"
#include "extensions/browser/api/api_resource_manager.h"
#include "extensions/common/api/serial.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "net/base/io_buffer.h"
#include "services/device/public/mojom/serial.mojom.h"
using content::BrowserThread;
namespace extensions {
namespace api {
class SerialPortManager;
}
class SerialConnection : public ApiResource,
public device::mojom::SerialPortClient {
public:
using OpenCompleteCallback = base::OnceCallback<void(bool)>;
using GetInfoCompleteCallback =
base::OnceCallback<void(bool,
std::unique_ptr<api::serial::ConnectionInfo>)>;
using ReceiveEventCallback =
base::RepeatingCallback<void(std::vector<uint8_t> data,
api::serial::ReceiveError error)>;
using SendCompleteCallback =
base::OnceCallback<void(uint32_t bytes_sent,
api::serial::SendError error)>;
using ConfigureCompleteCallback =
device::mojom::SerialPort::ConfigurePortCallback;
using FlushCompleteCallback = device::mojom::SerialPort::FlushCallback;
using GetControlSignalsCompleteCallback = base::OnceCallback<void(
std::unique_ptr<api::serial::DeviceControlSignals>)>;
using SetControlSignalsCompleteCallback =
device::mojom::SerialPort::SetControlSignalsCallback;
explicit SerialConnection(const std::string& owner_extension_id);
~SerialConnection() override;
bool IsPersistent() const override;
void set_persistent(bool persistent) { persistent_ = persistent; }
bool persistent() const { return persistent_; }
void set_name(const std::string& name) { name_ = name; }
const std::string& name() const { return name_; }
void set_buffer_size(int buffer_size);
int buffer_size() const { return buffer_size_; }
void set_receive_timeout(int receive_timeout);
int receive_timeout() const { return receive_timeout_; }
void set_send_timeout(int send_timeout);
int send_timeout() const { return send_timeout_; }
void SetPaused(bool paused);
bool paused() const { return paused_; }
void SetConnectionErrorHandler(base::OnceClosure connection_error_handler);
virtual void Open(api::SerialPortManager* port_manager,
const std::string& path,
const api::serial::ConnectionOptions& options,
OpenCompleteCallback callback);
virtual void Send(const std::vector<uint8_t>& data,
SendCompleteCallback callback);
virtual void StartPolling(const ReceiveEventCallback& callback);
void Flush(device::mojom::SerialPortFlushMode mode,
FlushCompleteCallback callback) const;
void Configure(const api::serial::ConnectionOptions& options,
ConfigureCompleteCallback callback);
void GetInfo(GetInfoCompleteCallback callback) const;
void GetControlSignals(GetControlSignalsCompleteCallback callback) const;
void SetControlSignals(device::mojom::SerialHostControlSignalsPtr signals,
SetControlSignalsCompleteCallback callback);
void Close(base::OnceClosure callback);
static const BrowserThread::ID kThreadId = BrowserThread::UI;
protected:
void InitSerialPortForTesting();
private:
friend class ApiResourceManager<SerialConnection>;
static const char* service_name() { return "SerialConnectionManager"; }
void OnReadError(device::mojom::SerialReceiveError error) override;
void OnSendError(device::mojom::SerialSendError error) override;
void OnOpen(
mojo::PendingReceiver<device::mojom::SerialPortClient> client_receiver,
OpenCompleteCallback callback,
mojo::PendingRemote<device::mojom::SerialPort> serial_port);
void OnReadPipeReadableOrClosed(MojoResult result,
const mojo::HandleSignalsState& state);
void OnReadPipeClosed();
void CreatePipe(mojo::ScopedDataPipeProducerHandle* producer,
mojo::ScopedDataPipeConsumerHandle* consumer);
void SetUpReceiveDataPipe();
void SetUpSendDataPipe();
void SetTimeoutCallback();
void OnReceiveTimeout();
void OnSendTimeout();
void OnSendPipeWritableOrClosed(MojoResult result,
const mojo::HandleSignalsState& state);
void OnSendPipeClosed();
void OnConnectionError();
void OnClientReceiverClosed();
bool persistent_;
std::string name_;
int buffer_size_;
int receive_timeout_;
int send_timeout_;
bool paused_;
ReceiveEventCallback receive_event_cb_;
std::optional<device::mojom::SerialReceiveError> read_error_;
SendCompleteCallback send_complete_;
size_t bytes_written_;
std::vector<uint8_t> data_to_send_;
base::CancelableOnceClosure receive_timeout_task_;
base::CancelableOnceClosure send_timeout_task_;
mojo::Remote<device::mojom::SerialPort> serial_port_;
mojo::ScopedDataPipeConsumerHandle receive_pipe_;
mojo::SimpleWatcher receive_pipe_watcher_;
mojo::ScopedDataPipeProducerHandle send_pipe_;
mojo::SimpleWatcher send_pipe_watcher_;
mojo::Receiver<device::mojom::SerialPortClient> client_receiver_{this};
base::OnceClosure connection_error_handler_;
base::WeakPtrFactory<SerialConnection> weak_factory_{this};
};
}
namespace mojo {
template <>
struct TypeConverter<device::mojom::SerialHostControlSignalsPtr,
extensions::api::serial::HostControlSignals> {
static device::mojom::SerialHostControlSignalsPtr Convert(
const extensions::api::serial::HostControlSignals& input);
};
template <>
struct TypeConverter<device::mojom::SerialConnectionOptionsPtr,
extensions::api::serial::ConnectionOptions> {
static device::mojom::SerialConnectionOptionsPtr Convert(
const extensions::api::serial::ConnectionOptions& input);
};
}
#endif