1#ifndef BLUETOE_SERVICE_HPP
2#define BLUETOE_SERVICE_HPP
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>
21 template < const
char* const >
24 using meta_type = details::valid_service_option_meta_type;
29 struct is_secondary_service_meta_type {};
30 struct include_service_meta_type {};
31 struct service_defintion_tag {};
33 template <
typename ... Options >
34 struct count_service_attributes;
55 :
public details::uuid< A, B, C, D, E >
61 details::service_uuid_128_meta_type,
62 details::valid_service_option_meta_type {};
75 template < std::u
int64_t UUID >
78 :
public details::uuid16< UUID >
84 details::service_uuid_16_meta_type,
85 details::valid_service_option_meta_type {};
94 template < std::u
int16_t Handle >
100 details::valid_service_option_meta_type {};
148 template <
typename ... Options >
153 typedef typename details::find_all_by_meta_type< details::characteristic_meta_type, Options... >::type characteristics;
155 typedef typename details::find_by_meta_type< details::service_uuid_meta_type, Options... >::type uuid;
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)." );
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;
163 using notification_priority =
typename details::find_by_meta_type< details::outgoing_priority_meta_type, Options...,
higher_outgoing_priority<> >::type;
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!" );
171 static constexpr std::size_t number_of_attributes =
172 number_of_service_attributes
173 + number_of_characteristic_attributes;
176 details::service_meta_type,
177 details::valid_server_option_meta_type {};
182 template <
typename CCCDIndices, std::
size_t ClientCharacteristicIndex,
typename ServiceList,
typename Server >
183 static details::attribute attribute_at( std::size_t index );
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 );
191 static_assert( std::is_same<
192 typename details::find_by_not_meta_type<
193 details::valid_service_option_meta_type,
195 >::type, details::no_such_type
196 >::value,
"Parameter passed to a service that is not a valid service option!" );
210 details::is_secondary_service_meta_type,
211 details::valid_service_option_meta_type {};
226 template <
typename ... Options >
240 template <
typename UUID >
253 details::include_service_meta_type,
254 details::valid_service_option_meta_type {};
258 template < std::u
int64_t UUID >
263 details::include_service_meta_type,
264 details::valid_service_option_meta_type {};
277 template <
typename ... Options >
278 using attribute_generation_parameters =
typename
280 service_defintion_tag,
281 typename find_all_by_meta_type<
282 include_service_meta_type,
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 )
292 assert( index < number_of_attributes );
294 using attribute_generator = details::generate_attribute_list< details::attribute_generation_parameters< Options... >, CCCDIndices, ClientCharacteristicIndex, service< Options... >, Server, std::tuple< Options..., ServiceList > >;
296 if ( index < number_of_service_attributes )
297 return attribute_generator::attribute_at( index );
299 return details::attribute_at_list< characteristics, CCCDIndices, ClientCharacteristicIndex, service< Options... >, Server >::attribute_at( index - number_of_service_attributes );
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 )
306 const std::size_t attribute_data_size = is_128bit_filter ? 16 + 4 : 2 + 4;
307 using mapping =
typename Server::handle_mapping;
309 if ( is_128bit_filter == uuid::is_128bit &&
static_cast< std::size_t
>( end - output ) >= attribute_data_size )
311 std::uint8_t*
const old_output = output;
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 ) );
316 const details::attribute primary_service = attribute_at< CCCDIndices, ClientCharacteristicIndex, ServiceList, Server >( 0 );
318 auto read = details::attribute_access_arguments::read( output, end, 0,
319 details::client_characteristic_configuration(),
320 connection_security_attributes(),
323 if ( primary_service.access( read, 1 ) == details::attribute_access_result::success )
325 output += read.buffer_size;
338 template <
typename ServiceList,
typename UUID >
339 struct find_service_by_uuid
342 struct equal_uuid : std::is_same< typename T::uuid, UUID > {};
344 typedef typename find_if< ServiceList, equal_uuid >::type type;
347 template <
typename ServiceList,
typename Service, std::u
int16_t Handle = 1 >
348 struct service_handles;
350 template <
typename Service,
typename ... Ss, std::uint16_t Handle >
351 struct service_handles< std::tuple< Service, Ss... >, Service, Handle >
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;
357 template <
typename Service,
typename S,
typename ... Ss, std::uint16_t Handle >
358 struct service_handles< std::tuple< S, Ss... >, Service, Handle >
360 typedef service_handles< std::tuple< Ss... >, Service, Handle + S::number_of_attributes > next;
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;
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... >
372 static attribute_access_result access( attribute_access_arguments& args, std::size_t )
374 typedef typename find_by_meta_type< service_uuid_meta_type, Options... >::type uuid;
376 if ( args.type == attribute_access_type::read )
378 if ( args.buffer_offset >
sizeof( uuid::bytes ) )
379 return attribute_access_result::invalid_offset;
381 args.buffer_size = std::min< std::size_t >(
sizeof( uuid::bytes ) - args.buffer_offset, args.buffer_size );
383 std::copy( std::begin( uuid::bytes ) + args.buffer_offset , std::begin( uuid::bytes ) + args.buffer_offset + args.buffer_size, args.buffer );
385 return attribute_access_result::success;
387 else if ( args.type == attribute_access_type::compare_value )
389 if (
sizeof( uuid::bytes ) == args.buffer_size
390 && std::equal( std::begin( uuid::bytes ), std::end( uuid::bytes ), &args.buffer[ 0 ] ) )
392 return attribute_access_result::value_equal;
396 return attribute_access_result::write_not_permitted;
399 static const attribute attr;
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
415 typename CCCDIndices,
416 std::size_t ClientCharacteristicIndex,
417 typename ServiceUUID,
419 typename ... Options >
420 struct generate_attribute< include_service< service_uuid16< UUID > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >
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;
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." );
427 typedef service_handles< service_list, included_service > handles;
429 static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )
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,
440 return attribute_value_read_only_access( args, &value[ 0 ],
sizeof( value ) );
443 static const attribute attr;
448 typename CCCDIndices,
449 std::size_t ClientCharacteristicIndex,
450 typename ServiceUUID,
452 typename ... Options >
453 constexpr attribute generate_attribute< include_service< service_uuid16< UUID > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::attr =
455 bits( details::gatt_uuids::include ),
456 &generate_attribute< include_service< service_uuid16< UUID > >, CCCDIndices, ClientCharacteristicIndex, Options... >::access
468 typename CCCDIndices,
469 std::size_t ClientCharacteristicIndex,
470 typename ServiceUUID,
472 typename ... Options >
473 struct generate_attribute< include_service< service_uuid< A, B, C, D, E > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >
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;
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." );
480 typedef service_handles< service_list, included_service > handles;
482 static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )
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,
491 return attribute_value_read_only_access( args, &value[ 0 ],
sizeof( value ) );
494 static const attribute attr;
503 typename CCCDIndices,
504 std::size_t ClientCharacteristicIndex,
505 typename ServiceUUID,
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
513 template <
typename ... Options >
514 struct count_service_attributes{
516 number_of_attributes = std::tuple_size< attribute_generation_parameters< Options... > >::value
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