Joystick.cc 26.1 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
    _loadSettings();
79 80

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

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

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
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;

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

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

    _saveSettings();
}

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
void Joystick::_activeVehicleChanged(Vehicle *activeVehicle)
{
    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;
        }

        QSettings settings;
        settings.beginGroup(_settingsGroup);
        int mode = settings.value(_txModeSettingsKey, activeVehicle->firmwarePlugin()->defaultJoystickTXMode()).toInt();

        setTXMode(mode);
    }
}

149 150 151
void Joystick::_loadSettings(void)
{
    QSettings   settings;
152

153
    settings.beginGroup(_settingsGroup);
154

155 156
    if(_txModeSettingsKey)
        _transmitterMode = settings.value(_txModeSettingsKey, 2).toInt();
157

158
    settings.beginGroup(_name);
159

160 161
    bool badSettings = false;
    bool convertOk;
162

163
    qCDebug(JoystickLog) << "_loadSettings " << _name;
164

165
    _calibrated = settings.value(_calibratedSettingsKey, false).toBool();
166
    _exponential = settings.value(_exponentialSettingsKey, 0).toFloat();
167
    _accumulator = settings.value(_accumulatorSettingsKey, false).toBool();
Gregory Dymarek's avatar
Gregory Dymarek committed
168
    _deadband = settings.value(_deadbandSettingsKey, false).toBool();
169

170 171
    _throttleMode = (ThrottleMode_t)settings.value(_throttleModeSettingsKey, ThrottleModeCenterZero).toInt(&convertOk);
    badSettings |= !convertOk;
172

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

175 176 177 178
    QString minTpl  ("Axis%1Min");
    QString maxTpl  ("Axis%1Max");
    QString trimTpl ("Axis%1Trim");
    QString revTpl  ("Axis%1Rev");
179
    QString deadbndTpl  ("Axis%1Deadbnd");
180

181
    for (int axis=0; axis<_axisCount; axis++) {
182
        Calibration_t* calibration = &_rgCalibration[axis];
183

184 185
        calibration->center = settings.value(trimTpl.arg(axis), 0).toInt(&convertOk);
        badSettings |= !convertOk;
186

187 188
        calibration->min = settings.value(minTpl.arg(axis), -32768).toInt(&convertOk);
        badSettings |= !convertOk;
189

190
        calibration->max = settings.value(maxTpl.arg(axis), 32767).toInt(&convertOk);
191
        badSettings |= !convertOk;
192

193 194 195
        calibration->deadband = settings.value(deadbndTpl.arg(axis), 0).toInt(&convertOk);
        badSettings |= !convertOk;

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

198

199
        qCDebug(JoystickLog) << "_loadSettings axis:min:max:trim:reversed:deadband:badsettings" << axis << calibration->min << calibration->max << calibration->center << calibration->reversed << calibration->deadband << badSettings;
200
    }
201

202 203
    for (int function=0; function<maxFunction; function++) {
        int functionAxis;
204

205 206
        functionAxis = settings.value(_rgFunctionSettingsKey[function], -1).toInt(&convertOk);
        badSettings |= !convertOk || (functionAxis == -1);
207

208
        _rgFunctionAxis[function] = functionAxis;
209

210 211
        qCDebug(JoystickLog) << "_loadSettings function:axis:badsettings" << function << functionAxis << badSettings;
    }
212

213 214 215 216
    // 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
217
    for (int button=0; button<_totalButtonCount; button++) {
218
        _rgButtonActions << settings.value(QString(_buttonActionSettingsKey).arg(button), QString()).toString();
Don Gagne's avatar
Don Gagne committed
219
        qCDebug(JoystickLog) << "_loadSettings button:action" << button << _rgButtonActions[button];
220
    }
221

222 223 224 225 226 227 228 229 230
    if (badSettings) {
        _calibrated = false;
        settings.setValue(_calibratedSettingsKey, false);
    }
}

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

232
    settings.beginGroup(_settingsGroup);
233 234 235

    // Transmitter mode is static
    // Save the mode we are using
236 237
    if(_txModeSettingsKey)
        settings.setValue(_txModeSettingsKey, _transmitterMode);
238

239
    settings.beginGroup(_name);
240

241
    settings.setValue(_calibratedSettingsKey, _calibrated);
242
    settings.setValue(_exponentialSettingsKey, _exponential);
243
    settings.setValue(_accumulatorSettingsKey, _accumulator);
Gregory Dymarek's avatar
Gregory Dymarek committed
244
    settings.setValue(_deadbandSettingsKey, _deadband);
245
    settings.setValue(_throttleModeSettingsKey, _throttleMode);
246

247
    qCDebug(JoystickLog) << "_saveSettings calibrated:throttlemode:deadband:txmode" << _calibrated << _throttleMode << _deadband << _transmitterMode;
