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/>.
26 #include "build_config.h"
28 #include "common/axis.h"
29 #include "common/maths.h"
31 #include "config/config.h"
32 #include "config/runtime_config.h"
34 #include "drivers/system.h"
35 #include "drivers/sensor.h"
36 #include "drivers/accgyro.h"
37 #include "drivers/gyro_sync.h"
39 #include "sensors/barometer.h"
40 #include "sensors/battery.h"
41 #include "sensors/sensors.h"
42 #include "sensors/gyro.h"
43 #include "sensors/acceleration.h"
48 #include "io/beeper.h"
49 #include "io/escservo.h"
50 #include "io/rc_controls.h"
51 #include "io/rc_curves.h"
54 #include "io/display.h"
56 #include "flight/pid.h"
57 #include "flight/navigation.h"
58 #include "flight/failsafe.h"
60 #include "blackbox/blackbox.h"
64 static escAndServoConfig_t
*escAndServoConfig
;
65 static pidProfile_t
*pidProfile
;
67 // true if arming is done via the sticks (as opposed to a switch)
68 static bool isUsingSticksToArm
= true;
70 int16_t rcCommand
[4]; // interval [1000;2000] for THROTTLE and [-500;+500] for ROLL/PITCH/YAW
72 uint32_t rcModeActivationMask
; // one bit per mode defined in boxId_e
74 bool isAirmodeActive(void) {
75 return (IS_RC_MODE_ACTIVE(BOXAIRMODE
) || feature(FEATURE_AIRMODE
));
78 bool isSuperExpoActive(void) {
79 return (feature(FEATURE_SUPEREXPO
));
82 void blackboxLogInflightAdjustmentEvent(adjustmentFunction_e adjustmentFunction
, int32_t newValue
) {
84 UNUSED(adjustmentFunction
);
87 if (feature(FEATURE_BLACKBOX
)) {
88 flightLogEvent_inflightAdjustment_t eventData
;
89 eventData
.adjustmentFunction
= adjustmentFunction
;
90 eventData
.newValue
= newValue
;
91 eventData
.floatFlag
= false;
92 blackboxLogEvent(FLIGHT_LOG_EVENT_INFLIGHT_ADJUSTMENT
, (flightLogEventData_t
*)&eventData
);
97 void blackboxLogInflightAdjustmentEventFloat(adjustmentFunction_e adjustmentFunction
, float newFloatValue
) {
99 UNUSED(adjustmentFunction
);
100 UNUSED(newFloatValue
);
102 if (feature(FEATURE_BLACKBOX
)) {
103 flightLogEvent_inflightAdjustment_t eventData
;
104 eventData
.adjustmentFunction
= adjustmentFunction
;
105 eventData
.newFloatValue
= newFloatValue
;
106 eventData
.floatFlag
= true;
107 blackboxLogEvent(FLIGHT_LOG_EVENT_INFLIGHT_ADJUSTMENT
, (flightLogEventData_t
*)&eventData
);
112 bool isUsingSticksForArming(void)
114 return isUsingSticksToArm
;
117 bool areSticksInApModePosition(uint16_t ap_mode
)
119 return ABS(rcCommand
[ROLL
]) < ap_mode
&& ABS(rcCommand
[PITCH
]) < ap_mode
;
122 throttleStatus_e
calculateThrottleStatus(rxConfig_t
*rxConfig
, uint16_t deadband3d_throttle
)
124 if (feature(FEATURE_3D
) && !IS_RC_MODE_ACTIVE(BOX3DDISABLESWITCH
)) {
125 if ((rcData
[THROTTLE
] > (rxConfig
->midrc
- deadband3d_throttle
) && rcData
[THROTTLE
] < (rxConfig
->midrc
+ deadband3d_throttle
)))
128 if (rcData
[THROTTLE
] < rxConfig
->mincheck
)
132 return THROTTLE_HIGH
;
135 void processRcStickPositions(rxConfig_t
*rxConfig
, throttleStatus_e throttleStatus
, bool disarm_kill_switch
)
137 static uint8_t rcDelayCommand
; // this indicates the number of time (multiple of RC measurement at 50Hz) the sticks must be maintained to run or switch off motors
138 static uint8_t rcSticks
; // this hold sticks position for command combos
139 static uint8_t rcDisarmTicks
; // this is an extra guard for disarming through switch to prevent that one frame can disarm it
143 // ------------------ STICKS COMMAND HANDLER --------------------
144 // checking sticks positions
145 for (i
= 0; i
< 4; i
++) {
147 if (rcData
[i
] > rxConfig
->mincheck
)
148 stTmp
|= 0x80; // check for MIN
149 if (rcData
[i
] < rxConfig
->maxcheck
)
150 stTmp
|= 0x40; // check for MAX
152 if (stTmp
== rcSticks
) {
153 if (rcDelayCommand
< 250)
160 if (!isUsingSticksToArm
) {
162 if (IS_RC_MODE_ACTIVE(BOXARM
)) {
164 // Arming via ARM BOX
165 if (throttleStatus
== THROTTLE_LOW
) {
166 if (ARMING_FLAG(OK_TO_ARM
)) {
171 // Disarming via ARM BOX
173 if (ARMING_FLAG(ARMED
) && rxIsReceivingSignal() && !failsafeIsActive() ) {
175 if (rcDisarmTicks
> 3) {
176 if (disarm_kill_switch
) {
178 } else if (throttleStatus
== THROTTLE_LOW
) {
186 if (rcDelayCommand
!= 20) {
190 if (isUsingSticksToArm
) {
191 // Disarm on throttle down + yaw
192 if (rcSticks
== THR_LO
+ YAW_LO
+ PIT_CE
+ ROL_CE
) {
193 if (ARMING_FLAG(ARMED
))
196 beeper(BEEPER_DISARM_REPEAT
); // sound tone while stick held
197 rcDelayCommand
= 0; // reset so disarm tone will repeat
202 if (ARMING_FLAG(ARMED
)) {
203 // actions during armed
207 // actions during not armed
210 if (rcSticks
== THR_LO
+ YAW_LO
+ PIT_LO
+ ROL_CE
) {
212 gyroSetCalibrationCycles(calculateCalibratingCycles());
215 if (feature(FEATURE_GPS
)) {
216 GPS_reset_home_position();
221 if (sensors(SENSOR_BARO
))
222 baroSetCalibrationCycles(10); // calibrate baro to new ground level (10 * 25 ms = ~250 ms non blocking)
228 if (feature(FEATURE_INFLIGHT_ACC_CAL
) && (rcSticks
== THR_LO
+ YAW_LO
+ PIT_HI
+ ROL_HI
)) {
229 // Inflight ACC Calibration
230 handleInflightCalibrationStickPosition();
234 // Multiple configuration profiles
235 if (rcSticks
== THR_LO
+ YAW_LO
+ PIT_CE
+ ROL_LO
) // ROLL left -> Profile 1
237 else if (rcSticks
== THR_LO
+ YAW_LO
+ PIT_HI
+ ROL_CE
) // PITCH up -> Profile 2
239 else if (rcSticks
== THR_LO
+ YAW_LO
+ PIT_CE
+ ROL_HI
) // ROLL right -> Profile 3
242 changeProfile(i
- 1);
246 if (rcSticks
== THR_LO
+ YAW_LO
+ PIT_LO
+ ROL_HI
) {
247 saveConfigAndNotify();
250 if (isUsingSticksToArm
) {
252 if (rcSticks
== THR_LO
+ YAW_HI
+ PIT_CE
+ ROL_CE
) {
259 if (rcSticks
== THR_HI
+ YAW_LO
+ PIT_LO
+ ROL_CE
) {
261 accSetCalibrationCycles(CALIBRATING_ACC_CYCLES
);
266 if (rcSticks
== THR_HI
+ YAW_HI
+ PIT_LO
+ ROL_CE
) {
268 ENABLE_STATE(CALIBRATE_MAG
);
273 // Accelerometer Trim
275 rollAndPitchTrims_t accelerometerTrimsDelta
;
276 memset(&accelerometerTrimsDelta
, 0, sizeof(accelerometerTrimsDelta
));
278 bool shouldApplyRollAndPitchTrimDelta
= false;
279 if (rcSticks
== THR_HI
+ YAW_CE
+ PIT_HI
+ ROL_CE
) {
280 accelerometerTrimsDelta
.values
.pitch
= 2;
281 shouldApplyRollAndPitchTrimDelta
= true;
282 } else if (rcSticks
== THR_HI
+ YAW_CE
+ PIT_LO
+ ROL_CE
) {
283 accelerometerTrimsDelta
.values
.pitch
= -2;
284 shouldApplyRollAndPitchTrimDelta
= true;
285 } else if (rcSticks
== THR_HI
+ YAW_CE
+ PIT_CE
+ ROL_HI
) {
286 accelerometerTrimsDelta
.values
.roll
= 2;
287 shouldApplyRollAndPitchTrimDelta
= true;
288 } else if (rcSticks
== THR_HI
+ YAW_CE
+ PIT_CE
+ ROL_LO
) {
289 accelerometerTrimsDelta
.values
.roll
= -2;
290 shouldApplyRollAndPitchTrimDelta
= true;
292 if (shouldApplyRollAndPitchTrimDelta
) {
293 applyAndSaveAccelerometerTrimsDelta(&accelerometerTrimsDelta
);
294 rcDelayCommand
= 0; // allow autorepetition
299 if (rcSticks
== THR_LO
+ YAW_CE
+ PIT_HI
+ ROL_LO
) {
300 displayDisablePageCycling();
303 if (rcSticks
== THR_LO
+ YAW_CE
+ PIT_HI
+ ROL_HI
) {
304 displayEnablePageCycling();
309 if (rcSticks
== THR_HI
+ YAW_LO
+ PIT_CE
+ ROL_HI
) {
312 if (rcSticks
== THR_HI
+ YAW_LO
+ PIT_CE
+ ROL_LO
) {
315 if (rcSticks
== THR_HI
+ YAW_HI
+ PIT_CE
+ ROL_HI
) {
316 vtxIncrementChannel();
318 if (rcSticks
== THR_HI
+ YAW_HI
+ PIT_CE
+ ROL_LO
) {
319 vtxDecrementChannel();
325 bool isModeActivationConditionPresent(modeActivationCondition_t
*modeActivationConditions
, boxId_e modeId
)
329 for (index
= 0; index
< MAX_MODE_ACTIVATION_CONDITION_COUNT
; index
++) {
330 modeActivationCondition_t
*modeActivationCondition
= &modeActivationConditions
[index
];
332 if (modeActivationCondition
->modeId
== modeId
&& IS_RANGE_USABLE(&modeActivationCondition
->range
)) {
340 bool isRangeActive(uint8_t auxChannelIndex
, channelRange_t
*range
) {
341 if (!IS_RANGE_USABLE(range
)) {
345 uint16_t channelValue
= constrain(rcData
[auxChannelIndex
+ NON_AUX_CHANNEL_COUNT
], CHANNEL_RANGE_MIN
, CHANNEL_RANGE_MAX
- 1);
346 return (channelValue
>= 900 + (range
->startStep
* 25) &&
347 channelValue
< 900 + (range
->endStep
* 25));
350 void updateActivatedModes(modeActivationCondition_t
*modeActivationConditions
)
352 rcModeActivationMask
= 0;
356 for (index
= 0; index
< MAX_MODE_ACTIVATION_CONDITION_COUNT
; index
++) {
357 modeActivationCondition_t
*modeActivationCondition
= &modeActivationConditions
[index
];
359 if (isRangeActive(modeActivationCondition
->auxChannelIndex
, &modeActivationCondition
->range
)) {
360 ACTIVATE_RC_MODE(modeActivationCondition
->modeId
);
365 uint8_t adjustmentStateMask
= 0;
367 #define MARK_ADJUSTMENT_FUNCTION_AS_BUSY(adjustmentIndex) adjustmentStateMask |= (1 << adjustmentIndex)
368 #define MARK_ADJUSTMENT_FUNCTION_AS_READY(adjustmentIndex) adjustmentStateMask &= ~(1 << adjustmentIndex)
370 #define IS_ADJUSTMENT_FUNCTION_BUSY(adjustmentIndex) (adjustmentStateMask & (1 << adjustmentIndex))
372 // sync with adjustmentFunction_e
373 static const adjustmentConfig_t defaultAdjustmentConfigs
[ADJUSTMENT_FUNCTION_COUNT
- 1] = {
375 .adjustmentFunction
= ADJUSTMENT_RC_RATE
,
376 .mode
= ADJUSTMENT_MODE_STEP
,
377 .data
= { .stepConfig
= { .step
= 1 }}
380 .adjustmentFunction
= ADJUSTMENT_RC_EXPO
,
381 .mode
= ADJUSTMENT_MODE_STEP
,
382 .data
= { .stepConfig
= { .step
= 1 }}
385 .adjustmentFunction
= ADJUSTMENT_THROTTLE_EXPO
,
386 .mode
= ADJUSTMENT_MODE_STEP
,
387 .data
= { .stepConfig
= { .step
= 1 }}
390 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_RATE
,
391 .mode
= ADJUSTMENT_MODE_STEP
,
392 .data
= { .stepConfig
= { .step
= 1 }}
395 .adjustmentFunction
= ADJUSTMENT_YAW_RATE
,
396 .mode
= ADJUSTMENT_MODE_STEP
,
397 .data
= { .stepConfig
= { .step
= 1 }}
400 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_P
,
401 .mode
= ADJUSTMENT_MODE_STEP
,
402 .data
= { .stepConfig
= { .step
= 1 }}
405 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_I
,
406 .mode
= ADJUSTMENT_MODE_STEP
,
407 .data
= { .stepConfig
= { .step
= 1 }}
410 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_D
,
411 .mode
= ADJUSTMENT_MODE_STEP
,
412 .data
= { .stepConfig
= { .step
= 1 }}
415 .adjustmentFunction
= ADJUSTMENT_YAW_P
,
416 .mode
= ADJUSTMENT_MODE_STEP
,
417 .data
= { .stepConfig
= { .step
= 1 }}
420 .adjustmentFunction
= ADJUSTMENT_YAW_I
,
421 .mode
= ADJUSTMENT_MODE_STEP
,
422 .data
= { .stepConfig
= { .step
= 1 }}
425 .adjustmentFunction
= ADJUSTMENT_YAW_D
,
426 .mode
= ADJUSTMENT_MODE_STEP
,
427 .data
= { .stepConfig
= { .step
= 1 }}
430 .adjustmentFunction
= ADJUSTMENT_RATE_PROFILE
,
431 .mode
= ADJUSTMENT_MODE_SELECT
,
432 .data
= { .selectConfig
= { .switchPositions
= 3 }}
435 .adjustmentFunction
= ADJUSTMENT_PITCH_RATE
,
436 .mode
= ADJUSTMENT_MODE_STEP
,
437 .data
= { .stepConfig
= { .step
= 1 }}
440 .adjustmentFunction
= ADJUSTMENT_ROLL_RATE
,
441 .mode
= ADJUSTMENT_MODE_STEP
,
442 .data
= { .stepConfig
= { .step
= 1 }}
445 .adjustmentFunction
= ADJUSTMENT_PITCH_P
,
446 .mode
= ADJUSTMENT_MODE_STEP
,
447 .data
= { .stepConfig
= { .step
= 1 }}
450 .adjustmentFunction
= ADJUSTMENT_PITCH_I
,
451 .mode
= ADJUSTMENT_MODE_STEP
,
452 .data
= { .stepConfig
= { .step
= 1 }}
455 .adjustmentFunction
= ADJUSTMENT_PITCH_D
,
456 .mode
= ADJUSTMENT_MODE_STEP
,
457 .data
= { .stepConfig
= { .step
= 1 }}
460 .adjustmentFunction
= ADJUSTMENT_ROLL_P
,
461 .mode
= ADJUSTMENT_MODE_STEP
,
462 .data
= { .stepConfig
= { .step
= 1 }}
465 .adjustmentFunction
= ADJUSTMENT_ROLL_I
,
466 .mode
= ADJUSTMENT_MODE_STEP
,
467 .data
= { .stepConfig
= { .step
= 1 }}
470 .adjustmentFunction
= ADJUSTMENT_ROLL_D
,
471 .mode
= ADJUSTMENT_MODE_STEP
,
472 .data
= { .stepConfig
= { .step
= 1 }}
476 #define ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET 1
478 adjustmentState_t adjustmentStates
[MAX_SIMULTANEOUS_ADJUSTMENT_COUNT
];
480 void configureAdjustment(uint8_t index
, uint8_t auxSwitchChannelIndex
, const adjustmentConfig_t
*adjustmentConfig
) {
481 adjustmentState_t
*adjustmentState
= &adjustmentStates
[index
];
483 if (adjustmentState
->config
== adjustmentConfig
) {
484 // already configured
487 adjustmentState
->auxChannelIndex
= auxSwitchChannelIndex
;
488 adjustmentState
->config
= adjustmentConfig
;
489 adjustmentState
->timeoutAt
= 0;
491 MARK_ADJUSTMENT_FUNCTION_AS_READY(index
);
494 void applyStepAdjustment(controlRateConfig_t
*controlRateConfig
, uint8_t adjustmentFunction
, int delta
) {
498 beeperConfirmationBeeps(2);
500 beeperConfirmationBeeps(1);
502 switch(adjustmentFunction
) {
503 case ADJUSTMENT_RC_RATE
:
504 newValue
= constrain((int)controlRateConfig
->rcRate8
+ delta
, 0, 250); // FIXME magic numbers repeated in serial_cli.c
505 controlRateConfig
->rcRate8
= newValue
;
506 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RC_RATE
, newValue
);
508 case ADJUSTMENT_RC_EXPO
:
509 newValue
= constrain((int)controlRateConfig
->rcExpo8
+ delta
, 0, 100); // FIXME magic numbers repeated in serial_cli.c
510 controlRateConfig
->rcExpo8
= newValue
;
511 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RC_EXPO
, newValue
);
513 case ADJUSTMENT_THROTTLE_EXPO
:
514 newValue
= constrain((int)controlRateConfig
->thrExpo8
+ delta
, 0, 100); // FIXME magic numbers repeated in serial_cli.c
515 controlRateConfig
->thrExpo8
= newValue
;
516 generateThrottleCurve(controlRateConfig
, escAndServoConfig
);
517 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_THROTTLE_EXPO
, newValue
);
519 case ADJUSTMENT_PITCH_ROLL_RATE
:
520 case ADJUSTMENT_PITCH_RATE
:
521 newValue
= constrain((int)controlRateConfig
->rates
[FD_PITCH
] + delta
, 0, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX
);
522 controlRateConfig
->rates
[FD_PITCH
] = newValue
;
523 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RATE
, newValue
);
524 if (adjustmentFunction
== ADJUSTMENT_PITCH_RATE
) {
527 // follow though for combined ADJUSTMENT_PITCH_ROLL_RATE
528 case ADJUSTMENT_ROLL_RATE
:
529 newValue
= constrain((int)controlRateConfig
->rates
[FD_ROLL
] + delta
, 0, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX
);
530 controlRateConfig
->rates
[FD_ROLL
] = newValue
;
531 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RATE
, newValue
);
533 case ADJUSTMENT_YAW_RATE
:
534 newValue
= constrain((int)controlRateConfig
->rates
[FD_YAW
] + delta
, 0, CONTROL_RATE_CONFIG_YAW_RATE_MAX
);
535 controlRateConfig
->rates
[FD_YAW
] = newValue
;
536 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_RATE
, newValue
);
538 case ADJUSTMENT_PITCH_ROLL_P
:
539 case ADJUSTMENT_PITCH_P
:
540 newValue
= constrain((int)pidProfile
->P8
[PIDPITCH
] + delta
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
541 pidProfile
->P8
[PIDPITCH
] = newValue
;
542 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_P
, newValue
);
544 if (adjustmentFunction
== ADJUSTMENT_PITCH_P
) {
547 // follow though for combined ADJUSTMENT_PITCH_ROLL_P
548 case ADJUSTMENT_ROLL_P
:
549 newValue
= constrain((int)pidProfile
->P8
[PIDROLL
] + delta
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
550 pidProfile
->P8
[PIDROLL
] = newValue
;
551 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_P
, newValue
);
553 case ADJUSTMENT_PITCH_ROLL_I
:
554 case ADJUSTMENT_PITCH_I
:
555 newValue
= constrain((int)pidProfile
->I8
[PIDPITCH
] + delta
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
556 pidProfile
->I8
[PIDPITCH
] = newValue
;
557 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_I
, newValue
);
559 if (adjustmentFunction
== ADJUSTMENT_PITCH_I
) {
562 // follow though for combined ADJUSTMENT_PITCH_ROLL_I
563 case ADJUSTMENT_ROLL_I
:
564 newValue
= constrain((int)pidProfile
->I8
[PIDROLL
] + delta
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
565 pidProfile
->I8
[PIDROLL
] = newValue
;
566 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_I
, newValue
);
568 case ADJUSTMENT_PITCH_ROLL_D
:
569 case ADJUSTMENT_PITCH_D
:
570 newValue
= constrain((int)pidProfile
->D8
[PIDPITCH
] + delta
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
571 pidProfile
->D8
[PIDPITCH
] = newValue
;
572 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_D
, newValue
);
574 if (adjustmentFunction
== ADJUSTMENT_PITCH_D
) {
577 // follow though for combined ADJUSTMENT_PITCH_ROLL_D
578 case ADJUSTMENT_ROLL_D
:
579 newValue
= constrain((int)pidProfile
->D8
[PIDROLL
] + delta
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
580 pidProfile
->D8
[PIDROLL
] = newValue
;
581 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_D
, newValue
);
583 case ADJUSTMENT_YAW_P
:
584 newValue
= constrain((int)pidProfile
->P8
[PIDYAW
] + delta
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
585 pidProfile
->P8
[PIDYAW
] = newValue
;
586 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_P
, newValue
);
588 case ADJUSTMENT_YAW_I
:
589 newValue
= constrain((int)pidProfile
->I8
[PIDYAW
] + delta
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
590 pidProfile
->I8
[PIDYAW
] = newValue
;
591 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_I
, newValue
);
593 case ADJUSTMENT_YAW_D
:
594 newValue
= constrain((int)pidProfile
->D8
[PIDYAW
] + delta
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
595 pidProfile
->D8
[PIDYAW
] = newValue
;
596 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_D
, newValue
);
603 void applySelectAdjustment(uint8_t adjustmentFunction
, uint8_t position
)
605 bool applied
= false;
607 switch(adjustmentFunction
) {
608 case ADJUSTMENT_RATE_PROFILE
:
609 if (getCurrentControlRateProfile() != position
) {
610 changeControlRateProfile(position
);
611 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RATE_PROFILE
, position
);
618 beeperConfirmationBeeps(position
+ 1);
622 #define RESET_FREQUENCY_2HZ (1000 / 2)
624 void processRcAdjustments(controlRateConfig_t
*controlRateConfig
, rxConfig_t
*rxConfig
)
626 uint8_t adjustmentIndex
;
627 uint32_t now
= millis();
629 bool canUseRxData
= rxIsReceivingSignal();
632 for (adjustmentIndex
= 0; adjustmentIndex
< MAX_SIMULTANEOUS_ADJUSTMENT_COUNT
; adjustmentIndex
++) {
633 adjustmentState_t
*adjustmentState
= &adjustmentStates
[adjustmentIndex
];
635 if (!adjustmentState
->config
) {
638 uint8_t adjustmentFunction
= adjustmentState
->config
->adjustmentFunction
;
639 if (adjustmentFunction
== ADJUSTMENT_NONE
) {
643 int32_t signedDiff
= now
- adjustmentState
->timeoutAt
;
644 bool canResetReadyStates
= signedDiff
>= 0L;
646 if (canResetReadyStates
) {
647 adjustmentState
->timeoutAt
= now
+ RESET_FREQUENCY_2HZ
;
648 MARK_ADJUSTMENT_FUNCTION_AS_READY(adjustmentIndex
);
655 uint8_t channelIndex
= NON_AUX_CHANNEL_COUNT
+ adjustmentState
->auxChannelIndex
;
657 if (adjustmentState
->config
->mode
== ADJUSTMENT_MODE_STEP
) {
659 if (rcData
[channelIndex
] > rxConfig
->midrc
+ 200) {
660 delta
= adjustmentState
->config
->data
.stepConfig
.step
;
661 } else if (rcData
[channelIndex
] < rxConfig
->midrc
- 200) {
662 delta
= 0 - adjustmentState
->config
->data
.stepConfig
.step
;
664 // returning the switch to the middle immediately resets the ready state
665 MARK_ADJUSTMENT_FUNCTION_AS_READY(adjustmentIndex
);
666 adjustmentState
->timeoutAt
= now
+ RESET_FREQUENCY_2HZ
;
669 if (IS_ADJUSTMENT_FUNCTION_BUSY(adjustmentIndex
)) {
673 applyStepAdjustment(controlRateConfig
, adjustmentFunction
, delta
);
674 } else if (adjustmentState
->config
->mode
== ADJUSTMENT_MODE_SELECT
) {
675 uint16_t rangeWidth
= ((2100 - 900) / adjustmentState
->config
->data
.selectConfig
.switchPositions
);
676 uint8_t position
= (constrain(rcData
[channelIndex
], 900, 2100 - 1) - 900) / rangeWidth
;
678 applySelectAdjustment(adjustmentFunction
, position
);
680 MARK_ADJUSTMENT_FUNCTION_AS_BUSY(adjustmentIndex
);
684 void updateAdjustmentStates(adjustmentRange_t
*adjustmentRanges
)
688 for (index
= 0; index
< MAX_ADJUSTMENT_RANGE_COUNT
; index
++) {
689 adjustmentRange_t
*adjustmentRange
= &adjustmentRanges
[index
];
691 if (isRangeActive(adjustmentRange
->auxChannelIndex
, &adjustmentRange
->range
)) {
693 const adjustmentConfig_t
*adjustmentConfig
= &defaultAdjustmentConfigs
[adjustmentRange
->adjustmentFunction
- ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET
];
695 configureAdjustment(adjustmentRange
->adjustmentIndex
, adjustmentRange
->auxSwitchChannelIndex
, adjustmentConfig
);
700 int32_t getRcStickDeflection(int32_t axis
, uint16_t midrc
) {
701 return MIN(ABS(rcData
[axis
] - midrc
), 500);
704 void useRcControlsConfig(modeActivationCondition_t
*modeActivationConditions
, escAndServoConfig_t
*escAndServoConfigToUse
, pidProfile_t
*pidProfileToUse
)
706 escAndServoConfig
= escAndServoConfigToUse
;
707 pidProfile
= pidProfileToUse
;
709 isUsingSticksToArm
= !isModeActivationConditionPresent(modeActivationConditions
, BOXARM
);
712 void resetAdjustmentStates(void)
714 memset(adjustmentStates
, 0, sizeof(adjustmentStates
));