RadioConfigTest.cc 30.7 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

Don Gagne's avatar
Don Gagne committed
11
#include "RadioConfigTest.h"
12
#include "RadioComponentController.h"
13
#include "MultiVehicleManager.h"
14
#include "QGCApplication.h"
15 16 17
#include "PX4/PX4AutoPilotPlugin.h"
#include "APM/APMAutoPilotPlugin.h"
#include "APM/APMRadioComponent.h"
18
#include "PX4RadioComponent.h"
19 20

/// @file
21
///     @brief QRadioComponentController Widget unit test
22 23 24
///
///     @author Don Gagne <don@thegagnes.com>

25
QGC_LOGGING_CATEGORY(RadioConfigTestLog, "RadioConfigTestLog")
Don Gagne's avatar
Don Gagne committed
26

27 28 29 30
// This will check for the wizard buttons being enabled of disabled according to the mask you pass in.
// We use a macro instead of a method so that we get better line number reporting on failure.
#define CHK_BUTTONS(mask) \
{ \
31
    if (_controller->_nextButton->isEnabled() != !!((mask) & nextButtonMask) || \
32 33 34
    _controller->_skipButton->isEnabled() != !!((mask) & skipButtonMask) || \
    _controller->_cancelButton->isEnabled() != !!((mask) & cancelButtonMask) ) { \
    qCDebug(RadioConfigTestLog) << _controller->_statusText->property("text"); \
35
    } \
36 37 38
    QCOMPARE(_controller->_nextButton->isEnabled(), !!((mask) & nextButtonMask)); \
    QCOMPARE(_controller->_skipButton->isEnabled(), !!((mask) & skipButtonMask)); \
    QCOMPARE(_controller->_cancelButton->isEnabled(), !!((mask) & cancelButtonMask)); \
39
    }
40 41 42 43 44

// This allows you to write unit tests which will click the Cancel button the first time through, followed
// by the Next button on the second iteration.
#define NEXT_OR_CANCEL(cancelNum) \
{ \
Don Gagne's avatar
Don Gagne committed
45
    if (mode == testModeStandalone && tryCancel ## cancelNum) { \
46 47 48 49
    QTest::mouseClick(_cancelButton, Qt::LeftButton); \
    QCOMPARE(_controller->_rcCalState, RadioComponentController::rcCalStateChannelWait); \
    tryCancel ## cancelNum = false; \
    goto StartOver; \
50
    } else { \
51
    QTest::mouseClick(_nextButton, Qt::LeftButton); \
52
    } \
53
    }
54

55
const int RadioConfigTest::_stickSettleWait = RadioComponentController::_stickDetectSettleMSecs * 1.5;
Don Gagne's avatar
Don Gagne committed
56

57 58 59
const int RadioConfigTest::_testMinValue = RadioComponentController::_rcCalPWMDefaultMinValue + 10;
const int RadioConfigTest::_testMaxValue = RadioComponentController::_rcCalPWMDefaultMaxValue - 10;
const int RadioConfigTest::_testCenterValue = RadioConfigTest::_testMinValue + ((RadioConfigTest::_testMaxValue - RadioConfigTest::_testMinValue) / 2);
Don Gagne's avatar
Don Gagne committed
60

Don Gagne's avatar
Don Gagne committed
61
const struct RadioConfigTest::ChannelSettings RadioConfigTest::_rgChannelSettingsPX4[RadioComponentController::_chanMaxPX4] = {
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
    // Function										Min                 Max                 #  Reversed

    // Channel 0 : Not mapped to function, Simulate invalid Min/Max
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,	_testCenterValue,   0, false },

// Channels 1-4: Mapped to attitude control function
{ RadioComponentController::rcCalFunctionRoll,			_testMinValue,      _testMaxValue,      0, true },
{ RadioComponentController::rcCalFunctionPitch,			_testMinValue,      _testMaxValue,      0, false },
{ RadioComponentController::rcCalFunctionYaw,			_testMinValue,      _testMaxValue,      0, true },
{ RadioComponentController::rcCalFunctionThrottle,		_testMinValue,      _testMaxValue,      0,  false },

// Channels 5-11: Not mapped to function, Simulate invalid Min/Max, since available channel Min/Max is still shown.
// These are here to skip over the flight mode functions
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },

// Channel 12 : Not mapped to function, Simulate invalid Min, valid Max
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,	_testMaxValue,      0,  false },

// Channel 13 : Not mapped to function, Simulate valid Min, invalid Max
{ RadioComponentController::rcCalFunctionMax,           _testMinValue,      _testCenterValue,   0,	false },

// Channels 14-17: Not mapped to function, Simulate invalid Min/Max, since available channel Min/Max is still shown
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
Don Gagne's avatar
Don Gagne committed
94 95
};

Don Gagne's avatar
Don Gagne committed
96
// Note the: 1500/*RadioComponentController::_rcCalPWMCenterPoint*/ entries. For some reason I couldn't get the compiler to do the
97
// right thing with the constant. So I just hacked inthe real value instead of fighting with it any longer.
Don Gagne's avatar
Don Gagne committed
98
const struct RadioConfigTest::ChannelSettings RadioConfigTest::_rgChannelSettingsValidatePX4[RadioComponentController::_chanMaxPX4] = {
Don Gagne's avatar
Don Gagne committed
99
    // Function										Min Value									Max Value									Trim Value										Reversed
100

101
    // Channels 0: not mapped and should be set to defaults
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },

// Channels 1-4: Mapped to attitude control function
{ RadioComponentController::rcCalFunctionRoll,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               true },
{ RadioComponentController::rcCalFunctionPitch,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               false },
{ RadioComponentController::rcCalFunctionYaw,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               true },
{ RadioComponentController::rcCalFunctionThrottle,		_testMinValue,                              _testMaxValue,                              _testMinValue,                                  false },

// Channels 5-11: not mapped and should be set to defaults
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },

// Channels 12-17 are not mapped and should be set to defaults
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
Don Gagne's avatar
Don Gagne committed
126 127
};

Don Gagne's avatar
Don Gagne committed
128 129 130 131
const struct RadioConfigTest::ChannelSettings RadioConfigTest::_rgChannelSettingsAPM[RadioComponentController::_chanMaxAPM] = {
    // Function										Min                 Max                 #  Reversed

    // Channel 0 : Not mapped to function, Simulate invalid Min/Max
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,	_testCenterValue,   0, false },

// Channels 1-4: Mapped to attitude control function
{ RadioComponentController::rcCalFunctionRoll,			_testMinValue,      _testMaxValue,      0, true },
{ RadioComponentController::rcCalFunctionPitch,			_testMinValue,      _testMaxValue,      0, false },
{ RadioComponentController::rcCalFunctionYaw,			_testMinValue,      _testMaxValue,      0, true },
{ RadioComponentController::rcCalFunctionThrottle,		_testMinValue,      _testMaxValue,      0,  false },

// Channels 5-11: Not mapped to function, Simulate invalid Min/Max, since available channel Min/Max is still shown.
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },

// Channel 12 : Not mapped to function, Simulate invalid Min, valid Max
{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,	_testMaxValue,      0,  false },

// Channel 13 : Not mapped to function, Simulate valid Min, invalid Max
{ RadioComponentController::rcCalFunctionMax,           _testMinValue,      _testCenterValue,   0,	false },
Don Gagne's avatar
Don Gagne committed
154 155 156 157 158 159 160 161
};

// Note the: 1500/*RadioComponentController::_rcCalPWMCenterPoint*/ entries. For some reason I couldn't get the compiler to do the
// right thing with the constant. So I just hacked inthe real value instead of fighting with it any longer.
const struct RadioConfigTest::ChannelSettings RadioConfigTest::_rgChannelSettingsValidateAPM[RadioComponentController::_chanMaxAPM] = {
    // Function										Min Value									Max Value									Trim Value										Reversed

    // Channels 0: not mapped and should be set to defaults
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },

// Channels 1-4: Mapped to attitude control function
{ RadioComponentController::rcCalFunctionRoll,			_testMinValue, _testMaxValue, _testCenterValue, true },
{ RadioComponentController::rcCalFunctionPitch,			_testMinValue, _testMaxValue, _testCenterValue, true },
{ RadioComponentController::rcCalFunctionYaw,			_testMinValue, _testMaxValue, _testCenterValue, true },
{ RadioComponentController::rcCalFunctionThrottle,		_testMinValue, _testMaxValue, _testMinValue,    false },

