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 "common/utils.h"
35 #include "common/maths.h"
36 #include "fc/fc_core.h"
37 #include "fc/rc_controls.h"
38 #include "fc/runtime_config.h"
39 #include "navigation/navigation.h"
40 #include "sensors/battery.h"
41 #include "sensors/pitotmeter.h"
42 #include "flight/imu.h"
43 #include "flight/pid.h"
45 #include "navigation/navigation.h"
46 #include "navigation/navigation_private.h"
48 PG_REGISTER_ARRAY_WITH_RESET_FN(logicCondition_t
, MAX_LOGIC_CONDITIONS
, logicConditions
, PG_LOGIC_CONDITIONS
, 1);
50 void pgResetFn_logicConditions(logicCondition_t
*instance
)
52 for (int i
= 0; i
< MAX_LOGIC_CONDITIONS
; i
++) {
53 RESET_CONFIG(logicCondition_t
, &instance
[i
],
58 .type
= LOGIC_CONDITION_OPERAND_TYPE_VALUE
,
62 .type
= LOGIC_CONDITION_OPERAND_TYPE_VALUE
,
70 logicConditionState_t logicConditionStates
[MAX_LOGIC_CONDITIONS
];
72 static int logicConditionCompute(
74 logicOperation_e operation
,
81 case LOGIC_CONDITION_TRUE
:
85 case LOGIC_CONDITION_EQUAL
:
86 return operandA
== operandB
;
89 case LOGIC_CONDITION_GREATER_THAN
:
90 return operandA
> operandB
;
93 case LOGIC_CONDITION_LOWER_THAN
:
94 return operandA
< operandB
;
97 case LOGIC_CONDITION_LOW
:
98 return operandA
< 1333;
101 case LOGIC_CONDITION_MID
:
102 return operandA
>= 1333 && operandA
<= 1666;
105 case LOGIC_CONDITION_HIGH
:
106 return operandA
> 1666;
109 case LOGIC_CONDITION_AND
:
110 return (operandA
&& operandB
);
113 case LOGIC_CONDITION_OR
:
114 return (operandA
|| operandB
);
117 case LOGIC_CONDITION_XOR
:
118 return (operandA
!= operandB
);
121 case LOGIC_CONDITION_NAND
:
122 return !(operandA
&& operandB
);
125 case LOGIC_CONDITION_NOR
:
126 return !(operandA
|| operandB
);
129 case LOGIC_CONDITION_NOT
:
133 case LOGIC_CONDITION_STICKY
:
134 // Operand A is activation operator
138 //Operand B is deactivation operator
143 //When both operands are not met, keep current value
147 case LOGIC_CONDITION_GVAR_SET
:
148 gvSet(operandA
, operandB
);
152 case LOGIC_CONDITION_GVAR_INC
:
153 temporaryValue
= gvGet(operandA
) + operandB
;
154 gvSet(operandA
, temporaryValue
);
155 return temporaryValue
;
158 case LOGIC_CONDITION_GVAR_DEC
:
159 temporaryValue
= gvGet(operandA
) - operandB
;
160 gvSet(operandA
, temporaryValue
);
161 return temporaryValue
;
164 case LOGIC_CONDITION_ADD
:
165 return constrain(operandA
+ operandB
, INT16_MIN
, INT16_MAX
);
168 case LOGIC_CONDITION_SUB
:
169 return constrain(operandA
- operandB
, INT16_MIN
, INT16_MAX
);
172 case LOGIC_CONDITION_MUL
:
173 return constrain(operandA
* operandB
, INT16_MIN
, INT16_MAX
);
176 case LOGIC_CONDITION_DIV
:
178 return constrain(operandA
/ operandB
, INT16_MIN
, INT16_MAX
);
190 void logicConditionProcess(uint8_t i
) {
192 const int activatorValue
= logicConditionGetValue(logicConditions(i
)->activatorId
);
194 if (logicConditions(i
)->enabled
&& activatorValue
) {
197 * Process condition only when latch flag is not set
198 * Latched LCs can only go from OFF to ON, not the other way
200 if (!(logicConditionStates
[i
].flags
& LOGIC_CONDITION_FLAG_LATCH
)) {
201 const int operandAValue
= logicConditionGetOperandValue(logicConditions(i
)->operandA
.type
, logicConditions(i
)->operandA
.value
);
202 const int operandBValue
= logicConditionGetOperandValue(logicConditions(i
)->operandB
.type
, logicConditions(i
)->operandB
.value
);
203 const int newValue
= logicConditionCompute(
204 logicConditionStates
[i
].value
,
205 logicConditions(i
)->operation
,
210 logicConditionStates
[i
].value
= newValue
;
213 * if value evaluates as true, put a latch on logic condition
215 if (logicConditions(i
)->flags
& LOGIC_CONDITION_FLAG_LATCH
&& newValue
) {
216 logicConditionStates
[i
].flags
|= LOGIC_CONDITION_FLAG_LATCH
;
220 logicConditionStates
[i
].value
= false;
224 static int logicConditionGetFlightOperandValue(int operand
) {
228 case LOGIC_CONDITION_OPERAND_FLIGHT_ARM_TIMER
: // in s
229 return constrain((uint32_t)getFlightTime(), 0, INT16_MAX
);
232 case LOGIC_CONDITION_OPERAND_FLIGHT_HOME_DISTANCE
: //in m
233 return constrain(GPS_distanceToHome
, 0, INT16_MAX
);
236 case LOGIC_CONDITION_OPERAND_FLIGHT_TRIP_DISTANCE
: //in m
237 return constrain(getTotalTravelDistance() / 100, 0, INT16_MAX
);
240 case LOGIC_CONDITION_OPERAND_FLIGHT_RSSI
:
241 return constrain(getRSSI() * 100 / RSSI_MAX_VALUE
, 0, 99);
244 case LOGIC_CONDITION_OPERAND_FLIGHT_VBAT
: // V / 10
245 return getBatteryVoltage();
248 case LOGIC_CONDITION_OPERAND_FLIGHT_CELL_VOLTAGE
: // V / 10
249 return getBatteryAverageCellVoltage();
251 case LOGIC_CONDITION_OPERAND_FLIGHT_CURRENT
: // Amp / 100
252 return getAmperage();
255 case LOGIC_CONDITION_OPERAND_FLIGHT_MAH_DRAWN
: // mAh
256 return getMAhDrawn();
259 case LOGIC_CONDITION_OPERAND_FLIGHT_GPS_SATS
:
260 return gpsSol
.numSat
;
263 case LOGIC_CONDITION_OPERAND_FLIGHT_GROUD_SPEED
: // cm/s
264 return gpsSol
.groundSpeed
;
267 //FIXME align with osdGet3DSpeed
268 case LOGIC_CONDITION_OPERAND_FLIGHT_3D_SPEED
: // cm/s
269 return (int) sqrtf(sq(gpsSol
.groundSpeed
) + sq((int)getEstimatedActualVelocity(Z
)));
272 case LOGIC_CONDITION_OPERAND_FLIGHT_AIR_SPEED
: // cm/s
274 return constrain(pitot
.airSpeed
, 0, INT16_MAX
);
280 case LOGIC_CONDITION_OPERAND_FLIGHT_ALTITUDE
: // cm
281 return constrain(getEstimatedActualPosition(Z
), INT16_MIN
, INT16_MAX
);
284 case LOGIC_CONDITION_OPERAND_FLIGHT_VERTICAL_SPEED
: // cm/s
285 return constrain(getEstimatedActualVelocity(Z
), 0, INT16_MAX
);
288 case LOGIC_CONDITION_OPERAND_FLIGHT_TROTTLE_POS
: // %
289 return (constrain(rcCommand
[THROTTLE
], PWM_RANGE_MIN
, PWM_RANGE_MAX
) - PWM_RANGE_MIN
) * 100 / (PWM_RANGE_MAX
- PWM_RANGE_MIN
);
292 case LOGIC_CONDITION_OPERAND_FLIGHT_ATTITUDE_ROLL
: // deg
293 return constrain(attitude
.values
.roll
/ 10, -180, 180);
296 case LOGIC_CONDITION_OPERAND_FLIGHT_ATTITUDE_PITCH
: // deg
297 return constrain(attitude
.values
.pitch
/ 10, -180, 180);
300 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_ARMED
: // 0/1
301 return ARMING_FLAG(ARMED
) ? 1 : 0;
304 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_AUTOLAUNCH
: // 0/1
305 return (navGetCurrentStateFlags() & NAV_CTL_LAUNCH
) ? 1 : 0;
308 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_ALTITUDE_CONTROL
: // 0/1
309 return (navGetCurrentStateFlags() & NAV_CTL_ALT
) ? 1 : 0;
312 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_POSITION_CONTROL
: // 0/1
313 return (navGetCurrentStateFlags() & NAV_CTL_POS
) ? 1 : 0;
316 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_EMERGENCY_LANDING
: // 0/1
317 return (navGetCurrentStateFlags() & NAV_CTL_EMERG
) ? 1 : 0;
320 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_RTH
: // 0/1
321 return (navGetCurrentStateFlags() & NAV_AUTO_RTH
) ? 1 : 0;
324 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_WP
: // 0/1
325 return (navGetCurrentStateFlags() & NAV_AUTO_WP
) ? 1 : 0;
328 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_LANDING
: // 0/1
329 return (navGetCurrentStateFlags() & NAV_CTL_LAND
) ? 1 : 0;
332 case LOGIC_CONDITION_OPERAND_FLIGHT_IS_FAILSAFE
: // 0/1
333 return (failsafePhase() == FAILSAFE_RX_LOSS_MONITORING
) ? 1 : 0;
336 case LOGIC_CONDITION_OPERAND_FLIGHT_STABILIZED_YAW
: //
340 case LOGIC_CONDITION_OPERAND_FLIGHT_STABILIZED_ROLL
: //
341 return axisPID
[ROLL
];
344 case LOGIC_CONDITION_OPERAND_FLIGHT_STABILIZED_PITCH
: //
345 return axisPID
[PITCH
];
354 static int logicConditionGetFlightModeOperandValue(int operand
) {
358 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_FAILSAFE
:
359 return (bool) FLIGHT_MODE(FAILSAFE_MODE
);
362 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_MANUAL
:
363 return (bool) FLIGHT_MODE(MANUAL_MODE
);
366 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_RTH
:
367 return (bool) FLIGHT_MODE(NAV_RTH_MODE
);
370 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_POSHOLD
:
371 return (bool) FLIGHT_MODE(NAV_POSHOLD_MODE
);
374 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_CRUISE
:
375 return (bool) FLIGHT_MODE(NAV_CRUISE_MODE
);
378 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_ALTHOLD
:
379 return (bool) FLIGHT_MODE(NAV_ALTHOLD_MODE
);
382 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_ANGLE
:
383 return (bool) FLIGHT_MODE(ANGLE_MODE
);
386 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_HORIZON
:
387 return (bool) FLIGHT_MODE(HORIZON_MODE
);
390 case LOGIC_CONDITION_OPERAND_FLIGHT_MODE_AIR
:
391 return (bool) FLIGHT_MODE(AIRMODE_ACTIVE
);
400 int logicConditionGetOperandValue(logicOperandType_e type
, int operand
) {
405 case LOGIC_CONDITION_OPERAND_TYPE_VALUE
:
409 case LOGIC_CONDITION_OPERAND_TYPE_RC_CHANNEL
:
410 //Extract RC channel raw value
411 if (operand
>= 1 && operand
<= 16) {
412 retVal
= rxGetChannelValue(operand
- 1);
416 case LOGIC_CONDITION_OPERAND_TYPE_FLIGHT
:
417 retVal
= logicConditionGetFlightOperandValue(operand
);
420 case LOGIC_CONDITION_OPERAND_TYPE_FLIGHT_MODE
:
421 retVal
= logicConditionGetFlightModeOperandValue(operand
);
424 case LOGIC_CONDITION_OPERAND_TYPE_LC
:
425 if (operand
>= 0 && operand
< MAX_LOGIC_CONDITIONS
) {
426 retVal
= logicConditionGetValue(operand
);
430 case LOGIC_CONDITION_OPERAND_TYPE_GVAR
:
431 if (operand
>= 0 && operand
< MAX_GLOBAL_VARIABLES
) {
432 retVal
= gvGet(operand
);
444 * conditionId == -1 is always evaluated as true
446 int logicConditionGetValue(int8_t conditionId
) {
447 if (conditionId
>= 0) {
448 return logicConditionStates
[conditionId
].value
;
454 void logicConditionUpdateTask(timeUs_t currentTimeUs
) {
455 UNUSED(currentTimeUs
);
456 for (uint8_t i
= 0; i
< MAX_LOGIC_CONDITIONS
; i
++) {
457 logicConditionProcess(i
);
461 void logicConditionReset(void) {
462 for (uint8_t i
= 0; i
< MAX_LOGIC_CONDITIONS
; i
++) {
463 logicConditionStates
[i
].value
= 0;
464 logicConditionStates
[i
].flags
= 0;