• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 #include <lib/fit/function.h>
17 
18 #include <unordered_set>
19 
20 #include "pw_bluetooth_sapphire/internal/host/att/att.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
22 #include "pw_bluetooth_sapphire/internal/host/gatt/local_service_manager.h"
23 #include "pw_bluetooth_sapphire/internal/host/gatt/persisted_data.h"
24 
25 namespace bt::gatt {
26 constexpr IdType kServiceChangedChrcId = 0u;
27 
28 // Callback to send an indication. Used to inject the GATT object's
29 // update-sending ability without requiring this service to carry a reference to
30 // GATT or Server.
31 //   |chrc_id|: the service-defined ID of the characteristic to indicate
32 //   |svc_id|: the gatt::GATT-defined ID of the service containing |chrc_id|.
33 // For example, to indicate a new service to a peer via the Service Changed
34 // chrc, one would invoke this with svc_id = the GenericAttributeService's
35 // service_id_, chrc_id = kServiceChangedChrcId, peer_id of the peer, and value
36 // = the att::Handle range of the new service.
37 using SendIndicationCallback = fit::function<void(
38     IdType svc_id, IdType chrc_id, PeerId peer_id, BufferView value)>;
39 
40 // Implements the "Generic Attribute Profile Service" containing the "Service
41 // Changed" characteristic that is "...used to indicate to connected devices
42 // that services have changed (Vol 3, Part G, 7)."
43 class GenericAttributeService final {
44  public:
45   // Registers this service and makes this service the callee of the Service
46   // Changed callback. GATT remote clients must still request that they be sent
47   // indications for the Service Changed characteristic. Holds the
48   // LocalServiceManager pointer for this object's lifetime. Do not register
49   // multiple instances of this service in a single bt-host.
50   GenericAttributeService(LocalServiceManager::WeakPtr local_service_manager,
51                           SendIndicationCallback send_indication_callback);
52   ~GenericAttributeService();
53 
54   // This callback is called when a client changes the CCC for the service
55   // changed characteristic to inform the upper layers of the stack to persist
56   // this value.
SetPersistServiceChangedCCCCallback(PersistServiceChangedCCCCallback callback)57   void SetPersistServiceChangedCCCCallback(
58       PersistServiceChangedCCCCallback callback) {
59     persist_service_changed_ccc_callback_ = std::move(callback);
60   }
61 
62   // Set the service changed indication subscription for a given peer.
63   void SetServiceChangedIndicationSubscription(PeerId peer_id, bool indicate);
64 
service_id()65   inline IdType service_id() const { return service_id_; }
66 
67  private:
68   void Register();
69 
70   // Send indications to subscribed clients when a service has changed.
71   void OnServiceChanged(IdType service_id, att::Handle start, att::Handle end);
72 
73   // Data store against which to register and unregister this service. It must
74   // outlive this instance.
75   LocalServiceManager::WeakPtr local_service_manager_;
76   const SendIndicationCallback send_indication_callback_;
77 
78   // Peers that have subscribed to indications.
79   std::unordered_set<PeerId> subscribed_peers_;
80 
81   // Handle for the Service Changed characteristic that is read when it is first
82   // configured for indications.
83   att::Handle svc_changed_handle_ = att::kInvalidHandle;
84 
85   // Local service ID; hidden because registration is tied to instance lifetime.
86   IdType service_id_ = kInvalidId;
87 
88   // Callback to inform uper stack layers to persist service changed CCC.
89   PersistServiceChangedCCCCallback persist_service_changed_ccc_callback_;
90 };
91 
92 }  // namespace bt::gatt
93