1#ifndef BLUETOE_LINK_LAYER_CONNECTION_EVENT_CALLBACK_HPP
2#define BLUETOE_LINK_LAYER_CONNECTION_EVENT_CALLBACK_HPP
4#include <bluetoe/ll_meta_types.hpp>
5#include <bluetoe/delta_time.hpp>
11 struct connection_event_callback_meta_type : details::valid_link_layer_option_meta_type {};
12 struct synchronized_connection_event_callback_meta_type : details::valid_link_layer_option_meta_type {};
13 struct check_synchronized_connection_event_callback_meta_type : details::valid_link_layer_option_meta_type {};
15 struct default_connection_event_callback
17 static void call_connection_event_callback(
const delta_time& )
21 typedef connection_event_callback_meta_type meta_type;
40 template <
typename T, T& Obj,
unsigned RequiredTimeMS = 0 >
44 static void call_connection_event_callback(
const delta_time& time_till_next_event )
46 if ( RequiredTimeMS == 0 || time_till_next_event >=
delta_time::msec( RequiredTimeMS ) )
47 Obj.ll_connection_event_happend();
50 typedef details::connection_event_callback_meta_type meta_type;
149 template <
typename T, T& Obj,
unsigned MaximumPeriodUS,
int PhaseShiftUS,
unsigned MaximumExecutionTimeUS = 100 >
171 template <
typename LinkLayer >
177 static_assert( LinkLayer::hardware_supports_synchronized_user_timer,
"choosen binding does not support the use of user timer!" );
180 void stop_synchronized_connection_event_callbacks()
185 link_layer().cancel_synchronized_user_timer();
188 void restart_synchronized_connection_event_callbacks()
192 num_intervals_since_anchor_moved_ = 0;
195 link_layer().restart_user_timer();
198 void force_synchronized_connection_event_callback()
203 void synchronized_connection_event_callback_new_connection( delta_time connection_interval )
208 connection_value_ =
typename T::connection();
209 instance_ = PhaseShiftUS > 0 ? 1 : 0;
212 calculate_effective_period( connection_interval );
213 call_ll_connect< T >( connection_interval, connection_value_ );
214 link_layer().cancel_synchronized_user_timer();
215 setup_timer( first_timeout() );
218 void synchronized_connection_event_callback_start_changing_connection()
220 link_layer().cancel_synchronized_user_timer();
223 void synchronized_connection_event_callback_connection_changed( delta_time connection_interval )
228 instance_ = PhaseShiftUS > 0 ? 1 : 0;
231 calculate_effective_period( connection_interval );
232 call_ll_update< T >( connection_interval );
233 setup_timer( first_timeout() );
236 void synchronized_connection_event_callback_disconnect()
238 call_ll_disconnect< T >( 0 );
239 link_layer().cancel_synchronized_user_timer();
242 void synchronized_connection_event_callback_timeout(
bool anchor_moved )
253 latency_ = latency_ == 0
254 ? Obj.ll_synchronized_callback( instance_, connection_value_ )
258 instance_ = ( instance_ + 1 ) % num_calls_;
262 static constexpr unsigned first_interval_after_anchor = ( PhaseShiftUS < 0 )
266 num_intervals_since_anchor_moved_ = anchor_moved
267 ? first_interval_after_anchor
268 : num_intervals_since_anchor_moved_ + 1;
270 setup_timer( first_timeout() + num_intervals_since_anchor_moved_ * effective_period_ );
274 template <
class TT >
276 ->
decltype(&TT::ll_synchronized_callback_connect)
278 con = Obj.ll_synchronized_callback_connect( connection_interval, num_calls_ );
283 template <
class TT >
284 void call_ll_connect( ... )
288 template <
class TT >
289 auto call_ll_disconnect(
int ) ->
decltype(&TT::ll_synchronized_callback_disconnect)
291 Obj.ll_synchronized_callback_disconnect( connection_value_ );
295 template <
class TT >
296 void call_ll_disconnect( ... )
300 template <
class TT >
304 Obj.ll_synchronized_callback_period_update( connection_interval, num_calls_, connection_value_ );
309 template <
class TT >
310 void call_ll_update( ... )
314 void setup_timer( delta_time dt )
316 const bool setup = link_layer().schedule_synchronized_user_timer( dt, delta_time( MaximumExecutionTimeUS ) );
317 static_cast< void >( setup );
321 LinkLayer& link_layer()
323 return *
static_cast< LinkLayer*
>( this );
326 void calculate_effective_period( delta_time connection_interval )
328 const auto interval_us = connection_interval.usec();
330 if ( interval_us > MaximumPeriodUS )
332 num_calls_ = ( interval_us + MaximumPeriodUS - 1 ) / MaximumPeriodUS;
334 effective_period_ = delta_time( interval_us / num_calls_ );
339 num_intervals_ = MaximumPeriodUS / interval_us;
340 effective_period_ = delta_time( num_intervals_ * interval_us );
343 num_intervals_since_anchor_moved_ = 0;
345 assert( effective_period_.usec() <= MaximumPeriodUS );
348 delta_time first_timeout()
const
350 return PhaseShiftUS < 0
351 ? effective_period_ - delta_time::usec( -PhaseShiftUS )
352 : effective_period_ + delta_time::usec( PhaseShiftUS );
355 delta_time effective_period_;
364 unsigned num_intervals_;
366 unsigned num_intervals_since_anchor_moved_;
368 typename T::connection connection_value_;
370 volatile bool stopped_;
371 volatile bool force_;
374 typedef details::synchronized_connection_event_callback_meta_type meta_type;
386 template <
typename LinkLayer >
388 void synchronized_connection_event_callback_new_connection(
delta_time )
392 void synchronized_connection_event_callback_start_changing_connection()
396 void synchronized_connection_event_callback_connection_changed(
delta_time )
400 void synchronized_connection_event_callback_timeout(
bool )
404 void synchronized_connection_event_callback_disconnect()
409 typedef details::synchronized_connection_event_callback_meta_type meta_type;
426 template <
unsigned ExpectedMinimumInterval_US >
430 template <
typename Radio >
435 template <
typename Radio,
typename T, T& Obj,
unsigned MaximumPeriodUS,
int PhaseShiftUS,
unsigned MaximumExecutionTimeUS >
438 static_assert( MaximumPeriodUS <= ExpectedMinimumInterval_US,
439 "To guaranty the timely execution of the callback, the MaximumPeriodUS must be small or equal to the minimum connection interval!" );
441 static_assert( PhaseShiftUS < 0,
442 "In order to make sure, that the callback is finished when the connection event starts, the callback must start prior to the connection event!" );
444 static_assert( -PhaseShiftUS >= Radio::connection_event_setup_time_us,
445 "PhaseShiftUS must start before the radios setup time." );
447 static_assert( -PhaseShiftUS >= Radio::connection_event_setup_time_us + MaximumExecutionTimeUS,
448 "Callback execution must end before setup time of the configured radio." );
450 static_assert( MaximumPeriodUS / 2 >= MaximumExecutionTimeUS,
451 "In worst case, the effective period of the callback invocation is half the requested period and thus must still be large enough for the expected runtimer of the callback." );
453 static_assert( -PhaseShiftUS < MaximumPeriodUS / 2,
454 "In worst case, the effective period of the callback invocation is half the requested period and thus must still be small than the phase shift." );
457 using meta_type = details::check_synchronized_connection_event_callback_meta_type;
472 template <
typename Radio,
class CBs >
473 static void check(
const CBs& )
477 using meta_type = details::check_synchronized_connection_event_callback_meta_type;
positiv time quantum used to express distance in time.
Definition: delta_time.hpp:14
static delta_time msec(std::uint32_t msec)
creates a delta_time from a positive number of ms (milliseconds).
link layer implementation
Definition: link_layer.hpp:489
install a callback that will be called, when a connection event happened.
Definition: connection_event_callback.hpp:42
no compiler time parameter check
Definition: connection_event_callback.hpp:470
Do not user synchronized connection event callbacks.
Definition: connection_event_callback.hpp:384
if this parameter is given to the link layer, some compile time checks are done.
Definition: connection_event_callback.hpp:428
Install a callback that will be called with a maximum period synchronized to the connection events of...
Definition: connection_event_callback.hpp:151
void stop_synchronized_connection_event_callbacks()
stop the call of the synchronized callbacks.
void force_synchronized_connection_event_callback()
Ask Bluetoe to ignore the last return value of ll_synchronized_callback() and call the callback at th...
void restart_synchronized_connection_event_callbacks()
restart the invocation of synchronized callbacks, after they where stopped.