2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
24 #include "blackbox/blackbox.h"
25 #include "blackbox/blackbox_fielddefs.h"
27 #include "common/axis.h"
28 #include "common/maths.h"
29 #include "common/utils.h"
31 #include "config/feature.h"
32 #include "config/parameter_group.h"
33 #include "config/parameter_group_ids.h"
35 #include "drivers/time.h"
36 #include "drivers/vtx_common.h"
38 #include "fc/config.h"
39 #include "fc/controlrate_profile.h"
40 #include "fc/rc_adjustments.h"
41 #include "fc/rc_curves.h"
42 #include "fc/settings.h"
44 #include "navigation/navigation.h"
45 #include "navigation/navigation_private.h"
47 #include "flight/mixer.h"
48 #include "flight/pid.h"
50 #include "io/beeper.h"
53 #include "sensors/battery.h"
54 #include "sensors/boardalignment.h"
58 PG_REGISTER_ARRAY(adjustmentRange_t
, MAX_ADJUSTMENT_RANGE_COUNT
, adjustmentRanges
, PG_ADJUSTMENT_RANGE_CONFIG
, 0);
60 static uint8_t adjustmentStateMask
= 0;
62 #define MARK_ADJUSTMENT_FUNCTION_AS_BUSY(adjustmentIndex) adjustmentStateMask |= (1 << adjustmentIndex)
63 #define MARK_ADJUSTMENT_FUNCTION_AS_READY(adjustmentIndex) adjustmentStateMask &= ~(1 << adjustmentIndex)
65 #define IS_ADJUSTMENT_FUNCTION_BUSY(adjustmentIndex) (adjustmentStateMask & (1 << adjustmentIndex))
67 // sync with adjustmentFunction_e
68 static const adjustmentConfig_t defaultAdjustmentConfigs
[ADJUSTMENT_FUNCTION_COUNT
- 1] = {
70 .adjustmentFunction
= ADJUSTMENT_RC_RATE
,
71 .mode
= ADJUSTMENT_MODE_STEP
,
72 .data
= { .stepConfig
= { .step
= 1 }}
74 .adjustmentFunction
= ADJUSTMENT_RC_EXPO
,
75 .mode
= ADJUSTMENT_MODE_STEP
,
76 .data
= { .stepConfig
= { .step
= 1 }}
78 .adjustmentFunction
= ADJUSTMENT_THROTTLE_EXPO
,
79 .mode
= ADJUSTMENT_MODE_STEP
,
80 .data
= { .stepConfig
= { .step
= 1 }}
82 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_RATE
,
83 .mode
= ADJUSTMENT_MODE_STEP
,
84 .data
= { .stepConfig
= { .step
= 1 }}
86 .adjustmentFunction
= ADJUSTMENT_YAW_RATE
,
87 .mode
= ADJUSTMENT_MODE_STEP
,
88 .data
= { .stepConfig
= { .step
= 1 }}
90 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_P
,
91 .mode
= ADJUSTMENT_MODE_STEP
,
92 .data
= { .stepConfig
= { .step
= 1 }}
94 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_I
,
95 .mode
= ADJUSTMENT_MODE_STEP
,
96 .data
= { .stepConfig
= { .step
= 1 }}
98 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_D
,
99 .mode
= ADJUSTMENT_MODE_STEP
,
100 .data
= { .stepConfig
= { .step
= 1 }}
102 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_FF
,
103 .mode
= ADJUSTMENT_MODE_STEP
,
104 .data
= { .stepConfig
= { .step
= 1 }}
106 .adjustmentFunction
= ADJUSTMENT_PITCH_P
,
107 .mode
= ADJUSTMENT_MODE_STEP
,
108 .data
= { .stepConfig
= { .step
= 1 }}
110 .adjustmentFunction
= ADJUSTMENT_PITCH_I
,
111 .mode
= ADJUSTMENT_MODE_STEP
,
112 .data
= { .stepConfig
= { .step
= 1 }}
114 .adjustmentFunction
= ADJUSTMENT_PITCH_D
,
115 .mode
= ADJUSTMENT_MODE_STEP
,
116 .data
= { .stepConfig
= { .step
= 1 }}
118 .adjustmentFunction
= ADJUSTMENT_PITCH_FF
,
119 .mode
= ADJUSTMENT_MODE_STEP
,
120 .data
= { .stepConfig
= { .step
= 1 }}
122 .adjustmentFunction
= ADJUSTMENT_ROLL_P
,
123 .mode
= ADJUSTMENT_MODE_STEP
,
124 .data
= { .stepConfig
= { .step
= 1 }}
126 .adjustmentFunction
= ADJUSTMENT_ROLL_I
,
127 .mode
= ADJUSTMENT_MODE_STEP
,
128 .data
= { .stepConfig
= { .step
= 1 }}
130 .adjustmentFunction
= ADJUSTMENT_ROLL_D
,
131 .mode
= ADJUSTMENT_MODE_STEP
,
132 .data
= { .stepConfig
= { .step
= 1 }}
134 .adjustmentFunction
= ADJUSTMENT_ROLL_FF
,
135 .mode
= ADJUSTMENT_MODE_STEP
,
136 .data
= { .stepConfig
= { .step
= 1 }}
138 .adjustmentFunction
= ADJUSTMENT_YAW_P
,
139 .mode
= ADJUSTMENT_MODE_STEP
,
140 .data
= { .stepConfig
= { .step
= 1 }}
142 .adjustmentFunction
= ADJUSTMENT_YAW_I
,
143 .mode
= ADJUSTMENT_MODE_STEP
,
144 .data
= { .stepConfig
= { .step
= 1 }}
146 .adjustmentFunction
= ADJUSTMENT_YAW_D
,
147 .mode
= ADJUSTMENT_MODE_STEP
,
148 .data
= { .stepConfig
= { .step
= 1 }}
150 .adjustmentFunction
= ADJUSTMENT_YAW_FF
,
151 .mode
= ADJUSTMENT_MODE_STEP
,
152 .data
= { .stepConfig
= { .step
= 1 }}
154 .adjustmentFunction
= ADJUSTMENT_RATE_PROFILE
,
155 .mode
= ADJUSTMENT_MODE_STEP
,
156 .data
= { .stepConfig
= { .step
= 1 }}
158 .adjustmentFunction
= ADJUSTMENT_PITCH_RATE
,
159 .mode
= ADJUSTMENT_MODE_STEP
,
160 .data
= { .stepConfig
= { .step
= 1 }}
162 .adjustmentFunction
= ADJUSTMENT_ROLL_RATE
,
163 .mode
= ADJUSTMENT_MODE_STEP
,
164 .data
= { .stepConfig
= { .step
= 1 }}
166 .adjustmentFunction
= ADJUSTMENT_RC_YAW_EXPO
,
167 .mode
= ADJUSTMENT_MODE_STEP
,
168 .data
= { .stepConfig
= { .step
= 1 }}
170 .adjustmentFunction
= ADJUSTMENT_MANUAL_RC_EXPO
,
171 .mode
= ADJUSTMENT_MODE_STEP
,
172 .data
= { .stepConfig
= { .step
= 1 }}
174 .adjustmentFunction
= ADJUSTMENT_MANUAL_RC_YAW_EXPO
,
175 .mode
= ADJUSTMENT_MODE_STEP
,
176 .data
= { .stepConfig
= { .step
= 1 }}
178 .adjustmentFunction
= ADJUSTMENT_MANUAL_PITCH_ROLL_RATE
,
179 .mode
= ADJUSTMENT_MODE_STEP
,
180 .data
= { .stepConfig
= { .step
= 1 }}
182 .adjustmentFunction
= ADJUSTMENT_MANUAL_ROLL_RATE
,
183 .mode
= ADJUSTMENT_MODE_STEP
,
184 .data
= { .stepConfig
= { .step
= 1 }}
186 .adjustmentFunction
= ADJUSTMENT_MANUAL_PITCH_RATE
,
187 .mode
= ADJUSTMENT_MODE_STEP
,
188 .data
= { .stepConfig
= { .step
= 1 }}
190 .adjustmentFunction
= ADJUSTMENT_MANUAL_YAW_RATE
,
191 .mode
= ADJUSTMENT_MODE_STEP
,
192 .data
= { .stepConfig
= { .step
= 1 }}
194 .adjustmentFunction
= ADJUSTMENT_NAV_FW_CRUISE_THR
,
195 .mode
= ADJUSTMENT_MODE_STEP
,
196 .data
= { .stepConfig
= { .step
= 10 }}
198 .adjustmentFunction
= ADJUSTMENT_NAV_FW_PITCH2THR
,
199 .mode
= ADJUSTMENT_MODE_STEP
,
200 .data
= { .stepConfig
= { .step
= 1 }}
202 .adjustmentFunction
= ADJUSTMENT_ROLL_BOARD_ALIGNMENT
,
203 .mode
= ADJUSTMENT_MODE_STEP
,
204 .data
= { .stepConfig
= { .step
= 5 }}
206 .adjustmentFunction
= ADJUSTMENT_PITCH_BOARD_ALIGNMENT
,
207 .mode
= ADJUSTMENT_MODE_STEP
,
208 .data
= { .stepConfig
= { .step
= 5 }}
210 .adjustmentFunction
= ADJUSTMENT_LEVEL_P
,
211 .mode
= ADJUSTMENT_MODE_STEP
,
212 .data
= { .stepConfig
= { .step
= 1 }}
214 .adjustmentFunction
= ADJUSTMENT_LEVEL_I
,
215 .mode
= ADJUSTMENT_MODE_STEP
,
216 .data
= { .stepConfig
= { .step
= 1 }}
218 .adjustmentFunction
= ADJUSTMENT_LEVEL_D
,
219 .mode
= ADJUSTMENT_MODE_STEP
,
220 .data
= { .stepConfig
= { .step
= 1 }}
222 .adjustmentFunction
= ADJUSTMENT_POS_XY_P
,
223 .mode
= ADJUSTMENT_MODE_STEP
,
224 .data
= { .stepConfig
= { .step
= 1 }}
226 .adjustmentFunction
= ADJUSTMENT_POS_XY_I
,
227 .mode
= ADJUSTMENT_MODE_STEP
,
228 .data
= { .stepConfig
= { .step
= 1 }}
230 .adjustmentFunction
= ADJUSTMENT_POS_XY_D
,
231 .mode
= ADJUSTMENT_MODE_STEP
,
232 .data
= { .stepConfig
= { .step
= 1 }}
234 .adjustmentFunction
= ADJUSTMENT_POS_Z_P
,
235 .mode
= ADJUSTMENT_MODE_STEP
,
236 .data
= { .stepConfig
= { .step
= 1 }}
238 .adjustmentFunction
= ADJUSTMENT_POS_Z_I
,
239 .mode
= ADJUSTMENT_MODE_STEP
,
240 .data
= { .stepConfig
= { .step
= 1 }}
242 .adjustmentFunction
= ADJUSTMENT_POS_Z_D
,
243 .mode
= ADJUSTMENT_MODE_STEP
,
244 .data
= { .stepConfig
= { .step
= 1 }}
246 .adjustmentFunction
= ADJUSTMENT_HEADING_P
,
247 .mode
= ADJUSTMENT_MODE_STEP
,
248 .data
= { .stepConfig
= { .step
= 1 }}
250 .adjustmentFunction
= ADJUSTMENT_VEL_XY_P
,
251 .mode
= ADJUSTMENT_MODE_STEP
,
252 .data
= { .stepConfig
= { .step
= 1 }}
254 .adjustmentFunction
= ADJUSTMENT_VEL_XY_I
,
255 .mode
= ADJUSTMENT_MODE_STEP
,
256 .data
= { .stepConfig
= { .step
= 1 }}
258 .adjustmentFunction
= ADJUSTMENT_VEL_XY_D
,
259 .mode
= ADJUSTMENT_MODE_STEP
,
260 .data
= { .stepConfig
= { .step
= 1 }}
262 .adjustmentFunction
= ADJUSTMENT_VEL_Z_P
,
263 .mode
= ADJUSTMENT_MODE_STEP
,
264 .data
= { .stepConfig
= { .step
= 1 }}
266 .adjustmentFunction
= ADJUSTMENT_VEL_Z_I
,
267 .mode
= ADJUSTMENT_MODE_STEP
,
268 .data
= { .stepConfig
= { .step
= 1 }}
270 .adjustmentFunction
= ADJUSTMENT_VEL_Z_D
,
271 .mode
= ADJUSTMENT_MODE_STEP
,
272 .data
= { .stepConfig
= { .step
= 1 }}
274 .adjustmentFunction
= ADJUSTMENT_FW_MIN_THROTTLE_DOWN_PITCH_ANGLE
,
275 .mode
= ADJUSTMENT_MODE_STEP
,
276 .data
= { .stepConfig
= { .step
= 5 }}
278 .adjustmentFunction
= ADJUSTMENT_VTX_POWER_LEVEL
,
279 .mode
= ADJUSTMENT_MODE_STEP
,
280 .data
= { .stepConfig
= { .step
= 1 }}
282 .adjustmentFunction
= ADJUSTMENT_TPA
,
283 .mode
= ADJUSTMENT_MODE_STEP
,
284 .data
= { .stepConfig
= { .step
= 1 }}
286 .adjustmentFunction
= ADJUSTMENT_TPA_BREAKPOINT
,
287 .mode
= ADJUSTMENT_MODE_STEP
,
288 .data
= { .stepConfig
= { .step
= 5 }}
290 .adjustmentFunction
= ADJUSTMENT_NAV_FW_CONTROL_SMOOTHNESS
,
291 .mode
= ADJUSTMENT_MODE_STEP
,
292 .data
= { .stepConfig
= { .step
= 1 }}
294 .adjustmentFunction
= ADJUSTMENT_FW_TPA_TIME_CONSTANT
,
295 .mode
= ADJUSTMENT_MODE_STEP
,
296 .data
= { .stepConfig
= { .step
= 5 }}
298 .adjustmentFunction
= ADJUSTMENT_FW_LEVEL_TRIM
,
299 .mode
= ADJUSTMENT_MODE_STEP
,
300 .data
= { .stepConfig
= { .step
= 1 }}
302 .adjustmentFunction
= ADJUSTMENT_NAV_WP_MULTI_MISSION_INDEX
,
303 .mode
= ADJUSTMENT_MODE_STEP
,
304 .data
= { .stepConfig
= { .step
= 1 }}
308 #define ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET 1
310 static adjustmentState_t adjustmentStates
[MAX_SIMULTANEOUS_ADJUSTMENT_COUNT
];
312 static void configureAdjustment(uint8_t index
, uint8_t auxSwitchChannelIndex
, const adjustmentConfig_t
*adjustmentConfig
)
314 adjustmentState_t
* const adjustmentState
= &adjustmentStates
[index
];
316 if (adjustmentState
->config
== adjustmentConfig
) {
317 // already configured
320 adjustmentState
->auxChannelIndex
= auxSwitchChannelIndex
;
321 adjustmentState
->config
= adjustmentConfig
;
322 adjustmentState
->timeoutAt
= 0;
324 MARK_ADJUSTMENT_FUNCTION_AS_READY(index
);
327 static void blackboxLogInflightAdjustmentEvent(adjustmentFunction_e adjustmentFunction
, int32_t newValue
)
330 UNUSED(adjustmentFunction
);
333 if (feature(FEATURE_BLACKBOX
)) {
334 flightLogEvent_inflightAdjustment_t eventData
;
335 eventData
.adjustmentFunction
= adjustmentFunction
;
336 eventData
.newValue
= newValue
;
337 eventData
.floatFlag
= false;
338 blackboxLogEvent(FLIGHT_LOG_EVENT_INFLIGHT_ADJUSTMENT
, (flightLogEventData_t
*)&eventData
);
343 static void applyAdjustmentU8(adjustmentFunction_e adjustmentFunction
, uint8_t *val
, int delta
, int low
, int high
)
345 int newValue
= constrain((int)(*val
) + delta
, low
, high
);
347 blackboxLogInflightAdjustmentEvent(adjustmentFunction
, newValue
);
350 static void applyAdjustmentU16(adjustmentFunction_e adjustmentFunction
, uint16_t *val
, int delta
, int low
, int high
)
352 int newValue
= constrain((int)(*val
) + delta
, low
, high
);
354 blackboxLogInflightAdjustmentEvent(adjustmentFunction
, newValue
);
357 static void applyAdjustmentExpo(adjustmentFunction_e adjustmentFunction
, uint8_t *val
, int delta
)
359 applyAdjustmentU8(adjustmentFunction
, val
, delta
, SETTING_RC_EXPO_MIN
, SETTING_RC_EXPO_MAX
);
362 static void applyAdjustmentManualRate(adjustmentFunction_e adjustmentFunction
, uint8_t *val
, int delta
)
364 return applyAdjustmentU8(adjustmentFunction
, val
, delta
, SETTING_CONSTANT_MANUAL_RATE_MIN
, SETTING_CONSTANT_MANUAL_RATE_MAX
);
367 static void applyAdjustmentPID(adjustmentFunction_e adjustmentFunction
, uint16_t *val
, int delta
)
369 applyAdjustmentU16(adjustmentFunction
, val
, delta
, SETTING_CONSTANT_RPYL_PID_MIN
, SETTING_CONSTANT_RPYL_PID_MAX
);
372 static void applyStepAdjustment(controlRateConfig_t
*controlRateConfig
, uint8_t adjustmentFunction
, int delta
)
375 beeperConfirmationBeeps(2);
377 beeperConfirmationBeeps(1);
379 switch (adjustmentFunction
) {
380 case ADJUSTMENT_RC_EXPO
:
381 applyAdjustmentExpo(ADJUSTMENT_RC_EXPO
, &controlRateConfig
->stabilized
.rcExpo8
, delta
);
383 case ADJUSTMENT_RC_YAW_EXPO
:
384 applyAdjustmentExpo(ADJUSTMENT_RC_YAW_EXPO
, &controlRateConfig
->stabilized
.rcYawExpo8
, delta
);
386 case ADJUSTMENT_MANUAL_RC_EXPO
:
387 applyAdjustmentExpo(ADJUSTMENT_MANUAL_RC_EXPO
, &controlRateConfig
->manual
.rcExpo8
, delta
);
389 case ADJUSTMENT_MANUAL_RC_YAW_EXPO
:
390 applyAdjustmentExpo(ADJUSTMENT_MANUAL_RC_YAW_EXPO
, &controlRateConfig
->manual
.rcYawExpo8
, delta
);
392 case ADJUSTMENT_THROTTLE_EXPO
:
393 applyAdjustmentExpo(ADJUSTMENT_THROTTLE_EXPO
, &controlRateConfig
->throttle
.rcExpo8
, delta
);
395 case ADJUSTMENT_PITCH_ROLL_RATE
:
396 case ADJUSTMENT_PITCH_RATE
:
397 applyAdjustmentU8(ADJUSTMENT_PITCH_RATE
, &controlRateConfig
->stabilized
.rates
[FD_PITCH
], delta
, SETTING_PITCH_RATE_MIN
, SETTING_PITCH_RATE_MAX
);
398 if (adjustmentFunction
== ADJUSTMENT_PITCH_RATE
) {
399 schedulePidGainsUpdate();
402 // follow though for combined ADJUSTMENT_PITCH_ROLL_RATE
405 case ADJUSTMENT_ROLL_RATE
:
406 applyAdjustmentU8(ADJUSTMENT_ROLL_RATE
, &controlRateConfig
->stabilized
.rates
[FD_ROLL
], delta
, SETTING_CONSTANT_ROLL_PITCH_RATE_MIN
, SETTING_CONSTANT_ROLL_PITCH_RATE_MAX
);
407 schedulePidGainsUpdate();
409 case ADJUSTMENT_MANUAL_PITCH_ROLL_RATE
:
410 case ADJUSTMENT_MANUAL_ROLL_RATE
:
411 applyAdjustmentManualRate(ADJUSTMENT_MANUAL_ROLL_RATE
, &controlRateConfig
->manual
.rates
[FD_ROLL
], delta
);
412 if (adjustmentFunction
== ADJUSTMENT_MANUAL_ROLL_RATE
)
414 // follow though for combined ADJUSTMENT_MANUAL_PITCH_ROLL_RATE
416 case ADJUSTMENT_MANUAL_PITCH_RATE
:
417 applyAdjustmentManualRate(ADJUSTMENT_MANUAL_PITCH_RATE
, &controlRateConfig
->manual
.rates
[FD_PITCH
], delta
);
419 case ADJUSTMENT_YAW_RATE
:
420 applyAdjustmentU8(ADJUSTMENT_YAW_RATE
, &controlRateConfig
->stabilized
.rates
[FD_YAW
], delta
, SETTING_YAW_RATE_MIN
, SETTING_YAW_RATE_MAX
);
421 schedulePidGainsUpdate();
423 case ADJUSTMENT_MANUAL_YAW_RATE
:
424 applyAdjustmentManualRate(ADJUSTMENT_MANUAL_YAW_RATE
, &controlRateConfig
->manual
.rates
[FD_YAW
], delta
);
426 case ADJUSTMENT_PITCH_ROLL_P
:
427 case ADJUSTMENT_PITCH_P
:
428 applyAdjustmentPID(ADJUSTMENT_PITCH_P
, &pidBankMutable()->pid
[PID_PITCH
].P
, delta
);
429 if (adjustmentFunction
== ADJUSTMENT_PITCH_P
) {
430 schedulePidGainsUpdate();
433 // follow though for combined ADJUSTMENT_PITCH_ROLL_P
436 case ADJUSTMENT_ROLL_P
:
437 applyAdjustmentPID(ADJUSTMENT_ROLL_P
, &pidBankMutable()->pid
[PID_ROLL
].P
, delta
);
438 schedulePidGainsUpdate();
440 case ADJUSTMENT_PITCH_ROLL_I
:
441 case ADJUSTMENT_PITCH_I
:
442 applyAdjustmentPID(ADJUSTMENT_PITCH_I
, &pidBankMutable()->pid
[PID_PITCH
].I
, delta
);
443 if (adjustmentFunction
== ADJUSTMENT_PITCH_I
) {
444 schedulePidGainsUpdate();
447 // follow though for combined ADJUSTMENT_PITCH_ROLL_I
450 case ADJUSTMENT_ROLL_I
:
451 applyAdjustmentPID(ADJUSTMENT_ROLL_I
, &pidBankMutable()->pid
[PID_ROLL
].I
, delta
);
452 schedulePidGainsUpdate();
454 case ADJUSTMENT_PITCH_ROLL_D
:
455 case ADJUSTMENT_PITCH_D
:
456 applyAdjustmentPID(ADJUSTMENT_PITCH_D
, &pidBankMutable()->pid
[PID_PITCH
].D
, delta
);
457 if (adjustmentFunction
== ADJUSTMENT_PITCH_D
) {
458 schedulePidGainsUpdate();
461 // follow though for combined ADJUSTMENT_PITCH_ROLL_D
464 case ADJUSTMENT_ROLL_D
:
465 applyAdjustmentPID(ADJUSTMENT_ROLL_D
, &pidBankMutable()->pid
[PID_ROLL
].D
, delta
);
466 schedulePidGainsUpdate();
468 case ADJUSTMENT_PITCH_ROLL_FF
:
469 case ADJUSTMENT_PITCH_FF
:
470 applyAdjustmentPID(ADJUSTMENT_PITCH_FF
, &pidBankMutable()->pid
[PID_PITCH
].FF
, delta
);
471 if (adjustmentFunction
== ADJUSTMENT_PITCH_FF
) {
472 schedulePidGainsUpdate();
475 // follow though for combined ADJUSTMENT_PITCH_ROLL_FF
478 case ADJUSTMENT_ROLL_FF
:
479 applyAdjustmentPID(ADJUSTMENT_ROLL_FF
, &pidBankMutable()->pid
[PID_ROLL
].FF
, delta
);
480 schedulePidGainsUpdate();
482 case ADJUSTMENT_YAW_P
:
483 applyAdjustmentPID(ADJUSTMENT_YAW_P
, &pidBankMutable()->pid
[PID_YAW
].P
, delta
);
484 schedulePidGainsUpdate();
486 case ADJUSTMENT_YAW_I
:
487 applyAdjustmentPID(ADJUSTMENT_YAW_I
, &pidBankMutable()->pid
[PID_YAW
].I
, delta
);
488 schedulePidGainsUpdate();
490 case ADJUSTMENT_YAW_D
:
491 applyAdjustmentPID(ADJUSTMENT_YAW_D
, &pidBankMutable()->pid
[PID_YAW
].D
, delta
);
492 schedulePidGainsUpdate();
494 case ADJUSTMENT_YAW_FF
:
495 applyAdjustmentPID(ADJUSTMENT_YAW_FF
, &pidBankMutable()->pid
[PID_YAW
].FF
, delta
);
496 schedulePidGainsUpdate();
498 case ADJUSTMENT_NAV_FW_CRUISE_THR
:
499 applyAdjustmentU16(ADJUSTMENT_NAV_FW_CRUISE_THR
, ¤tBatteryProfileMutable
->nav
.fw
.cruise_throttle
, delta
, SETTING_NAV_FW_CRUISE_THR_MIN
, SETTING_NAV_FW_CRUISE_THR_MAX
);
501 case ADJUSTMENT_NAV_FW_PITCH2THR
:
502 applyAdjustmentU8(ADJUSTMENT_NAV_FW_PITCH2THR
, ¤tBatteryProfileMutable
->nav
.fw
.pitch_to_throttle
, delta
, SETTING_NAV_FW_PITCH2THR_MIN
, SETTING_NAV_FW_PITCH2THR_MAX
);
504 case ADJUSTMENT_ROLL_BOARD_ALIGNMENT
:
505 updateBoardAlignment(delta
, 0);
506 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_BOARD_ALIGNMENT
, boardAlignment()->rollDeciDegrees
);
508 case ADJUSTMENT_PITCH_BOARD_ALIGNMENT
:
509 updateBoardAlignment(0, delta
);
510 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_BOARD_ALIGNMENT
, boardAlignment()->pitchDeciDegrees
);
512 case ADJUSTMENT_LEVEL_P
:
513 applyAdjustmentPID(ADJUSTMENT_LEVEL_P
, &pidBankMutable()->pid
[PID_LEVEL
].P
, delta
);
514 // TODO: Need to call something to take it into account?
516 case ADJUSTMENT_LEVEL_I
:
517 applyAdjustmentPID(ADJUSTMENT_LEVEL_I
, &pidBankMutable()->pid
[PID_LEVEL
].I
, delta
);
518 // TODO: Need to call something to take it into account?
520 case ADJUSTMENT_LEVEL_D
:
521 applyAdjustmentPID(ADJUSTMENT_LEVEL_D
, &pidBankMutable()->pid
[PID_LEVEL
].D
, delta
);
522 // TODO: Need to call something to take it into account?
524 case ADJUSTMENT_POS_XY_P
:
525 applyAdjustmentPID(ADJUSTMENT_POS_XY_P
, &pidBankMutable()->pid
[PID_POS_XY
].P
, delta
);
528 case ADJUSTMENT_POS_XY_I
:
529 applyAdjustmentPID(ADJUSTMENT_POS_XY_I
, &pidBankMutable()->pid
[PID_POS_XY
].I
, delta
);
532 case ADJUSTMENT_POS_XY_D
:
533 applyAdjustmentPID(ADJUSTMENT_POS_XY_D
, &pidBankMutable()->pid
[PID_POS_XY
].D
, delta
);
536 case ADJUSTMENT_POS_Z_P
:
537 applyAdjustmentPID(ADJUSTMENT_POS_Z_P
, &pidBankMutable()->pid
[PID_POS_Z
].P
, delta
);
540 case ADJUSTMENT_POS_Z_I
:
541 applyAdjustmentPID(ADJUSTMENT_POS_Z_I
, &pidBankMutable()->pid
[PID_POS_Z
].I
, delta
);
544 case ADJUSTMENT_POS_Z_D
:
545 applyAdjustmentPID(ADJUSTMENT_POS_Z_D
, &pidBankMutable()->pid
[PID_POS_Z
].D
, delta
);
548 case ADJUSTMENT_HEADING_P
:
549 applyAdjustmentPID(ADJUSTMENT_HEADING_P
, &pidBankMutable()->pid
[PID_HEADING
].P
, delta
);
550 // TODO: navigationUsePIDs()?
552 case ADJUSTMENT_VEL_XY_P
:
553 applyAdjustmentPID(ADJUSTMENT_VEL_XY_P
, &pidBankMutable()->pid
[PID_VEL_XY
].P
, delta
);
556 case ADJUSTMENT_VEL_XY_I
:
557 applyAdjustmentPID(ADJUSTMENT_VEL_XY_I
, &pidBankMutable()->pid
[PID_VEL_XY
].I
, delta
);
560 case ADJUSTMENT_VEL_XY_D
:
561 applyAdjustmentPID(ADJUSTMENT_VEL_XY_D
, &pidBankMutable()->pid
[PID_VEL_XY
].D
, delta
);
564 case ADJUSTMENT_VEL_Z_P
:
565 applyAdjustmentPID(ADJUSTMENT_VEL_Z_P
, &pidBankMutable()->pid
[PID_VEL_Z
].P
, delta
);
568 case ADJUSTMENT_VEL_Z_I
:
569 applyAdjustmentPID(ADJUSTMENT_VEL_Z_I
, &pidBankMutable()->pid
[PID_VEL_Z
].I
, delta
);
572 case ADJUSTMENT_VEL_Z_D
:
573 applyAdjustmentPID(ADJUSTMENT_VEL_Z_D
, &pidBankMutable()->pid
[PID_VEL_Z
].D
, delta
);
576 case ADJUSTMENT_FW_MIN_THROTTLE_DOWN_PITCH_ANGLE
:
577 applyAdjustmentU16(ADJUSTMENT_FW_MIN_THROTTLE_DOWN_PITCH_ANGLE
, &navConfigMutable()->fw
.minThrottleDownPitchAngle
, delta
, SETTING_FW_MIN_THROTTLE_DOWN_PITCH_MIN
, SETTING_FW_MIN_THROTTLE_DOWN_PITCH_MAX
);
579 #if defined(USE_VTX_SMARTAUDIO) || defined(USE_VTX_TRAMP) || defined(USE_VTX_MSP)
580 case ADJUSTMENT_VTX_POWER_LEVEL
:
582 vtxDeviceCapability_t vtxDeviceCapability
;
583 if (vtxCommonGetDeviceCapability(vtxCommonDevice(), &vtxDeviceCapability
)) {
584 applyAdjustmentU8(ADJUSTMENT_VTX_POWER_LEVEL
, &vtxSettingsConfigMutable()->power
, delta
, VTX_SETTINGS_MIN_POWER
, vtxDeviceCapability
.powerCount
);
590 applyAdjustmentU8(ADJUSTMENT_TPA
, &controlRateConfig
->throttle
.dynPID
, delta
, 0, SETTING_TPA_RATE_MAX
);
592 case ADJUSTMENT_TPA_BREAKPOINT
:
593 applyAdjustmentU16(ADJUSTMENT_TPA_BREAKPOINT
, &controlRateConfig
->throttle
.pa_breakpoint
, delta
, PWM_RANGE_MIN
, PWM_RANGE_MAX
);
595 case ADJUSTMENT_FW_TPA_TIME_CONSTANT
:
596 applyAdjustmentU16(ADJUSTMENT_FW_TPA_TIME_CONSTANT
, &controlRateConfig
->throttle
.fixedWingTauMs
, delta
, SETTING_FW_TPA_TIME_CONSTANT_MIN
, SETTING_FW_TPA_TIME_CONSTANT_MAX
);
598 case ADJUSTMENT_NAV_FW_CONTROL_SMOOTHNESS
:
599 applyAdjustmentU8(ADJUSTMENT_NAV_FW_CONTROL_SMOOTHNESS
, &navConfigMutable()->fw
.control_smoothness
, delta
, SETTING_NAV_FW_CONTROL_SMOOTHNESS_MIN
, SETTING_NAV_FW_CONTROL_SMOOTHNESS_MAX
);
601 case ADJUSTMENT_FW_LEVEL_TRIM
:
603 float newValue
= pidProfileMutable()->fixedWingLevelTrim
+ (delta
/ 10.0f
);
604 if (newValue
> SETTING_FW_LEVEL_PITCH_TRIM_MAX
) {newValue
= (float)SETTING_FW_LEVEL_PITCH_TRIM_MAX
;}
605 else if (newValue
< SETTING_FW_LEVEL_PITCH_TRIM_MIN
) {newValue
= (float)SETTING_FW_LEVEL_PITCH_TRIM_MIN
;}
606 pidProfileMutable()->fixedWingLevelTrim
= newValue
;
607 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_FW_LEVEL_TRIM
, (int)(newValue
* 10.0f
));
610 #ifdef USE_MULTI_MISSION
611 case ADJUSTMENT_NAV_WP_MULTI_MISSION_INDEX
:
612 if (posControl
.multiMissionCount
&& !FLIGHT_MODE(NAV_WP_MODE
)) {
613 applyAdjustmentU8(ADJUSTMENT_NAV_WP_MULTI_MISSION_INDEX
, &navConfigMutable()->general
.waypoint_multi_mission_index
, delta
, SETTING_NAV_WP_MULTI_MISSION_INDEX_MIN
, posControl
.multiMissionCount
);
622 #ifdef USE_INFLIGHT_PROFILE_ADJUSTMENT
623 static void applySelectAdjustment(uint8_t adjustmentFunction
, uint8_t position
)
625 bool applied
= false;
627 switch (adjustmentFunction
) {
628 case ADJUSTMENT_RATE_PROFILE
:
629 if (getCurrentControlRateProfile() != position
) {
630 changeControlRateProfile(position
);
631 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RATE_PROFILE
, position
);
638 beeperConfirmationBeeps(position
+ 1);
643 #define RESET_FREQUENCY_2HZ (1000 / 2)
645 void processRcAdjustments(controlRateConfig_t
*controlRateConfig
, bool canUseRxData
)
647 const uint32_t now
= millis();
649 for (int adjustmentIndex
= 0; adjustmentIndex
< MAX_SIMULTANEOUS_ADJUSTMENT_COUNT
; adjustmentIndex
++) {
650 adjustmentState_t
* const adjustmentState
= &adjustmentStates
[adjustmentIndex
];
652 if (!adjustmentState
->config
) {
655 const uint8_t adjustmentFunction
= adjustmentState
->config
->adjustmentFunction
;
656 if (adjustmentFunction
== ADJUSTMENT_NONE
) {
660 const int32_t signedDiff
= now
- adjustmentState
->timeoutAt
;
661 const bool canResetReadyStates
= signedDiff
>= 0L;
663 if (canResetReadyStates
) {
664 adjustmentState
->timeoutAt
= now
+ RESET_FREQUENCY_2HZ
;
665 MARK_ADJUSTMENT_FUNCTION_AS_READY(adjustmentIndex
);
672 const uint8_t channelIndex
= NON_AUX_CHANNEL_COUNT
+ adjustmentState
->auxChannelIndex
;
674 if (adjustmentState
->config
->mode
== ADJUSTMENT_MODE_STEP
) {
676 if (rxGetChannelValue(channelIndex
) > PWM_RANGE_MIDDLE
+ 200) {
677 delta
= adjustmentState
->config
->data
.stepConfig
.step
;
678 } else if (rxGetChannelValue(channelIndex
) < PWM_RANGE_MIDDLE
- 200) {
679 delta
= 0 - adjustmentState
->config
->data
.stepConfig
.step
;
681 // returning the switch to the middle immediately resets the ready state
682 MARK_ADJUSTMENT_FUNCTION_AS_READY(adjustmentIndex
);
683 adjustmentState
->timeoutAt
= now
+ RESET_FREQUENCY_2HZ
;
686 if (IS_ADJUSTMENT_FUNCTION_BUSY(adjustmentIndex
)) {
690 // it is legitimate to adjust an otherwise const item here
691 applyStepAdjustment(controlRateConfig
, adjustmentFunction
, delta
);
692 #ifdef USE_INFLIGHT_PROFILE_ADJUSTMENT
693 } else if (adjustmentState
->config
->mode
== ADJUSTMENT_MODE_SELECT
) {
694 const uint16_t rangeWidth
= ((2100 - 900) / adjustmentState
->config
->data
.selectConfig
.switchPositions
);
695 const uint8_t position
= (constrain(rxGetChannelValue(channelIndex
), 900, 2100 - 1) - 900) / rangeWidth
;
697 applySelectAdjustment(adjustmentFunction
, position
);
700 MARK_ADJUSTMENT_FUNCTION_AS_BUSY(adjustmentIndex
);
704 void resetAdjustmentStates(void)
706 memset(adjustmentStates
, 0, sizeof(adjustmentStates
));
709 void updateAdjustmentStates(bool canUseRxData
)
711 for (int index
= 0; index
< MAX_ADJUSTMENT_RANGE_COUNT
; index
++) {
712 const adjustmentRange_t
* const adjustmentRange
= adjustmentRanges(index
);
713 if (adjustmentRange
->adjustmentFunction
== ADJUSTMENT_NONE
) {
717 const adjustmentConfig_t
*adjustmentConfig
= &defaultAdjustmentConfigs
[adjustmentRange
->adjustmentFunction
- ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET
];
718 adjustmentState_t
* const adjustmentState
= &adjustmentStates
[adjustmentRange
->adjustmentIndex
];
720 if (canUseRxData
&& isRangeActive(adjustmentRange
->auxChannelIndex
, &adjustmentRange
->range
)) {
721 if (!adjustmentState
->config
) {
722 configureAdjustment(adjustmentRange
->adjustmentIndex
, adjustmentRange
->auxSwitchChannelIndex
, adjustmentConfig
);
725 if (adjustmentState
->config
== adjustmentConfig
) {
726 adjustmentState
->config
= NULL
;
732 bool isAdjustmentFunctionSelected(uint8_t adjustmentFunction
) {
733 for (uint8_t index
= 0; index
< MAX_SIMULTANEOUS_ADJUSTMENT_COUNT
; ++index
) {
734 if (adjustmentStates
[index
].config
&& adjustmentStates
[index
].config
->adjustmentFunction
== adjustmentFunction
) {
741 uint8_t getActiveAdjustmentFunctions(uint8_t *adjustmentFunctions
) {
742 uint8_t adjustmentCount
= 0;
743 for (uint8_t i
= 0; i
< MAX_SIMULTANEOUS_ADJUSTMENT_COUNT
; i
++) {
744 if (adjustmentStates
[i
].config
) {
746 adjustmentFunctions
[i
] = adjustmentStates
[i
].config
->adjustmentFunction
;
749 return adjustmentCount
;