1#ifndef BLUETOE_NOTIFICATION_QUEUE_HPP 
    2#define BLUETOE_NOTIFICATION_QUEUE_HPP 
   17        enum class notification_queue_entry_type {
 
   26        template < 
typename Size, 
int C >
 
   27        class notification_queue_impl_base;
 
   29        static constexpr std::size_t no_outstanding_indicaton = ~std::size_t{ 0 };
 
   45    template < 
typename Sizes, 
class Mixin >
 
   50        using entry_type = details::notification_queue_entry_type;
 
   58        template < 
class ... Args >
 
  118        using impl = details::notification_queue_impl_base< Sizes, 0 >;
 
  119        std::size_t outstanding_confirmation_index_;
 
  123    template < 
typename Sizes, 
class Mixin >
 
  124    template < 
class ... Args >
 
  126        : Mixin( mixin_arguments... )
 
  127        , outstanding_confirmation_index_( details::no_outstanding_indicaton )
 
  131    template < 
typename Sizes, 
class Mixin >
 
  134        return impl::queue_notification( index );
 
  137    template < 
typename Sizes, 
class Mixin >
 
  140        return impl::queue_indication( index );
 
  143    template < 
typename Sizes, 
class Mixin >
 
  146        outstanding_confirmation_index_ = details::no_outstanding_indicaton;
 
  149    template < 
typename Sizes, 
class Mixin >
 
  152        const auto result = impl::dequeue_indication_or_confirmation( 0, outstanding_confirmation_index_ );
 
  157    template < 
typename Sizes, 
class Mixin >
 
  160        outstanding_confirmation_index_ = details::no_outstanding_indicaton;
 
  161        impl::clear_indications_and_confirmations();
 
  167        template < 
int Size, 
int C >
 
  168        class notification_queue_impl
 
  171            notification_queue_impl()
 
  173                clear_indications_and_confirmations();
 
  176            bool queue_notification( std::size_t index )
 
  178                assert( index < Size );
 
  179                return add( index, notification_bit );
 
  182            bool queue_indication( std::size_t index )
 
  184                assert( index < Size );
 
  186                return add( index, indication_bit );
 
  189            std::pair< notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation( std::size_t offset, std::size_t& outstanding_confirmation )
 
  191                bool ignore_first = 
true;
 
  194                for ( std::size_t i = next_; ignore_first || i != next_; i = ( i + 1 ) % Size )
 
  196                    ignore_first = 
false;
 
  197                    auto entry = at( i );
 
  199                    if ( entry & indication_bit && outstanding_confirmation == no_outstanding_indicaton )
 
  201                        outstanding_confirmation = i + offset;
 
  202                        next_ = ( i + 1 ) % Size;
 
  203                        remove( i, indication_bit );
 
  204                        return { notification_queue_entry_type::indication, i + offset };
 
  206                    else if ( entry & notification_bit )
 
  208                        next_ = ( i + 1 ) % Size;
 
  209                        remove( i, notification_bit );
 
  210                        return { notification_queue_entry_type::notification, i + offset };
 
  215                return { notification_queue_entry_type::empty, 0 };
 
  218            void clear_indications_and_confirmations()
 
  221                std::fill( std::begin( queue_ ), std::end( queue_ ), 0 );
 
  225            int at( std::size_t index )
 
  227                const auto bit_offset  = ( index * bits_per_characteristc ) % 8;
 
  228                const auto byte_offset = index * bits_per_characteristc / 8;
 
  229                assert( byte_offset < 
sizeof( queue_ ) / 
sizeof( queue_[ 0 ] ) );
 
  231                return ( queue_[ byte_offset ] >> bit_offset ) & 0x03;
 
  234            bool add( std::size_t index, 
int bits )
 
  236                assert( bits & ( ( 1 << bits_per_characteristc ) -1 ) );
 
  237                const auto bit_offset  = ( index * bits_per_characteristc ) % 8;
 
  238                const auto byte_offset = index * bits_per_characteristc / 8;
 
  239                assert( byte_offset < 
sizeof( queue_ ) / 
sizeof( queue_[ 0 ] ) );
 
  241                const bool result = ( queue_[ byte_offset ] & ( bits << bit_offset ) ) == 0;
 
  242                queue_[ byte_offset ] |= bits << bit_offset;
 
  247            void remove( std::size_t index, 
int bits )
 
  249                assert( bits & ( ( 1 << bits_per_characteristc ) -1 ) );
 
  250                const auto bit_offset  = ( index * bits_per_characteristc ) % 8;
 
  251                const auto byte_offset = index * bits_per_characteristc / 8;
 
  252                assert( byte_offset < 
sizeof( queue_ ) / 
sizeof( queue_[ 0 ] ) );
 
  254                queue_[ byte_offset ] &= ~( bits << bit_offset );
 
  257            static constexpr std::size_t bits_per_characteristc = 2;
 
  260                notification_bit = 0x01,
 
  261                indication_bit   = 0x02
 
  265            std::uint8_t    queue_[ ( Size * bits_per_characteristc + 7 ) / 8 ];
 
  272        class notification_queue_impl< 1, C >
 
  275            notification_queue_impl()
 
  276                : state_( notification_queue_entry_type::empty )
 
  280            bool queue_notification( std::size_t idx )
 
  282                static_cast< void >( idx );
 
  285                const bool result = state_ == notification_queue_entry_type::empty;
 
  288                    state_ = notification_queue_entry_type::notification;
 
  293            bool queue_indication( std::size_t idx )
 
  295                static_cast< void >( idx );
 
  297                const bool result = state_ == notification_queue_entry_type::empty;
 
  300                    state_ = notification_queue_entry_type::indication;
 
  305            std::pair< notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation( std::size_t offset, std::size_t& outstanding_confirmation )
 
  307                const auto result = state_ == notification_queue_entry_type::notification || ( state_ == notification_queue_entry_type::indication && outstanding_confirmation == details::no_outstanding_indicaton )
 
  308                    ? std::pair< notification_queue_entry_type, std::size_t >{ 
static_cast< notification_queue_entry_type 
>( state_ ), offset }
 
  309                    : std::pair< notification_queue_entry_type, std::size_t >{ notification_queue_entry_type::empty, 0 };
 
  311                if ( result.first == notification_queue_entry_type::indication )
 
  312                    outstanding_confirmation = offset;
 
  314                if ( result.first != notification_queue_entry_type::empty )
 
  315                    state_ = notification_queue_entry_type::empty;
 
  320            void clear_indications_and_confirmations()
 
  322                state_ = notification_queue_entry_type::empty;
 
  325            notification_queue_entry_type state_;
 
  329        class notification_queue_impl_base< std::tuple<>, C >
 
  332            bool queue_notification( std::size_t ) { 
return false; }
 
  333            bool queue_indication( std::size_t ) { 
return false; }
 
  335            std::pair< notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation( std::size_t, std::size_t )
 
  337                return { notification_queue_entry_type::empty, 0 };
 
  340            void clear_indications_and_confirmations() {}
 
  343        template < 
int Size, 
class ...Ts, 
int C >
 
  344        class notification_queue_impl_base< std::tuple< std::integral_constant< int, Size >, Ts... >, C >
 
  345            : 
public notification_queue_impl_base< std::tuple< Ts... >, C + 1 >
 
  346            , 
private notification_queue_impl< Size, C >
 
  349            using base = notification_queue_impl_base< std::tuple< Ts... >, C + 1 >;
 
  350            using impl = notification_queue_impl< Size, C >;
 
  352            bool queue_notification( std::size_t idx )
 
  355                    ? impl::queue_notification( idx )
 
  356                    : base::queue_notification( idx - Size );
 
  359            bool queue_indication( std::size_t idx )
 
  362                    ? impl::queue_indication( idx )
 
  363                    : base::queue_indication( idx - Size );
 
  366            std::pair< notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation( std::size_t offset, std::size_t& outstanding_confirmation )
 
  368                auto result = impl::dequeue_indication_or_confirmation( offset, outstanding_confirmation );
 
  370                if ( result.first != notification_queue_entry_type::empty )
 
  375                result = base::dequeue_indication_or_confirmation( offset + Size, outstanding_confirmation );
 
  380            void clear_indications_and_confirmations()
 
  382                impl::clear_indications_and_confirmations();
 
  383                base::clear_indications_and_confirmations();
 
class responsible to keep track of those characteristics that have outstanding notifications or indic...
Definition: notification_queue.hpp:47
std::pair< details::notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation()
return a next notification or indication to be send.
Definition: notification_queue.hpp:150
bool queue_indication(std::size_t index)
queue the indexed characteristic for indication
Definition: notification_queue.hpp:138
void clear_indications_and_confirmations()
removes all entries from the queue
Definition: notification_queue.hpp:158
notification_queue(Args... mixin_arguments)
constructs an empty notification_queue_impl
Definition: notification_queue.hpp:125
bool queue_notification(std::size_t index)
queue the indexed characteristic for notification
Definition: notification_queue.hpp:132
void indication_confirmed()
to be called, when a ATT Handle Value Confirmation was received.
Definition: notification_queue.hpp:144