1 /******************************************************************************
3 * Copyright 2018 The Android Open Source Project
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
21 #include "stack/include/gattdefs.h"
23 #include <base/logging.h>
28 using bluetooth::Uuid;
33 const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
34 const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
35 const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
36 const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
38 bool HandleInRange(const Service& svc, uint16_t handle) {
39 return handle >= svc.handle && handle <= svc.end_handle;
43 Service* FindService(std::list<Service>& services, uint16_t handle) {
44 for (Service& service : services) {
45 if (handle >= service.handle && handle <= service.end_handle)
52 std::string Database::ToString() const {
53 std::stringstream tmp;
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";
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
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";
73 for (const Descriptor& d : c.descriptors) {
74 tmp << "\t\t Descriptor: handle=" << loghex(d.handle)
75 << ", uuid=" << d.uuid << "\n";
82 std::vector<StoredAttribute> Database::Serialize() const {
83 std::vector<StoredAttribute> nv_attr;
85 if (services.empty()) return std::vector<StoredAttribute>();
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}}});
95 for (const Service& service : services) {
96 for (const IncludedService& p_isvc : service.included_services) {
97 nv_attr.push_back({p_isvc.handle,
99 {.included_service = {.handle = p_isvc.start_handle,
100 .end_handle = p_isvc.end_handle,
101 .uuid = p_isvc.uuid}}});
104 for (const Characteristic& charac : service.characteristics) {
106 {charac.declaration_handle,
108 {.characteristic = {.properties = charac.properties,
109 .value_handle = charac.value_handle,
110 .uuid = charac.uuid}}});
112 for (const Descriptor& desc : charac.descriptors) {
113 nv_attr.push_back({desc.handle, desc.uuid, {}});
121 Database Database::Deserialize(const std::vector<StoredAttribute>& nv_attr,
123 // clear reallocating
125 auto it = nv_attr.cbegin();
127 for (; it != nv_attr.cend(); ++it) {
128 const auto& attr = *it;
129 if (attr.type != PRIMARY_SERVICE && attr.type != SECONDARY_SERVICE) break;
130 result.services.emplace_back(
131 Service{.handle = attr.handle,
132 .end_handle = attr.value.service.end_handle,
133 .is_primary = (attr.type == PRIMARY_SERVICE),
134 .uuid = attr.value.service.uuid});
137 auto current_service_it = result.services.begin();
138 for (; it != nv_attr.cend(); it++) {
139 const auto& attr = *it;
141 // go to the service this attribute belongs to; attributes are stored in
142 // order, so iterating just forward is enough
143 while (current_service_it != result.services.end() &&
144 current_service_it->end_handle < attr.handle) {
145 current_service_it++;
148 if (current_service_it == result.services.end() ||
149 !HandleInRange(*current_service_it, attr.handle)) {
150 LOG(ERROR) << "Can't find service for attribute with handle: "
151 << loghex(attr.handle);
156 if (attr.type == INCLUDE) {
157 Service* included_service =
158 FindService(result.services, attr.value.included_service.handle);
159 if (!included_service) {
160 LOG(ERROR) << __func__ << ": Non-existing included service!";
164 current_service_it->included_services.push_back(IncludedService{
165 .handle = attr.handle,
166 .uuid = attr.value.included_service.uuid,
167 .start_handle = attr.value.included_service.handle,
168 .end_handle = attr.value.included_service.end_handle,
170 } else if (attr.type == CHARACTERISTIC) {
171 current_service_it->characteristics.emplace_back(
172 Characteristic{.declaration_handle = attr.handle,
173 .value_handle = attr.value.characteristic.value_handle,
174 .properties = attr.value.characteristic.properties,
175 .uuid = attr.value.characteristic.uuid});
178 current_service_it->characteristics.back().descriptors.emplace_back(
179 Descriptor{.handle = attr.handle, .uuid = attr.type});