Joystick.cc 26.5 KB
Newer Older
1 2 3 4 5 6 7 8 9
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

10 11 12 13 14 15 16 17 18

#include "Joystick.h"
#include "QGC.h"
#include "AutoPilotPlugin.h"
#include "UAS.h"

#include <QSettings>

QGC_LOGGING_CATEGORY(JoystickLog, "JoystickLog")
19
QGC_LOGGING_CATEGORY(JoystickValuesLog, "JoystickValuesLog")
20

21
const char* Joystick::_settingsGroup =                  "Joysticks";
22
const char* Joystick::_calibratedSettingsKey =          "Calibrated2"; // Increment number to force recalibration
23 24 25 26 27 28 29 30 31 32 33
const char* Joystick::_buttonActionSettingsKey =        "ButtonActionName%1";
const char* Joystick::_throttleModeSettingsKey =        "ThrottleMode";
const char* Joystick::_exponentialSettingsKey =         "Exponential";
const char* Joystick::_accumulatorSettingsKey =         "Accumulator";
const char* Joystick::_deadbandSettingsKey =            "Deadband";
const char* Joystick::_txModeSettingsKey =              NULL;
const char* Joystick::_fixedWingTXModeSettingsKey =     "TXMode_FixedWing";
const char* Joystick::_multiRotorTXModeSettingsKey =    "TXMode_MultiRotor";
const char* Joystick::_roverTXModeSettingsKey =         "TXMode_Rover";
const char* Joystick::_vtolTXModeSettingsKey =          "TXMode_VTOL";
const char* Joystick::_submarineTXModeSettingsKey =     "TXMode_Submarine";
34 35 36 37 38 39 40 41

const char* Joystick::_rgFunctionSettingsKey[Joystick::maxFunction] = {
    "RollAxis",
    "PitchAxis",
    "YawAxis",
    "ThrottleAxis"
};

42 43
int Joystick::_transmitterMode = 2;

44
Joystick::Joystick(const QString& name, int axisCount, int buttonCount, int hatCount, MultiVehicleManager* multiVehicleManager)
Gregory Dymarek's avatar
Gregory Dymarek committed
45
    : _exitThread(false)
46 47 48
    , _name(name)
    , _axisCount(axisCount)
    , _buttonCount(buttonCount)
49 50 51
    , _hatCount(hatCount)
    , _hatButtonCount(4*hatCount)
    , _totalButtonCount(_buttonCount+_hatButtonCount)
Don Gagne's avatar
Don Gagne committed
52
    , _calibrationMode(CalibrationModeOff)
53 54 55
    , _rgAxisValues(NULL)
    , _rgCalibration(NULL)
    , _rgButtonValues(NULL)
56 57
    , _lastButtonBits(0)
    , _throttleMode(ThrottleModeCenterZero)
58
    , _negativeThrust(false)
59
    , _exponential(0)
60
    , _accumulator(false)
Gregory Dymarek's avatar
Gregory Dymarek committed
61
    , _deadband(false)
62 63
    , _activeVehicle(NULL)
    , _pollingStartedForCalibration(false)
64
    , _multiVehicleManager(multiVehicleManager)
65
{
66

67 68
    _rgAxisValues = new int[_axisCount];
    _rgCalibration = new Calibration_t[_axisCount];
69
    _rgButtonValues = new bool[_totalButtonCount];
70 71

    for (int i=0; i<_axisCount; i++) {
72 73
        _rgAxisValues[i] = 0;
    }
74
    for (int i=0; i<_totalButtonCount; i++) {
75 76
        _rgButtonValues[i] = false;
    }
77

78 79
    _updateTXModeSettingsKey(_multiVehicleManager->activeVehicle());

80
    _loadSettings();
81 82

    connect(_multiVehicleManager, &MultiVehicleManager::activeVehicleChanged, this, &Joystick::_activeVehicleChanged);
83 84 85 86
}

