• 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 "database_builder.h"
20 
21 #include "bt_trace.h"
22 
23 #include <base/logging.h>
24 #include <algorithm>
25 
26 using bluetooth::Uuid;
27 
28 namespace gatt {
29 
AddService(uint16_t handle,uint16_t end_handle,const Uuid & uuid,bool is_primary)30 void DatabaseBuilder::AddService(uint16_t handle, uint16_t end_handle,
31                                  const Uuid& uuid, bool is_primary) {
32   // general case optimization - we add services in order
33   if (database.services.empty() ||
34       database.services.back().end_handle < handle) {
35     database.services.emplace_back(Service{.handle = handle,
36                                            .end_handle = end_handle,
37                                            .is_primary = is_primary,
38                                            .uuid = uuid});
39   } else {
40     auto& vec = database.services;
41 
42     // Find first service whose start handle is bigger than new service handle
43     auto it = std::lower_bound(
44         vec.begin(), vec.end(), handle,
45         [](Service s, uint16_t handle) { return s.end_handle < handle; });
46 
47     // Insert new service just before it
48     vec.emplace(it, Service{.handle = handle,
49                             .end_handle = end_handle,
50                             .is_primary = is_primary,
51                             .uuid = uuid});
52   }
53 
54   services_to_discover.insert({handle, end_handle});
55 }
56 
AddIncludedService(uint16_t handle,const Uuid & uuid,uint16_t start_handle,uint16_t end_handle)57 void DatabaseBuilder::AddIncludedService(uint16_t handle, const Uuid& uuid,
58                                          uint16_t start_handle,
59                                          uint16_t end_handle) {
60   Service* service = FindService(database.services, handle);
61   if (!service) {
62     LOG(ERROR) << "Illegal action to add to non-existing service!";
63     return;
64   }
65 
66   /* We discover all Primary Services first. If included service was not seen
67    * before, it must be a Secondary Service */
68   if (!FindService(database.services, start_handle)) {
69     AddService(start_handle, end_handle, uuid, false /* not primary */);
70   }
71 
72   service->included_services.push_back(IncludedService{
73       .handle = handle,
74       .uuid = uuid,
75       .start_handle = start_handle,
76       .end_handle = end_handle,
77   });
78 }
79 
AddCharacteristic(uint16_t handle,uint16_t value_handle,const Uuid & uuid,uint8_t properties)80 void DatabaseBuilder::AddCharacteristic(uint16_t handle, uint16_t value_handle,
81                                         const Uuid& uuid, uint8_t properties) {
82   Service* service = FindService(database.services, handle);
83   if (!service) {
84     LOG(ERROR) << "Illegal action to add to non-existing service!";
85     return;
86   }
87 
88   if (service->end_handle < value_handle)
89     LOG(WARNING) << "Remote device violates spec: value_handle="
90                  << loghex(value_handle) << " is after service end_handle="
91                  << loghex(service->end_handle);
92 
93   service->characteristics.emplace_back(
94       Characteristic{.declaration_handle = handle,
95                      .value_handle = value_handle,
96                      .properties = properties,
97                      .uuid = uuid});
98   return;
99 }
100 
AddDescriptor(uint16_t handle,const Uuid & uuid)101 void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
102   Service* service = FindService(database.services, handle);
103   if (!service) {
104     LOG(ERROR) << "Illegal action to add to non-existing service!";
105     return;
106   }
107 
108   if (service->characteristics.empty()) {
109     LOG(ERROR) << __func__
110                << ": Illegal action to add to non-existing characteristic!";
111     return;
112   }
113 
114   Characteristic* char_node = &service->characteristics.front();
115   for (auto it = service->characteristics.begin();
116        it != service->characteristics.end(); it++) {
117     if (it->declaration_handle > handle) break;
118     char_node = &(*it);
119   }
120 
121   char_node->descriptors.emplace_back(
122       gatt::Descriptor{.handle = handle, .uuid = uuid});
123 }
124 
StartNextServiceExploration()125 bool DatabaseBuilder::StartNextServiceExploration() {
126   while (!services_to_discover.empty()) {
127     auto handle_range = services_to_discover.begin();
128     pending_service = *handle_range;
129     services_to_discover.erase(handle_range);
130 
131     // Empty service declaration, nothing to explore, skip to next.
132     if (pending_service.first == pending_service.second) continue;
133 
134     pending_characteristic = HANDLE_MIN;
135     return true;
136   }
137   return false;
138 }
139 
140 const std::pair<uint16_t, uint16_t>&
CurrentlyExploredService()141 DatabaseBuilder::CurrentlyExploredService() {
142   return pending_service;
143 }
144 
NextDescriptorRangeToExplore()145 std::pair<uint16_t, uint16_t> DatabaseBuilder::NextDescriptorRangeToExplore() {
146   Service* service = FindService(database.services, pending_service.first);
147   if (!service || service->characteristics.empty()) {
148     return {HANDLE_MAX, HANDLE_MAX};
149   }
150 
151   for (auto it = service->characteristics.cbegin();
152        it != service->characteristics.cend(); it++) {
153     if (it->declaration_handle > pending_characteristic) {
154       auto next = std::next(it);
155 
156       /* Characteristic Declaration is followed by Characteristic Value
157        * Declaration, first descriptor is after that, see BT Spect 5.0 Vol 3,
158        * Part G 3.3.2 and 3.3.3 */
159       uint16_t start = it->declaration_handle + 2;
160       uint16_t end;
161       if (next != service->characteristics.end())
162         end = next->declaration_handle - 1;
163       else
164         end = service->end_handle;
165 
166       // No place for descriptor - skip to next characteristic
167       if (start > end) continue;
168 
169       pending_characteristic = start;
170       return {start, end};
171     }
172   }
173 
174   pending_characteristic = HANDLE_MAX;
175   return {HANDLE_MAX, HANDLE_MAX};
176 }
177 
InProgress() const178 bool DatabaseBuilder::InProgress() const { return !database.services.empty(); }
179 
Build()180 Database DatabaseBuilder::Build() {
181   Database tmp = database;
182   database.Clear();
183   return tmp;
184 }
185 
Clear()186 void DatabaseBuilder::Clear() { database.Clear(); }
187 
ToString() const188 std::string DatabaseBuilder::ToString() const { return database.ToString(); }
189 
190 }  // namespace gatt
191