• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 2018 The Android Open Source Project
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <list>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include "bt_target.h"  // Must be first to define build configuration
27 
28 #include "bta/gatt/database.h"
29 #include "bta/gatt/database_builder.h"
30 #include "stack/include/gattdefs.h"
31 #include "types/bluetooth/uuid.h"
32 
33 using bluetooth::Uuid;
34 
35 namespace gatt {
36 
AddService(uint16_t handle,uint16_t end_handle,const Uuid & uuid,bool is_primary)37 void DatabaseBuilder::AddService(uint16_t handle, uint16_t end_handle,
38                                  const Uuid& uuid, bool is_primary) {
39   // general case optimization - we add services in order
40   if (database.services.empty() ||
41       database.services.back().end_handle < handle) {
42     database.services.emplace_back(Service{
43         .handle = handle,
44         .uuid = uuid,
45         .is_primary = is_primary,
46         .end_handle = end_handle,
47     });
48   } else {
49     auto& vec = database.services;
50 
51     // Find first service whose start handle is bigger than new service handle
52     auto it = std::lower_bound(
53         vec.begin(), vec.end(), handle,
54         [](Service s, uint16_t handle) { return s.end_handle < handle; });
55 
56     // Insert new service just before it
57     vec.emplace(it, Service{
58                         .handle = handle,
59                         .uuid = uuid,
60                         .is_primary = is_primary,
61                         .end_handle = end_handle,
62                     });
63   }
64 
65   services_to_discover.insert({handle, end_handle});
66 }
67 
AddIncludedService(uint16_t handle,const Uuid & uuid,uint16_t start_handle,uint16_t end_handle)68 void DatabaseBuilder::AddIncludedService(uint16_t handle, const Uuid& uuid,
69                                          uint16_t start_handle,
70                                          uint16_t end_handle) {
71   Service* service = FindService(database.services, handle);
72   if (!service) {
73     LOG(ERROR) << "Illegal action to add to non-existing service!";
74     return;
75   }
76 
77   /* We discover all Primary Services first. If included service was not seen
78    * before, it must be a Secondary Service */
79   if (!FindService(database.services, start_handle)) {
80     AddService(start_handle, end_handle, uuid, false /* not primary */);
81   }
82 
83   service->included_services.push_back(IncludedService{
84       .handle = handle,
85       .uuid = uuid,
86       .start_handle = start_handle,
87       .end_handle = end_handle,
88   });
89 }
90 
AddCharacteristic(uint16_t handle,uint16_t value_handle,const Uuid & uuid,uint8_t properties)91 void DatabaseBuilder::AddCharacteristic(uint16_t handle, uint16_t value_handle,
92                                         const Uuid& uuid, uint8_t properties) {
93   Service* service = FindService(database.services, handle);
94   if (!service) {
95     LOG(ERROR) << "Illegal action to add to non-existing service!";
96     return;
97   }
98 
99   if (service->end_handle < value_handle)
100     LOG(WARNING) << "Remote device violates spec: value_handle="
101                  << loghex(value_handle) << " is after service end_handle="
102                  << loghex(service->end_handle);
103 
104   service->characteristics.emplace_back(Characteristic{
105       .declaration_handle = handle,
106       .uuid = uuid,
107       .value_handle = value_handle,
108       .properties = properties,
109   });
110   return;
111 }
112 
AddDescriptor(uint16_t handle,const Uuid & uuid)113 void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
114   Service* service = FindService(database.services, handle);
115   if (!service) {
116     LOG(ERROR) << "Illegal action to add to non-existing service!";
117     return;
118   }
119 
120   if (service->characteristics.empty()) {
121     LOG(ERROR) << __func__
122                << ": Illegal action to add to non-existing characteristic!";
123     return;
124   }
125 
126   Characteristic* char_node = &service->characteristics.front();
127   for (auto it = service->characteristics.begin();
128        it != service->characteristics.end(); it++) {
129     if (it->declaration_handle > handle) break;
130     char_node = &(*it);
131   }
132 
133   char_node->descriptors.emplace_back(
134       gatt::Descriptor{.handle = handle, .uuid = uuid});
135 
136   // We must read value for Characteristic Extended Properties
137   if (uuid == Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP)) {
138     descriptor_handles_to_read.emplace_back(handle);
139   }
140 }
141 
StartNextServiceExploration()142 bool DatabaseBuilder::StartNextServiceExploration() {
143   while (!services_to_discover.empty()) {
144     auto handle_range = services_to_discover.begin();
145     pending_service = *handle_range;
146     services_to_discover.erase(handle_range);
147 
148     // Empty service declaration, nothing to explore, skip to next.
149     if (pending_service.first == pending_service.second) continue;
150 
151     pending_characteristic = HANDLE_MIN;
152     return true;
153   }
154   return false;
155 }
156 
157 const std::pair<uint16_t, uint16_t>&
CurrentlyExploredService()158 DatabaseBuilder::CurrentlyExploredService() {
159   return pending_service;
160 }
161 
NextDescriptorRangeToExplore()162 std::pair<uint16_t, uint16_t> DatabaseBuilder::NextDescriptorRangeToExplore() {
163   Service* service = FindService(database.services, pending_service.first);
164   if (!service || service->characteristics.empty()) {
165     return {HANDLE_MAX, HANDLE_MAX};
166   }
167 
168   for (auto it = service->characteristics.cbegin();
169        it != service->characteristics.cend(); it++) {
170     if (it->declaration_handle > pending_characteristic) {
171       auto next = std::next(it);
172 
173       /* Characteristic Declaration is followed by Characteristic Value
174        * Declaration, first descriptor is after that, see BT Spect 5.0 Vol 3,
175        * Part G 3.3.2 and 3.3.3 */
176       uint16_t start = it->declaration_handle + 2;
177       uint16_t end;
178       if (next != service->characteristics.end())
179         end = next->declaration_handle - 1;
180       else
181         end = service->end_handle;
182 
183       // No place for descriptor - skip to next characteristic
184       if (start > end) continue;
185 
186       pending_characteristic = start;
187       return {start, end};
188     }
189   }
190 
191   pending_characteristic = HANDLE_MAX;
192   return {HANDLE_MAX, HANDLE_MAX};
193 }
194 
FindDescriptorByHandle(std::list<Service> & services,uint16_t handle)195 Descriptor* FindDescriptorByHandle(std::list<Service>& services,
196                                    uint16_t handle) {
197   Service* service = FindService(services, handle);
198   if (!service) return nullptr;
199 
200   Characteristic* char_node = &service->characteristics.front();
201   for (auto it = service->characteristics.begin();
202        it != service->characteristics.end(); it++) {
203     if (it->declaration_handle > handle) break;
204     char_node = &(*it);
205   }
206 
207   for (auto& descriptor : char_node->descriptors) {
208     if (descriptor.handle == handle) return &descriptor;
209   }
210 
211   return nullptr;
212 }
213 
SetValueOfDescriptors(const std::vector<uint16_t> & values)214 bool DatabaseBuilder::SetValueOfDescriptors(
215     const std::vector<uint16_t>& values) {
216   if (values.size() > descriptor_handles_to_read.size()) {
217     LOG(ERROR) << "values.size() <= descriptors.size() expected";
218     descriptor_handles_to_read.clear();
219     return false;
220   }
221 
222   for (size_t i = 0; i < values.size(); i++) {
223     Descriptor* d = FindDescriptorByHandle(database.services,
224                                            descriptor_handles_to_read[i]);
225     if (!d) {
226       LOG(ERROR) << __func__ << "non-existing descriptor!";
227       descriptor_handles_to_read.clear();
228       return false;
229     }
230 
231     d->characteristic_extended_properties = values[i];
232   }
233 
234   descriptor_handles_to_read.erase(
235       descriptor_handles_to_read.begin(),
236       descriptor_handles_to_read.begin() + values.size());
237   return true;
238 }
239 
InProgress() const240 bool DatabaseBuilder::InProgress() const { return !database.services.empty(); }
241 
Build()242 Database DatabaseBuilder::Build() {
243   Database tmp = database;
244   database.Clear();
245   return tmp;
246 }
247 
Clear()248 void DatabaseBuilder::Clear() { database.Clear(); }
249 
ToString() const250 std::string DatabaseBuilder::ToString() const { return database.ToString(); }
251 
252 }  // namespace gatt
253