Joystick.cc 25.3 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
    , _exponential(false)
59
    , _accumulator(false)
Gregory Dymarek's avatar
Gregory Dymarek committed
60
    , _deadband(false)
61 62
    , _activeVehicle(NULL)
    , _pollingStartedForCalibration(false)
63
    , _multiVehicleManager(multiVehicleManager)
64
{
65

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

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

77
    _loadSettings();
78 79

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

Joystick::~Joystick()
{
84 85 86
    delete _rgAxisValues;
    delete _rgCalibration;
    delete _rgButtonValues;
87 88
}

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

106 107 108 109 110
    // Default TX Mode 2 axis assignments for gamecontrollers
    _rgFunctionAxis[rollFunction]       = 2;
    _rgFunctionAxis[pitchFunction]      = 3;
    _rgFunctionAxis[yawFunction]        = 0;
    _rgFunctionAxis[throttleFunction]   = 1;
111 112 113 114 115 116 117 118 119 120

    _exponential = false;
    _accumulator = false;
    _deadband = false;
    _throttleMode = ThrottleModeCenterZero;
    _calibrated = true;

    _saveSettings();
}

121 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
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);
    }
}

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

152
    settings.beginGroup(_settingsGroup);
153

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

157
    settings.beginGroup(_name);
158

159 160
    bool badSettings = false;
    bool convertOk;
161

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

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

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

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

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

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

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

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

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

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

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

197

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

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

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

207
        _rgFunctionAxis[function] = functionAxis;
208

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

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

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

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

231
    settings.beginGroup(_settingsGroup);
232 233 234

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

238
    settings.beginGroup(_name);
239

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

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

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

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

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

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

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

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

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

289 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
// 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;
    }
}

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

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

342
    if (withDeadbands) {
Gregory Dymarek's avatar
Gregory Dymarek committed
343 344
        if (valueNormalized>calibration.deadband) valueNormalized-=calibration.deadband;
        else if (valueNormalized<-calibration.deadband) valueNormalized+=calibration.deadband;
345 346 347
        else valueNormalized = 0.f;
    }

348
    float axisPercent = valueNormalized / axisLength;
349

350
    float correctedValue = axisBasis * axisPercent;
351

352 353 354
    if (calibration.reversed) {
        correctedValue *= -1.0f;
    }
355

356
#if 0
357
    qCDebug(JoystickLog) << "_adjustRange corrected:value:min:max:center:reversed:deadband:basis:normalized:length"
358 359 360 361 362
                            << correctedValue
                            << value
                            << calibration.min
                            << calibration.max
                            << calibration.center
363
                            << calibration.reversed
364
                            << calibration.deadband
365 366 367 368 369
                            << axisBasis
                            << valueNormalized
                            << axisLength;
#endif

370
    return std::max(-1.0f, std::min(correctedValue, 1.0f));
371 372 373 374 375
}


void Joystick::run(void)
{
Gregory Dymarek's avatar
Gregory Dymarek committed
376
    _open();
377

378
    while (!_exitThread) {
Gregory Dymarek's avatar
Gregory Dymarek committed
379
    _update();
380 381 382

        // Update axes
        for (int axisIndex=0; axisIndex<_axisCount; axisIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
383
            int newAxisValue = _getAxis(axisIndex);
384 385 386 387
            // Calibration code requires signal to be emitted even if value hasn't changed
            _rgAxisValues[axisIndex] = newAxisValue;
            emit rawAxisValueChanged(axisIndex, newAxisValue);
        }
388

389 390
        // Update buttons
        for (int buttonIndex=0; buttonIndex<_buttonCount; buttonIndex++) {
Gregory Dymarek's avatar
Gregory Dymarek committed
391
            bool newButtonValue = _getButton(buttonIndex);
392 393 394 395 396
            if (newButtonValue != _rgButtonValues[buttonIndex]) {
                _rgButtonValues[buttonIndex] = newButtonValue;
                emit rawButtonPressedChanged(buttonIndex, newButtonValue);
            }
        }
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411

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

Don Gagne's avatar
Don Gagne committed
413
        if (_calibrationMode != CalibrationModeCalibrating) {
414
            int     axis = _rgFunctionAxis[rollFunction];
415
            float   roll = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _deadband);
416

417
                    axis = _rgFunctionAxis[pitchFunction];
418
            float   pitch = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _deadband);
419

420
                    axis = _rgFunctionAxis[yawFunction];
421
            float   yaw = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis],_deadband);
422

423
                    axis = _rgFunctionAxis[throttleFunction];
424
            float   throttle = _adjustRange(_rgAxisValues[axis], _rgCalibration[axis], _throttleMode==ThrottleModeDownZero?false:_deadband);
425

426 427 428 429 430 431 432 433 434
            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;
            }