248 249 250 251 252

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

255
    for (int axis=0; axis<_axisCount; axis++) {
256
        Calibration_t* calibration = &_rgCalibration[axis];
257

258 259 260 261
        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);
262
        settings.setValue(deadbndTpl.arg(axis), calibration->deadband);
263

264
        qCDebug(JoystickLog) << "_saveSettings name:axis:min:max:trim:reversed:deadband"
265 266 267 268 269
                                << _name
                                << axis
                                << calibration->min
                                << calibration->max
                                << calibration->center
270 271
                                << calibration->reversed
                                << calibration->deadband;
272
    }
273

274 275 276 277 278
    // 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);

279
    for (int function=0; function<maxFunction; function++) {
280
        settings.setValue(_rgFunctionSettingsKey[function], temp[function]);
281 282
        qCDebug(JoystickLog) << "_saveSettings name:function:axis" << _name << function << _rgFunctionSettingsKey[function];
    }
283

Don Gagne's avatar
Don Gagne committed
284
    for (int button=0; button<_totalButtonCount; button++) {
285 286 287 288 289
        settings.setValue(QString(_buttonActionSettingsKey).arg(button), _rgButtonActions[button]);
        qCDebug(JoystickLog) << "_saveSettings button:action" << button << _rgButtonActions[button];
    }
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
// 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;
    }
}

326
/// Adjust the raw axis value to the -1:1 range given calibration information
327
float Joystick::_adjustRange(int value, Calibration_t calibration, bool withDeadbands)
328 329 330 331
{
    float valueNormalized;
    float axisLength;
    float axisBasis;
332

333 334 335 336 337 338 339 340 341
    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;
    }
342

343 344
    float axisPercent;

345
    if (withDeadbands) {
346 347 348 349 350 351 352
        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;
        }
353 354 355
    }
    else {
        axisPercent = valueNormalized / axisLength;
356
    }
357

358
    float correctedValue = axisBasis * axisPercent;
359

360 361 362
    if (calibration.reversed) {
        correctedValue *= -1.0f;
    }
363

364
#if 0
365
    qCDebug(JoystickLog) << "_adjustRange corrected:value:min:max:center:reversed:deadband:basis:normalized:length"
366 367 368 369 370
                            << correctedValue
                            << value
                            << calibration.min
                            << calibration.max
                            << calibration.center
371
                            << calibration.reversed
372
                            << calibration.deadband
373 374 375 376 377
                            << axisBasis
                            << valueNormalized
                            << axisLength;
#endif

378
    return std::max(-1.0f, std::min(correctedValue, 1.0f));
379 380 381 382 383
}


void Joystick::run(void)
{
Gregory Dymarek's avatar
Gregory Dymarek committed
384
    _open();
385

386
    while (!_exitThread) {
Gregory Dymarek's avatar
Gregory Dymarek committed
387
    _update();
388 389 390

        // Update axes
        for (int axisIndex=0; axisIndex<_axisCount; axisIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
391
            int newAxisValue = _getAxis(axisIndex);
392 393 394 395
            // Calibration code requires signal to be emitted even if value hasn't changed
            _rgAxisValues[axisIndex] = newAxisValue;
            emit rawAxisValueChanged(axisIndex, newAxisValue);
        }
396

397 398
        // Update buttons
        for (int buttonIndex=0; buttonIndex<_buttonCount; buttonIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
399
            bool newButtonValue = _getButton(buttonIndex);
400 401 402 403 404
            if (newButtonValue != _rgButtonValues[buttonIndex]) {
                _rgButtonValues[buttonIndex] = newButtonValue;
                emit rawButtonPressedChanged(buttonIndex, newButtonValue);
            }
        }
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419

        // 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);
                }
            }
        }
420

Jacob Walser's avatar
Jacob Walser committed
421
        if (_calibrationMode != CalibrationModeCalibrating && _calibrated) {
422
            int     axis = _rgFunctionAxis[rollFunction];
423
            float   roll = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _deadband);
424

425
                    axis = _rgFunctionAxis[pitchFunction];
426
            float   pitch = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _deadband);
427

428
                    axis = _rgFunctionAxis[yawFunction];
429
            float   yaw = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis],_deadband);
430

431
                    axis = _rgFunctionAxis[throttleFunction];
432
            float   throttle = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _throttleMode==ThrottleModeDownZero?false:_deadband);
433

434 435 436 437 438 439 440 441 442
            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;
            }

443 444 445 446 447
            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)));

448
            // Map from unit circle to linear range and limit
449 450 451 452
            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));
453
            
