BlueToe
an alternative GATT/BLE implementation
Loading...
Searching...
No Matches
attribute_handle.hpp
1#ifndef BLUETOE_ATTRIBUTE_HANDLE_HPP
2#define BLUETOE_ATTRIBUTE_HANDLE_HPP
3
4#include <bluetoe/meta_types.hpp>
6
7#include <cstdint>
8#include <cstdlib>
9#include <cassert>
10#include <algorithm>
11
12namespace bluetoe {
13
14 namespace details {
15 struct attribute_handle_meta_type {};
16 struct attribute_handles_meta_type {};
17 }
18
32 template < std::uint16_t AttributeHandleValue >
34 {
36 static constexpr std::uint16_t attribute_handle_value = AttributeHandleValue;
37
38 struct meta_type :
39 details::attribute_handle_meta_type,
40 details::valid_service_option_meta_type,
41 details::valid_characteristic_option_meta_type {};
43 };
44
56 template < std::uint16_t Declaration, std::uint16_t Value, std::uint16_t CCCD = 0x0000 >
58 {
60 static constexpr std::uint16_t declaration_handle = Declaration;
61 static constexpr std::uint16_t value_handle = Value;
62 static constexpr std::uint16_t cccd_handle = CCCD;
63
64 static_assert( value_handle > declaration_handle, "value handle has to be larger than declaration handle" );
65 static_assert( cccd_handle > declaration_handle || cccd_handle == 0, "CCCD handle has to be larger than declaration handle" );
66 static_assert( cccd_handle > value_handle || cccd_handle == 0, "CCCD handle has to be larger than value handle" );
67
68 struct meta_type :
69 details::attribute_handles_meta_type,
70 details::valid_characteristic_option_meta_type {};
72 };
73
74 template < typename ... Options >
75 class server;
76
77 template < typename ... Options >
78 class service;
79
80 template < typename ... Options >
81 class characteristic;
82
83 namespace details {
84
85 static constexpr std::uint16_t invalid_attribute_handle = 0;
86 static constexpr std::size_t invalid_attribute_index = ~0;
87
88 /*
89 * select one of attribute_handle< H > or attribute_handle< H, B, C >
90 */
91 template < std::uint16_t Default, class, class >
92 struct select_attribute_handles
93 {
94 static constexpr std::uint16_t declaration_handle = Default;
95 static constexpr std::uint16_t value_handle = Default + 1;
96 static constexpr std::uint16_t cccd_handle = Default + 2;
97 };
98
99 template < std::uint16_t Default, std::uint16_t AttributeHandleValue, typename T >
100 struct select_attribute_handles< Default, attribute_handle< AttributeHandleValue >, T >
101 {
102 static constexpr std::uint16_t declaration_handle = AttributeHandleValue;
103 static constexpr std::uint16_t value_handle = AttributeHandleValue + 1;
104 static constexpr std::uint16_t cccd_handle = AttributeHandleValue + 2;
105 };
106
107 template < std::uint16_t Default, typename T, std::uint16_t Declaration, std::uint16_t Value, std::uint16_t CCCD >
108 struct select_attribute_handles< Default, T, attribute_handles< Declaration, Value, CCCD > >
109 {
110 static constexpr std::uint16_t declaration_handle = Declaration;
111 static constexpr std::uint16_t value_handle = Value;
112 static constexpr std::uint16_t cccd_handle = CCCD == 0 ? Value + 1 : CCCD;
113 };
114
115 template < std::uint16_t Default, std::uint16_t AttributeHandleValue, std::uint16_t Declaration, std::uint16_t Value, std::uint16_t CCCD >
116 struct select_attribute_handles< Default, attribute_handle< AttributeHandleValue >, attribute_handles< Declaration, Value, CCCD > >
117 {
118 static_assert( Declaration == Value, "either attribute_handle<> or attribute_handles<> can be used as characteristic<> option, not both." );
119 };
120
121 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options >
122 struct characteristic_index_mapping
123 {
124 using characteristic_t = ::bluetoe::characteristic< Options... >;
125
126 using attribute_handles_t = select_attribute_handles< StartHandle,
127 typename find_by_meta_type< attribute_handle_meta_type, Options... >::type,
128 typename find_by_meta_type< attribute_handles_meta_type, Options... >::type
129 >;
130
131 static_assert( attribute_handles_t::declaration_handle >= StartHandle, "attribute_handle<> can only be used to create increasing attribute handles." );
132
133 static constexpr std::uint16_t end_handle = characteristic_t::number_of_attributes == 2
134 ? attribute_handles_t::value_handle + 1
135 : attribute_handles_t::cccd_handle + ( characteristic_t::number_of_attributes - 2 );
136 static constexpr std::uint16_t end_index = StartIndex + characteristic_t::number_of_attributes;
137
138 static constexpr std::size_t declaration_position = 0;
139 static constexpr std::size_t value_position = 1;
140 static constexpr std::size_t cccd_position = 2;
141
142 static std::uint16_t characteristic_attribute_handle_by_index( std::size_t index )
143 {
144 const std::size_t relative_index = index - StartIndex;
145
146 assert( relative_index < characteristic_t::number_of_attributes );
147
148 switch ( relative_index )
149 {
150 case declaration_position:
151 return attribute_handles_t::declaration_handle;
152 break;
153
154 case value_position:
155 return attribute_handles_t::value_handle;
156 break;
157
158 case cccd_position:
159 return attribute_handles_t::cccd_handle;
160 break;
161 }
162
163 return relative_index - cccd_position + attribute_handles_t::cccd_handle;
164 }
165
166 static std::size_t characteristic_attribute_index_by_handle( std::uint16_t handle )
167 {
168 if ( handle <= attribute_handles_t::declaration_handle )
169 return StartIndex + declaration_position;
170
171 if ( handle <= attribute_handles_t::value_handle )
172 return StartIndex + value_position;
173
174 if ( handle <= attribute_handles_t::cccd_handle )
175 return StartIndex + cccd_position;
176
177 return StartIndex + cccd_position + handle - attribute_handles_t::cccd_handle;
178 }
179 };
180
181 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename CharacteristicList >
182 struct interate_characteristic_index_mappings;
183
184 template < std::uint16_t StartHandle, std::uint16_t StartIndex >
185 struct interate_characteristic_index_mappings< StartHandle, StartIndex, std::tuple<> >
186 {
187 static std::uint16_t attribute_handle_by_index( std::size_t )
188 {
189 return invalid_attribute_handle;
190 }
191
192 static std::size_t attribute_index_by_handle( std::uint16_t )
193 {
194 return invalid_attribute_index;
195 }
196
197 static constexpr std::uint16_t last_characteristic_end_handle = StartHandle;
198 };
199
200 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename Characteristics, typename ... Options >
201 using next_characteristic_mapping = interate_characteristic_index_mappings<
202 characteristic_index_mapping< StartHandle, StartIndex, Options... >::end_handle,
203 characteristic_index_mapping< StartHandle, StartIndex, Options... >::end_index,
204 Characteristics
205 >;
206
207 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ...Options, typename ... Chars >
208 struct interate_characteristic_index_mappings< StartHandle, StartIndex, std::tuple< ::bluetoe::characteristic< Options... >, Chars... > >
209 : characteristic_index_mapping< StartHandle, StartIndex, Options... >
210 , next_characteristic_mapping< StartHandle, StartIndex, std::tuple< Chars... >, Options... >
211 {
212 static constexpr std::uint16_t last_characteristic_end_handle =
213 next_characteristic_mapping< StartHandle, StartIndex, std::tuple< Chars... >, Options... >::last_characteristic_end_handle;
214
215 using next = characteristic_index_mapping< StartHandle, StartIndex, Options... >;
216
217 static std::uint16_t attribute_handle_by_index( std::size_t index )
218 {
219 if ( index < next::end_index )
220 return next::characteristic_attribute_handle_by_index( index );
221
222 return next_characteristic_mapping< StartHandle, StartIndex, std::tuple< Chars... >, Options... >::attribute_handle_by_index( index );
223 }
224
225 static std::size_t attribute_index_by_handle( std::uint16_t handle )
226 {
227 if ( handle < next::end_handle )
228 return next::characteristic_attribute_index_by_handle( handle );
229
230 return next_characteristic_mapping< StartHandle, StartIndex, std::tuple< Chars... >, Options... >::attribute_index_by_handle( handle );
231 }
232 };
233
234 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options >
235 struct service_start_handle
236 {
237 using start_handle_t = typename find_by_meta_type< attribute_handle_meta_type, Options..., attribute_handle< StartHandle > >::type;
238
239 static constexpr std::uint16_t value = start_handle_t::attribute_handle_value;
240 };
241
242 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options >
243 using next_char_mapping = interate_characteristic_index_mappings<
244 service_start_handle< StartHandle, StartIndex, Options... >::value + 1, StartIndex + 1,
245 typename find_all_by_meta_type< characteristic_meta_type, Options... >::type >;
246
247 /*
248 * Map index to handle within a single service
249 */
250 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options >
251 struct service_index_mapping
252 : next_char_mapping< StartHandle, StartIndex, Options... >
253 {
254 using service_t = ::bluetoe::service< Options... >;
255
256 static constexpr std::uint16_t service_handle = service_start_handle< StartHandle, StartIndex, Options... >::value;
257
258 static_assert( service_handle >= StartHandle, "attribute_handle<> can only be used to create increasing attribute handles." );
259
260 static constexpr std::uint16_t end_handle = next_char_mapping< StartHandle, StartIndex, Options... >::last_characteristic_end_handle;
261 static constexpr std::uint16_t end_index = StartIndex + service_t::number_of_attributes;
262
263 static std::uint16_t characteristic_handle_by_index( std::size_t index )
264 {
265 if ( index == StartIndex )
266 return service_handle;
267
268 return next_char_mapping< StartHandle, StartIndex, Options... >::attribute_handle_by_index( index );
269 }
270
271 static std::size_t characteristic_first_index_by_handle( std::uint16_t handle )
272 {
273 if ( handle <= service_handle )
274 return StartIndex;
275
276 return next_char_mapping< StartHandle, StartIndex, Options... >::attribute_index_by_handle( handle );
277 }
278 };
279
280 /*
281 * Iterate over all services in a server
282 */
283 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename OptionTuple >
284 struct interate_service_index_mappings;
285
286 template < std::uint16_t StartHandle, std::uint16_t StartIndex >
287 struct interate_service_index_mappings< StartHandle, StartIndex, std::tuple<> >
288 {
289 static std::uint16_t service_handle_by_index( std::size_t )
290 {
291 return invalid_attribute_handle;
292 }
293
294 static std::size_t service_first_index_by_handle( std::uint16_t )
295 {
296 return invalid_attribute_index;
297 }
298 };
299
300 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename Services, typename ... Options >
301 using next_service_mapping = interate_service_index_mappings<
302 service_index_mapping< StartHandle, StartIndex, Options... >::end_handle,
303 service_index_mapping< StartHandle, StartIndex, Options... >::end_index,
304 Services
305 >;
306
307 template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options, typename ... Services >
308 struct interate_service_index_mappings< StartHandle, StartIndex, std::tuple< ::bluetoe::service< Options... >, Services... > >
309 : service_index_mapping< StartHandle, StartIndex, Options... >
310 , next_service_mapping< StartHandle, StartIndex, std::tuple< Services... >, Options... >
311 {
312 static std::uint16_t service_handle_by_index( std::size_t index )
313 {
314 if ( index < service_index_mapping< StartHandle, StartIndex, Options... >::end_index )
315 return service_index_mapping< StartHandle, StartIndex, Options... >::characteristic_handle_by_index( index );
316
317 return next_service_mapping< StartHandle, StartIndex, std::tuple< Services... >, Options... >::service_handle_by_index( index );
318 }
319
320 static std::size_t service_first_index_by_handle( std::uint16_t handle )
321 {
322 if ( handle < service_index_mapping< StartHandle, StartIndex, Options... >::end_handle )
323 return service_index_mapping< StartHandle, StartIndex, Options... >::characteristic_first_index_by_handle( handle );
324
325 return next_service_mapping< StartHandle, StartIndex, std::tuple< Services... >, Options... >::service_first_index_by_handle( handle );
326 }
327 };
328
329 /*
330 * Interface, providing function to map from 0-based attribute index to ATT attribute handle and vice versa
331 *
332 * An attribute index is a 0-based into an array of all attributes contained in a server. Accessing the
333 * attribute by table is very fast. If neither attribute_handle<> or attribute_handles<> is used, the mapping
334 * is trivial and an index I is mapped to a handle I + 1.
335 */
336 template < typename Server >
337 struct handle_index_mapping;
338
339 template < typename ... Options >
340 struct handle_index_mapping< ::bluetoe::server< Options... > >
341 : private interate_service_index_mappings< 1u, 0u, typename ::bluetoe::server< Options... >::services >
342 {
343 static constexpr std::size_t invalid_attribute_index = ::bluetoe::details::invalid_attribute_index;
344 static constexpr std::uint16_t invalid_attribute_handle = ::bluetoe::details::invalid_attribute_handle;
345
346 using iterator = interate_service_index_mappings< 1u, 0u, typename ::bluetoe::server< Options... >::services >;
347
348 static std::uint16_t handle_by_index( std::size_t index )
349 {
350 return iterator::service_handle_by_index( index );
351 }
352
359 static std::size_t first_index_by_handle( std::uint16_t handle )
360 {
361 return iterator::service_first_index_by_handle( handle );
362 }
363
364 static std::size_t index_by_handle( std::uint16_t handle )
365 {
366 std::size_t result = first_index_by_handle( handle );
367 if ( result != invalid_attribute_index && handle_by_index( result ) != handle )
368 result = invalid_attribute_index;
369
370 return result;
371 }
372 };
373
374 }
375}
376
377#endif
378
A characteristic is a typed value that is accessable by a GATT client hosted by a GATT server.
Definition: characteristic.hpp:160
Root of the declaration of a GATT server.
Definition: server.hpp:85
a service with zero or more characteristics
Definition: service.hpp:150
define the first attribute handle used by a characteristic or service
Definition: attribute_handle.hpp:34
define the attributes handles for the characteristic declaration, characteristic value and optional,...
Definition: attribute_handle.hpp:58