Joystick.cc 25.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
    , _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()
{
Jacob Walser's avatar
Jacob Walser committed
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

Jacob Walser's avatar
Jacob Walser committed
413
        if (_calibrationMode != CalibrationModeCalibrating && _calibrated) {
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);
        }

Jacob Walser's avatar
Jacob Walser committed
533 534 535
        // Update qml in case of joystick transition
        emit calibratedChanged(_calibrated);

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

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

        if (_activeVehicle && _activeVehicle->joystickEnabled()) {
            UAS* uas = _activeVehicle->uas();
Jacob Walser's avatar
Jacob Walser committed
560 561
            // Neutral attitude controls
            // emit manualControl(0, 0, 0, 0.5, 0, _activeVehicle->joystickMode());
562 563
            disconnect(this, &Joystick::manualControl,          uas, &UAS::setExternalControlSetpoint);
        }
Don Gagne's avatar
Don Gagne committed
564 565
        // FIXME: ****
        //disconnect(this, &Joystick::buttonActionTriggered,  uas, &UAS::triggerAction);
566

567
        _exitThread = true;
Jacob Walser's avatar
Jacob Walser committed
568
    }
569 570 571 572
}

void Joystick::setCalibration(int axis, Calibration_t& calibration)
{
573
    if (!_validAxis(axis)) {
574 575 576
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }
577

578 579 580 581 582 583 584 585
    _calibrated = true;
    _rgCalibration[axis] = calibration;
    _saveSettings();
    emit calibratedChanged(_calibrated);
}

Joystick::Calibration_t Joystick::getCalibration(int axis)
{
586
    if (!_validAxis(axis)) {
587 588
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
    }
589

590 591 592 593 594
    return _rgCalibration[axis];
}

void Joystick::setFunctionAxis(AxisFunction_t function, int axis)
{
595
    if (!_validAxis(axis)) {
596 597 598 599 600 601
        qCWarning(JoystickLog) << "Invalid axis index" << axis;
        return;
    }

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

603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
    _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
619 620

    list << "Arm" << "Disarm";
621 622 623 624

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

626 627 628
    return list;
}

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

Don Gagne's avatar
Don Gagne committed
636
    qDebug() << "setButtonAction" << action;
637

638 639 640 641 642
    _rgButtonActions[button] = action;
    _saveSettings();
    emit buttonActionsChanged(buttonActions());
}

Don Gagne's avatar
Don Gagne committed
643
QString Joystick::getButtonAction(int button)
644
{
645
    if (!_validButton(button)) {
646 647
        qCWarning(JoystickLog) << "Invalid button index" << button;
    }
648

649 650 651 652 653 654
    return _rgButtonActions[button];
}

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

Don Gagne's avatar
Don Gagne committed
656
    for (int button=0; button<_totalButtonCount; button++) {
657 658
        list += QVariant::fromValue(_rgButtonActions[button]);
    }
659

660 661 662 663 664 665 666 667 668 669 670 671 672 673
    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;
    }
674

675
    _throttleMode = (ThrottleMode_t)mode;
676 677 678 679 680

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

681 682 683 684
    _saveSettings();
    emit throttleModeChanged(_throttleMode);
}

685 686 687 688 689 690 691 692 693 694 695 696 697
bool Joystick::exponential(void)
{
    return _exponential;
}

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

    _saveSettings();
    emit exponentialChanged(_exponential);
}

698 699 700 701 702 703 704 705 706 707 708 709 710
bool Joystick::accumulator(void)
{
    return _accumulator;
}

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

    _saveSettings();
    emit accumulatorChanged(_accumulator);
}

Gregory Dymarek's avatar
Gregory Dymarek committed
711 712 713 714 715 716 717 718 719 720 721 722
bool Joystick::deadband(void)
{
    return _deadband;
}

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

    _saveSettings();
}

Don Gagne's avatar
Don Gagne committed
723
void Joystick::startCalibrationMode(CalibrationMode_t mode)
724
{
Don Gagne's avatar
Don Gagne committed
725 726 727 728
    if (mode == CalibrationModeOff) {
        qWarning() << "Incorrect mode CalibrationModeOff";
        return;
    }
729

Don Gagne's avatar
Don Gagne committed
730
    _calibrationMode = mode;
731

732 733
    if (!isRunning()) {
        _pollingStartedForCalibration = true;
734
        startPolling(_multiVehicleManager->activeVehicle());
735
    }
736 737
}

Don Gagne's avatar
Don Gagne committed
738
void Joystick::stopCalibrationMode(CalibrationMode_t mode)
739
{
Don Gagne's avatar
Don Gagne committed
740 741 742 743
    if (mode == CalibrationModeOff) {
        qWarning() << "Incorrect mode: CalibrationModeOff";
        return;
    }
744

Don Gagne's avatar
Don Gagne committed
745 746 747 748
    if (mode == CalibrationModeCalibrating) {
        _calibrationMode = CalibrationModeMonitor;
    } else {
        _calibrationMode = CalibrationModeOff;
749 750 751
        if (_pollingStartedForCalibration) {
            stopPolling();
        }
752 753
    }
}
754

Don Gagne's avatar
Don Gagne committed
755 756
void Joystick::_buttonAction(const QString& action)
{
757 758 759 760
    if (!_activeVehicle || !_activeVehicle->joystickEnabled()) {
        return;
    }

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

772 773 774 775 776 777 778
bool Joystick::_validAxis(int axis)
{
    return axis >= 0 && axis < _axisCount;
}

bool Joystick::_validButton(int button)
{
779
    return button >= 0 && button < _totalButtonCount;
780 781
}