BlueToe
an alternative GATT/BLE implementation
Loading...
Searching...
No Matches
service.hpp
1#ifndef BLUETOE_SERVICE_HPP
2#define BLUETOE_SERVICE_HPP
3
4#include <bluetoe/service_uuid.hpp>
5#include <bluetoe/attribute.hpp>
6#include <bluetoe/codes.hpp>
8#include <bluetoe/meta_types.hpp>
9#include <bluetoe/uuid.hpp>
10#include <bluetoe/characteristic.hpp>
11#include <bluetoe/bits.hpp>
12#include <bluetoe/find_notification_data.hpp>
13#include <bluetoe/outgoing_priority.hpp>
14#include <cstddef>
15#include <cassert>
16#include <algorithm>
17#include <type_traits>
18
19namespace bluetoe {
20
21 template < const char* const >
22 struct service_name {
24 using meta_type = details::valid_service_option_meta_type;
26 };
27
28 namespace details {
29 struct is_secondary_service_meta_type {};
30 struct include_service_meta_type {};
31 struct service_defintion_tag {};
32
33 template < typename ... Options >
34 struct count_service_attributes;
35 }
36
47 template <
48 std::uint32_t A,
49 std::uint16_t B,
50 std::uint16_t C,
51 std::uint16_t D,
52 std::uint64_t E >
55 : public details::uuid< A, B, C, D, E >
57 {
58 public:
60 struct meta_type :
61 details::service_uuid_128_meta_type,
62 details::valid_service_option_meta_type {};
64 };
65
75 template < std::uint64_t UUID >
78 : public details::uuid16< UUID >
80 {
81 public:
83 struct meta_type :
84 details::service_uuid_16_meta_type,
85 details::valid_service_option_meta_type {};
87 };
88
94 template < std::uint16_t Handle >
96 {
97 public:
99 struct meta_type :
100 details::valid_service_option_meta_type {};
102 };
103
148 template < typename ... Options >
150 {
151 public:
153 typedef typename details::find_all_by_meta_type< details::characteristic_meta_type, Options... >::type characteristics;
154
155 typedef typename details::find_by_meta_type< details::service_uuid_meta_type, Options... >::type uuid;
156
157 static_assert( !std::is_same< uuid, details::no_such_type >::value, "Please provide a UUID to the service (service_uuid or service_uuid16 for example)." );
158
159 static constexpr std::size_t number_of_service_attributes = details::count_service_attributes< Options... >::number_of_attributes;
160 static constexpr std::size_t number_of_characteristic_attributes = details::sum_by< characteristics, details::sum_by_attributes >::value;
161 static constexpr std::size_t number_of_client_configs = details::sum_by< characteristics, details::sum_by_client_configs >::value;
162
163 using notification_priority = typename details::find_by_meta_type< details::outgoing_priority_meta_type, Options..., higher_outgoing_priority<> >::type;
164
165 static_assert( std::tuple_size< typename details::find_all_by_meta_type< details::outgoing_priority_meta_type, Options... >::type >::value <= 1,
166 "Only one of bluetoe::higher_outgoing_priority<> or bluetoe::lower_outgoing_priority<> per service allowed!" );
167
171 static constexpr std::size_t number_of_attributes =
172 number_of_service_attributes
173 + number_of_characteristic_attributes;
174
175 struct meta_type :
176 details::service_meta_type,
177 details::valid_server_option_meta_type {};
178
182 template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceList, typename Server >
183 static details::attribute attribute_at( std::size_t index );
184
188 template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceList, typename Server = void >
189 static std::uint8_t* read_primary_service_response( std::uint8_t* output, std::uint8_t* end, std::size_t starting_index, bool is_128bit_filter, Server& server );
190
191 static_assert( std::is_same<
192 typename details::find_by_not_meta_type<
193 details::valid_service_option_meta_type,
194 Options...
195 >::type, details::no_such_type
196 >::value, "Parameter passed to a service that is not a valid service option!" );
197
199 };
200
209 struct meta_type :
210 details::is_secondary_service_meta_type,
211 details::valid_service_option_meta_type {};
213 };
214
226 template < typename ... Options >
227 struct secondary_service : service< Options..., is_secondary_service > {};
228
240 template < typename UUID >
242
243 template <
244 std::uint32_t A,
245 std::uint16_t B,
246 std::uint16_t C,
247 std::uint16_t D,
248 std::uint64_t E >
249 struct include_service< service_uuid< A, B, C, D, E > >
250 {
252 struct meta_type :
253 details::include_service_meta_type,
254 details::valid_service_option_meta_type {};
256 };
257
258 template < std::uint64_t UUID >
260 {
262 struct meta_type :
263 details::include_service_meta_type,
264 details::valid_service_option_meta_type {};
266 };
267
275 // service implementation
276 namespace details {
277 template < typename ... Options >
278 using attribute_generation_parameters = typename
279 add_type<
280 service_defintion_tag, // force generation of service generation attribute
281 typename find_all_by_meta_type<
282 include_service_meta_type,
283 Options...
284 >::type
285 >::type;
286 }
287
288 template < typename ... Options >
289 template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceList, typename Server >
290 details::attribute service< Options... >::attribute_at( std::size_t index )
291 {
292 assert( index < number_of_attributes );
293
294 using attribute_generator = details::generate_attribute_list< details::attribute_generation_parameters< Options... >, CCCDIndices, ClientCharacteristicIndex, service< Options... >, Server, std::tuple< Options..., ServiceList > >;
295
296 if ( index < number_of_service_attributes )
297 return attribute_generator::attribute_at( index );
298
299 return details::attribute_at_list< characteristics, CCCDIndices, ClientCharacteristicIndex, service< Options... >, Server >::attribute_at( index - number_of_service_attributes );
300 }
301
302 template < typename ... Options >
303 template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceList, typename Server >
304 std::uint8_t* service< Options... >::read_primary_service_response( std::uint8_t* output, std::uint8_t* end, std::size_t starting_index, bool is_128bit_filter, Server& server )
305 {
306 const std::size_t attribute_data_size = is_128bit_filter ? 16 + 4 : 2 + 4;
307 using mapping = typename Server::handle_mapping;
308
309 if ( is_128bit_filter == uuid::is_128bit && static_cast< std::size_t >( end - output ) >= attribute_data_size )
310 {
311 std::uint8_t* const old_output = output;
312
313 output = details::write_handle( output, mapping::handle_by_index( starting_index ) );
314 output = details::write_handle( output, mapping::handle_by_index( starting_index + number_of_attributes -1 ) );
315
316 const details::attribute primary_service = attribute_at< CCCDIndices, ClientCharacteristicIndex, ServiceList, Server >( 0 );
317
318 auto read = details::attribute_access_arguments::read( output, end, 0,
319 details::client_characteristic_configuration(),
320 connection_security_attributes(),
321 &server );
322
323 if ( primary_service.access( read, 1 ) == details::attribute_access_result::success )
324 {
325 output += read.buffer_size;
326 }
327 else
328 {
329 output = old_output;
330 }
331 }
332
333 return output;
334 }
335
336 namespace details {
337
338 template < typename ServiceList, typename UUID >
339 struct find_service_by_uuid
340 {
341 template < class T >
342 struct equal_uuid : std::is_same< typename T::uuid, UUID > {};
343
344 typedef typename find_if< ServiceList, equal_uuid >::type type;
345 };
346
347 template < typename ServiceList, typename Service, std::uint16_t Handle = 1 >
348 struct service_handles;
349
350 template < typename Service, typename ... Ss, std::uint16_t Handle >
351 struct service_handles< std::tuple< Service, Ss... >, Service, Handle >
352 {
353 static constexpr std::uint16_t service_attribute_handle = Handle;
354 static constexpr std::uint16_t end_service_handle = Handle + Service::number_of_attributes - 1;
355 };
356
357 template < typename Service, typename S, typename ... Ss, std::uint16_t Handle >
358 struct service_handles< std::tuple< S, Ss... >, Service, Handle >
359 {
360 typedef service_handles< std::tuple< Ss... >, Service, Handle + S::number_of_attributes > next;
361
362 static constexpr std::uint16_t service_attribute_handle = next::service_attribute_handle;
363 static constexpr std::uint16_t end_service_handle = next::end_service_handle;
364 };
365
366 /*
367 * service declaration
368 */
369 template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceUUID, typename Server, typename ... Options >
370 struct generate_attribute< service_defintion_tag, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >
371 {
372 static attribute_access_result access( attribute_access_arguments& args, std::size_t )
373 {
374 typedef typename find_by_meta_type< service_uuid_meta_type, Options... >::type uuid;
375
376 if ( args.type == attribute_access_type::read )
377 {
378 if ( args.buffer_offset > sizeof( uuid::bytes ) )
379 return attribute_access_result::invalid_offset;
380
381 args.buffer_size = std::min< std::size_t >( sizeof( uuid::bytes ) - args.buffer_offset, args.buffer_size );
382
383 std::copy( std::begin( uuid::bytes ) + args.buffer_offset , std::begin( uuid::bytes ) + args.buffer_offset + args.buffer_size, args.buffer );
384
385 return attribute_access_result::success;
386 }
387 else if ( args.type == attribute_access_type::compare_value )
388 {
389 if ( sizeof( uuid::bytes ) == args.buffer_size
390 && std::equal( std::begin( uuid::bytes ), std::end( uuid::bytes ), &args.buffer[ 0 ] ) )
391 {
392 return attribute_access_result::value_equal;
393 }
394 }
395
396 return attribute_access_result::write_not_permitted;
397 }
398
399 static const attribute attr;
400 };
401
402 template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceUUID, typename Server, typename ... Options >
403 constexpr attribute generate_attribute< service_defintion_tag, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::attr {
404 bits( has_option< is_secondary_service, Options... >::value
405 ? gatt_uuids::secondary_service
406 : gatt_uuids::primary_service ),
407 &generate_attribute< service_defintion_tag, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::access
408 };
409
410 /*
411 * include attribute for 16-bit includes
412 */
413 template <
414 std::uint64_t UUID,
415 typename CCCDIndices,
416 std::size_t ClientCharacteristicIndex,
417 typename ServiceUUID,
418 typename Server,
419 typename ... Options >
420 struct generate_attribute< include_service< service_uuid16< UUID > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >
421 {
422 typedef typename last_from_pack< Options... >::type service_list;
423 typedef typename find_service_by_uuid< service_list, service_uuid16< UUID > >::type included_service;
424
425 static_assert( !std::is_same< included_service, no_such_type >::value, "The included service is was not found by UUID, please add the referenced service." );
426
427 typedef service_handles< service_list, included_service > handles;
428
429 static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )
430 {
431 static constexpr std::uint8_t value[] = {
432 handles::service_attribute_handle & 0xff,
433 handles::service_attribute_handle >> 8,
434 handles::end_service_handle & 0xff,
435 handles::end_service_handle >> 8,
436 UUID & 0xff,
437 UUID >> 8
438 };
439
440 return attribute_value_read_only_access( args, &value[ 0 ], sizeof( value ) );
441 }
442
443 static const attribute attr;
444 };
445
446 template <
447 std::uint64_t UUID,
448 typename CCCDIndices,
449 std::size_t ClientCharacteristicIndex,
450 typename ServiceUUID,
451 typename Server,
452 typename ... Options >
453 constexpr attribute generate_attribute< include_service< service_uuid16< UUID > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::attr =
454 {
455 bits( details::gatt_uuids::include ),
456 &generate_attribute< include_service< service_uuid16< UUID > >, CCCDIndices, ClientCharacteristicIndex, Options... >::access
457 };
458
459 /*
460 * include attribute for 128-bit includes
461 */
462 template <
463 std::uint32_t A,
464 std::uint16_t B,
465 std::uint16_t C,
466 std::uint16_t D,
467 std::uint64_t E,
468 typename CCCDIndices,
469 std::size_t ClientCharacteristicIndex,
470 typename ServiceUUID,
471 typename Server,
472 typename ... Options >
473 struct generate_attribute< include_service< service_uuid< A, B, C, D, E > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >
474 {
475 typedef typename last_from_pack< Options... >::type service_list;
476 typedef typename find_service_by_uuid< service_list, service_uuid< A, B, C, D, E > >::type included_service;
477
478 static_assert( !std::is_same< included_service, no_such_type >::value, "The included service is was not found by UUID, please add the references service." );
479
480 typedef service_handles< service_list, included_service > handles;
481
482 static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )
483 {
484 static constexpr std::uint8_t value[] = {
485 handles::service_attribute_handle & 0xff,
486 handles::service_attribute_handle >> 8,
487 handles::end_service_handle & 0xff,
488 handles::end_service_handle >> 8,
489 };
490
491 return attribute_value_read_only_access( args, &value[ 0 ], sizeof( value ) );
492 }
493
494 static const attribute attr;
495 };
496
497 template <
498 std::uint32_t A,
499 std::uint16_t B,
500 std::uint16_t C,
501 std::uint16_t D,
502 std::uint64_t E,
503 typename CCCDIndices,
504 std::size_t ClientCharacteristicIndex,
505 typename ServiceUUID,
506 typename Server,
507 typename ... Options >
508 constexpr attribute generate_attribute< include_service< service_uuid< A, B, C, D, E > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::attr {
509 bits( details::gatt_uuids::include ),
510 &generate_attribute< include_service< service_uuid< A, B, C, D, E > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::access
511 };
512
513 template < typename ... Options >
514 struct count_service_attributes{
515 enum {
516 number_of_attributes = std::tuple_size< attribute_generation_parameters< Options... > >::value
517 };
518 };
519
520
521 }
523}
524
525#endif
Root of the declaration of a GATT server.
Definition: server.hpp:85
a 16-Bit UUID used to identify a service
Definition: service.hpp:80
a 128-Bit UUID used to identify a service.
Definition: service.hpp:57
a service with zero or more characteristics
Definition: service.hpp:150
value of the first attribute handle used in a service or characteristic
Definition: service.hpp:96
Defines priorities of notified or indicated characteristics.
Definition: outgoing_priority.hpp:160
includes an other service into the defined service
Definition: service.hpp:241
modifier that defines a service to be a secondary service.
Definition: service.hpp:207
definition of a secondary service
Definition: service.hpp:227
Definition: service.hpp:22