1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-19 14:25:20 +03:00

Merge pull request #10540 from etracer65/osd_warnings_msp

Separate OSD warnings from OSD task and make available via MSP
This commit is contained in:
Michael Keller 2021-02-17 07:52:37 +13:00 committed by GitHub
commit d2867ef9ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 417 additions and 288 deletions

View file

@ -96,30 +96,26 @@
#include "fc/core.h"
#include "fc/rc_adjustments.h"
#include "fc/rc_controls.h"
#include "fc/rc_modes.h"
#include "fc/rc.h"
#include "fc/runtime_config.h"
#include "flight/gps_rescue.h"
#include "flight/failsafe.h"
#include "flight/position.h"
#include "flight/imu.h"
#include "flight/mixer.h"
#include "flight/pid.h"
#include "io/beeper.h"
#include "io/gps.h"
#include "io/vtx.h"
#include "osd/osd.h"
#include "osd/osd_elements.h"
#include "osd/osd_warnings.h"
#include "pg/motor.h"
#include "pg/stats.h"
#include "rx/rx.h"
#include "sensors/acceleration.h"
#include "sensors/adcinternal.h"
#include "sensors/barometer.h"
#include "sensors/battery.h"
@ -1348,278 +1344,13 @@ static void osdElementVtxChannel(osdElementParms_t *element)
static void osdElementWarnings(osdElementParms_t *element)
{
#define OSD_WARNINGS_MAX_SIZE 12
#define OSD_FORMAT_MESSAGE_BUFFER_SIZE (OSD_WARNINGS_MAX_SIZE + 1)
STATIC_ASSERT(OSD_FORMAT_MESSAGE_BUFFER_SIZE <= OSD_ELEMENT_BUFFER_LENGTH, osd_warnings_size_exceeds_buffer_size);
const batteryState_e batteryState = getBatteryState();
const timeUs_t currentTimeUs = micros();
static timeUs_t armingDisabledUpdateTimeUs;
static unsigned armingDisabledDisplayIndex;
CLR_BLINK(OSD_WARNINGS);
// Cycle through the arming disabled reasons
if (osdWarnGetState(OSD_WARNING_ARMING_DISABLE)) {
if (IS_RC_MODE_ACTIVE(BOXARM) && isArmingDisabled()) {
const armingDisableFlags_e armSwitchOnlyFlag = 1 << (ARMING_DISABLE_FLAGS_COUNT - 1);
armingDisableFlags_e flags = getArmingDisableFlags();
// Remove the ARMSWITCH flag unless it's the only one
if ((flags & armSwitchOnlyFlag) && (flags != armSwitchOnlyFlag)) {
flags -= armSwitchOnlyFlag;
}
// Rotate to the next arming disabled reason after a 0.5 second time delay
// or if the current flag is no longer set
if ((currentTimeUs - armingDisabledUpdateTimeUs > 5e5) || !(flags & (1 << armingDisabledDisplayIndex))) {
if (armingDisabledUpdateTimeUs == 0) {
armingDisabledDisplayIndex = ARMING_DISABLE_FLAGS_COUNT - 1;
}
armingDisabledUpdateTimeUs = currentTimeUs;
do {
if (++armingDisabledDisplayIndex >= ARMING_DISABLE_FLAGS_COUNT) {
armingDisabledDisplayIndex = 0;
}
} while (!(flags & (1 << armingDisabledDisplayIndex)));
}
tfp_sprintf(element->buff, "%s", armingDisableFlagNames[armingDisabledDisplayIndex]);
element->attr = DISPLAYPORT_ATTR_WARNING;
return;
} else {
armingDisabledUpdateTimeUs = 0;
}
}
#ifdef USE_DSHOT
if (isTryingToArm() && !ARMING_FLAG(ARMED)) {
int armingDelayTime = (getLastDshotBeaconCommandTimeUs() + DSHOT_BEACON_GUARD_DELAY_US - currentTimeUs) / 1e5;
if (armingDelayTime < 0) {
armingDelayTime = 0;
}
if (armingDelayTime >= (DSHOT_BEACON_GUARD_DELAY_US / 1e5 - 5)) {
tfp_sprintf(element->buff, " BEACON ON"); // Display this message for the first 0.5 seconds
} else {
tfp_sprintf(element->buff, "ARM IN %d.%d", armingDelayTime / 10, armingDelayTime % 10);
}
element->attr = DISPLAYPORT_ATTR_INFO;
return;
}
#endif // USE_DSHOT
if (osdWarnGetState(OSD_WARNING_FAIL_SAFE) && failsafeIsActive()) {
tfp_sprintf(element->buff, "FAIL SAFE");
element->attr = DISPLAYPORT_ATTR_CRITICAL;
bool elementBlinking = false;
renderOsdWarning(element->buff, &elementBlinking, &element->attr);
if (elementBlinking) {
SET_BLINK(OSD_WARNINGS);
return;
} else {
CLR_BLINK(OSD_WARNINGS);
}
// Warn when in flip over after crash mode
if (osdWarnGetState(OSD_WARNING_CRASH_FLIP) && isFlipOverAfterCrashActive()) {
tfp_sprintf(element->buff, "CRASH FLIP");
element->attr = DISPLAYPORT_ATTR_INFO;
return;
}
#ifdef USE_LAUNCH_CONTROL
// Warn when in launch control mode
if (osdWarnGetState(OSD_WARNING_LAUNCH_CONTROL) && isLaunchControlActive()) {
#ifdef USE_ACC
if (sensors(SENSOR_ACC)) {
const int pitchAngle = constrain((attitude.raw[FD_PITCH] - accelerometerConfig()->accelerometerTrims.raw[FD_PITCH]) / 10, -90, 90);
tfp_sprintf(element->buff, "LAUNCH %d", pitchAngle);
} else
#endif // USE_ACC
{
tfp_sprintf(element->buff, "LAUNCH");
}
// Blink the message if the throttle is within 10% of the launch setting
if ( calculateThrottlePercent() >= MAX(currentPidProfile->launchControlThrottlePercent - 10, 0)) {
SET_BLINK(OSD_WARNINGS);
}
element->attr = DISPLAYPORT_ATTR_INFO;
return;
}
#endif // USE_LAUNCH_CONTROL
// RSSI
if (osdWarnGetState(OSD_WARNING_RSSI) && (getRssiPercent() < osdConfig()->rssi_alarm)) {
tfp_sprintf(element->buff, "RSSI LOW");
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
#ifdef USE_RX_RSSI_DBM
// rssi dbm
if (osdWarnGetState(OSD_WARNING_RSSI_DBM) && (getRssiDbm() < osdConfig()->rssi_dbm_alarm)) {
tfp_sprintf(element->buff, "RSSI DBM");
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
#endif // USE_RX_RSSI_DBM
#ifdef USE_RX_LINK_QUALITY_INFO
// Link Quality
if (osdWarnGetState(OSD_WARNING_LINK_QUALITY) && (rxGetLinkQualityPercent() < osdConfig()->link_quality_alarm)) {
tfp_sprintf(element->buff, "LINK QUALITY");
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
#endif // USE_RX_LINK_QUALITY_INFO
if (osdWarnGetState(OSD_WARNING_BATTERY_CRITICAL) && batteryState == BATTERY_CRITICAL) {
tfp_sprintf(element->buff, " LAND NOW");
element->attr = DISPLAYPORT_ATTR_CRITICAL;
SET_BLINK(OSD_WARNINGS);
return;
}
#ifdef USE_GPS_RESCUE
if (osdWarnGetState(OSD_WARNING_GPS_RESCUE_UNAVAILABLE) &&
ARMING_FLAG(ARMED) &&
gpsRescueIsConfigured() &&
!gpsRescueIsDisabled() &&
!gpsRescueIsAvailable()) {
tfp_sprintf(element->buff, "RESCUE N/A");
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
if (osdWarnGetState(OSD_WARNING_GPS_RESCUE_DISABLED) &&
ARMING_FLAG(ARMED) &&
gpsRescueIsConfigured() &&
gpsRescueIsDisabled()) {
statistic_t *stats = osdGetStats();
if (cmpTimeUs(stats->armed_time, OSD_GPS_RESCUE_DISABLED_WARNING_DURATION_US) < 0) {
tfp_sprintf(element->buff, "RESCUE OFF");
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
}
#endif // USE_GPS_RESCUE
// Show warning if in HEADFREE flight mode
if (FLIGHT_MODE(HEADFREE_MODE)) {
tfp_sprintf(element->buff, "HEADFREE");
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
#ifdef USE_ADC_INTERNAL
const int16_t coreTemperature = getCoreTemperatureCelsius();
if (osdWarnGetState(OSD_WARNING_CORE_TEMPERATURE) && coreTemperature >= osdConfig()->core_temp_alarm) {
tfp_sprintf(element->buff, "CORE %c: %3d%c", SYM_TEMPERATURE, osdConvertTemperatureToSelectedUnit(coreTemperature), osdGetTemperatureSymbolForSelectedUnit());
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
#endif // USE_ADC_INTERNAL
#ifdef USE_ESC_SENSOR
// Show warning if we lose motor output, the ESC is overheating or excessive current draw
if (featureIsEnabled(FEATURE_ESC_SENSOR) && osdWarnGetState(OSD_WARNING_ESC_FAIL)) {
char escWarningMsg[OSD_FORMAT_MESSAGE_BUFFER_SIZE];
unsigned pos = 0;
const char *title = "ESC";
// center justify message
while (pos < (OSD_WARNINGS_MAX_SIZE - (strlen(title) + getMotorCount())) / 2) {
escWarningMsg[pos++] = ' ';
}
strcpy(escWarningMsg + pos, title);
pos += strlen(title);
unsigned i = 0;
unsigned escWarningCount = 0;
while (i < getMotorCount() && pos < OSD_FORMAT_MESSAGE_BUFFER_SIZE - 1) {
escSensorData_t *escData = getEscSensorData(i);
const char motorNumber = '1' + i;
// if everything is OK just display motor number else R, T or C
char warnFlag = motorNumber;
if (ARMING_FLAG(ARMED) && osdConfig()->esc_rpm_alarm != ESC_RPM_ALARM_OFF && calcEscRpm(escData->rpm) <= osdConfig()->esc_rpm_alarm) {
warnFlag = 'R';
}
if (osdConfig()->esc_temp_alarm != ESC_TEMP_ALARM_OFF && escData->temperature >= osdConfig()->esc_temp_alarm) {
warnFlag = 'T';
}
if (ARMING_FLAG(ARMED) && osdConfig()->esc_current_alarm != ESC_CURRENT_ALARM_OFF && escData->current >= osdConfig()->esc_current_alarm) {
warnFlag = 'C';
}
escWarningMsg[pos++] = warnFlag;
if (warnFlag != motorNumber) {
escWarningCount++;
}
i++;
}
escWarningMsg[pos] = '\0';
if (escWarningCount > 0) {
tfp_sprintf(element->buff, "%s", escWarningMsg);
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
}
#endif // USE_ESC_SENSOR
if (osdWarnGetState(OSD_WARNING_BATTERY_WARNING) && batteryState == BATTERY_WARNING) {
tfp_sprintf(element->buff, "LOW BATTERY");
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
#ifdef USE_RC_SMOOTHING_FILTER
// Show warning if rc smoothing hasn't initialized the filters
if (osdWarnGetState(OSD_WARNING_RC_SMOOTHING) && ARMING_FLAG(ARMED) && !rcSmoothingInitializationComplete()) {
tfp_sprintf(element->buff, "RCSMOOTHING");
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
#endif // USE_RC_SMOOTHING_FILTER
// Show warning if mah consumed is over the configured limit
if (osdWarnGetState(OSD_WARNING_OVER_CAP) && ARMING_FLAG(ARMED) && osdConfig()->cap_alarm > 0 && getMAhDrawn() >= osdConfig()->cap_alarm) {
tfp_sprintf(element->buff, "OVER CAP");
element->attr = DISPLAYPORT_ATTR_WARNING;
SET_BLINK(OSD_WARNINGS);
return;
}
// Show warning if battery is not fresh
if (osdWarnGetState(OSD_WARNING_BATTERY_NOT_FULL) && !(ARMING_FLAG(ARMED) || ARMING_FLAG(WAS_EVER_ARMED)) && (getBatteryState() == BATTERY_OK)
&& getBatteryAverageCellVoltage() < batteryConfig()->vbatfullcellvoltage) {
tfp_sprintf(element->buff, "BATT < FULL");
element->attr = DISPLAYPORT_ATTR_INFO;
return;
}
// Visual beeper
if (osdWarnGetState(OSD_WARNING_VISUAL_BEEPER) && osdGetVisualBeeperState()) {
tfp_sprintf(element->buff, " * * * *");
element->attr = DISPLAYPORT_ATTR_INFO;
return;
}
}
// Define the order in which the elements are drawn.