Joystick::~Joystick()
{
Jacob Walser's avatar
Jacob Walser committed
87 88 89
    delete[] _rgAxisValues;
    delete[] _rgCalibration;
    delete[] _rgButtonValues;
90 91
}

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
void Joystick::_setDefaultCalibration(void) {
    QSettings   settings;
    settings.beginGroup(_settingsGroup);
    settings.beginGroup(_name);
    _calibrated = settings.value(_calibratedSettingsKey, false).toBool();

    // Only set default calibrations if we do not have a calibration for this gamecontroller
    if(_calibrated) return;

    for(int axis = 0; axis < _axisCount; axis++) {
        Joystick::Calibration_t calibration;
        _rgCalibration[axis] = calibration;
    }

    _rgCalibration[1].reversed = true;
    _rgCalibration[3].reversed = true;

109 110 111 112 113
    // Default TX Mode 2 axis assignments for gamecontrollers
    _rgFunctionAxis[rollFunction]       = 2;
    _rgFunctionAxis[pitchFunction]      = 3;
    _rgFunctionAxis[yawFunction]        = 0;
    _rgFunctionAxis[throttleFunction]   = 1;
114

115
    _exponential = 0;
116 117 118 119 120 121 122 123
    _accumulator = false;
    _deadband = false;
    _throttleMode = ThrottleModeCenterZero;
    _calibrated = true;

    _saveSettings();
}

124
void Joystick::_updateTXModeSettingsKey(Vehicle* activeVehicle)
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
{
    if(activeVehicle) {
        if(activeVehicle->fixedWing()) {
            _txModeSettingsKey = _fixedWingTXModeSettingsKey;
        } else if(activeVehicle->multiRotor()) {
            _txModeSettingsKey = _multiRotorTXModeSettingsKey;
        } else if(activeVehicle->rover()) {
            _txModeSettingsKey = _roverTXModeSettingsKey;
        } else if(activeVehicle->vtol()) {
            _txModeSettingsKey = _vtolTXModeSettingsKey;
        } else if(activeVehicle->sub()) {
            _txModeSettingsKey = _submarineTXModeSettingsKey;
        } else {
            _txModeSettingsKey = NULL;
            qWarning() << "No valid joystick TXmode settings key for selected vehicle";
            return;
        }
142 143 144 145
    } else {
        _txModeSettingsKey = NULL;
    }
}
146

147 148 149 150 151
void Joystick::_activeVehicleChanged(Vehicle* activeVehicle)
{
    _updateTXModeSettingsKey(activeVehicle);

    if(activeVehicle) {
152 153 154 155 156 157 158 159
        QSettings settings;
        settings.beginGroup(_settingsGroup);
        int mode = settings.value(_txModeSettingsKey, activeVehicle->firmwarePlugin()->defaultJoystickTXMode()).toInt();

        setTXMode(mode);
    }
}

