blob: 7457c6e46bd11ec089b69f62759cadb69093b3a6 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GARNET_DRIVERS_BLUETOOTH_LIB_GATT_REMOTE_CHARACTERISTIC_H_
#define GARNET_DRIVERS_BLUETOOTH_LIB_GATT_REMOTE_CHARACTERISTIC_H_
#include <queue>
#include <unordered_map>
#include <vector>
#include <lib/async/dispatcher.h>
#include <lib/fit/function.h>
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/weak_ptr.h"
#include "lib/fxl/synchronization/thread_checker.h"
#include "garnet/drivers/bluetooth/lib/att/status.h"
#include "garnet/drivers/bluetooth/lib/gatt/gatt_defs.h"
namespace btlib {
namespace gatt {
class Client;
// Used by a RemoteService to represent one of its characteristics. This object
// maintains information about a characteristic (such as its descriptors, known
// permissions, etc) and is responsible for routing notifications to subscribed
// clients.
//
// The public accessors of this class are thread-safe and can be called on any
// thread as long as this object is alive and is only managed by a
// RemoteService.
//
// Instances are created and owned by a RemoteService. Creation and all
// modifications will happen on the GATT thread.
//
// ID SCHEME:
//
// The ID that gets assigned to a RemoteCharacteristic is its index in the
// owning RemoteService's |characteristics_| member. This allows for constant
// time look up of a characteristic using the ID.
//
// The lower 16 bits of a Descriptor's ID is its index in the owning
// RemoteCharacteristic's |descriptors_| member. The next 16 bits store the
// characteristic ID. This enables constant-time lookup of a descriptor by ID
// from a RemoteService.
//
// THREAD-SAFETY:
//
// Since each RemoteService is shared (potentially across threads),
// RemoteCharacteristic objects can get destroyed on any thread. RemoteService
// MUST call ShutDown() on the GATT thread to ensure safe clean up.
class RemoteCharacteristic final {
public:
using ValueCallback = fit::function<void(const common::ByteBuffer&)>;
using NotifyStatusCallback =
fit::function<void(att::Status, IdType handler_id)>;
// Represents a "Characteristic Descriptor" (Vol 3, Part G, 3.3.3).
class Descriptor final {
public:
Descriptor(IdType id, const DescriptorData& info);
IdType id() const { return id_; }
const DescriptorData& info() const { return info_; }
private:
IdType id_;
DescriptorData info_;
};
using DescriptorList = std::vector<Descriptor>;
RemoteCharacteristic(fxl::WeakPtr<Client> client, IdType id,
const CharacteristicData& info);
~RemoteCharacteristic() = default;
// The move constructor allows this move-only type to be stored in a vector
// (or array) by value (this allows RemoteService to store
// RemoteCharacteristics in contiguous memory).
//
// Moving transfers all data from the source object to the destination except
// for the weak pointer factory. All weak pointers to the source object are
// invalidated.
//
// Care should be taken when used together with std::vector as it moves its
// contents while resizing its storage.
RemoteCharacteristic(RemoteCharacteristic&&);
// Returns the ID for this characteristic.
IdType id() const { return id_; }
// ATT declaration data for this characteristic.
const CharacteristicData& info() const { return info_; }
// Descriptors of this characteristic.
const DescriptorList& descriptors() const { return descriptors_; }
private:
friend class RemoteService;
// The following private methods can only be called by a RemoteService. All
// except the destructor will be called on the GATT thread.
// Cleans up all state associated with this characteristic.
void ShutDown();
// Discovers the descriptors of this characteristic and reports the status in
// |callback|.
//
// NOTE: The owning RemoteService is responsible for ensuring that this object
// outlives the discovery procedure.
void DiscoverDescriptors(att::Handle range_end, att::StatusCallback callback);
// (See RemoteService::NotifyCharacteristic in remote_service.h).
void EnableNotifications(ValueCallback value_callback,
NotifyStatusCallback status_callback,
async_dispatcher_t* dispatcher = nullptr);
bool DisableNotifications(IdType handler_id);
// Sends a request to disable notifications and indications. Called by
// DisableNotifications and ShutDown.
void DisableNotificationsInternal();
// Resolves all pending notification subscription requests. Called by
// EnableNotifications().
void ResolvePendingNotifyRequests(att::Status status);
// Called when a notification is received for this characteristic.
void HandleNotification(const common::ByteBuffer& value);
fxl::ThreadChecker thread_checker_;
IdType id_;
CharacteristicData info_;
DescriptorList descriptors_;
bool discovery_error_;
std::atomic_bool shut_down_;
// Handle of the Client Characteristic Configuration descriptor, or 0 if none.
att::Handle ccc_handle_;
// Represents a pending request to subscribe to notifications or indications.
struct PendingNotifyRequest {
PendingNotifyRequest(async_dispatcher_t* dispatcher, ValueCallback value_callback,
NotifyStatusCallback status_callback);
PendingNotifyRequest() = default;
PendingNotifyRequest(PendingNotifyRequest&&) = default;
async_dispatcher_t* dispatcher;
ValueCallback value_callback;
NotifyStatusCallback status_callback;
};
std::queue<PendingNotifyRequest> pending_notify_reqs_;
// Active notification handlers.
struct NotifyHandler {
NotifyHandler(async_dispatcher_t* dispatcher, ValueCallback callback);
NotifyHandler() = default;
NotifyHandler(NotifyHandler&&) = default;
NotifyHandler& operator=(NotifyHandler&&) = default;
async_dispatcher_t* dispatcher;
ValueCallback callback;
};
std::unordered_map<IdType, NotifyHandler> notify_handlers_;
// The next available notification handler ID.
size_t next_notify_handler_id_;
// The GATT client bearer used for ATT requests.
fxl::WeakPtr<Client> client_;
fxl::WeakPtrFactory<RemoteCharacteristic> weak_ptr_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(RemoteCharacteristic);
};
} // namespace gatt
} // namespace btlib
#endif // GARNET_DRIVERS_BLUETOOTH_LIB_GATT_REMOTE_CHARACTERISTIC_H_