@@ -65,11 +65,11 @@ PG_REGISTER_WITH_RESET_TEMPLATE(failsafeConfig_t, failsafeConfig, PG_FAILSAFE_CO
65
65
PG_RESET_TEMPLATE (failsafeConfig_t , failsafeConfig ,
66
66
.failsafe_throttle = 1000 , // default throttle off.
67
67
.failsafe_throttle_low_delay = 100 , // default throttle low delay for "just disarm" on failsafe condition
68
- .failsafe_delay = 4 , // 0,4sec
69
- .failsafe_off_delay = 10 , // 1sec
70
- .failsafe_switch_mode = 0 , // default failsafe switch action is identical to rc link loss
68
+ .failsafe_delay = 10 , // 1 sec, can regain control on signal recovery, at idle in drop mode
69
+ .failsafe_off_delay = 10 , // 1 sec in landing phase, if enabled
70
+ .failsafe_switch_mode = FAILSAFE_SWITCH_MODE_STAGE1 , // default failsafe switch action is identical to rc link loss
71
71
.failsafe_procedure = FAILSAFE_PROCEDURE_DROP_IT ,// default full failsafe procedure is 0: auto-landing
72
- .failsafe_recovery_delay = 20 , // 2 sec of valid rx data (plus 200ms) needed to allow recovering from failsafe procedure
72
+ .failsafe_recovery_delay = 10 , // 1 sec of valid rx data needed to allow recovering from failsafe procedure
73
73
.failsafe_stick_threshold = 30 // 30 percent of stick deflection to exit GPS Rescue procedure
74
74
);
75
75
@@ -86,8 +86,12 @@ const char * const failsafeProcedureNames[FAILSAFE_PROCEDURE_COUNT] = {
86
86
*/
87
87
void failsafeReset (void )
88
88
{
89
- failsafeState .rxDataFailurePeriod = PERIOD_RXDATA_FAILURE + failsafeConfig ()-> failsafe_delay * MILLIS_PER_TENTH_SECOND ;
90
- failsafeState .rxDataRecoveryPeriod = PERIOD_RXDATA_RECOVERY + failsafeConfig ()-> failsafe_recovery_delay * MILLIS_PER_TENTH_SECOND ;
89
+ failsafeState .rxDataFailurePeriod = failsafeConfig ()-> failsafe_delay * MILLIS_PER_TENTH_SECOND ; // time to start stage2
90
+ failsafeState .rxDataRecoveryPeriod = failsafeConfig ()-> failsafe_recovery_delay * MILLIS_PER_TENTH_SECOND ;
91
+ if (failsafeState .rxDataRecoveryPeriod < PERIOD_RXDATA_RECOVERY ){
92
+ // PERIOD_RXDATA_RECOVERY (200ms) is the minimum allowed RxData recovery time
93
+ failsafeState .rxDataRecoveryPeriod = PERIOD_RXDATA_RECOVERY ;
94
+ }
91
95
failsafeState .validRxDataReceivedAt = 0 ;
92
96
failsafeState .validRxDataFailedAt = 0 ;
93
97
failsafeState .throttleLowPeriod = 0 ;
@@ -121,6 +125,13 @@ bool failsafeIsActive(void)
121
125
return failsafeState .active ;
122
126
}
123
127
128
+ #ifdef USE_GPS_RESCUE
129
+ bool failsafePhaseIsGpsRescue (void )
130
+ {
131
+ return failsafeState .phase == FAILSAFE_GPS_RESCUE ;
132
+ }
133
+ #endif
134
+
124
135
void failsafeStartMonitoring (void )
125
136
{
126
137
failsafeState .monitoring = true;
@@ -138,26 +149,12 @@ static void failsafeActivate(void)
138
149
failsafeState .phase = FAILSAFE_LANDING ;
139
150
140
151
ENABLE_FLIGHT_MODE (FAILSAFE_MODE );
152
+
141
153
failsafeState .landingShouldBeFinishedAt = millis () + failsafeConfig ()-> failsafe_off_delay * MILLIS_PER_TENTH_SECOND ;
142
154
143
155
failsafeState .events ++ ;
144
156
}
145
157
146
- static void failsafeApplyControlInput (void )
147
- {
148
- #ifdef USE_GPS_RESCUE
149
- if (failsafeConfig ()-> failsafe_procedure == FAILSAFE_PROCEDURE_GPS_RESCUE ) {
150
- ENABLE_FLIGHT_MODE (GPS_RESCUE_MODE );
151
- return ;
152
- }
153
- #endif
154
-
155
- for (int i = 0 ; i < 3 ; i ++ ) {
156
- rcData [i ] = rxConfig ()-> midrc ;
157
- }
158
- rcData [THROTTLE ] = failsafeConfig ()-> failsafe_throttle ;
159
- }
160
-
161
158
bool failsafeIsReceivingRxData (void )
162
159
{
163
160
return (failsafeState .rxLinkState == FAILSAFE_RXLINK_UP );
@@ -177,42 +174,61 @@ void failsafeOnRxResume(void)
177
174
void failsafeOnValidDataReceived (void )
178
175
{
179
176
failsafeState .validRxDataReceivedAt = millis ();
180
- if ((failsafeState .validRxDataReceivedAt - failsafeState .validRxDataFailedAt ) > failsafeState .rxDataRecoveryPeriod ) {
177
+ if ((cmp32 (failsafeState .validRxDataReceivedAt , failsafeState .validRxDataFailedAt ) > (int32_t )failsafeState .rxDataRecoveryPeriod ) ||
178
+ (cmp32 (failsafeState .validRxDataFailedAt , failsafeState .validRxDataReceivedAt ) > 0 )) {
179
+ // rxDataRecoveryPeriod defaults to 1.0s with minimum of PERIOD_RXDATA_RECOVERY (200ms)
181
180
failsafeState .rxLinkState = FAILSAFE_RXLINK_UP ;
181
+ // Allow arming now we have an RX link
182
182
unsetArmingDisabled (ARMING_DISABLED_RX_FAILSAFE );
183
183
}
184
184
}
185
185
186
186
void failsafeOnValidDataFailed (void )
187
187
{
188
- setArmingDisabled (ARMING_DISABLED_RX_FAILSAFE ); // To prevent arming with no RX link
189
188
failsafeState .validRxDataFailedAt = millis ();
190
- if ((failsafeState .validRxDataFailedAt - failsafeState .validRxDataReceivedAt ) > failsafeState .rxDataFailurePeriod ) {
189
+ if ((cmp32 (failsafeState .validRxDataFailedAt , failsafeState .validRxDataReceivedAt ) > (int32_t )failsafeState .rxDataFailurePeriod )) {
190
+ // rxDataFailurePeriod is stage 1 guard time
191
191
failsafeState .rxLinkState = FAILSAFE_RXLINK_DOWN ;
192
+ // Prevent arming with no RX link
193
+ setArmingDisabled (ARMING_DISABLED_RX_FAILSAFE );
192
194
}
193
195
}
194
196
195
197
void failsafeCheckDataFailurePeriod (void )
198
+ // forces link down directly from scheduler?
196
199
{
197
200
if (cmp32 (millis (), failsafeState .validRxDataReceivedAt ) > (int32_t )failsafeState .rxDataFailurePeriod ) {
198
- setArmingDisabled (ARMING_DISABLED_RX_FAILSAFE ); // To prevent arming with no RX link
199
201
failsafeState .rxLinkState = FAILSAFE_RXLINK_DOWN ;
202
+ // Prevent arming with no RX link
203
+ setArmingDisabled (ARMING_DISABLED_RX_FAILSAFE );
200
204
}
201
205
}
202
206
207
+ uint32_t failsafeFailurePeriodMs (void )
208
+ {
209
+ return failsafeState .rxDataFailurePeriod ;
210
+ }
211
+
203
212
FAST_CODE_NOINLINE void failsafeUpdateState (void )
213
+ // triggered directly, and ONLY, by the cheduler, at 10ms = PERIOD_RXDATA_FAILURE - intervals
204
214
{
205
215
if (!failsafeIsMonitoring ()) {
206
216
return ;
207
217
}
208
218
209
219
bool receivingRxData = failsafeIsReceivingRxData ();
220
+ // should be true when FAILSAFE_RXLINK_UP
221
+ // FAILSAFE_RXLINK_UP is set in failsafeOnValidDataReceived
222
+ // failsafeOnValidDataReceived runs from detectAndApplySignalLossBehaviour
223
+
210
224
bool armed = ARMING_FLAG (ARMED );
211
225
bool failsafeSwitchIsOn = IS_RC_MODE_ACTIVE (BOXFAILSAFE );
212
226
beeperMode_e beeperMode = BEEPER_SILENCE ;
213
227
214
- if (failsafeSwitchIsOn && failsafeConfig ()-> failsafe_switch_mode == FAILSAFE_SWITCH_MODE_STAGE2 ) {
215
- receivingRxData = false; // force Stage2
228
+ if (failsafeSwitchIsOn && (failsafeConfig ()-> failsafe_switch_mode == FAILSAFE_SWITCH_MODE_STAGE2 )) {
229
+ // Aux switch set to failsafe stage2 emulates loss of signal without waiting
230
+ failsafeOnValidDataFailed ();
231
+ receivingRxData = false;
216
232
}
217
233
218
234
// Beep RX lost only if we are not seeing data and we have been armed earlier
@@ -232,23 +248,27 @@ FAST_CODE_NOINLINE void failsafeUpdateState(void)
232
248
if (THROTTLE_HIGH == calculateThrottleStatus ()) {
233
249
failsafeState .throttleLowPeriod = millis () + failsafeConfig ()-> failsafe_throttle_low_delay * MILLIS_PER_TENTH_SECOND ;
234
250
}
235
- // Kill switch logic (must be independent of receivingRxData to skip PERIOD_RXDATA_FAILURE delay before disarming)
236
- if (failsafeSwitchIsOn && failsafeConfig ()-> failsafe_switch_mode == FAILSAFE_SWITCH_MODE_KILL ) {
237
- // KillswitchEvent: failsafe switch is configured as KILL switch and is switched ON
251
+ if (failsafeSwitchIsOn && (failsafeConfig ()-> failsafe_switch_mode == FAILSAFE_SWITCH_MODE_KILL )) {
252
+ // Failsafe switch is configured as KILL switch and is switched ON
238
253
failsafeActivate ();
239
- failsafeState .phase = FAILSAFE_LANDED ; // skip auto-landing procedure
240
- failsafeState .receivingRxDataPeriodPreset = PERIOD_OF_1_SECONDS ; // require 1 seconds of valid rxData
254
+ // Skip auto-landing procedure
255
+ failsafeState .phase = FAILSAFE_LANDED ;
256
+ // Require 3 seconds of valid rxData
257
+ failsafeState .receivingRxDataPeriodPreset = PERIOD_OF_3_SECONDS ;
241
258
reprocessState = true;
242
259
} else if (!receivingRxData ) {
243
260
if (millis () > failsafeState .throttleLowPeriod
244
261
#ifdef USE_GPS_RESCUE
245
262
&& failsafeConfig ()-> failsafe_procedure != FAILSAFE_PROCEDURE_GPS_RESCUE
246
263
#endif
247
264
) {
248
- // JustDisarm: throttle was LOW for at least 'failsafe_throttle_low_delay' seconds
265
+ // JustDisarm: throttle was LOW for at least 'failsafe_throttle_low_delay' seconds before failsafe
266
+ // protects against false arming when the Tx is powered up after the quad
249
267
failsafeActivate ();
250
- failsafeState .phase = FAILSAFE_LANDED ; // skip auto-landing procedure
251
- failsafeState .receivingRxDataPeriodPreset = PERIOD_OF_3_SECONDS ; // require 3 seconds of valid rxData
268
+ // skip auto-landing procedure
269
+ failsafeState .phase = FAILSAFE_LANDED ;
270
+ // re-arm at rxDataRecoveryPeriod - default is 1.0 seconds
271
+ failsafeState .receivingRxDataPeriodPreset = failsafeState .rxDataRecoveryPeriod ;
252
272
} else {
253
273
failsafeState .phase = FAILSAFE_RX_LOSS_DETECTED ;
254
274
}
@@ -279,7 +299,10 @@ FAST_CODE_NOINLINE void failsafeUpdateState(void)
279
299
case FAILSAFE_PROCEDURE_DROP_IT :
280
300
// Drop the craft
281
301
failsafeActivate ();
282
- failsafeState .phase = FAILSAFE_LANDED ; // skip auto-landing procedure
302
+ // re-arm at rxDataRecoveryPeriod - default is 1.0 seconds
303
+ failsafeState .receivingRxDataPeriodPreset = failsafeState .rxDataRecoveryPeriod ;
304
+ // skip auto-landing procedure
305
+ failsafeState .phase = FAILSAFE_LANDED ;
283
306
break ;
284
307
#ifdef USE_GPS_RESCUE
285
308
case FAILSAFE_PROCEDURE_GPS_RESCUE :
@@ -296,37 +319,42 @@ FAST_CODE_NOINLINE void failsafeUpdateState(void)
296
319
if (receivingRxData ) {
297
320
failsafeState .phase = FAILSAFE_RX_LOSS_RECOVERED ;
298
321
reprocessState = true;
299
- }
300
- if (armed ) {
301
- failsafeApplyControlInput ();
302
- beeperMode = BEEPER_RX_LOST_LANDING ;
303
- }
304
- if (failsafeShouldHaveCausedLandingByNow () || crashRecoveryModeActive () || !armed ) {
305
- failsafeState .receivingRxDataPeriodPreset = PERIOD_OF_30_SECONDS ; // require 30 seconds of valid rxData
306
- failsafeState .phase = FAILSAFE_LANDED ;
307
- reprocessState = true;
322
+ } else {
323
+ if (armed ) {
324
+ beeperMode = BEEPER_RX_LOST_LANDING ;
325
+ }
326
+ if (failsafeShouldHaveCausedLandingByNow () || crashRecoveryModeActive () || !armed ) {
327
+ // require 3 seconds of valid rxData
328
+ failsafeState .receivingRxDataPeriodPreset = PERIOD_OF_3_SECONDS ;
329
+ failsafeState .phase = FAILSAFE_LANDED ;
330
+ reprocessState = true;
331
+ }
308
332
}
309
333
break ;
310
334
#ifdef USE_GPS_RESCUE
311
335
case FAILSAFE_GPS_RESCUE :
312
336
if (receivingRxData ) {
313
337
if (areSticksActive (failsafeConfig ()-> failsafe_stick_threshold )) {
338
+ // hence we must allow stick inputs during FAILSAFE_GPS_RESCUE see PR #7936 for rationale
314
339
failsafeState .phase = FAILSAFE_RX_LOSS_RECOVERED ;
315
340
reprocessState = true;
316
341
}
317
- }
318
- if (armed ) {
319
- failsafeApplyControlInput ();
320
- beeperMode = BEEPER_RX_LOST_LANDING ;
321
342
} else {
322
- failsafeState .receivingRxDataPeriodPreset = PERIOD_OF_30_SECONDS ; // require 30 seconds of valid rxData
323
- failsafeState .phase = FAILSAFE_LANDED ;
324
- reprocessState = true;
343
+ if (armed ) {
344
+ ENABLE_FLIGHT_MODE (GPS_RESCUE_MODE );
345
+ beeperMode = BEEPER_RX_LOST_LANDING ;
346
+ } else {
347
+ // require 3 seconds of valid rxData
348
+ failsafeState .receivingRxDataPeriodPreset = PERIOD_OF_3_SECONDS ;
349
+ failsafeState .phase = FAILSAFE_LANDED ;
350
+ reprocessState = true;
351
+ }
325
352
}
326
353
break ;
327
354
#endif
328
355
case FAILSAFE_LANDED :
329
- setArmingDisabled (ARMING_DISABLED_FAILSAFE ); // To prevent accidently rearming by an intermittent rx link
356
+ // Prevent accidently rearming by an intermittent rx link
357
+ setArmingDisabled (ARMING_DISABLED_FAILSAFE );
330
358
disarm (DISARM_REASON_FAILSAFE );
331
359
failsafeState .receivingRxDataPeriod = millis () + failsafeState .receivingRxDataPeriodPreset ; // set required period of valid rxData
332
360
failsafeState .phase = FAILSAFE_RX_LOSS_MONITORING ;
@@ -337,12 +365,9 @@ FAST_CODE_NOINLINE void failsafeUpdateState(void)
337
365
// Monitoring the rx link to allow rearming when it has become good for > `receivingRxDataPeriodPreset` time.
338
366
if (receivingRxData ) {
339
367
if (millis () > failsafeState .receivingRxDataPeriod ) {
340
- // rx link is good now, when arming via ARM switch, it must be OFF first
341
- if (!(!isUsingSticksForArming () && IS_RC_MODE_ACTIVE (BOXARM ))) {
342
- unsetArmingDisabled (ARMING_DISABLED_FAILSAFE );
343
- failsafeState .phase = FAILSAFE_RX_LOSS_RECOVERED ;
344
- reprocessState = true;
345
- }
368
+ // rx link is good now
369
+ failsafeState .phase = FAILSAFE_RX_LOSS_RECOVERED ;
370
+ reprocessState = true;
346
371
}
347
372
} else {
348
373
failsafeState .receivingRxDataPeriod = millis () + failsafeState .receivingRxDataPeriodPreset ;
@@ -357,6 +382,7 @@ FAST_CODE_NOINLINE void failsafeUpdateState(void)
357
382
failsafeState .phase = FAILSAFE_IDLE ;
358
383
failsafeState .active = false;
359
384
DISABLE_FLIGHT_MODE (FAILSAFE_MODE );
385
+ unsetArmingDisabled (ARMING_DISABLED_FAILSAFE );
360
386
reprocessState = true;
361
387
break ;
362
388
0 commit comments