160 161 162
void Joystick::_loadSettings(void)
{
    QSettings   settings;
163

164
    settings.beginGroup(_settingsGroup);
165

166 167 168 169
    Vehicle* activeVehicle = _multiVehicleManager->activeVehicle();

    if(_txModeSettingsKey && activeVehicle)
        _transmitterMode = settings.value(_txModeSettingsKey, activeVehicle->firmwarePlugin()->defaultJoystickTXMode()).toInt();
170

171
    settings.beginGroup(_name);
172

173 174
    bool badSettings = false;
    bool convertOk;
175

176
    qCDebug(JoystickLog) << "_loadSettings " << _name;
177

178
    _calibrated = settings.value(_calibratedSettingsKey, false).toBool();
179
    _exponential = settings.value(_exponentialSettingsKey, 0).toFloat();
180
    _accumulator = settings.value(_accumulatorSettingsKey, false).toBool();
Gregory Dymarek's avatar
Gregory Dymarek committed
181
    _deadband = settings.value(_deadbandSettingsKey, false).toBool();
182

183 184
    _throttleMode = (ThrottleMode_t)settings.value(_throttleModeSettingsKey, ThrottleModeCenterZero).toInt(&convertOk);
    badSettings |= !convertOk;
185

186
    qCDebug(JoystickLog) << "_loadSettings calibrated:txmode:throttlemode:exponential:deadband:badsettings" << _calibrated << _transmitterMode << _throttleMode << _exponential << _deadband << badSettings;
187

188 189 190 191
    QString minTpl  ("Axis%1Min");
    QString maxTpl  ("Axis%1Max");
    QString trimTpl ("Axis%1Trim");
    QString revTpl  ("Axis%1Rev");
192
    QString deadbndTpl  ("Axis%1Deadbnd");
193

194
    for (int axis=0; axis<_axisCount; axis++) {
195
        Calibration_t* calibration = &_rgCalibration[axis];
196

197 198
        calibration->center = settings.value(trimTpl.arg(axis), 0).toInt(&convertOk);
        badSettings |= !convertOk;
199

200 201
        calibration->min = settings.value(minTpl.arg(axis), -32768).toInt(&convertOk);
        badSettings |= !convertOk;
202

203
        calibration->max = settings.value(maxTpl.arg(axis), 32767).toInt(&convertOk);
204
        badSettings |= !convertOk;
205

206 207 208
        calibration->deadband = settings.value(deadbndTpl.arg(axis), 0).toInt(&convertOk);
        badSettings |= !convertOk;

209
        calibration->reversed = settings.value(revTpl.arg(axis), false).toBool();
210

211

212
        qCDebug(JoystickLog) << "_loadSettings axis:min:max:trim:reversed:deadband:badsettings" << axis << calibration->min << calibration->max << calibration->center << calibration->reversed << calibration->deadband << badSettings;
213
    }
214

215 216
    for (int function=0; function<maxFunction; function++) {
        int functionAxis;
217

218 219
        functionAxis = settings.value(_rgFunctionSettingsKey[function], -1).toInt(&convertOk);
        badSettings |= !convertOk || (functionAxis == -1);
220

221
        _rgFunctionAxis[function] = functionAxis;
222

223 224
        qCDebug(JoystickLog) << "_loadSettings function:axis:badsettings" << function << functionAxis << badSettings;
    }
225

226 227 228 229
    // FunctionAxis mappings are always stored in TX mode 2
    // Remap to stored TX mode in settings
    _remapAxes(2, _transmitterMode, _rgFunctionAxis);

Don Gagne's avatar
Don Gagne committed
230
    for (int button=0; button<_totalButtonCount; button++) {
231
        _rgButtonActions << settings.value(QString(_buttonActionSettingsKey).arg(button), QString()).toString();
Don Gagne's avatar
Don Gagne committed
232
        qCDebug(JoystickLog) << "_loadSettings button:action" << button << _rgButtonActions[button];
233
    }
234

235 236 237 238 239 240 241 242 243
    if (badSettings) {
        _calibrated = false;
        settings.setValue(_calibratedSettingsKey, false);
    }
}