454
            if ( _exponential != 0 ) {
455
                // Exponential (0% to -50% range like most RC radios)
nanthony21's avatar
nanthony21 committed
456
                //_exponential is set by a slider in joystickConfig.qml
457 458

                // Calculate new RPY with exponential applied
459 460 461
                roll =      -_exponential*powf(roll,3) + (1+_exponential)*roll;
                pitch =     -_exponential*powf(pitch,3) + (1+_exponential)*pitch;
                yaw =       -_exponential*powf(yaw,3) + (1+_exponential)*yaw;
462
            }
463

464
            // Adjust throttle to 0:1 range
465
            if (_throttleMode == ThrottleModeCenterZero && _activeVehicle->supportsThrottleModeCenterZero()) {
466
                if (!_activeVehicle->supportsNegativeThrust() || !_negativeThrust) {
467 468
                    throttle = std::max(0.0f, throttle);
                }
469
            } else {
470 471
                throttle = (throttle + 1.0f) / 2.0f;
            }
472

473
            // Set up button pressed information
474

475
            // We only send the buttons the firmwware has reserved
476
            int reservedButtonCount = _activeVehicle->manualControlReservedButtonCount();
477
            if (reservedButtonCount == -1) {
478
                reservedButtonCount = _totalButtonCount;
479
            }
480

481 482
            quint16 newButtonBits = 0;      // New set of button which are down
            quint16 buttonPressedBits = 0;  // Buttons pressed for manualControl signal
483

484
            for (int buttonIndex=0; buttonIndex<_totalButtonCount; buttonIndex++) {
485
                quint16 buttonBit = 1 << buttonIndex;
486

487 488
                if (!_rgButtonValues[buttonIndex]) {
                    // Button up, just record it
489 490 491
                    newButtonBits |= buttonBit;
                } else {
                    if (_lastButtonBits & buttonBit) {
492
                        // Button was up last time through, but is now down which indicates a button press
493
                        qCDebug(JoystickLog) << "button triggered" << buttonIndex;
494

495 496
                        if (buttonIndex >= reservedButtonCount) {
                            // Button is above firmware reserved set
Don Gagne's avatar
Don Gagne committed
497 498 499
                            QString buttonAction =_rgButtonActions[buttonIndex];
                            if (!buttonAction.isEmpty()) {
                                _buttonAction(buttonAction);
500 501 502
                            }
                        }
                    }
503 504

                    // Mark the button as pressed as long as its pressed
505
                    buttonPressedBits |= buttonBit;
506 507
                }
            }
508

509
            _lastButtonBits = newButtonBits;
510

511
            qCDebug(JoystickValuesLog) << "name:roll:pitch:yaw:throttle" << name() << roll << -pitch << yaw << throttle;
512

513
            emit manualControl(roll, -pitch, yaw, throttle, buttonPressedBits, _activeVehicle->joystickMode());
514
        }
515

516 517 518
        // Sleep, update rate of joystick is approx. 25 Hz (1000 ms / 25 = 40 ms)
        QGC::SLEEP::msleep(40);
    }
519

Gregory Dymarek's avatar
Gregory Dymarek committed
520
    _close();
521 522
}

523
void Joystick::startPolling(Vehicle* vehicle)
524
{
525 526 527 528 529 530
    if (vehicle) {

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

        // Always set up the new vehicle
534
        _activeVehicle = vehicle;
535

536 537 538 539 540
        // If joystick is not calibrated, disable it
        if ( !_calibrated ) {
            vehicle->setJoystickEnabled(false);
        }

Jacob Walser's avatar
Jacob Walser committed
541 542 543
        // Update qml in case of joystick transition
        emit calibratedChanged(_calibrated);

544 545 546 547 548 549 550 551 552 553 554 555 556
        // 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()) {
557 558
        _exitThread = false;
        start();
559 560 561 562 563
    }
}

void Joystick::stopPolling(void)
{
564
    if (isRunning()) {
565 566 567

        if (_activeVehicle && _activeVehicle->joystickEnabled()) {
            UAS* uas = _activeVehicle->uas();
Jacob Walser's avatar
Jacob Walser committed
568 569
            // Neutral attitude controls
            // emit manualControl(0, 0, 0, 0.5, 0, _activeVehicle->joystickMode());
570 571
            disconnect(this, &Joystick::manualControl,          uas, &UAS::setExternalControlSetpoint);
        }
Don Gagne's avatar
Don Gagne committed
572 573
        // FIXME: ****
        //disconnect(this, &Joystick::buttonActionTriggered,  uas, &UAS::triggerAction);
574

575
        _exitThread = true;
Jacob Walser's avatar
Jacob Walser committed
576
    }
577 578 579 580
}

void Joystick::setCalibration(int axis, Calibration_t& calibration)
{
581
    if (!_validAxis(axis)) {
582 583 584
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }
585

586 587 588 589 590 591 592 593
    _calibrated = true;
    _rgCalibration[axis] = calibration;
    _saveSettings();
    emit calibratedChanged(_calibrated);
}

