1#ifndef BLUETOE_SERVER_HPP 
    2#define BLUETOE_SERVER_HPP 
    4#include <bluetoe/codes.hpp> 
    5#include <bluetoe/service.hpp> 
    6#include <bluetoe/bits.hpp> 
    7#include <bluetoe/filter.hpp> 
    8#include <bluetoe/gatt_options.hpp> 
    9#include <bluetoe/server_name.hpp> 
   10#include <bluetoe/adv_service_list.hpp> 
   11#include <bluetoe/peripheral_connection_interval_range.hpp> 
   12#include <bluetoe/server_meta_type.hpp> 
   13#include <bluetoe/client_characteristic_configuration.hpp> 
   14#include <bluetoe/write_queue.hpp> 
   15#include <bluetoe/gap_service.hpp> 
   16#include <bluetoe/appearance.hpp> 
   17#include <bluetoe/mixin.hpp> 
   18#include <bluetoe/find_notification_data.hpp> 
   19#include <bluetoe/outgoing_priority.hpp> 
   20#include <bluetoe/link_state.hpp> 
   21#include <bluetoe/attribute_handle.hpp> 
   22#include <bluetoe/l2cap_channels.hpp> 
   23#include <bluetoe/notification_queue.hpp> 
   24#include <bluetoe/custom_advertising.hpp> 
   35        template < 
typename ... Options >
 
   36        using selected_advertising_data_source =
 
   37            typename details::find_by_meta_type<
 
   38                        details::advertising_data_meta_type,
 
   43        template < 
typename ... Options >
 
   44        using selected_scan_response_data_source =
 
   45            typename details::find_by_meta_type<
 
   46                        details::scan_response_data_meta_type,
 
   48                        auto_scan_response_data
 
   79    template < 
typename ... Options >
 
   81        : 
private details::write_queue< typename details::find_by_meta_type< details::write_queue_meta_type, Options... >::type >
 
   82        , 
public details::derive_from< typename details::collect_mixins< Options... >::type >
 
   83        , 
public details::selected_advertising_data_source< Options ... >
 
   84        , 
public details::selected_scan_response_data_source< Options ... >
 
   88        using services_without_gap = 
typename details::find_all_by_meta_type< details::service_meta_type, Options... >::type;
 
   89        using selected_advertising_data_t = details::selected_advertising_data_source< Options ... >;
 
   90        using selected_scan_response_data_t = details::selected_scan_response_data_source< Options ... >;
 
   93        using gap_service_definition = 
typename details::find_by_meta_type< details::gap_service_definition_meta_type,
 
   95        using services = 
typename gap_service_definition::template add_service< services_without_gap, Options... >::type;
 
   97        static constexpr std::size_t number_of_client_configs = details::sum_by< services, details::sum_by_client_configs >::value;
 
   99        using write_queue_type = 
typename details::find_by_meta_type< details::write_queue_meta_type, Options... >::type;
 
  101        using notification_priority = 
typename details::find_by_meta_type< details::outgoing_priority_meta_type, Options..., 
higher_outgoing_priority<> >::type;
 
  103        static_assert( std::tuple_size< 
typename details::find_all_by_meta_type< details::outgoing_priority_meta_type, Options... >::type >::value <= 1,
 
  104            "Only one of bluetoe::higher_outgoing_priority<> or bluetoe::lower_outgoing_priority<> per server allowed!" );
 
  106        using cccd_indices = 
typename details::find_notification_data_in_list< notification_priority, services >::cccd_indices;
 
  108        using server_t       = 
server< Options... >;
 
  109        using handle_mapping = details::handle_index_mapping< server_t >;
 
  121            : 
public details::client_characteristic_configurations< number_of_client_configs >
 
  125                : client_mtu_( details::default_att_mtu_size )
 
  146                assert( mtu >= details::default_att_mtu_size );
 
  166                return maximum_channel_mtu_size;
 
  171            std::uint16_t               client_mtu_;
 
  249        template < 
class CharacteristicUUID >
 
  273        template < 
class CharacteristicUUID >
 
  279        template < 
class CharacteristicUUID >
 
  285        template < 
class CharacteristicUUID >
 
  291        template < 
class CharacteristicUUID >
 
  299        template < 
typename ConnectionData >
 
  300        void l2cap_input( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );
 
  302        template < 
typename ConnectionData >
 
  303        void l2cap_output( std::uint8_t*, std::size_t& out_size, ConnectionData& );
 
  308        std::size_t advertising_data( std::uint8_t* buffer, std::size_t buffer_size ) 
const;
 
  314        std::size_t scan_response_data( std::uint8_t* buffer, std::size_t buffer_size ) 
const;
 
  319        bool advertising_or_scan_response_data_has_been_changed();
 
  321        typedef bool (*lcap_notification_callback_t)( 
const details::notification_data& item, 
void* usr_arg, details::notification_type type );
 
  330        void notification_callback( lcap_notification_callback_t, 
void* usr_arg );
 
  335        template < 
typename Connection >
 
  336        void client_disconnected( Connection& );
 
  338        typedef details::server_meta_type meta_type;
 
  340        static details::attribute attribute_at( std::size_t index );
 
  342        static constexpr std::uint16_t channel_id               = l2cap_channel_ids::att;
 
  343        static constexpr std::size_t   minimum_channel_mtu_size = bluetoe::details::default_att_mtu_size;
 
  344        static constexpr std::size_t   maximum_channel_mtu_size = bluetoe::details::find_by_meta_type<
 
  345                details::mtu_size_meta_type,
 
  350        template < 
class PreviousData = details::no_such_type >
 
  353                typename notification_priority::template numbers< services >::type,
 
  359        void notification_subscription_changed( 
const details::client_characteristic_configuration& );
 
  363        static constexpr std::size_t number_of_attributes       = details::sum_by< services, details::sum_by_attributes >::value;
 
  365        static_assert( std::tuple_size< services >::value > 0, 
"A server should at least contain one service." );
 
  367        void error_response( std::uint8_t opcode, details::att_error_codes error_code, std::uint16_t handle, std::uint8_t* output, std::size_t& out_size );
 
  368        void error_response( std::uint8_t opcode, details::att_error_codes error_code, std::uint8_t* output, std::size_t& out_size );
 
  370        static details::att_error_codes access_result_to_att_code( details::attribute_access_result, details::att_error_codes default_att_code );
 
  377        template < std::
size_t A, std::
size_t B = A >
 
  378        bool check_size_and_handle_range( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& starting_handle, std::uint16_t& ending_handle );
 
  380        template < std::