void Joystick::_saveSettings(void)
{
    QSettings settings;
244

245
    settings.beginGroup(_settingsGroup);
246 247 248

    // Transmitter mode is static
    // Save the mode we are using
249 250
    if(_txModeSettingsKey)
        settings.setValue(_txModeSettingsKey, _transmitterMode);
251

252
    settings.beginGroup(_name);
253

254
    settings.setValue(_calibratedSettingsKey, _calibrated);
255
    settings.setValue(_exponentialSettingsKey, _exponential);
256
    settings.setValue(_accumulatorSettingsKey, _accumulator);
Gregory Dymarek's avatar
Gregory Dymarek committed
257
    settings.setValue(_deadbandSettingsKey, _deadband);
258
    settings.setValue(_throttleModeSettingsKey, _throttleMode);
259

260
    qCDebug(JoystickLog) << "_saveSettings calibrated:throttlemode:deadband:txmode" << _calibrated << _throttleMode << _deadband << _transmitterMode;
261 262 263 264 265

    QString minTpl  ("Axis%1Min");
    QString maxTpl  ("Axis%1Max");
    QString trimTpl ("Axis%1Trim");
    QString revTpl  ("Axis%1Rev");
266
    QString deadbndTpl  ("Axis%1Deadbnd");
267

268
    for (int axis=0; axis<_axisCount; axis++) {
269
        Calibration_t* calibration = &_rgCalibration[axis];
270

271 272 273 274
        settings.setValue(trimTpl.arg(axis), calibration->center);
        settings.setValue(minTpl.arg(axis), calibration->min);
        settings.setValue(maxTpl.arg(axis), calibration->max);
        settings.setValue(revTpl.arg(axis), calibration->reversed);
275
        settings.setValue(deadbndTpl.arg(axis), calibration->deadband);
276

277
        qCDebug(JoystickLog) << "_saveSettings name:axis:min:max:trim:reversed:deadband"
278 279 280 281 282
                                << _name
                                << axis
                                << calibration->min
                                << calibration->max
                                << calibration->center
283 284
                                << calibration->reversed
                                << calibration->deadband;
285
    }
286

287 288 289 290 291
    // Always save function Axis mappings in TX Mode 2
    // Write mode 2 mappings without changing mapping currently in use
    int temp[maxFunction];
    _remapAxes(_transmitterMode, 2, temp);

292
    for (int function=0; function<maxFunction; function++) {
293
        settings.setValue(_rgFunctionSettingsKey[function], temp[function]);
294 295
        qCDebug(JoystickLog) << "_saveSettings name:function:axis" << _name << function << _rgFunctionSettingsKey[function];
    }
296

Don Gagne's avatar
Don Gagne committed
297
    for (int button=0; button<_totalButtonCount; button++) {
298 299 300 301 302
        settings.setValue(QString(_buttonActionSettingsKey).arg(button), _rgButtonActions[button]);
        qCDebug(JoystickLog) << "_saveSettings button:action" << button << _rgButtonActions[button];
    }
}

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
// Relative mappings of axis functions between different TX modes
int Joystick::_mapFunctionMode(int mode, int function) {

    static const int mapping[][4] = {
        { 2, 1, 0, 3 },
        { 2, 3, 0, 1 },
        { 0, 1, 2, 3 },
        { 0, 3, 2, 1 }};

    return mapping[mode-1][function];
}

// Remap current axis functions from current TX mode to new TX mode
void Joystick::_remapAxes(int currentMode, int newMode, int (&newMapping)[maxFunction]) {
    int temp[maxFunction];

    for(int function = 0; function < maxFunction; function++) {
        temp[_mapFunctionMode(newMode, function)] = _rgFunctionAxis[_mapFunctionMode(currentMode, function)];
    }

    for(int function = 0; function < maxFunction; function++) {
        newMapping[function] = temp[function];
    }

}

void Joystick::setTXMode(int mode) {
    if(mode > 0 && mode <= 4) {
        _remapAxes(_transmitterMode, mode, _rgFunctionAxis);
        _transmitterMode = mode;
        _saveSettings();
    } else {
        qCWarning(JoystickLog) << "Invalid mode:" << mode;
    }
}

339
/// Adjust the raw axis value to the -1:1 range given calibration information
340
float Joystick::_adjustRange(int value, Calibration_t calibration, bool withDeadbands)
341 342 343 344
{
    float valueNormalized;
    float axisLength;
    float axisBasis;
345

346 347 348 349 350 351 352 353 354
    if (value > calibration.center) {
        axisBasis = 1.0f;
        valueNormalized = value - calibration.center;
        axisLength =  calibration.max - calibration.center;
    } else {
        axisBasis = -1.0f;
        valueNormalized = calibration.center - value;
        axisLength =  calibration.center - calibration.min;
    }
355

356 357
    float axisPercent;

358
    if (withDeadbands) {
359 360 361 362 363 364 365
        if (valueNormalized>calibration.deadband) {
            axisPercent = (valueNormalized - calibration.deadband) / (axisLength - calibration.deadband);
        } else if (valueNormalized<-calibration.deadband) {
            axisPercent = (valueNormalized + calibration.deadband) / (axisLength - calibration.deadband);
        } else {
            axisPercent = 0.f;
        }
366 367 368
    }
    else {
        axisPercent = valueNormalized / axisLength;
369
    }
370

371
    float correctedValue = axisBasis * axisPercent;
372

373 374 375
    if (calibration.reversed) {
        correctedValue *= -1.0f;
    }
376

377
#if 0
378
    qCDebug(JoystickLog) << "_adjustRange corrected:value:min:max:center:reversed:deadband:basis:normalized:length"
379 380 381 382 383
                            << correctedValue
                            << value
                            << calibration.min
                            << calibration.max
                            << calibration.center
384
                            << calibration.reversed
385
                            << calibration.deadband
386 387 388 389 390
                            << axisBasis
                            << valueNormalized
                            << axisLength;
#endif

391
    return std::max(-1.0f, std::min(correctedValue, 1.0f));
392 393 394 395 396
}


