/*
* This file is part of Cleanflight.
*
* Cleanflight is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cleanflight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cleanflight. If not, see .
*/
#include
#include
#include
#include
extern "C" {
#include "platform.h"
#include "build/debug.h"
#include "blackbox/blackbox.h"
#include "config/parameter_group_ids.h"
#include "drivers/max7456_symbols.h"
#include "fc/config.h"
#include "fc/rc_controls.h"
#include "fc/rc_modes.h"
#include "fc/runtime_config.h"
#include "flight/pid.h"
#include "flight/imu.h"
#include "io/gps.h"
#include "io/osd.h"
#include "sensors/battery.h"
#include "rx/rx.h"
void osdRefresh(timeUs_t currentTimeUs);
void osdFormatTime(char * buff, osd_timer_precision_e precision, timeUs_t time);
void osdFormatTimer(char *buff, bool showSymbol, int timerIndex);
uint16_t rssi;
attitudeEulerAngles_t attitude;
pidProfile_t *currentPidProfile;
int16_t debug[DEBUG16_VALUE_COUNT];
int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT];
uint8_t GPS_numSat;
uint16_t GPS_distanceToHome;
uint16_t GPS_directionToHome;
int32_t GPS_coord[2];
gpsSolutionData_t gpsSol;
PG_REGISTER(batteryConfig_t, batteryConfig, PG_BATTERY_CONFIG, 0);
PG_REGISTER(blackboxConfig_t, blackboxConfig, PG_BLACKBOX_CONFIG, 0);
PG_REGISTER(systemConfig_t, systemConfig, PG_SYSTEM_CONFIG, 0);
PG_REGISTER(pilotConfig_t, pilotConfig, PG_PILOT_CONFIG, 0);
timeUs_t simulationTime = 0;
batteryState_e simulationBatteryState;
uint8_t simulationBatteryCellCount;
uint16_t simulationBatteryVoltage;
uint32_t simulationBatteryAmperage;
uint32_t simulationMahDrawn;
int32_t simulationAltitude;
int32_t simulationVerticalSpeed;
}
/* #define DEBUG_OSD */
#include "unittest_macros.h"
#include "unittest_displayport.h"
#include "gtest/gtest.h"
void setDefualtSimulationState()
{
rssi = 1024;
simulationBatteryState = BATTERY_OK;
simulationBatteryCellCount = 4;
simulationBatteryVoltage = 168;
simulationBatteryAmperage = 0;
simulationMahDrawn = 0;
simulationAltitude = 0;
simulationVerticalSpeed = 0;
}
/*
* Performs a test of the OSD actions on arming.
* (reused throughout the test suite)
*/
void doTestArm(bool testEmpty = true)
{
// given
// craft has been armed
ENABLE_ARMING_FLAG(ARMED);
// when
// sufficient OSD updates have been called
osdRefresh(simulationTime);
// then
// arming alert displayed
displayPortTestBufferSubstring(12, 7, "ARMED");
// given
// armed alert times out (0.5 seconds)
simulationTime += 0.5e6;
// when
// sufficient OSD updates have been called
osdRefresh(simulationTime);
// then
// arming alert disappears
#ifdef DEBUG_OSD
displayPortTestPrint();
#endif
if (testEmpty) {
displayPortTestBufferIsEmpty();
}
}
/*
* Performs a test of the OSD actions on disarming.
* (reused throughout the test suite)
*/
void doTestDisarm()
{
// given
// craft is disarmed after having been armed
DISABLE_ARMING_FLAG(ARMED);
// when
// sufficient OSD updates have been called
osdRefresh(simulationTime);
// then
// post flight statistics displayed
displayPortTestBufferSubstring(2, 2, " --- STATS ---");
}
/*
* Tests initialisation of the OSD and the power on splash screen.
*/
TEST(OsdTest, TestInit)
{
// given
// display port is initialised
displayPortTestInit();
// and
// default state values are set
setDefualtSimulationState();
// and
// this battery configuration (used for battery voltage elements)
batteryConfigMutable()->vbatmincellvoltage = 33;
batteryConfigMutable()->vbatmaxcellvoltage = 43;
// when
// OSD is initialised
osdInit(&testDisplayPort);
// then
// display buffer should contain splash screen
displayPortTestBufferSubstring(7, 8, "MENU: THR MID");
displayPortTestBufferSubstring(11, 9, "+ YAW LEFT");
displayPortTestBufferSubstring(11, 10, "+ PITCH UP");
// when
// splash screen timeout has elapsed
simulationTime += 4e6;
osdUpdate(simulationTime);
// then
// display buffer should be empty
#ifdef DEBUG_OSD
displayPortTestPrint();
#endif
displayPortTestBufferIsEmpty();
}
/*
* Tests visibility of the ARMED notification after arming.
*/
TEST(OsdTest, TestArm)
{
doTestArm();
}
/*
* Tests display and timeout of the post flight statistics screen after disarming.
*/
TEST(OsdTest, TestDisarm)
{
doTestDisarm();
// given
// post flight stats times out (60 seconds)
simulationTime += 60e6;
// when
// sufficient OSD updates have been called
osdRefresh(simulationTime);
// then
// post flight stats screen disappears
#ifdef DEBUG_OSD
displayPortTestPrint();
#endif
displayPortTestBufferIsEmpty();
}
/*
* Tests disarming and immediately rearming clears post flight stats and shows ARMED notification.
*/
TEST(OsdTest, TestDisarmWithImmediateRearm)
{
doTestArm();
doTestDisarm();
doTestArm();
}
/*
* Tests dismissing the statistics screen with pitch stick after disarming.
*/
TEST(OsdTest, TestDisarmWithDismissStats)
{
// Craft is alread armed after previous test
doTestDisarm();
// given
// sticks have been moved
rcData[PITCH] = 1800;
// when
// sufficient OSD updates have been called
osdRefresh(simulationTime);
osdRefresh(simulationTime);
// then
// post flight stats screen disappears
#ifdef DEBUG_OSD
displayPortTestPrint();
#endif
displayPortTestBufferIsEmpty();
rcData[PITCH] = 1500;
}
/*
* Tests the calculation of statistics with imperial unit output.
*/
TEST(OsdTest, TestStatsImperial)
{
// given
// this set of enabled post flight statistics
osdConfigMutable()->enabled_stats[OSD_STAT_MAX_SPEED] = true;
osdConfigMutable()->enabled_stats[OSD_STAT_MIN_BATTERY] = true;
osdConfigMutable()->enabled_stats[OSD_STAT_MIN_RSSI] = true;
osdConfigMutable()->enabled_stats[OSD_STAT_MAX_CURRENT] = false;
osdConfigMutable()->enabled_stats[OSD_STAT_USED_MAH] = false;
osdConfigMutable()->enabled_stats[OSD_STAT_MAX_ALTITUDE] = true;
osdConfigMutable()->enabled_stats[OSD_STAT_BLACKBOX] = false;
osdConfigMutable()->enabled_stats[OSD_STAT_END_BATTERY] = true;
osdConfigMutable()->enabled_stats[OSD_STAT_TIMER_1] = true;
osdConfigMutable()->enabled_stats[OSD_STAT_TIMER_2] = true;
osdConfigMutable()->enabled_stats[OSD_STAT_MAX_DISTANCE] = true;
osdConfigMutable()->enabled_stats[OSD_STAT_BLACKBOX_NUMBER] = false;
// and
// using imperial unit system
osdConfigMutable()->units = OSD_UNIT_IMPERIAL;
// and
// this timer 1 configuration
osdConfigMutable()->timers[OSD_TIMER_1] = OSD_TIMER(OSD_TIMER_SRC_TOTAL_ARMED, OSD_TIMER_PREC_HUNDREDTHS, 0);
// and
// this timer 2 configuration
osdConfigMutable()->timers[OSD_TIMER_2] = OSD_TIMER(OSD_TIMER_SRC_LAST_ARMED, OSD_TIMER_PREC_SECOND, 0);
// and
// a GPS fix is present
stateFlags |= GPS_FIX | GPS_FIX_HOME;
// when
// the craft is armed
doTestArm();
// and
// these conditions occur during flight
rssi = 1024;
gpsSol.groundSpeed = 500;
GPS_distanceToHome = 20;
simulationBatteryVoltage = 158;
simulationAltitude = 100;
simulationTime += 1e6;
osdRefresh(simulationTime);
rssi = 512;
gpsSol.groundSpeed = 800;
GPS_distanceToHome = 50;
simulationBatteryVoltage = 147;
simulationAltitude = 150;
simulationTime += 1e6;
osdRefresh(simulationTime);
rssi = 256;
gpsSol.groundSpeed = 200;
GPS_distanceToHome = 100;
simulationBatteryVoltage = 152;
simulationAltitude = 200;
simulationTime += 1e6;
osdRefresh(simulationTime);
// and
// the craft is disarmed
doTestDisarm();
// then
// statistics screen should display the following
int row = 3;
displayPortTestBufferSubstring(2, row++, "TOTAL ARM : 00:05.00");
displayPortTestBufferSubstring(2, row++, "LAST ARM : 00:03");
displayPortTestBufferSubstring(2, row++, "MAX SPEED : 28");
displayPortTestBufferSubstring(2, row++, "MAX DISTANCE : 328%c", SYM_FT);
displayPortTestBufferSubstring(2, row++, "MIN BATTERY : 14.7%c", SYM_VOLT);
displayPortTestBufferSubstring(2, row++, "END BATTERY : 15.2%c", SYM_VOLT);
displayPortTestBufferSubstring(2, row++, "MIN RSSI : 25%%");
displayPortTestBufferSubstring(2, row++, "MAX ALTITUDE : 6.5%c", SYM_FT);
}
/*
* Tests the calculation of statistics with metric unit output.
* (essentially an abridged version of the previous test
*/
TEST(OsdTest, TestStatsMetric)
{
// given
// using metric unit system
osdConfigMutable()->units = OSD_UNIT_METRIC;
// and
// default state values are set
setDefualtSimulationState();
// when
// the craft is armed
doTestArm();
// and
// these conditions occur during flight (simplified to less assignments than previous test)
rssi = 256;
gpsSol.groundSpeed = 800;
GPS_distanceToHome = 100;
simulationBatteryVoltage = 147;
simulationAltitude = 200;
simulationTime += 1e6;
osdRefresh(simulationTime);
osdRefresh(simulationTime);
simulationBatteryVoltage = 152;
simulationTime += 1e6;
osdRefresh(simulationTime);
// and
// the craft is disarmed
doTestDisarm();
// then
// statistics screen should display the following
int row = 3;
displayPortTestBufferSubstring(2, row++, "TOTAL ARM : 00:07.50");
displayPortTestBufferSubstring(2, row++, "LAST ARM : 00:02");
displayPortTestBufferSubstring(2, row++, "MAX SPEED : 28");
displayPortTestBufferSubstring(2, row++, "MAX DISTANCE : 100%c", SYM_M);
displayPortTestBufferSubstring(2, row++, "MIN BATTERY : 14.7%c", SYM_VOLT);
displayPortTestBufferSubstring(2, row++, "END BATTERY : 15.2%c", SYM_VOLT);
displayPortTestBufferSubstring(2, row++, "MIN RSSI : 25%%");
displayPortTestBufferSubstring(2, row++, "MAX ALTITUDE : 2.0%c", SYM_M);
}
/*
* Tests activation of alarms and element flashing.
*/
TEST(OsdTest, TestAlarms)
{
// given
// default state is set
setDefualtSimulationState();
// and
// the following OSD elements are visible
osdConfigMutable()->item_pos[OSD_RSSI_VALUE] = OSD_POS(8, 1) | VISIBLE_FLAG;
osdConfigMutable()->item_pos[OSD_MAIN_BATT_VOLTAGE] = OSD_POS(12, 1) | VISIBLE_FLAG;
osdConfigMutable()->item_pos[OSD_ITEM_TIMER_1] = OSD_POS(20, 1) | VISIBLE_FLAG;
osdConfigMutable()->item_pos[OSD_ITEM_TIMER_2] = OSD_POS(1, 1) | VISIBLE_FLAG;
osdConfigMutable()->item_pos[OSD_ALTITUDE] = OSD_POS(23, 7) | VISIBLE_FLAG;
// and
// this set of alarm values
osdConfigMutable()->rssi_alarm = 20;
osdConfigMutable()->cap_alarm = 2200;
osdConfigMutable()->alt_alarm = 100; // meters
// and
// this timer 1 configuration
osdConfigMutable()->timers[OSD_TIMER_1] = OSD_TIMER(OSD_TIMER_SRC_ON, OSD_TIMER_PREC_HUNDREDTHS, 2);
EXPECT_EQ(OSD_TIMER_SRC_ON, OSD_TIMER_SRC(osdConfig()->timers[OSD_TIMER_1]));
EXPECT_EQ(OSD_TIMER_PREC_HUNDREDTHS, OSD_TIMER_PRECISION(osdConfig()->timers[OSD_TIMER_1]));
EXPECT_EQ(2, OSD_TIMER_ALARM(osdConfig()->timers[OSD_TIMER_1]));
// and
// this timer 2 configuration
osdConfigMutable()->timers[OSD_TIMER_2] = OSD_TIMER(OSD_TIMER_SRC_TOTAL_ARMED, OSD_TIMER_PREC_SECOND, 1);
EXPECT_EQ(OSD_TIMER_SRC_TOTAL_ARMED, OSD_TIMER_SRC(osdConfig()->timers[OSD_TIMER_2]));
EXPECT_EQ(OSD_TIMER_PREC_SECOND, OSD_TIMER_PRECISION(osdConfig()->timers[OSD_TIMER_2]));
EXPECT_EQ(1, OSD_TIMER_ALARM(osdConfig()->timers[OSD_TIMER_2]));
// and
// using the metric unit system
osdConfigMutable()->units = OSD_UNIT_METRIC;
// when
// the craft is armed
doTestArm(false);
// then
// no elements should flash as all values are out of alarm range
for (int i = 0; i < 30; i++) {
// Check for visibility every 100ms, elements should always be visible
simulationTime += 0.1e6;
osdRefresh(simulationTime);
#ifdef DEBUG_OSD
printf("%d\n", i);
#endif
displayPortTestBufferSubstring(8, 1, "%c99", SYM_RSSI);
displayPortTestBufferSubstring(12, 1, "%c16.8%c", SYM_BATT_FULL, SYM_VOLT);
displayPortTestBufferSubstring(1, 1, "%c00:", SYM_FLY_M); // only test the minute part of the timer
displayPortTestBufferSubstring(20, 1, "%c01:", SYM_ON_M); // only test the minute part of the timer
displayPortTestBufferSubstring(23, 7, " 0.0%c", SYM_M);
}
// when
// all values are out of range
rssi = 128;
simulationBatteryState = BATTERY_CRITICAL;
simulationBatteryVoltage = 135;
simulationAltitude = 12000;
simulationTime += 60e6;
osdRefresh(simulationTime);
// then
// elements showing values in alarm range should flash
for (int i = 0; i < 15; i++) {
// Blinking should happen at 5Hz
simulationTime += 0.2e6;
osdRefresh(simulationTime);
#ifdef DEBUG_OSD
printf("%d\n", i);
displayPortTestPrint();
#endif
if (i % 2 == 0) {
displayPortTestBufferSubstring(8, 1, "%c12", SYM_RSSI);
displayPortTestBufferSubstring(12, 1, "%c13.5%c", SYM_MAIN_BATT, SYM_VOLT);
displayPortTestBufferSubstring(1, 1, "%c01:", SYM_FLY_M); // only test the minute part of the timer
displayPortTestBufferSubstring(20, 1, "%c02:", SYM_ON_M); // only test the minute part of the timer
displayPortTestBufferSubstring(23, 7, " 120.0%c", SYM_M);
} else {
displayPortTestBufferIsEmpty();
}
}
}
/*
* Tests the RSSI OSD element.
*/
TEST(OsdTest, TestElementRssi)
{
// given
osdConfigMutable()->item_pos[OSD_RSSI_VALUE] = OSD_POS(8, 1) | VISIBLE_FLAG;
osdConfigMutable()->rssi_alarm = 0;
// when
rssi = 1024;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(8, 1, "%c99", SYM_RSSI);
// when
rssi = 0;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(8, 1, "%c0", SYM_RSSI);
// when
rssi = 512;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(8, 1, "%c50", SYM_RSSI);
}
/*
* Tests the instantaneous battery current OSD element.
*/
TEST(OsdTest, TestElementAmperage)
{
// given
osdConfigMutable()->item_pos[OSD_CURRENT_DRAW] = OSD_POS(1, 12) | VISIBLE_FLAG;
// when
simulationBatteryAmperage = 0;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 12, " 0.00%c", SYM_AMP);
// when
simulationBatteryAmperage = 2156;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 12, " 21.56%c", SYM_AMP);
// when
simulationBatteryAmperage = 12345;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 12, "123.45%c", SYM_AMP);
}
/*
* Tests the battery capacity drawn OSD element.
*/
TEST(OsdTest, TestElementMahDrawn)
{
// given
osdConfigMutable()->item_pos[OSD_MAH_DRAWN] = OSD_POS(1, 11) | VISIBLE_FLAG;
// when
simulationMahDrawn = 0;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 11, " 0%c", SYM_MAH);
// when
simulationMahDrawn = 4;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 11, " 4%c", SYM_MAH);
// when
simulationMahDrawn = 15;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 11, " 15%c", SYM_MAH);
// when
simulationMahDrawn = 246;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 11, " 246%c", SYM_MAH);
// when
simulationMahDrawn = 1042;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 11, "1042%c", SYM_MAH);
}
/*
* Tests the instantaneous electrical power OSD element.
*/
TEST(OsdTest, TestElementPower)
{
// given
osdConfigMutable()->item_pos[OSD_POWER] = OSD_POS(1, 10) | VISIBLE_FLAG;
// and
simulationBatteryVoltage = 100; // 10V
// and
simulationBatteryAmperage = 0; // 0A
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 10, " 0W");
// given
simulationBatteryAmperage = 10; // 0.1A
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 10, " 1W");
// given
simulationBatteryAmperage = 120; // 1.2A
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 10, " 12W");
// given
simulationBatteryAmperage = 1230; // 12.3A
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 10, " 123W");
// given
simulationBatteryAmperage = 12340; // 123.4A
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(1, 10, "1234W");
}
/*
* Tests the altitude OSD element.
*/
TEST(OsdTest, TestElementAltitude)
{
// given
osdConfigMutable()->item_pos[OSD_ALTITUDE] = OSD_POS(23, 7) | VISIBLE_FLAG;
// and
osdConfigMutable()->units = OSD_UNIT_METRIC;
// when
simulationAltitude = 0;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(23, 7, " 0.0%c", SYM_M);
// when
simulationAltitude = 247;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(23, 7, " 2.4%c", SYM_M);
// when
simulationAltitude = 4247;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(23, 7, " 42.4%c", SYM_M);
// when
simulationAltitude = -247;
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(23, 7, " -2.4%c", SYM_M);
}
/*
* Tests the battery notifications shown on the warnings OSD element.
*/
TEST(OsdTest, TestElementWarningsBattery)
{
// given
osdConfigMutable()->item_pos[OSD_WARNINGS] = OSD_POS(9, 10) | VISIBLE_FLAG;
// and
batteryConfigMutable()->vbatfullcellvoltage = 41;
// and
// 4S battery
simulationBatteryCellCount = 4;
// and
// full battery
simulationBatteryVoltage = 168;
simulationBatteryState = BATTERY_OK;
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(9, 10, " ");
// given
// low battery
simulationBatteryVoltage = 140;
simulationBatteryState = BATTERY_WARNING;
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(9, 10, "LOW BATTERY ");
// given
// crtical battery
simulationBatteryVoltage = 132;
simulationBatteryState = BATTERY_CRITICAL;
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(9, 10, " LAND NOW ");
// given
// used battery
simulationBatteryVoltage = ((batteryConfig()->vbatmaxcellvoltage - 2) * simulationBatteryCellCount) - 1;
simulationBatteryState = BATTERY_OK;
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(9, 10, "BATT NOT FULL");
// given
// full battery
simulationBatteryVoltage = ((batteryConfig()->vbatmaxcellvoltage - 2) * simulationBatteryCellCount);
simulationBatteryState = BATTERY_OK;
// when
displayClearScreen(&testDisplayPort);
osdRefresh(simulationTime);
// then
displayPortTestBufferSubstring(9, 10, " ");
// TODO
}
/*
* Tests the time string formatting function with a series of precision settings and time values.
*/
TEST(OsdTest, TestFormatTimeString)
{
char buff[OSD_ELEMENT_BUFFER_LENGTH];
/* Seconds precision, 0 us */
osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 0);
EXPECT_EQ(0, strcmp("00:00", buff));
/* Seconds precision, 0.9 seconds */
osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 0.9e6);
EXPECT_EQ(0, strcmp("00:00", buff));
/* Seconds precision, 10 seconds */
osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 10e6);
EXPECT_EQ(0, strcmp("00:10", buff));
/* Seconds precision, 1 minute */
osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 60e6);
EXPECT_EQ(0, strcmp("01:00", buff));
/* Seconds precision, 1 minute 59 seconds */
osdFormatTime(buff, OSD_TIMER_PREC_SECOND, 119e6);
EXPECT_EQ(0, strcmp("01:59", buff));
/* Hundredths precision, 0 us */
osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 0);
EXPECT_EQ(0, strcmp("00:00.00", buff));
/* Hundredths precision, 10 milliseconds (one 100th of a second) */
osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 10e3);
EXPECT_EQ(0, strcmp("00:00.01", buff));
/* Hundredths precision, 0.9 seconds */
osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 0.9e6);
EXPECT_EQ(0, strcmp("00:00.90", buff));
/* Hundredths precision, 10 seconds */
osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 10e6);
EXPECT_EQ(0, strcmp("00:10.00", buff));
/* Hundredths precision, 1 minute */
osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 60e6);
EXPECT_EQ(0, strcmp("01:00.00", buff));
/* Hundredths precision, 1 minute 59 seconds */
osdFormatTime(buff, OSD_TIMER_PREC_HUNDREDTHS, 119e6);
EXPECT_EQ(0, strcmp("01:59.00", buff));
}
// STUBS
extern "C" {
void beeperConfirmationBeeps(uint8_t) {}
bool isModeActivationConditionPresent(boxId_e) {
return false;
}
bool IS_RC_MODE_ACTIVE(boxId_e) {
return false;
}
uint32_t micros() {
return simulationTime;
}
bool isBeeperOn() {
return false;
}
bool isAirmodeActive() {
return false;
}
uint8_t getCurrentPidProfileIndex() {
return 0;
}
uint8_t getCurrentControlRateProfileIndex() {
return 0;
}
batteryState_e getBatteryState() {
return simulationBatteryState;
}
uint8_t getBatteryCellCount() {
return simulationBatteryCellCount;
}
uint16_t getBatteryVoltage() {
return simulationBatteryVoltage;
}
uint16_t getBatteryAverageCellVoltage() {
return simulationBatteryVoltage / simulationBatteryCellCount;
}
int32_t getAmperage() {
return simulationBatteryAmperage;
}
int32_t getMAhDrawn() {
return simulationMahDrawn;
}
int32_t getEstimatedAltitude() {
return simulationAltitude;
}
int32_t getEstimatedVario() {
return simulationVerticalSpeed;
}
unsigned int blackboxGetLogNumber() {
return 0;
}
bool isSerialTransmitBufferEmpty(const serialPort_t *) {
return false;
}
void serialWrite(serialPort_t *, uint8_t) {}
bool cmsDisplayPortRegister(displayPort_t *) {
return false;
}
}