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