void Joystick::run(void)
{
Gregory Dymarek's avatar
Gregory Dymarek committed
397
    _open();
398

399
    while (!_exitThread) {
Gregory Dymarek's avatar
Gregory Dymarek committed
400
    _update();
401 402 403

        // Update axes
        for (int axisIndex=0; axisIndex<_axisCount; axisIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
404
            int newAxisValue = _getAxis(axisIndex);
405 406 407 408
            // Calibration code requires signal to be emitted even if value hasn't changed
            _rgAxisValues[axisIndex] = newAxisValue;
            emit rawAxisValueChanged(axisIndex, newAxisValue);
        }
409

410 411
        // Update buttons
        for (int buttonIndex=0; buttonIndex<_buttonCount; buttonIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
412
            bool newButtonValue = _getButton(buttonIndex);
413 414 415 416 417
            if (newButtonValue != _rgButtonValues[buttonIndex]) {
                _rgButtonValues[buttonIndex] = newButtonValue;
                emit rawButtonPressedChanged(buttonIndex, newButtonValue);
            }
        }
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432

        // Update hat - append hat buttons to the end of the normal button list
        int numHatButtons = 4;
        for (int hatIndex=0; hatIndex<_hatCount; hatIndex++) {
            for (int hatButtonIndex=0; hatButtonIndex<numHatButtons; hatButtonIndex++) {
                // Create new index value that includes the normal button list
                int rgButtonValueIndex = hatIndex*numHatButtons + hatButtonIndex + _buttonCount;
                // Get hat value from joystick
                bool newButtonValue = _getHat(hatIndex,hatButtonIndex);
                if (newButtonValue != _rgButtonValues[rgButtonValueIndex]) {
                    _rgButtonValues[rgButtonValueIndex] = newButtonValue;
                    emit rawButtonPressedChanged(rgButtonValueIndex, newButtonValue);
                }
            }
        }
433

Jacob Walser's avatar
Jacob Walser committed
434
        if (_calibrationMode != CalibrationModeCalibrating && _calibrated) {
435
            int     axis = _rgFunctionAxis[rollFunction];
436
            float   roll = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _deadband);
437

438
                    axis = _rgFunctionAxis[pitchFunction];
439
            float   pitch = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _deadband);
440

441
                    axis = _rgFunctionAxis[yawFunction];
442
            float   yaw = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis],_deadband);
443

444
                    axis = _rgFunctionAxis[throttleFunction];
445
            float   throttle = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _throttleMode==ThrottleModeDownZero?false:_deadband);
446

447 448 449 450 451 452 453 454 455
            if ( _accumulator ) {
                static float throttle_accu = 0.f;

                throttle_accu += throttle*(40/1000.f); //for throttle to change from min to max it will take 1000ms (40ms is a loop time)

                throttle_accu = std::max(static_cast<float>(-1.f), std::min(throttle_accu, static_cast<float>(1.f)));
                throttle = throttle_accu;
            }

456 457 458 459 460
            float roll_limited = std::max(static_cast<float>(-M_PI_4), std::min(roll, static_cast<float>(M_PI_4)));
            float pitch_limited = std::max(static_cast<float>(-M_PI_4), std::min(pitch, static_cast<float>(M_PI_4)));
            float yaw_limited = std::max(static_cast<float>(-M_PI_4), std::min(yaw, static_cast<float>(M_PI_4)));
            float throttle_limited = std::max(static_cast<float>(-M_PI_4), std::min(throttle, static_cast<float>(M_PI_4)));

461
            // Map from unit circle to linear range and limit
