2 * This file is part of INAV Project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 * You can obtain one at http://mozilla.org/MPL/2.0/.
8 * Alternatively, the contents of this file may be used under the terms
9 * of the GNU General Public License Version 3, as described below:
11 * This file is free software: you may copy, redistribute and/or modify
12 * it under the terms of the GNU General Public License as published by the
13 * Free Software Foundation, either version 3 of the License, or (at your
14 * option) any later version.
16 * This file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
19 * Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see http://www.gnu.org/licenses/.
27 #include "config/config_reset.h"
28 #include "config/parameter_group.h"
29 #include "config/parameter_group_ids.h"
31 #include "programming/logic_condition.h"
32 #include "programming/global_variables.h"
33 #include "programming/pid.h"
34 #include "common/utils.h"
36 #include "common/maths.h"
37 #include "fc/config.h"
39 #include "fc/fc_core.h"
40 #include "fc/rc_controls.h"
41 #include "fc/runtime_config.h"
42 #include "fc/rc_modes.h"
43 #include "navigation/navigation.h"
44 #include "sensors/battery.h"
45 #include "sensors/pitotmeter.h"
46 #include "sensors/rangefinder.h"
47 #include "flight/imu.h"
48 #include "flight/pid.h"
49 #include "flight/mixer_profile.h"
50 #include "drivers/io_port_expander.h"
51 #include "io/osd_common.h"
52 #include "sensors/diagnostics.h"
54 #include "navigation/navigation.h"
55 #include "navigation/navigation_private.h"
58 #include "drivers/vtx_common.h"
59 #include "drivers/light_ws2811strip.h"
61 PG_REGISTER_ARRAY_WITH_RESET_FN(logicCondition_t
, MAX_LOGIC_CONDITIONS
, logicConditions
, PG_LOGIC_CONDITIONS
, 4);
63 EXTENDED_FASTRAM
uint64_t logicConditionsGlobalFlags
;
64 EXTENDED_FASTRAM
int logicConditionValuesByType
[LOGIC_CONDITION_LAST
];
65 EXTENDED_FASTRAM rcChannelOverride_t rcChannelOverrides
[MAX_SUPPORTED_RC_CHANNEL_COUNT
];
66 EXTENDED_FASTRAM flightAxisOverride_t flightAxisOverride
[XYZ_AXIS_COUNT
];
68 void pgResetFn_logicConditions(logicCondition_t
*instance
)
70 for (int i
= 0; i
< MAX_LOGIC_CONDITIONS
; i
++) {
71 RESET_CONFIG(logicCondition_t
, &instance
[i
],
76 .type
= LOGIC_CONDITION_OPERAND_TYPE_VALUE
,
80 .type
= LOGIC_CONDITION_OPERAND_TYPE_VALUE
,
88 logicConditionState_t logicConditionStates
[MAX_LOGIC_CONDITIONS
];
90 static int logicConditionCompute(
92 logicOperation_e operation
,
98 #if defined(USE_VTX_CONTROL)
99 vtxDeviceCapability_t vtxDeviceCapability
;
104 case LOGIC_CONDITION_TRUE
:
108 case LOGIC_CONDITION_EQUAL
:
109 return operandA
== operandB
;
112 case LOGIC_CONDITION_APPROX_EQUAL
:
114 uint16_t offest
= operandA
/ 100;
115 return ((operandB
>= (operandA
- offest
)) && (operandB
<= (operandA
+ offest
)));
119 case LOGIC_CONDITION_GREATER_THAN
:
120 return operandA
> operandB
;
123 case LOGIC_CONDITION_LOWER_THAN
:
124 return operandA
< operandB
;
127 case LOGIC_CONDITION_LOW
:
128 return operandA
< 1333;
131 case LOGIC_CONDITION_MID
:
132 return operandA
>= 1333 && operandA
<= 1666;
135 case LOGIC_CONDITION_HIGH
:
136 return operandA
> 1666;
139 case LOGIC_CONDITION_AND
:
140 return (operandA
&& operandB
);
143 case LOGIC_CONDITION_OR
:
144 return (operandA
|| operandB
);
147 case LOGIC_CONDITION_XOR
:
148 return (operandA
!= operandB
);
151 case LOGIC_CONDITION_NAND
:
152 return !(operandA
&& operandB
);
155 case LOGIC_CONDITION_NOR
:
156 return !(operandA
|| operandB
);
159 case LOGIC_CONDITION_NOT
:
163 case LOGIC_CONDITION_STICKY
:
164 // Operand A is activation operator
168 //Operand B is deactivation operator
173 //When both operands are not met, keep current value
177 case LOGIC_CONDITION_EDGE
:
178 if (operandA
&& logicConditionStates
[lcIndex
].timeout
== 0 && !(logicConditionStates
[lcIndex
].flags
& LOGIC_CONDITION_FLAG_TIMEOUT_SATISFIED
)) {
179 if (operandB
< 100) {
180 logicConditionStates
[lcIndex
].timeout
= millis();
182 logicConditionStates
[lcIndex
].timeout
= millis() + operandB
;
184 logicConditionStates
[lcIndex
].flags
|= LOGIC_CONDITION_FLAG_TIMEOUT_SATISFIED
;
186 } else if (logicConditionStates
[lcIndex
].timeout
> 0) {
187 if (logicConditionStates
[lcIndex
].timeout
< millis()) {
188 logicConditionStates
[lcIndex
].timeout
= 0;
195 logicConditionStates
[lcIndex
].flags
&= ~LOGIC_CONDITION_FLAG_TIMEOUT_SATISFIED
;
200 case LOGIC_CONDITION_DELAY
:
202 if (logicConditionStates
[lcIndex
].timeout
== 0) {
203 logicConditionStates
[lcIndex
].timeout
= millis() + operandB
;
204 } else if (millis() > logicConditionStates
[lcIndex
].timeout
) {
205 logicConditionStates
[lcIndex
].flags
|= LOGIC_CONDITION_FLAG_TIMEOUT_SATISFIED
;
207 } else if (logicConditionStates
[lcIndex
].flags
& LOGIC_CONDITION_FLAG_TIMEOUT_SATISFIED
) {
211 logicConditionStates
[lcIndex
].timeout
= 0;
212 logicConditionStates
[lcIndex
].flags
&= ~LOGIC_CONDITION_FLAG_TIMEOUT_SATISFIED
;
218 case LOGIC_CONDITION_TIMER
:
219 if ((logicConditionStates
[lcIndex
].timeout
== 0) || (millis() > logicConditionStates
[lcIndex
].timeout
&& !currentValue
)) {
220 logicConditionStates
[lcIndex
].timeout
= millis() + operandA
;
222 } else if (millis() > logicConditionStates
[lcIndex
].timeout
&& currentValue
) {
223 logicConditionStates
[lcIndex
].timeout
= millis() + operandB
;
229 case LOGIC_CONDITION_DELTA
:
231 int difference
= logicConditionStates
[lcIndex
].lastValue
- operandA
;
232 logicConditionStates
[lcIndex
].lastValue
= operandA
;
233 return ABS(difference
) >= operandB
;
237 case LOGIC_CONDITION_GVAR_SET
:
238 gvSet(operandA
, operandB
);
242 case LOGIC_CONDITION_GVAR_INC
:
243 temporaryValue
= gvGet(operandA
) + operandB
;
244 gvSet(operandA
, temporaryValue
);
245 return temporaryValue
;
248 case LOGIC_CONDITION_GVAR_DEC
:
249 temporaryValue
= gvGet(operandA
) - operandB
;
250 gvSet(operandA
, temporaryValue
);
251 return temporaryValue
;
254 case LOGIC_CONDITION_ADD
:
255 return constrain(operandA
+ operandB
, INT32_MIN
, INT32_MAX
);
258 case LOGIC_CONDITION_SUB
:
259 return constrain(operandA
- operandB
, INT32_MIN
, INT32_MAX
);
262 case LOGIC_CONDITION_MUL
:
263 return constrain(operandA
* operandB
, INT32_MIN
, INT32_MAX
);
266 case LOGIC_CONDITION_DIV
:
268 return constrain(operandA
/ operandB
, INT32_MIN
, INT32_MAX
);
274 case LOGIC_CONDITION_OVERRIDE_ARMING_SAFETY
:
275 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_ARMING_SAFETY
);
279 case LOGIC_CONDITION_OVERRIDE_THROTTLE_SCALE
:
280 logicConditionValuesByType
[LOGIC_CONDITION_OVERRIDE_THROTTLE_SCALE
] = operandA
;
281 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_THROTTLE_SCALE
);
285 case LOGIC_CONDITION_SWAP_ROLL_YAW
:
286 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_SWAP_ROLL_YAW
);
291 case LOGIC_CONDITION_RESET_MAG_CALIBRATION
:
293 ENABLE_STATE(CALIBRATE_MAG
);
297 case LOGIC_CONDITION_SET_VTX_POWER_LEVEL
:
298 #if defined(USE_VTX_CONTROL)
299 #if(defined(USE_VTX_SMARTAUDIO) || defined(USE_VTX_TRAMP))
301 logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_POWER_LEVEL
] != operandA
&&
302 vtxCommonGetDeviceCapability(vtxCommonDevice(), &vtxDeviceCapability
)
304 logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_POWER_LEVEL
] = constrain(operandA
, VTX_SETTINGS_MIN_POWER
, vtxDeviceCapability
.powerCount
);
305 vtxSettingsConfigMutable()->power
= logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_POWER_LEVEL
];
306 return logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_POWER_LEVEL
];
315 case LOGIC_CONDITION_SET_VTX_BAND
:
317 logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_BAND
] != operandA
&&
318 vtxCommonGetDeviceCapability(vtxCommonDevice(), &vtxDeviceCapability
)
320 logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_BAND
] = constrain(operandA
, VTX_SETTINGS_MIN_BAND
, VTX_SETTINGS_MAX_BAND
);
321 vtxSettingsConfigMutable()->band
= logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_BAND
];
322 return logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_BAND
];
327 case LOGIC_CONDITION_SET_VTX_CHANNEL
:
329 logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_CHANNEL
] != operandA
&&
330 vtxCommonGetDeviceCapability(vtxCommonDevice(), &vtxDeviceCapability
)
332 logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_CHANNEL
] = constrain(operandA
, VTX_SETTINGS_MIN_CHANNEL
, VTX_SETTINGS_MAX_CHANNEL
);
333 vtxSettingsConfigMutable()->channel
= logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_CHANNEL
];
334 return logicConditionValuesByType
[LOGIC_CONDITION_SET_VTX_CHANNEL
];
340 case LOGIC_CONDITION_INVERT_ROLL
:
341 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_INVERT_ROLL
);
345 case LOGIC_CONDITION_INVERT_PITCH
:
346 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_INVERT_PITCH
);
350 case LOGIC_CONDITION_INVERT_YAW
:
351 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_INVERT_YAW
);
355 case LOGIC_CONDITION_OVERRIDE_THROTTLE
:
356 logicConditionValuesByType
[LOGIC_CONDITION_OVERRIDE_THROTTLE
] = operandA
;
357 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_THROTTLE
);
361 case LOGIC_CONDITION_SET_OSD_LAYOUT
:
362 logicConditionValuesByType
[LOGIC_CONDITION_SET_OSD_LAYOUT
] = operandA
;
363 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_OSD_LAYOUT
);
367 #ifdef USE_I2C_IO_EXPANDER
368 case LOGIC_CONDITION_PORT_SET
:
369 ioPortExpanderSet((uint8_t)operandA
, (uint8_t)operandB
);
374 case LOGIC_CONDITION_SIN
:
375 temporaryValue
= (operandB
== 0) ? 500 : operandB
;
376 return sin_approx(DEGREES_TO_RADIANS(operandA
)) * temporaryValue
;
379 case LOGIC_CONDITION_COS
:
380 temporaryValue
= (operandB
== 0) ? 500 : operandB
;
381 return cos_approx(DEGREES_TO_RADIANS(operandA
)) * temporaryValue
;
385 case LOGIC_CONDITION_TAN
:
386 temporaryValue
= (operandB
== 0) ? 500 : operandB
;
387 return tan_approx(DEGREES_TO_RADIANS(operandA
)) * temporaryValue
;
390 case LOGIC_CONDITION_MIN
:
391 return (operandA
< operandB
) ? operandA
: operandB
;
394 case LOGIC_CONDITION_MAX
:
395 return (operandA
> operandB
) ? operandA
: operandB
;
398 case LOGIC_CONDITION_MAP_INPUT
:
399 return scaleRange(constrain(operandA
, 0, operandB
), 0, operandB
, 0, 1000);
402 case LOGIC_CONDITION_MAP_OUTPUT
:
403 return scaleRange(constrain(operandA
, 0, 1000), 0, 1000, 0, operandB
);
406 case LOGIC_CONDITION_RC_CHANNEL_OVERRIDE
:
407 temporaryValue
= constrain(operandA
- 1, 0, MAX_SUPPORTED_RC_CHANNEL_COUNT
- 1);
408 rcChannelOverrides
[temporaryValue
].active
= true;
409 rcChannelOverrides
[temporaryValue
].value
= constrain(operandB
, PWM_RANGE_MIN
, PWM_RANGE_MAX
);
410 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_RC_CHANNEL
);
414 case LOGIC_CONDITION_SET_HEADING_TARGET
:
415 temporaryValue
= CENTIDEGREES_TO_DEGREES(wrap_36000(DEGREES_TO_CENTIDEGREES(operandA
)));
416 updateHeadingHoldTarget(temporaryValue
);
417 return temporaryValue
;
420 case LOGIC_CONDITION_MODULUS
:
422 return constrain(operandA
% operandB
, INT32_MIN
, INT32_MAX
);
428 case LOGIC_CONDITION_SET_PROFILE
:
430 if ( getConfigProfile() != operandA
&& (operandA
>= 0 && operandA
< MAX_PROFILE_COUNT
)) {
431 bool profileChanged
= false;
432 if (setConfigProfile(operandA
)) {
435 schedulePidGainsUpdate();
436 navigationUsePIDs(); //set navigation pid gains
437 profileChanged
= true;
439 return profileChanged
;
445 case LOGIC_CONDITION_LOITER_OVERRIDE
:
446 logicConditionValuesByType
[LOGIC_CONDITION_LOITER_OVERRIDE
] = constrain(operandA
, 0, 100000);
447 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_LOITER_RADIUS
);
451 case LOGIC_CONDITION_FLIGHT_AXIS_ANGLE_OVERRIDE
:
452 if (operandA
>= 0 && operandA
<= 2) {
454 flightAxisOverride
[operandA
].angleTargetActive
= true;
455 int target
= DEGREES_TO_DECIDEGREES(operandB
);
458 target
= constrain(target
, -pidProfile()->max_angle_inclination
[FD_ROLL
], pidProfile()->max_angle_inclination
[FD_ROLL
]);
459 } else if (operandA
== 1) {
461 target
= constrain(target
, -pidProfile()->max_angle_inclination
[FD_PITCH
], pidProfile()->max_angle_inclination
[FD_PITCH
]);
462 } else if (operandA
== 2) {
464 target
= (constrain(target
, 0, 3600));
466 flightAxisOverride
[operandA
].angleTarget
= target
;
467 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_FLIGHT_AXIS
);
475 case LOGIC_CONDITION_FLIGHT_AXIS_RATE_OVERRIDE
:
476 if (operandA
>= 0 && operandA
<= 2) {
477 flightAxisOverride
[operandA
].rateTargetActive
= true;
478 flightAxisOverride
[operandA
].rateTarget
= constrain(operandB
, -2000, 2000);
479 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_FLIGHT_AXIS
);
487 case LOGIC_CONDITION_LED_PIN_PWM
:
489 if (operandA
>=0 && operandA
<= 100) {
490 ledPinStartPWM((uint8_t)operandA
);
497 #ifdef USE_GPS_FIX_ESTIMATION
498 case LOGIC_CONDITION_DISABLE_GPS_FIX
:
500 LOGIC_CONDITION_GLOBAL_FLAG_ENABLE(LOGIC_CONDITION_GLOBAL_FLAG_DISABLE_GPS_FIX
);
502 LOGIC_CONDITION_GLOBAL_FLAG_DISABLE(LOGIC_CONDITION_GLOBAL_FLAG_DISABLE_GPS_FIX
);
514 void logicConditionProcess(uint8_t i
) {
516 const int activatorValue
= logicConditionGetValue(logicConditions(i
)->activatorId
);
518 if (logicConditions(i
)->enabled
&& activatorValue
&& !cliMode
) {
521 * Process condition only when latch flag is not set
522 * Latched LCs can only go from OFF to ON, not the other way
524 if (!(logicConditionStates
[i
].flags
& LOGIC_CONDITION_FLAG_LATCH
)) {
525 const int operandAValue
= logicConditionGetOperandValue(logicConditions(i
)->operandA
.type
, logicConditions(i
)->operandA
.value
);
526 const int operandBValue
= logicConditionGetOperandValue(logicConditions(i
)->operandB
.type
, logicConditions(i
)->operandB
.value
);
527 const int newValue
= logicConditionCompute(
528 logicConditionStates
[i
].value
,
529 logicConditions(i
)->operation
,
535 logicConditionStates
[i
].value
= newValue
;
538 * if value evaluates as true, put a latch on logic condition
540 if (logicConditions(i
)->flags
& LOGIC_CONDITION_FLAG_LATCH
&& newValue
) {
541 logicConditionStates
[i
].flags
|= LOGIC_CONDITION_FLAG_LATCH
;
545 logicConditionStates
[i
].value
= false;
549 static int logicConditionGetWaypointOperandValue(int operand
) {
552 case LOGIC_CONDITION_OPERAND_WAYPOINTS_IS_WP
: // 0/1
553 return (navGetCurrentStateFlags() & NAV_AUTO_WP
) ? 1 : 0;
556 case LOGIC_CONDITION_OPERAND_WAYPOINTS_WAYPOINT_INDEX
:
557 return NAV_Status
.activeWpNumber
;
560 case LOGIC_CONDITION_OPERAND_WAYPOINTS_WAYPOINT_ACTION
:
561 return NAV_Status
.activeWpAction
;
564 case LOGIC_CONDITION_OPERAND_WAYPOINTS_NEXT_WAYPOINT_ACTION
:
566 uint8_t wpIndex
= posControl
.activeWaypointIndex
+ 1;
567 if ((wpIndex
> 0) && (wpIndex
< NAV_MAX_WAYPOINTS
)) {
568 return posControl
.waypointList
[wpIndex
].action
;
574 case LOGIC_CONDITION_OPERAND_WAYPOINTS_WAYPOINT_DISTANCE
:
576 uint32_t distance
= 0;
577 if (navGetCurrentStateFlags() & NAV_AUTO_WP
) {
580 wp
.lat
= posControl
.waypointList
[NAV_Status
.activeWpIndex
].lat
;
581 wp
.lon
= posControl
.waypointList
[NAV_Status
.activeWpIndex
].lon
;
582 wp
.alt
= posControl
.waypointList
[NAV_Status
.activeWpIndex
].alt
;
583 geoConvertGeodeticToLocal(&poi
, &posControl
.gpsOrigin
, &wp
, GEO_ALT_RELATIVE
);
585 distance
= calculateDistanceToDestination(&poi
) / 100;
592 case LOGIC_CONDTIION_OPERAND_WAYPOINTS_DISTANCE_FROM_WAYPOINT
:
594 uint32_t distance
= 0;
595 if ((navGetCurrentStateFlags() & NAV_AUTO_WP
) && NAV_Status
.activeWpIndex
> 0) {
598 wp
.lat
= posControl
.waypointList
[NAV_Status
.activeWpIndex
-1].lat
;
599 wp
.lon
= posControl
.waypointList
[NAV_Status
.activeWpIndex
-1].lon
;
600 wp
.alt
= posControl
.waypointList
[NAV_Status
.activeWpIndex
-1].alt
;
601 geoConvertGeodeticToLocal(&poi
, &posControl
.gpsOrigin
, &wp
, GEO_ALT_RELATIVE
);
603 distance
= calculateDistanceToDestination(&poi
) / 100;
610 case LOGIC_CONDITION_OPERAND_WAYPOINTS_USER1_ACTION
:
611 return (NAV_Status
.activeWpIndex
> 0) ? ((posControl
.waypointList
[NAV_Status
.activeWpIndex
-1].p3
& NAV_WP_USER1
) == NAV_WP_USER1
) : 0;
614 case LOGIC_CONDITION_OPERAND_WAYPOINTS_USER2_ACTION
:
615 return (NAV_Status
.activeWpIndex
> 0) ? ((posControl
.waypointList
[NAV_Status
.activeWpIndex
-1].p3
& NAV_WP_USER2
) == NAV_WP_USER2
) : 0;
618 case LOGIC_CONDITION_OPERAND_WAYPOINTS_USER3_ACTION
:
619 return (NAV_Status
.activeWpIndex
> 0) ? ((posControl
.waypointList
[NAV_Status
.activeWpIndex
-1].p3
& NAV_WP_USER3
) == NAV_WP_USER3
) : 0;
622 case LOGIC_CONDITION_OPERAND_WAYPOINTS_USER4_ACTION
:
623 return (NAV_Status
.activeWpIndex
> 0) ? ((posControl
.waypointList
[NAV_Status
.activeWpIndex
-1].p3
& NAV_WP_USER4
) == NAV_WP_USER4
) : 0;
626 case LOGIC_CONDITION_OPERAND_WAYPOINTS_USER1_ACTION_NEXT_WP
:
627 return ((posControl
.waypointList
[NAV_Status
.activeWpIndex
].p3
& NAV_WP_USER1
) == NAV_WP_USER1
);
630 case LOGIC_CONDITION_OPERAND_WAYPOINTS_USER2_ACTION_NEXT_WP
:
631 return ((posControl
.waypointList
[NAV_Status
.activeWpIndex
].p3
& NAV_WP_USER2
) == NAV_WP_USER2
);
634 case LOGIC_CONDITION_OPERAND_WAYPOINTS_USER3_ACTION_NEXT_WP
:
635 return ((posControl
.waypointList
[NAV_Status
.activeWpIndex
].p3
& NAV_WP_USER3
) == NAV_WP_USER3
);
638 case LOGIC_CONDITION_OPERAND_WAYPOINTS_USER4_ACTION_NEXT_WP
:
639 return ((posControl
.waypointList
[NAV_Status
.activeWpIndex
].p3
& NAV_WP_USER4
) == NAV_WP_USER4
);
648 static int logicConditionGetFlightOperandValue(int operand
) {
652 case LOGIC_CONDITION_OPERAND_FLIGHT_ARM_TIMER
: // in s
653 return constrain((uint32_t)getFlightTime(), 0, INT16_MAX
);
656 case LOGIC_CONDITION_OPERAND_FLIGHT_HOME_DISTANCE
: //in m
657 return constrain(GPS_distanceToHome
, 0, INT16_MAX
);
660 case LOGIC_CONDITION_OPERAND_FLIGHT_TRIP_DISTANCE
: //in m
661 return constrain(getTotalTravelDistance() / 100, 0, INT16_MAX
);
664 case LOGIC_CONDITION_OPERAND_FLIGHT_RSSI
:
665 return constrain(getRSSI() * 100 / RSSI_MAX_VALUE
, 0, 99);
668 case LOGIC_CONDITION_OPERAND_FLIGHT_VBAT
: // V / 100
669 return getBatteryVoltage();
672 case LOGIC_CONDITION_OPERAND_FLIGHT_CELL_VOLTAGE
: // V / 10
673 return getBatteryAverageCellVoltage();
676 case LOGIC_CONDITION_OPERAND_FLIGHT_BATT_CELLS
:
677 return getBatteryCellCount();
680 case LOGIC_CONDITION_OPERAND_FLIGHT_CURRENT
: // Amp / 100
681 return getAmperage();
684 case LOGIC_CONDITION_OPERAND_FLIGHT_MAH_DRAWN
: // mAh
685 return getMAhDrawn();
688 case LOGIC_CONDITION_OPERAND_FLIGHT_GPS_SATS
:
689 #ifdef USE_GPS_FIX_ESTIMATION
690 if ( STATE(GPS_ESTIMATED_FIX
) ){
691 return gpsSol
.numSat
; //99
694 if (getHwGPSStatus() == HW_SENSOR_UNAVAILABLE
|| getHwGPSStatus() == HW_SENSOR_UNHEALTHY
) {
697 return gpsSol
.numSat
;
701 case LOGIC_CONDITION_OPERAND_FLIGHT_GPS_VALID
: // 0/1
702 return STATE(GPS_FIX
) ? 1 : 0;
705 case LOGIC_CONDITION_OPERAND_FLIGHT_GROUD_SPEED
: // cm/s
706 return gpsSol
.groundSpeed
;
709 //FIXME align with osdGet3DSpeed
710 case LOGIC_CONDITION_OPERAND_FLIGHT_3D_SPEED
: // cm/s
711 return osdGet3DSpeed();
714 case LOGIC_CONDITION_OPERAND_FLIGHT_AIR_SPEED
: // cm/s
716 return constrain(getAirspeedEstimate(), 0, INT16_MAX
);
722 case LOGIC_CONDITION_OPERAND_FLIGHT_ALTITUDE
: // cm
723 return constrain(getEstimatedActualPosition(Z
), INT16_MIN
, INT16_MAX
);
726 case LOGIC_CONDITION_OPERAND_FLIGHT_VERTICAL_SPEED
: // cm/s
727 return constrain(getEstimatedActualVelocity(Z
), INT16_MIN
, INT16_MAX
);
730 case LOGIC_CONDITION_OPERAND_FLIGHT_TROTTLE_POS
: // %
731 return (constrain(rcCommand
[THROTTLE
], PWM_RANGE_MIN
, PWM_RANGE_MAX
) - PWM_RANGE_MIN
) * 100 / (PWM_RANGE_MAX
- PWM_RANGE_MIN
);
734 case LOGIC_CONDITION_OPERAND_FLIGHT_ATTITUDE_ROLL
: // deg
735 return constrain(attitude
.values
.roll
/ 10, -180, 180);
738 case LOGIC_CONDITION_OPERAND_FLIGHT_ATTITUDE_PITCH
: // deg
739 return constrain(attitude
.values
.pitch
/ 10, -180, 180);
742 case LOGIC_CONDITION_OPERAND_FLIGHT_ATTITUDE_YAW
: // deg
743 return constrain(attitude
.values
.yaw
/ 10, 0, 360);
746 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_ARMED
: // 0/1
747 return ARMING_FLAG(ARMED
) ? 1 : 0;
750 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_AUTOLAUNCH
: // 0/1
751 return (navGetCurrentStateFlags() & NAV_CTL_LAUNCH
) ? 1 : 0;
754 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_ALTITUDE_CONTROL
: // 0/1
755 return (navGetCurrentStateFlags() & NAV_CTL_ALT
) ? 1 : 0;
758 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_POSITION_CONTROL
: // 0/1
759 return (navGetCurrentStateFlags() & NAV_CTL_POS
) ? 1 : 0;
762 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_EMERGENCY_LANDING
: // 0/1
763 return (navGetCurrentStateFlags() & NAV_CTL_EMERG
) ? 1 : 0;
766 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_RTH
: // 0/1
767 return (navGetCurrentStateFlags() & NAV_AUTO_RTH
) ? 1 : 0;
770 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_LANDING
: // 0/1
771 #ifdef USE_FW_AUTOLAND
772 return ((navGetCurrentStateFlags() & NAV_CTL_LAND
) || FLIGHT_MODE(NAV_FW_AUTOLAND
)) ? 1 : 0;
774 return ((navGetCurrentStateFlags() & NAV_CTL_LAND
)) ? 1 : 0;
779 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_FAILSAFE
: // 0/1
780 return (failsafePhase() != FAILSAFE_IDLE
) ? 1 : 0;
783 case LOGIC_CONDITION_OPERAND_FLIGHT_STABILIZED_YAW
: //
787 case LOGIC_CONDITION_OPERAND_FLIGHT_STABILIZED_ROLL
: //
788 return axisPID
[ROLL
];
791 case LOGIC_CONDITION_OPERAND_FLIGHT_STABILIZED_PITCH
: //
792 return axisPID
[PITCH
];
795 case LOGIC_CONDITION_OPERAND_FLIGHT_3D_HOME_DISTANCE
: //in m
796 return constrain(calc_length_pythagorean_2D(GPS_distanceToHome
, getEstimatedActualPosition(Z
) / 100.0f
), 0, INT16_MAX
);
799 case LOGIC_CONDITION_OPERAND_FLIGHT_CRSF_LQ
:
800 #ifdef USE_SERIALRX_CRSF
801 return rxLinkStatistics
.uplinkLQ
;
807 case LOGIC_CONDITION_OPERAND_FLIGHT_CRSF_SNR
:
808 #ifdef USE_SERIALRX_CRSF
809 return rxLinkStatistics
.uplinkSNR
;
815 case LOGIC_CONDITION_OPERAND_FLIGHT_ACTIVE_PROFILE
: // int
816 return getConfigProfile() + 1;
819 case LOGIC_CONDITION_OPERAND_FLIGHT_BATT_PROFILE
: //int
820 return getConfigBatteryProfile() + 1;
823 case LOGIC_CONDITION_OPERAND_FLIGHT_ACTIVE_MIXER_PROFILE
: // int
824 return currentMixerProfileIndex
+ 1;
827 case LOGIC_CONDITION_OPERAND_FLIGHT_MIXER_TRANSITION_ACTIVE
: //0,1
828 return isMixerTransitionMixing
? 1 : 0;
831 case LOGIC_CONDITION_OPERAND_FLIGHT_LOITER_RADIUS
:
832 return getLoiterRadius(navConfig()->fw
.loiter_radius
);
835 case LOGIC_CONDITION_OPERAND_FLIGHT_FLOWN_LOITER_RADIUS
:
836 return getFlownLoiterRadius();
839 case LOGIC_CONDITION_OPERAND_FLIGHT_AGL_STATUS
:
840 return isEstimatedAglTrusted();
843 case LOGIC_CONDITION_OPERAND_FLIGHT_AGL
:
844 return getEstimatedAglPosition();
847 case LOGIC_CONDITION_OPERAND_FLIGHT_RANGEFINDER_RAW
:
848 return rangefinderGetLatestRawAltitude();
850 #ifdef USE_FW_AUTOLAND
851 case LOGIC_CONDITION_OPERAND_FLIGHT_FW_LAND_STATE
:
852 return posControl
.fwLandState
.landState
;
861 static int logicConditionGetFlightModeOperandValue(int operand
) {
865 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_FAILSAFE
:
866 return (bool) FLIGHT_MODE(FAILSAFE_MODE
);
869 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_MANUAL
:
870 return (bool) FLIGHT_MODE(MANUAL_MODE
);
873 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_RTH
:
874 return (bool) FLIGHT_MODE(NAV_RTH_MODE
);
877 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_POSHOLD
:
878 return (bool) FLIGHT_MODE(NAV_POSHOLD_MODE
);
881 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_WAYPOINT_MISSION
:
882 return (bool) FLIGHT_MODE(NAV_WP_MODE
);
885 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_COURSE_HOLD
:
886 return ((bool) FLIGHT_MODE(NAV_COURSE_HOLD_MODE
) && !(bool)FLIGHT_MODE(NAV_ALTHOLD_MODE
));
889 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_CRUISE
:
890 return (bool) (FLIGHT_MODE(NAV_COURSE_HOLD_MODE
) && FLIGHT_MODE(NAV_ALTHOLD_MODE
));
893 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_ALTHOLD
:
894 return (bool) FLIGHT_MODE(NAV_ALTHOLD_MODE
);
897 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_ANGLE
:
898 return (bool) FLIGHT_MODE(ANGLE_MODE
);
901 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_HORIZON
:
902 return (bool) FLIGHT_MODE(HORIZON_MODE
);
905 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_ANGLEHOLD
:
906 return (bool) FLIGHT_MODE(ANGLEHOLD_MODE
);
909 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_AIR
:
910 return (bool) FLIGHT_MODE(AIRMODE_ACTIVE
);
913 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_ACRO
:
914 return (((bool) FLIGHT_MODE(ANGLE_MODE
) || (bool) FLIGHT_MODE(HORIZON_MODE
) || (bool) FLIGHT_MODE(ANGLEHOLD_MODE
) ||
915 (bool) FLIGHT_MODE(MANUAL_MODE
) || (bool) FLIGHT_MODE(NAV_RTH_MODE
) || (bool) FLIGHT_MODE(NAV_POSHOLD_MODE
) ||
916 (bool) FLIGHT_MODE(NAV_COURSE_HOLD_MODE
) || (bool) FLIGHT_MODE(NAV_WP_MODE
)) == false);
919 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_USER1
:
920 return IS_RC_MODE_ACTIVE(BOXUSER1
);
923 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_USER2
:
924 return IS_RC_MODE_ACTIVE(BOXUSER2
);
927 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_USER3
:
928 return IS_RC_MODE_ACTIVE(BOXUSER3
);
931 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_USER4
:
932 return IS_RC_MODE_ACTIVE(BOXUSER4
);
941 int logicConditionGetOperandValue(logicOperandType_e type
, int operand
) {
946 case LOGIC_CONDITION_OPERAND_TYPE_VALUE
:
950 case LOGIC_CONDITION_OPERAND_TYPE_RC_CHANNEL
:
951 //Extract RC channel raw value
952 if (operand
>= 1 && operand
<= MAX_SUPPORTED_RC_CHANNEL_COUNT
) {
953 retVal
= rxGetChannelValue(operand
- 1);
957 case LOGIC_CONDITION_OPERAND_TYPE_FLIGHT
:
958 retVal
= logicConditionGetFlightOperandValue(operand
);
961 case LOGIC_CONDITION_OPERAND_TYPE_FLIGHT_MODE
:
962 retVal
= logicConditionGetFlightModeOperandValue(operand
);
965 case LOGIC_CONDITION_OPERAND_TYPE_LC
:
966 if (operand
>= 0 && operand
< MAX_LOGIC_CONDITIONS
) {
967 retVal
= logicConditionGetValue(operand
);
971 case LOGIC_CONDITION_OPERAND_TYPE_GVAR
:
972 if (operand
>= 0 && operand
< MAX_GLOBAL_VARIABLES
) {
973 retVal
= gvGet(operand
);
977 case LOGIC_CONDITION_OPERAND_TYPE_PID
:
978 if (operand
>= 0 && operand
< MAX_PROGRAMMING_PID_COUNT
) {
979 retVal
= programmingPidGetOutput(operand
);
983 case LOGIC_CONDITION_OPERAND_TYPE_WAYPOINTS
:
984 retVal
= logicConditionGetWaypointOperandValue(operand
);
995 * conditionId == -1 is always evaluated as true
997 int logicConditionGetValue(int8_t conditionId
) {
998 if (conditionId
>= 0) {
999 return logicConditionStates
[conditionId
].value
;
1005 void logicConditionUpdateTask(timeUs_t currentTimeUs
) {
1006 UNUSED(currentTimeUs
);
1009 logicConditionsGlobalFlags
= 0;
1011 for (uint8_t i
= 0; i
< MAX_SUPPORTED_RC_CHANNEL_COUNT
; i
++) {
1012 rcChannelOverrides
[i
].active
= false;
1015 for (uint8_t i
= 0; i
< XYZ_AXIS_COUNT
; i
++) {
1016 flightAxisOverride
[i
].rateTargetActive
= false;
1017 flightAxisOverride
[i
].angleTargetActive
= false;
1020 for (uint8_t i
= 0; i
< MAX_LOGIC_CONDITIONS
; i
++) {
1021 logicConditionProcess(i
);
1024 #ifdef USE_I2C_IO_EXPANDER
1025 ioPortExpanderSync();
1029 void logicConditionReset(void) {
1030 for (uint8_t i
= 0; i
< MAX_LOGIC_CONDITIONS
; i
++) {
1031 logicConditionStates
[i
].value
= 0;
1032 logicConditionStates
[i
].lastValue
= 0;
1033 logicConditionStates
[i
].flags
= 0;
1034 logicConditionStates
[i
].timeout
= 0;
1038 float NOINLINE
getThrottleScale(float globalThrottleScale
) {
1039 if (LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_THROTTLE_SCALE
)) {
1040 return constrainf(logicConditionValuesByType
[LOGIC_CONDITION_OVERRIDE_THROTTLE_SCALE
] / 100.0f
, 0.0f
, 1.0f
);
1042 return globalThrottleScale
;
1046 int16_t getRcCommandOverride(int16_t command
[], uint8_t axis
) {
1047 int16_t outputValue
= command
[axis
];
1049 if (LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_SWAP_ROLL_YAW
) && axis
== FD_ROLL
) {
1050 outputValue
= command
[FD_YAW
];
1051 } else if (LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_SWAP_ROLL_YAW
) && axis
== FD_YAW
) {
1052 outputValue
= command
[FD_ROLL
];
1055 if (LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_INVERT_ROLL
) && axis
== FD_ROLL
) {
1058 if (LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_INVERT_PITCH
) && axis
== FD_PITCH
) {
1061 if (LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_INVERT_YAW
) && axis
== FD_YAW
) {
1068 int16_t getRcChannelOverride(uint8_t channel
, int16_t originalValue
) {
1069 if (rcChannelOverrides
[channel
].active
) {
1070 return rcChannelOverrides
[channel
].value
;
1072 return originalValue
;
1076 uint32_t getLoiterRadius(uint32_t loiterRadius
) {
1077 #ifdef USE_PROGRAMMING_FRAMEWORK
1078 if (LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_LOITER_RADIUS
) &&
1079 !(FLIGHT_MODE(FAILSAFE_MODE
) || FLIGHT_MODE(NAV_RTH_MODE
) || FLIGHT_MODE(NAV_WP_MODE
) || navigationIsExecutingAnEmergencyLanding())) {
1080 return constrain(logicConditionValuesByType
[LOGIC_CONDITION_LOITER_OVERRIDE
], loiterRadius
, 100000);
1082 return loiterRadius
;
1085 return loiterRadius
;
1089 float getFlightAxisAngleOverride(uint8_t axis
, float angle
) {
1090 if (flightAxisOverride
[axis
].angleTargetActive
) {
1091 return flightAxisOverride
[axis
].angleTarget
;
1097 float getFlightAxisRateOverride(uint8_t axis
, float rate
) {
1098 if (flightAxisOverride
[axis
].rateTargetActive
) {
1099 return flightAxisOverride
[axis
].rateTarget
;
1105 bool isFlightAxisAngleOverrideActive(uint8_t axis
) {
1106 if (flightAxisOverride
[axis
].angleTargetActive
) {
1113 bool isFlightAxisRateOverrideActive(uint8_t axis
) {
1114 if (flightAxisOverride
[axis
].rateTargetActive
) {