@@ -134,6 +134,8 @@ static struct {
134
134
135
135
uint8_t volatile ticker_id_prepare ;
136
136
uint8_t volatile ticker_id_event ;
137
+ uint8_t volatile ticker_id_stop ;
138
+
137
139
enum role volatile role ;
138
140
enum state state ;
139
141
@@ -214,6 +216,10 @@ static uint16_t const gc_lookup_ppm[] = { 500, 250, 150, 100, 75, 50, 30, 20 };
214
216
215
217
static void common_init (void );
216
218
static void ticker_success_assert (uint32_t status , void * params );
219
+ static void ticker_stop_adv_assert (uint32_t status , void * params );
220
+ static void ticker_stop_obs_assert (uint32_t status , void * params );
221
+ static void ticker_update_adv_assert (uint32_t status , void * params );
222
+ static void ticker_update_slave_assert (uint32_t status , void * params );
217
223
static void event_inactive (uint32_t ticks_at_expire , uint32_t remainder ,
218
224
uint16_t lazy , void * context );
219
225
static void adv_setup (void );
@@ -694,23 +700,21 @@ static inline uint32_t isr_rx_adv(uint8_t devmatch_ok, uint8_t irkmatch_ok,
694
700
ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
695
701
RADIO_TICKER_USER_ID_WORKER ,
696
702
RADIO_TICKER_ID_ADV ,
697
- ticker_success_assert , ( void * ) __LINE__ );
698
- LL_ASSERT (( ticker_status == TICKER_STATUS_SUCCESS ) ||
699
- (ticker_status == TICKER_STATUS_BUSY ) );
703
+ ticker_stop_adv_assert ,
704
+ ( void * ) __LINE__ );
705
+ ticker_stop_adv_assert (ticker_status , ( void * ) __LINE__ );
700
706
701
707
/* Stop Direct Adv Stopper */
702
708
_pdu_adv = (struct pdu_adv * )& _radio .advertiser .adv_data .data
703
709
[_radio .advertiser .adv_data .first ][0 ];
704
710
if (_pdu_adv -> type == PDU_ADV_TYPE_DIRECT_IND ) {
705
- ticker_status =
706
- ticker_stop (
707
- RADIO_TICKER_INSTANCE_ID_RADIO ,
708
- RADIO_TICKER_USER_ID_WORKER ,
709
- RADIO_TICKER_ID_ADV_STOP ,
710
- 0 , /* @todo ticker_success_assert */
711
- 0 /* @todo (void *) __LINE__*/ );
712
- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
713
- (ticker_status == TICKER_STATUS_BUSY ));
711
+ /* Advertiser stop can expire while here in this ISR.
712
+ * Deferred attempt to stop can fail as it would have
713
+ * expired, hence ignore failure.
714
+ */
715
+ ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
716
+ RADIO_TICKER_USER_ID_WORKER ,
717
+ RADIO_TICKER_ID_ADV_STOP , NULL , NULL );
714
718
}
715
719
716
720
/* Start Slave */
@@ -901,21 +905,23 @@ static inline uint32_t isr_rx_obs(uint8_t irkmatch_id, uint8_t rssi_ready)
901
905
conn -> hdr .ticks_xtal_to_start :
902
906
conn -> hdr .ticks_active_to_start ;
903
907
904
- /* Stop Observer and start Master */
908
+ /* Stop Observer */
905
909
ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
906
910
RADIO_TICKER_USER_ID_WORKER ,
907
911
RADIO_TICKER_ID_OBS ,
908
- ticker_success_assert ,
912
+ ticker_stop_obs_assert ,
909
913
(void * )__LINE__ );
910
- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
911
- (ticker_status == TICKER_STATUS_BUSY ));
912
- ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
913
- RADIO_TICKER_USER_ID_WORKER ,
914
- RADIO_TICKER_ID_OBS_STOP ,
915
- 0 , /* @todo ticker_success_assert */
916
- 0 /* @todo (void *) __LINE__ */ );
917
- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
918
- (ticker_status == TICKER_STATUS_BUSY ));
914
+ ticker_stop_obs_assert (ticker_status , (void * )__LINE__ );
915
+
916
+ /* Observer stop can expire while here in this ISR.
917
+ * Deferred attempt to stop can fail as it would have
918
+ * expired, hence ignore failure.
919
+ */
920
+ ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
921
+ RADIO_TICKER_USER_ID_WORKER ,
922
+ RADIO_TICKER_ID_OBS_STOP , NULL , NULL );
923
+
924
+ /* Start master */
919
925
ticker_status =
920
926
ticker_start (RADIO_TICKER_INSTANCE_ID_RADIO ,
921
927
RADIO_TICKER_USER_ID_WORKER ,
@@ -2102,16 +2108,25 @@ static inline uint32_t isr_close_adv(void)
2102
2108
/** @todo use random 0-10 */
2103
2109
random_delay = 10 ;
2104
2110
2111
+ /* Call to ticker_update can fail under the race
2112
+ * condition where in the Adv role is being stopped but
2113
+ * at the same time it is preempted by Adv event that
2114
+ * gets into close state. Accept failure when Adv role
2115
+ * is being stopped.
2116
+ */
2105
2117
ticker_status =
2106
2118
ticker_update (RADIO_TICKER_INSTANCE_ID_RADIO ,
2107
2119
RADIO_TICKER_USER_ID_WORKER ,
2108
2120
RADIO_TICKER_ID_ADV ,
2109
- TICKER_US_TO_TICKS (random_delay * 1000 ),
2121
+ TICKER_US_TO_TICKS (random_delay *
2122
+ 1000 ),
2110
2123
0 , 0 , 0 , 0 , 0 ,
2111
- ticker_success_assert ,
2124
+ ticker_update_adv_assert ,
2112
2125
(void * )__LINE__ );
2113
2126
LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
2114
- (ticker_status == TICKER_STATUS_BUSY ));
2127
+ (ticker_status == TICKER_STATUS_BUSY ) ||
2128
+ (_radio .ticker_id_stop ==
2129
+ RADIO_TICKER_ID_ADV ));
2115
2130
}
2116
2131
}
2117
2132
@@ -2139,20 +2154,16 @@ static inline uint32_t isr_close_obs(void)
2139
2154
2140
2155
radio_tmr_end_capture ();
2141
2156
} else {
2142
- uint32_t ticker_status ;
2143
-
2144
2157
radio_filter_disable ();
2145
2158
2146
2159
if (_radio .state == STATE_ABORT ) {
2147
- ticker_status =
2148
- ticker_stop (
2149
- RADIO_TICKER_INSTANCE_ID_RADIO ,
2150
- RADIO_TICKER_USER_ID_WORKER ,
2151
- RADIO_TICKER_ID_OBS_STOP ,
2152
- 0 /** @todo ticker_success_assert */ ,
2153
- 0 /** @todo (void *) __LINE__ */ );
2154
- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
2155
- (ticker_status == TICKER_STATUS_BUSY ));
2160
+ /* Observer stop can expire while here in this ISR.
2161
+ * Deferred attempt to stop can fail as it would have
2162
+ * expired, hence ignore failure.
2163
+ */
2164
+ ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
2165
+ RADIO_TICKER_USER_ID_WORKER ,
2166
+ RADIO_TICKER_ID_OBS_STOP , NULL , NULL );
2156
2167
}
2157
2168
}
2158
2169
@@ -2423,18 +2434,25 @@ static inline void isr_close_conn(void)
2423
2434
if ((ticks_drift_plus != 0 ) || (ticks_drift_minus != 0 ) ||
2424
2435
(lazy != 0 ) || (force != 0 )) {
2425
2436
uint32_t ticker_status ;
2426
-
2437
+ uint8_t ticker_id = RADIO_TICKER_ID_FIRST_CONNECTION +
2438
+ _radio .conn_curr -> handle ;
2439
+
2440
+ /* Call to ticker_update can fail under the race
2441
+ * condition where in the Slave role is being stopped but
2442
+ * at the same time it is preempted by Slave event that
2443
+ * gets into close state. Accept failure when Slave role
2444
+ * is being stopped.
2445
+ */
2427
2446
ticker_status =
2428
2447
ticker_update (RADIO_TICKER_INSTANCE_ID_RADIO ,
2429
2448
RADIO_TICKER_USER_ID_WORKER ,
2430
- RADIO_TICKER_ID_FIRST_CONNECTION +
2431
- _radio .conn_curr -> handle ,
2449
+ ticker_id ,
2432
2450
ticks_drift_plus , ticks_drift_minus , 0 , 0 ,
2433
- lazy , force ,
2434
- 0 /** @todo ticker_success_assert */ ,
2435
- 0 /** @todo (void *) __LINE__ */ );
2451
+ lazy , force , ticker_update_slave_assert ,
2452
+ (void * )(uint32_t )ticker_id );
2436
2453
LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
2437
- (ticker_status == TICKER_STATUS_BUSY ));
2454
+ (ticker_status == TICKER_STATUS_BUSY ) ||
2455
+ (_radio .ticker_id_stop == ticker_id ));
2438
2456
}
2439
2457
}
2440
2458
@@ -2457,6 +2475,20 @@ static inline void isr_radio_state_close(void)
2457
2475
break ;
2458
2476
2459
2477
case ROLE_NONE :
2478
+ /* If a role closes graceful while it is being stopped, then
2479
+ * Radio ISR will be triggered to process the stop state with
2480
+ * no active role at that instance in time.
2481
+ * Just reset the state to none. The role has gracefully closed
2482
+ * before this ISR run.
2483
+ * The above applies to aborting a role event too.
2484
+ */
2485
+ LL_ASSERT ((_radio .state == STATE_STOP ) ||
2486
+ (_radio .state == STATE_ABORT ));
2487
+
2488
+ _radio .state = STATE_NONE ;
2489
+
2490
+ return ;
2491
+
2460
2492
default :
2461
2493
LL_ASSERT (0 );
2462
2494
break ;
@@ -2569,6 +2601,60 @@ static void ticker_success_assert(uint32_t status, void *params)
2569
2601
LL_ASSERT (status == TICKER_STATUS_SUCCESS );
2570
2602
}
2571
2603
2604
+ static void ticker_stop_adv_assert (uint32_t status , void * params )
2605
+ {
2606
+ ARG_UNUSED (params );
2607
+
2608
+ if (status == TICKER_STATUS_FAILURE ) {
2609
+ if (_radio .ticker_id_stop == RADIO_TICKER_ID_ADV ) {
2610
+ /* ticker_stop failed due to race condition
2611
+ * while in role_disable. Let the role_disable
2612
+ * be made aware of, so it can return failure
2613
+ * (to stop Adv role as it is now transitioned
2614
+ * to Slave role).
2615
+ */
2616
+ _radio .ticker_id_stop = 0 ;
2617
+ } else {
2618
+ LL_ASSERT (0 );
2619
+ }
2620
+ }
2621
+ }
2622
+
2623
+ static void ticker_stop_obs_assert (uint32_t status , void * params )
2624
+ {
2625
+ ARG_UNUSED (params );
2626
+
2627
+ if (status == TICKER_STATUS_FAILURE ) {
2628
+ if (_radio .ticker_id_stop == RADIO_TICKER_ID_OBS ) {
2629
+ /* ticker_stop failed due to race condition
2630
+ * while in role_disable. Let the role_disable
2631
+ * be made aware of, so it can return failure
2632
+ * (to stop Obs role as it is now transitioned
2633
+ * to Master role).
2634
+ */
2635
+ _radio .ticker_id_stop = 0 ;
2636
+ } else {
2637
+ LL_ASSERT (0 );
2638
+ }
2639
+ }
2640
+ }
2641
+
2642
+ static void ticker_update_adv_assert (uint32_t status , void * params )
2643
+ {
2644
+ ARG_UNUSED (params );
2645
+
2646
+ LL_ASSERT ((status == TICKER_STATUS_SUCCESS ) ||
2647
+ (_radio .ticker_id_stop == RADIO_TICKER_ID_ADV ));
2648
+ }
2649
+
2650
+ static void ticker_update_slave_assert (uint32_t status , void * params )
2651
+ {
2652
+ uint8_t ticker_id = (uint32_t )params & 0xFF ;
2653
+
2654
+ LL_ASSERT ((status == TICKER_STATUS_SUCCESS ) ||
2655
+ (_radio .ticker_id_stop == ticker_id ));
2656
+ }
2657
+
2572
2658
static void work_radio_active (void * params )
2573
2659
{
2574
2660
static uint8_t s_active ;
@@ -3534,7 +3620,7 @@ static void event_common_prepare(uint32_t ticks_at_expire,
3534
3620
#endif
3535
3621
#undef RADIO_DEFERRED_PREEMPT
3536
3622
3537
- /** Handle change in _ticks_active_to_start */
3623
+ /** Handle change in _ticks_active_to_start */
3538
3624
if (_radio .ticks_active_to_start != _ticks_active_to_start ) {
3539
3625
uint32_t ticks_to_start_new =
3540
3626
((_radio .ticks_active_to_start <
@@ -6585,6 +6671,10 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
6585
6671
break ;
6586
6672
}
6587
6673
6674
+ LL_ASSERT (!_radio .ticker_id_stop );
6675
+
6676
+ _radio .ticker_id_stop = ticker_id_primary ;
6677
+
6588
6678
/* Step 1: Is Primary started? Stop the Primary ticker */
6589
6679
ticker_status =
6590
6680
ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
@@ -6605,7 +6695,7 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
6605
6695
}
6606
6696
6607
6697
if (ticker_status != TICKER_STATUS_SUCCESS ) {
6608
- return 1 ;
6698
+ goto role_disable_cleanup ;
6609
6699
}
6610
6700
6611
6701
/* Inside our event, gracefully handle XTAL and Radio actives */
@@ -6616,7 +6706,14 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
6616
6706
ticks_xtal_to_start , ticks_active_to_start );
6617
6707
}
6618
6708
6619
- return 0 ;
6709
+ if (!_radio .ticker_id_stop ) {
6710
+ ticker_status = TICKER_STATUS_FAILURE ;
6711
+ }
6712
+
6713
+ role_disable_cleanup :
6714
+ _radio .ticker_id_stop = 0 ;
6715
+
6716
+ return ticker_status ;
6620
6717
}
6621
6718
6622
6719
uint32_t radio_adv_enable (uint16_t interval , uint8_t chl_map ,
0 commit comments