mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-15 04:15:44 +03:00
1413 lines
37 KiB
C++
1413 lines
37 KiB
C++
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
extern "C" {
|
|
#include "platform.h"
|
|
|
|
#include "build/debug.h"
|
|
|
|
#include "blackbox/blackbox.h"
|
|
#include "blackbox/blackbox_io.h"
|
|
|
|
#include "common/time.h"
|
|
|
|
#include "config/config.h"
|
|
#include "config/feature.h"
|
|
|
|
#include "drivers/osd_symbols.h"
|
|
#include "drivers/persistent.h"
|
|
#include "drivers/serial.h"
|
|
|
|
#include "fc/core.h"
|
|
#include "fc/rc_controls.h"
|
|
#include "fc/rc_modes.h"
|
|
#include "fc/runtime_config.h"
|
|
|
|
#include "flight/gps_rescue.h"
|
|
#include "flight/imu.h"
|
|
#include "flight/mixer.h"
|
|
#include "flight/pid.h"
|
|
|
|
#include "io/beeper.h"
|
|
#include "io/gps.h"
|
|
|
|
#include "osd/osd.h"
|
|
#include "osd/osd_elements.h"
|
|
#include "osd/osd_warnings.h"
|
|
|
|
#include "pg/pg.h"
|
|
#include "pg/pg_ids.h"
|
|
#include "pg/rx.h"
|
|
|
|
#include "sensors/acceleration.h"
|
|
#include "sensors/battery.h"
|
|
|
|
#include "rx/rx.h"
|
|
|
|
void osdUpdate(timeUs_t currentTimeUs);
|
|
void osdFormatTime(char * buff, osd_timer_precision_e precision, timeUs_t time);
|
|
int osdConvertTemperatureToSelectedUnit(int tempInDegreesCelcius);
|
|
|
|
uint16_t rssi;
|
|
attitudeEulerAngles_t attitude;
|
|
float rMat[3][3];
|
|
|
|
pidProfile_t *currentPidProfile;
|
|
int16_t debug[DEBUG16_VALUE_COUNT];
|
|
float rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT];
|
|
uint8_t GPS_numSat;
|
|
uint16_t GPS_distanceToHome;
|
|
int16_t GPS_directionToHome;
|
|
uint32_t GPS_distanceFlownInCm;
|
|
int32_t GPS_coord[2];
|
|
gpsSolutionData_t gpsSol;
|
|
float motor[8];
|
|
|
|
linkQualitySource_e linkQualitySource;
|
|
|
|
acc_t acc;
|
|
|
|
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);
|
|
PG_REGISTER(gpsRescueConfig_t, gpsRescueConfig, PG_GPS_RESCUE, 0);
|
|
PG_REGISTER(imuConfig_t, imuConfig, PG_IMU_CONFIG, 0);
|
|
PG_REGISTER(gpsConfig_t, gpsConfig, PG_GPS_CONFIG, 0);
|
|
|
|
timeUs_t simulationTime = 0;
|
|
batteryState_e simulationBatteryState;
|
|
uint8_t simulationBatteryCellCount;
|
|
uint16_t simulationBatteryVoltage;
|
|
uint32_t simulationBatteryAmperage;
|
|
uint32_t simulationMahDrawn;
|
|
float simulationWhDrawn;
|
|
int32_t simulationAltitude;
|
|
int32_t simulationVerticalSpeed;
|
|
uint16_t simulationCoreTemperature;
|
|
bool simulationGpsHealthy;
|
|
}
|
|
|
|
uint32_t simulationFeatureFlags = FEATURE_GPS;
|
|
|
|
/* #define DEBUG_OSD */
|
|
|
|
#include "unittest_macros.h"
|
|
#include "unittest_displayport.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
void setDefaultSimulationState()
|
|
{
|
|
memset(osdElementConfigMutable(), 0, sizeof(osdElementConfig_t));
|
|
|
|
osdConfigMutable()->enabled_stats = 0;
|
|
osdConfigMutable()->framerate_hz = 12;
|
|
|
|
rssi = 1024;
|
|
|
|
simulationBatteryState = BATTERY_OK;
|
|
simulationBatteryCellCount = 4;
|
|
simulationBatteryVoltage = 1680;
|
|
simulationBatteryAmperage = 0;
|
|
simulationMahDrawn = 0;
|
|
simulationWhDrawn = 0;
|
|
simulationAltitude = 0;
|
|
simulationVerticalSpeed = 0;
|
|
simulationCoreTemperature = 0;
|
|
simulationGpsHealthy = false;
|
|
|
|
rcData[PITCH] = 1500;
|
|
|
|
osdFlyTime = 0;
|
|
|
|
DISABLE_ARMING_FLAG(ARMED);
|
|
}
|
|
|
|
void osdRefresh()
|
|
{
|
|
while (osdUpdateCheck(simulationTime, 0)) {
|
|
osdUpdate(simulationTime);
|
|
simulationTime += 10;
|
|
}
|
|
simulationTime += 0.1e6;
|
|
}
|
|
/*
|
|
* 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);
|
|
|
|
simulationTime += 5e6;
|
|
// when
|
|
// sufficient OSD updates have been called
|
|
osdRefresh();
|
|
|
|
// 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();
|
|
|
|
// then
|
|
// arming alert disappears
|
|
#ifdef DEBUG_OSD
|
|
displayPortTestPrint();
|
|
#endif
|
|
if (testEmpty) {
|
|
displayPortTestBufferIsEmpty();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Auxiliary function. Test is there're stats that must be shown
|
|
*/
|
|
bool isSomeStatEnabled(void)
|
|
{
|
|
return (osdConfigMutable()->enabled_stats != 0);
|
|
}
|
|
|
|
/*
|
|
* 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();
|
|
|
|
// then
|
|
// post flight statistics displayed
|
|
if (isSomeStatEnabled()) {
|
|
unsigned enabledStats = osdConfigMutable()->enabled_stats;
|
|
unsigned count = 0;
|
|
while (enabledStats) {
|
|
count += enabledStats & 1;
|
|
enabledStats >>= 1;
|
|
}
|
|
|
|
displayPortTestBufferSubstring(2, 7 - count / 2, " --- STATS ---");
|
|
}
|
|
}
|
|
|
|
void setupStats(void)
|
|
{
|
|
// this set of enabled post flight statistics
|
|
osdStatSetState(OSD_STAT_MAX_SPEED, true);
|
|
osdStatSetState(OSD_STAT_MIN_BATTERY, true);
|
|
osdStatSetState(OSD_STAT_MIN_RSSI, true);
|
|
osdStatSetState(OSD_STAT_MAX_CURRENT, false);
|
|
osdStatSetState(OSD_STAT_USED_MAH, false);
|
|
osdStatSetState(OSD_STAT_MAX_ALTITUDE, true);
|
|
osdStatSetState(OSD_STAT_BLACKBOX, false);
|
|
osdStatSetState(OSD_STAT_END_BATTERY, true);
|
|
osdStatSetState(OSD_STAT_RTC_DATE_TIME, true);
|
|
osdStatSetState(OSD_STAT_MAX_DISTANCE, true);
|
|
osdStatSetState(OSD_STAT_FLIGHT_DISTANCE, true);
|
|
osdStatSetState(OSD_STAT_BLACKBOX_NUMBER, false);
|
|
osdStatSetState(OSD_STAT_MAX_G_FORCE, false);
|
|
osdStatSetState(OSD_STAT_MAX_ESC_TEMP, false);
|
|
osdStatSetState(OSD_STAT_MAX_ESC_RPM, false);
|
|
}
|
|
|
|
void simulateFlight(void)
|
|
{
|
|
// these conditions occur during flight
|
|
rssi = 1024;
|
|
gpsSol.groundSpeed = 500;
|
|
GPS_distanceToHome = 20;
|
|
GPS_distanceFlownInCm = 2000;
|
|
simulationBatteryVoltage = 1580;
|
|
simulationAltitude = 100;
|
|
simulationTime += 1e6;
|
|
while (osdUpdateCheck(simulationTime, 0)) {
|
|
osdUpdate(simulationTime);
|
|
simulationTime += 10;
|
|
}
|
|
|
|
rssi = 512;
|
|
gpsSol.groundSpeed = 800;
|
|
GPS_distanceToHome = 50;
|
|
GPS_distanceFlownInCm = 10000;
|
|
simulationBatteryVoltage = 1470;
|
|
simulationAltitude = 150;
|
|
simulationTime += 1e6;
|
|
while (osdUpdateCheck(simulationTime, 0)) {
|
|
osdUpdate(simulationTime);
|
|
simulationTime += 10;
|
|
}
|
|
|
|
rssi = 256;
|
|
gpsSol.groundSpeed = 200;
|
|
GPS_distanceToHome = 100;
|
|
GPS_distanceFlownInCm = 20000;
|
|
simulationBatteryVoltage = 1520;
|
|
simulationAltitude = 200;
|
|
simulationTime += 1e6;
|
|
while (osdUpdateCheck(simulationTime, 0)) {
|
|
osdUpdate(simulationTime);
|
|
simulationTime += 10;
|
|
}
|
|
|
|
rssi = 256;
|
|
gpsSol.groundSpeed = 800;
|
|
GPS_distanceToHome = 100;
|
|
GPS_distanceFlownInCm = 10000;
|
|
simulationBatteryVoltage = 1470;
|
|
simulationAltitude = 200; // converts to 6.56168 feet which rounds to 6.6 in imperial units stats test
|
|
simulationTime += 1e6;
|
|
while (osdUpdateCheck(simulationTime, 0)) {
|
|
osdUpdate(simulationTime);
|
|
simulationTime += 10;
|
|
}
|
|
|
|
simulationBatteryVoltage = 1520;
|
|
simulationTime += 1e6;
|
|
while (osdUpdateCheck(simulationTime, 0)) {
|
|
osdUpdate(simulationTime);
|
|
simulationTime += 10;
|
|
}
|
|
|
|
rssi = 256;
|
|
gpsSol.groundSpeed = 800;
|
|
GPS_distanceToHome = 1150;
|
|
GPS_distanceFlownInCm = 1050000;
|
|
simulationBatteryVoltage = 1470;
|
|
simulationAltitude = 200;
|
|
simulationTime += 1e6;
|
|
while (osdUpdateCheck(simulationTime, 0)) {
|
|
osdUpdate(simulationTime);
|
|
simulationTime += 10;
|
|
}
|
|
|
|
simulationBatteryVoltage = 1520;
|
|
simulationTime += 1e6;
|
|
}
|
|
|
|
class OsdTest : public ::testing::Test
|
|
{
|
|
protected:
|
|
static void SetUpTestCase() {
|
|
displayPortTestInit();
|
|
}
|
|
|
|
virtual void SetUp() {
|
|
setDefaultSimulationState();
|
|
}
|
|
|
|
virtual void TearDown() {
|
|
// Clean up the armed state without showing stats at the end of a test
|
|
osdConfigMutable()->enabled_stats = 0;
|
|
|
|
doTestDisarm();
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Tests initialisation of the OSD and the power on splash screen.
|
|
*/
|
|
TEST_F(OsdTest, TestInit)
|
|
{
|
|
// given
|
|
// display port is initialised
|
|
displayPortTestInit();
|
|
|
|
// and
|
|
// default state values are set
|
|
setDefaultSimulationState();
|
|
|
|
// and
|
|
// this battery configuration (used for battery voltage elements)
|
|
batteryConfigMutable()->vbatmincellvoltage = 330;
|
|
batteryConfigMutable()->vbatmaxcellvoltage = 430;
|
|
|
|
// when
|
|
// OSD is initialised
|
|
osdInit(&testDisplayPort, OSD_DISPLAYPORT_DEVICE_AUTO);
|
|
|
|
osdRefresh();
|
|
|
|
// 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;
|
|
osdRefresh();
|
|
|
|
// then
|
|
// display buffer should be empty
|
|
#ifdef DEBUG_OSD
|
|
displayPortTestPrint();
|
|
#endif
|
|
displayPortTestBufferIsEmpty();
|
|
}
|
|
|
|
/*
|
|
* Tests visibility of the ARMED notification after arming.
|
|
*/
|
|
TEST_F(OsdTest, TestArm)
|
|
{
|
|
doTestArm();
|
|
}
|
|
|
|
/*
|
|
* Tests display and timeout of the post flight statistics screen after disarming.
|
|
*/
|
|
TEST_F(OsdTest, TestDisarm)
|
|
{
|
|
doTestArm();
|
|
|
|
doTestDisarm();
|
|
|
|
// given
|
|
// post flight stats times out (60 seconds)
|
|
simulationTime += 60e6;
|
|
|
|
// when
|
|
// sufficient OSD updates have been called
|
|
osdRefresh();
|
|
|
|
// 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_F(OsdTest, TestDisarmWithImmediateRearm)
|
|
{
|
|
doTestArm();
|
|
|
|
doTestDisarm();
|
|
|
|
doTestArm();
|
|
}
|
|
|
|
/*
|
|
* Tests dismissing the statistics screen with pitch stick after disarming.
|
|
*/
|
|
TEST_F(OsdTest, TestDisarmWithDismissStats)
|
|
{
|
|
doTestArm();
|
|
|
|
doTestDisarm();
|
|
|
|
// given
|
|
// sticks have been moved
|
|
rcData[PITCH] = 1800;
|
|
|
|
// when
|
|
// sufficient OSD updates have been called
|
|
osdRefresh();
|
|
|
|
// then
|
|
// post flight stats screen disappears
|
|
#ifdef DEBUG_OSD
|
|
displayPortTestPrint();
|
|
#endif
|
|
displayPortTestBufferIsEmpty();
|
|
}
|
|
|
|
/*
|
|
* Tests the calculation of timing in statistics
|
|
*/
|
|
TEST_F(OsdTest, TestStatsTiming)
|
|
{
|
|
// given
|
|
osdStatSetState(OSD_STAT_RTC_DATE_TIME, true);
|
|
osdStatSetState(OSD_STAT_TIMER_1, true);
|
|
osdStatSetState(OSD_STAT_TIMER_2, true);
|
|
|
|
// 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
|
|
// this RTC time
|
|
dateTime_t dateTime;
|
|
dateTime.year = 2017;
|
|
dateTime.month = 11;
|
|
dateTime.day = 19;
|
|
dateTime.hours = 10;
|
|
dateTime.minutes = 12;
|
|
dateTime.seconds = 0;
|
|
dateTime.millis = 0;
|
|
rtcSetDateTime(&dateTime);
|
|
|
|
// when
|
|
// the craft is armed
|
|
doTestArm();
|
|
|
|
// and
|
|
// these conditions occur during flight
|
|
simulationTime += 1e6;
|
|
osdRefresh();
|
|
|
|
// and
|
|
// the craft is disarmed
|
|
doTestDisarm();
|
|
|
|
// and
|
|
// the craft is armed again
|
|
doTestArm();
|
|
|
|
// and
|
|
// these conditions occur during flight
|
|
simulationTime += 1e6;
|
|
osdRefresh();
|
|
|
|
// and
|
|
// the craft is disarmed
|
|
doTestDisarm();
|
|
|
|
// then
|
|
// statistics screen should display the following
|
|
int row = 7;
|
|
displayPortTestBufferSubstring(2, row++, "2017-11-19 10:12:");
|
|
displayPortTestBufferSubstring(2, row++, "TOTAL ARM : 00:13.61");
|
|
displayPortTestBufferSubstring(2, row++, "LAST ARM : 00:01");
|
|
}
|
|
|
|
/*
|
|
* Tests the calculation of statistics with imperial unit output.
|
|
*/
|
|
TEST_F(OsdTest, TestStatsImperial)
|
|
{
|
|
// given
|
|
setupStats();
|
|
|
|
// and
|
|
// using imperial unit system
|
|
osdConfigMutable()->units = UNIT_IMPERIAL;
|
|
|
|
// and
|
|
// a GPS fix is present
|
|
stateFlags |= GPS_FIX | GPS_FIX_HOME;
|
|
|
|
// when
|
|
// the craft is armed
|
|
doTestArm();
|
|
|
|
// and
|
|
simulateFlight();
|
|
|
|
// and
|
|
// the craft is disarmed
|
|
doTestDisarm();
|
|
|
|
// then
|
|
// statistics screen should display the following
|
|
int row = 5;
|
|
displayPortTestBufferSubstring(2, row++, "MAX ALTITUDE : 6.6%c", SYM_FT);
|
|
displayPortTestBufferSubstring(2, row++, "MAX SPEED : 17");
|
|
displayPortTestBufferSubstring(2, row++, "MAX DISTANCE : 3772%c", SYM_FT);
|
|
displayPortTestBufferSubstring(2, row++, "FLIGHT DISTANCE : 6.52%c", SYM_MILES);
|
|
displayPortTestBufferSubstring(2, row++, "MIN BATTERY : 14.70%c", SYM_VOLT);
|
|
displayPortTestBufferSubstring(2, row++, "END BATTERY : 15.20%c", SYM_VOLT);
|
|
displayPortTestBufferSubstring(2, row++, "MIN RSSI : 25%%");
|
|
}
|
|
|
|
/*
|
|
* Tests the calculation of statistics with metric unit output.
|
|
* (essentially an abridged version of the previous test
|
|
*/
|
|
TEST_F(OsdTest, TestStatsMetric)
|
|
{
|
|
// given
|
|
setupStats();
|
|
|
|
// and
|
|
// using metric unit system
|
|
osdConfigMutable()->units = UNIT_METRIC;
|
|
|
|
// when
|
|
// the craft is armed
|
|
doTestArm();
|
|
|
|
// and
|
|
simulateFlight();
|
|
|
|
// and
|
|
// the craft is disarmed
|
|
doTestDisarm();
|
|
|
|
// then
|
|
// statistics screen should display the following
|
|
int row = 5;
|
|
displayPortTestBufferSubstring(2, row++, "MAX ALTITUDE : 2.0%c", SYM_M);
|
|
displayPortTestBufferSubstring(2, row++, "MAX SPEED : 28");
|
|
displayPortTestBufferSubstring(2, row++, "MAX DISTANCE : 1.15%c", SYM_KM);
|
|
displayPortTestBufferSubstring(2, row++, "FLIGHT DISTANCE : 10.5%c", SYM_KM);
|
|
displayPortTestBufferSubstring(2, row++, "MIN BATTERY : 14.70%c", SYM_VOLT);
|
|
displayPortTestBufferSubstring(2, row++, "END BATTERY : 15.20%c", SYM_VOLT);
|
|
displayPortTestBufferSubstring(2, row++, "MIN RSSI : 25%%");
|
|
}
|
|
|
|
/*
|
|
* Tests the calculation of statistics with metric unit output.
|
|
* (essentially an abridged version of the previous test
|
|
*/
|
|
TEST_F(OsdTest, TestStatsMetricDistanceUnits)
|
|
{
|
|
// given
|
|
setupStats();
|
|
|
|
// and
|
|
// using metric unit system
|
|
osdConfigMutable()->units = UNIT_METRIC;
|
|
|
|
// when
|
|
// the craft is armed
|
|
doTestArm();
|
|
|
|
// and
|
|
simulateFlight();
|
|
|
|
// and
|
|
// the craft is disarmed
|
|
doTestDisarm();
|
|
|
|
// then
|
|
// statistics screen should display the following
|
|
int row = 5;
|
|
displayPortTestBufferSubstring(2, row++, "MAX ALTITUDE : 2.0%c", SYM_M);
|
|
displayPortTestBufferSubstring(2, row++, "MAX SPEED : 28");
|
|
displayPortTestBufferSubstring(2, row++, "MAX DISTANCE : 1.15%c", SYM_KM);
|
|
displayPortTestBufferSubstring(2, row++, "FLIGHT DISTANCE : 10.5%c", SYM_KM);
|
|
displayPortTestBufferSubstring(2, row++, "MIN BATTERY : 14.70%c", SYM_VOLT);
|
|
displayPortTestBufferSubstring(2, row++, "END BATTERY : 15.20%c", SYM_VOLT);
|
|
displayPortTestBufferSubstring(2, row++, "MIN RSSI : 25%%");
|
|
}
|
|
|
|
/*
|
|
* Tests activation of alarms and element flashing.
|
|
*/
|
|
TEST_F(OsdTest, TestAlarms)
|
|
{
|
|
// given
|
|
sensorsSet(SENSOR_GPS);
|
|
|
|
// and
|
|
// the following OSD elements are visible
|
|
osdElementConfigMutable()->item_pos[OSD_RSSI_VALUE] = OSD_POS(8, 1) | OSD_PROFILE_1_FLAG;
|
|
osdElementConfigMutable()->item_pos[OSD_MAIN_BATT_VOLTAGE] = OSD_POS(12, 1) | OSD_PROFILE_1_FLAG;
|
|
osdElementConfigMutable()->item_pos[OSD_ITEM_TIMER_1] = OSD_POS(20, 1) | OSD_PROFILE_1_FLAG;
|
|
osdElementConfigMutable()->item_pos[OSD_ITEM_TIMER_2] = OSD_POS(1, 1) | OSD_PROFILE_1_FLAG;
|
|
osdElementConfigMutable()->item_pos[OSD_REMAINING_TIME_ESTIMATE] = OSD_POS(1, 2) | OSD_PROFILE_1_FLAG;
|
|
osdElementConfigMutable()->item_pos[OSD_ALTITUDE] = OSD_POS(23, 7) | OSD_PROFILE_1_FLAG;
|
|
|
|
// and
|
|
// this set of alarm values
|
|
osdConfigMutable()->rssi_alarm = 20;
|
|
osdConfigMutable()->cap_alarm = 2200;
|
|
osdConfigMutable()->alt_alarm = 100; // meters
|
|
|
|
osdAnalyzeActiveElements();
|
|
|
|
// and
|
|
// this timer 1 configuration
|
|
osdConfigMutable()->timers[OSD_TIMER_1] = OSD_TIMER(OSD_TIMER_SRC_ON, OSD_TIMER_PREC_HUNDREDTHS, 5);
|
|
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(5, 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, 2);
|
|
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(2, OSD_TIMER_ALARM(osdConfig()->timers[OSD_TIMER_2]));
|
|
|
|
// and
|
|
// using the metric unit system
|
|
osdConfigMutable()->units = UNIT_METRIC;
|
|
|
|
// when
|
|
// time is passing by
|
|
simulationTime += 60e6;
|
|
osdRefresh();
|
|
|
|
// and
|
|
// the craft is armed
|
|
doTestArm(false);
|
|
|
|
simulationTime += 70e6;
|
|
osdRefresh();
|
|
|
|
// 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();
|
|
|
|
#ifdef DEBUG_OSD
|
|
printf("%d\n", i);
|
|
#endif
|
|
displayPortTestBufferSubstring(1, 1, "%c01:", SYM_FLY_M); // only test the minute part of the timer
|
|
displayPortTestBufferSubstring(8, 1, "%c99", SYM_RSSI);
|
|
displayPortTestBufferSubstring(12, 1, "%c16.8%c", SYM_BATT_FULL, SYM_VOLT);
|
|
displayPortTestBufferSubstring(20, 1, "%c04:", SYM_ON_M); // only test the minute part of the timer
|
|
displayPortTestBufferSubstring(23, 7, "%c0.0%c", SYM_ALTITUDE, SYM_M);
|
|
}
|
|
|
|
// when
|
|
// all values are out of range
|
|
rssi = 128;
|
|
simulationBatteryState = BATTERY_CRITICAL;
|
|
simulationBatteryVoltage = 1350;
|
|
simulationAltitude = 12000;
|
|
simulationMahDrawn = 999999;
|
|
|
|
simulationTime += 60e6;
|
|
osdRefresh();
|
|
|
|
// then
|
|
// elements showing values in alarm range should flash
|
|
simulationTime += 1000000;
|
|
simulationTime -= simulationTime % 1000000;
|
|
timeUs_t startTime = simulationTime;
|
|
for (int i = 0; i < 15; i++) {
|
|
// Blinking should happen at 2Hz
|
|
simulationTime = startTime + i*0.25e6;
|
|
osdRefresh();
|
|
|
|
#ifdef DEBUG_OSD
|
|
printf("%d\n", i);
|
|
displayPortTestPrint();
|
|
#endif
|
|
if (i % 2 == 1) {
|
|
displayPortTestBufferSubstring(8, 1, "%c12", SYM_RSSI);
|
|
displayPortTestBufferSubstring(12, 1, "%c13.5%c", SYM_MAIN_BATT, SYM_VOLT);
|
|
displayPortTestBufferSubstring(1, 1, "%c02:", SYM_FLY_M); // only test the minute part of the timer
|
|
displayPortTestBufferSubstring(20, 1, "%c05:", SYM_ON_M); // only test the minute part of the timer
|
|
displayPortTestBufferSubstring(23, 7, "%c120.0%c", SYM_ALTITUDE, SYM_M);
|
|
} else {
|
|
displayPortTestBufferIsEmpty();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Tests the RSSI OSD element.
|
|
*/
|
|
TEST_F(OsdTest, TestElementRssi)
|
|
{
|
|
// given
|
|
osdElementConfigMutable()->item_pos[OSD_RSSI_VALUE] = OSD_POS(8, 1) | OSD_PROFILE_1_FLAG;
|
|
osdConfigMutable()->rssi_alarm = 0;
|
|
|
|
osdAnalyzeActiveElements();
|
|
|
|
// when
|
|
rssi = 1024;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(8, 1, "%c99", SYM_RSSI);
|
|
|
|
// when
|
|
rssi = 0;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(8, 1, "%c 0", SYM_RSSI);
|
|
|
|
// when
|
|
rssi = 512;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(8, 1, "%c50", SYM_RSSI);
|
|
}
|
|
|
|
/*
|
|
* Tests the instantaneous battery current OSD element.
|
|
*/
|
|
TEST_F(OsdTest, TestElementAmperage)
|
|
{
|
|
// given
|
|
osdElementConfigMutable()->item_pos[OSD_CURRENT_DRAW] = OSD_POS(1, 12) | OSD_PROFILE_1_FLAG;
|
|
|
|
osdAnalyzeActiveElements();
|
|
|
|
// when
|
|
simulationBatteryAmperage = 0;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 12, " 0.00%c", SYM_AMP);
|
|
|
|
// when
|
|
simulationBatteryAmperage = 2156;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 12, " 21.56%c", SYM_AMP);
|
|
|
|
// when
|
|
simulationBatteryAmperage = 12345;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 12, "123.45%c", SYM_AMP);
|
|
}
|
|
|
|
/*
|
|
* Tests the battery capacity drawn OSD element.
|
|
*/
|
|
TEST_F(OsdTest, TestElementMahDrawn)
|
|
{
|
|
// given
|
|
osdElementConfigMutable()->item_pos[OSD_MAH_DRAWN] = OSD_POS(1, 11) | OSD_PROFILE_1_FLAG;
|
|
|
|
osdAnalyzeActiveElements();
|
|
|
|
// when
|
|
simulationMahDrawn = 0;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 11, " 0%c", SYM_MAH);
|
|
|
|
// when
|
|
simulationMahDrawn = 4;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 11, " 4%c", SYM_MAH);
|
|
|
|
// when
|
|
simulationMahDrawn = 15;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 11, " 15%c", SYM_MAH);
|
|
|
|
// when
|
|
simulationMahDrawn = 246;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 11, " 246%c", SYM_MAH);
|
|
|
|
// when
|
|
simulationMahDrawn = 1042;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 11, "1042%c", SYM_MAH);
|
|
}
|
|
|
|
/*
|
|
* Tests the instantaneous electrical power OSD element.
|
|
*/
|
|
TEST_F(OsdTest, TestElementPower)
|
|
{
|
|
// given
|
|
osdElementConfigMutable()->item_pos[OSD_POWER] = OSD_POS(1, 10) | OSD_PROFILE_1_FLAG;
|
|
|
|
osdAnalyzeActiveElements();
|
|
|
|
// and
|
|
simulationBatteryVoltage = 1000; // 10V
|
|
|
|
// and
|
|
simulationBatteryAmperage = 0; // 0A
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 10, " 0W");
|
|
|
|
// given
|
|
simulationBatteryAmperage = 10; // 0.1A
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 10, " 1W");
|
|
|
|
// given
|
|
simulationBatteryAmperage = 120; // 1.2A
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 10, " 12W");
|
|
|
|
// given
|
|
simulationBatteryAmperage = 1230; // 12.3A
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 10, " 123W");
|
|
|
|
// given
|
|
simulationBatteryAmperage = 12340; // 123.4A
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 10, "1234W");
|
|
}
|
|
|
|
/*
|
|
* Tests the altitude OSD element.
|
|
*/
|
|
TEST_F(OsdTest, TestElementAltitude)
|
|
{
|
|
// given
|
|
osdElementConfigMutable()->item_pos[OSD_ALTITUDE] = OSD_POS(23, 7) | OSD_PROFILE_1_FLAG;
|
|
|
|
osdAnalyzeActiveElements();
|
|
|
|
// and
|
|
osdConfigMutable()->units = UNIT_METRIC;
|
|
sensorsClear(SENSOR_GPS);
|
|
|
|
// when
|
|
simulationAltitude = 0;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(23, 7, "%c-", SYM_ALTITUDE);
|
|
|
|
// when
|
|
sensorsSet(SENSOR_GPS);
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(23, 7, "%c0.0%c", SYM_ALTITUDE, SYM_M);
|
|
|
|
// when
|
|
simulationAltitude = 247; // rounds to 2.5m
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(23, 7, "%c2.5%c", SYM_ALTITUDE, SYM_M);
|
|
|
|
// when
|
|
simulationAltitude = 4247; // rounds to 42.5m
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(23, 7, "%c42.5%c", SYM_ALTITUDE, SYM_M);
|
|
|
|
// when
|
|
simulationAltitude = -247; // rounds to -2.5m
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(23, 7, "%c-2.5%c", SYM_ALTITUDE, SYM_M);
|
|
|
|
// when
|
|
simulationAltitude = -70;
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(23, 7, "%c-0.7%c", SYM_ALTITUDE, SYM_M);
|
|
|
|
}
|
|
|
|
/*
|
|
* Tests the core temperature OSD element.
|
|
*/
|
|
TEST_F(OsdTest, TestElementCoreTemperature)
|
|
{
|
|
// given
|
|
osdElementConfigMutable()->item_pos[OSD_CORE_TEMPERATURE] = OSD_POS(1, 8) | OSD_PROFILE_1_FLAG;
|
|
|
|
osdAnalyzeActiveElements();
|
|
|
|
// and
|
|
osdConfigMutable()->units = UNIT_METRIC;
|
|
|
|
// and
|
|
simulationCoreTemperature = 0;
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 8, "C%c 0%c", SYM_TEMPERATURE, SYM_C);
|
|
|
|
// given
|
|
simulationCoreTemperature = 33;
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 8, "C%c 33%c", SYM_TEMPERATURE, SYM_C);
|
|
|
|
// given
|
|
osdConfigMutable()->units = UNIT_IMPERIAL;
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(1, 8, "C%c 91%c", SYM_TEMPERATURE, SYM_F);
|
|
}
|
|
|
|
/*
|
|
* Tests the battery notifications shown on the warnings OSD element.
|
|
*/
|
|
TEST_F(OsdTest, TestElementWarningsBattery)
|
|
{
|
|
// given
|
|
osdElementConfigMutable()->item_pos[OSD_WARNINGS] = OSD_POS(9, 10) | OSD_PROFILE_1_FLAG;
|
|
osdConfigMutable()->enabledWarnings = 0; // disable all warnings
|
|
osdWarnSetState(OSD_WARNING_BATTERY_WARNING, true);
|
|
osdWarnSetState(OSD_WARNING_BATTERY_CRITICAL, true);
|
|
osdWarnSetState(OSD_WARNING_BATTERY_NOT_FULL, true);
|
|
|
|
osdAnalyzeActiveElements();
|
|
|
|
// and
|
|
batteryConfigMutable()->vbatfullcellvoltage = 410;
|
|
|
|
// and
|
|
// 4S battery
|
|
simulationBatteryCellCount = 4;
|
|
|
|
// and
|
|
// used battery
|
|
simulationBatteryVoltage = ((batteryConfig()->vbatmaxcellvoltage - 20) * simulationBatteryCellCount) - 1;
|
|
simulationBatteryState = BATTERY_OK;
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
// Delay as the warnings are flashing
|
|
simulationTime += 1000000;
|
|
simulationTime -= simulationTime % 1000000;
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(9, 10, "BATT < FULL");
|
|
|
|
// given
|
|
// full battery
|
|
simulationBatteryVoltage = 1680;
|
|
simulationBatteryState = BATTERY_OK;
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(9, 10, " ");
|
|
|
|
// given
|
|
// low battery
|
|
simulationBatteryVoltage = 1400;
|
|
simulationBatteryState = BATTERY_WARNING;
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
// Delay as the warnings are flashing
|
|
simulationTime += 1000000;
|
|
simulationTime -= simulationTime % 1000000;
|
|
simulationTime += 0.25e6;
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(9, 10, "LOW BATTERY ");
|
|
|
|
// given
|
|
// critical battery
|
|
simulationBatteryVoltage = 1320;
|
|
simulationBatteryState = BATTERY_CRITICAL;
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
// Delay as the warnings are flashing
|
|
simulationTime += 1000000;
|
|
simulationTime -= simulationTime % 1000000;
|
|
simulationTime += 0.25e6;
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(9, 10, " LAND NOW ");
|
|
|
|
// given
|
|
// full battery
|
|
simulationBatteryVoltage = ((batteryConfig()->vbatmaxcellvoltage - 20) * simulationBatteryCellCount);
|
|
simulationBatteryState = BATTERY_OK;
|
|
|
|
// when
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(9, 10, " ");
|
|
|
|
// TODO
|
|
}
|
|
|
|
/*
|
|
* Tests the time string formatting function with a series of precision settings and time values.
|
|
*/
|
|
TEST_F(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));
|
|
}
|
|
|
|
TEST_F(OsdTest, TestConvertTemperatureUnits)
|
|
{
|
|
/* In Celsius */
|
|
osdConfigMutable()->units = UNIT_METRIC;
|
|
EXPECT_EQ(osdConvertTemperatureToSelectedUnit(40), 40);
|
|
|
|
/* In Fahrenheit */
|
|
osdConfigMutable()->units = UNIT_IMPERIAL;
|
|
EXPECT_EQ(osdConvertTemperatureToSelectedUnit(40), 104);
|
|
|
|
/* In Fahrenheit with rounding */
|
|
osdConfigMutable()->units = UNIT_IMPERIAL;
|
|
EXPECT_EQ(osdConvertTemperatureToSelectedUnit(41), 106);
|
|
}
|
|
|
|
TEST_F(OsdTest, TestGpsElements)
|
|
{
|
|
// given
|
|
osdElementConfigMutable()->item_pos[OSD_GPS_SATS] = OSD_POS(2, 4) | OSD_PROFILE_1_FLAG;
|
|
|
|
sensorsSet(SENSOR_GPS);
|
|
osdAnalyzeActiveElements();
|
|
|
|
// when
|
|
simulationGpsHealthy = false;
|
|
gpsSol.numSat = 0;
|
|
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
// Sat indicator should blink and show "NC"
|
|
simulationTime += 1000000;
|
|
simulationTime -= simulationTime % 1000000;
|
|
timeUs_t startTime = simulationTime;
|
|
for (int i = 0; i < 15; i++) {
|
|
// Blinking should happen at 2Hz
|
|
simulationTime = startTime + i*0.25e6;
|
|
osdRefresh();
|
|
|
|
if (i % 2 == 1) {
|
|
displayPortTestBufferSubstring(2, 4, "%c%cNC", SYM_SAT_L, SYM_SAT_R);
|
|
} else {
|
|
displayPortTestBufferIsEmpty();
|
|
}
|
|
}
|
|
|
|
// when
|
|
simulationGpsHealthy = true;
|
|
gpsSol.numSat = 0;
|
|
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
// Sat indicator should blink and show "0"
|
|
simulationTime += 1000000;
|
|
simulationTime -= simulationTime % 1000000;
|
|
startTime = simulationTime;
|
|
for (int i = 0; i < 15; i++) {
|
|
// Blinking should happen at 2Hz
|
|
simulationTime = startTime + i*0.25e6;
|
|
osdRefresh();
|
|
|
|
if (i % 2 == 1) {
|
|
displayPortTestBufferSubstring(2, 4, "%c%c 0", SYM_SAT_L, SYM_SAT_R);
|
|
} else {
|
|
displayPortTestBufferIsEmpty();
|
|
}
|
|
}
|
|
|
|
// when
|
|
simulationGpsHealthy = true;
|
|
gpsSol.numSat = 10;
|
|
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
// Sat indicator should show "10" without flashing
|
|
for (int i = 0; i < 15; i++) {
|
|
// Blinking should happen at 2Hz
|
|
simulationTime += 0.2e6;
|
|
osdRefresh();
|
|
|
|
displayPortTestBufferSubstring(2, 4, "%c%c10", SYM_SAT_L, SYM_SAT_R);
|
|
}
|
|
}
|
|
|
|
TEST_F(OsdTest, TestHdPositioning)
|
|
{
|
|
// given
|
|
// Try to round-trip the OSD_POS macro with an "HD location"
|
|
osdElementConfigMutable()->item_pos[OSD_RSSI_VALUE] = OSD_POS(53, 0) | OSD_PROFILE_1_FLAG;
|
|
osdConfigMutable()->rssi_alarm = 0;
|
|
// Also try to round-trip a raw value matching one generated by the Configurator.
|
|
osdElementConfigMutable()->item_pos[OSD_CURRENT_DRAW] = 3125 | OSD_PROFILE_1_FLAG;
|
|
|
|
osdAnalyzeActiveElements();
|
|
|
|
// when
|
|
simulationBatteryAmperage = 0;
|
|
rssi = 1024;
|
|
|
|
displayClearScreen(&testDisplayPort, DISPLAY_CLEAR_WAIT);
|
|
osdRefresh();
|
|
|
|
// then
|
|
displayPortTestBufferSubstring(53, 0, "%c99", SYM_RSSI);
|
|
displayPortTestBufferSubstring(53, 1, " 0.00%c", SYM_AMP);
|
|
}
|
|
|
|
// STUBS
|
|
extern "C" {
|
|
bool featureIsEnabled(uint32_t f) { return simulationFeatureFlags & f; }
|
|
|
|
void beeperConfirmationBeeps(uint8_t) {}
|
|
|
|
bool isModeActivationConditionPresent(boxId_e) {
|
|
return false;
|
|
}
|
|
|
|
bool IS_RC_MODE_ACTIVE(boxId_e) {
|
|
return false;
|
|
}
|
|
|
|
uint32_t micros() {
|
|
return simulationTime;
|
|
}
|
|
|
|
uint32_t millis() {
|
|
return micros() / 1000;
|
|
}
|
|
|
|
bool isBeeperOn() {
|
|
return false;
|
|
}
|
|
|
|
bool airmodeIsEnabled() {
|
|
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;
|
|
}
|
|
|
|
float getWhDrawn() {
|
|
return simulationWhDrawn;
|
|
}
|
|
|
|
int32_t getEstimatedAltitudeCm() {
|
|
return simulationAltitude;
|
|
}
|
|
|
|
int32_t getEstimatedVario() {
|
|
return simulationVerticalSpeed;
|
|
}
|
|
|
|
int32_t blackboxGetLogNumber() {
|
|
return 0;
|
|
}
|
|
|
|
bool isBlackboxDeviceWorking() {
|
|
return true;
|
|
}
|
|
|
|
bool isBlackboxDeviceFull() {
|
|
return false;
|
|
}
|
|
|
|
bool isSerialTransmitBufferEmpty(const serialPort_t *) {
|
|
return false;
|
|
}
|
|
|
|
void serialWrite(serialPort_t *, uint8_t) {}
|
|
|
|
bool cmsDisplayPortRegister(displayPort_t *) {
|
|
return false;
|
|
}
|
|
|
|
uint16_t getRssi(void) { return rssi; }
|
|
|
|
uint8_t getRssiPercent(void) { return scaleRange(rssi, 0, RSSI_MAX_VALUE, 0, 100); }
|
|
|
|
uint16_t rxGetLinkQuality(void) { return LINK_QUALITY_MAX_VALUE; }
|
|
|
|
uint16_t getCoreTemperatureCelsius(void) { return simulationCoreTemperature; }
|
|
|
|
bool isFlipOverAfterCrashActive(void) { return false; }
|
|
|
|
float pidItermAccelerator(void) { return 1.0; }
|
|
uint8_t getMotorCount(void){ return 4; }
|
|
bool areMotorsRunning(void){ return true; }
|
|
bool pidOsdAntiGravityActive(void) { return false; }
|
|
bool failsafeIsActive(void) { return false; }
|
|
bool gpsRescueIsConfigured(void) { return false; }
|
|
bool gpsIsHealthy(void) { return simulationGpsHealthy; }
|
|
int8_t calculateThrottlePercent(void) { return 0; }
|
|
uint32_t persistentObjectRead(persistentObjectId_e) { return 0; }
|
|
void persistentObjectWrite(persistentObjectId_e, uint32_t) {}
|
|
bool isUpright(void) { return true; }
|
|
float getMotorOutputLow(void) { return 1000.0; }
|
|
float getMotorOutputHigh(void) { return 2047.0; }
|
|
void schedulerIgnoreTaskStateTime(void) { }
|
|
void schedulerIgnoreTaskExecRate(void) { }
|
|
void schedulerIgnoreTaskExecTime(void) { }
|
|
bool schedulerGetIgnoreTaskExecTime() { return false; }
|
|
void schedulerSetNextStateTime(timeDelta_t) {}
|
|
}
|