// Channels 5-11: not mapped and should be set to defaults
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },

// Channels 12-13 are not mapped and should be set to defaults
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
Don Gagne's avatar
Don Gagne committed
182 183
};

184 185 186
RadioConfigTest::RadioConfigTest(void) :
    _calWidget(NULL),
    _controller(NULL)
187
{
188
    
Don Gagne's avatar
Don Gagne committed
189 190
}

Don Gagne's avatar
Don Gagne committed
191
void RadioConfigTest::_init(MAV_AUTOPILOT firmwareType)
192
{
Don Gagne's avatar
Don Gagne committed
193
    _connectMockLink(firmwareType);
194
    
195
    _autopilot = qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()->autopilotPlugin();
196
    Q_ASSERT(_autopilot);
197 198 199 200

    // This test is so quick that it tends to finish before the mission item protocol completes. This causes an error to pop up.
    // So we wait a little to let mission items sync.
    QTest::qWait(500);
201 202
    
    // This will instatiate the widget with an active uas with ready parameters
203
    _calWidget = new QGCQmlWidgetHolder(QString(), NULL);
204
    _calWidget->resize(600, 600);
205
    Q_CHECK_PTR(_calWidget);
206
    _calWidget->setAutoPilot(_autopilot);
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

    // Find the radio component
    QObject* vehicleComponent = NULL;
    foreach (const QVariant& varVehicleComponent, _autopilot->vehicleComponents()) {
        if (firmwareType == MAV_AUTOPILOT_PX4) {
            PX4RadioComponent* radioComponent = qobject_cast<PX4RadioComponent*>(varVehicleComponent.value<VehicleComponent*>());
            if (radioComponent) {
                vehicleComponent = radioComponent;
                break;
            }
        } else {
            APMRadioComponent* radioComponent = qobject_cast<APMRadioComponent*>(varVehicleComponent.value<VehicleComponent*>());
            if (radioComponent) {
                vehicleComponent = radioComponent;
                break;
            }
        }
224
    }
225 226
    Q_CHECK_PTR(vehicleComponent);

227
    _calWidget->setContextPropertyObject("vehicleComponent", vehicleComponent);
228
    _calWidget->setSource(QUrl::fromUserInput("qrc:/qml/RadioComponent.qml"));
229
    
230 231 232
    // Nasty hack to get to controller
    _controller = RadioComponentController::_unitTestController;
    Q_ASSERT(_controller);
Don Gagne's avatar
Don Gagne committed
233

234
    _controller->_setUnitTestMode();
Don Gagne's avatar
Don Gagne committed
235 236 237 238
    
    _rgSignals[0] = SIGNAL(nextButtonMessageBoxDisplayed());
    _multiSpyNextButtonMessageBox = new MultiSignalSpy();
    Q_CHECK_PTR(_multiSpyNextButtonMessageBox);
239
    QCOMPARE(_multiSpyNextButtonMessageBox->init(_controller, _rgSignals, 1), true);
Don Gagne's avatar
Don Gagne committed
240
    
241
    QCOMPARE(_controller->_currentStep, -1);
242 243
}

244
void RadioConfigTest::cleanup(void)
245
{
Don Gagne's avatar
Don Gagne committed
246 247 248
    Q_ASSERT(_calWidget);
    delete _calWidget;
    
249 250
    // Disconnecting the link will prompt for log file save
    setExpectedFileDialog(getSaveFileName, QStringList());
251
    
Don Gagne's avatar
Don Gagne committed
252
    UnitTest::cleanup();
253 254
}

255
void RadioConfigTest::_beginCalibration(void)
256 257 258
{
    CHK_BUTTONS(nextButtonMask | cancelButtonMask);

Don Gagne's avatar
Don Gagne committed
259 260
    // We should already have enough channels to proceed with calibration. Click next to start the process.
    
261 262
    _controller->nextButtonClicked();
    QCOMPARE(_controller->_currentStep, 1);
263 264 265
    CHK_BUTTONS(cancelButtonMask);
}

