1 // Copyright 2024 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 
17 #include <fuchsia/bluetooth/gatt2/cpp/fidl.h>
18 
19 #include "lib/zx/eventpair.h"
20 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/gatt2_server_ids.h"
21 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/server_base.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
23 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt.h"
24 
25 namespace bthost {
26 
27 // Implements the gatt2::Server FIDL interface.
28 // TODO(fxbug.dev/42054947): Support sending gatt2::LocalService::PeerUpdate.
29 // TODO(fxbug.dev/42147529): Support GATT service includes.
30 // TODO(fxbug.dev/42180948): Support OnSuppressDiscovery
31 class Gatt2ServerServer
32     : public GattServerBase<fuchsia::bluetooth::gatt2::Server> {
33  public:
34   // Arbitrary; we only refresh credits when the peer starts to get low.
35   // The current implementation does not support a value of 0.
36   static const uint8_t REFRESH_CREDITS_AT = 3;
37 
38   // |gatt| - The GATT instance underlying this Server.
39   // |request| - The FIDL request.
40   Gatt2ServerServer(
41       bt::gatt::GATT::WeakPtr gatt,
42       fidl::InterfaceRequest<fuchsia::bluetooth::gatt2::Server> request);
43 
44   ~Gatt2ServerServer() override;
45 
46  private:
47   struct Service {
48     // The LocalService FIDL proxy
49     fidl::InterfacePtr<fuchsia::bluetooth::gatt2::LocalService> local_svc_ptr;
50 
51     // The credits available for this LocalService
52     int16_t credits = fuchsia::bluetooth::gatt2::INITIAL_VALUE_CHANGED_CREDITS;
53   };
54 
55   // ::fuchsia::bluetooth::gatt2::Server overrides:
56   void PublishService(
57       fuchsia::bluetooth::gatt2::ServiceInfo info,
58       fidl::InterfaceHandle<fuchsia::bluetooth::gatt2::LocalService> service,
59       PublishServiceCallback callback) override;
60 
61   // Removes the service with the given |id| if it is known, usually as a result
62   // of FIDL connection errors (such as handle closure).
63   void RemoveService(InternalServiceId id);
64 
65   // Handles the ::fuchsia::bluetooth:gatt2::Server OnSuppressDiscovery event.
66   void OnSuppressDiscovery(InternalServiceId service_id);
67 
68   // If the update has the required fields and there are credits available,
69   // subtracts a credit from the service and returns true. Otherwise, returns
70   // false.
71   bool ValidateValueChangedEvent(
72       InternalServiceId service_id,
73       const fuchsia::bluetooth::gatt2::ValueChangedParameters& update,
74       const char* update_type);
75 
76   // Handles the ::fuchsia::bluetooth:gatt2::Server OnNotifyValue event.
77   void OnNotifyValue(InternalServiceId service_id,
78                      fuchsia::bluetooth::gatt2::ValueChangedParameters update);
79 
80   // Handles the ::fuchsia::bluetooth:gatt2::Server OnSuppressDiscovery event.
81   void OnIndicateValue(InternalServiceId service_id,
82                        fuchsia::bluetooth::gatt2::ValueChangedParameters update,
83                        zx::eventpair confirmation);
84 
85   // Called when a remote device issues a read request to one of our services.
86   void OnReadRequest(bt::PeerId peer_id,
87                      bt::gatt::IdType service_id,
88                      bt::gatt::IdType id,
89                      uint16_t offset,
90                      bt::gatt::ReadResponder responder);
91 
92   // Called when a remote device issues a write request to one of our services.
93   void OnWriteRequest(bt::PeerId peer_id,
94                       bt::gatt::IdType service_id,
95                       bt::gatt::IdType id,
96                       uint16_t offset,
97                       const bt::ByteBuffer& value,
98                       bt::gatt::WriteResponder responder);
99 
100   // Called when a remote device has configured notifications or indications on
101   // a local characteristic.
102   void OnClientCharacteristicConfiguration(bt::gatt::IdType service_id,
103                                            bt::gatt::IdType chrc_id,
104                                            bt::PeerId peer_id,
105                                            bool notify,
106                                            bool indicate);
107 
108   // Subtract one credit from the client, potentially refreshing the credits to
109   // the client.
110   static void SubtractCredit(Service& svc);
111 
112   // The mapping between internal service identifiers and FIDL Service
113   // implementations.
114   std::unordered_map<InternalServiceId, Service> services_;
115 
116   // Mapping between client-provided Service IDs and internally-generated IDs.
117   // TODO(fxbug.dev/42147529): This will be necessary for supporting service
118   // includes.
119   std::unordered_map<ClientServiceId, InternalServiceId> service_id_mapping_;
120 
121   // Keep this as the last member to make sure that all weak pointers are
122   // invalidated before other members get destroyed.
123   WeakSelf<Gatt2ServerServer> weak_self_;
124 
125   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Gatt2ServerServer);
126 };
127 
128 }  // namespace bthost
129