2626#include "build/debug.h"
2727#include "drivers/time.h"
2828
29- #ifdef USE_MULTI_FUNCTIONS
30-
29+ #include "fc/config.h"
3130#include "fc/fc_core.h"
3231#include "fc/multifunction.h"
3332#include "fc/rc_modes.h"
34- #include "fc/runtime_config.h"
33+
34+ #include "flight/imu.h"
3535
3636#include "io/osd.h"
37+
3738#include "navigation/navigation.h"
39+ #include "navigation/navigation_private.h"
40+
41+ #include "sensors/acceleration.h"
42+ #include "sensors/battery.h"
43+ #include "sensors/compass.h"
44+ #include "sensors/diagnostics.h"
45+ #include "sensors/pitotmeter.h"
46+ #include "sensors/sensors.h"
3847
48+ textAttributes_t osdGetMultiFunctionMessage (char * buff );
49+ multiFunctionWarning_t multiFunctionWarning ;
50+
51+ #ifdef USE_MULTI_FUNCTIONS
3952multi_function_e selectedItem = MULTI_FUNC_NONE ;
4053uint8_t multiFunctionFlags ;
4154
@@ -49,27 +62,19 @@ static void multiFunctionApply(multi_function_e selectedItem)
4962 break ;
5063 case MULTI_FUNC_2 : // toggle Safehome suspend
5164#if defined(USE_SAFE_HOME )
52- if (navConfig ()-> general .flags .safehome_usage_mode != SAFEHOME_USAGE_OFF ) {
53- MULTI_FUNC_FLAG (MF_SUSPEND_SAFEHOMES ) ? MULTI_FUNC_FLAG_DISABLE (MF_SUSPEND_SAFEHOMES ) : MULTI_FUNC_FLAG_ENABLE (MF_SUSPEND_SAFEHOMES );
54- }
65+ MULTI_FUNC_FLAG (MF_SUSPEND_SAFEHOMES ) ? MULTI_FUNC_FLAG_DISABLE (MF_SUSPEND_SAFEHOMES ) : MULTI_FUNC_FLAG_ENABLE (MF_SUSPEND_SAFEHOMES );
5566#endif
5667 break ;
5768 case MULTI_FUNC_3 : // toggle RTH Trackback suspend
58- if (navConfig ()-> general .flags .rth_trackback_mode != RTH_TRACKBACK_OFF ) {
59- MULTI_FUNC_FLAG (MF_SUSPEND_TRACKBACK ) ? MULTI_FUNC_FLAG_DISABLE (MF_SUSPEND_TRACKBACK ) : MULTI_FUNC_FLAG_ENABLE (MF_SUSPEND_TRACKBACK );
60- }
69+ MULTI_FUNC_FLAG (MF_SUSPEND_TRACKBACK ) ? MULTI_FUNC_FLAG_DISABLE (MF_SUSPEND_TRACKBACK ) : MULTI_FUNC_FLAG_ENABLE (MF_SUSPEND_TRACKBACK );
6170 break ;
62- case MULTI_FUNC_4 :
71+ case MULTI_FUNC_4 : // toggle Turtle mode
6372#ifdef USE_DSHOT
64- if (!ARMING_FLAG (ARMED ) && STATE (MULTIROTOR )) { // toggle Turtle mode
65- MULTI_FUNC_FLAG (MF_TURTLE_MODE ) ? MULTI_FUNC_FLAG_DISABLE (MF_TURTLE_MODE ) : MULTI_FUNC_FLAG_ENABLE (MF_TURTLE_MODE );
66- }
73+ MULTI_FUNC_FLAG (MF_TURTLE_MODE ) ? MULTI_FUNC_FLAG_DISABLE (MF_TURTLE_MODE ) : MULTI_FUNC_FLAG_ENABLE (MF_TURTLE_MODE );
6774#endif
6875 break ;
6976 case MULTI_FUNC_5 : // emergency ARM
70- if (!ARMING_FLAG (ARMED )) {
71- emergencyArmingUpdate (true, true);
72- }
77+ emergencyArmingUpdate (true, true);
7378 break ;
7479 case MULTI_FUNC_6 : // Calibrate compass/Zero yaw heading
7580#if defined(USE_GPS ) || defined(USE_MAG )
@@ -123,4 +128,220 @@ multi_function_e multiFunctionSelection(void)
123128
124129 return selectedItem ;
125130}
131+ #endif // multifunction
132+
133+ static bool osdCheckWarning (bool condition , uint8_t warningFlag )
134+ {
135+ static timeMs_t newWarningEndTime = 0 ;
136+ static uint8_t newWarningFlags = 0 ; // bitfield
137+ const timeMs_t currentTimeMs = millis ();
138+
139+ /* New warnings dislayed individually for 10s with blinking after which
140+ * all current warnings displayed without blinking on 1 second cycle */
141+ if (condition ) { // condition required to trigger warning
142+ if (!(multiFunctionWarning .osdWarningsFlags & warningFlag )) { // check for new warnings
143+ multiFunctionWarning .osdWarningsFlags |= warningFlag ;
144+ newWarningFlags |= warningFlag ;
145+ newWarningEndTime = currentTimeMs + 10000 ;
146+ multiFunctionWarning .newWarningActive = true;
147+ }
148+ #ifdef USE_DEV_TOOLS
149+ if (systemConfig ()-> groundTestMode ) {
150+ return true;
151+ }
126152#endif
153+ if (currentTimeMs < newWarningEndTime ) {
154+ return (newWarningFlags & warningFlag ); // filter out new warnings excluding older warnings
155+ } else {
156+ newWarningFlags = 0 ;
157+ multiFunctionWarning .newWarningActive = false;
158+ }
159+ return true;
160+ } else if (multiFunctionWarning .osdWarningsFlags & warningFlag ) {
161+ multiFunctionWarning .osdWarningsFlags &= ~warningFlag ;
162+ }
163+
164+ return false;
165+ }
166+
167+ textAttributes_t osdGetMultiFunctionMessage (char * buff )
168+ {
169+ /* Message length limit 10 char max */
170+
171+ textAttributes_t elemAttr = TEXT_ATTRIBUTES_NONE ;
172+ const char * message = NULL ;
173+
174+ #ifdef USE_MULTI_FUNCTIONS
175+ /* --- FUNCTIONS --- */
176+ multi_function_e selectedFunction = multiFunctionSelection ();
177+
178+ if (selectedFunction ) {
179+ multi_function_e activeFunction = selectedFunction ;
180+
181+ switch (selectedFunction ) {
182+ case MULTI_FUNC_NONE :
183+ case MULTI_FUNC_1 :
184+ if (ARMING_FLAG (ARMED )) {
185+ message = posControl .flags .manualEmergLandActive ? "ABORT LAND" : "EMERG LAND" ;
186+ break ;
187+ }
188+ activeFunction ++ ;
189+ FALLTHROUGH ;
190+ case MULTI_FUNC_2 :
191+ #if defined(USE_SAFE_HOME )
192+ if (navConfig ()-> general .flags .safehome_usage_mode != SAFEHOME_USAGE_OFF ) {
193+ message = MULTI_FUNC_FLAG (MF_SUSPEND_SAFEHOMES ) ? "USE SFHOME" : "SUS SFHOME" ;
194+ break ;
195+ }
196+ #endif
197+ activeFunction ++ ;
198+ FALLTHROUGH ;
199+ case MULTI_FUNC_3 :
200+ if (navConfig ()-> general .flags .rth_trackback_mode != RTH_TRACKBACK_OFF ) {
201+ message = MULTI_FUNC_FLAG (MF_SUSPEND_TRACKBACK ) ? "USE TKBACK" : "SUS TKBACK" ;
202+ break ;
203+ }
204+ activeFunction ++ ;
205+ FALLTHROUGH ;
206+ case MULTI_FUNC_4 :
207+ #ifdef USE_DSHOT
208+ if (!ARMING_FLAG (ARMED ) && STATE (MULTIROTOR )) {
209+ message = MULTI_FUNC_FLAG (MF_TURTLE_MODE ) ? "END TURTLE" : "USE TURTLE" ;
210+ break ;
211+ }
212+ #endif
213+ activeFunction ++ ;
214+ FALLTHROUGH ;
215+ case MULTI_FUNC_5 :
216+ if (!ARMING_FLAG (ARMED )) {
217+ message = "EMERG ARM " ;
218+ break ;
219+ }
220+ activeFunction ++ ;
221+ FALLTHROUGH ;
222+ case MULTI_FUNC_6 :
223+ if (!ARMING_FLAG (ARMED )) {
224+ #if defined(USE_MAG )
225+ if (sensors (SENSOR_MAG )) {
226+ message = "CAL COMPAS" ;
227+ break ;
228+ }
229+ #endif
230+ #if defined(USE_GPS )
231+ if (isYawZeroResetAllowed ()) {
232+ message = "SET HEADIN" ;
233+ break ;
234+ }
235+ #endif
236+ }
237+ activeFunction ++ ;
238+ break ;
239+ case MULTI_FUNC_END :
240+ message = "*FUNC SET*" ;
241+ break ;
242+ }
243+
244+ if (activeFunction != selectedFunction ) {
245+ if (selectedFunction == MULTI_FUNC_1 && activeFunction == MULTI_FUNC_END ) { // no functions available so end process
246+ message = "*NO FUNCS*" ;
247+ setMultifunctionSelection (MULTI_FUNC_NONE );
248+ } else {
249+ setMultifunctionSelection (activeFunction );
250+ if (activeFunction == MULTI_FUNC_END ) { // no messages to display so return
251+ return elemAttr ;
252+ }
253+ }
254+ }
255+
256+ strcpy (buff , message );
257+
258+ return elemAttr ;
259+ }
260+ #endif // MULTIFUNCTION - functions only, warnings always defined
261+
262+ /* --- WARNINGS --- */
263+ const char * messages [8 ];
264+ uint8_t messageCount = 0 ;
265+ bool warningCondition = false;
266+ uint8_t warningFlagID = 1 ;
267+
268+ // Low Battery Voltage
269+ const batteryState_e batteryVoltageState = checkBatteryVoltageState ();
270+ warningCondition = batteryVoltageState == BATTERY_CRITICAL || batteryVoltageState == BATTERY_WARNING ;
271+ if (osdCheckWarning (warningCondition , warningFlagID )) {
272+ messages [messageCount ++ ] = batteryVoltageState == BATTERY_CRITICAL ? "VBATT LAND" : "VBATT LOW " ;
273+ }
274+
275+ // Low Battery Capacity
276+ if (batteryUsesCapacityThresholds ()) {
277+ const batteryState_e batteryState = getBatteryState ();
278+ warningCondition = batteryState == BATTERY_CRITICAL || batteryState == BATTERY_WARNING ;
279+ if (osdCheckWarning (warningCondition , warningFlagID <<= 1 )) {
280+ messages [messageCount ++ ] = batteryState == BATTERY_CRITICAL ? "BATT EMPTY" : "BATT DYING" ;
281+ }
282+ }
283+ #if defined(USE_GPS )
284+ // GPS Fix and Failure
285+ if (feature (FEATURE_GPS )) {
286+ if (osdCheckWarning (!STATE (GPS_FIX ), warningFlagID <<= 1 )) {
287+ bool gpsFailed = getHwGPSStatus () == HW_SENSOR_UNAVAILABLE ;
288+ messages [messageCount ++ ] = gpsFailed ? "GPS FAILED" : "NO GPS FIX" ;
289+ }
290+ }
291+
292+ // RTH sanity (warning if RTH heads 200m further away from home than closest point)
293+ warningCondition = NAV_Status .state == MW_NAV_STATE_RTH_ENROUTE && !posControl .flags .rthTrackbackActive &&
294+ (posControl .homeDistance - posControl .rthSanityChecker .minimalDistanceToHome ) > 20000 ;
295+ if (osdCheckWarning (warningCondition , warningFlagID <<= 1 )) {
296+ messages [messageCount ++ ] = "RTH SANITY" ;
297+ }
298+
299+ // Altitude sanity (warning if significant mismatch between estimated and GPS altitude)
300+ if (osdCheckWarning (posControl .flags .gpsCfEstimatedAltitudeMismatch , warningFlagID <<= 1 )) {
301+ messages [messageCount ++ ] = "ALT SANITY" ;
302+ }
303+ #endif
304+
305+ #if defined(USE_MAG )
306+ // Magnetometer failure
307+ if (requestedSensors [SENSOR_INDEX_MAG ] != MAG_NONE ) {
308+ hardwareSensorStatus_e magStatus = getHwCompassStatus ();
309+ if (osdCheckWarning (magStatus == HW_SENSOR_UNAVAILABLE || magStatus == HW_SENSOR_UNHEALTHY , warningFlagID <<= 1 )) {
310+ messages [messageCount ++ ] = "MAG FAILED" ;
311+ }
312+ }
313+ #endif
314+
315+ #if defined(USE_PITOT )
316+ // Pitot sensor validation failure (blocked/failed pitot tube)
317+ if (sensors (SENSOR_PITOT ) && detectedSensors [SENSOR_INDEX_PITOT ] != PITOT_VIRTUAL ) {
318+ if (osdCheckWarning (pitotHasFailed (), warningFlagID <<= 1 )) {
319+ messages [messageCount ++ ] = "PITOT FAIL" ;
320+ }
321+ }
322+ #endif
323+
324+ // Vibration levels TODO - needs better vibration measurement to be useful
325+ // const float vibrationLevel = accGetVibrationLevel();
326+ // warningCondition = vibrationLevel > 1.5f;
327+ // if (osdCheckWarning(warningCondition, warningFlagID <<= 1, &warningsCount)) {
328+ // messages[messageCount++] = vibrationLevel > 2.5f ? "BAD VIBRTN" : "VIBRATION!";
329+ // }
330+
331+ #ifdef USE_DEV_TOOLS
332+ if (osdCheckWarning (systemConfig ()-> groundTestMode , warningFlagID <<= 1 )) {
333+ messages [messageCount ++ ] = "GRD TEST !" ;
334+ }
335+ #endif
336+
337+ if (messageCount ) {
338+ message = messages [(millis () / 1000 ) % messageCount ]; // display each warning on 1s cycle
339+ strcpy (buff , message );
340+ if (multiFunctionWarning .newWarningActive ) {
341+ TEXT_ATTRIBUTES_ADD_BLINK (elemAttr );
342+ }
343+ }
344+
345+ return elemAttr ;
346+ }
347+
0 commit comments