chromium/chromecast/device/bluetooth/le/remote_device_impl.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMECAST_DEVICE_BLUETOOTH_LE_REMOTE_DEVICE_IMPL_H_
#define CHROMECAST_DEVICE_BLUETOOTH_LE_REMOTE_DEVICE_IMPL_H_

#include <atomic>
#include <deque>
#include <map>
#include <queue>
#include <string>
#include <utility>
#include <vector>

#include "base/memory/weak_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "chromecast/device/bluetooth/le/remote_characteristic.h"
#include "chromecast/device/bluetooth/le/remote_descriptor.h"
#include "chromecast/device/bluetooth/le/remote_device.h"
#include "chromecast/public/bluetooth/gatt.h"

namespace chromecast {
namespace bluetooth {

class GattClientManagerImpl;
class RemoteCharacteristicImpl;
class RemoteDescriptorImpl;
class RemoteService;
class RemoteServiceImpl;

class RemoteDeviceImpl : public RemoteDevice {
 public:
  // If commands take longer than this amount of time, we will disconnect the
  // device.
  static constexpr base::TimeDelta kCommandTimeout = base::Seconds(30);

  RemoteDeviceImpl(const RemoteDeviceImpl&) = delete;
  RemoteDeviceImpl& operator=(const RemoteDeviceImpl&) = delete;

  // RemoteDevice implementation
  void Connect(ConnectCallback cb, bluetooth_v2_shlib::Gatt::Client::Transport transport) override;
  void Disconnect(StatusCallback cb) override;
  void CreateBond(StatusCallback cb) override;
  void RemoveBond(StatusCallback cb) override;
  void ReadRemoteRssi(RssiCallback cb) override;
  void RequestMtu(int mtu, StatusCallback cb) override;
  void ConnectionParameterUpdate(int min_interval,
                                 int max_interval,
                                 int latency,
                                 int timeout,
                                 StatusCallback cb) override;
  bool IsConnected() override;
  bool IsBonded() override;
  int GetMtu() override;
  void GetServices(
      base::OnceCallback<void(std::vector<scoped_refptr<RemoteService>>)> cb)
      override;
  std::vector<scoped_refptr<RemoteService>> GetServicesSync() override;
  void GetServiceByUuid(
      const bluetooth_v2_shlib::Uuid& uuid,
      base::OnceCallback<void(scoped_refptr<RemoteService>)> cb) override;
  scoped_refptr<RemoteService> GetServiceByUuidSync(
      const bluetooth_v2_shlib::Uuid& uuid) override;
  const bluetooth_v2_shlib::Addr& addr() const override;

  void ReadCharacteristic(
      scoped_refptr<RemoteCharacteristicImpl> characteristic,
      bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
      RemoteCharacteristic::ReadCallback cb);
  void WriteCharacteristic(
      scoped_refptr<RemoteCharacteristicImpl> characteristic,
      bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
      bluetooth_v2_shlib::Gatt::WriteType write_type,
      std::vector<uint8_t> value,
      RemoteCharacteristic::StatusCallback cb);
  void ReadDescriptor(scoped_refptr<RemoteDescriptorImpl> descriptor,
                      bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
                      RemoteDescriptor::ReadCallback cb);
  void WriteDescriptor(scoped_refptr<RemoteDescriptorImpl> descriptor,
                       bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
                       std::vector<uint8_t> value,
                       RemoteDescriptor::StatusCallback cb);

 private:
  friend class GattClientManagerImpl;