462 463 464 465
            roll =      std::max(-1.0f, std::min(tanf(asinf(roll_limited)), 1.0f));
            pitch =     std::max(-1.0f, std::min(tanf(asinf(pitch_limited)), 1.0f));
            yaw =       std::max(-1.0f, std::min(tanf(asinf(yaw_limited)), 1.0f));
            throttle =  std::max(-1.0f, std::min(tanf(asinf(throttle_limited)), 1.0f));
466
            
467
            if ( _exponential != 0 ) {
468
                // Exponential (0% to -50% range like most RC radios)
nanthony21's avatar
nanthony21 committed
469
                //_exponential is set by a slider in joystickConfig.qml
470 471

                // Calculate new RPY with exponential applied
472 473 474
                roll =      -_exponential*powf(roll,3) + (1+_exponential)*roll;
                pitch =     -_exponential*powf(pitch,3) + (1+_exponential)*pitch;
                yaw =       -_exponential*powf(yaw,3) + (1+_exponential)*yaw;
475
            }
476

477
            // Adjust throttle to 0:1 range
478
            if (_throttleMode == ThrottleModeCenterZero && _activeVehicle->supportsThrottleModeCenterZero()) {
479
                if (!_activeVehicle->supportsNegativeThrust() || !_negativeThrust) {
480 481
                    throttle = std::max(0.0f, throttle);
                }
482
            } else {
483 484
                throttle = (throttle + 1.0f) / 2.0f;
            }
485

486
            // Set up button pressed information
487

488
            // We only send the buttons the firmwware has reserved
489
            int reservedButtonCount = _activeVehicle->manualControlReservedButtonCount();
490
            if (reservedButtonCount == -1) {
491
                reservedButtonCount = _totalButtonCount;
492
            }
493

494 495
            quint16 newButtonBits = 0;      // New set of button which are down
            quint16 buttonPressedBits = 0;  // Buttons pressed for manualControl signal
496

497
            for (int buttonIndex=0; buttonIndex<_totalButtonCount; buttonIndex++) {
498
                quint16 buttonBit = 1 << buttonIndex;
499

500 501
                if (!_rgButtonValues[buttonIndex]) {
                    // Button up, just record it
502 503 504
                    newButtonBits |= buttonBit;
                } else {
                    if (_lastButtonBits & buttonBit) {
505
                        // Button was up last time through, but is now down which indicates a button press
506
                        qCDebug(JoystickLog) << "button triggered" << buttonIndex;
507

508 509
                        if (buttonIndex >= reservedButtonCount) {
                            // Button is above firmware reserved set
Don Gagne's avatar
Don Gagne committed
510 511 512
                            QString buttonAction =_rgButtonActions[buttonIndex];
                            if (!buttonAction.isEmpty()) {
                                _buttonAction(buttonAction);
513 514 515
                            }
                        }
                    }
516 517

                    // Mark the button as pressed as long as its pressed
518
                    buttonPressedBits |= buttonBit;
519 520
                }
            }
521

522
            _lastButtonBits = newButtonBits;
523

524
            qCDebug(JoystickValuesLog) << "name:roll:pitch:yaw:throttle" << name() << roll << -pitch << yaw << throttle;
525

526
            emit manualControl(roll, -pitch, yaw, throttle, buttonPressedBits, _activeVehicle->joystickMode());
527
        }
528

529 530 531
        // Sleep, update rate of joystick is approx. 25 Hz (1000 ms / 25 = 40 ms)
        QGC::SLEEP::msleep(40);
    }
532

Gregory Dymarek's avatar
Gregory Dymarek committed
533
    _close();
534 535
}