435 436 437 438 439
            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)));

440
            // Map from unit circle to linear range and limit
441 442 443 444
            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));
445
            
446 447 448 449 450 451 452 453 454 455 456
            if ( _exponential ) {
                // Exponential (0% to -50% range like most RC radios)
                // 0 for no exponential
                // -0.5 for strong exponential
                float expo = -0.35f;

                // Calculate new RPY with exponential applied
                roll =      -expo*powf(roll,3) + (1+expo)*roll;
                pitch =     -expo*powf(pitch,3) + (1+expo)*pitch;
                yaw =       -expo*powf(yaw,3) + (1+expo)*yaw;
            }
457

458
            // Adjust throttle to 0:1 range
459
            if (_throttleMode == ThrottleModeCenterZero && _activeVehicle->supportsThrottleModeCenterZero()) {
460
                throttle = std::max(0.0f, throttle);
461
            } else {
462 463
                throttle = (throttle + 1.0f) / 2.0f;
            }
464

465
            // Set up button pressed information
466

467
            // We only send the buttons the firmwware has reserved
468
            int reservedButtonCount = _activeVehicle->manualControlReservedButtonCount();
469
            if (reservedButtonCount == -1) {
470
                reservedButtonCount = _totalButtonCount;
471
            }
472

473 474
            quint16 newButtonBits = 0;      // New set of button which are down
            quint16 buttonPressedBits = 0;  // Buttons pressed for manualControl signal
475

476
            for (int buttonIndex=0; buttonIndex<_totalButtonCount; buttonIndex++) {
477
                quint16 buttonBit = 1 << buttonIndex;
478

479 480
                if (!_rgButtonValues[buttonIndex]) {
                    // Button up, just record it
481 482 483
                    newButtonBits |= buttonBit;
                } else {
                    if (_lastButtonBits & buttonBit) {
484
                        // Button was up last time through, but is now down which indicates a button press
485
                        qCDebug(JoystickLog) << "button triggered" << buttonIndex;
486

487 488
                        if (buttonIndex >= reservedButtonCount) {
                            // Button is above firmware reserved set
Don Gagne's avatar
Don Gagne committed
489 490 491
                            QString buttonAction =_rgButtonActions[buttonIndex];
                            if (!buttonAction.isEmpty()) {
                                _buttonAction(buttonAction);
492 493 494
                            }
                        }
                    }
495 496

                    // Mark the button as pressed as long as its pressed
497
                    buttonPressedBits |= buttonBit;
498 499
                }
            }
500

501
            _lastButtonBits = newButtonBits;
502

503
            qCDebug(JoystickValuesLog) << "name:roll:pitch:yaw:throttle" << name() << roll << -pitch << yaw << throttle;
504

505
            emit manualControl(roll, -pitch, yaw, throttle, buttonPressedBits, _activeVehicle->joystickMode());
506
        }
507

508 509 510
        // Sleep, update rate of joystick is approx. 25 Hz (1000 ms / 25 = 40 ms)
        QGC::SLEEP::msleep(40);
    }
511

Gregory Dymarek's avatar
Gregory Dymarek committed
512
    _close();
513 514
}

515
void Joystick::startPolling(Vehicle* vehicle)
516
{
517 518 519 520 521 522
    if (vehicle) {

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

        // Always set up the new vehicle
526
        _activeVehicle = vehicle;
527

528 529 530 531 532
        // If joystick is not calibrated, disable it
        if ( !_calibrated ) {
            vehicle->setJoystickEnabled(false);
        }

533 534 535 536 537 538 539 540 541 542 543 544 545
        // 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()) {
546 547
        _exitThread = false;
        start();
548 549 550 551 552
    }
}

void Joystick::stopPolling(void)
{
553
    if (isRunning()) {
554 555 556 557 558 559

        if (_activeVehicle && _activeVehicle->joystickEnabled()) {
            UAS* uas = _activeVehicle->uas();

            disconnect(this, &Joystick::manualControl,          uas, &UAS::setExternalControlSetpoint);
        }
Don Gagne's avatar
Don Gagne committed
560 561
        // FIXME: ****
        //disconnect(this, &Joystick::buttonActionTriggered,  uas, &UAS::triggerAction);
562

563 564
        _exitThread = true;
        }
565 566 567 568
}

void Joystick::setCalibration(int axis, Calibration_t& calibration)
{
569
    if (!_validAxis(axis)) {
570 571 572
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }
573

574 575 576 577 578 579 580 581
    _calibrated = true;
    _rgCalibration[axis] = calibration;
    _saveSettings();
    emit calibratedChanged(_calibrated);
}

Joystick::Calibration_t Joystick::getCalibration(int axis)
{
582
    if (!_validAxis(axis)) {
583 584
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
    }
585

586 587 588 589 590
    return _rgCalibration[axis];
}

