blob: 58f70566f05a6a5d28db21e270b984f2eba30331 [file] [log] [blame]
Jakub Pawlowski55faa9e2018-06-21 09:03:45 +02001/******************************************************************************
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
Jakub Pawlowski3ee08ac2018-04-18 07:31:30 -070019#include "database.h"
20#include "bt_trace.h"
21#include "stack/include/gattdefs.h"
22
23#include <base/logging.h>
Myles Watson1bff6982019-03-22 16:51:39 -070024#include <list>
Jakub Pawlowski3ee08ac2018-04-18 07:31:30 -070025#include <memory>
26#include <sstream>
27
28using bluetooth::Uuid;
29
30namespace gatt {
31
32namespace {
33const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
34const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
35const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
36const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
37
38bool HandleInRange(const Service& svc, uint16_t handle) {
39 return handle >= svc.handle && handle <= svc.end_handle;
40}
41} // namespace
42
Myles Watson1bff6982019-03-22 16:51:39 -070043Service* FindService(std::list<Service>& services, uint16_t handle) {
Jakub Pawlowski3ee08ac2018-04-18 07:31:30 -070044 for (Service& service : services) {
45 if (handle >= service.handle && handle <= service.end_handle)
46 return &service;
47 }
48
49 return nullptr;
50}
51
52std::string Database::ToString() const {
53 std::stringstream tmp;
54
55 for (const Service& service : services) {
56 tmp << "Service: handle=" << loghex(service.handle)
57 << ", end_handle=" << loghex(service.end_handle)
58 << ", uuid=" << service.uuid << "\n";
59
60 for (const auto& is : service.included_services) {
61 tmp << "\t Included service: handle=" << loghex(is.handle)
62 << ", start_handle=" << loghex(is.start_handle)
63 << ", end_handle=" << loghex(is.end_handle) << ", uuid=" << is.uuid
64 << "\n";
65 }
66
67 for (const Characteristic& c : service.characteristics) {
68 tmp << "\t Characteristic: declaration_handle="
69 << loghex(c.declaration_handle)
70 << ", value_handle=" << loghex(c.value_handle) << ", uuid=" << c.uuid
71 << ", prop=" << loghex(c.properties) << "\n";
72
73 for (const Descriptor& d : c.descriptors) {
74 tmp << "\t\t Descriptor: handle=" << loghex(d.handle)
75 << ", uuid=" << d.uuid << "\n";
76 }
77 }
78 }
79 return tmp.str();
80}
81
82std::vector<StoredAttribute> Database::Serialize() const {
83 std::vector<StoredAttribute> nv_attr;
84
85 if (services.empty()) return std::vector<StoredAttribute>();
86
87 for (const Service& service : services) {
88 // TODO: add constructor to NV_ATTR, use emplace_back
89 nv_attr.push_back({service.handle,
90 service.is_primary ? PRIMARY_SERVICE : SECONDARY_SERVICE,
91 {.service = {.uuid = service.uuid,
92 .end_handle = service.end_handle}}});
93 }
94
95 for (const Service& service : services) {
96 for (const IncludedService& p_isvc : service.included_services) {
97 nv_attr.push_back({p_isvc.handle,
98 INCLUDE,
99 {.included_service = {.handle = p_isvc.start_handle,
100 .end_handle = p_isvc.end_handle,
101 .uuid = p_isvc.uuid}}});
102 }
103
104 for (const Characteristic& charac : service.characteristics) {
105 nv_attr.push_back(
106 {charac.declaration_handle,
107 CHARACTERISTIC,
108 {.characteristic = {.properties = charac.properties,
109 .value_handle = charac.value_handle,
110 .uuid = charac.uuid}}});
111
112 for (const Descriptor& desc : charac.descriptors) {
113 nv_attr.push_back({desc.handle, desc.uuid, {}});
114 }
115 }
116 }
117
118 return nv_attr;
119}
120
121Database Database::Deserialize(const std::vector<StoredAttribute>& nv_attr,
122 bool* success) {
123 // clear reallocating
124 Database result;
125 auto it = nv_attr.cbegin();
126
127 for (; it != nv_attr.cend(); ++it) {
128 const auto& attr = *it;
129 if (attr.type != PRIMARY_SERVICE && attr.type != SECONDARY_SERVICE) break;
Nick Desaulniers7ee58352019-10-09 11:06:55 -0700130 result.services.emplace_back(Service{
131 .handle = attr.handle,
132 .uuid = attr.value.service.uuid,
133 .is_primary = (attr.type == PRIMARY_SERVICE),
134 .end_handle = attr.value.service.end_handle,
135 });
Jakub Pawlowski3ee08ac2018-04-18 07:31:30 -0700136 }
137
138 auto current_service_it = result.services.begin();
139 for (; it != nv_attr.cend(); it++) {
140 const auto& attr = *it;
141
142 // go to the service this attribute belongs to; attributes are stored in
143 // order, so iterating just forward is enough
144 while (current_service_it != result.services.end() &&
145 current_service_it->end_handle < attr.handle) {
146 current_service_it++;
147 }
148
149 if (current_service_it == result.services.end() ||
150 !HandleInRange(*current_service_it, attr.handle)) {
151 LOG(ERROR) << "Can't find service for attribute with handle: "
152 << loghex(attr.handle);
153 *success = false;
154 return result;
155 }
156
157 if (attr.type == INCLUDE) {
158 Service* included_service =
159 FindService(result.services, attr.value.included_service.handle);
160 if (!included_service) {
161 LOG(ERROR) << __func__ << ": Non-existing included service!";
162 *success = false;
163 return result;
164 }
165 current_service_it->included_services.push_back(IncludedService{
166 .handle = attr.handle,
167 .uuid = attr.value.included_service.uuid,
168 .start_handle = attr.value.included_service.handle,
169 .end_handle = attr.value.included_service.end_handle,
170 });
171 } else if (attr.type == CHARACTERISTIC) {
Nick Desaulniers7ee58352019-10-09 11:06:55 -0700172 current_service_it->characteristics.emplace_back(Characteristic{
173 .declaration_handle = attr.handle,
174 .uuid = attr.value.characteristic.uuid,
175 .value_handle = attr.value.characteristic.value_handle,
176 .properties = attr.value.characteristic.properties,
177 });
Jakub Pawlowski3ee08ac2018-04-18 07:31:30 -0700178
179 } else {
180 current_service_it->characteristics.back().descriptors.emplace_back(
181 Descriptor{.handle = attr.handle, .uuid = attr.type});
182 }
183 }
184 *success = true;
185 return result;
186}
187
Myles Watson1bff6982019-03-22 16:51:39 -0700188} // namespace gatt