size_t A, std::
size_t B = A >
 
  381        bool check_size_and_handle( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& handle, std::size_t& index );
 
  382        bool check_handle( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& handle, std::size_t& index );
 
  384        template < 
typename ConnectionData >
 
  385        void handle_exchange_mtu_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );
 
  386        void handle_find_information_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size );
 
  387        void handle_find_by_type_value_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size );
 
  388        template < 
typename ConnectionData >
 
  389        void handle_read_by_type_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );
 
  390        template < 
typename ConnectionData >
 
  391        void handle_read_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );
 
  392        template < 
typename ConnectionData >
 
  393        void handle_read_blob_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );
 
  394        void handle_read_by_group_type_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size );
 
  395        template < 
typename ConnectionData >
 
  396        void handle_read_multiple_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );
 
  397        template < 
typename ConnectionData >
 
  398        void handle_write_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );
 
  399        template < 
typename ConnectionData >
 
  400        void handle_write_command( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );
 
  402        template < 
typename Connection >
 
  403        void handle_prepair_write_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection&, 
const details::no_such_type& );
 
  404        template < 
typename Connection, 
typename WriteQueue >
 
  405        void handle_prepair_write_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection&, 
const WriteQueue& );
 
  406        template < 
typename Connection >
 
  407        void handle_execute_write_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection&, 
const details::no_such_type& );
 
  408        template < 
typename Connection, 
typename WriteQueue >
 
  409        void handle_execute_write_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection&, 
const WriteQueue& );
 
  410        void handle_value_confirmation( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, connection_data& );
 
  412        template < 
class Iterator, 
class Filter = details::all_uu
id_filter >
 
  413        void all_attributes( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator&, 
const Filter& filter = details::all_uuid_filter() );
 
  415        template < 
class Iterator, 
class Filter = details::all_uu
id_filter >
 
  416        bool all_services_by_group( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator&, 
const Filter& filter = details::all_uuid_filter() );
 
  418        std::uint8_t* collect_handle_uuid_tuples( std::size_t start, std::size_t end, 
bool only_16_bit, std::uint8_t* output, std::uint8_t* output_end );
 
  420        static void write_128bit_uuid( std::uint8_t* out, 
const details::attribute& char_declaration );
 
  423        std::size_t last_handle_index( std::uint16_t ending_handle );
 
  425        std::size_t advertising_data_impl( std::uint8_t* buffer, std::size_t buffer_size, 
const auto_advertising_data& ) 
const;
 
  428        std::size_t advertising_data_impl( std::uint8_t* buffer, std::size_t buffer_size, 
const T& ) 
const;
 
  430        std::size_t scan_response_data_impl( std::uint8_t* buffer, std::size_t buffer_size, 
const auto_scan_response_data& ) 
const;
 
  433        std::size_t scan_response_data_impl( std::uint8_t* buffer, std::size_t buffer_size, 
const T& ) 
const;
 
  436        lcap_notification_callback_t l2cap_cb_;
 
  441                typename details::find_by_not_meta_type<
 
  442                    details::valid_server_option_meta_type,
 
  444                >::type, details::no_such_type
 
  445            >::value, 
"Option passed to a server that is not a valid server option." );
 
  449        details::notification_data find_notification_data( 
const void* ) 
const;
 
  450        details::notification_data find_notification_data_by_index( std::size_t client_characteristic_configuration_index ) 
const;
 
  479    template < 
typename Server, 
typename ... Options >
 
  482    template < 
typename ... ServerOptions, 
typename ... Options >
 
  491    template < 
typename ... Options >
 
  493        : l2cap_cb_( nullptr )
 
  498    template < 
typename ... Options >
 
  499    template < 
typename ConnectionData >
 
  500    void server< Options... >::l2cap_input( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )
 
  503        out_size = std::min< std::size_t >( out_size, connection.negotiated_mtu() );
 
  505        assert( in_size != 0 );
 
  506        assert( out_size >= details::default_att_mtu_size );
 
  508        const details::att_opcodes opcode = 
static_cast< details::att_opcodes 
>( input[ 0 ] );
 
  513        case details::att_opcodes::error_response:
 
  517        case details::att_opcodes::exchange_mtu_request:
 
  518            handle_exchange_mtu_request( input, in_size, output, out_size, connection );
 
  520        case details::att_opcodes::find_information_request:
 
  521            handle_find_information_request( input, in_size, output, out_size );
 
  523        case details::att_opcodes::find_by_type_value_request:
 
  524            handle_find_by_type_value_request( input, in_size, output, out_size );
 
  526        case details::att_opcodes::read_by_type_request:
 
  527            handle_read_by_type_request( input, in_size, output, out_size, connection );
 
  529        case details::att_opcodes::read_request:
 
  530            handle_read_request( input, in_size, output, out_size, connection );
 
  532        case details::att_opcodes::read_blob_request:
 
  533            handle_read_blob_request( input, in_size, output, out_size, connection );
 
  535        case details::att_opcodes::read_by_group_type_request:
 
  536            handle_read_by_group_type_request( input, in_size, output, out_size );
 
  538        case details::att_opcodes::read_multiple_request:
 
  539            handle_read_multiple_request( input, in_size, output, out_size, connection );
 
  541        case details::att_opcodes::write_request:
 
  542            handle_write_request( input, in_size, output, out_size, connection );
 
  544        case details::att_opcodes::write_command:
 
  545            handle_write_command( input, in_size, output, out_size, connection );
 
  547        case details::att_opcodes::prepare_write_request:
 
  548            handle_prepair_write_request( input, in_size, output, out_size, connection, write_queue_type() );
 
  550        case details::att_opcodes::execute_write_request:
 
  551            handle_execute_write_request( input, in_size, output, out_size, connection, write_queue_type() );
 
  553        case details::att_opcodes::confirmation:
 
  554            handle_value_confirmation( input, in_size, output, out_size, connection );
 
  557            error_response( *input, details::att_error_codes::request_not_supported, output, out_size );
 
  562    template < 
typename ... Options >
 
  563    template < 