Joystick::Calibration_t Joystick::getCalibration(int axis)
{
594
    if (!_validAxis(axis)) {
595 596
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
    }
597

598 599 600 601 602
    return _rgCalibration[axis];
}

void Joystick::setFunctionAxis(AxisFunction_t function, int axis)
{
603
    if (!_validAxis(axis)) {
604 605 606 607 608 609
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }

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

611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
    _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
627 628

    list << "Arm" << "Disarm";
629 630 631 632

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

634 635 636
    return list;
}

Don Gagne's avatar
Don Gagne committed
637
void Joystick::setButtonAction(int button, const QString& action)
638
{
639
    if (!_validButton(button)) {
640 641 642
        qCWarning(JoystickLog) << "Invalid button index" << button;
        return;
    }
643

Don Gagne's avatar
Don Gagne committed
644
    qDebug() << "setButtonAction" << action;
645

646 647 648 649 650
    _rgButtonActions[button] = action;
    _saveSettings();
    emit buttonActionsChanged(buttonActions());
}

Don Gagne's avatar
Don Gagne committed
651
QString Joystick::getButtonAction(int button)
652
{
653
    if (!_validButton(button)) {
654 655
        qCWarning(JoystickLog) << "Invalid button index" << button;
    }
656

657 658 659 660 661 662
    return _rgButtonActions[button];
}

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

Don Gagne's avatar
Don Gagne committed
664
    for (int button=0; button<_totalButtonCount; button++) {
665 666
        list += QVariant::fromValue(_rgButtonActions[button]);
    }
667

668 669 670 671 672 673 674 675 676 677 678 679 680 681
    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;
    }
682

683
    _throttleMode = (ThrottleMode_t)mode;
684 685 686 687 688

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

689 690 691 692
    _saveSettings();
    emit throttleModeChanged(_throttleMode);
}

693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
bool Joystick::negativeThrust(void)
{
    return _negativeThrust;
}

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

    _saveSettings();
    emit negativeThrustChanged(_negativeThrust);
}

709
float Joystick::exponential(void)
710 711 712 713
{
    return _exponential;
}

714
void Joystick::setExponential(float expo)
715 716 717 718 719 720 721
{
    _exponential = expo;

    _saveSettings();
    emit exponentialChanged(_exponential);
}

722 723 724 725 726 727 728 729 730 731 732 733 734
bool Joystick::accumulator(void)
{
    return _accumulator;
}

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

    _saveSettings();
    emit accumulatorChanged(_accumulator);
}

Gregory Dymarek's avatar
Gregory Dymarek committed
735 736 737 738 739 740 741 742 743 744 745 746
bool Joystick::deadband(void)
{
    return _deadband;
}

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

    _saveSettings();
}

Don Gagne's avatar
Don Gagne committed
747
void Joystick::startCalibrationMode(CalibrationMode_t mode)
748
{
Don Gagne's avatar
Don Gagne committed
749 750 751 752
    if (mode == CalibrationModeOff) {
        qWarning() << "Incorrect mode CalibrationModeOff";
        return;
    }
753

Don Gagne's avatar
Don Gagne committed
754
    _calibrationMode = mode;
755

756 757
    if (!isRunning()) {
        _pollingStartedForCalibration = true;
758
        startPolling(_multiVehicleManager->activeVehicle());
759
    }
760 761
}

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

Don Gagne's avatar
Don Gagne committed
769 770 771 772
    if (mode == CalibrationModeCalibrating) {
        _calibrationMode = CalibrationModeMonitor;
    } else {
        _calibrationMode = CalibrationModeOff;
773 774 775
        if (_pollingStartedForCalibration) {
            stopPolling();
        }
776 777
    }
}
778

Don Gagne's avatar
Don Gagne committed
779 780
void Joystick::_buttonAction(const QString& action)
{
781 782 783 784
    if (!_activeVehicle || !_activeVehicle->joystickEnabled()) {
        return;
    }

Don Gagne's avatar
Don Gagne committed
785 786 787 788
    if (action == "Arm") {
        _activeVehicle->setArmed(true);
    } else if (action == "Disarm") {
        _activeVehicle->setArmed(false);
789 790
    } else if (_activeVehicle->flightModes().contains(action)) {
        _activeVehicle->setFlightMode(action);
Don Gagne's avatar
Don Gagne committed
791 792 793 794 795
    } else {
        qCDebug(JoystickLog) << "_buttonAction unknown action:" << action;
    }
}

796 797 798 799 800 801 802
bool Joystick::_validAxis(int axis)
{
    return axis >= 0 && axis < _axisCount;
}

bool Joystick::_validButton(int button)
{
803
    return button >= 0 && button < _totalButtonCount;
804 805
}