@@ -132,6 +132,8 @@ static struct {
132
132
133
133
uint8_t volatile ticker_id_prepare ;
134
134
uint8_t volatile ticker_id_event ;
135
+ uint8_t volatile ticker_id_stop ;
136
+
135
137
enum role volatile role ;
136
138
enum state state ;
137
139
@@ -217,6 +219,10 @@ static uint16_t const gc_lookup_ppm[] = { 500, 250, 150, 100, 75, 50, 30, 20 };
217
219
218
220
static void common_init (void );
219
221
static 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 );
220
226
static void event_inactive (uint32_t ticks_at_expire , uint32_t remainder ,
221
227
uint16_t lazy , void * context );
222
228
static void adv_setup (void );
@@ -739,23 +745,21 @@ static inline uint32_t isr_rx_adv(uint8_t devmatch_ok, uint8_t irkmatch_ok,
739
745
ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
740
746
RADIO_TICKER_USER_ID_WORKER ,
741
747
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__ );
745
751
746
752
/* Stop Direct Adv Stopper */
747
753
_pdu_adv = (struct pdu_adv * )& _radio .advertiser .adv_data .data
748
754
[_radio .advertiser .adv_data .first ][0 ];
749
755
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 );
759
763
}
760
764
761
765
/* Start Slave */
@@ -947,21 +951,23 @@ static inline uint32_t isr_rx_obs(uint8_t irkmatch_id, uint8_t rssi_ready)
947
951
conn -> hdr .ticks_xtal_to_start :
948
952
conn -> hdr .ticks_active_to_start ;
949
953
950
- /* Stop Observer and start Master */
954
+ /* Stop Observer */
951
955
ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
952
956
RADIO_TICKER_USER_ID_WORKER ,
953
957
RADIO_TICKER_ID_OBS ,
954
- ticker_success_assert ,
958
+ ticker_stop_obs_assert ,
955
959
(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 */
965
971
ticker_status =
966
972
ticker_start (RADIO_TICKER_INSTANCE_ID_RADIO ,
967
973
RADIO_TICKER_USER_ID_WORKER ,
@@ -2306,16 +2312,25 @@ static inline uint32_t isr_close_adv(void)
2306
2312
/** @todo use random 0-10 */
2307
2313
random_delay = 10 ;
2308
2314
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
+ */
2309
2321
ticker_status =
2310
2322
ticker_update (RADIO_TICKER_INSTANCE_ID_RADIO ,
2311
2323
RADIO_TICKER_USER_ID_WORKER ,
2312
2324
RADIO_TICKER_ID_ADV ,
2313
- TICKER_US_TO_TICKS (random_delay * 1000 ),
2325
+ TICKER_US_TO_TICKS (random_delay *
2326
+ 1000 ),
2314
2327
0 , 0 , 0 , 0 , 0 ,
2315
- ticker_success_assert ,
2328
+ ticker_update_adv_assert ,
2316
2329
(void * )__LINE__ );
2317
2330
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 ));
2319
2334
}
2320
2335
}
2321
2336
@@ -2343,20 +2358,16 @@ static inline uint32_t isr_close_obs(void)
2343
2358
2344
2359
radio_tmr_end_capture ();
2345
2360
} else {
2346
- uint32_t ticker_status ;
2347
-
2348
2361
radio_filter_disable ();
2349
2362
2350
2363
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 );
2360
2371
}
2361
2372
}
2362
2373
@@ -2631,18 +2642,25 @@ static inline void isr_close_conn(void)
2631
2642
if ((ticks_drift_plus != 0 ) || (ticks_drift_minus != 0 ) ||
2632
2643
(lazy != 0 ) || (force != 0 )) {
2633
2644
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
+ */
2635
2654
ticker_status =
2636
2655
ticker_update (RADIO_TICKER_INSTANCE_ID_RADIO ,
2637
2656
RADIO_TICKER_USER_ID_WORKER ,
2638
- RADIO_TICKER_ID_FIRST_CONNECTION +
2639
- _radio .conn_curr -> handle ,
2657
+ ticker_id ,
2640
2658
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 );
2644
2661
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 ));
2646
2664
}
2647
2665
}
2648
2666
@@ -2665,6 +2683,20 @@ static inline void isr_radio_state_close(void)
2665
2683
break ;
2666
2684
2667
2685
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
+
2668
2700
default :
2669
2701
LL_ASSERT (0 );
2670
2702
break ;
@@ -2783,6 +2815,60 @@ static void ticker_success_assert(uint32_t status, void *params)
2783
2815
LL_ASSERT (status == TICKER_STATUS_SUCCESS );
2784
2816
}
2785
2817
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
+
2786
2872
static void mayfly_radio_active (void * params )
2787
2873
{
2788
2874
static uint8_t s_active ;
@@ -3767,7 +3853,7 @@ static void event_common_prepare(uint32_t ticks_at_expire,
3767
3853
#endif
3768
3854
#undef RADIO_DEFERRED_PREEMPT
3769
3855
3770
- /** Handle change in _ticks_active_to_start */
3856
+ /** Handle change in _ticks_active_to_start */
3771
3857
if (_radio .ticks_active_to_start != _ticks_active_to_start ) {
3772
3858
uint32_t ticks_to_start_new =
3773
3859
((_radio .ticks_active_to_start <
@@ -6917,6 +7003,10 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
6917
7003
break ;
6918
7004
}
6919
7005
7006
+ LL_ASSERT (!_radio .ticker_id_stop );
7007
+
7008
+ _radio .ticker_id_stop = ticker_id_primary ;
7009
+
6920
7010
/* Step 1: Is Primary started? Stop the Primary ticker */
6921
7011
ticker_status =
6922
7012
ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
@@ -6938,7 +7028,7 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
6938
7028
}
6939
7029
6940
7030
if (ticker_status != TICKER_STATUS_SUCCESS ) {
6941
- return 1 ;
7031
+ goto role_disable_cleanup ;
6942
7032
}
6943
7033
6944
7034
/* Inside our event, gracefully handle XTAL and Radio actives */
@@ -6949,7 +7039,14 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
6949
7039
ticks_xtal_to_start , ticks_active_to_start );
6950
7040
}
6951
7041
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 ;
6953
7050
}
6954
7051
6955
7052
uint32_t radio_adv_enable (uint16_t interval , uint8_t chl_map ,
0 commit comments