  RemoteDeviceImpl(const bluetooth_v2_shlib::Addr& addr,
                   base::WeakPtr<GattClientManagerImpl> gatt_client_manager,
                   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
  ~RemoteDeviceImpl() override;

  // Friend methods for GattClientManagerImpl
  void SetConnected(bool connected);
  void SetBonded(bool bonded);
  void SetServicesDiscovered(bool discovered);
  bool GetServicesDiscovered();
  void SetMtu(int mtu);

  scoped_refptr<RemoteCharacteristic> CharacteristicFromHandle(uint16_t handle);

  void OnCharacteristicRead(bool status,
                            uint16_t handle,
                            const std::vector<uint8_t>& value);
  void OnCharacteristicWrite(bool status, uint16_t handle);
  void OnDescriptorRead(bool status,
                        uint16_t handle,
                        const std::vector<uint8_t>& value);
  void OnDescriptorWrite(bool status, uint16_t handle);
  void OnGetServices(
      const std::vector<bluetooth_v2_shlib::Gatt::Service>& services);
  void OnServicesRemoved(uint16_t start_handle, uint16_t end_handle);
  void OnServicesAdded(
      const std::vector<bluetooth_v2_shlib::Gatt::Service>& services);
  void OnReadRemoteRssiComplete(bool status, int rssi);
  // end Friend methods for GattClientManagerImpl

  void ConnectComplete(bool success);

  // Add an operation to the queue. Certain operations can only be executed
  // serially.
  void EnqueueOperation(const std::string& name, base::OnceClosure op);

  // Notify that the currently queued operation has completed.
  void NotifyQueueOperationComplete();

  // Run the next queued operation.
  void RunNextOperation();

  void RequestMtuImpl(int mtu);
  void ReadCharacteristicImpl(
      scoped_refptr<RemoteCharacteristicImpl> descriptor,
      bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req);
  void WriteCharacteristicImpl(
      scoped_refptr<RemoteCharacteristicImpl> descriptor,
      bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
      bluetooth_v2_shlib::Gatt::WriteType write_type,
      std::vector<uint8_t> value);
  void ReadDescriptorImpl(scoped_refptr<RemoteDescriptorImpl> descriptor,
                          bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req);
  void WriteDescriptorImpl(scoped_refptr<RemoteDescriptorImpl> descriptor,
                           bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
                           std::vector<uint8_t> value);
  void ClearServices();

  void OnCommandTimeout(const std::string& command_name);

  const base::WeakPtr<GattClientManagerImpl> gatt_client_manager_;
  const bluetooth_v2_shlib::Addr addr_;

  // All bluetooth_v2_shlib calls are run on this task_runner. Below members
  // should only be accessed on this task_runner.
  const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;

  bool services_discovered_ = false;

  ConnectCallback connect_cb_;

  bool disconnect_pending_ = false;
  StatusCallback disconnect_cb_;

  bool create_bond_pending_ = false;
  StatusCallback create_bond_cb_;

  bool remove_bond_pending_ = false;
  StatusCallback remove_bond_cb_;

  bool rssi_pending_ = false;
  RssiCallback rssi_cb_;

  std::atomic<bool> connected_{false};
  std::atomic<bool> bonded_{false};
  std::atomic<int> mtu_{kDefaultMtu};
  std::map<bluetooth_v2_shlib::Uuid, scoped_refptr<RemoteServiceImpl>>
      uuid_to_service_;
  std::map<uint16_t, scoped_refptr<RemoteCharacteristicImpl>>
      handle_to_characteristic_;

  // Timer for commands on |command_queue_|. If any command times out, we will
  // force disconnect of this device.
  base::OneShotTimer command_timeout_timer_;

  // Queue of operation name and the operation itself.
  std::deque<std::pair<std::string, base::OnceClosure>> command_queue_;
  std::queue<StatusCallback> mtu_callbacks_;
  std::map<uint16_t, std::queue<RemoteCharacteristic::ReadCallback>>
      handle_to_characteristic_read_cbs_;
  std::map<uint16_t, std::queue<RemoteCharacteristic::StatusCallback>>
      handle_to_characteristic_write_cbs_;
  std::map<uint16_t, std::queue<RemoteDescriptor::ReadCallback>>
      handle_to_descriptor_read_cbs_;
  std::map<uint16_t, std::queue<RemoteDescriptor::StatusCallback>>
      handle_to_descriptor_write_cbs_;
};

}  // namespace bluetooth
}  // namespace chromecast

#endif  // CHROMECAST_DEVICE_BLUETOOTH_LE_REMOTE_DEVICE_IMPL_H_