typename ConnectionData >
 
  564    void server< Options... >::l2cap_output( std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )
 
  566        const auto pending = connection.dequeue_indication_or_confirmation();
 
  568        if ( pending.first != details::notification_queue_entry_type::empty )
 
  570            const std::uint16_t required_flag = pending.first == details::notification_queue_entry_type::notification
 
  571                ? details::client_characteristic_configuration_notification_enabled
 
  572                : details::client_characteristic_configuration_indication_enabled;
 
  574            const auto data = find_notification_data_by_index( pending.second );
 
  576            if ( connection.client_configurations().flags( data.client_characteristic_configuration_index() ) & required_flag &&
 
  579                auto read = details::attribute_access_arguments::read( output + 3, output + out_size, 0, connection.client_configurations(), connection.security_attributes(), 
this );
 
  580                auto attr = attribute_at( data.attribute_table_index() );
 
  581                auto rc   = attr.access( read, data.attribute_table_index() );
 
  583                if ( rc == details::attribute_access_result::success )
 
  585                    *output = pending.first == details::notification_queue_entry_type::notification
 
  586                        ? bits( details::att_opcodes::notification )
 
  587                        : bits( details::att_opcodes::indication );
 
  588                    details::write_handle( output +1, handle_mapping::handle_by_index( data.attribute_table_index() ) );
 
  590                    out_size = 3 + read.buffer_size;
 
  604            static std::uint8_t* impl( std::uint8_t* begin, std::uint8_t* end, 
const char* 
const name )
 
  606                if ( ( end - begin ) <= 2 )
 
  609                const std::size_t name_length  = std::strlen( name );
 
  610                const std::size_t max_name_len = std::min< std::size_t >( name_length, end - begin - 2 );
 
  612                if ( name_length > 0 )
 
  614                    begin[ 0 ] = max_name_len + 1;
 
  615                    begin[ 1 ] = max_name_len == name_length
 
  616                        ? bits( details::gap_types::complete_local_name )
 
  617                        : bits( details::gap_types::shortened_local_name );
 
  619                    std::copy( name + 0, name + max_name_len, &begin[ 2 ] );
 
  620                    begin += max_name_len + 2;
 
  628        struct copy_name< false >
 
  630            static std::uint8_t* impl( std::uint8_t* begin, std::uint8_t*, 
const char* 
const )
 
  638    template < 
typename ... Options >
 
  639    std::size_t server< Options... >::advertising_data( std::uint8_t* begin, std::size_t buffer_size )
 const 
  641        return advertising_data_impl( begin, buffer_size, selected_advertising_data_t() );
 
  644    template < 
typename ... Options >
 
  645    template < 
class Advertiser >
 
  646    std::size_t server< Options... >::advertising_data_impl( std::uint8_t* begin, std::size_t buffer_size, 
const Advertiser& )
 const 
  648        return static_cast< const Advertiser& 
>( *this ).advertising_data( begin, buffer_size );
 
  651    template < 
typename ... Options >
 
  652    std::size_t server< Options... >::advertising_data_impl( std::uint8_t* begin, std::size_t buffer_size, 
const auto_advertising_data& )
 const 
  654        std::uint8_t* 
const end = begin + buffer_size;
 
  656        if ( buffer_size >= 3 )
 
  659            begin[ 1 ] = bits( details::gap_types::flags );
 
  666        using device_appearance = 
typename details::find_by_meta_type<
 
  667                details::device_appearance_meta_type,
 
  672        using appearance_advertising_config = 
typename details::find_by_meta_type<
 
  673            details::advertise_appearance_meta_type,
 
  675            no_advertise_appearance >::type;
 
  677        begin = appearance_advertising_config::template advertising_data< device_appearance >( begin, end );
 
  679        typedef typename details::find_by_meta_type< details::server_name_meta_type, Options..., server_name< nullptr > >::type name;
 
  681        begin = details::copy_name< name::name != nullptr >::impl( begin, end, name::name );
 
  683        typedef typename details::find_by_meta_type<
 
  684            details::list_of_16_bit_service_uuids_tag,
 
  686            details::default_list_of_16_bit_service_uuids< services >
 
  687        >::type service_list_uuid16;
 
  689        begin = service_list_uuid16::advertising_data( begin, end );
 
  691        typedef typename details::find_by_meta_type<
 
  692            details::list_of_128_bit_service_uuids_tag,
 
  694            details::default_list_of_128_bit_service_uuids< services >
 
  695        >::type service_list_uuid128;
 
  697        begin = service_list_uuid128::advertising_data( begin, end );
 
  699        typedef typename details::find_by_meta_type<
 
  700            details::peripheral_connection_interval_range_meta_type,
 
  702            details::no_peripheral_connection_interval_range
 
  703        >::type peripheral_connection_interval_range_ad;
 
  705        begin = peripheral_connection_interval_range_ad::advertising_data( begin, end );
 
  708        if ( 
static_cast< unsigned >( end - begin ) >= 2u )
 
  716        return buffer_size - ( end - begin );
 
  719    template < 
typename ... Options >
 
  720    std::size_t server< Options... >::scan_response_data( std::uint8_t* buffer, std::size_t buffer_size )
 const 
  722        return scan_response_data_impl( buffer, buffer_size, selected_scan_response_data_t() );
 
  725    template < 
typename ... Options >
 
  726    std::size_t server< Options... >::scan_response_data_impl( std::uint8_t* buffer, std::size_t , 
const auto_scan_response_data& )
 const 
  736    template < 
typename ... Options >
 
  738    std::size_t server< Options... >::scan_response_data_impl( std::uint8_t* buffer, std::size_t buffer_size, 
const T& )
 const 
  740        return static_cast< const T& 
>( *this ).scan_response_data( buffer, buffer_size );
 
  743    template < 
typename ... Options >
 
  744    bool server< Options... >::advertising_or_scan_response_data_has_been_changed()
 
  746        const bool advertising_changed   = this->advertising_data_dirty();
 
  747        const bool scan_response_changed = this->scan_response_data_dirty();
 
  749        return advertising_changed || scan_response_changed;
 
  752    template < 
typename ... Options >
 
  756        static_assert( number_of_client_configs != 0, 
"there is no characteristic that is configured for notification or indication" );
 
  758        const details::notification_data data = find_notification_data( &value );
 
  759        assert( data.valid() );
 
  762            return l2cap_cb_( data, l2cap_arg_, details::notification_type::notification );
 
  767    template < 
typename ... Options >
 
  768    template < 
class CharacteristicUUID >
 
  771        static_assert( number_of_client_configs != 0, 
"there is no characteristic that is configured for notification or indication" );
 
  773        using characteristic = 
typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;
 
  775        static_assert( !std::is_same< characteristic, details::no_such_type >::value, 
"Notified characteristic not found by UUID." );
 
  776        static_assert( characteristic::has_notification, 
"Characteristic must be configured for notification!" );
 
  778        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();
 
  781            return l2cap_cb_( data, l2cap_arg_, details::notification_type::notification );
 
  786    template < 
typename ... Options >
 
  790        static_assert( number_of_client_configs != 0, 
"there is no characteristic that is configured for notification or indication" );
 
  792        const details::notification_data data = find_notification_data( &value );
 
  793        assert( data.valid() );
 
  796            return l2cap_cb_( data, l2cap_arg_, details::notification_type::indication );
 
  801    template < 
typename ... Options >
 
  802    template < 
class CharacteristicUUID >
 
  805        static_assert( number_of_client_configs != 0, 
"there is no characteristic that is configured for notification or indication" );
 
  807        using characteristic = 
typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;
 
  809        static_assert( !std::is_same< characteristic, details::no_such_type >::value, 
"Indicated characteristic not found by UUID." );
 
  810        static_assert( characteristic::has_indication, 
"Characteristic must be configured for indication!" );
 
  812        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();
 
  815            return l2cap_cb_( data, l2cap_arg_, details::notification_type::indication );
 
  820    template < 
typename ... Options >
 
  821    template < 
class CharacteristicUUID >
 
  824        using characteristic = 
typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;
 
  825        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();
 
  827        return connection.flags( data.client_characteristic_configuration_index() ) & details::client_characteristic_configuration_indication_enabled;
 
  830    template < 
typename ... Options >
 
  831    template < 
class CharacteristicUUID >
 
  834        using characteristic = 
typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;
 
  835        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();
 
  837        return connection.flags( data.client_characteristic_configuration_index() ) & details::client_characteristic_configuration_notification_enabled;
 
  840    template < 
typename ... Options >
 
  841    template < 
class CharacteristicUUID >
 
  844        using characteristic = 
typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;
 
  845        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();
 
  847        static const auto both = ( details::client_characteristic_configuration_notification_enabled | details::client_characteristic_configuration_indication_enabled );
 
  849        return connection.flags( data.client_characteristic_configuration_index() ) & both;
 
  852    template < 
typename ... Options >
 
  853    void server< Options... >::notification_callback( lcap_notification_callback_t cb, 
void* usr_arg )
 
  856        l2cap_arg_ = usr_arg;
 
  859    template < 
typename ... Options >
 
  860    template < 
typename Connection >
 
  861    void server< Options... >::client_disconnected( Connection& client )
 
  863        this->free_write_queue( client );
 
  866    template < 
typename ... Options >
 
  867    details::attribute server< Options... >::attribute_at( std::size_t index )
 
  869        return details::attribute_from_service_list< services, server< Options... >, cccd_indices >::attribute_at( index );
 
  872    template < 
typename ... Options >
 
  873    void server< Options... >::error_response( std::uint8_t opcode, details::att_error_codes error_code, std::uint16_t handle, std::uint8_t* output, std::size_t& out_size )
 
  877            output[ 0 ] = bits( details::att_opcodes::error_response );
 
  878            output[ 1 ] = opcode;
 
  879            output[ 2 ] = handle & 0xff;
 
  880            output[ 3 ] = handle >> 8;
 
  881            output[ 4 ] = bits( error_code );
 
  890    template < 
typename ... Options >
 
  891    void server< Options... >::error_response( std::uint8_t opcode, details::att_error_codes error_code, std::uint8_t* output, std::size_t& out_size )
 
  893        error_response( opcode, error_code, 0, output, out_size );
 
  897    template < 
typename ... Options >
 
  898    details::att_error_codes server< Options... >::access_result_to_att_code( details::attribute_access_result access_code, details::att_error_codes default_att_code )
 
  901        const details::att_error_codes result = 
static_cast< details::att_error_codes 
>( access_code );
 
  903        return static_cast< details::attribute_access_result 
>( result ) == access_code
 
  908    template < 
typename ... Options >
 
  909    template < std::
size_t A, std::
size_t B >
 
  910    bool server< Options... >::check_size_and_handle_range(
 
  911        const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& starting_handle, std::uint16_t& ending_handle )
 
  913        if ( in_size != A && in_size != B )
 
  915            error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );
 
  919        starting_handle = details::read_handle( &input[ 1 ] );
 
  920        ending_handle   = details::read_handle( &input[ 3 ] );
 
  922        if ( starting_handle == 0 || starting_handle > ending_handle )
 
  924            error_response( *input, details::att_error_codes::invalid_handle, starting_handle, output, out_size );
 
  928        if ( handle_mapping::first_index_by_handle( starting_handle ) == details::invalid_attribute_index )
 
  930            error_response( *input, details::att_error_codes::attribute_not_found, starting_handle, output, out_size );
 
  937    template < 
