| // Copyright 2017 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_LOCAL_SERVICE_MANAGER_H_ |
| #define GARNET_DRIVERS_BLUETOOTH_LIB_GATT_LOCAL_SERVICE_MANAGER_H_ |
| |
| #include <unordered_map> |
| |
| #include "garnet/drivers/bluetooth/lib/att/attribute.h" |
| #include "garnet/drivers/bluetooth/lib/att/database.h" |
| #include "garnet/drivers/bluetooth/lib/gatt/types.h" |
| #include "lib/fxl/macros.h" |
| #include "lib/fxl/memory/ref_ptr.h" |
| |
| namespace btlib { |
| namespace gatt { |
| |
| // Called to read the value of a dynamic characteristic or characteristic |
| // descriptor. |
| // - |service_id|: Identifies the service that the object belongs to. |
| // - |id|: Identifies the object to be read. This is a user assigned |
| // identifier provided while registering the service. |
| // - |offset|: The offset into the value that is being read. |
| // - |responder|: Should be called to respond to the read request with a |
| // characteristic or descriptor value, or an ATT error code. |
| using ReadResponder = att::Attribute::ReadResultCallback; |
| using ReadHandler = fit::function<void(IdType service_id, |
| IdType id, |
| uint16_t offset, |
| ReadResponder responder)>; |
| |
| // Called to write the value of a dynamic characteristic or characteristic |
| // descriptor. |
| // - |service_id|: Identifies the service that the object belongs to. |
| // - |id|: Identifies the object to be written. This is a user assigned |
| // identifier provided while registering the service. |
| // - |offset|: The offset into the value that is being written. |
| // - |responder|: Should be called to respond to the write request with |
| // success or an ATT error code. This can be a null callback |
| // if the client has initiated a "Write Without Response" |
| // procedure, in which case a response is not required. |
| using WriteResponder = att::Attribute::WriteResultCallback; |
| using WriteHandler = fit::function<void(IdType service_id, |
| IdType id, |
| uint16_t offset, |
| const common::ByteBuffer& value, |
| WriteResponder responder)>; |
| |
| // Called when the peer device with the given |peer_id| has enabled or disabled |
| // notifications/indications on the characteristic with id |chrc_id|. |
| using ClientConfigCallback = fit::function<void(IdType service_id, |
| IdType chrc_id, |
| const std::string& peer_id, |
| bool notify, |
| bool indicate)>; |
| |
| // Called with the ID and range of attributes handles spanned (inclusive) by a |
| // service that was added or removed. |
| using ServiceChangedCallback = fit::function<void(IdType service_id, |
| att::Handle start, |
| att::Handle end)>; |
| |
| // LocalServiceManager allows clients to implement GATT services. This |
| // internally maintains an attribute database and provides hooks for clients to |
| // respond to read and write requests, send notifications/indications, |
| // add/remove services, etc. |
| class LocalServiceManager final { |
| public: |
| LocalServiceManager(); |
| ~LocalServiceManager(); |
| |
| // Registers the GATT service hierarchy represented by |service| with the |
| // local attribute database. Once successfully registered, the service will be |
| // available for discovery and other ATT protocol requests. |
| // |
| // This method returns an opaque identifier on successful registration, which |
| // can be used by the caller to refer to the service in the future. |
| // |
| // Returns |kInvalidId| on failure. Registration can fail if the attribute |
| // database has run out of handles or if the hierarchy contains |
| // characteristics or descriptors with repeated IDs. Objects under |service| |
| // must have unique identifiers to aid in value request handling. |
| IdType RegisterService(ServicePtr service, |
| ReadHandler read_handler, |
| WriteHandler write_handler, |
| ClientConfigCallback ccc_callback); |
| |
| // Unregisters the GATT service hierarchy identified by |service_id|. Returns |
| // false if |service_id| is unrecognized. |
| bool UnregisterService(IdType service_id); |
| |
| // Returns the client characteristic configuration for the given |peer_id| and |
| // the characteristic identified by |service_id| and |chrc_id|. Returns false |
| // if |service_id| is unknown or no configurations exist for |chrc_id|. |
| struct ClientCharacteristicConfig { |
| att::Handle handle; |
| bool notify; |
| bool indicate; |
| }; |
| bool GetCharacteristicConfig(IdType service_id, |
| IdType chrc_id, |
| const std::string& peer_id, |
| ClientCharacteristicConfig* out_config); |
| |
| // Erase any client characteristic configuration associated to a specific |
| // client and invoke its ClientConfigCallback to signal that notifications and |
| // indications are now disabled. |
| void DisconnectClient(const std::string& peer_id); |
| |
| void set_service_changed_callback(ServiceChangedCallback callback) { |
| service_changed_callback_ = std::move(callback); |
| } |
| |
| fxl::RefPtr<att::Database> database() const { return db_; } |
| |
| private: |
| class ServiceData; |
| |
| fxl::RefPtr<att::Database> db_; |
| IdType next_service_id_; |
| |
| // Mapping from service instance ids to ServiceData. |
| std::unordered_map<IdType, std::unique_ptr<ServiceData>> services_; |
| |
| ServiceChangedCallback service_changed_callback_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(LocalServiceManager); |
| }; |
| |
| } // namespace gatt |
| } // namespace btlib |
| |
| #endif // GARNET_DRIVERS_BLUETOOTH_LIB_GATT_LOCAL_SERVICE_MANAGER_H_ |