Merge pull request #9484 from mikeller/remove_legacy_timer_index
[betaflight.git] / src / test / unit / osd_unittest.cc
blob1148be2a8522275aa8678b858783271c9b0464ef
1 /*
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/>.
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <string.h>
23 extern "C" {
24 #include "platform.h"
26 #include "build/debug.h"
28 #include "blackbox/blackbox.h"
29 #include "blackbox/blackbox_io.h"
31 #include "config/feature.h"
33 #include "pg/pg.h"
34 #include "pg/pg_ids.h"
35 #include "pg/rx.h"
37 #include "common/time.h"
39 #include "drivers/osd_symbols.h"
40 #include "drivers/persistent.h"
41 #include "drivers/serial.h"
43 #include "config/config.h"
44 #include "fc/core.h"
45 #include "fc/rc_controls.h"
46 #include "fc/rc_modes.h"
47 #include "fc/runtime_config.h"
49 #include "flight/gps_rescue.h"
50 #include "flight/pid.h"
51 #include "flight/imu.h"
53 #include "io/beeper.h"
54 #include "io/gps.h"
56 #include "osd/osd.h"
57 #include "osd/osd_elements.h"
59 #include "sensors/acceleration.h"
60 #include "sensors/battery.h"
62 #include "rx/rx.h"
63 #include "flight/mixer.h"
65 void osdRefresh(timeUs_t currentTimeUs);
66 void osdFormatTime(char * buff, osd_timer_precision_e precision, timeUs_t time);
67 int osdConvertTemperatureToSelectedUnit(int tempInDegreesCelcius);
69 uint16_t rssi;
70 attitudeEulerAngles_t attitude;
71 pidProfile_t *currentPidProfile;
72 int16_t debug[DEBUG16_VALUE_COUNT];
73 int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT];
74 uint8_t GPS_numSat;
75 uint16_t GPS_distanceToHome;
76 int16_t GPS_directionToHome;
77 uint32_t GPS_distanceFlownInCm;
78 int32_t GPS_coord[2];
79 gpsSolutionData_t gpsSol;
80 float motor[8];
81 float motorOutputHigh = 2047;
82 float motorOutputLow = 1000;
84 linkQualitySource_e linkQualitySource;
86 acc_t acc;
87 float accAverage[XYZ_AXIS_COUNT];
89 PG_REGISTER(batteryConfig_t, batteryConfig, PG_BATTERY_CONFIG, 0);
90 PG_REGISTER(blackboxConfig_t, blackboxConfig, PG_BLACKBOX_CONFIG, 0);
91 PG_REGISTER(systemConfig_t, systemConfig, PG_SYSTEM_CONFIG, 0);
92 PG_REGISTER(pilotConfig_t, pilotConfig, PG_PILOT_CONFIG, 0);
93 PG_REGISTER(gpsRescueConfig_t, gpsRescueConfig, PG_GPS_RESCUE, 0);
94 PG_REGISTER(imuConfig_t, imuConfig, PG_IMU_CONFIG, 0);
95 PG_REGISTER(gpsConfig_t, gpsConfig, PG_GPS_CONFIG, 0);
97 timeUs_t simulationTime = 0;
98 batteryState_e simulationBatteryState;
99 uint8_t simulationBatteryCellCount;
100 uint16_t simulationBatteryVoltage;
101 uint32_t simulationBatteryAmperage;
102 uint32_t simulationMahDrawn;
103 int32_t simulationAltitude;
104 int32_t simulationVerticalSpeed;
105 uint16_t simulationCoreTemperature;
108 uint32_t simulationFeatureFlags = FEATURE_GPS;
110 /* #define DEBUG_OSD */
112 #include "unittest_macros.h"
113 #include "unittest_displayport.h"
114 #include "gtest/gtest.h"
116 void setDefaultSimulationState()
118 memset(osdElementConfigMutable(), 0, sizeof(osdElementConfig_t));
120 osdConfigMutable()->enabled_stats = 0;
122 rssi = 1024;
124 simulationBatteryState = BATTERY_OK;
125 simulationBatteryCellCount = 4;
126 simulationBatteryVoltage = 1680;
127 simulationBatteryAmperage = 0;
128 simulationMahDrawn = 0;
129 simulationAltitude = 0;
130 simulationVerticalSpeed = 0;
131 simulationCoreTemperature = 0;
133 rcData[PITCH] = 1500;
135 simulationTime = 0;
136 osdFlyTime = 0;
140 * Performs a test of the OSD actions on arming.
141 * (reused throughout the test suite)
143 void doTestArm(bool testEmpty = true)
145 // given
146 // craft has been armed
147 ENABLE_ARMING_FLAG(ARMED);
149 // when
150 // sufficient OSD updates have been called
151 osdRefresh(simulationTime);
153 // then
154 // arming alert displayed
155 displayPortTestBufferSubstring(12, 7, "ARMED");
157 // given
158 // armed alert times out (0.5 seconds)
159 simulationTime += 0.5e6;
161 // when
162 // sufficient OSD updates have been called
163 osdRefresh(simulationTime);
165 // then
166 // arming alert disappears
167 #ifdef DEBUG_OSD
168 displayPortTestPrint();
169 #endif
170 if (testEmpty) {
171 displayPortTestBufferIsEmpty();
176 * Auxiliary function. Test is there're stats that must be shown
178 bool isSomeStatEnabled(void) {
179 return (osdConfigMutable()->enabled_stats != 0);
183 * Performs a test of the OSD actions on disarming.
184 * (reused throughout the test suite)
186 void doTestDisarm()
188 // given
189 // craft is disarmed after having been armed
190 DISABLE_ARMING_FLAG(ARMED);
192 // when
193 // sufficient OSD updates have been called
194 osdRefresh(simulationTime);
196 // then
197 // post flight statistics displayed
198 if (isSomeStatEnabled()) {
199 unsigned enabledStats = osdConfigMutable()->enabled_stats;
200 unsigned count = 0;
201 while (enabledStats) {
202 count += enabledStats & 1;
203 enabledStats >>= 1;
206 displayPortTestBufferSubstring(2, 7 - count / 2, " --- STATS ---");
210 void setupStats(void)
212 // this set of enabled post flight statistics
213 osdStatSetState(OSD_STAT_MAX_SPEED, true);
214 osdStatSetState(OSD_STAT_MIN_BATTERY, true);
215 osdStatSetState(OSD_STAT_MIN_RSSI, true);
216 osdStatSetState(OSD_STAT_MAX_CURRENT, false);
217 osdStatSetState(OSD_STAT_USED_MAH, false);
218 osdStatSetState(OSD_STAT_MAX_ALTITUDE, true);
219 osdStatSetState(OSD_STAT_BLACKBOX, false);
220 osdStatSetState(OSD_STAT_END_BATTERY, true);
221 osdStatSetState(OSD_STAT_RTC_DATE_TIME, true);
222 osdStatSetState(OSD_STAT_MAX_DISTANCE, true);
223 osdStatSetState(OSD_STAT_FLIGHT_DISTANCE, true);
224 osdStatSetState(OSD_STAT_BLACKBOX_NUMBER, false);
225 osdStatSetState(OSD_STAT_MAX_G_FORCE, false);
226 osdStatSetState(OSD_STAT_MAX_ESC_TEMP, false);
227 osdStatSetState(OSD_STAT_MAX_ESC_RPM, false);
230 void simulateFlight(void)
232 // these conditions occur during flight
233 rssi = 1024;
234 gpsSol.groundSpeed = 500;
235 GPS_distanceToHome = 20;
236 GPS_distanceFlownInCm = 2000;
237 simulationBatteryVoltage = 1580;
238 simulationAltitude = 100;
239 simulationTime += 1e6;
240 osdRefresh(simulationTime);
242 rssi = 512;
243 gpsSol.groundSpeed = 800;
244 GPS_distanceToHome = 50;
245 GPS_distanceFlownInCm = 10000;
246 simulationBatteryVoltage = 1470;
247 simulationAltitude = 150;
248 simulationTime += 1e6;
249 osdRefresh(simulationTime);
251 rssi = 256;
252 gpsSol.groundSpeed = 200;
253 GPS_distanceToHome = 100;
254 GPS_distanceFlownInCm = 20000;
255 simulationBatteryVoltage = 1520;
256 simulationAltitude = 200;
257 simulationTime += 1e6;
258 osdRefresh(simulationTime);
260 rssi = 256;
261 gpsSol.groundSpeed = 800;
262 GPS_distanceToHome = 100;
263 GPS_distanceFlownInCm = 10000;
264 simulationBatteryVoltage = 1470;
265 simulationAltitude = 200;
266 simulationTime += 1e6;
267 osdRefresh(simulationTime);
269 simulationBatteryVoltage = 1520;
270 simulationTime += 1e6;
271 osdRefresh(simulationTime);
273 rssi = 256;
274 gpsSol.groundSpeed = 800;
275 GPS_distanceToHome = 1150;
276 GPS_distanceFlownInCm = 1050000;
277 simulationBatteryVoltage = 1470;
278 simulationAltitude = 200;
279 simulationTime += 1e6;
280 osdRefresh(simulationTime);
282 simulationBatteryVoltage = 1520;
283 simulationTime += 1e6;
284 osdRefresh(simulationTime);
287 class OsdTest : public ::testing::Test
289 protected:
290 static void SetUpTestCase() {
291 displayPortTestInit();
294 virtual void SetUp() {
295 setDefaultSimulationState();
298 virtual void TearDown() {
299 // Clean up the armed state without showing stats at the end of a test
300 osdConfigMutable()->enabled_stats = 0;
302 doTestDisarm();
307 * Tests initialisation of the OSD and the power on splash screen.
309 TEST_F(OsdTest, TestInit)
311 // given
312 // this battery configuration (used for battery voltage elements)
313 batteryConfigMutable()->vbatmincellvoltage = 330;
314 batteryConfigMutable()->vbatmaxcellvoltage = 430;
316 // when
317 // OSD is initialised
318 osdInit(&testDisplayPort, OSD_DISPLAYPORT_DEVICE_AUTO);
320 // then
321 // display buffer should contain splash screen
322 displayPortTestBufferSubstring(7, 8, "MENU:THR MID");
323 displayPortTestBufferSubstring(11, 9, "+ YAW LEFT");
324 displayPortTestBufferSubstring(11, 10, "+ PITCH UP");
326 // when
327 // splash screen timeout has elapsed
328 simulationTime += 4e6;
329 osdUpdate(simulationTime);
331 // then
332 // display buffer should be empty
333 #ifdef DEBUG_OSD
334 displayPortTestPrint();
335 #endif
336 displayPortTestBufferIsEmpty();
340 * Tests visibility of the ARMED notification after arming.
342 TEST_F(OsdTest, TestArm)
344 doTestArm();
348 * Tests display and timeout of the post flight statistics screen after disarming.
350 TEST_F(OsdTest, TestDisarm)
352 doTestArm();
354 doTestDisarm();
356 // given
357 // post flight stats times out (60 seconds)
358 simulationTime += 60e6;
360 // when
361 // sufficient OSD updates have been called
362 osdRefresh(simulationTime);
364 // then
365 // post flight stats screen disappears
366 #ifdef DEBUG_OSD
367 displayPortTestPrint();
368 #endif
369 displayPortTestBufferIsEmpty();
373 * Tests disarming and immediately rearming clears post flight stats and shows ARMED notification.
375 TEST_F(OsdTest, TestDisarmWithImmediateRearm)
377 doTestArm();
379 doTestDisarm();
381 doTestArm();
385 * Tests dismissing the statistics screen with pitch stick after disarming.
387 TEST_F(OsdTest, TestDisarmWithDismissStats)
389 doTestArm();
391 doTestDisarm();
393 // given
394 // sticks have been moved
395 rcData[PITCH] = 1800;
397 // when
398 // sufficient OSD updates have been called
399 osdRefresh(simulationTime);
401 // then
402 // post flight stats screen disappears
403 #ifdef DEBUG_OSD
404 displayPortTestPrint();
405 #endif
406 displayPortTestBufferIsEmpty();
410 * Tests the calculation of timing in statistics
412 TEST_F(OsdTest, TestStatsTiming)
414 // given
415 osdStatSetState(OSD_STAT_RTC_DATE_TIME, true);
416 osdStatSetState(OSD_STAT_TIMER_1, true);
417 osdStatSetState(OSD_STAT_TIMER_2, true);
419 // and
420 // this timer 1 configuration
421 osdConfigMutable()->timers[OSD_TIMER_1] = OSD_TIMER(OSD_TIMER_SRC_TOTAL_ARMED, OSD_TIMER_PREC_HUNDREDTHS, 0);
423 // and
424 // this timer 2 configuration
425 osdConfigMutable()->timers[OSD_TIMER_2] = OSD_TIMER(OSD_TIMER_SRC_LAST_ARMED, OSD_TIMER_PREC_SECOND, 0);
427 // and
428 // this RTC time
429 dateTime_t dateTime;
430 dateTime.year = 2017;
431 dateTime.month = 11;
432 dateTime.day = 19;
433 dateTime.hours = 10;
434 dateTime.minutes = 12;
435 dateTime.seconds = 0;
436 dateTime.millis = 0;
437 rtcSetDateTime(&dateTime);
439 // when
440 // the craft is armed
441 doTestArm();
443 // and
444 // these conditions occur during flight
445 simulationTime += 1e6;
446 osdRefresh(simulationTime);
448 // and
449 // the craft is disarmed
450 doTestDisarm();
452 // and
453 // the craft is armed again
454 doTestArm();
456 // and
457 // these conditions occur during flight
458 simulationTime += 1e6;
459 osdRefresh(simulationTime);
461 // and
462 // the craft is disarmed
463 doTestDisarm();
465 // then
466 // statistics screen should display the following
467 int row = 7;
468 displayPortTestBufferSubstring(2, row++, "2017-11-19 10:12:");
469 displayPortTestBufferSubstring(2, row++, "TOTAL ARM : 00:02.50");
470 displayPortTestBufferSubstring(2, row++, "LAST ARM : 00:01");
474 * Tests the calculation of statistics with imperial unit output.
476 TEST_F(OsdTest, TestStatsImperial)
478 // given
479 setupStats();
481 // and
482 // using imperial unit system
483 osdConfigMutable()->units = OSD_UNIT_IMPERIAL;
485 // and
486 // a GPS fix is present
487 stateFlags |= GPS_FIX | GPS_FIX_HOME;
489 // when
490 // the craft is armed
491 doTestArm();
493 // and
494 simulateFlight();
496 // and
497 // the craft is disarmed
498 doTestDisarm();
500 // then
501 // statistics screen should display the following
502 int row = 5;
503 displayPortTestBufferSubstring(2, row++, "MAX ALTITUDE : 6.5%c", SYM_FT);
504 displayPortTestBufferSubstring(2, row++, "MAX SPEED : 17");
505 displayPortTestBufferSubstring(2, row++, "MAX DISTANCE : 3772%c", SYM_FT);
506 displayPortTestBufferSubstring(2, row++, "FLIGHT DISTANCE : 6.52%c", SYM_MILES);
507 displayPortTestBufferSubstring(2, row++, "MIN BATTERY : 14.70%c", SYM_VOLT);
508 displayPortTestBufferSubstring(2, row++, "END BATTERY : 15.20%c", SYM_VOLT);
509 displayPortTestBufferSubstring(2, row++, "MIN RSSI : 25%%");
513 * Tests the calculation of statistics with metric unit output.
514 * (essentially an abridged version of the previous test
516 TEST_F(OsdTest, TestStatsMetric)
518 // given
519 setupStats();
521 // and
522 // using metric unit system
523 osdConfigMutable()->units = OSD_UNIT_METRIC;
525 // when
526 // the craft is armed
527 doTestArm();
529 // and
530 simulateFlight();
532 // and
533 // the craft is disarmed
534 doTestDisarm();
536 // then
537 // statistics screen should display the following
538 int row = 5;
539 displayPortTestBufferSubstring(2, row++, "MAX ALTITUDE : 2.0%c", SYM_M);
540 displayPortTestBufferSubstring(2, row++, "MAX SPEED : 28");
541 displayPortTestBufferSubstring(2, row++, "MAX DISTANCE : 1.15%c", SYM_KM);
542 displayPortTestBufferSubstring(2, row++, "FLIGHT DISTANCE : 10.5%c", SYM_KM);
543 displayPortTestBufferSubstring(2, row++, "MIN BATTERY : 14.70%c", SYM_VOLT);
544 displayPortTestBufferSubstring(2, row++, "END BATTERY : 15.20%c", SYM_VOLT);
545 displayPortTestBufferSubstring(2, row++, "MIN RSSI : 25%%");
549 * Tests the calculation of statistics with metric unit output.
550 * (essentially an abridged version of the previous test
552 TEST_F(OsdTest, TestStatsMetricDistanceUnits)
554 // given
555 setupStats();
557 // and
558 // using metric unit system
559 osdConfigMutable()->units = OSD_UNIT_METRIC;
561 // when
562 // the craft is armed
563 doTestArm();
565 // and
566 simulateFlight();
568 // and
569 // the craft is disarmed
570 doTestDisarm();
572 // then
573 // statistics screen should display the following
574 int row = 5;
575 displayPortTestBufferSubstring(2, row++, "MAX ALTITUDE : 2.0%c", SYM_M);
576 displayPortTestBufferSubstring(2, row++, "MAX SPEED : 28");
577 displayPortTestBufferSubstring(2, row++, "MAX DISTANCE : 1.15%c", SYM_KM);
578 displayPortTestBufferSubstring(2, row++, "FLIGHT DISTANCE : 10.5%c", SYM_KM);
579 displayPortTestBufferSubstring(2, row++, "MIN BATTERY : 14.70%c", SYM_VOLT);
580 displayPortTestBufferSubstring(2, row++, "END BATTERY : 15.20%c", SYM_VOLT);
581 displayPortTestBufferSubstring(2, row++, "MIN RSSI : 25%%");
585 * Tests activation of alarms and element flashing.
587 TEST_F(OsdTest, TestAlarms)
589 // given
590 sensorsSet(SENSOR_GPS);
592 // and
593 // the following OSD elements are visible
594 osdElementConfigMutable()->item_pos[OSD_RSSI_VALUE] = OSD_POS(8, 1) | OSD_PROFILE_1_FLAG;
595 osdElementConfigMutable()->item_pos[OSD_MAIN_BATT_VOLTAGE] = OSD_POS(12, 1) | OSD_PROFILE_1_FLAG;
596 osdElementConfigMutable()->item_pos[OSD_ITEM_TIMER_1] = OSD_POS(20, 1) | OSD_PROFILE_1_FLAG;
597 osdElementConfigMutable()->item_pos[OSD_ITEM_TIMER_2] = OSD_POS(1, 1) | OSD_PROFILE_1_FLAG;
598 osdElementConfigMutable()->item_pos[OSD_REMAINING_TIME_ESTIMATE] = OSD_POS(1, 2) | OSD_PROFILE_1_FLAG;
599 osdElementConfigMutable()->item_pos[OSD_ALTITUDE] = OSD_POS(23, 7) | OSD_PROFILE_1_FLAG;
601 // and
602 // this set of alarm values
603 osdConfigMutable()->rssi_alarm = 20;
604 osdConfigMutable()->cap_alarm = 2200;
605 osdConfigMutable()->alt_alarm = 100; // meters
607 osdAnalyzeActiveElements();
609 // and
610 // this timer 1 configuration
611 osdConfigMutable()->timers[OSD_TIMER_1] = OSD_TIMER(OSD_TIMER_SRC_ON, OSD_TIMER_PREC_HUNDREDTHS, 3);
612 EXPECT_EQ(OSD_TIMER_SRC_ON, OSD_TIMER_SRC(osdConfig()->timers[OSD_TIMER_1]));
613 EXPECT_EQ(OSD_TIMER_PREC_HUNDREDTHS, OSD_TIMER_PRECISION(osdConfig()->timers[OSD_TIMER_1]));
614 EXPECT_EQ(3, OSD_TIMER_ALARM(osdConfig()->timers[OSD_TIMER_1]));
616 // and
617 // this timer 2 configuration
618 osdConfigMutable()->timers[OSD_TIMER_2] = OSD_TIMER(OSD_TIMER_SRC_TOTAL_ARMED, OSD_TIMER_PREC_SECOND, 2);
619 EXPECT_EQ(OSD_TIMER_SRC_TOTAL_ARMED, OSD_TIMER_SRC(osdConfig()->timers[OSD_TIMER_2]));
620 EXPECT_EQ(OSD_TIMER_PREC_SECOND, OSD_TIMER_PRECISION(osdConfig()->timers[OSD_TIMER_2]));
621 EXPECT_EQ(2, OSD_TIMER_ALARM(osdConfig()->timers[OSD_TIMER_2]));
623 // and
624 // using the metric unit system
625 osdConfigMutable()->units = OSD_UNIT_METRIC;
627 // when
628 // time is passing by
629 simulationTime += 60e6;
630 osdRefresh(simulationTime);
632 // and
633 // the craft is armed
634 doTestArm(false);
636 simulationTime += 70e6;
637 osdRefresh(simulationTime);
639 // then
640 // no elements should flash as all values are out of alarm range
641 for (int i = 0; i < 30; i++) {
642 // Check for visibility every 100ms, elements should always be visible
643 simulationTime += 0.1e6;
644 osdRefresh(simulationTime);
646 #ifdef DEBUG_OSD
647 printf("%d\n", i);
648 #endif
649 displayPortTestBufferSubstring(1, 1, "%c01:", SYM_FLY_M); // only test the minute part of the timer
650 displayPortTestBufferSubstring(8, 1, "%c99", SYM_RSSI);
651 displayPortTestBufferSubstring(12, 1, "%c16.8%c", SYM_BATT_FULL, SYM_VOLT);
652 displayPortTestBufferSubstring(20, 1, "%c02:", SYM_ON_M); // only test the minute part of the timer
653 displayPortTestBufferSubstring(23, 7, "%c0.0%c", SYM_ALTITUDE, SYM_M);
656 // when
657 // all values are out of range
658 rssi = 128;
659 simulationBatteryState = BATTERY_CRITICAL;
660 simulationBatteryVoltage = 1350;
661 simulationAltitude = 12000;
662 simulationMahDrawn = 999999;
664 simulationTime += 60e6;
665 osdRefresh(simulationTime);
667 // then
668 // elements showing values in alarm range should flash
669 for (int i = 0; i < 15; i++) {
670 // Blinking should happen at 5Hz
671 simulationTime += 0.2e6;
672 osdRefresh(simulationTime);
674 #ifdef DEBUG_OSD
675 printf("%d\n", i);
676 displayPortTestPrint();
677 #endif
678 if (i % 2 == 0) {
679 displayPortTestBufferSubstring(8, 1, "%c12", SYM_RSSI);
680 displayPortTestBufferSubstring(12, 1, "%c13.5%c", SYM_MAIN_BATT, SYM_VOLT);
681 displayPortTestBufferSubstring(1, 1, "%c02:", SYM_FLY_M); // only test the minute part of the timer
682 displayPortTestBufferSubstring(20, 1, "%c03:", SYM_ON_M); // only test the minute part of the timer
683 displayPortTestBufferSubstring(23, 7, "%c120.0%c", SYM_ALTITUDE, SYM_M);
684 } else {
685 displayPortTestBufferIsEmpty();
691 * Tests the RSSI OSD element.
693 TEST_F(OsdTest, TestElementRssi)
695 // given
696 osdElementConfigMutable()->item_pos[OSD_RSSI_VALUE] = OSD_POS(8, 1) | OSD_PROFILE_1_FLAG;
697 osdConfigMutable()->rssi_alarm = 0;
699 osdAnalyzeActiveElements();
701 // when
702 rssi = 1024;
703 displayClearScreen(&testDisplayPort);
704 osdRefresh(simulationTime);
706 // then
707 displayPortTestBufferSubstring(8, 1, "%c99", SYM_RSSI);
709 // when
710 rssi = 0;
711 displayClearScreen(&testDisplayPort);
712 osdRefresh(simulationTime);
714 // then
715 displayPortTestBufferSubstring(8, 1, "%c 0", SYM_RSSI);
717 // when
718 rssi = 512;
719 displayClearScreen(&testDisplayPort);
720 osdRefresh(simulationTime);
722 // then
723 displayPortTestBufferSubstring(8, 1, "%c50", SYM_RSSI);
727 * Tests the instantaneous battery current OSD element.
729 TEST_F(OsdTest, TestElementAmperage)
731 // given
732 osdElementConfigMutable()->item_pos[OSD_CURRENT_DRAW] = OSD_POS(1, 12) | OSD_PROFILE_1_FLAG;
734 osdAnalyzeActiveElements();
736 // when
737 simulationBatteryAmperage = 0;
738 displayClearScreen(&testDisplayPort);
739 osdRefresh(simulationTime);
741 // then
742 displayPortTestBufferSubstring(1, 12, " 0.00%c", SYM_AMP);
744 // when
745 simulationBatteryAmperage = 2156;
746 displayClearScreen(&testDisplayPort);
747 osdRefresh(simulationTime);
749 // then
750 displayPortTestBufferSubstring(1, 12, " 21.56%c", SYM_AMP);
752 // when
753 simulationBatteryAmperage = 12345;
754 displayClearScreen(&testDisplayPort);
755 osdRefresh(simulationTime);
757 // then
758 displayPortTestBufferSubstring(1, 12, "123.45%c", SYM_AMP);
762 * Tests the battery capacity drawn OSD element.
764 TEST_F(OsdTest, TestElementMahDrawn)
766 // given
767 osdElementConfigMutable()->item_pos[OSD_MAH_DRAWN] = OSD_POS(1, 11) | OSD_PROFILE_1_FLAG;
769 osdAnalyzeActiveElements();
771 // when
772 simulationMahDrawn = 0;
773 displayClearScreen(&testDisplayPort);
774 osdRefresh(simulationTime);
776 // then
777 displayPortTestBufferSubstring(1, 11, " 0%c", SYM_MAH);
779 // when
780 simulationMahDrawn = 4;
781 displayClearScreen(&testDisplayPort);
782 osdRefresh(simulationTime);
784 // then
785 displayPortTestBufferSubstring(1, 11, " 4%c", SYM_MAH);
787 // when
788 simulationMahDrawn = 15;
789 displayClearScreen(&testDisplayPort);
790 osdRefresh(simulationTime);
792 // then
793 displayPortTestBufferSubstring(1, 11, " 15%c", SYM_MAH);
795 // when
796 simulationMahDrawn = 246;
797 displayClearScreen(&testDisplayPort);
798 osdRefresh(simulationTime);
800 // then
801 displayPortTestBufferSubstring(1, 11, " 246%c", SYM_MAH);
803 // when
804 simulationMahDrawn = 1042;
805 displayClearScreen(&testDisplayPort);
806 osdRefresh(simulationTime);
808 // then
809 displayPortTestBufferSubstring(1, 11, "1042%c", SYM_MAH);
813 * Tests the instantaneous electrical power OSD element.
815 TEST_F(OsdTest, TestElementPower)
817 // given
818 osdElementConfigMutable()->item_pos[OSD_POWER] = OSD_POS(1, 10) | OSD_PROFILE_1_FLAG;
820 osdAnalyzeActiveElements();
822 // and
823 simulationBatteryVoltage = 1000; // 10V
825 // and
826 simulationBatteryAmperage = 0; // 0A
828 // when
829 displayClearScreen(&testDisplayPort);
830 osdRefresh(simulationTime);
832 // then
833 displayPortTestBufferSubstring(1, 10, " 0W");
835 // given
836 simulationBatteryAmperage = 10; // 0.1A
838 // when
839 displayClearScreen(&testDisplayPort);
840 osdRefresh(simulationTime);
842 // then
843 displayPortTestBufferSubstring(1, 10, " 1W");
845 // given
846 simulationBatteryAmperage = 120; // 1.2A
848 // when
849 displayClearScreen(&testDisplayPort);
850 osdRefresh(simulationTime);
852 // then
853 displayPortTestBufferSubstring(1, 10, " 12W");
855 // given
856 simulationBatteryAmperage = 1230; // 12.3A
858 // when
859 displayClearScreen(&testDisplayPort);
860 osdRefresh(simulationTime);
862 // then
863 displayPortTestBufferSubstring(1, 10, " 123W");
865 // given
866 simulationBatteryAmperage = 12340; // 123.4A
868 // when
869 displayClearScreen(&testDisplayPort);
870 osdRefresh(simulationTime);
872 // then
873 displayPortTestBufferSubstring(1, 10, "1234W");
877 * Tests the altitude OSD element.
879 TEST_F(OsdTest, TestElementAltitude)
881 // given
882 osdElementConfigMutable()->item_pos[OSD_ALTITUDE] = OSD_POS(23, 7) | OSD_PROFILE_1_FLAG;
884 osdAnalyzeActiveElements();
886 // and
887 osdConfigMutable()->units = OSD_UNIT_METRIC;
888 sensorsClear(SENSOR_GPS);
890 // when
891 simulationAltitude = 0;
892 displayClearScreen(&testDisplayPort);
893 osdRefresh(simulationTime);
895 // then
896 displayPortTestBufferSubstring(23, 7, "%c-", SYM_ALTITUDE);
898 // when
899 sensorsSet(SENSOR_GPS);
900 displayClearScreen(&testDisplayPort);
901 osdRefresh(simulationTime);
903 // then
904 displayPortTestBufferSubstring(23, 7, "%c0.0%c", SYM_ALTITUDE, SYM_M);
906 // when
907 simulationAltitude = 247;
908 displayClearScreen(&testDisplayPort);
909 osdRefresh(simulationTime);
911 // then
912 displayPortTestBufferSubstring(23, 7, "%c2.4%c", SYM_ALTITUDE, SYM_M);
914 // when
915 simulationAltitude = 4247;
916 displayClearScreen(&testDisplayPort);
917 osdRefresh(simulationTime);
919 // then
920 displayPortTestBufferSubstring(23, 7, "%c42.4%c", SYM_ALTITUDE, SYM_M);
922 // when
923 simulationAltitude = -247;
924 displayClearScreen(&testDisplayPort);
925 osdRefresh(simulationTime);
927 // then
928 displayPortTestBufferSubstring(23, 7, "%c-2.4%c", SYM_ALTITUDE, SYM_M);
930 // when
931 simulationAltitude = -70;
932 displayClearScreen(&testDisplayPort);
933 osdRefresh(simulationTime);
935 // then
936 displayPortTestBufferSubstring(23, 7, "%c-0.7%c", SYM_ALTITUDE, SYM_M);
941 * Tests the core temperature OSD element.
943 TEST_F(OsdTest, TestElementCoreTemperature)
945 // given
946 osdElementConfigMutable()->item_pos[OSD_CORE_TEMPERATURE] = OSD_POS(1, 8) | OSD_PROFILE_1_FLAG;
948 osdAnalyzeActiveElements();
950 // and
951 osdConfigMutable()->units = OSD_UNIT_METRIC;
953 // and
954 simulationCoreTemperature = 0;
956 // when
957 displayClearScreen(&testDisplayPort);
958 osdRefresh(simulationTime);
960 // then
961 displayPortTestBufferSubstring(1, 8, "C%c 0%c", SYM_TEMPERATURE, SYM_C);
963 // given
964 simulationCoreTemperature = 33;
966 // when
967 displayClearScreen(&testDisplayPort);
968 osdRefresh(simulationTime);
970 // then
971 displayPortTestBufferSubstring(1, 8, "C%c 33%c", SYM_TEMPERATURE, SYM_C);
973 // given
974 osdConfigMutable()->units = OSD_UNIT_IMPERIAL;
976 // when
977 displayClearScreen(&testDisplayPort);
978 osdRefresh(simulationTime);
980 // then
981 displayPortTestBufferSubstring(1, 8, "C%c 91%c", SYM_TEMPERATURE, SYM_F);
985 * Tests the battery notifications shown on the warnings OSD element.
987 TEST_F(OsdTest, TestElementWarningsBattery)
989 // given
990 osdElementConfigMutable()->item_pos[OSD_WARNINGS] = OSD_POS(9, 10) | OSD_PROFILE_1_FLAG;
991 osdConfigMutable()->enabledWarnings = 0; // disable all warnings
992 osdWarnSetState(OSD_WARNING_BATTERY_WARNING, true);
993 osdWarnSetState(OSD_WARNING_BATTERY_CRITICAL, true);
994 osdWarnSetState(OSD_WARNING_BATTERY_NOT_FULL, true);
996 osdAnalyzeActiveElements();
998 // and
999 batteryConfigMutable()->vbatfullcellvoltage = 410;
1001 // and
1002 // 4S battery
1003 simulationBatteryCellCount = 4;
1005 // and
1006 // used battery
1007 simulationBatteryVoltage = ((batteryConfig()->vbatmaxcellvoltage - 20) * simulationBatteryCellCount) - 1;
1008 simulationBatteryState = BATTERY_OK;
1010 // when
1011 displayClearScreen(&testDisplayPort);
1012 osdRefresh(simulationTime);
1014 // then
1015 displayPortTestBufferSubstring(9, 10, "BATT < FULL");
1017 // given
1018 // full battery
1019 simulationBatteryVoltage = 1680;
1020 simulationBatteryState = BATTERY_OK;
1022 // when
1023 displayClearScreen(&testDisplayPort);
1024 osdRefresh(simulationTime);
1026 // then
1027 displayPortTestBufferSubstring(9, 10, " ");
1029 // given
1030 // low battery
1031 simulationBatteryVoltage = 1400;
1032 simulationBatteryState = BATTERY_WARNING;
1034 // when
1035 displayClearScreen(&testDisplayPort);
1036 osdRefresh(simulationTime);
1038 // then
1039 displayPortTestBufferSubstring(9, 10, "LOW BATTERY ");
1041 // given
1042 // critical battery
1043 simulationBatteryVoltage = 1320;
1044 simulationBatteryState = BATTERY_CRITICAL;
1046 // when
1047 displayClearScreen(&testDisplayPort);
1048 osdRefresh(simulationTime);
1050 // then
1051 displayPortTestBufferSubstring(9, 10, " LAND NOW ");
1053 // given
1054 // full battery
1055 simulationBatteryVoltage = ((batteryConfig()->vbatmaxcellvoltage - 20) * simulationBatteryCellCount);
1056 simulationBatteryState = BATTERY_OK;
1058 // when
1059 displayClearScreen(&testDisplayPort);
1060 osdRefresh(simulationTime);
1062 // then
1063 displayPortTestBufferSubstring(9, 10, " ");
1065 // TODO
1069 * Tests the time string formatting function with a series of precision settings and time values.
1071 TEST_F(OsdTest, TestFormatTimeString)
1073 char buff[OSD_ELEMENT_BUFFER_LENGTH];
1075 /* Seconds precision, 0 us */
1076 osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 0);
1077 EXPECT_EQ(0, strcmp("00:00", buff));
1079 /* Seconds precision, 0.9 seconds */
1080 osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 0.9e6);
1081 EXPECT_EQ(0, strcmp("00:00", buff));
1083 /* Seconds precision, 10 seconds */
1084 osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 10e6);
1085 EXPECT_EQ(0, strcmp("00:10", buff));
1087 /* Seconds precision, 1 minute */
1088 osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 60e6);
1089 EXPECT_EQ(0, strcmp("01:00", buff));
1091 /* Seconds precision, 1 minute 59 seconds */
1092 osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 119e6);
1093 EXPECT_EQ(0, strcmp("01:59", buff));
1095 /* Hundredths precision, 0 us */
1096 osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 0);
1097 EXPECT_EQ(0, strcmp("00:00.00", buff));
1099 /* Hundredths precision, 10 milliseconds (one 100th of a second) */
1100 osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 10e3);
1101 EXPECT_EQ(0, strcmp("00:00.01", buff));
1103 /* Hundredths precision, 0.9 seconds */
1104 osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 0.9e6);
1105 EXPECT_EQ(0, strcmp("00:00.90", buff));
1107 /* Hundredths precision, 10 seconds */
1108 osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 10e6);
1109 EXPECT_EQ(0, strcmp("00:10.00", buff));
1111 /* Hundredths precision, 1 minute */
1112 osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 60e6);
1113 EXPECT_EQ(0, strcmp("01:00.00", buff));
1115 /* Hundredths precision, 1 minute 59 seconds */
1116 osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 119e6);
1117 EXPECT_EQ(0, strcmp("01:59.00", buff));
1120 TEST_F(OsdTest, TestConvertTemperatureUnits)
1122 /* In Celsius */
1123 osdConfigMutable()->units = OSD_UNIT_METRIC;
1124 EXPECT_EQ(osdConvertTemperatureToSelectedUnit(40), 40);
1126 /* In Fahrenheit */
1127 osdConfigMutable()->units = OSD_UNIT_IMPERIAL;
1128 EXPECT_EQ(osdConvertTemperatureToSelectedUnit(40), 104);
1130 /* In Fahrenheit with rounding */
1131 osdConfigMutable()->units = OSD_UNIT_IMPERIAL;
1132 EXPECT_EQ(osdConvertTemperatureToSelectedUnit(41), 106);
1135 // STUBS
1136 extern "C" {
1137 bool featureIsEnabled(uint32_t f) { return simulationFeatureFlags & f; }
1139 void beeperConfirmationBeeps(uint8_t) {}
1141 bool isModeActivationConditionPresent(boxId_e) {
1142 return false;
1145 bool IS_RC_MODE_ACTIVE(boxId_e) {
1146 return false;
1149 uint32_t micros() {
1150 return simulationTime;
1153 uint32_t millis() {
1154 return micros() / 1000;
1157 bool isBeeperOn() {
1158 return false;
1161 bool airmodeIsEnabled() {
1162 return false;
1165 uint8_t getCurrentPidProfileIndex() {
1166 return 0;
1169 uint8_t getCurrentControlRateProfileIndex() {
1170 return 0;
1173 batteryState_e getBatteryState() {
1174 return simulationBatteryState;
1177 uint8_t getBatteryCellCount() {
1178 return simulationBatteryCellCount;
1181 uint16_t getBatteryVoltage() {
1182 return simulationBatteryVoltage;
1185 uint16_t getBatteryAverageCellVoltage() {
1186 return simulationBatteryVoltage / simulationBatteryCellCount;
1189 int32_t getAmperage() {
1190 return simulationBatteryAmperage;
1193 int32_t getMAhDrawn() {
1194 return simulationMahDrawn;
1197 int32_t getEstimatedAltitudeCm() {
1198 return simulationAltitude;
1201 int32_t getEstimatedVario() {
1202 return simulationVerticalSpeed;
1205 int32_t blackboxGetLogNumber() {
1206 return 0;
1209 bool isBlackboxDeviceWorking() {
1210 return true;
1213 bool isBlackboxDeviceFull() {
1214 return false;
1217 bool isSerialTransmitBufferEmpty(const serialPort_t *) {
1218 return false;
1221 void serialWrite(serialPort_t *, uint8_t) {}
1223 bool cmsDisplayPortRegister(displayPort_t *) {
1224 return false;
1227 uint16_t getRssi(void) { return rssi; }
1229 uint8_t getRssiPercent(void) { return scaleRange(rssi, 0, RSSI_MAX_VALUE, 0, 100); }
1231 uint16_t rxGetLinkQuality(void) { return LINK_QUALITY_MAX_VALUE; }
1233 uint16_t getCoreTemperatureCelsius(void) { return simulationCoreTemperature; }
1235 bool isFlipOverAfterCrashActive(void) { return false; }
1237 float pidItermAccelerator(void) { return 1.0; }
1238 uint8_t getMotorCount(void){ return 4; }
1239 bool areMotorsRunning(void){ return true; }
1240 bool pidOsdAntiGravityActive(void) { return false; }
1241 bool failsafeIsActive(void) { return false; }
1242 bool gpsRescueIsConfigured(void) { return false; }
1243 int8_t calculateThrottlePercent(void) { return 0; }
1244 uint32_t persistentObjectRead(persistentObjectId_e) { return 0; }
1245 void persistentObjectWrite(persistentObjectId_e, uint32_t) {}
1246 bool isUpright(void) { return true; }