1#ifndef BLUETOE_CHARACTERISTIC_HPP 
    2#define BLUETOE_CHARACTERISTIC_HPP 
    4#include <bluetoe/characteristic_value.hpp> 
    5#include <bluetoe/attribute.hpp> 
    6#include <bluetoe/attribute_handle.hpp> 
    7#include <bluetoe/codes.hpp> 
    8#include <bluetoe/uuid.hpp> 
   10#include <bluetoe/bits.hpp> 
   11#include <bluetoe/scattered_access.hpp> 
   12#include <bluetoe/service_uuid.hpp> 
   13#include <bluetoe/attribute_generator.hpp> 
   14#include <bluetoe/server_meta_type.hpp> 
   15#include <bluetoe/meta_types.hpp> 
   16#include <bluetoe/encryption.hpp> 
   17#include <bluetoe/descriptor.hpp> 
   28        struct characteristic_uuid_meta_type {};
 
   30        struct characteristic_declaration_parameter {};
 
   31        struct characteristic_user_description_parameter {};
 
   33        template < 
typename CCCDIndices, 
typename ... Options >
 
   34        struct generate_characteristic_attributes;
 
   36        template < 
typename ... Options >
 
   37        struct count_characteristic_attributes;
 
   39        template < 
typename Characteristic >
 
   40        struct sum_by_attributes;
 
   42        template < 
typename Characteristic >
 
   43        struct sum_by_client_configs;
 
   65            details::characteristic_uuid_meta_type,
 
   66            details::characteristic_value_declaration_parameter,
 
   67            details::characteristic_declaration_parameter,
 
   68            details::valid_characteristic_option_meta_type {};
 
   82            details::characteristic_uuid_meta_type,
 
   83            details::characteristic_value_declaration_parameter,
 
   84            details::characteristic_declaration_parameter,
 
   85            details::valid_characteristic_option_meta_type {};
 
   86        static constexpr bool is_128bit = 
false;
 
  158    template < 
typename ... Options >
 
  164        using attribute_numbers = details::count_characteristic_attributes< Options... >;
 
  169        static constexpr std::size_t number_of_attributes     = attribute_numbers::number_of_attributes;
 
  170        static constexpr std::size_t number_of_client_configs = attribute_numbers::number_of_client_configs;
 
  173            details::characteristic_meta_type,
 
  174            details::valid_service_option_meta_type {};
 
  178        typedef typename details::find_by_meta_type< details::characteristic_uuid_meta_type, Options... >::type configured_uuid;
 
  184        template < 
typename CCCDIndices, std::
size_t ClientCharacteristicIndex, 
typename Service, 
typename Server >
 
  185        static details::attribute attribute_at( std::size_t index );
 
  187        typedef typename details::find_by_meta_type< details::characteristic_value_meta_type, Options... >::type    base_value_type;
 
  189        static_assert( !std::is_same< base_value_type, details::no_such_type >::value,
 
  190            "please make sure, that every characteristic defines some kind of value (bind_characteristic_value<> for example)" );
 
  192        typedef typename base_value_type::template value_impl< Options... >                                         value_type;
 
  196                typename details::find_by_not_meta_type<
 
  197                    details::valid_characteristic_option_meta_type,
 
  199                >::type, details::no_such_type >::value,
 
  200            "Parameter passed to a characteristic that is not a valid characteristic option!" );
 
  204        static constexpr std::size_t characteristic_declaration_index = 0;
 
  205        static constexpr std::size_t characteristic_value_index       = 1;
 
  225    template < const 
char* const >
 
  230            details::characteristic_parameter_meta_type,
 
  231            details::characteristic_user_description_parameter,
 
  232            details::characteristic_declaration_parameter,
 
  233            details::valid_characteristic_option_meta_type {};
 
  240    template < 
typename ... Options >
 
  241    template < 
typename CCCDIndices, std::
size_t ClientCharacteristicIndex, 
typename Service, 
typename Server >
 
  244        assert( index < number_of_attributes );
 
  246        using characteristic_descriptor_declarations = 
typename details::generate_characteristic_attributes< CCCDIndices, Options... >;
 
  247        return characteristic_descriptor_declarations::template attribute_at< ClientCharacteristicIndex, Service, Server >( index );
 
  251        template < 
typename ServiceUUID, 
typename ... Options >
 
  252        struct characteristic_or_service_uuid
 
  254            using char_uuid = 
typename find_by_meta_type< characteristic_uuid_meta_type, Options... >::type;
 
  255            using uuid      = 