266
void RadioConfigTest::_stickMoveWaitForSettle(int channel, int value)
267
{
268
    qCDebug(RadioConfigTestLog) << "_stickMoveWaitForSettle channel:value" << channel << value;
Don Gagne's avatar
Don Gagne committed
269 270

    // Move the stick, this will initialized the settle checker
271
    _mockLink->emitRemoteControlChannelRawChanged(channel, value);
Don Gagne's avatar
Don Gagne committed
272 273
    
    // Emit the signal again to start the settle timer
274
    _mockLink->emitRemoteControlChannelRawChanged(channel, value);
Don Gagne's avatar
Don Gagne committed
275 276
    
    // Wait long enough for the settle timer to expire
277
    QTest::qWait(RadioComponentController::_stickDetectSettleMSecs * 1.5);
Don Gagne's avatar
Don Gagne committed
278 279
    
    // Emit the signal again so that we detect stick settle
280
    _mockLink->emitRemoteControlChannelRawChanged(channel, value);
281 282
}

283
void RadioConfigTest::_stickMoveAutoStep(const char* functionStr, enum RadioComponentController::rcCalFunctions function, enum RadioConfigTest::MoveToDirection direction, bool identifyStep)
284
{
Don Gagne's avatar
Don Gagne committed
285
    Q_UNUSED(functionStr);
286
    qCDebug(RadioConfigTestLog) << "_stickMoveAutoStep function:direction:reversed:identifyStep" << functionStr << function << direction << identifyStep;
287
    
Don Gagne's avatar
Don Gagne committed
288 289 290
    CHK_BUTTONS(cancelButtonMask);
    
    int channel = _rgFunctionChannelMap[function];
291
    int saveStep = _controller->_currentStep;
Don Gagne's avatar
Don Gagne committed
292
    
Don Gagne's avatar
Don Gagne committed
293
    bool reversed = _channelSettings()[channel].reversed;
294
    
Don Gagne's avatar
Don Gagne committed
295 296
    if (!identifyStep && direction != moveToCenter) {
        // We have already identified the function channel mapping. Move other channels around to make sure there is no impact.
297
        
Don Gagne's avatar
Don Gagne committed
298
        int otherChannel = channel + 1;
Don Gagne's avatar
Don Gagne committed
299
        if (otherChannel >= _chanMax()) {
Don Gagne's avatar
Don Gagne committed
300
            otherChannel = 0;
Don Gagne's avatar
Don Gagne committed
301 302
        }
        
Don Gagne's avatar
Don Gagne committed
303
        _stickMoveWaitForSettle(otherChannel, _testMinValue);
304
        QCOMPARE(_controller->_currentStep, saveStep);
Don Gagne's avatar
Don Gagne committed
305
        CHK_BUTTONS(cancelButtonMask);
306
        
307 308
        _stickMoveWaitForSettle(otherChannel, RadioComponentController::_rcCalPWMCenterPoint);
        QCOMPARE(_controller->_currentStep, saveStep);
Don Gagne's avatar
Don Gagne committed
309
        CHK_BUTTONS(cancelButtonMask);
310 311
    }
    
Don Gagne's avatar
Don Gagne committed
312 313 314 315 316 317 318 319
    // Move channel to specified position to trigger next step
    
    int value;
    if (direction == moveToMin) {
        value = reversed ? _testMaxValue : _testMinValue;
    } else if (direction == moveToMax) {
        value = reversed ? _testMinValue : _testMaxValue;
    } else if (direction == moveToCenter) {
320
        value = RadioComponentController::_rcCalPWMCenterPoint;
Don Gagne's avatar
Don Gagne committed
321 322
    } else {
        Q_ASSERT(false);
323
    }
Don Gagne's avatar
Don Gagne committed
324 325
    
    _stickMoveWaitForSettle(channel, value);
326
    QCOMPARE(_controller->_currentStep, saveStep + 1);
327 328
}

