1#ifndef BLUETOE_LINK_LAYER_PERIPHERAL_LATENCY_HPP
2#define BLUETOE_LINK_LAYER_PERIPHERAL_LATENCY_HPP
4#include <bluetoe/ll_meta_types.hpp>
5#include <bluetoe/connection_events.hpp>
24 struct peripheral_latency_meta_type {};
30 static constexpr auto maximum_link_layer_peripheral_latency = 499;
103 template < peripheral_latency >
104 struct wrap_latency_option {};
106 template < peripheral_latency RequestedFeature, peripheral_latency ... Options >
107 struct feature_enabled
110 bluetoe::details::has_option< wrap_latency_option< RequestedFeature >, wrap_latency_option< Options >... >::value,
112 std::false_type >::type;
114 static constexpr bool value = type::value;
141 details::peripheral_latency_meta_type,
142 details::valid_link_layer_option_meta_type {};
172 template <
typename ... Configurations >
182 template <
typename NewConfig >
187 details::peripheral_latency_meta_type,
188 details::valid_link_layer_option_meta_type {};
203 peripheral_latency::listen_always
224 peripheral_latency::listen_if_pending_transmit_data,
225 peripheral_latency::listen_if_last_received_had_more_data
244 peripheral_latency::listen_if_last_received_not_empty,
245 peripheral_latency::listen_if_last_received_had_more_data
260 peripheral_latency::listen_if_pending_transmit_data,
261 peripheral_latency::listen_if_unacknowledged_data,
262 peripheral_latency::listen_if_last_received_not_empty,
263 peripheral_latency::listen_if_last_transmitted_not_empty,
264 peripheral_latency::listen_if_last_received_had_more_data
277 template <
class Base >
278 class connection_state_base
284 unsigned current_channel_index()
const
286 return channel_index_;
292 std::uint16_t connection_event_counter()
const
294 return event_counter_;
306 return time_since_last_event_;
312 void plan_next_connection_event_after_timeout(
317 time_since_last_event_ += connection_interval;
323 void plan_next_connection_event(
324 std::uint16_t connection_peripheral_latency,
327 std::pair< bool, std::uint16_t > pending_instance )
329 if ( ( base().
template peripheral_latency_feature< peripheral_latency::listen_if_unacknowledged_data >() and last_event_events.
unacknowledged_data )
330 or ( base().
template peripheral_latency_feature< peripheral_latency::listen_if_last_received_not_empty >() and last_event_events.
last_received_not_empty )
331 or ( base().
template peripheral_latency_feature< peripheral_latency::listen_if_last_transmitted_not_empty >() and last_event_events.
last_transmitted_not_empty )
332 or ( base().
template peripheral_latency_feature< peripheral_latency::listen_if_last_received_had_more_data >() and last_event_events.
last_received_had_more_data )
333 or ( base().
template peripheral_latency_feature< peripheral_latency::listen_if_pending_transmit_data >() and last_event_events.
pending_outgoing_data )
334 or ( base().
template peripheral_latency_feature< peripheral_latency::listen_always >() )
338 connection_peripheral_latency = 0;
341 ++connection_peripheral_latency;
343 if ( pending_instance.first )
345 const std::uint16_t instance_distance = event_counter_ < pending_instance.second
346 ? pending_instance.second - event_counter_
347 : pending_instance.second + ~event_counter_ + 1;
349 if ( instance_distance > 0 )
350 connection_peripheral_latency = std::min( connection_peripheral_latency, instance_distance );
354 event_counter_ += connection_peripheral_latency;
355 time_since_last_event_ = connection_peripheral_latency * connection_interval;
357 base().disarmable_connection_state_last_latency( connection_peripheral_latency );
371 template <
class Radio >
372 bool reschedule_on_pending_data( Radio&,
delta_time )
380 void reset_connection_state()
385 base().disarmable_connection_state_last_latency( 1 );
388 void peripheral_latency_move_connection_event(
int count,
delta_time connection_iterval )
390 assert( count <= 0 );
391 assert( -count <= maximum_link_layer_peripheral_latency );
399 event_counter_ += count;
401 time_since_last_event_ -= -count * connection_iterval;
405 unsigned channel_index_;
406 std::uint16_t event_counter_;
411 return *
static_cast< Base*
>( this );
415 template <
typename DisarmSupport,
typename State >
416 class disarmable_connection_state;
418 template <
typename State >
419 class disarmable_connection_state< std::true_type, State >
422 void disarmable_connection_state_last_latency(
int l )
429 template <
class Radio >
430 bool reschedule_on_pending_data_impl( Radio& radio,
delta_time connection_iterval )
434 if ( last_latency_ == 1 )
437 const std::pair< bool, bluetoe::link_layer::delta_time > rc = radio.disarm_connection_event();
441 assert( !connection_iterval.
zero() );
443 const unsigned times = std::max( 1u, ( rc.second + connection_iterval -
delta_time( 1 ) ) / connection_iterval );
446 const int moved = std::min< int >( times, last_latency_ );
447 static_cast< State*
>( this )->peripheral_latency_move_connection_event( moved - last_latency_, connection_iterval );
459 template <
typename State >
460 class disarmable_connection_state< std::false_type, State >
463 void disarmable_connection_state_last_latency(
int ) {}
466 template <
class Radio >
467 bool reschedule_on_pending_data_impl( Radio&,
delta_time )
476 template <
typename Options >
477 class peripheral_latency_state;
481 :
public connection_state_base< peripheral_latency_state< peripheral_latency_configuration< Options... > > >
482 ,
public disarmable_connection_state<
483 typename feature_enabled< peripheral_latency::listen_if_pending_transmit_data, Options... >::type,
484 peripheral_latency_state< peripheral_latency_configuration< Options... > > >
487 static constexpr bool listen_always_given = details::feature_enabled< peripheral_latency::listen_always, Options... >::value;
488 static constexpr bool other_parameters_given =
sizeof...( Options ) > 1;
490 static_assert( !( listen_always_given and other_parameters_given ),
491 "if `listen_always` is given, there is no point in adding addition options" );
504 template <
class Radio >
505 bool reschedule_on_pending_data( Radio& radio,
delta_time connection_iterval )
507 return this->reschedule_on_pending_data_impl( radio, connection_iterval );
510 template < peripheral_latency RequestedFeature >
511 constexpr bool peripheral_latency_feature()
const
513 return feature_enabled< RequestedFeature, Options... >::type::value;
518 template <
typename ... Configurations >
519 struct listen_if_pending_transmit_data_is_part_of_any_configuration
521 using type = std::true_type;
524 template <
typename ... Configurations >
526 :
public connection_state_base< peripheral_latency_state< peripheral_latency_configuration_set< Configurations... > > >
527 ,
public disarmable_connection_state<
528 typename listen_if_pending_transmit_data_is_part_of_any_configuration< Configurations... >::type,
529 peripheral_latency_state< peripheral_latency_configuration_set< Configurations... > > >
532 static_assert(
sizeof...(Configurations) > 0,
"At least on configuration is required!" );
537 peripheral_latency_state()
538 : current_configuration_( 0 )
542 template <
class Radio >
543 bool reschedule_on_pending_data( Radio& radio,
delta_time connection_iterval )
545 return this->reschedule_on_pending_data_impl( radio, connection_iterval );
548 template <
typename NewConfig >
549 void change_peripheral_latency()
551 using new_index = bluetoe::details::index_of< NewConfig, Configurations... >;
552 static_assert( new_index::value <
sizeof...( Configurations ),
"given NewConfig is not member of Configurations..." );
554 current_configuration_ = new_index::value;
557 template < peripheral_latency RequestedFeature >
558 bool peripheral_latency_feature()
const;
561 template < peripheral_latency RequestedFeature >
562 bool runtime_feature()
const;
564 int current_configuration_;
567 template < peripheral_latency RequestedFeature,
typename Configuration >
568 struct has_feature_enabled_impl;
573 static constexpr bool value = feature_enabled< RequestedFeature, Options... >::value;
578 struct is_part_of_all_configurations
580 template <
typename Configuration >
581 using has_feature_enabled = has_feature_enabled_impl< RequestedFeature, Configuration >;
583 static constexpr bool value =
584 bluetoe::details::count_if<
585 std::tuple< Configurations... >,
587 >::value ==
sizeof...( Configurations );
591 struct is_part_of_no_configurations
593 template <
typename Configuration >
594 using has_feature_enabled = has_feature_enabled_impl< RequestedFeature, Configuration >;
596 static constexpr bool value =
597 bluetoe::details::count_if<
598 std::tuple< Configurations... >,
603 template <
typename ... Configurations >
604 template < peripheral_latency RequestedFeature >
609 if ( is_part_of_all_configurations< RequestedFeature, Configurations... >::value )
612 if ( is_part_of_no_configurations< RequestedFeature, Configurations... >::value )
615 return runtime_feature< RequestedFeature >();
618 template < peripheral_latency RequestedFeature >
619 struct peripheral_latency_feature_checker
621 inline explicit peripheral_latency_feature_checker(
int config )
627 template<
typename Config >
630 if ( index == 0 && has_feature_enabled_impl< RequestedFeature, Config >::value )
640 template <
typename ... Configurations >
641 template < peripheral_latency RequestedFeature >
644 peripheral_latency_feature_checker< RequestedFeature > check_feature( current_configuration_ );
646 bluetoe::details::for_< Configurations... >::
647 template each< peripheral_latency_feature_checker< RequestedFeature >& >( check_feature );
649 return check_feature.result;
static constexpr unsigned max_number_of_data_channels
Definition: channel_map.hpp:43
positiv time quantum used to express distance in time.
Definition: delta_time.hpp:14
bool zero() const
returns true, if the represented time distance is zero.
allows the peripheral latency configuration to be changed at runtime between a given set of configura...
Definition: peripheral_latency.hpp:174
void change_peripheral_latency()
change to a different peripheral latency configuration
peripheral_latency
detailed options for the peripheral latency behavior
Definition: peripheral_latency.hpp:46
@ listen_if_unacknowledged_data
listen if the link layer contains unacknowledged data.
@ listen_if_last_received_not_empty
listen to the next connection event, if the last received PDU was not empty.
@ listen_if_last_transmitted_not_empty
listen to the next connection event, if the last transmitted PDU was not empty.
@ listen_always
listen at all connection events, despite the negotiated peripheral latency value of the current conne...
@ listen_if_last_received_had_more_data
listen to the next connection event, if the last received PDU had the more data (MD) flag set.
@ listen_if_pending_transmit_data
listen at the very next connection event if bluetoe has an available PDU for sending.
set of events, that could have happend during a connection event
Definition: connection_events.hpp:14
bool unacknowledged_data
The last, not empty PDU, that was send out during the connection event was not acknowlaged by the cen...
Definition: connection_events.hpp:19
bool last_transmitted_not_empty
At the last connection event, there was at least one PDU transmitted, that was not empty.
Definition: connection_events.hpp:30
bool last_received_not_empty
At the last connection event, there was at least one not empty PDU received from the central.
Definition: connection_events.hpp:25
bool last_received_had_more_data
The last PDU received at the connection event, had the MD flag beeing set.
Definition: connection_events.hpp:35
bool error_occured
there was a CRC error at the last connection event
Definition: connection_events.hpp:45
bool pending_outgoing_data
There is pending, outgoing data.
Definition: connection_events.hpp:40
defines a peripheral configuration to be used by the link layer
Definition: peripheral_latency.hpp:138