typename or_type< no_such_type, char_uuid, ServiceUUID >::type;
 
  257            static_assert( !std::is_same< uuid, no_such_type >::value, 
"If instanciating a characteristic<> for testing, please provide a UUID." );
 
  259            static constexpr bool auto_generated_uuid   = std::is_same< char_uuid, no_such_type >::value;
 
  260            static constexpr bool serice_uuid_is_16_bit = count_by_meta_type< details::service_uuid_16_meta_type, ServiceUUID >::count;
 
  262            static_assert( !( auto_generated_uuid && serice_uuid_is_16_bit ), 
"No support for automatic generated characteristic UUIDs, if the containing service has not 128 bit UUID" );
 
  268        template < 
typename ... AttrOptions, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename ... ServiceOptions, 
typename Server, 
typename ... Options >
 
  269        struct generate_attribute< std::tuple< characteristic_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, service< ServiceOptions...>, Server, Options... >
 
  271            using characteristic_or_service_uuid_t = characteristic_or_service_uuid< 
typename service< ServiceOptions... >::uuid, Options... >;
 
  272            using uuid       = 
typename characteristic_or_service_uuid_t::uuid;
 
  273            using value_type = 
typename characteristic< Options... >::value_type;
 
  275            static void fixup_auto_uuid( details::attribute_access_arguments& args )
 
  277                using characteristics_t = 
typename find_all_by_meta_type<
 
  278                    details::characteristic_meta_type,
 
  279                    ServiceOptions... >::type;
 
  281                std::uint16_t char_index = index_of< characteristic< Options... >, characteristics_t >::value + 1;
 
  283                static constexpr std::size_t uuid_offset = 3;
 
  285                int index_low  = 
static_cast< int >( args.buffer_offset ) - 
static_cast< int >( uuid_offset );
 
  286                int index_high = 