536
void Joystick::startPolling(Vehicle* vehicle)
537
{
538 539 540 541 542 543
    if (vehicle) {

        // If a vehicle is connected, disconnect it
        if (_activeVehicle) {
            UAS* uas = _activeVehicle->uas();
            disconnect(this, &Joystick::manualControl, uas, &UAS::setExternalControlSetpoint);
544
        }
545 546

        // Always set up the new vehicle
547
        _activeVehicle = vehicle;
548

549 550 551 552 553
        // If joystick is not calibrated, disable it
        if ( !_calibrated ) {
            vehicle->setJoystickEnabled(false);
        }

Jacob Walser's avatar
Jacob Walser committed
554 555 556
        // Update qml in case of joystick transition
        emit calibratedChanged(_calibrated);

557 558 559 560 561 562 563 564 565 566 567 568 569
        // Only connect the new vehicle if it wants joystick data
        if (vehicle->joystickEnabled()) {
            _pollingStartedForCalibration = false;

            UAS* uas = _activeVehicle->uas();
            connect(this, &Joystick::manualControl, uas, &UAS::setExternalControlSetpoint);
            // FIXME: ****
            //connect(this, &Joystick::buttonActionTriggered, uas, &UAS::triggerAction);
        }
    }


    if (!isRunning()) {
570 571
        _exitThread = false;
        start();
572 573 574 575 576
    }
}

void Joystick::stopPolling(void)
{
577
    if (isRunning()) {
578 579 580

        if (_activeVehicle && _activeVehicle->joystickEnabled()) {
            UAS* uas = _activeVehicle->uas();
Jacob Walser's avatar
Jacob Walser committed
581 582
            // Neutral attitude controls
            // emit manualControl(0, 0, 0, 0.5, 0, _activeVehicle->joystickMode());
583 584
            disconnect(this, &Joystick::manualControl,          uas, &UAS::setExternalControlSetpoint);
        }
Don Gagne's avatar
Don Gagne committed
585 586
        // FIXME: ****
        //disconnect(this, &Joystick::buttonActionTriggered,  uas, &UAS::triggerAction);
587

588
        _exitThread = true;
Jacob Walser's avatar
Jacob Walser committed
589
    }
590 591 592 593
}

void Joystick::setCalibration(int axis, Calibration_t& calibration)
{
594
    if (!_validAxis(axis)) {
595 596 597
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }
598

599 600 601 602 603 604 605 606
    _calibrated = true;
    _rgCalibration[axis] = calibration;
    _saveSettings();
    emit calibratedChanged(_calibrated);
}

Joystick::Calibration_t Joystick::getCalibration(int axis)
{
607
    if (!_validAxis(axis)) {
608 609
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
    }
610

611 612 613 614 615
    return _rgCalibration[axis];
}

void Joystick::setFunctionAxis(AxisFunction_t function, int axis)
{
616
    if (!_validAxis(axis)) {
617 618 619 620 621 622
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }

    _calibrated = true;
    _rgFunctionAxis[function] = axis;
623

624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
    _saveSettings();
    emit calibratedChanged(_calibrated);
}

int Joystick::getFunctionAxis(AxisFunction_t function)
{
    if (function < 0 || function >= maxFunction) {
        qCWarning(JoystickLog) << "Invalid function" << function;
    }

    return _rgFunctionAxis[function];
}

QStringList Joystick::actions(void)
{
    QStringList list;
Don Gagne's avatar
Don Gagne committed
640 641

    list << "Arm" << "Disarm";
642 643 644 645

    if (_activeVehicle) {
        list << _activeVehicle->flightModes();
    }
646

647 648 649
    return list;
}

Don Gagne's avatar
Don Gagne committed
650
void Joystick::setButtonAction(int button, const QString& action)
651
{
652
    if (!_validButton(button)) {
653 654 655
        qCWarning(JoystickLog) << "Invalid button index" << button;
        return;
    }
656

Don Gagne's avatar
Don Gagne committed
657
    qDebug() << "setButtonAction" << action;
658

659 660 661 662 663
    _rgButtonActions[button] = action;
    _saveSettings();
    emit buttonActionsChanged(buttonActions());
}

Don Gagne's avatar
Don Gagne committed
664
QString Joystick::getButtonAction(int button)
665
{
666
    if (!_validButton(button)) {
667 668
        qCWarning(JoystickLog) << "Invalid button index" << button;
    }
669

670 671 672 673 674 675
    return _rgButtonActions[button];
}

QVariantList Joystick::buttonActions(void)
{
    QVariantList list;
676

Don Gagne's avatar
Don Gagne committed
677
    for (int button=0; button<_totalButtonCount; button++) {
678 679
        list += QVariant::fromValue(_rgButtonActions[button]);
    }
680

681 682 683 684 685 686 687 688 689 690 691 692 693 694
    return list;
}