void Joystick::setFunctionAxis(AxisFunction_t function, int axis)
{
591
    if (!_validAxis(axis)) {
592 593 594 595 596 597
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }

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

599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
    _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
615 616

    list << "Arm" << "Disarm";
617 618 619 620

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

622 623 624
    return list;
}

Don Gagne's avatar
Don Gagne committed
625
void Joystick::setButtonAction(int button, const QString& action)
626
{
627
    if (!_validButton(button)) {
628 629 630
        qCWarning(JoystickLog) << "Invalid button index" << button;
        return;
    }
631

Don Gagne's avatar
Don Gagne committed
632
    qDebug() << "setButtonAction" << action;
633

634 635 636 637 638
    _rgButtonActions[button] = action;
    _saveSettings();
    emit buttonActionsChanged(buttonActions());
}

Don Gagne's avatar
Don Gagne committed
639
QString Joystick::getButtonAction(int button)
640
{
641
    if (!_validButton(button)) {
642 643
        qCWarning(JoystickLog) << "Invalid button index" << button;
    }
644

645 646 647 648 649 650
    return _rgButtonActions[button];
}

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

Don Gagne's avatar
Don Gagne committed
652
    for (int button=0; button<_totalButtonCount; button++) {
653 654
        list += QVariant::fromValue(_rgButtonActions[button]);
    }
655

656 657 658 659 660 661 662 663 664 665 666 667 668 669
    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;
    }
670

671
    _throttleMode = (ThrottleMode_t)mode;
672 673 674 675 676

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

677 678 679 680
    _saveSettings();
    emit throttleModeChanged(_throttleMode);
}

681 682 683 684 685 686 687 688 689 690 691 692 693
bool Joystick::exponential(void)
{
    return _exponential;
}

void Joystick::setExponential(bool expo)
{
    _exponential = expo;

    _saveSettings();
    emit exponentialChanged(_exponential);
}

694 695 696 697 698 699 700 701 702 703 704 705 706
bool Joystick::accumulator(void)
{
    return _accumulator;
}

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

    _saveSettings();
    emit accumulatorChanged(_accumulator);
}

Gregory Dymarek's avatar
Gregory Dymarek committed
707 708 709 710 711 712 713 714 715 716 717 718
bool Joystick::deadband(void)
{
    return _deadband;
}

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

    _saveSettings();
}

Don Gagne's avatar
Don Gagne committed
719
void Joystick::startCalibrationMode(CalibrationMode_t mode)
720
{
Don Gagne's avatar
Don Gagne committed
721 722 723 724
    if (mode == CalibrationModeOff) {
        qWarning() << "Incorrect mode CalibrationModeOff";
        return;
    }
725

Don Gagne's avatar
Don Gagne committed
726
    _calibrationMode = mode;
727

728 729
    if (!isRunning()) {
        _pollingStartedForCalibration = true;
730
        startPolling(_multiVehicleManager->activeVehicle());
731
    }
732 733
}

Don Gagne's avatar
Don Gagne committed
734
void Joystick::stopCalibrationMode(CalibrationMode_t mode)
735
{
Don Gagne's avatar
Don Gagne committed
736 737 738 739
    if (mode == CalibrationModeOff) {
        qWarning() << "Incorrect mode: CalibrationModeOff";
        return;
    }
740

Don Gagne's avatar
Don Gagne committed
741 742 743 744
    if (mode == CalibrationModeCalibrating) {
        _calibrationMode = CalibrationModeMonitor;
    } else {
        _calibrationMode = CalibrationModeOff;
745 746 747
        if (_pollingStartedForCalibration) {
            stopPolling();
        }
748 749
    }
}
750

Don Gagne's avatar
Don Gagne committed
751 752
void Joystick::_buttonAction(const QString& action)
{
753 754 755 756
    if (!_activeVehicle || !_activeVehicle->joystickEnabled()) {
        return;
    }

Don Gagne's avatar
Don Gagne committed
757 758 759 760
    if (action == "Arm") {
        _activeVehicle->setArmed(true);
    } else if (action == "Disarm") {
        _activeVehicle->setArmed(false);
761 762
    } else if (_activeVehicle->flightModes().contains(action)) {
        _activeVehicle->setFlightMode(action);
Don Gagne's avatar
Don Gagne committed
763 764 765 766 767
    } else {
        qCDebug(JoystickLog) << "_buttonAction unknown action:" << action;
    }
}

768 769 770 771 772 773 774
bool Joystick::_validAxis(int axis)
{
    return axis >= 0 && axis < _axisCount;
}

bool Joystick::_validButton(int button)
{
775
    return button >= 0 && button < _totalButtonCount;
776 777
}