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)(PERIOD_RXDATA_FAILURE
+ 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_30_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_1_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());
439 EXPECT_TRUE(isArmingDisabled());
440 EXPECT_EQ(0, CALL_COUNTER(COUNTER_MW_DISARM
));
441 EXPECT_EQ(FAILSAFE_LANDING
, failsafePhase());
444 sysTickUptime
+= failsafeConfig()->failsafe_off_delay
* MILLIS_PER_TENTH_SECOND
+ 1;
447 failsafeOnValidDataFailed(); // set last invalid sample at current time
450 failsafeUpdateState();
453 EXPECT_TRUE(failsafeIsActive());
454 EXPECT_TRUE(isArmingDisabled());
455 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
));
456 EXPECT_EQ(FAILSAFE_RX_LOSS_MONITORING
, failsafePhase());
459 sysTickUptime
+= PERIOD_OF_30_SECONDS
+ 1; // adjust time to point just past the required additional recovery time
462 deactivateBoxFailsafe();
463 failsafeOnValidDataReceived(); // inactive box failsafe gives valid data
466 failsafeUpdateState();
469 EXPECT_FALSE(failsafeIsActive());
470 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
471 EXPECT_EQ(1, CALL_COUNTER(COUNTER_MW_DISARM
)); // disarm not called repeatedly.
472 EXPECT_FALSE(isArmingDisabled());
476 /****************************************************************************************/
478 // Additional non-stepwise tests
480 /****************************************************************************************/
481 TEST(FlightFailsafeTest
, TestFailsafeNotActivatedWhenDisarmedAndRXLossIsDetected
)
491 DISABLE_ARMING_FLAG(ARMED
);
494 failsafeStartMonitoring();
497 sysTickUptime
= 0; // restart time from 0
498 failsafeOnValidDataReceived(); // set last valid sample at current time
501 for (sysTickUptime
= 0; sysTickUptime
< PERIOD_RXDATA_FAILURE
; sysTickUptime
++) {
502 failsafeOnValidDataFailed();
504 failsafeUpdateState();
507 EXPECT_FALSE(failsafeIsActive());
508 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
512 sysTickUptime
++; // adjust time to point just past the failure time to
513 failsafeOnValidDataFailed(); // cause a lost link
516 failsafeUpdateState();
519 EXPECT_TRUE(failsafeIsMonitoring());
520 EXPECT_FALSE(failsafeIsActive());
521 EXPECT_EQ(FAILSAFE_IDLE
, failsafePhase());
522 EXPECT_EQ(0, CALL_COUNTER(COUNTER_MW_DISARM
));
523 EXPECT_TRUE(isArmingDisabled());
526 // enough valid data is received
527 uint32_t sysTickTarget
= sysTickUptime
+ PERIOD_RXDATA_RECOVERY
;
528 for (; sysTickUptime
< sysTickTarget
; sysTickUptime
++) {
529 failsafeOnValidDataReceived();
530 failsafeUpdateState();
532 EXPECT_TRUE(isArmingDisabled());
536 sysTickUptime
++; // adjust time to point just past the failure time to
537 failsafeOnValidDataReceived(); // cause link recovery
540 EXPECT_FALSE(isArmingDisabled());
546 float rcData
[MAX_SUPPORTED_RC_CHANNEL_COUNT
];
548 int16_t debug
[DEBUG16_VALUE_COUNT
];
549 bool isUsingSticksToArm
= true;
551 PG_REGISTER(rxConfig_t
, rxConfig
, PG_RX_CONFIG
, 0);
553 // Return system uptime in milliseconds (rollover in 49 days)
554 uint32_t millis(void)
556 return sysTickUptime
;
559 uint32_t micros(void)
561 return millis() * 1000;
564 throttleStatus_e
calculateThrottleStatus()
566 return throttleStatus
;
569 void delay(uint32_t) {}
571 bool featureIsEnabled(uint32_t mask
) {
572 return (mask
& testFeatureMask
);
575 void disarm(flightLogDisarmReason_e
) {
576 callCounts
[COUNTER_MW_DISARM
]++;
579 void beeper(beeperMode_e mode
) {
583 uint16_t getCurrentMinthrottle(void)
585 return testMinThrottle
;
588 bool isUsingSticksForArming(void)
590 return isUsingSticksToArm
;
593 bool areSticksActive(uint8_t stickPercentLimit
) {
594 UNUSED(stickPercentLimit
);
598 void beeperConfirmationBeeps(uint8_t beepCount
) { UNUSED(beepCount
); }
600 bool crashRecoveryModeActive(void) { return false; }
601 void pinioBoxTaskControl(void) {}