/**************************************************************************** * * (c) 2009-2020 QGROUNDCONTROL PROJECT * * QGroundControl is licensed according to the terms in the file * COPYING.md in the root of the source code directory. * ****************************************************************************/ /// @file /// @brief Joystick Config Qml Controller /// @author Don Gagne #include "FactPanelController.h" #include "QGCLoggingCategory.h" #include "Joystick.h" Q_DECLARE_LOGGING_CATEGORY(JoystickConfigControllerLog) class RadioConfigest; class JoystickManager; namespace Ui { class JoystickConfigController; } class JoystickConfigController : public FactPanelController { Q_OBJECT //friend class RadioConfigTest; ///< This allows our unit test to access internal information needed. public: JoystickConfigController(void); ~JoystickConfigController(); Q_PROPERTY(QString statusText READ statusText NOTIFY statusTextChanged) Q_PROPERTY(bool rollAxisMapped READ rollAxisMapped NOTIFY rollAxisMappedChanged) Q_PROPERTY(bool pitchAxisMapped READ pitchAxisMapped NOTIFY pitchAxisMappedChanged) Q_PROPERTY(bool yawAxisMapped READ yawAxisMapped NOTIFY yawAxisMappedChanged) Q_PROPERTY(bool throttleAxisMapped READ throttleAxisMapped NOTIFY throttleAxisMappedChanged) Q_PROPERTY(bool hasGimbalPitch READ hasGimbalPitch NOTIFY hasGimbalPitchChanged) Q_PROPERTY(bool hasGimbalYaw READ hasGimbalYaw NOTIFY hasGimbalYawChanged) Q_PROPERTY(bool gimbalPitchAxisMapped READ gimbalPitchAxisMapped NOTIFY gimbalPitchAxisMappedChanged) Q_PROPERTY(bool gimbalYawAxisMapped READ gimbalYawAxisMapped NOTIFY gimbalYawAxisMappedChanged) Q_PROPERTY(int rollAxisReversed READ rollAxisReversed NOTIFY rollAxisReversedChanged) Q_PROPERTY(int pitchAxisReversed READ pitchAxisReversed NOTIFY pitchAxisReversedChanged) Q_PROPERTY(int yawAxisReversed READ yawAxisReversed NOTIFY yawAxisReversedChanged) Q_PROPERTY(int throttleAxisReversed READ throttleAxisReversed NOTIFY throttleAxisReversedChanged) Q_PROPERTY(int gimbalPitchAxisReversed READ gimbalPitchAxisReversed NOTIFY gimbalPitchAxisReversedChanged) Q_PROPERTY(int gimbalYawAxisReversed READ gimbalYawAxisReversed NOTIFY gimbalYawAxisReversedChanged) Q_PROPERTY(bool deadbandToggle READ getDeadbandToggle WRITE setDeadbandToggle NOTIFY deadbandToggled) Q_PROPERTY(int transmitterMode READ transmitterMode WRITE setTransmitterMode NOTIFY transmitterModeChanged) Q_PROPERTY(bool calibrating READ calibrating NOTIFY calibratingChanged) Q_PROPERTY(bool nextEnabled READ nextEnabled NOTIFY nextEnabledChanged) Q_PROPERTY(bool skipEnabled READ skipEnabled NOTIFY skipEnabledChanged) Q_PROPERTY(QList stickPositions READ stickPositions NOTIFY stickPositionsChanged) Q_PROPERTY(QList gimbalPositions READ gimbalPositions NOTIFY gimbalPositionsChanged) Q_INVOKABLE void cancelButtonClicked (); Q_INVOKABLE void skipButtonClicked (); Q_INVOKABLE void nextButtonClicked (); Q_INVOKABLE void start (); Q_INVOKABLE void setDeadbandValue (int axis, int value); QString statusText () { return _statusText; } bool rollAxisMapped () { return _rgFunctionAxisMapping[Joystick::rollFunction] != _axisNoAxis; } bool pitchAxisMapped () { return _rgFunctionAxisMapping[Joystick::pitchFunction] != _axisNoAxis; } bool yawAxisMapped () { return _rgFunctionAxisMapping[Joystick::yawFunction] != _axisNoAxis; } bool throttleAxisMapped () { return _rgFunctionAxisMapping[Joystick::throttleFunction] != _axisNoAxis; } bool gimbalPitchAxisMapped () { return _rgFunctionAxisMapping[Joystick::gimbalPitchFunction] != _axisNoAxis; } bool gimbalYawAxisMapped () { return _rgFunctionAxisMapping[Joystick::gimbalYawFunction] != _axisNoAxis; } bool rollAxisReversed (); bool pitchAxisReversed (); bool yawAxisReversed (); bool throttleAxisReversed (); bool gimbalPitchAxisReversed (); bool gimbalYawAxisReversed (); bool hasGimbalPitch () { return _axisCount > 4; } bool hasGimbalYaw () { return _axisCount > 5; } bool getDeadbandToggle (); void setDeadbandToggle (bool); int axisCount () { return _axisCount; } int transmitterMode () { return _transmitterMode; } void setTransmitterMode (int mode); bool calibrating () { return _currentStep != -1; } bool nextEnabled (); bool skipEnabled (); QList stickPositions () { return _currentStickPositions; } QList gimbalPositions () { return _currentGimbalPositions; } struct stateStickPositions { qreal leftX; qreal leftY; qreal rightX; qreal rightY; }; signals: void axisValueChanged (int axis, int value); void axisDeadbandChanged (int axis, int value); void rollAxisMappedChanged (bool mapped); void pitchAxisMappedChanged (bool mapped); void yawAxisMappedChanged (bool mapped); void throttleAxisMappedChanged (bool mapped); void gimbalPitchAxisMappedChanged (bool mapped); void gimbalYawAxisMappedChanged (bool mapped); void rollAxisReversedChanged (bool reversed); void pitchAxisReversedChanged (bool reversed); void yawAxisReversedChanged (bool reversed); void throttleAxisReversedChanged (bool reversed); void gimbalPitchAxisReversedChanged (bool reversed); void gimbalYawAxisReversedChanged (bool reversed); void deadbandToggled (bool value); void transmitterModeChanged (int mode); void calibratingChanged (); void nextEnabledChanged (); void skipEnabledChanged (); void stickPositionsChanged (); void gimbalPositionsChanged (); void hasGimbalPitchChanged (); void hasGimbalYawChanged (); void statusTextChanged (); // @brief Signalled when in unit test mode and a message box should be displayed by the next button void nextButtonMessageBoxDisplayed (); private slots: void _activeJoystickChanged(Joystick* joystick); void _axisValueChanged(int axis, int value); void _axisDeadbandChanged(int axis, int value); private: /// @brief The states of the calibration state machine. enum calStates { calStateAxisWait, calStateBegin, calStateIdentify, calStateMinMax, calStateCenterThrottle, calStateDetectInversion, calStateTrims, calStateSave }; typedef void (JoystickConfigController::*inputFn)(Joystick::AxisFunction_t function, int axis, int value); typedef void (JoystickConfigController::*buttonFn)(void); struct stateMachineEntry { Joystick::AxisFunction_t function; const char* instructions; stateStickPositions stickPositions; stateStickPositions gimbalPositions; inputFn rcInputFn; buttonFn nextFn; buttonFn skipFn; int channelID; }; /// @brief A set of information associated with a radio axis. struct AxisInfo { Joystick::AxisFunction_t function; ///< Function mapped to this axis, Joystick::maxFunction for none bool reversed; ///< true: axis is reverse, false: not reversed int axisMin; ///< Minimum axis value int axisMax; ///< Maximum axis value int axisTrim; ///< Trim position int deadband; ///< Deadband }; Joystick* _activeJoystick = nullptr; int _transmitterMode = 2; int _currentStep = -1; ///< Current step of state machine const struct stateMachineEntry* _getStateMachineEntry(int step); void _advanceState (); void _setupCurrentState (); bool _validAxis (int axis); void _inputCenterWaitBegin (Joystick::AxisFunction_t function, int axis, int value); void _inputStickDetect (Joystick::AxisFunction_t function, int axis, int value); void _inputStickMin (Joystick::AxisFunction_t function, int axis, int value); void _inputCenterWait (Joystick::AxisFunction_t function, int axis, int value); void _switchDetect (Joystick::AxisFunction_t function, int axis, int value, bool moveToNextStep); void _saveFlapsDown (); void _skipFlaps (); void _saveAllTrims (); bool _stickSettleComplete (int axis, int value); void _validateCalibration (); void _writeCalibration (); void _resetInternalCalibrationValues(); void _setInternalCalibrationValuesFromSettings(); void _startCalibration (); void _stopCalibration (); void _calSaveCurrentValues (); void _setStickPositions (); void _signalAllAttitudeValueChanges(); void _setStatusText (const QString& text); stateStickPositions _sticksCentered; stateStickPositions _sticksThrottleUp; stateStickPositions _sticksThrottleDown; stateStickPositions _sticksYawLeft; stateStickPositions _sticksYawRight; stateStickPositions _sticksRollLeft; stateStickPositions _sticksRollRight; stateStickPositions _sticksPitchUp; stateStickPositions _sticksPitchDown; QList _currentStickPositions; QList _currentGimbalPositions; int _rgFunctionAxisMapping[Joystick::maxFunction]; ///< Maps from joystick function to axis index. _axisMax indicates axis not set for this function. static const int _attitudeControls = 5; int _axisCount = 0; ///< Number of actual joystick axes available static const int _axisNoAxis = -1; ///< Signals no axis set static const int _axisMinimum = 4; ///< Minimum numner of joystick axes required to run PX4 struct AxisInfo* _rgAxisInfo = nullptr; ///< Information associated with each axis int* _axisValueSave = nullptr; ///< Saved values prior to detecting axis movement int* _axisRawValue = nullptr; ///< Current set of raw axis values enum calStates _calState = calStateAxisWait; ///< Current calibration state int _calStateCurrentAxis; ///< Current axis being worked on in calStateIdentify and calStateDetectInversion bool _calStateAxisComplete; ///< Work associated with current axis is complete int _calStateIdentifyOldMapping; ///< Previous mapping for axis being currently identified int _calStateReverseOldMapping; ///< Previous mapping for axis being currently used to detect inversion static const int _calCenterPoint; static const int _calValidMinValue; static const int _calValidMaxValue; static const int _calDefaultMinValue; static const int _calDefaultMaxValue; static const int _calRoughCenterDelta; static const int _calMoveDelta; static const int _calSettleDelta; static const int _calMinDelta; int _stickDetectAxis; int _stickDetectInitialValue; int _stickDetectValue; bool _stickDetectSettleStarted; QElapsedTimer _stickDetectSettleElapsed; static const int _stickDetectSettleMSecs; QString _statusText; JoystickManager* _joystickManager; }; #endif // JoystickConfigController_H