329
void RadioConfigTest::_switchMinMaxStep(void)
330
{
Don Gagne's avatar
Don Gagne committed
331
    CHK_BUTTONS(nextButtonMask | cancelButtonMask);
Don Gagne's avatar
Don Gagne committed
332 333
    
    // Try setting a min/max value that is below the threshold to make sure min/max doesn't go valid
334 335
    _mockLink->emitRemoteControlChannelRawChanged(0, (float)(RadioComponentController::_rcCalPWMValidMinValue + 1));
    _mockLink->emitRemoteControlChannelRawChanged(0, (float)(RadioComponentController::_rcCalPWMValidMaxValue - 1));
Don Gagne's avatar
Don Gagne committed
336 337
    
    // Send min/max values switch channels
Don Gagne's avatar
Don Gagne committed
338 339 340
    for (int chan=0; chan<_chanMax(); chan++) {
        _mockLink->emitRemoteControlChannelRawChanged(chan, _channelSettings()[chan].rcMin);
        _mockLink->emitRemoteControlChannelRawChanged(chan, _channelSettings()[chan].rcMax);
341
    }
Don Gagne's avatar
Don Gagne committed
342
    
Don Gagne's avatar
Don Gagne committed
343
    _channelHomePosition();
344

345 346 347
    int saveStep = _controller->_currentStep;
    _controller->nextButtonClicked();
    QCOMPARE(_controller->_currentStep, saveStep + 1);
348 349
}

Don Gagne's avatar
Don Gagne committed
350
void RadioConfigTest::_fullCalibrationWorker(MAV_AUTOPILOT firmwareType)
351
{
Don Gagne's avatar
Don Gagne committed
352 353
    _init(firmwareType);

354
    // IMPORTANT NOTE: We used channels 1-5 for attitude mapping in the test below.
355
    // MockLink.params file cannot have flight mode switches mapped to those channels.
356 357 358 359 360
    // If it does it will cause errors since the stick will not be detetected where

    /// _rgFunctionChannelMap maps from function index to channel index. For channels which are not part of
    /// rc cal set the mapping the the previous mapping.
    
361
    for (int function=0; function<RadioComponentController::rcCalFunctionMax; function++) {
362 363 364
        bool found = false;
        
        // If we are mapping this function during cal set it into _rgFunctionChannelMap
Don Gagne's avatar
Don Gagne committed
365 366
        for (int channel=0; channel<_chanMax(); channel++) {
            if (_channelSettings()[channel].function == function) {
367
                
Don Gagne's avatar
Don Gagne committed
368 369 370 371 372
                if (_px4Vehicle()) {
                    // Make sure this function isn't being use for a switch
                    QStringList switchList;
                    switchList << "RC_MAP_MODE_SW" << "RC_MAP_LOITER_SW" << "RC_MAP_RETURN_SW" << "RC_MAP_POSCTL_SW" << "RC_MAP_ACRO_SW";

373
                    foreach (const QString &switchParam, switchList) {
374
                        Q_ASSERT(_vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, switchParam)->rawValue().toInt() != channel + 1);
Don Gagne's avatar
Don Gagne committed
375
                    }
376 377 378 379 380 381 382 383 384 385 386
                }
                
                _rgFunctionChannelMap[function] = channel;
                found = true;
                
                break;
            }
        }
        
        // If we aren't mapping this function during calibration, set it to the previous setting
        if (!found) {
Don Gagne's avatar
Don Gagne committed
387 388
            const char* paramName = _functionInfo()[function].parameterName;
            if (paramName) {
389
                _rgFunctionChannelMap[function] = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, paramName)->rawValue().toInt();
Don Gagne's avatar
Don Gagne committed
390 391 392 393 394 395
                qCDebug(RadioConfigTestLog) << "Assigning switch" << function << _rgFunctionChannelMap[function];
                if (_rgFunctionChannelMap[function] == 0) {
                    _rgFunctionChannelMap[function] = -1;   // -1 signals no mapping
                } else {
                    _rgFunctionChannelMap[function]--;   // parameter is 1-based, _rgFunctionChannelMap is not
                }
396
            } else {
Don Gagne's avatar
Don Gagne committed
397
                _rgFunctionChannelMap[function] = -1;   // -1 signals no mapping
398 399 400
            }
        }
    }
Don Gagne's avatar
Don Gagne committed
401 402
    
    _channelHomePosition();
403
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
404
    _beginCalibration();