int Joystick::throttleMode(void)
{
    return _throttleMode;
}

void Joystick::setThrottleMode(int mode)
{
    if (mode < 0 || mode >= ThrottleModeMax) {
        qCWarning(JoystickLog) << "Invalid throttle mode" << mode;
        return;
    }
695

696
    _throttleMode = (ThrottleMode_t)mode;
697 698 699 700 701

    if (_throttleMode == ThrottleModeDownZero) {
        setAccumulator(false);
    }

702 703 704 705
    _saveSettings();
    emit throttleModeChanged(_throttleMode);
}

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
bool Joystick::negativeThrust(void)
{
    return _negativeThrust;
}

void Joystick::setNegativeThrust(bool allowNegative)
{
    if (_negativeThrust == allowNegative) {
        return;
    }
    _negativeThrust = allowNegative;

    _saveSettings();
    emit negativeThrustChanged(_negativeThrust);
}

722
float Joystick::exponential(void)
723 724 725 726
{
    return _exponential;
}

727
void Joystick::setExponential(float expo)
728 729 730 731 732 733 734
{
    _exponential = expo;

    _saveSettings();
    emit exponentialChanged(_exponential);
}

735 736 737 738 739 740 741 742 743 744 745 746 747
bool Joystick::accumulator(void)
{
    return _accumulator;
}

void Joystick::setAccumulator(bool accu)
{
    _accumulator = accu;

    _saveSettings();
    emit accumulatorChanged(_accumulator);
}

Gregory Dymarek's avatar
Gregory Dymarek committed
748 749 750 751 752 753 754 755 756 757 758 759
bool Joystick::deadband(void)
{
    return _deadband;
}

void Joystick::setDeadband(bool deadband)
{
    _deadband = deadband;

    _saveSettings();
}

Don Gagne's avatar
Don Gagne committed
760
void Joystick::startCalibrationMode(CalibrationMode_t mode)
761
{
Don Gagne's avatar
Don Gagne committed
762 763 764 765
    if (mode == CalibrationModeOff) {
        qWarning() << "Incorrect mode CalibrationModeOff";
        return;
    }
766

Don Gagne's avatar
Don Gagne committed
767
    _calibrationMode = mode;
768

769 770
    if (!isRunning()) {
        _pollingStartedForCalibration = true;
771
        startPolling(_multiVehicleManager->activeVehicle());
772
    }
773 774
}

Don Gagne's avatar
Don Gagne committed
775
void Joystick::stopCalibrationMode(CalibrationMode_t mode)
776
{
Don Gagne's avatar
Don Gagne committed
777 778 779 780
    if (mode == CalibrationModeOff) {
        qWarning() << "Incorrect mode: CalibrationModeOff";
        return;
    }
781

Don Gagne's avatar
Don Gagne committed
782 783 784 785
    if (mode == CalibrationModeCalibrating) {
        _calibrationMode = CalibrationModeMonitor;
    } else {
        _calibrationMode = CalibrationModeOff;
786 787 788
        if (_pollingStartedForCalibration) {
            stopPolling();
        }
789 790
    }
}
791

Don Gagne's avatar
Don Gagne committed
792 793
void Joystick::_buttonAction(const QString& action)
{
794 795 796 797
    if (!_activeVehicle || !_activeVehicle->joystickEnabled()) {
        return;
    }

Don Gagne's avatar
Don Gagne committed
798 799 800 801
    if (action == "Arm") {
        _activeVehicle->setArmed(true);
    } else if (action == "Disarm") {
        _activeVehicle->setArmed(false);
802 803
    } else if (_activeVehicle->flightModes().contains(action)) {
        _activeVehicle->setFlightMode(action);
Don Gagne's avatar
Don Gagne committed
804 805 806 807 808
    } else {
        qCDebug(JoystickLog) << "_buttonAction unknown action:" << action;
    }
}

809 810 811 812 813 814 815
bool Joystick::_validAxis(int axis)
{
    return axis >= 0 && axis < _axisCount;
}

bool Joystick::_validButton(int button)
{
816
    return button >= 0 && button < _totalButtonCount;
817 818
}