@@ -132,6 +132,8 @@ static struct {
132132
133133 uint8_t volatile ticker_id_prepare ;
134134 uint8_t volatile ticker_id_event ;
135+ uint8_t volatile ticker_id_stop ;
136+
135137 enum role volatile role ;
136138 enum state state ;
137139
@@ -217,6 +219,10 @@ static uint16_t const gc_lookup_ppm[] = { 500, 250, 150, 100, 75, 50, 30, 20 };
217219
218220static void common_init (void );
219221static void ticker_success_assert (uint32_t status , void * params );
222+ static void ticker_stop_adv_assert (uint32_t status , void * params );
223+ static void ticker_stop_obs_assert (uint32_t status , void * params );
224+ static void ticker_update_adv_assert (uint32_t status , void * params );
225+ static void ticker_update_slave_assert (uint32_t status , void * params );
220226static void event_inactive (uint32_t ticks_at_expire , uint32_t remainder ,
221227 uint16_t lazy , void * context );
222228static void adv_setup (void );
@@ -739,23 +745,21 @@ static inline uint32_t isr_rx_adv(uint8_t devmatch_ok, uint8_t irkmatch_ok,
739745 ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
740746 RADIO_TICKER_USER_ID_WORKER ,
741747 RADIO_TICKER_ID_ADV ,
742- ticker_success_assert , ( void * ) __LINE__ );
743- LL_ASSERT (( ticker_status == TICKER_STATUS_SUCCESS ) ||
744- (ticker_status == TICKER_STATUS_BUSY ) );
748+ ticker_stop_adv_assert ,
749+ ( void * ) __LINE__ );
750+ ticker_stop_adv_assert (ticker_status , ( void * ) __LINE__ );
745751
746752 /* Stop Direct Adv Stopper */
747753 _pdu_adv = (struct pdu_adv * )& _radio .advertiser .adv_data .data
748754 [_radio .advertiser .adv_data .first ][0 ];
749755 if (_pdu_adv -> type == PDU_ADV_TYPE_DIRECT_IND ) {
750- ticker_status =
751- ticker_stop (
752- RADIO_TICKER_INSTANCE_ID_RADIO ,
753- RADIO_TICKER_USER_ID_WORKER ,
754- RADIO_TICKER_ID_ADV_STOP ,
755- 0 , /* @todo ticker_success_assert */
756- 0 /* @todo (void *) __LINE__*/ );
757- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
758- (ticker_status == TICKER_STATUS_BUSY ));
756+ /* Advertiser stop can expire while here in this ISR.
757+ * Deferred attempt to stop can fail as it would have
758+ * expired, hence ignore failure.
759+ */
760+ ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
761+ RADIO_TICKER_USER_ID_WORKER ,
762+ RADIO_TICKER_ID_ADV_STOP , NULL , NULL );
759763 }
760764
761765 /* Start Slave */
@@ -947,21 +951,23 @@ static inline uint32_t isr_rx_obs(uint8_t irkmatch_id, uint8_t rssi_ready)
947951 conn -> hdr .ticks_xtal_to_start :
948952 conn -> hdr .ticks_active_to_start ;
949953
950- /* Stop Observer and start Master */
954+ /* Stop Observer */
951955 ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
952956 RADIO_TICKER_USER_ID_WORKER ,
953957 RADIO_TICKER_ID_OBS ,
954- ticker_success_assert ,
958+ ticker_stop_obs_assert ,
955959 (void * )__LINE__ );
956- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
957- (ticker_status == TICKER_STATUS_BUSY ));
958- ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
959- RADIO_TICKER_USER_ID_WORKER ,
960- RADIO_TICKER_ID_OBS_STOP ,
961- 0 , /* @todo ticker_success_assert */
962- 0 /* @todo (void *) __LINE__ */ );
963- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
964- (ticker_status == TICKER_STATUS_BUSY ));
960+ ticker_stop_obs_assert (ticker_status , (void * )__LINE__ );
961+
962+ /* Observer stop can expire while here in this ISR.
963+ * Deferred attempt to stop can fail as it would have
964+ * expired, hence ignore failure.
965+ */
966+ ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
967+ RADIO_TICKER_USER_ID_WORKER ,
968+ RADIO_TICKER_ID_OBS_STOP , NULL , NULL );
969+
970+ /* Start master */
965971 ticker_status =
966972 ticker_start (RADIO_TICKER_INSTANCE_ID_RADIO ,
967973 RADIO_TICKER_USER_ID_WORKER ,
@@ -2306,16 +2312,25 @@ static inline uint32_t isr_close_adv(void)
23062312 /** @todo use random 0-10 */
23072313 random_delay = 10 ;
23082314
2315+ /* Call to ticker_update can fail under the race
2316+ * condition where in the Adv role is being stopped but
2317+ * at the same time it is preempted by Adv event that
2318+ * gets into close state. Accept failure when Adv role
2319+ * is being stopped.
2320+ */
23092321 ticker_status =
23102322 ticker_update (RADIO_TICKER_INSTANCE_ID_RADIO ,
23112323 RADIO_TICKER_USER_ID_WORKER ,
23122324 RADIO_TICKER_ID_ADV ,
2313- TICKER_US_TO_TICKS (random_delay * 1000 ),
2325+ TICKER_US_TO_TICKS (random_delay *
2326+ 1000 ),
23142327 0 , 0 , 0 , 0 , 0 ,
2315- ticker_success_assert ,
2328+ ticker_update_adv_assert ,
23162329 (void * )__LINE__ );
23172330 LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
2318- (ticker_status == TICKER_STATUS_BUSY ));
2331+ (ticker_status == TICKER_STATUS_BUSY ) ||
2332+ (_radio .ticker_id_stop ==
2333+ RADIO_TICKER_ID_ADV ));
23192334 }
23202335 }
23212336
@@ -2343,20 +2358,16 @@ static inline uint32_t isr_close_obs(void)
23432358
23442359 radio_tmr_end_capture ();
23452360 } else {
2346- uint32_t ticker_status ;
2347-
23482361 radio_filter_disable ();
23492362
23502363 if (_radio .state == STATE_ABORT ) {
2351- ticker_status =
2352- ticker_stop (
2353- RADIO_TICKER_INSTANCE_ID_RADIO ,
2354- RADIO_TICKER_USER_ID_WORKER ,
2355- RADIO_TICKER_ID_OBS_STOP ,
2356- 0 /** @todo ticker_success_assert */ ,
2357- 0 /** @todo (void *) __LINE__ */ );
2358- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
2359- (ticker_status == TICKER_STATUS_BUSY ));
2364+ /* Observer stop can expire while here in this ISR.
2365+ * Deferred attempt to stop can fail as it would have
2366+ * expired, hence ignore failure.
2367+ */
2368+ ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
2369+ RADIO_TICKER_USER_ID_WORKER ,
2370+ RADIO_TICKER_ID_OBS_STOP , NULL , NULL );
23602371 }
23612372 }
23622373
@@ -2631,18 +2642,25 @@ static inline void isr_close_conn(void)
26312642 if ((ticks_drift_plus != 0 ) || (ticks_drift_minus != 0 ) ||
26322643 (lazy != 0 ) || (force != 0 )) {
26332644 uint32_t ticker_status ;
2634-
2645+ uint8_t ticker_id = RADIO_TICKER_ID_FIRST_CONNECTION +
2646+ _radio .conn_curr -> handle ;
2647+
2648+ /* Call to ticker_update can fail under the race
2649+ * condition where in the Slave role is being stopped but
2650+ * at the same time it is preempted by Slave event that
2651+ * gets into close state. Accept failure when Slave role
2652+ * is being stopped.
2653+ */
26352654 ticker_status =
26362655 ticker_update (RADIO_TICKER_INSTANCE_ID_RADIO ,
26372656 RADIO_TICKER_USER_ID_WORKER ,
2638- RADIO_TICKER_ID_FIRST_CONNECTION +
2639- _radio .conn_curr -> handle ,
2657+ ticker_id ,
26402658 ticks_drift_plus , ticks_drift_minus , 0 , 0 ,
2641- lazy , force ,
2642- 0 /** @todo ticker_success_assert */ ,
2643- 0 /** @todo (void *) __LINE__ */ );
2659+ lazy , force , ticker_update_slave_assert ,
2660+ (void * )(uint32_t )ticker_id );
26442661 LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
2645- (ticker_status == TICKER_STATUS_BUSY ));
2662+ (ticker_status == TICKER_STATUS_BUSY ) ||
2663+ (_radio .ticker_id_stop == ticker_id ));
26462664 }
26472665}
26482666
@@ -2665,6 +2683,20 @@ static inline void isr_radio_state_close(void)
26652683 break ;
26662684
26672685 case ROLE_NONE :
2686+ /* If a role closes graceful while it is being stopped, then
2687+ * Radio ISR will be triggered to process the stop state with
2688+ * no active role at that instance in time.
2689+ * Just reset the state to none. The role has gracefully closed
2690+ * before this ISR run.
2691+ * The above applies to aborting a role event too.
2692+ */
2693+ LL_ASSERT ((_radio .state == STATE_STOP ) ||
2694+ (_radio .state == STATE_ABORT ));
2695+
2696+ _radio .state = STATE_NONE ;
2697+
2698+ return ;
2699+
26682700 default :
26692701 LL_ASSERT (0 );
26702702 break ;
@@ -2783,6 +2815,60 @@ static void ticker_success_assert(uint32_t status, void *params)
27832815 LL_ASSERT (status == TICKER_STATUS_SUCCESS );
27842816}
27852817
2818+ static void ticker_stop_adv_assert (uint32_t status , void * params )
2819+ {
2820+ ARG_UNUSED (params );
2821+
2822+ if (status == TICKER_STATUS_FAILURE ) {
2823+ if (_radio .ticker_id_stop == RADIO_TICKER_ID_ADV ) {
2824+ /* ticker_stop failed due to race condition
2825+ * while in role_disable. Let the role_disable
2826+ * be made aware of, so it can return failure
2827+ * (to stop Adv role as it is now transitioned
2828+ * to Slave role).
2829+ */
2830+ _radio .ticker_id_stop = 0 ;
2831+ } else {
2832+ LL_ASSERT (0 );
2833+ }
2834+ }
2835+ }
2836+
2837+ static void ticker_stop_obs_assert (uint32_t status , void * params )
2838+ {
2839+ ARG_UNUSED (params );
2840+
2841+ if (status == TICKER_STATUS_FAILURE ) {
2842+ if (_radio .ticker_id_stop == RADIO_TICKER_ID_OBS ) {
2843+ /* ticker_stop failed due to race condition
2844+ * while in role_disable. Let the role_disable
2845+ * be made aware of, so it can return failure
2846+ * (to stop Obs role as it is now transitioned
2847+ * to Master role).
2848+ */
2849+ _radio .ticker_id_stop = 0 ;
2850+ } else {
2851+ LL_ASSERT (0 );
2852+ }
2853+ }
2854+ }
2855+
2856+ static void ticker_update_adv_assert (uint32_t status , void * params )
2857+ {
2858+ ARG_UNUSED (params );
2859+
2860+ LL_ASSERT ((status == TICKER_STATUS_SUCCESS ) ||
2861+ (_radio .ticker_id_stop == RADIO_TICKER_ID_ADV ));
2862+ }
2863+
2864+ static void ticker_update_slave_assert (uint32_t status , void * params )
2865+ {
2866+ uint8_t ticker_id = (uint32_t )params & 0xFF ;
2867+
2868+ LL_ASSERT ((status == TICKER_STATUS_SUCCESS ) ||
2869+ (_radio .ticker_id_stop == ticker_id ));
2870+ }
2871+
27862872static void mayfly_radio_active (void * params )
27872873{
27882874 static uint8_t s_active ;
@@ -3767,7 +3853,7 @@ static void event_common_prepare(uint32_t ticks_at_expire,
37673853#endif
37683854#undef RADIO_DEFERRED_PREEMPT
37693855
3770- /** Handle change in _ticks_active_to_start */
3856+ /** Handle change in _ticks_active_to_start */
37713857 if (_radio .ticks_active_to_start != _ticks_active_to_start ) {
37723858 uint32_t ticks_to_start_new =
37733859 ((_radio .ticks_active_to_start <
@@ -6917,6 +7003,10 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
69177003 break ;
69187004 }
69197005
7006+ LL_ASSERT (!_radio .ticker_id_stop );
7007+
7008+ _radio .ticker_id_stop = ticker_id_primary ;
7009+
69207010 /* Step 1: Is Primary started? Stop the Primary ticker */
69217011 ticker_status =
69227012 ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
@@ -6938,7 +7028,7 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
69387028 }
69397029
69407030 if (ticker_status != TICKER_STATUS_SUCCESS ) {
6941- return 1 ;
7031+ goto role_disable_cleanup ;
69427032 }
69437033
69447034 /* Inside our event, gracefully handle XTAL and Radio actives */
@@ -6949,7 +7039,14 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
69497039 ticks_xtal_to_start , ticks_active_to_start );
69507040 }
69517041
6952- return 0 ;
7042+ if (!_radio .ticker_id_stop ) {
7043+ ticker_status = TICKER_STATUS_FAILURE ;
7044+ }
7045+
7046+ role_disable_cleanup :
7047+ _radio .ticker_id_stop = 0 ;
7048+
7049+ return ticker_status ;
69537050}
69547051
69557052uint32_t radio_adv_enable (uint16_t interval , uint8_t chl_map ,
0 commit comments