405 406 407 408 409 410 411 412 413
    _stickMoveAutoStep("Throttle",  RadioComponentController::rcCalFunctionThrottle,    moveToMax,      true /* identify step */);
    _stickMoveAutoStep("Throttle",  RadioComponentController::rcCalFunctionThrottle,    moveToMin,      false /* not identify step */);
    _stickMoveAutoStep("Yaw",       RadioComponentController::rcCalFunctionYaw,         moveToMax,      true /* identify step */);
    _stickMoveAutoStep("Yaw",       RadioComponentController::rcCalFunctionYaw,         moveToMin,      false /* not identify step */);
    _stickMoveAutoStep("Roll",      RadioComponentController::rcCalFunctionRoll,        moveToMax,      true /* identify step */);
    _stickMoveAutoStep("Roll",      RadioComponentController::rcCalFunctionRoll,        moveToMin,      false /* not identify step */);
    _stickMoveAutoStep("Pitch",     RadioComponentController::rcCalFunctionPitch,       moveToMax,      true /* identify step */);
    _stickMoveAutoStep("Pitch",     RadioComponentController::rcCalFunctionPitch,       moveToMin,      false /* not identify step */);
    _stickMoveAutoStep("Pitch",     RadioComponentController::rcCalFunctionPitch,       moveToCenter,   false /* not identify step */);
Don Gagne's avatar
Don Gagne committed
414
    _switchMinMaxStep();
415 416

    // One more click and the parameters should get saved
417
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
418
    _validateParameters();
419 420
}

Don Gagne's avatar
Don Gagne committed
421 422 423 424 425 426 427 428 429 430 431
void RadioConfigTest::_fullCalibration_px4_test(void)
{
    _fullCalibrationWorker(MAV_AUTOPILOT_PX4);
}


void RadioConfigTest::_fullCalibration_apm_test(void)
{
    _fullCalibrationWorker(MAV_AUTOPILOT_ARDUPILOTMEGA);
}

Don Gagne's avatar
Don Gagne committed
432
/// @brief Sets rc input to Throttle down home position. Centers all other channels.
433
void RadioConfigTest::_channelHomePosition(void)
434
{
Don Gagne's avatar
Don Gagne committed
435
    // Initialize available channels to center point.
Don Gagne's avatar
Don Gagne committed
436
    for (int i=0; i<_chanMax(); i++) {
437
        _mockLink->emitRemoteControlChannelRawChanged(i, (float)RadioComponentController::_rcCalPWMCenterPoint);
438
    }
Don Gagne's avatar
Don Gagne committed
439
    
440 441
    // Throttle to min - 1 (throttle is not reversed). We do this so that the trim value is below the min value. This should end up
    // being validated and raised to min value. If not, something is wrong with RC Cal code.
442
    _mockLink->emitRemoteControlChannelRawChanged(_rgFunctionChannelMap[RadioComponentController::rcCalFunctionThrottle], _testMinValue - 1);
443 444
}

445
void RadioConfigTest::_validateParameters(void)
446 447 448 449
{
    QString minTpl("RC%1_MIN");
    QString maxTpl("RC%1_MAX");
    QString trimTpl("RC%1_TRIM");
450 451 452 453

    QString revTplPX4("RC%1_REV");
    QString revTplAPM("RC%1_REVERSED");

Don Gagne's avatar
Don Gagne committed
454
    // Check mapping for all fuctions
455
    for (int chanFunction=0; chanFunction<RadioComponentController::rcCalFunctionMax; chanFunction++) {
Don Gagne's avatar
Don Gagne committed
456 457 458 459 460 461 462 463 464
        int chanIndex = _rgFunctionChannelMap[chanFunction];
        
        int expectedParameterValue;
        if (chanIndex == -1) {
            expectedParameterValue = 0;  // 0 signals no mapping
        } else {
            expectedParameterValue = chanIndex + 1; // 1-based parameter value
        }
        
Don Gagne's avatar
Don Gagne committed
465 466
        const char* paramName = _functionInfo()[chanFunction].parameterName;
        if (paramName) {
467 468
            qCDebug(RadioConfigTestLog) << "Validate" << chanFunction << _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, paramName)->rawValue().toInt();
            QCOMPARE(_vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, paramName)->rawValue().toInt(), expectedParameterValue);
Don Gagne's avatar
Don Gagne committed
469
        }
Don Gagne's avatar
Don Gagne committed
470
    }
Don Gagne's avatar
Don Gagne committed
471 472

    // Validate the channel settings. Note the channels are 1-based in parameter names.
