2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
25 #include "build/debug.h"
28 #include "pg/pg_ids.h"
31 #include "common/axis.h"
32 #include "common/maths.h"
33 #include "common/bitarray.h"
35 #include "fc/runtime_config.h"
36 #include "fc/rc_modes.h"
37 #include "fc/rc_controls.h"
40 #include "flight/failsafe.h"
42 #include "io/beeper.h"
44 #include "drivers/io.h"
47 extern boxBitmask_t rcModeActivationMask
;
50 #include "unittest_macros.h"
51 #include "gtest/gtest.h"
53 uint32_t testFeatureMask
= 0;
54 uint16_t testMinThrottle
= 0;
55 throttleStatus_e throttleStatus
= THROTTLE_HIGH
;
58 COUNTER_MW_DISARM
= 0,
60 #define CALL_COUNT_ITEM_COUNT 1
62 static int callCounts
[CALL_COUNT_ITEM_COUNT
];
64 #define CALL_COUNTER(item) (callCounts[item])
66 void resetCallCounters(void) {
67 memset(&callCounts
, 0, sizeof(callCounts
));
70 #define TEST_MID_RC 1495 // something other than the default 1500 will suffice.
71 #define TEST_MIN_CHECK 1100;
72 #define PERIOD_OF_10_SCONDS 10000
73 #define DE_ACTIVATE_ALL_BOXES 0
75 uint32_t sysTickUptime
;
77 void configureFailsafe(void)
79 rxConfigMutable()->midrc
= TEST_MID_RC
;
80 rxConfigMutable()->mincheck
= TEST_MIN_CHECK
;
82 failsafeConfigMutable()->failsafe_delay
= 10; // 1 second
83 failsafeConfigMutable()->failsafe_off_delay
= 50; // 5 seconds
84 failsafeConfigMutable()->failsafe_switch_mode
= FAILSAFE_SWITCH_MODE_STAGE1
;
85 failsafeConfigMutable()->failsafe_throttle
= 1200;
86 failsafeConfigMutable()->failsafe_throttle_low_delay
= 50; // 5 seconds
87 failsafeConfigMutable()->failsafe_procedure
= FAILSAFE_PROCEDURE_AUTO_LANDING
;
91 void activateBoxFailsafe()
94 bitArraySet(&newMask
, BOXFAILSAFE
);
95 rcModeUpdate(&newMask
);
98 void deactivateBoxFailsafe()
100 boxBitmask_t newMask
;
101 memset(&newMask
, 0, sizeof(newMask
));
102 rcModeUpdate(&newMask
);
109 /****************************************************************************************/
110 TEST(FlightFailsafeTest
, TestFailsafeInitialState
)
115 DISABLE_ARMING_FLAG(ARMED
);
122 EXPECT_FALSE(failsafeIsMonitoring());
123 EXPECT_FALSE(failsafeIsActive());
124 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
127 /****************************************************************************************/
128 TEST(FlightFailsafeTest
, TestFailsafeStartMonitoring
)
131 failsafeStartMonitoring();
134 EXPECT_TRUE(failsafeIsMonitoring());
135 EXPECT_FALSE(failsafeIsActive());
136 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
139 /****************************************************************************************/
140 TEST(FlightFailsafeTest
, TestFailsafeFirstArmedCycle
)
143 ENABLE_ARMING_FLAG(ARMED
);
146 failsafeOnValidDataFailed(); // set last invalid sample at current time
147 sysTickUptime
+= PERIOD_RXDATA_RECOVERY
+ 1; // adjust time to point just past the recovery time to
148 failsafeOnValidDataReceived(); // cause a recovered link
151 failsafeUpdateState();
154 EXPECT_FALSE(failsafeIsActive());
155 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
158 /****************************************************************************************/
159 TEST(FlightFailsafeTest
, TestFailsafeNotActivatedWhenReceivingData
)
162 for (sysTickUptime
= 0; sysTickUptime
< PERIOD_OF_10_SCONDS
; sysTickUptime
++) {
163 failsafeOnValidDataReceived();
165 failsafeUpdateState();
168 EXPECT_FALSE(failsafeIsActive());
169 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
173 /****************************************************************************************/
174 TEST(FlightFailsafeTest
, TestFailsafeDetectsRxLossAndStartsLanding
)
177 ENABLE_ARMING_FLAG(ARMED
);
180 failsafeStartMonitoring();
181 throttleStatus
= THROTTLE_HIGH
; // throttle HIGH to go for a failsafe landing procedure
182 sysTickUptime
= 0; // restart time from 0
183 failsafeOnValidDataReceived(); // set last valid sample at current time
186 for (sysTickUptime
= 0; sysTickUptime
< (uint32_t)(failsafeConfig()->failsafe_delay
* MILLIS_PER_TENTH_SECOND
); sysTickUptime
++) {
187 failsafeOnValidDataFailed();
189 failsafeUpdateState();
192 EXPECT_FALSE(failsafeIsActive());
193 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
197 sysTickUptime
++; // adjust time to point just past the failure time to
198 failsafeOnValidDataFailed(); // cause a lost link
201 failsafeUpdateState();
204 EXPECT_EQ(FAILSAFE_LANDING
, failsafePhase());
205 EXPECT_TRUE(failsafeIsActive());
208 /****************************************************************************************/
209 TEST(FlightFailsafeTest
, TestFailsafeCausesLanding
)
212 sysTickUptime
+= failsafeConfig()->failsafe_off_delay
* MILLIS_PER_TENTH_SECOND
;
216 // no call to failsafeOnValidDataReceived();
217 failsafeUpdateState();
220 EXPECT_TRUE(failsafeIsActive());
221 EXPECT_EQ(FAILSAFE_RX_LOSS_MONITORING
, failsafePhase());
222 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
));
223 EXPECT_TRUE(isArmingDisabled());
226 failsafeOnValidDataFailed(); // set last invalid sample at current time
227 sysTickUptime
+= PERIOD_RXDATA_RECOVERY
+ 1; // adjust time to point just past the recovery time to
228 failsafeOnValidDataReceived(); // cause a recovered link
231 failsafeUpdateState();
234 EXPECT_TRUE(failsafeIsActive());
235 EXPECT_EQ(FAILSAFE_RX_LOSS_MONITORING
, failsafePhase());
236 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
));
237 EXPECT_TRUE(isArmingDisabled());
240 sysTickUptime
+= PERIOD_OF_3_SECONDS
+ 1; // adjust time to point just past the required additional recovery time
241 failsafeOnValidDataReceived();
244 failsafeUpdateState();
247 EXPECT_FALSE(failsafeIsActive());
248 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
249 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
)); // disarm not called repeatedly.
250 EXPECT_FALSE(isArmingDisabled());
253 /****************************************************************************************/
254 TEST(FlightFailsafeTest
, TestFailsafeDetectsRxLossAndJustDisarms
)
257 DISABLE_ARMING_FLAG(ARMED
);
261 failsafeStartMonitoring();
262 throttleStatus
= THROTTLE_LOW
; // throttle LOW to go for a failsafe just-disarm procedure
263 sysTickUptime
= 0; // restart time from 0
264 failsafeOnValidDataReceived(); // set last valid sample at current time
267 for (sysTickUptime
= 0; sysTickUptime
< (uint32_t)(failsafeConfig()->failsafe_delay
* MILLIS_PER_TENTH_SECOND
+ PERIOD_RXDATA_FAILURE
); sysTickUptime
++) {
268 failsafeOnValidDataFailed();
270 failsafeUpdateState();
273 EXPECT_FALSE(failsafeIsActive());
274 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
278 sysTickUptime
++; // adjust time to point just past the failure time to
279 failsafeOnValidDataFailed(); // cause a lost link
280 ENABLE_ARMING_FLAG(ARMED
); // armed from here (disarmed state has cleared throttleLowPeriod).
283 failsafeUpdateState();
286 EXPECT_TRUE(failsafeIsActive());
287 EXPECT_EQ(FAILSAFE_RX_LOSS_MONITORING
, failsafePhase());
288 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
));
289 EXPECT_TRUE(isArmingDisabled());
292 failsafeOnValidDataFailed(); // set last invalid sample at current time
293 sysTickUptime
+= PERIOD_RXDATA_RECOVERY
+ 1; // adjust time to point just past the recovery time to
294 failsafeOnValidDataReceived(); // cause a recovered link
297 failsafeUpdateState();
300 EXPECT_TRUE(failsafeIsActive());
301 EXPECT_EQ(FAILSAFE_RX_LOSS_MONITORING
, failsafePhase());
302 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
));
303 EXPECT_TRUE(isArmingDisabled());
306 sysTickUptime
+= PERIOD_OF_3_SECONDS
+ 1; // adjust time to point just past the required additional recovery time
307 failsafeOnValidDataReceived();
310 failsafeUpdateState();
313 EXPECT_FALSE(failsafeIsActive());
314 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
315 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
)); // disarm not called repeatedly.
316 EXPECT_FALSE(isArmingDisabled());
319 /****************************************************************************************/
320 TEST(FlightFailsafeTest
, TestFailsafeSwitchModeKill
)
323 ENABLE_ARMING_FLAG(ARMED
);
325 failsafeStartMonitoring();
328 throttleStatus
= THROTTLE_HIGH
; // throttle HIGH to go for a failsafe landing procedure
329 failsafeConfigMutable()->failsafe_switch_mode
= FAILSAFE_SWITCH_MODE_KILL
;
331 activateBoxFailsafe();
333 sysTickUptime
= 0; // restart time from 0
334 failsafeOnValidDataReceived(); // set last valid sample at current time
335 sysTickUptime
= PERIOD_RXDATA_FAILURE
+ 1; // adjust time to point just past the failure time to
336 failsafeOnValidDataFailed(); // cause a lost link
339 failsafeUpdateState(); // kill switch handling should come first
342 EXPECT_TRUE(failsafeIsActive());
343 EXPECT_TRUE(isArmingDisabled());
344 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
));
345 EXPECT_EQ(FAILSAFE_RX_LOSS_MONITORING
, failsafePhase());
348 failsafeOnValidDataFailed(); // set last invalid sample at current time
349 sysTickUptime
+= PERIOD_RXDATA_RECOVERY
+ 1; // adjust time to point just past the recovery time to
350 failsafeOnValidDataReceived(); // cause a recovered link
352 deactivateBoxFailsafe();
355 failsafeUpdateState();
358 EXPECT_TRUE(failsafeIsActive());
359 EXPECT_TRUE(isArmingDisabled());
360 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
));
361 EXPECT_EQ(FAILSAFE_RX_LOSS_MONITORING
, failsafePhase());
364 sysTickUptime
+= PERIOD_OF_3_SECONDS
+ 1; // adjust time to point just past the required additional recovery time
365 failsafeOnValidDataReceived();
368 failsafeUpdateState();
371 EXPECT_FALSE(failsafeIsActive());
372 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
373 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
)); // disarm not called repeatedly.
374 EXPECT_FALSE(isArmingDisabled());
377 TEST(FlightFailsafeTest
, TestFailsafeSwitchModeStage2Drop
)
380 ENABLE_ARMING_FLAG(ARMED
);
384 throttleStatus
= THROTTLE_HIGH
; // throttle HIGH to go for a failsafe landing procedure
385 failsafeConfigMutable()->failsafe_switch_mode
= FAILSAFE_SWITCH_MODE_STAGE2
;
386 failsafeConfigMutable()->failsafe_procedure
= FAILSAFE_PROCEDURE_DROP_IT
;
390 sysTickUptime
= 0; // restart time from 0
391 activateBoxFailsafe();
392 failsafeOnValidDataFailed(); // box failsafe causes data to be invalid
395 failsafeUpdateState(); // should activate stage2 immediately
398 EXPECT_TRUE(failsafeIsActive());
399 EXPECT_TRUE(isArmingDisabled());
400 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
));
401 EXPECT_EQ(FAILSAFE_RX_LOSS_MONITORING
, failsafePhase());
404 sysTickUptime
+= PERIOD_OF_3_SECONDS
+ 1; // adjust time to point just past the required additional recovery time
405 deactivateBoxFailsafe();
406 failsafeOnValidDataReceived(); // inactive box failsafe gives valid data
409 failsafeUpdateState();
412 EXPECT_FALSE(failsafeIsActive());
413 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
414 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
)); // disarm not called repeatedly.
415 EXPECT_FALSE(isArmingDisabled());
418 TEST(FlightFailsafeTest
, TestFailsafeSwitchModeStage2Land
)
421 ENABLE_ARMING_FLAG(ARMED
);
425 throttleStatus
= THROTTLE_HIGH
; // throttle HIGH to go for a failsafe landing procedure
426 failsafeConfigMutable()->failsafe_switch_mode
= FAILSAFE_SWITCH_MODE_STAGE2
;
427 failsafeConfigMutable()->failsafe_procedure
= FAILSAFE_PROCEDURE_AUTO_LANDING
;
430 sysTickUptime
= 0; // restart time from 0
431 activateBoxFailsafe();
432 failsafeOnValidDataFailed(); // box failsafe causes data to be invalid
435 failsafeUpdateState(); // should activate stage2 immediately
438 EXPECT_TRUE(failsafeIsActive()); // stick induced failsafe allows re-arming
439 EXPECT_EQ(0, CALL_COUNTER(COUNTER_MW_DISARM
));
440 EXPECT_EQ(FAILSAFE_LANDING
, failsafePhase());
443 sysTickUptime
+= failsafeConfig()->failsafe_off_delay
* MILLIS_PER_TENTH_SECOND
+ 1;
446 failsafeOnValidDataFailed(); // set last invalid sample at current time
449 failsafeUpdateState();
452 EXPECT_TRUE(failsafeIsActive());
453 EXPECT_TRUE(isArmingDisabled());
454 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
));
455 EXPECT_EQ(FAILSAFE_RX_LOSS_MONITORING
, failsafePhase());
458 sysTickUptime
+= PERIOD_OF_3_SECONDS
+ 1; // adjust time to point just past the required additional recovery time
461 deactivateBoxFailsafe();
462 failsafeOnValidDataReceived(); // inactive box failsafe gives valid data
465 failsafeUpdateState();
468 EXPECT_FALSE(failsafeIsActive());
469 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
470 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
)); // disarm not called repeatedly.
471 EXPECT_FALSE(isArmingDisabled());
475 /****************************************************************************************/
477 // Additional non-stepwise tests
479 /****************************************************************************************/
480 TEST(FlightFailsafeTest
, TestFailsafeNotActivatedWhenDisarmedAndRXLossIsDetected
)
490 DISABLE_ARMING_FLAG(ARMED
);
493 failsafeStartMonitoring();
496 sysTickUptime
= 0; // restart time from 0
497 failsafeOnValidDataReceived(); // set last valid sample at current time
499 // enter stage 1 failsafe
500 for (sysTickUptime
= 0; sysTickUptime
< PERIOD_RXDATA_FAILURE
; sysTickUptime
++) {
501 failsafeOnValidDataFailed();
503 failsafeUpdateState();
506 EXPECT_FALSE(failsafeIsActive());
507 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
511 sysTickUptime
++; // adjust time to point just past the failure time to
512 failsafeOnValidDataFailed(); // cause a lost link
515 failsafeUpdateState();
518 EXPECT_TRUE(failsafeIsMonitoring());
519 EXPECT_FALSE(failsafeIsActive());
520 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
521 EXPECT_EQ(0, CALL_COUNTER(COUNTER_MW_DISARM
));
522 EXPECT_FALSE(isArmingDisabled()); // arming not blocked in stage 1
524 // add enough time to enter stage 2
525 sysTickUptime
+= failsafeConfig()->failsafe_off_delay
* MILLIS_PER_TENTH_SECOND
+ 1;
526 failsafeOnValidDataFailed();
529 failsafeUpdateState();
532 EXPECT_TRUE(isArmingDisabled()); // arming blocked until recovery time
533 EXPECT_FALSE(failsafeIsActive()); // failsafe is still not active
535 // given valid data is received for the recovery time, allow re-arming
536 uint32_t sysTickTarget
= sysTickUptime
+ PERIOD_RXDATA_RECOVERY
;
537 for (; sysTickUptime
< sysTickTarget
; sysTickUptime
++) {
538 failsafeOnValidDataReceived();
539 failsafeUpdateState();
541 EXPECT_TRUE(isArmingDisabled());
545 sysTickUptime
++; // adjust time to point just past the failure time to
546 failsafeOnValidDataReceived(); // cause link recovery
549 EXPECT_FALSE(isArmingDisabled());
555 float rcData
[MAX_SUPPORTED_RC_CHANNEL_COUNT
];
557 int16_t debug
[DEBUG16_VALUE_COUNT
];
558 uint8_t debugMode
= 0;
559 bool isUsingSticksToArm
= true;
561 PG_REGISTER(rxConfig_t
, rxConfig
, PG_RX_CONFIG
, 0);
563 // Return system uptime in milliseconds (rollover in 49 days)
564 uint32_t millis(void)
566 return sysTickUptime
;
569 uint32_t micros(void)
571 return millis() * 1000;
574 throttleStatus_e
calculateThrottleStatus()
576 return throttleStatus
;
579 void delay(uint32_t) {}
581 bool featureIsEnabled(uint32_t mask
) {
582 return (mask
& testFeatureMask
);
585 void disarm(flightLogDisarmReason_e
) {
586 callCounts
[COUNTER_MW_DISARM
]++;
589 void beeper(beeperMode_e mode
) {
593 uint16_t getCurrentMinthrottle(void)
595 return testMinThrottle
;
598 bool isUsingSticksForArming(void)
600 return isUsingSticksToArm
;
603 bool areSticksActive(uint8_t stickPercentLimit
) {
604 UNUSED(stickPercentLimit
);
608 void beeperConfirmationBeeps(uint8_t beepCount
) { UNUSED(beepCount
); }
610 bool crashRecoveryModeActive(void) { return false; }
611 void pinioBoxTaskControl(void) {}