typename ... Options >
 
  938    template < std::
size_t A, std::
size_t B >
 
  939    bool server< Options... >::check_size_and_handle( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& handle, std::size_t& index )
 
  941        if ( in_size != A && in_size != B )
 
  943            error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );
 
  947        return check_handle( input, in_size, output, out_size, handle, index );
 
  950    template < 
typename ... Options >
 
  951    bool server< Options... >::check_handle( 
const std::uint8_t* input, std::size_t, std::uint8_t* output, std::size_t& out_size, std::uint16_t& handle, std::size_t& index )
 
  953        handle = details::read_handle( &input[ 1 ] );
 
  957            error_response( *input, details::att_error_codes::invalid_handle, handle, output, out_size );
 
  961        index = handle_mapping::index_by_handle( handle );
 
  963        if ( index == details::invalid_attribute_index )
 
  965            error_response( *input, details::att_error_codes::invalid_handle, handle, output, out_size );
 
  972    template < 
typename ... Options >
 
  973    template < 
typename ConnectionData >
 
  974    void server< Options... >::handle_exchange_mtu_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )
 
  977            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );
 
  979        const std::uint16_t mtu = details::read_16bit( input + 1 );
 
  981        if ( mtu < details::default_att_mtu_size )
 
  982            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );
 
  984        connection.client_mtu( mtu );
 
  986        *output = bits( details::att_opcodes::exchange_mtu_response );
 
  987        details::write_16bit( output + 1, connection.server_mtu() );
 
  992    template < 
