[FLYWOOF411] add board documentation
[inav/snaewe.git] / src / main / fc / rc_adjustments.c
blobbf07c3d6f348369d7f1a8df5ba9a34be5c42a583
1 /*
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/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <string.h>
22 #include "platform.h"
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"
43 #include "navigation/navigation.h"
45 #include "flight/mixer.h"
46 #include "flight/pid.h"
48 #include "io/beeper.h"
49 #include "io/vtx.h"
51 #include "sensors/boardalignment.h"
53 #include "rx/rx.h"
55 PG_REGISTER_ARRAY(adjustmentRange_t, MAX_ADJUSTMENT_RANGE_COUNT, adjustmentRanges, PG_ADJUSTMENT_RANGE_CONFIG, 0);
57 static uint8_t adjustmentStateMask = 0;
59 #define MARK_ADJUSTMENT_FUNCTION_AS_BUSY(adjustmentIndex) adjustmentStateMask |= (1 << adjustmentIndex)
60 #define MARK_ADJUSTMENT_FUNCTION_AS_READY(adjustmentIndex) adjustmentStateMask &= ~(1 << adjustmentIndex)
62 #define IS_ADJUSTMENT_FUNCTION_BUSY(adjustmentIndex) (adjustmentStateMask & (1 << adjustmentIndex))
64 #define RC_ADJUSTMENT_EXPO_MIN 0
65 #define RC_ADJUSTMENT_EXPO_MAX 100
67 #define RC_ADJUSTMENT_MANUAL_RATE_MIN 0
68 #define RC_ADJUSTMENT_MANUAL_RATE_MAX 100
70 #define RC_ADJUSTMENT_PID_MIN 0
71 #define RC_ADJUSTMENT_PID_MAX 200
73 // sync with adjustmentFunction_e
74 static const adjustmentConfig_t defaultAdjustmentConfigs[ADJUSTMENT_FUNCTION_COUNT - 1] = {
76 .adjustmentFunction = ADJUSTMENT_RC_RATE,
77 .mode = ADJUSTMENT_MODE_STEP,
78 .data = { .stepConfig = { .step = 1 }}
79 }, {
80 .adjustmentFunction = ADJUSTMENT_RC_EXPO,
81 .mode = ADJUSTMENT_MODE_STEP,
82 .data = { .stepConfig = { .step = 1 }}
83 }, {
84 .adjustmentFunction = ADJUSTMENT_THROTTLE_EXPO,
85 .mode = ADJUSTMENT_MODE_STEP,
86 .data = { .stepConfig = { .step = 1 }}
87 }, {
88 .adjustmentFunction = ADJUSTMENT_PITCH_ROLL_RATE,
89 .mode = ADJUSTMENT_MODE_STEP,
90 .data = { .stepConfig = { .step = 1 }}
91 }, {
92 .adjustmentFunction = ADJUSTMENT_YAW_RATE,
93 .mode = ADJUSTMENT_MODE_STEP,
94 .data = { .stepConfig = { .step = 1 }}
95 }, {
96 .adjustmentFunction = ADJUSTMENT_PITCH_ROLL_P,
97 .mode = ADJUSTMENT_MODE_STEP,
98 .data = { .stepConfig = { .step = 1 }}
99 }, {
100 .adjustmentFunction = ADJUSTMENT_PITCH_ROLL_I,
101 .mode = ADJUSTMENT_MODE_STEP,
102 .data = { .stepConfig = { .step = 1 }}
103 }, {
104 .adjustmentFunction = ADJUSTMENT_PITCH_ROLL_D,
105 .mode = ADJUSTMENT_MODE_STEP,
106 .data = { .stepConfig = { .step = 1 }}
107 }, {
108 .adjustmentFunction = ADJUSTMENT_YAW_P,
109 .mode = ADJUSTMENT_MODE_STEP,
110 .data = { .stepConfig = { .step = 1 }}
111 }, {
112 .adjustmentFunction = ADJUSTMENT_YAW_I,
113 .mode = ADJUSTMENT_MODE_STEP,
114 .data = { .stepConfig = { .step = 1 }}
115 }, {
116 .adjustmentFunction = ADJUSTMENT_YAW_D,
117 .mode = ADJUSTMENT_MODE_STEP,
118 .data = { .stepConfig = { .step = 1 }}
119 }, {
120 .adjustmentFunction = ADJUSTMENT_RATE_PROFILE,
121 .mode = ADJUSTMENT_MODE_STEP,
122 .data = { .stepConfig = { .step = 1 }}
123 }, {
124 .adjustmentFunction = ADJUSTMENT_PITCH_RATE,
125 .mode = ADJUSTMENT_MODE_STEP,
126 .data = { .stepConfig = { .step = 1 }}
127 }, {
128 .adjustmentFunction = ADJUSTMENT_ROLL_RATE,
129 .mode = ADJUSTMENT_MODE_STEP,
130 .data = { .stepConfig = { .step = 1 }}
131 }, {
132 .adjustmentFunction = ADJUSTMENT_PITCH_P,
133 .mode = ADJUSTMENT_MODE_STEP,
134 .data = { .stepConfig = { .step = 1 }}
135 }, {
136 .adjustmentFunction = ADJUSTMENT_PITCH_I,
137 .mode = ADJUSTMENT_MODE_STEP,
138 .data = { .stepConfig = { .step = 1 }}
139 }, {
140 .adjustmentFunction = ADJUSTMENT_PITCH_D,
141 .mode = ADJUSTMENT_MODE_STEP,
142 .data = { .stepConfig = { .step = 1 }}
143 }, {
144 .adjustmentFunction = ADJUSTMENT_ROLL_P,
145 .mode = ADJUSTMENT_MODE_STEP,
146 .data = { .stepConfig = { .step = 1 }}
147 }, {
148 .adjustmentFunction = ADJUSTMENT_ROLL_I,
149 .mode = ADJUSTMENT_MODE_STEP,
150 .data = { .stepConfig = { .step = 1 }}
151 }, {
152 .adjustmentFunction = ADJUSTMENT_ROLL_D,
153 .mode = ADJUSTMENT_MODE_STEP,
154 .data = { .stepConfig = { .step = 1 }}
155 }, {
156 .adjustmentFunction = ADJUSTMENT_RC_YAW_EXPO,
157 .mode = ADJUSTMENT_MODE_STEP,
158 .data = { .stepConfig = { .step = 1 }}
159 }, {
160 .adjustmentFunction = ADJUSTMENT_MANUAL_RC_EXPO,
161 .mode = ADJUSTMENT_MODE_STEP,
162 .data = { .stepConfig = { .step = 1 }}
163 }, {
164 .adjustmentFunction = ADJUSTMENT_MANUAL_RC_YAW_EXPO,
165 .mode = ADJUSTMENT_MODE_STEP,
166 .data = { .stepConfig = { .step = 1 }}
167 }, {
168 .adjustmentFunction = ADJUSTMENT_MANUAL_PITCH_ROLL_RATE,
169 .mode = ADJUSTMENT_MODE_STEP,
170 .data = { .stepConfig = { .step = 1 }}
171 }, {
172 .adjustmentFunction = ADJUSTMENT_MANUAL_ROLL_RATE,
173 .mode = ADJUSTMENT_MODE_STEP,
174 .data = { .stepConfig = { .step = 1 }}
175 }, {
176 .adjustmentFunction = ADJUSTMENT_MANUAL_PITCH_RATE,
177 .mode = ADJUSTMENT_MODE_STEP,
178 .data = { .stepConfig = { .step = 1 }}
179 }, {
180 .adjustmentFunction = ADJUSTMENT_MANUAL_YAW_RATE,
181 .mode = ADJUSTMENT_MODE_STEP,
182 .data = { .stepConfig = { .step = 1 }}
183 }, {
184 .adjustmentFunction = ADJUSTMENT_NAV_FW_CRUISE_THR,
185 .mode = ADJUSTMENT_MODE_STEP,
186 .data = { .stepConfig = { .step = 10 }}
187 }, {
188 .adjustmentFunction = ADJUSTMENT_NAV_FW_PITCH2THR,
189 .mode = ADJUSTMENT_MODE_STEP,
190 .data = { .stepConfig = { .step = 1 }}
191 }, {
192 .adjustmentFunction = ADJUSTMENT_ROLL_BOARD_ALIGNMENT,
193 .mode = ADJUSTMENT_MODE_STEP,
194 .data = { .stepConfig = { .step = 5 }}
195 }, {
196 .adjustmentFunction = ADJUSTMENT_PITCH_BOARD_ALIGNMENT,
197 .mode = ADJUSTMENT_MODE_STEP,
198 .data = { .stepConfig = { .step = 5 }}
199 }, {
200 .adjustmentFunction = ADJUSTMENT_LEVEL_P,
201 .mode = ADJUSTMENT_MODE_STEP,
202 .data = { .stepConfig = { .step = 1 }}
203 }, {
204 .adjustmentFunction = ADJUSTMENT_LEVEL_I,
205 .mode = ADJUSTMENT_MODE_STEP,
206 .data = { .stepConfig = { .step = 1 }}
207 }, {
208 .adjustmentFunction = ADJUSTMENT_LEVEL_D,
209 .mode = ADJUSTMENT_MODE_STEP,
210 .data = { .stepConfig = { .step = 1 }}
211 }, {
212 .adjustmentFunction = ADJUSTMENT_POS_XY_P,
213 .mode = ADJUSTMENT_MODE_STEP,
214 .data = { .stepConfig = { .step = 1 }}
215 }, {
216 .adjustmentFunction = ADJUSTMENT_POS_XY_I,
217 .mode = ADJUSTMENT_MODE_STEP,
218 .data = { .stepConfig = { .step = 1 }}
219 }, {
220 .adjustmentFunction = ADJUSTMENT_POS_XY_D,
221 .mode = ADJUSTMENT_MODE_STEP,
222 .data = { .stepConfig = { .step = 1 }}
223 }, {
224 .adjustmentFunction = ADJUSTMENT_POS_Z_P,
225 .mode = ADJUSTMENT_MODE_STEP,
226 .data = { .stepConfig = { .step = 1 }}
227 }, {
228 .adjustmentFunction = ADJUSTMENT_POS_Z_I,
229 .mode = ADJUSTMENT_MODE_STEP,
230 .data = { .stepConfig = { .step = 1 }}
231 }, {
232 .adjustmentFunction = ADJUSTMENT_POS_Z_D,
233 .mode = ADJUSTMENT_MODE_STEP,
234 .data = { .stepConfig = { .step = 1 }}
235 }, {
236 .adjustmentFunction = ADJUSTMENT_HEADING_P,
237 .mode = ADJUSTMENT_MODE_STEP,
238 .data = { .stepConfig = { .step = 1 }}
239 }, {
240 .adjustmentFunction = ADJUSTMENT_VEL_XY_P,
241 .mode = ADJUSTMENT_MODE_STEP,
242 .data = { .stepConfig = { .step = 1 }}
243 }, {
244 .adjustmentFunction = ADJUSTMENT_VEL_XY_I,
245 .mode = ADJUSTMENT_MODE_STEP,
246 .data = { .stepConfig = { .step = 1 }}
247 }, {
248 .adjustmentFunction = ADJUSTMENT_VEL_XY_D,
249 .mode = ADJUSTMENT_MODE_STEP,
250 .data = { .stepConfig = { .step = 1 }}
251 }, {
252 .adjustmentFunction = ADJUSTMENT_VEL_Z_P,
253 .mode = ADJUSTMENT_MODE_STEP,
254 .data = { .stepConfig = { .step = 1 }}
255 }, {
256 .adjustmentFunction = ADJUSTMENT_VEL_Z_I,
257 .mode = ADJUSTMENT_MODE_STEP,
258 .data = { .stepConfig = { .step = 1 }}
259 }, {
260 .adjustmentFunction = ADJUSTMENT_VEL_Z_D,
261 .mode = ADJUSTMENT_MODE_STEP,
262 .data = { .stepConfig = { .step = 1 }}
263 }, {
264 .adjustmentFunction = ADJUSTMENT_FW_MIN_THROTTLE_DOWN_PITCH_ANGLE,
265 .mode = ADJUSTMENT_MODE_STEP,
266 .data = { .stepConfig = { .step = 5 }}
267 }, {
268 .adjustmentFunction = ADJUSTMENT_VTX_POWER_LEVEL,
269 .mode = ADJUSTMENT_MODE_STEP,
270 .data = { .stepConfig = { .step = 1 }}
271 #ifdef USE_INFLIGHT_PROFILE_ADJUSTMENT
272 }, {
273 .adjustmentFunction = ADJUSTMENT_PROFILE,
274 .mode = ADJUSTMENT_MODE_SELECT,
275 .data = { .selectConfig = { .switchPositions = 3 }}
276 #endif
280 #define ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET 1
282 static adjustmentState_t adjustmentStates[MAX_SIMULTANEOUS_ADJUSTMENT_COUNT];
284 static void configureAdjustment(uint8_t index, uint8_t auxSwitchChannelIndex, const adjustmentConfig_t *adjustmentConfig)
286 adjustmentState_t * const adjustmentState = &adjustmentStates[index];
288 if (adjustmentState->config == adjustmentConfig) {
289 // already configured
290 return;
292 adjustmentState->auxChannelIndex = auxSwitchChannelIndex;
293 adjustmentState->config = adjustmentConfig;
294 adjustmentState->timeoutAt = 0;
296 MARK_ADJUSTMENT_FUNCTION_AS_READY(index);
299 static void blackboxLogInflightAdjustmentEvent(adjustmentFunction_e adjustmentFunction, int32_t newValue)
301 #ifndef USE_BLACKBOX
302 UNUSED(adjustmentFunction);
303 UNUSED(newValue);
304 #else
305 if (feature(FEATURE_BLACKBOX)) {
306 flightLogEvent_inflightAdjustment_t eventData;
307 eventData.adjustmentFunction = adjustmentFunction;
308 eventData.newValue = newValue;
309 eventData.floatFlag = false;
310 blackboxLogEvent(FLIGHT_LOG_EVENT_INFLIGHT_ADJUSTMENT, (flightLogEventData_t*)&eventData);
312 #endif
315 #if 0
316 static void blackboxLogInflightAdjustmentEventFloat(adjustmentFunction_e adjustmentFunction, float newFloatValue)
318 #ifndef USE_BLACKBOX
319 UNUSED(adjustmentFunction);
320 UNUSED(newFloatValue);
321 #else
322 if (feature(FEATURE_BLACKBOX)) {
323 flightLogEvent_inflightAdjustment_t eventData;
324 eventData.adjustmentFunction = adjustmentFunction;
325 eventData.newFloatValue = newFloatValue;
326 eventData.floatFlag = true;
327 blackboxLogEvent(FLIGHT_LOG_EVENT_INFLIGHT_ADJUSTMENT, (flightLogEventData_t*)&eventData);
329 #endif
331 #endif
333 static void applyAdjustmentU8(adjustmentFunction_e adjustmentFunction, uint8_t *val, int delta, int low, int high)
335 int newValue = constrain((int)(*val) + delta, low, high);
336 *val = newValue;
337 blackboxLogInflightAdjustmentEvent(adjustmentFunction, newValue);
340 static void applyAdjustmentU16(adjustmentFunction_e adjustmentFunction, uint16_t *val, int delta, int low, int high)
342 int newValue = constrain((int)(*val) + delta, low, high);
343 *val = newValue;
344 blackboxLogInflightAdjustmentEvent(adjustmentFunction, newValue);
347 static void applyAdjustmentExpo(adjustmentFunction_e adjustmentFunction, uint8_t *val, int delta)
349 applyAdjustmentU8(adjustmentFunction, val, delta, RC_ADJUSTMENT_EXPO_MIN, RC_ADJUSTMENT_EXPO_MAX);
352 static void applyAdjustmentManualRate(adjustmentFunction_e adjustmentFunction, uint8_t *val, int delta)
354 return applyAdjustmentU8(adjustmentFunction, val, delta, RC_ADJUSTMENT_MANUAL_RATE_MIN, RC_ADJUSTMENT_MANUAL_RATE_MAX);
357 static void applyAdjustmentPID(adjustmentFunction_e adjustmentFunction, uint8_t *val, int delta)
359 applyAdjustmentU8(adjustmentFunction, val, delta, RC_ADJUSTMENT_PID_MIN, RC_ADJUSTMENT_PID_MAX);
362 static void applyStepAdjustment(controlRateConfig_t *controlRateConfig, uint8_t adjustmentFunction, int delta)
364 if (delta > 0) {
365 beeperConfirmationBeeps(2);
366 } else {
367 beeperConfirmationBeeps(1);
369 switch (adjustmentFunction) {
370 case ADJUSTMENT_RC_EXPO:
371 applyAdjustmentExpo(ADJUSTMENT_RC_EXPO, &controlRateConfig->stabilized.rcExpo8, delta);
372 break;
373 case ADJUSTMENT_RC_YAW_EXPO:
374 applyAdjustmentExpo(ADJUSTMENT_RC_YAW_EXPO, &controlRateConfig->stabilized.rcYawExpo8, delta);
375 break;
376 case ADJUSTMENT_MANUAL_RC_EXPO:
377 applyAdjustmentExpo(ADJUSTMENT_MANUAL_RC_EXPO, &controlRateConfig->manual.rcExpo8, delta);
378 break;
379 case ADJUSTMENT_MANUAL_RC_YAW_EXPO:
380 applyAdjustmentExpo(ADJUSTMENT_MANUAL_RC_YAW_EXPO, &controlRateConfig->manual.rcYawExpo8, delta);
381 break;
382 case ADJUSTMENT_THROTTLE_EXPO:
383 applyAdjustmentExpo(ADJUSTMENT_THROTTLE_EXPO, &controlRateConfig->throttle.rcExpo8, delta);
384 break;
385 case ADJUSTMENT_PITCH_ROLL_RATE:
386 case ADJUSTMENT_PITCH_RATE:
387 applyAdjustmentU8(ADJUSTMENT_PITCH_RATE, &controlRateConfig->stabilized.rates[FD_PITCH], delta, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX);
388 if (adjustmentFunction == ADJUSTMENT_PITCH_RATE) {
389 schedulePidGainsUpdate();
390 break;
392 // follow though for combined ADJUSTMENT_PITCH_ROLL_RATE
393 FALLTHROUGH;
395 case ADJUSTMENT_ROLL_RATE:
396 applyAdjustmentU8(ADJUSTMENT_ROLL_RATE, &controlRateConfig->stabilized.rates[FD_ROLL], delta, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX);
397 schedulePidGainsUpdate();
398 break;
399 case ADJUSTMENT_MANUAL_PITCH_ROLL_RATE:
400 case ADJUSTMENT_MANUAL_ROLL_RATE:
401 applyAdjustmentManualRate(ADJUSTMENT_MANUAL_ROLL_RATE, &controlRateConfig->manual.rates[FD_ROLL], delta);
402 if (adjustmentFunction == ADJUSTMENT_MANUAL_ROLL_RATE)
403 break;
404 // follow though for combined ADJUSTMENT_MANUAL_PITCH_ROLL_RATE
405 FALLTHROUGH;
406 case ADJUSTMENT_MANUAL_PITCH_RATE:
407 applyAdjustmentManualRate(ADJUSTMENT_MANUAL_PITCH_RATE, &controlRateConfig->manual.rates[FD_PITCH], delta);
408 break;
409 case ADJUSTMENT_YAW_RATE:
410 applyAdjustmentU8(ADJUSTMENT_YAW_RATE, &controlRateConfig->stabilized.rates[FD_YAW], delta, CONTROL_RATE_CONFIG_YAW_RATE_MIN, CONTROL_RATE_CONFIG_YAW_RATE_MAX);
411 schedulePidGainsUpdate();
412 break;
413 case ADJUSTMENT_MANUAL_YAW_RATE:
414 applyAdjustmentManualRate(ADJUSTMENT_MANUAL_YAW_RATE, &controlRateConfig->manual.rates[FD_YAW], delta);
415 break;
416 case ADJUSTMENT_PITCH_ROLL_P:
417 case ADJUSTMENT_PITCH_P:
418 applyAdjustmentPID(ADJUSTMENT_PITCH_P, &pidBankMutable()->pid[PID_PITCH].P, delta);
419 if (adjustmentFunction == ADJUSTMENT_PITCH_P) {
420 schedulePidGainsUpdate();
421 break;
423 // follow though for combined ADJUSTMENT_PITCH_ROLL_P
424 FALLTHROUGH;
426 case ADJUSTMENT_ROLL_P:
427 applyAdjustmentPID(ADJUSTMENT_ROLL_P, &pidBankMutable()->pid[PID_ROLL].P, delta);
428 schedulePidGainsUpdate();
429 break;
430 case ADJUSTMENT_PITCH_ROLL_I:
431 case ADJUSTMENT_PITCH_I:
432 applyAdjustmentPID(ADJUSTMENT_PITCH_I, &pidBankMutable()->pid[PID_PITCH].I, delta);
433 if (adjustmentFunction == ADJUSTMENT_PITCH_I) {
434 schedulePidGainsUpdate();
435 break;
437 // follow though for combined ADJUSTMENT_PITCH_ROLL_I
438 FALLTHROUGH;
440 case ADJUSTMENT_ROLL_I:
441 applyAdjustmentPID(ADJUSTMENT_ROLL_I, &pidBankMutable()->pid[PID_ROLL].I, delta);
442 schedulePidGainsUpdate();
443 break;
444 case ADJUSTMENT_PITCH_ROLL_D:
445 case ADJUSTMENT_PITCH_D:
446 applyAdjustmentPID(ADJUSTMENT_PITCH_D, &pidBankMutable()->pid[PID_PITCH].D, delta);
447 if (adjustmentFunction == ADJUSTMENT_PITCH_D) {
448 schedulePidGainsUpdate();
449 break;
451 // follow though for combined ADJUSTMENT_PITCH_ROLL_D
452 FALLTHROUGH;
454 case ADJUSTMENT_ROLL_D:
455 applyAdjustmentPID(ADJUSTMENT_ROLL_D, &pidBankMutable()->pid[PID_ROLL].D, delta);
456 schedulePidGainsUpdate();
457 break;
458 case ADJUSTMENT_YAW_P:
459 applyAdjustmentPID(ADJUSTMENT_YAW_P, &pidBankMutable()->pid[PID_YAW].P, delta);
460 schedulePidGainsUpdate();
461 break;
462 case ADJUSTMENT_YAW_I:
463 applyAdjustmentPID(ADJUSTMENT_YAW_I, &pidBankMutable()->pid[PID_YAW].I, delta);
464 schedulePidGainsUpdate();
465 break;
466 case ADJUSTMENT_YAW_D:
467 applyAdjustmentPID(ADJUSTMENT_YAW_D, &pidBankMutable()->pid[PID_YAW].D, delta);
468 schedulePidGainsUpdate();
469 break;
470 case ADJUSTMENT_NAV_FW_CRUISE_THR:
471 applyAdjustmentU16(ADJUSTMENT_NAV_FW_CRUISE_THR, &navConfigMutable()->fw.cruise_throttle, delta, 1000, 2000);
472 break;
473 case ADJUSTMENT_NAV_FW_PITCH2THR:
474 applyAdjustmentU8(ADJUSTMENT_NAV_FW_PITCH2THR, &navConfigMutable()->fw.pitch_to_throttle, delta, 0, 100);
475 break;
476 case ADJUSTMENT_ROLL_BOARD_ALIGNMENT:
477 updateBoardAlignment(delta, 0);
478 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_BOARD_ALIGNMENT, boardAlignment()->rollDeciDegrees);
479 break;
480 case ADJUSTMENT_PITCH_BOARD_ALIGNMENT:
481 updateBoardAlignment(0, delta);
482 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_BOARD_ALIGNMENT, boardAlignment()->pitchDeciDegrees);
483 break;
484 case ADJUSTMENT_LEVEL_P:
485 applyAdjustmentPID(ADJUSTMENT_LEVEL_P, &pidBankMutable()->pid[PID_LEVEL].P, delta);
486 // TODO: Need to call something to take it into account?
487 break;
488 case ADJUSTMENT_LEVEL_I:
489 applyAdjustmentPID(ADJUSTMENT_LEVEL_I, &pidBankMutable()->pid[PID_LEVEL].I, delta);
490 // TODO: Need to call something to take it into account?
491 break;
492 case ADJUSTMENT_LEVEL_D:
493 applyAdjustmentPID(ADJUSTMENT_LEVEL_D, &pidBankMutable()->pid[PID_LEVEL].D, delta);
494 // TODO: Need to call something to take it into account?
495 break;
496 case ADJUSTMENT_POS_XY_P:
497 applyAdjustmentPID(ADJUSTMENT_POS_XY_P, &pidBankMutable()->pid[PID_POS_XY].P, delta);
498 navigationUsePIDs();
499 break;
500 case ADJUSTMENT_POS_XY_I:
501 applyAdjustmentPID(ADJUSTMENT_POS_XY_I, &pidBankMutable()->pid[PID_POS_XY].I, delta);
502 navigationUsePIDs();
503 break;
504 case ADJUSTMENT_POS_XY_D:
505 applyAdjustmentPID(ADJUSTMENT_POS_XY_D, &pidBankMutable()->pid[PID_POS_XY].D, delta);
506 navigationUsePIDs();
507 break;
508 case ADJUSTMENT_POS_Z_P:
509 applyAdjustmentPID(ADJUSTMENT_POS_Z_P, &pidBankMutable()->pid[PID_POS_Z].P, delta);
510 navigationUsePIDs();
511 break;
512 case ADJUSTMENT_POS_Z_I:
513 applyAdjustmentPID(ADJUSTMENT_POS_Z_I, &pidBankMutable()->pid[PID_POS_Z].I, delta);
514 navigationUsePIDs();
515 break;
516 case ADJUSTMENT_POS_Z_D:
517 applyAdjustmentPID(ADJUSTMENT_POS_Z_D, &pidBankMutable()->pid[PID_POS_Z].D, delta);
518 navigationUsePIDs();
519 break;
520 case ADJUSTMENT_HEADING_P:
521 applyAdjustmentPID(ADJUSTMENT_HEADING_P, &pidBankMutable()->pid[PID_HEADING].P, delta);
522 // TODO: navigationUsePIDs()?
523 break;
524 case ADJUSTMENT_VEL_XY_P:
525 applyAdjustmentPID(ADJUSTMENT_VEL_XY_P, &pidBankMutable()->pid[PID_VEL_XY].P, delta);
526 navigationUsePIDs();
527 break;
528 case ADJUSTMENT_VEL_XY_I:
529 applyAdjustmentPID(ADJUSTMENT_VEL_XY_I, &pidBankMutable()->pid[PID_VEL_XY].I, delta);
530 navigationUsePIDs();
531 break;
532 case ADJUSTMENT_VEL_XY_D:
533 applyAdjustmentPID(ADJUSTMENT_VEL_XY_D, &pidBankMutable()->pid[PID_VEL_XY].D, delta);
534 navigationUsePIDs();
535 break;
536 case ADJUSTMENT_VEL_Z_P:
537 applyAdjustmentPID(ADJUSTMENT_VEL_Z_P, &pidBankMutable()->pid[PID_VEL_Z].P, delta);
538 navigationUsePIDs();
539 break;
540 case ADJUSTMENT_VEL_Z_I:
541 applyAdjustmentPID(ADJUSTMENT_VEL_Z_I, &pidBankMutable()->pid[PID_VEL_Z].I, delta);
542 navigationUsePIDs();
543 break;
544 case ADJUSTMENT_VEL_Z_D:
545 applyAdjustmentPID(ADJUSTMENT_VEL_Z_D, &pidBankMutable()->pid[PID_VEL_Z].D, delta);
546 navigationUsePIDs();
547 break;
548 case ADJUSTMENT_FW_MIN_THROTTLE_DOWN_PITCH_ANGLE:
549 applyAdjustmentU16(ADJUSTMENT_FW_MIN_THROTTLE_DOWN_PITCH_ANGLE, &mixerConfigMutable()->fwMinThrottleDownPitchAngle, delta, 0, FW_MIN_THROTTLE_DOWN_PITCH_ANGLE_MAX);
550 break;
551 case ADJUSTMENT_VTX_POWER_LEVEL:
553 vtxDeviceCapability_t vtxDeviceCapability;
554 if (vtxCommonGetDeviceCapability(vtxCommonDevice(), &vtxDeviceCapability)) {
555 applyAdjustmentU8(ADJUSTMENT_VTX_POWER_LEVEL, &vtxSettingsConfigMutable()->power, delta, VTX_SETTINGS_MIN_POWER, vtxDeviceCapability.powerCount);
558 break;
559 default:
560 break;
564 #ifdef USE_INFLIGHT_PROFILE_ADJUSTMENT
565 static void applySelectAdjustment(uint8_t adjustmentFunction, uint8_t position)
567 bool applied = false;
569 switch (adjustmentFunction) {
570 case ADJUSTMENT_RATE_PROFILE:
571 if (getCurrentControlRateProfile() != position) {
572 changeControlRateProfile(position);
573 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RATE_PROFILE, position);
574 applied = true;
576 break;
579 if (applied) {
580 beeperConfirmationBeeps(position + 1);
583 #endif
585 #define RESET_FREQUENCY_2HZ (1000 / 2)
587 void processRcAdjustments(controlRateConfig_t *controlRateConfig, bool canUseRxData)
589 const uint32_t now = millis();
591 for (int adjustmentIndex = 0; adjustmentIndex < MAX_SIMULTANEOUS_ADJUSTMENT_COUNT; adjustmentIndex++) {
592 adjustmentState_t * const adjustmentState = &adjustmentStates[adjustmentIndex];
594 if (!adjustmentState->config) {
595 continue;
597 const uint8_t adjustmentFunction = adjustmentState->config->adjustmentFunction;
598 if (adjustmentFunction == ADJUSTMENT_NONE) {
599 continue;
602 const int32_t signedDiff = now - adjustmentState->timeoutAt;
603 const bool canResetReadyStates = signedDiff >= 0L;
605 if (canResetReadyStates) {
606 adjustmentState->timeoutAt = now + RESET_FREQUENCY_2HZ;
607 MARK_ADJUSTMENT_FUNCTION_AS_READY(adjustmentIndex);
610 if (!canUseRxData) {
611 continue;
614 const uint8_t channelIndex = NON_AUX_CHANNEL_COUNT + adjustmentState->auxChannelIndex;
616 if (adjustmentState->config->mode == ADJUSTMENT_MODE_STEP) {
617 int delta;
618 if (rxGetChannelValue(channelIndex) > PWM_RANGE_MIDDLE + 200) {
619 delta = adjustmentState->config->data.stepConfig.step;
620 } else if (rxGetChannelValue(channelIndex) < PWM_RANGE_MIDDLE - 200) {
621 delta = 0 - adjustmentState->config->data.stepConfig.step;
622 } else {
623 // returning the switch to the middle immediately resets the ready state
624 MARK_ADJUSTMENT_FUNCTION_AS_READY(adjustmentIndex);
625 adjustmentState->timeoutAt = now + RESET_FREQUENCY_2HZ;
626 continue;
628 if (IS_ADJUSTMENT_FUNCTION_BUSY(adjustmentIndex)) {
629 continue;
632 // it is legitimate to adjust an otherwise const item here
633 applyStepAdjustment(controlRateConfig, adjustmentFunction, delta);
634 #ifdef USE_INFLIGHT_PROFILE_ADJUSTMENT
635 } else if (adjustmentState->config->mode == ADJUSTMENT_MODE_SELECT) {
636 const uint16_t rangeWidth = ((2100 - 900) / adjustmentState->config->data.selectConfig.switchPositions);
637 const uint8_t position = (constrain(rxGetChannelValue(channelIndex), 900, 2100 - 1) - 900) / rangeWidth;
639 applySelectAdjustment(adjustmentFunction, position);
640 #endif
642 MARK_ADJUSTMENT_FUNCTION_AS_BUSY(adjustmentIndex);
646 void resetAdjustmentStates(void)
648 memset(adjustmentStates, 0, sizeof(adjustmentStates));
651 void updateAdjustmentStates(bool canUseRxData)
653 for (int index = 0; index < MAX_ADJUSTMENT_RANGE_COUNT; index++) {
654 const adjustmentRange_t * const adjustmentRange = adjustmentRanges(index);
655 if (adjustmentRange->adjustmentFunction == ADJUSTMENT_NONE) {
656 // Range not set up
657 continue;
659 const adjustmentConfig_t *adjustmentConfig = &defaultAdjustmentConfigs[adjustmentRange->adjustmentFunction - ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET];
660 adjustmentState_t * const adjustmentState = &adjustmentStates[adjustmentRange->adjustmentIndex];
662 if (canUseRxData && isRangeActive(adjustmentRange->auxChannelIndex, &adjustmentRange->range)) {
663 if (!adjustmentState->config) {
664 configureAdjustment(adjustmentRange->adjustmentIndex, adjustmentRange->auxSwitchChannelIndex, adjustmentConfig);
666 } else {
667 if (adjustmentState->config == adjustmentConfig) {
668 adjustmentState->config = NULL;
674 bool isAdjustmentFunctionSelected(uint8_t adjustmentFunction) {
675 for (uint8_t index = 0; index < MAX_SIMULTANEOUS_ADJUSTMENT_COUNT; ++index) {
676 if (adjustmentStates[index].config && adjustmentStates[index].config->adjustmentFunction == adjustmentFunction) {
677 return true;
680 return false;