Don Gagne's avatar
Don Gagne committed
473
    for (int chan = 0; chan<_chanMax(); chan++) {
Don Gagne's avatar
Don Gagne committed
474 475 476 477
        int oneBasedChannel = chan + 1;
        bool convertOk;
        
        // Required channels have min/max set on them. Remaining channels are left to default.
Don Gagne's avatar
Don Gagne committed
478 479 480 481
        int rcMinExpected = _channelSettingsValidate()[chan].rcMin;
        int rcMaxExpected = _channelSettingsValidate()[chan].rcMax;
        int rcTrimExpected = _channelSettingsValidate()[chan].rcTrim;
        bool rcReversedExpected = _channelSettingsValidate()[chan].reversed;
Don Gagne's avatar
Don Gagne committed
482

483
        int rcMinActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, minTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
484
        QCOMPARE(convertOk, true);
485
        int rcMaxActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, maxTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
486
        QCOMPARE(convertOk, true);
487
        int rcTrimActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, trimTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
488
        QCOMPARE(convertOk, true);
489 490 491 492 493 494 495 496 497

        bool rcReversedActual;
        if (_vehicle->px4Firmware()) {
            float rcReversedFloat = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, revTplPX4.arg(oneBasedChannel))->rawValue().toFloat(&convertOk);
            QCOMPARE(convertOk, true);
            rcReversedActual = (rcReversedFloat == -1.0f);
        } else {
            rcReversedActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, revTplAPM.arg(oneBasedChannel))->rawValue().toBool();
        }
Don Gagne's avatar
Don Gagne committed
498
        
Lorenz Meier's avatar
Lorenz Meier committed
499 500
        qCDebug(RadioConfigTestLog) << "_validateParameters expected channel:min:max:trim:rev" << chan << rcMinExpected << rcMaxExpected << rcTrimExpected << rcReversedExpected;
        qCDebug(RadioConfigTestLog) << "_validateParameters actual channel:min:max:trim:rev" << chan << rcMinActual << rcMaxActual << rcTrimActual << rcReversedActual;
501

Don Gagne's avatar
Don Gagne committed
502 503 504 505
        QCOMPARE(rcMinExpected, rcMinActual);
        QCOMPARE(rcMaxExpected, rcMaxActual);
        QCOMPARE(rcTrimExpected, rcTrimActual);
        QCOMPARE(rcReversedExpected, rcReversedActual);
506 507
    }
    
Don Gagne's avatar
Don Gagne committed
508
    // Check mapping for all fuctions
509
    for (int chanFunction=0; chanFunction<RadioComponentController::rcCalFunctionMax; chanFunction++) {
Don Gagne's avatar
Don Gagne committed
510 511 512 513 514
        int expectedValue;
        if (_rgFunctionChannelMap[chanFunction] == -1) {
            expectedValue = 0;  // 0 signals no mapping
        } else {
            expectedValue = _rgFunctionChannelMap[chanFunction] + 1; // 1-based
515
        }
Don Gagne's avatar
Don Gagne committed
516 517 518
        const char* paramName = _functionInfo()[chanFunction].parameterName;
        if (paramName) {
            // qCDebug(RadioConfigTestLog) << chanFunction << expectedValue << mapParamsSet[paramName].toInt();
519
            QCOMPARE(_vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, paramName)->rawValue().toInt(), expectedValue);
Don Gagne's avatar
Don Gagne committed
520
        }
521
    }
Don Gagne's avatar
Don Gagne committed
522
}
Don Gagne's avatar
Don Gagne committed
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547

bool RadioConfigTest::_px4Vehicle(void) const
{
    return _vehicle->firmwareType() == MAV_AUTOPILOT_PX4;
}

const struct RadioConfigTest::ChannelSettings* RadioConfigTest::_channelSettings(void) const
{
    return _px4Vehicle() ? _rgChannelSettingsPX4 : _rgChannelSettingsAPM;
}

const struct RadioConfigTest::ChannelSettings* RadioConfigTest::_channelSettingsValidate(void) const
{
    return _px4Vehicle() ? _rgChannelSettingsValidatePX4 : _rgChannelSettingsValidateAPM;
}

const struct RadioComponentController::FunctionInfo* RadioConfigTest::_functionInfo(void) const
{
    return _px4Vehicle() ? RadioComponentController::_rgFunctionInfoPX4 : RadioComponentController::_rgFunctionInfoAPM;
}

int RadioConfigTest::_chanMax(void) const
{
    return _px4Vehicle() ? RadioComponentController::_chanMaxPX4 : RadioComponentController::_chanMaxAPM;
}