typename ... Options >
 
  993    void server< Options... >::handle_find_information_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size )
 
  995        std::uint16_t starting_handle, ending_handle;
 
  997        if ( !check_size_and_handle_range< 5u >( input, in_size, output, out_size, starting_handle, ending_handle ) )
 
 1000        const std::size_t start_index = handle_mapping::first_index_by_handle( starting_handle );
 
 1001        const bool only_16_bit_uuids = attribute_at( start_index ).uuid != bits( details::gatt_uuids::internal_128bit_uuid );
 
 1003        std::size_t ending_index = handle_mapping::first_index_by_handle( ending_handle );
 
 1006        if ( ending_index != details::invalid_attribute_index && handle_mapping::handle_by_index( ending_index ) != ending_handle )
 
 1009        std::uint8_t*        write_ptr = &output[ 0 ];
 
 1010        std::uint8_t* 
const  write_end = write_ptr + out_size;
 
 1012        *write_ptr = bits( details::att_opcodes::find_information_response );
 
 1015        if ( write_ptr != write_end )
 
 1019                    ? details::att_uuid_format::short_16bit
 
 1020                    : details::att_uuid_format::long_128bit );
 
 1026        write_ptr = collect_handle_uuid_tuples( start_index, ending_index, only_16_bit_uuids, write_ptr, write_end );
 
 1028        out_size = write_ptr - &output[ 0 ];
 
 1032        template < 
class Server >
 
 1035            value_filter( 
const std::uint8_t* begin, 
const std::uint8_t* end, Server& s )
 
 1042            bool operator()( std::uint16_t, 
const details::attribute& attr )
 const 
 1044                auto read = details::attribute_access_arguments::compare_value( begin_, end_, &server_ );
 
 1045                return attr.access( read, 1 ) == details::attribute_access_result::value_equal;
 
 1048            const std::uint8_t* 
const begin_;
 
 1049            const std::uint8_t* 
const end_;
 
 1053        struct collect_find_by_type_groups
 
 1055            collect_find_by_type_groups( std::uint8_t* begin, std::uint8_t* end )
 
 1062            template < 
typename Service >
 
 1063            bool operator()( std::uint16_t start_handle, std::uint16_t end_handle, 
const details::attribute& )
 
 1065                if ( end_ -  current_ >= 4 )
 
 1067                    current_ = details::write_handle( current_, start_handle );
 
 1068                    current_ = details::write_handle( current_, end_handle );
 
 1076            std::uint8_t size()
 const 
 1078                return current_ - begin_;
 
 1081            std::uint8_t* 
const begin_;
 
 1082            std::uint8_t* 
const end_;
 
 1083            std::uint8_t*       current_;
 
 1087    template < 
typename ... Options >
 
 1088    void server< Options... >::handle_find_by_type_value_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size )
 
 1090        std::uint16_t starting_handle, ending_handle;
 
 1092        if ( !check_size_and_handle_range< 9u, 23u >( input, in_size, output, out_size, starting_handle, ending_handle ) )
 
 1096        if ( details::read_handle( &input[ 5 ] ) != bits( details::gatt_uuids::primary_service ) )
 
 1097            return error_response( *input, details::att_error_codes::unsupported_group_type, starting_handle, output, out_size );
 
 1099        details::collect_find_by_type_groups iterator( output + 1 , output + out_size );
 
 1101        if ( all_services_by_group( starting_handle, ending_handle, iterator, details::value_filter< server< Options... > >( &input[ 7 ], &input[ in_size ], *
this ) ) )
 
 1103            *output  = bits( details::att_opcodes::find_by_type_value_response );
 
 1104            out_size = iterator.size() + 1;
 
 1108            error_response( *input, details::att_error_codes::attribute_not_found, starting_handle, output, out_size );
 
 1113    template < 
typename ... Options >
 
 1114    template < 
typename ConnectionData >
 
 1115    void server< Options... >::handle_read_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )
 
 1117        std::uint16_t handle;
 
 1120        if ( !check_size_and_handle< 3 >( input, in_size, output, out_size, handle, index ) )
 
 1123        auto read = details::attribute_access_arguments::read( output + 1, output + out_size, 0, connection.client_configurations(), connection.security_attributes(), 
this );
 
 1124        auto rc   = attribute_at( index ).access( read, index );
 
 1126        if ( rc == details::attribute_access_result::success )
 
 1128            *output  = bits( details::att_opcodes::read_response );
 
 1129            out_size = 1 + read.buffer_size;
 
 1133            error_response( *input, access_result_to_att_code( rc, details::att_error_codes::read_not_permitted ), handle, output, out_size );
 
 1137    template < 
typename ... Options >
 
 1138    template < 
typename ConnectionData >
 
 1139    void server< Options... >::handle_read_blob_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )
 
 1141        std::uint16_t handle;
 
 1144        if ( !check_size_and_handle< 5 >( input, in_size, output, out_size, handle, index ) )
 
 1147        const std::uint16_t offset = details::read_16bit( input + 3 );
 
 1149        auto read = details::attribute_access_arguments::read( output + 1, output + out_size, offset, connection.client_configurations(), connection.security_attributes(), 
this );
 
 1150        auto rc   = attribute_at( index ).access( read, index );
 
 1152        if ( rc == details::attribute_access_result::success )
 
 1154            *output  = bits( details::att_opcodes::read_blob_response );
 
 1155            out_size = 1 + read.buffer_size;
 
 1159            error_response( *input, access_result_to_att_code( rc, details::att_error_codes::read_not_permitted ), handle, output, out_size );
 
 1164        template < 
typename Server >
 
 1165        struct collect_attributes
 
 1167            void operator()( std::size_t index, 
const details::attribute& attr )
 
 1169                static constexpr std::size_t maximum_pdu_size = 253u;
 
 1170                static constexpr std::size_t header_size      = 2u;
 
 1172                if ( end_ - current_ >= 
static_cast< std::ptrdiff_t 
>( header_size ) )
 
 1174                    const std::size_t max_data_size = std::min< std::size_t >( end_ - current_, maximum_pdu_size + header_size ) - header_size;
 
 1176                    auto read = attribute_access_arguments::read( current_ + header_size, current_ + header_size + max_data_size, 0, config_, security_, &server_ );
 
 1177                    auto rc   = attr.access( read, index );
 
 1179                    if ( rc == details::attribute_access_result::success )
 
 1181                        assert( read.buffer_size <= maximum_pdu_size );
 
 1185                            size_   = read.buffer_size + header_size;
 
 1189                        if ( read.buffer_size + header_size == size_ )
 
 1191                            current_ = details::write_handle( current_, handle_index_mapping< Server >::handle_by_index( index ) );
 
 1192                            current_ += 
