diff --git a/mk/source.mk b/mk/source.mk index caefe30e0a..c8a878019f 100644 --- a/mk/source.mk +++ b/mk/source.mk @@ -105,6 +105,7 @@ COMMON_SRC = \ rx/msp.c \ rx/pwm.c \ rx/frsky_crc.c \ + rx/rc_stats.c \ rx/rx.c \ rx/rx_bind.c \ rx/rx_spi.c \ @@ -326,6 +327,7 @@ SPEED_OPTIMISED_SRC := $(SPEED_OPTIMISED_SRC) \ flight/pid.c \ flight/rpm_filter.c \ rx/ibus.c \ + rx/rc_stats.c \ rx/rx.c \ rx/rx_spi.c \ rx/crsf.c \ diff --git a/src/main/build/debug.c b/src/main/build/debug.c index 9fa64b3766..5e6ac432ac 100644 --- a/src/main/build/debug.c +++ b/src/main/build/debug.c @@ -114,4 +114,5 @@ const char * const debugModeNames[DEBUG_COUNT] = { "CURRENT_ANGLE", "DSHOT_TELEMETRY_COUNTS", "RPM_LIMIT", + "RC_STATS", }; diff --git a/src/main/build/debug.h b/src/main/build/debug.h index e681317550..7b71d583e9 100644 --- a/src/main/build/debug.h +++ b/src/main/build/debug.h @@ -20,6 +20,8 @@ #pragma once +#include + #define DEBUG16_VALUE_COUNT 8 extern int16_t debug[DEBUG16_VALUE_COUNT]; extern uint8_t debugMode; @@ -112,6 +114,7 @@ typedef enum { DEBUG_CURRENT_ANGLE, DEBUG_DSHOT_TELEMETRY_COUNTS, DEBUG_RPM_LIMIT, + DEBUG_RC_STATS, DEBUG_COUNT } debugType_e; diff --git a/src/main/cli/settings.c b/src/main/cli/settings.c index 90d0f5793f..79a2642cf2 100644 --- a/src/main/cli/settings.c +++ b/src/main/cli/settings.c @@ -1736,7 +1736,9 @@ const clivalue_t valueTable[] = { #ifdef USE_BATTERY_CONTINUE { "stats_mah_used", VAR_UINT32 | MASTER_VALUE, .config.u32Max = UINT32_MAX, PG_STATS_CONFIG, offsetof(statsConfig_t, stats_mah_used) }, #endif -#endif + +#endif // USE_PERSISTENT_STATS + { "craft_name", VAR_UINT8 | MASTER_VALUE | MODE_STRING, .config.string = { 1, MAX_NAME_LENGTH, STRING_FLAGS_NONE }, PG_PILOT_CONFIG, offsetof(pilotConfig_t, craftName) }, #ifdef USE_OSD { "pilot_name", VAR_UINT8 | MASTER_VALUE | MODE_STRING, .config.string = { 1, MAX_NAME_LENGTH, STRING_FLAGS_NONE }, PG_PILOT_CONFIG, offsetof(pilotConfig_t, pilotName) }, diff --git a/src/main/fc/core.c b/src/main/fc/core.c index c5759b9e2f..d7bf901a06 100644 --- a/src/main/fc/core.c +++ b/src/main/fc/core.c @@ -92,6 +92,7 @@ #include "pg/pg_ids.h" #include "pg/rx.h" +#include "rx/rc_stats.h" #include "rx/rx.h" #include "scheduler/scheduler.h" @@ -554,6 +555,10 @@ void tryArm(void) #endif ENABLE_ARMING_FLAG(ARMED); +#ifdef USE_RC_STATS + NotifyRcStatsArming(); +#endif + resetTryingToArm(); #ifdef USE_ACRO_TRAINER diff --git a/src/main/fc/tasks.c b/src/main/fc/tasks.c index bc3b554183..636c12b3e3 100644 --- a/src/main/fc/tasks.c +++ b/src/main/fc/tasks.c @@ -82,6 +82,7 @@ #include "pg/motor.h" #include "rx/rx.h" +#include "rx/rc_stats.h" #include "scheduler/scheduler.h" @@ -450,6 +451,11 @@ task_attribute_t task_attributes[TASK_COUNT] = { #ifdef USE_CRSF_V3 [TASK_SPEED_NEGOTIATION] = DEFINE_TASK("SPEED_NEGOTIATION", NULL, NULL, speedNegotiationProcess, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW), #endif + +#ifdef USE_RC_STATS + [TASK_RC_STATS] = DEFINE_TASK("RC_STATS", NULL, NULL, rcStatsUpdate, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW), +#endif + }; task_t *getTask(unsigned taskId) @@ -621,4 +627,8 @@ void tasksInit(void) #ifdef SIMULATOR_MULTITHREAD rescheduleTask(TASK_RX, 1); #endif + +#ifdef USE_RC_STATS + setTaskEnabled(TASK_RC_STATS, true); +#endif } diff --git a/src/main/osd/osd.c b/src/main/osd/osd.c index 4b2b537a6d..f4fb27190e 100644 --- a/src/main/osd/osd.c +++ b/src/main/osd/osd.c @@ -89,6 +89,7 @@ #include "pg/stats.h" #include "rx/crsf.h" +#include "rx/rc_stats.h" #include "rx/rx.h" #include "scheduler/scheduler.h" @@ -196,6 +197,9 @@ const osd_stats_e osdStatsDisplayOrder[OSD_STAT_COUNT] = { OSD_STAT_WATT_HOURS_DRAWN, OSD_STAT_BEST_3_CONSEC_LAPS, OSD_STAT_BEST_LAP, + OSD_STAT_FULL_THROTTLE_TIME, + OSD_STAT_FULL_THROTTLE_COUNTER, + OSD_STAT_AVG_THROTTLE, }; // Group elements in a number of groups to reduce task scheduling overhead @@ -355,6 +359,12 @@ void pgResetFn_osdConfig(osdConfig_t *osdConfig) // turn off the over mah capacity warning osdWarnSetState(OSD_WARNING_OVER_CAP, false); +#ifdef USE_RC_STATS + osdStatSetState(OSD_STAT_FULL_THROTTLE_TIME, true); + osdStatSetState(OSD_STAT_FULL_THROTTLE_COUNTER, true); + osdStatSetState(OSD_STAT_AVG_THROTTLE, true); +#endif + osdConfig->timers[OSD_TIMER_1] = osdTimerDefault[OSD_TIMER_1]; osdConfig->timers[OSD_TIMER_2] = osdTimerDefault[OSD_TIMER_2]; @@ -1009,6 +1019,28 @@ static bool osdDisplayStat(int statistic, uint8_t displayRow) osdDisplayStatisticLabel(midCol, displayRow, "TOTAL DISTANCE", buff); return true; #endif +#ifdef USE_RC_STATS + case OSD_STAT_FULL_THROTTLE_TIME: { + int seconds = RcStatsGetFullThrottleTimeUs() / 1000000; + const int minutes = seconds / 60; + seconds = seconds % 60; + tfp_sprintf(buff, "%02d:%02d", minutes, seconds); + osdDisplayStatisticLabel(midCol, displayRow, "100% THRT TIME", buff); + return true; + } + + case OSD_STAT_FULL_THROTTLE_COUNTER: { + itoa(RcStatsGetFullThrottleCounter(), buff, 10); + osdDisplayStatisticLabel(midCol, displayRow, "100% THRT COUNT", buff); + return true; + } + + case OSD_STAT_AVG_THROTTLE: { + itoa(RcStatsGetAverageThrottle(), buff, 10); + osdDisplayStatisticLabel(midCol, displayRow, "AVG THROTTLE", buff); + return true; + } +#endif // USE_RC_STATS } return false; } diff --git a/src/main/osd/osd.h b/src/main/osd/osd.h index aefc2400ca..5bb6060ddb 100644 --- a/src/main/osd/osd.h +++ b/src/main/osd/osd.h @@ -232,6 +232,9 @@ typedef enum { OSD_STAT_MIN_RSNR, OSD_STAT_BEST_3_CONSEC_LAPS, OSD_STAT_BEST_LAP, + OSD_STAT_FULL_THROTTLE_TIME, + OSD_STAT_FULL_THROTTLE_COUNTER, + OSD_STAT_AVG_THROTTLE, OSD_STAT_COUNT // MUST BE LAST } osd_stats_e; diff --git a/src/main/rx/rc_stats.c b/src/main/rx/rc_stats.c new file mode 100644 index 0000000000..5968fd06c8 --- /dev/null +++ b/src/main/rx/rc_stats.c @@ -0,0 +1,95 @@ +/* + * This file is part of Betaflight. + * + * Betaflight is free software. You can redistribute this software + * and/or modify this software 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. + * + * Betaflight 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 this software. + * + * If not, see . + */ + +#include +#include +#include + +#include "platform.h" + +#ifdef USE_RC_STATS + +#include "build/debug.h" +#include "fc/core.h" +#include "fc/rc_modes.h" +#include "fc/runtime_config.h" + +#include "rx/rc_stats.h" + +timeUs_t previousTimeUs = 0; +bool throttleEverRaisedAfterArming = false; +uint32_t counter = 0; +uint32_t totalTrottleNumber = 0; +timeUs_t fullThrottleTimeUs = 0; +uint32_t fullThrottleCounter = 0; +int8_t previousThrottlePercent = 0; + + +void rcStatsUpdate(timeUs_t currentTimeUs) +{ + uint32_t deltaT = currentTimeUs - previousTimeUs; + previousTimeUs = currentTimeUs; + const int8_t throttlePercent = calculateThrottlePercent(); + + if (ARMING_FLAG(ARMED) && !IS_RC_MODE_ACTIVE(BOXFLIPOVERAFTERCRASH) && !throttleEverRaisedAfterArming) { + if (abs(throttlePercent) >= 15) { // start counting stats if throttle was raised >= 15% after arming + throttleEverRaisedAfterArming = true; + } + } + + if (ARMING_FLAG(ARMED) && !IS_RC_MODE_ACTIVE(BOXFLIPOVERAFTERCRASH) && throttleEverRaisedAfterArming) { + counter++; + totalTrottleNumber += throttlePercent; + + if (abs(throttlePercent) == 100) { + fullThrottleTimeUs += deltaT; + if (abs(previousThrottlePercent) != 100) { + fullThrottleCounter ++; + } + } + } + + DEBUG_SET(DEBUG_RC_STATS, 0, lrintf(RcStatsGetAverageThrottle())); + + previousThrottlePercent = throttlePercent; +} + +uint32_t RcStatsGetFullThrottleCounter(void) +{ + return fullThrottleCounter; +} + +timeUs_t RcStatsGetFullThrottleTimeUs(void) +{ + return fullThrottleTimeUs; +} + +int8_t RcStatsGetAverageThrottle(void) +{ + return (float)totalTrottleNumber/(float)counter + 0.5; // rounding +} + +void NotifyRcStatsArming(void) +{ + throttleEverRaisedAfterArming = false; +} + +#endif // USE_RC_STATS diff --git a/src/main/rx/rc_stats.h b/src/main/rx/rc_stats.h new file mode 100644 index 0000000000..cbd0719b8f --- /dev/null +++ b/src/main/rx/rc_stats.h @@ -0,0 +1,34 @@ +/* + * This file is part of Betaflight. + * + * Betaflight is free software. You can redistribute this software + * and/or modify this software 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. + * + * Betaflight 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 this software. + * + * If not, see . + */ + +#pragma once + +#ifdef USE_RC_STATS + +#include "common/time.h" + +void rcStatsUpdate(timeUs_t currentTimeUs); +void NotifyRcStatsArming(void); +int8_t RcStatsGetAverageThrottle(void); +uint32_t RcStatsGetFullThrottleCounter(void); +timeUs_t RcStatsGetFullThrottleTimeUs(void); + +#endif // USE_RC_STATS diff --git a/src/main/scheduler/scheduler.h b/src/main/scheduler/scheduler.h index 037750ee43..d18511378b 100644 --- a/src/main/scheduler/scheduler.h +++ b/src/main/scheduler/scheduler.h @@ -176,6 +176,9 @@ typedef enum { #ifdef USE_CRSF_V3 TASK_SPEED_NEGOTIATION, #endif +#ifdef USE_RC_STATS + TASK_RC_STATS, +#endif /* Count of real tasks */ TASK_COUNT,