static_cast< int >( args.buffer_offset ) - 
static_cast< int >( uuid_offset + 1 );
 
  288                if ( index_low >= 0 && index_low < 
static_cast< int >( args.buffer_size ) )
 
  289                    args.buffer[ index_low ] ^= ( char_index & 0xff );
 
  291                if ( index_high >= 0 && index_high < 
static_cast< int >( args.buffer_size ) )
 
  292                    args.buffer[ index_high ] ^= ( char_index >> 8 );
 
  298            static details::attribute_access_result char_declaration_access( details::attribute_access_arguments& args, std::size_t attribute_index )
 
  300                if ( args.type != details::attribute_access_type::read )
 
  301                    return details::attribute_access_result::write_not_permitted;
 
  303                static constexpr bool has_write_attribute_ =
 
  304                    value_type::has_write_access && !value_type::has_only_write_without_response;
 
  305                static constexpr bool has_write_without_response_attribute =
 
  306                    value_type::has_only_write_without_response || value_type::has_write_without_response;
 
  308                const std::uint8_t properties[] = {
 
  309                    static_cast< std::uint8_t 
>(
 
  310                        ( value_type::has_read_access  ? bits( details::gatt_characteristic_properties::read ) : 0 ) |
 
  311                        ( has_write_attribute_         ? bits( details::gatt_characteristic_properties::write ) : 0 ) |
 
  312                        ( has_write_without_response_attribute ? bits( details::gatt_characteristic_properties::write_without_response ) : 0 ) |
 
  313                        ( value_type::has_notification ? bits( details::gatt_characteristic_properties::notify ) : 0 ) |
 
  314                        ( value_type::has_indication   ? bits( details::gatt_characteristic_properties::indicate ) : 0 ) )
 
  317                const std::uint16_t value_attribute_handle = handle_index_mapping< Server >::handle_by_index( attribute_index + 1 );
 
  318                assert( value_attribute_handle != details::invalid_attribute_handle );
 
  320                const std::uint8_t value_handle[] = {
 
  321                    static_cast< std::uint8_t 
>( value_attribute_handle & 0xff ),
 
  322                    static_cast< std::uint8_t 
>( value_attribute_handle >> 8 )
 
  325                static constexpr auto data_size = 
sizeof( properties ) + 
sizeof( value_handle ) + 
sizeof( uuid::bytes );
 
  327                if ( args.buffer_offset > data_size )
 
  328                    return details::attribute_access_result::invalid_offset;
 
  330                details::scattered_read_access( args.buffer_offset, properties, value_handle, uuid::bytes, args.buffer, args.buffer_size );
 
  332                if ( characteristic_or_service_uuid_t::auto_generated_uuid )
 
  333                    fixup_auto_uuid( args );
 
  335                args.buffer_size = std::min< std::size_t >( data_size - args.buffer_offset, args.buffer_size );
 
  337                return details::attribute_access_result::success;
 
  340            static const attribute attr;
 
  343        template < 
typename ... AttrOptions, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename ... ServiceOptions, 
typename Server, 
typename ... Options >
 
  344        const attribute generate_attribute< std::tuple< characteristic_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, service< ServiceOptions... > , Server, Options... >::attr {
 
  345            bits( details::gatt_uuids::characteristic ),
 
  346            &generate_attribute< std::tuple< characteristic_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, service< ServiceOptions... >, Server, Options... >::char_declaration_access
 
  352        template < 
typename ... AttrOptions, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename Service, 
typename Server, 
typename ... Options >
 
  353        struct generate_attribute< std::tuple< characteristic_value_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >
 
  356            typedef typename characteristic_or_service_uuid< 
typename Service::uuid, Options... >::uuid      uuid;
 
  357            using char_t = characteristic< Options... >;
 
  358            static constexpr bool requires_encryption = characteristic_requires_encryption< char_t, Service, Server >::value;
 
  360            static const attribute attr;
 
  363        template < 
typename ... AttrOptions, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename Service, 
typename Server, 
typename ... Options >
 
  364        const attribute generate_attribute< std::tuple< characteristic_value_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::attr {
 
  366                ? bits( details::gatt_uuids::internal_128bit_uuid )
 
  368            &characteristic< Options... >::value_type::template characteristic_value_access< Server, ClientCharacteristicIndex, requires_encryption >
 
  374        template < 
const char* 
const Name, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename Service, 
typename Server, 
typename ... Options >
 
  375        struct generate_attribute< std::tuple< characteristic_user_description_parameter, characteristic_name< Name > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >
 
  377            static const attribute attr;
 
  379            static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )
 
  381                const std::size_t str_len   = std::strlen( Name );
 
  383                if ( args.buffer_offset > str_len )
 
  384                    return details::attribute_access_result::invalid_offset;
 
  386                details::attribute_access_result result = attribute_access_result::write_not_permitted;
 
  388                if ( args.type == attribute_access_type::read )
 
  390                    const std::size_t read_size = std::min( args.buffer_size, str_len - args.buffer_offset );
 
  392                    std::copy( Name + args.buffer_offset, Name + args.buffer_offset + read_size, args.buffer );
 
  394                    result = attribute_access_result::success;
 
  396                    args.buffer_size = read_size;
 
  404        template < 
const char* 
const Name, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename Service, 
typename Server, 
typename ... Options >
 
  405        const attribute generate_attribute< std::tuple< characteristic_user_description_parameter, characteristic_name< Name > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::attr {
 
  406            bits( gatt_uuids::characteristic_user_description ),
 
  407            &generate_attribute< std::tuple< characteristic_user_description_parameter, characteristic_name< Name > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::access
 
  413        template < 
typename ... AttrOptions, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename Service, 
typename Server, 
typename ... Options >
 
  414        struct generate_attribute< std::tuple< client_characteristic_configuration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >
 
  416            static const attribute attr;
 
  417            using uuid   = 
typename characteristic_or_service_uuid< 
typename Service::uuid, Options... >::uuid;
 
  419            using char_t = characteristic< Options... >;
 
  420            static constexpr bool requires_encryption = characteristic_requires_encryption< char_t, Service, Server >::value;
 
  422            static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )
 
  424                const auto security_result = details::encryption_requirements< requires_encryption >::check( args.connection_security );
 
  426                if ( security_result != details::attribute_access_result::success )
 
  427                    return security_result;
 
  429                static constexpr std::size_t flags_size = 2;
 
  430                std::uint8_t buffer[ flags_size ];
 
  432                if ( args.buffer_offset > flags_size )
 
  433                    return details::attribute_access_result::invalid_offset;
 
  435                details::attribute_access_result result = attribute_access_result::write_not_permitted;
 
  438                const std::size_t cccd_position_index = index_of< std::integral_constant< std::size_t, ClientCharacteristicIndex >, CCCDIndices >::value;
 
  439                const std::size_t cccd_position = std::tuple_size< CCCDIndices >::value == 0
 
  440                                                    ? ClientCharacteristicIndex
 
  441                                                    : cccd_position_index;
 
  443                if ( args.type == attribute_access_type::read )
 
  445                    write_16bit( &buffer[ 0 ], args.client_config.flags( cccd_position ) );
 
  447                    const std::size_t read_size = std::min( args.buffer_size, flags_size - args.buffer_offset );
 
  449                    std::copy( &buffer[ args.buffer_offset ], &buffer[ args.buffer_offset + read_size ], args.buffer );
 
  451                    result = attribute_access_result::success;
 
  453                    args.buffer_size = read_size;
 
  455                else if ( args.type == attribute_access_type::write )
 
  457                    if ( args.buffer_size + args.buffer_offset > flags_size )
 
  458                        return details::attribute_access_result::invalid_attribute_value_length;
 
  460                    if ( args.buffer_offset == 0 )
 
  462                        const std::uint16_t old_config = args.client_config.flags( cccd_position );
 
  463                        std::uint8_t serialized_value[ flags_size ];
 
  464                        write_16bit( &serialized_value[ 0 ], old_config );
 
  466                        const std::size_t write_size = std::min( args.buffer_size, flags_size - args.buffer_offset );
 
  467                        std::copy( &args.buffer[ args.buffer_offset ], &args.buffer[ args.buffer_offset + write_size ], serialized_value );
 
  469                        args.client_config.flags( cccd_position, read_16bit( &serialized_value[ 0 ] ) );
 
  471                        using subscription_callback =
 
  472                            typename find_by_meta_type<
 
  473                                characteristic_subscription_call_back_meta_type,
 
  474                                Options..., default_on_characteristic_subscription >::type;
 
  476                        subscription_callback::template on_subscription< uuid >(
 
  477                            args.client_config.flags( cccd_position ),
 
  478                            *
static_cast< Server* 
>( args.server ) );
 
  480                        if ( old_config != args.client_config.flags( cccd_position ) )
 
  481                            static_cast< Server* 
>( args.server )->notification_subscription_changed( args.client_config );
 
  484                    result = attribute_access_result::success;
 
  491        template < 
typename ... AttrOptions, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename Service, 
typename Server, 
typename ... Options >
 
  492        constexpr attribute generate_attribute< std::tuple< client_characteristic_configuration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::attr {
 
  493            bits( gatt_uuids::client_characteristic_configuration ),
 
  494            &generate_attribute< std::tuple< client_characteristic_configuration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::access
 
  500        template < std::uint16_t UUID, 
const std::uint8_t* 
const Value, std::size_t Size, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename Service, 
typename Server, 
typename ... Options >
 
  501        struct generate_attribute< std::tuple< descriptor_parameter, descriptor< UUID, Value, Size > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >
 
  503            static const attribute attr;
 
  505            static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )
 
  507                if ( args.type != attribute_access_type::read )
 
  508                    return attribute_access_result::write_not_permitted;
 
  510                if ( args.buffer_offset > Size )
 
  511                    return details::attribute_access_result::invalid_offset;
 
  513                const std::size_t read_size = std::min( args.buffer_size, Size - args.buffer_offset );
 
  515                std::copy( Value + args.buffer_offset, Value + args.buffer_offset + read_size, args.buffer );
 
  516                args.buffer_size = read_size;
 
  518                return attribute_access_result::success;
 
  523        template < std::uint16_t UUID, 
const std::uint8_t* 
const Value, std::size_t Size, 
typename CCCDIndices, std::size_t ClientCharacteristicIndex, 
typename Service, 
typename Server, 
typename ... Options >
 
  524        constexpr attribute generate_attribute< std::tuple< descriptor_parameter, descriptor< UUID, Value, Size > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::attr {
 
  526            &generate_attribute< std::tuple< descriptor_parameter, descriptor< UUID, Value, Size > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::access
 
  529        template < 
typename CCCDIndices, 
typename ... Options >
 
  530        struct generate_characteristic_attributes : generate_attributes<
 
  531                std::tuple< Options... >,
 
  535                    characteristic_declaration_parameter,
 
  536                    characteristic_value_declaration_parameter,
 
  537                    client_characteristic_configuration_parameter,
 
  538                    characteristic_user_description_parameter,
 
  543                std::tuple< empty_meta_type< characteristic_declaration_parameter > >
 
  546        template < 
typename ... Options >
 
  547        struct count_characteristic_attributes
 
  549            enum { number_of_client_configs =
 
  550                count_by_meta_type< client_characteristic_configuration_parameter, Options... >::count != 0 ? 1 : 0 };
 
  552            enum { number_of_user_descriptions =
 
  553                count_by_meta_type< characteristic_user_description_parameter, Options... >::count != 0 ? 1 : 0 };
 
  555            enum { number_of_descriptors =
 
  556                count_by_meta_type< descriptor_parameter, Options...>::count };
 
  558            enum { number_of_attributes = 2 + number_of_client_configs + number_of_user_descriptions + number_of_descriptors };
 
  561        template < 
typename Characteristic >
 
  562        struct sum_by_attributes
 
  564            enum { value = Characteristic::number_of_attributes };
 
  567        template < 
typename Characteristic >
 
  568        struct sum_by_client_configs
 
  570            enum { value = Characteristic::number_of_client_configs };
 
A characteristic is a typed value that is accessable by a GATT client hosted by a GATT server.
Definition: characteristic.hpp:160
 
adds a name to characteristic
Definition: characteristic.hpp:227
 
a 16-Bit UUID used to identify a characteristic.
Definition: characteristic.hpp:79
 
a 128-Bit UUID used to identify a characteristic.
Definition: characteristic.hpp:62