static_cast< std::uint8_t 
>( read.buffer_size );
 
 1198            collect_attributes( std::uint8_t* begin, std::uint8_t* end,
 
 1199                const details::client_characteristic_configuration& config,
 
 1200                const connection_security_attributes& security,
 
 1208                , security_( security )
 
 1213            std::uint8_t size()
 const 
 1215                return current_ - begin_;
 
 1218            std::uint8_t data_size()
 const 
 1225                return current_ == begin_;
 
 1228            std::uint8_t*   begin_;
 
 1229            std::uint8_t*   current_;
 
 1233            details::client_characteristic_configuration config_;
 
 1234            connection_security_attributes security_;
 
 1239    template < 
typename ... Options >
 
 1240    template < 
typename ConnectionData >
 
 1241    void server< Options... >::handle_read_by_type_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )
 
 1243        std::uint16_t starting_handle, ending_handle;
 
 1245        if ( !check_size_and_handle_range< 5 + 2, 5 + 16 >( input, in_size, output, out_size, starting_handle, ending_handle ) )
 
 1248        details::collect_attributes< server< Options... > > iterator( output + 2, output + out_size,
 
 1249            connection.client_configurations(), connection.security_attributes(), *
this );
 
 1251        all_attributes( starting_handle, ending_handle, iterator, details::uuid_filter( input + 5, in_size == 5 + 16 ) );
 
 1253        if ( !iterator.empty() )
 
 1255            output[ 0 ] = bits( details::att_opcodes::read_by_type_response );
 
 1256            output[ 1 ] = iterator.data_size();
 
 1257            out_size = 2 + iterator.size();
 
 1261            error_response( *input, details::att_error_codes::attribute_not_found, starting_handle, output, out_size );
 
 1266        template < 
typename CCCDIndices, 
typename ServiceList, 
typename Server >
 
 1267        struct collect_primary_services
 
 1269            collect_primary_services( std::uint8_t*& output, std::uint8_t* end, std::uint16_t starting_index, std::uint16_t starting_handle, std::uint16_t ending_handle, std::uint8_t& attribute_data_size, Server& server )
 
 1272                , index_( details::handle_index_mapping< Server >::first_index_by_handle( starting_index ) )
 
 1273                , starting_index_( details::handle_index_mapping< Server >::first_index_by_handle( starting_handle ) )
 
 1274                , ending_index_( ending_handle )
 
 1277                , is_128bit_uuid_( true )
 
 1278                , attribute_data_size_( attribute_data_size )
 
 1283            template< 
typename Service >
 
 1287                    && ( starting_index_ != details::invalid_attribute_index && starting_index_ <= index_ )
 
 1288                    && ( index_ <= ending_index_ || ending_index_ == details::invalid_attribute_index ) )
 
 1292                        is_128bit_uuid_         = Service::uuid::is_128bit;
 
 1294                        attribute_data_size_    = is_128bit_uuid_ ? 16 + 4 : 2 + 4;
 
 1297                    else if ( is_128bit_uuid_ != Service::uuid::is_128bit )
 
 1304                    output_ = Service::template read_primary_service_response< CCCDIndices, 0, ServiceList, Server >( output_, end_, index_, is_128bit_uuid_, server_ );
 
 1307                index_ += Service::number_of_attributes;
 
 1310                  std::uint8_t*&  output_;
 
 1313            const std::size_t     starting_index_;
 
 1314            const std::size_t     ending_index_;
 
 1317                  bool            is_128bit_uuid_;
 
 1318                  std::uint8_t&   attribute_data_size_;
 
 1323    template < 
typename ... Options >
 
 1324    void server< Options... >::handle_read_by_group_type_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size )
 
 1326        std::uint16_t starting_handle, ending_handle;
 
 1328        if ( !check_size_and_handle_range< 5 + 2, 5 + 16 >( input, in_size, output, out_size, starting_handle, ending_handle ) )
 
 1331        if ( in_size == 5 + 16 || details::read_handle( &input[ 5 ] ) != bits( details::gatt_uuids::primary_service ) )
 
 1332            return error_response( *input, details::att_error_codes::unsupported_group_type, starting_handle, output, out_size );
 
 1334        std::uint8_t*       begin = output;
 
 1335        std::uint8_t* 
const end   = output + out_size;
 
 1337        begin = details::write_opcode( begin, details::att_opcodes::read_by_group_type_response );
 
 1340        std::uint8_t* 
const data_begin = begin;
 
 1341        details::for_< services >::each( details::collect_primary_services< cccd_indices, services, server< Options... > >( begin, end, 1, starting_handle, ending_handle, *(begin -1 ), *
this ) );
 
 1343        if ( begin == data_begin )
 
 1345            error_response( *input, details::att_error_codes::attribute_not_found, starting_handle, output, out_size );
 
 1349            out_size = begin - output;
 
 1353    template < 
typename ... Options >
 
 1354    template < 
typename ConnectionData >
 
 1355    void server< Options... >::handle_read_multiple_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* 
const output, std::size_t& out_size, ConnectionData& cc )
 
 1357        if ( in_size < 5 || in_size % 2 == 0 )
 
 1358            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );
 
 1360        const std::uint8_t opcode = *input;
 
 1364        std::uint8_t* 
const end_output = output + out_size;
 
 1365        std::uint8_t*       out_ptr    = output;
 
 1367        *out_ptr = bits( details::att_opcodes::read_multiple_response );
 
 1370        for ( 
const std::uint8_t* 
const end_input = input + in_size; input != end_input; input += 2 )
 
 1372            const std::uint16_t handle = details::read_handle( input );
 
 1375                return error_response( opcode, details::att_error_codes::invalid_handle, handle, output, out_size );
 
 1377            const std::size_t index = handle_mapping::index_by_handle( handle );
 
 1378            if ( index == details::invalid_attribute_index )
 
 1379                return error_response( opcode, details::att_error_codes::invalid_handle, handle, output, out_size );
 
 1381            auto read = details::attribute_access_arguments::read( out_ptr, end_output, 0, cc.client_configurations(), cc.security_attributes(), 
this );
 
 1382            auto rc   = attribute_at( index ).access( read, index );
 
 1384            if ( rc == details::attribute_access_result::success )
 
 1386                out_ptr += read.buffer_size;
 
 1387                assert( out_ptr <= end_output );
 
 1391                return error_response( opcode, access_result_to_att_code( rc, details::att_error_codes::read_not_permitted ), handle, output, out_size );
 
 1395        out_size = out_ptr - output;
 
 1398    template < 
typename ... Options >
 
 1399    template < 
typename ConnectionData >
 
 1400    void server< Options... >::handle_write_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )
 
 1403            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );
 
 1405        std::uint16_t handle;
 
 1408        if ( !check_handle( input, in_size, output, out_size, handle, index ) )
 
 1411        auto write = details::attribute_access_arguments::write( input + 3, input + in_size, 0, connection.client_configurations(), connection.security_attributes(), 
this );
 
 1412        auto rc    = attribute_at( index ).access( write, index );
 
 1414        if ( rc == details::attribute_access_result::success )
 
 1416            *output  = bits( details::att_opcodes::write_response );
 
 1421            error_response( *input, access_result_to_att_code( rc, details::att_error_codes::write_not_permitted ), handle, output, out_size );
 
 1425    template < 
typename ... Options >
 
 1426    template < 
typename ConnectionData >
 
 1427    void server< Options... >::handle_write_command( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& cc )
 
 1430        handle_write_request( input, in_size, output, out_size, cc );
 
 1436    template < 
typename ... Options >
 
 1437    template < 
typename Connection >
 
 1438    void server< Options... >::handle_prepair_write_request( 
const std::uint8_t* input, std::size_t, std::uint8_t* output, std::size_t& out_size, Connection&, 
const details::no_such_type& )
 
 1440        error_response( *input, details::att_error_codes::request_not_supported, output, out_size );
 
 1443    template < 
typename ... Options >
 
 1444    template < 
typename Connection, 
typename WriteQueue >
 
 1445    void server< Options... >::handle_prepair_write_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& client, 
const WriteQueue& )
 
 1448            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );
 
 1450        std::uint16_t handle;
 
 1453        if ( !check_handle( input, in_size, output, out_size, handle, index ) )
 
 1456        auto write = details::attribute_access_arguments::check_write( 
this );
 
 1457        auto rc    = attribute_at( index ).access( write, index );
 
 1459        if ( rc != details::attribute_access_result::success )
 
 1460            return error_response( *input, access_result_to_att_code( rc, details::att_error_codes::write_not_permitted ), handle, output, out_size );
 
 1463        std::uint8_t* 
const queue_element = this->allocate_from_write_queue( in_size - 1, client );
 
 1465        if ( queue_element == 
nullptr )
 
 1466            return error_response( *input, details::att_error_codes::prepare_queue_full, handle, output, out_size );
 
 1468        std::copy( input + 1, input + in_size, queue_element );
 
 1470        *output = bits( details::att_opcodes::prepare_write_response );
 
 1472        out_size = std::min< std::size_t >( out_size, in_size );
 
 1473        std::copy( input + 1, input + out_size, output + 1 );
 
 1476    template < 
typename ... Options >
 
 1477    template < 
typename Connection >
 
 1478    void server< Options... >::handle_execute_write_request( 
const std::uint8_t* input, std::size_t, std::uint8_t* output, std::size_t& out_size, Connection&, 
const details::no_such_type& )
 
 1480        error_response( *input, details::att_error_codes::request_not_supported, output, out_size );
 
 1483    template < 
typename ... Options >
 
 1484    template < 
typename Connection, 
typename WriteQueue >
 
 1485    void server< Options... >::handle_execute_write_request( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& client, 
const WriteQueue& )
 
 1487        if ( in_size != 2 || ( input[ 1 ] != 0 && input[ 1 ] != 1 ) )
 
 1488            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );
 
 1491        details::write_queue_guard< connection_data, details::write_queue< write_queue_type > > queue_guard( client, *
this );
 
 1493        const std::uint8_t execute_flag = input[ 1 ];
 
 1497            for ( std::pair< std::uint8_t*, std::size_t > queue = this->first_write_queue_element( client ); queue.first; queue = this->next_write_queue_element( queue.first, client ) )
 
 1499                const std::uint16_t handle = details::read_handle( queue.first );
 
 1500                const std::uint16_t offset = details::read_16bit( queue.first + 2 );
 
 1502                const std::size_t attribute_index = handle_mapping::index_by_handle( handle );
 
 1504                auto write = details::attribute_access_arguments::write( queue.first + 4 , queue.first + queue.second,
 
 1505                                offset, client.client_configurations(), client.security_attributes(), 
this );
 
 1506                auto rc    = attribute_at( attribute_index ).access( write, attribute_index );
 
 1508                if ( rc != details::attribute_access_result::success )
 
 1510                    this->free_write_queue( client );
 
 1512                    if ( rc == details::attribute_access_result::invalid_attribute_value_length )
 
 1513                        return error_response( *input, details::att_error_codes::invalid_attribute_value_length, handle, output, out_size );
 
 1515                    return error_response( *input, details::att_error_codes::invalid_offset, handle, output, out_size );
 
 1520        this->free_write_queue( client );
 
 1522        *output  = bits( details::att_opcodes::execute_write_response );
 
 1526    template < 
typename ... Options >
 
 1527    void server< Options... >::handle_value_confirmation( 
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, connection_data& )
 
 1530            return error_response( *input, 
static_cast< details::att_error_codes 
>( 0x04 ), output, out_size );
 
 1535            l2cap_cb_( details::notification_data(), l2cap_arg_, details::notification_type::confirmation );
 
 1539    template < 
typename ... Options >
 
 1540    template < 
class Iterator, 
class Filter >
 
 1541    void server< Options... >::all_attributes( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator& iter, 
const Filter& filter )
 
 1543        const std::size_t last_index = last_handle_index( ending_handle );
 
 1545        for ( std::size_t index = handle_mapping::first_index_by_handle( starting_handle ); index <= last_index; ++index )
 
 1547            const details::attribute attr = attribute_at( index );
 
 1549            if ( filter( index, attr ) )
 
 1550                iter( index, attr );
 
 1555        template < 
class Iterator, 
class Filter, 
class AllServices, 
class Server >
 
 1556        struct services_by_group
 
 1558            services_by_group( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator& iterator, 
const Filter& filter, 
bool& found )
 
 1559                : starting_index_( details::handle_index_mapping< Server >::first_index_by_handle( starting_handle ) )
 
 1560                , ending_index_( details::handle_index_mapping< Server >::first_index_by_handle( ending_handle ) )
 
 1562                , iterator_( iterator )
 
 1567                if ( ending_index_ != details::invalid_attribute_index && details::handle_index_mapping< Server >::handle_by_index( ending_index_ ) != ending_handle )
 
 1573            template< 
typename Service >
 
 1576                if ( ( starting_index_ != details::invalid_attribute_index && starting_index_ <= index_ )
 
 1577                    && ( index_ <= ending_index_ || ending_index_ == details::invalid_attribute_index ) )
 
 1579                    const details::attribute& attr = Server::attribute_at( index_ );
 
 1581                    using mapping = details::handle_index_mapping< Server >;
 
 1583                    if ( filter_( index_, attr ) )
 
 1585                        found_ = iterator_.template operator()< Service >(
 
 1586                            mapping::handle_by_index( index_ ),
 
 1587                            mapping::handle_by_index( index_ + Service::number_of_attributes - 1 ),
 
 1592                index_ += Service::number_of_attributes;
 
 1595            std::size_t     starting_index_;
 
 1596            std::size_t     ending_index_;
 
 1598            Iterator&       iterator_;
 
 1599            const Filter&   filter_;
 
 1604    template < 
typename ... Options >
 
 1605    template < 
class Iterator, 
class Filter >
 
 1606    bool server< Options... >::all_services_by_group( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator& iterator, 
const Filter& filter )
 
 1608        bool result = 
false;
 
 1609        details::services_by_group< Iterator, Filter, services, server< Options...  > > service_iterator( starting_handle, ending_handle, iterator, filter, result );
 
 1610        details::for_< services >::each( service_iterator );
 
 1615    template < 
typename ... Options >
 
 1616    std::uint8_t* server< Options... >::collect_handle_uuid_tuples( std::size_t start, std::size_t end, 
bool only_16_bit, std::uint8_t* out, std::uint8_t* out_end )
 
 1618        const std::size_t size_per_tuple = only_16_bit
 
 1622        for ( ; ( start <= end || end == details::invalid_attribute_index ) && start < number_of_attributes
 
 1623            && 
static_cast< std::size_t 
>( out_end - out ) >= size_per_tuple; ++start )
 
 1625            const details::attribute attr = attribute_at( start );
 
 1626            const bool is_16_bit_uuids    = attr.uuid != bits( details::gatt_uuids::internal_128bit_uuid );
 
 1628            if ( only_16_bit == is_16_bit_uuids )
 
 1630                details::write_handle( out, handle_mapping::handle_by_index( start ) );
 
 1632                if ( is_16_bit_uuids )
 
 1634                    details::write_16bit_uuid( out + 2, attr.uuid );
 
 1638                    write_128bit_uuid( out + 2, attribute_at( start - 1 ) );
 
 1641                out += size_per_tuple;
 
 1648    template < 
typename ... Options >
 
 1649    void server< Options... >::write_128bit_uuid( std::uint8_t* out, 
const details::attribute& char_declaration )
 
 1655        assert( char_declaration.uuid == bits( details::gatt_uuids::characteristic ) );
 
 1657        std::uint8_t buffer[ 3 + 16 ];
 
 1658        auto read = details::attribute_access_arguments::read( buffer, 0 );
 
 1659        char_declaration.access( read, 1 );
 
 1661        assert( read.buffer_size == 
sizeof( buffer ) );
 
 1663        std::copy( &read.buffer[ 3 ], &read.buffer[ 3 + 16 ], out );
 
 1666    template < 
typename ... Options >
 
 1667    std::size_t server< Options... >::last_handle_index( std::uint16_t ending_handle )
 
 1669        const std::size_t mapped = handle_mapping::first_index_by_handle( ending_handle );
 
 1671        return mapped == details::invalid_attribute_index
 
 1672            ? number_of_attributes - 1
 
 1676    template < 
typename ... Options >
 
 1677    details::notification_data server< Options... >::find_notification_data( 
const void* value )
 const 
 1679        return details::find_notification_data_in_list< notification_priority, services >::find_notification_data( value );
 
 1682    template < 
typename ... Options >
 
 1683    details::notification_data server< Options... >::find_notification_data_by_index( std::size_t client_characteristic_configuration_index )
 const 
 1685        return details::find_notification_data_in_list< notification_priority, services >::find_notification_data_by_index( client_characteristic_configuration_index );
 
 1688    template < 
typename ... Options >
 
 1689    void server< Options... >::notification_subscription_changed( 
const details::client_characteristic_configuration& data )
 
 1691        using cb_t = 
typename details::find_by_meta_type<
 
 1692            details::cccd_callback_meta_type,
 
 1694            no_client_characteristic_configuration_update_callback >::type;
 
 1696        cb_t::client_characteristic_configuration_updated( *
this, data );
 
class responsible to keep track of those characteristics that have outstanding notifications or indic...
Definition: notification_queue.hpp:47
 
per connection data
Definition: server.hpp:122
 
std::uint16_t server_mtu() const
returns the MTU of this server as provided in the c'tor
Definition: server.hpp:164
 
void client_mtu(std::uint16_t mtu)
sets the MTU size of the connected client.
Definition: server.hpp:144
 
std::uint16_t client_mtu() const
returns the client MTU
Definition: server.hpp:155
 
std::uint16_t negotiated_mtu() const
returns the negotiated MTU
Definition: server.hpp:132
 
Root of the declaration of a GATT server.
Definition: server.hpp:85
 
bool configured_for_notifications_or_indications(const details::client_characteristic_configuration &) const
returns true, if the given connection is configured to send indications or notifications for the give...
 
bool configured_for_indications(const details::client_characteristic_configuration &) const
returns true, if the given connection is configured to send indications for the given characteristic
 
bool indicate()
sends indications to all connceted clients.
 
bool configured_for_notifications(const details::client_characteristic_configuration &) const
returns true, if the given connection is configured to send notifications for the given characteristi...
 
bool indicate(const T &value)
sends indications to all connceted clients.
 
bool notify(const T &value)
notifies all connected clients about this value
 
server()
a server takes no runtime construction parameters
 
device_appearance< 0x0000 > unknown
Unknown.
Definition: appearance.hpp:54
 
Definition: custom_advertising.hpp:39
 
options, that allows Bluetoe to create the scan response data
Definition: custom_advertising.hpp:148
 
adds additional options to a given server definition
Definition: server.hpp:480
 
Used as a parameter to a server, to define that the GATT server will include a GAP service for GATT s...
Definition: gap_service.hpp:51
 
Defines priorities of notified or indicated characteristics.
Definition: outgoing_priority.hpp:160
 
define the maximum GATT MTU size to be used
Definition: gatt_options.hpp:24