RadioConfigTest.cc 32 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*=====================================================================
 
 QGroundControl Open Source Ground Control Station
 
 (c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 
 This file is part of the QGROUNDCONTROL project
 
 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
 
 ======================================================================*/

Don Gagne's avatar
Don Gagne committed
24
#include "RadioConfigTest.h"
25
#include "RadioComponentController.h"
26
#include "MultiVehicleManager.h"
27
#include "QGCApplication.h"
28 29

/// @file
30
///     @brief QRadioComponentController Widget unit test
31 32 33
///
///     @author Don Gagne <don@thegagnes.com>

34
QGC_LOGGING_CATEGORY(RadioConfigTestLog, "RadioConfigTestLog")
Don Gagne's avatar
Don Gagne committed
35

36 37 38 39
// 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) \
{ \
40 41 42 43
    if (_controller->_nextButton->isEnabled() != !!((mask) & nextButtonMask) || \
        _controller->_skipButton->isEnabled() != !!((mask) & skipButtonMask) || \
        _controller->_cancelButton->isEnabled() != !!((mask) & cancelButtonMask) ) { \
        qCDebug(RadioConfigTestLog) << _controller->_statusText->property("text"); \
44
    } \
45 46 47
    QCOMPARE(_controller->_nextButton->isEnabled(), !!((mask) & nextButtonMask)); \
    QCOMPARE(_controller->_skipButton->isEnabled(), !!((mask) & skipButtonMask)); \
    QCOMPARE(_controller->_cancelButton->isEnabled(), !!((mask) & cancelButtonMask)); \
48 49 50 51 52 53
}

// 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
54
    if (mode == testModeStandalone && tryCancel ## cancelNum) { \
55
        QTest::mouseClick(_cancelButton, Qt::LeftButton); \
56
        QCOMPARE(_controller->_rcCalState, RadioComponentController::rcCalStateChannelWait); \
57 58 59 60 61 62 63
        tryCancel ## cancelNum = false; \
        goto StartOver; \
    } else { \
        QTest::mouseClick(_nextButton, Qt::LeftButton); \
    } \
}

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

66 67 68
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
69

Don Gagne's avatar
Don Gagne committed
70
const struct RadioConfigTest::ChannelSettings RadioConfigTest::_rgChannelSettingsPX4[RadioComponentController::_chanMaxPX4] = {
Don Gagne's avatar
Don Gagne committed
71
	// Function										Min                 Max                 #  Reversed
72 73
	
	// Channel 0 : Not mapped to function, Simulate invalid Min/Max
74
	{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,	_testCenterValue,   0, false },
75
	
76
    // Channels 1-4: Mapped to attitude control function
77 78 79 80
    { RadioComponentController::rcCalFunctionRoll,			_testMinValue,      _testMaxValue,      0, true },
    { RadioComponentController::rcCalFunctionPitch,			_testMinValue,      _testMaxValue,      0, false },
    { RadioComponentController::rcCalFunctionYaw,			_testMinValue,      _testMaxValue,      0, true },
    { RadioComponentController::rcCalFunctionThrottle,		_testMinValue,      _testMaxValue,      0,  false },
81 82 83
    
    // Channels 5-8: 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
84 85 86 87
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
88 89
    
    // Channels 9-11: Remainder of non-flight mode switches
90 91 92
    { RadioComponentController::rcCalFunctionFlaps,			_testMinValue,      _testMaxValue,      0, false },
    { RadioComponentController::rcCalFunctionAux1,			_testMinValue,      _testMaxValue,      0, false },
    { RadioComponentController::rcCalFunctionAux2,			_testMinValue,      _testMaxValue,      0, false },
93 94
	
    // Channel 12 : Not mapped to function, Simulate invalid Min, valid Max
95
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,	_testMaxValue,      0,  false },
96 97
    
	// Channel 13 : Not mapped to function, Simulate valid Min, invalid Max
98
	{ RadioComponentController::rcCalFunctionMax,           _testMinValue,      _testCenterValue,   0,	false },
99 100
	
    // Channels 14-17: Not mapped to function, Simulate invalid Min/Max, since available channel Min/Max is still shown
101 102 103 104
    { 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
105 106
};

Don Gagne's avatar
Don Gagne committed
107
// Note the: 1500/*RadioComponentController::_rcCalPWMCenterPoint*/ entries. For some reason I couldn't get the compiler to do the
108
// 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
109
const struct RadioConfigTest::ChannelSettings RadioConfigTest::_rgChannelSettingsValidatePX4[RadioComponentController::_chanMaxPX4] = {
Don Gagne's avatar
Don Gagne committed
110
    // Function										Min Value									Max Value									Trim Value										Reversed
111
	
112
    // Channels 0: not mapped and should be set to defaults
113
	{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
114
	
115
    // Channels 1-4: Mapped to attitude control function
116 117 118 119
	{ RadioComponentController::rcCalFunctionRoll,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               true },
    { RadioComponentController::rcCalFunctionPitch,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               false },
    { RadioComponentController::rcCalFunctionYaw,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               true },
    { RadioComponentController::rcCalFunctionThrottle,		_testMinValue,                              _testMaxValue,                              _testMinValue,                                  false },
120 121
    
    // Channels 5-8: not mapped and should be set to defaults
122 123 124 125
    { 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 },
126 127
    
    // Channels 9-11: Remainder of non-flight mode switches
128 129 130
    { RadioComponentController::rcCalFunctionFlaps,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               false },
    { RadioComponentController::rcCalFunctionAux1,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               false },
    { RadioComponentController::rcCalFunctionAux2,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               false },
131
	
Don Gagne's avatar
Don Gagne committed
132
	// Channels 12-17 are not mapped and should be set to defaults
133 134 135 136 137 138
	{ 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
139 140
};

Don Gagne's avatar
Don Gagne committed
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
const struct RadioConfigTest::ChannelSettings RadioConfigTest::_rgChannelSettingsAPM[RadioComponentController::_chanMaxAPM] = {
    // 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.
    { 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 },
};

// 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
    { 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-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 },
};

197 198 199
RadioConfigTest::RadioConfigTest(void) :
    _calWidget(NULL),
    _controller(NULL)
200
{
201
    
Don Gagne's avatar
Don Gagne committed
202 203
}

Don Gagne's avatar
Don Gagne committed
204
void RadioConfigTest::_init(MAV_AUTOPILOT firmwareType)
205
{
Don Gagne's avatar
Don Gagne committed
206
    _connectMockLink(firmwareType);
207
    
208
    _autopilot = qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()->autopilotPlugin();
209
    Q_ASSERT(_autopilot);
210 211
    
    // This will instatiate the widget with an active uas with ready parameters
212
    _calWidget = new QGCQmlWidgetHolder(QString(), NULL);
213
    _calWidget->resize(600, 600);
214
    Q_CHECK_PTR(_calWidget);
215 216
    _calWidget->setAutoPilot(_autopilot);
    _calWidget->setSource(QUrl::fromUserInput("qrc:/qml/RadioComponent.qml"));
217
    
218 219 220
    // Nasty hack to get to controller
    _controller = RadioComponentController::_unitTestController;
    Q_ASSERT(_controller);
Don Gagne's avatar
Don Gagne committed
221

222
    _controller->_setUnitTestMode();
Don Gagne's avatar
Don Gagne committed
223 224 225 226
    
    _rgSignals[0] = SIGNAL(nextButtonMessageBoxDisplayed());
    _multiSpyNextButtonMessageBox = new MultiSignalSpy();
    Q_CHECK_PTR(_multiSpyNextButtonMessageBox);
227
    QCOMPARE(_multiSpyNextButtonMessageBox->init(_controller, _rgSignals, 1), true);
Don Gagne's avatar
Don Gagne committed
228
    
229
    QCOMPARE(_controller->_currentStep, -1);
230 231
}

232
void RadioConfigTest::cleanup(void)
233
{
Don Gagne's avatar
Don Gagne committed
234 235 236
    Q_ASSERT(_calWidget);
    delete _calWidget;
    
237 238
    // Disconnecting the link will prompt for log file save
    setExpectedFileDialog(getSaveFileName, QStringList());
239
    
Don Gagne's avatar
Don Gagne committed
240
    UnitTest::cleanup();
241 242
}

243
void RadioConfigTest::_beginCalibration(void)
244 245 246
{
    CHK_BUTTONS(nextButtonMask | cancelButtonMask);

Don Gagne's avatar
Don Gagne committed
247 248
    // We should already have enough channels to proceed with calibration. Click next to start the process.
    
249 250
    _controller->nextButtonClicked();
    QCOMPARE(_controller->_currentStep, 1);
251 252 253
    CHK_BUTTONS(cancelButtonMask);
}

254
void RadioConfigTest::_stickMoveWaitForSettle(int channel, int value)
255
{
256
    qCDebug(RadioConfigTestLog) << "_stickMoveWaitForSettle channel:value" << channel << value;
Don Gagne's avatar
Don Gagne committed
257 258

    // Move the stick, this will initialized the settle checker
259
    _mockLink->emitRemoteControlChannelRawChanged(channel, value);
Don Gagne's avatar
Don Gagne committed
260 261
    
    // Emit the signal again to start the settle timer
262
    _mockLink->emitRemoteControlChannelRawChanged(channel, value);
Don Gagne's avatar
Don Gagne committed
263 264
    
    // Wait long enough for the settle timer to expire
265
    QTest::qWait(RadioComponentController::_stickDetectSettleMSecs * 1.5);
Don Gagne's avatar
Don Gagne committed
266 267
    
    // Emit the signal again so that we detect stick settle
268
    _mockLink->emitRemoteControlChannelRawChanged(channel, value);
269 270
}

271
void RadioConfigTest::_stickMoveAutoStep(const char* functionStr, enum RadioComponentController::rcCalFunctions function, enum RadioConfigTest::MoveToDirection direction, bool identifyStep)
272
{
Don Gagne's avatar
Don Gagne committed
273
    Q_UNUSED(functionStr);
274
    qCDebug(RadioConfigTestLog) << "_stickMoveAutoStep function:direction:reversed:identifyStep" << functionStr << function << direction << identifyStep;
275
    
Don Gagne's avatar
Don Gagne committed
276 277 278
    CHK_BUTTONS(cancelButtonMask);
    
    int channel = _rgFunctionChannelMap[function];
279
    int saveStep = _controller->_currentStep;
Don Gagne's avatar
Don Gagne committed
280
    
Don Gagne's avatar
Don Gagne committed
281
    bool reversed = _channelSettings()[channel].reversed;
282
    
Don Gagne's avatar
Don Gagne committed
283 284
    if (!identifyStep && direction != moveToCenter) {
        // We have already identified the function channel mapping. Move other channels around to make sure there is no impact.
285
        
Don Gagne's avatar
Don Gagne committed
286
        int otherChannel = channel + 1;
Don Gagne's avatar
Don Gagne committed
287
        if (otherChannel >= _chanMax()) {
Don Gagne's avatar
Don Gagne committed
288
            otherChannel = 0;
Don Gagne's avatar
Don Gagne committed
289 290
        }
        
Don Gagne's avatar
Don Gagne committed
291
        _stickMoveWaitForSettle(otherChannel, _testMinValue);
292
        QCOMPARE(_controller->_currentStep, saveStep);
Don Gagne's avatar
Don Gagne committed
293
        CHK_BUTTONS(cancelButtonMask);
294
        
295 296
        _stickMoveWaitForSettle(otherChannel, RadioComponentController::_rcCalPWMCenterPoint);
        QCOMPARE(_controller->_currentStep, saveStep);
Don Gagne's avatar
Don Gagne committed
297
        CHK_BUTTONS(cancelButtonMask);
298 299
    }
    
Don Gagne's avatar
Don Gagne committed
300 301 302 303 304 305 306 307
    // 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) {
308
        value = RadioComponentController::_rcCalPWMCenterPoint;
Don Gagne's avatar
Don Gagne committed
309 310
    } else {
        Q_ASSERT(false);
311
    }
Don Gagne's avatar
Don Gagne committed
312 313
    
    _stickMoveWaitForSettle(channel, value);
314
    QCOMPARE(_controller->_currentStep, saveStep + 1);
315 316
}

317
void RadioConfigTest::_switchMinMaxStep(void)
318
{
Don Gagne's avatar
Don Gagne committed
319
    CHK_BUTTONS(nextButtonMask | cancelButtonMask);
Don Gagne's avatar
Don Gagne committed
320 321
    
    // Try setting a min/max value that is below the threshold to make sure min/max doesn't go valid
322 323
    _mockLink->emitRemoteControlChannelRawChanged(0, (float)(RadioComponentController::_rcCalPWMValidMinValue + 1));
    _mockLink->emitRemoteControlChannelRawChanged(0, (float)(RadioComponentController::_rcCalPWMValidMaxValue - 1));
Don Gagne's avatar
Don Gagne committed
324 325
    
    // Send min/max values switch channels
Don Gagne's avatar
Don Gagne committed
326 327 328
    for (int chan=0; chan<_chanMax(); chan++) {
        _mockLink->emitRemoteControlChannelRawChanged(chan, _channelSettings()[chan].rcMin);
        _mockLink->emitRemoteControlChannelRawChanged(chan, _channelSettings()[chan].rcMax);
329
    }
Don Gagne's avatar
Don Gagne committed
330
    
Don Gagne's avatar
Don Gagne committed
331
    _channelHomePosition();
332

333 334 335
    int saveStep = _controller->_currentStep;
    _controller->nextButtonClicked();
    QCOMPARE(_controller->_currentStep, saveStep + 1);
336 337
}

338
void RadioConfigTest::_flapsDetectStep(void)
339
{
340
    int channel = _rgFunctionChannelMap[RadioComponentController::rcCalFunctionFlaps];
341
    
342
    qCDebug(RadioConfigTestLog) << "_flapsDetectStep channel" << channel;
343
    
Don Gagne's avatar
Don Gagne committed
344
    // Test code can't handle reversed flaps channel
Don Gagne's avatar
Don Gagne committed
345
    Q_ASSERT(!_channelSettings()[channel].reversed);
346
    
Don Gagne's avatar
Don Gagne committed
347 348
    CHK_BUTTONS(nextButtonMask | cancelButtonMask | skipButtonMask);
    
349
    int saveStep = _controller->_currentStep;
350

Don Gagne's avatar
Don Gagne committed
351 352 353
    // Wiggle channel to identify
    _stickMoveWaitForSettle(channel, _testMaxValue);
    _stickMoveWaitForSettle(channel, _testMinValue);
354
    
Don Gagne's avatar
Don Gagne committed
355 356
    // Leave channel on full flaps down
    _stickMoveWaitForSettle(channel, _testMaxValue);
357
    
Don Gagne's avatar
Don Gagne committed
358
    // User has to hit next at this step
359
    QCOMPARE(_controller->_currentStep, saveStep);
Don Gagne's avatar
Don Gagne committed
360
    CHK_BUTTONS(nextButtonMask | cancelButtonMask | skipButtonMask);
361 362
    _controller->nextButtonClicked();
    QCOMPARE(_controller->_currentStep, saveStep + 1);
363 364
}

365
void RadioConfigTest::_switchSelectAutoStep(const char* functionStr, RadioComponentController::rcCalFunctions function)
366
{
Don Gagne's avatar
Don Gagne committed
367
    Q_UNUSED(functionStr);
368
    ////qCDebug(RadioConfigTestLog)() << "_switchSelectAutoStep" << functionStr << "function:" << function;
369
    
Don Gagne's avatar
Don Gagne committed
370
    int buttonMask = cancelButtonMask;
371
    if (function != RadioComponentController::rcCalFunctionModeSwitch) {
Don Gagne's avatar
Don Gagne committed
372
        buttonMask |= skipButtonMask;
Don Gagne's avatar
Don Gagne committed
373 374
    }
    
Don Gagne's avatar
Don Gagne committed
375
    CHK_BUTTONS(buttonMask);
Don Gagne's avatar
Don Gagne committed
376
    
377
    int saveStep = _controller->_currentStep;
378
    
Don Gagne's avatar
Don Gagne committed
379 380
    // Wiggle stick for channel
    int channel = _rgFunctionChannelMap[function];
381 382
    _mockLink->emitRemoteControlChannelRawChanged(channel, _testMinValue);
    _mockLink->emitRemoteControlChannelRawChanged(channel, _testMaxValue);
Don Gagne's avatar
Don Gagne committed
383
    
384
    QCOMPARE(_controller->_currentStep, saveStep + 1);
385 386
}

Don Gagne's avatar
Don Gagne committed
387
void RadioConfigTest::_fullCalibrationWorker(MAV_AUTOPILOT firmwareType)
388
{
Don Gagne's avatar
Don Gagne committed
389 390
    _init(firmwareType);

391
    // IMPORTANT NOTE: We used channels 1-5 for attitude mapping in the test below.
392
    // MockLink.params file cannot have flight mode switches mapped to those channels.
393 394 395 396 397
    // 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.
    
398
    for (int function=0; function<RadioComponentController::rcCalFunctionMax; function++) {
399 400 401
        bool found = false;
        
        // If we are mapping this function during cal set it into _rgFunctionChannelMap
Don Gagne's avatar
Don Gagne committed
402 403
        for (int channel=0; channel<_chanMax(); channel++) {
            if (_channelSettings()[channel].function == function) {
404
                
Don Gagne's avatar
Don Gagne committed
405 406 407 408 409 410 411 412
                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";

                    foreach (QString switchParam, switchList) {
                        Q_ASSERT(_autopilot->getParameterFact(FactSystem::defaultComponentId, switchParam)->rawValue().toInt() != channel + 1);
                    }
413 414 415 416 417 418 419 420 421 422 423
                }
                
                _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
424 425 426 427 428 429 430 431 432
            const char* paramName = _functionInfo()[function].parameterName;
            if (paramName) {
                _rgFunctionChannelMap[function] = _autopilot->getParameterFact(FactSystem::defaultComponentId, paramName)->rawValue().toInt();
                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
                }
433
            } else {
Don Gagne's avatar
Don Gagne committed
434
                _rgFunctionChannelMap[function] = -1;   // -1 signals no mapping
435 436 437
            }
        }
    }
Don Gagne's avatar
Don Gagne committed
438 439
    
    _channelHomePosition();
440
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
441
    _beginCalibration();
442 443 444 445 446 447 448 449 450
    _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
451
    _switchMinMaxStep();
Don Gagne's avatar
Don Gagne committed
452 453 454 455 456 457
    if (firmwareType == MAV_AUTOPILOT_PX4) {
        _flapsDetectStep();
        _stickMoveAutoStep("Flaps", RadioComponentController::rcCalFunctionFlaps, moveToMin, false /* not identify step */);
        _switchSelectAutoStep("Aux1", RadioComponentController::rcCalFunctionAux1);
        _switchSelectAutoStep("Aux2", RadioComponentController::rcCalFunctionAux2);
    }
458 459

    // One more click and the parameters should get saved
460
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
461
    _validateParameters();
462 463
}

Don Gagne's avatar
Don Gagne committed
464 465 466 467 468 469 470 471 472 473 474
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
475
/// @brief Sets rc input to Throttle down home position. Centers all other channels.
476
void RadioConfigTest::_channelHomePosition(void)
477
{
Don Gagne's avatar
Don Gagne committed
478
    // Initialize available channels to center point.
Don Gagne's avatar
Don Gagne committed
479
    for (int i=0; i<_chanMax(); i++) {
480
        _mockLink->emitRemoteControlChannelRawChanged(i, (float)RadioComponentController::_rcCalPWMCenterPoint);
481
    }
Don Gagne's avatar
Don Gagne committed
482
    
483 484
    // 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.
485
    _mockLink->emitRemoteControlChannelRawChanged(_rgFunctionChannelMap[RadioComponentController::rcCalFunctionThrottle], _testMinValue - 1);
486 487
}

488
void RadioConfigTest::_validateParameters(void)
489 490 491 492 493 494
{
    QString minTpl("RC%1_MIN");
    QString maxTpl("RC%1_MAX");
    QString trimTpl("RC%1_TRIM");
    QString revTpl("RC%1_REV");
    
Don Gagne's avatar
Don Gagne committed
495
    // Check mapping for all fuctions
496
    for (int chanFunction=0; chanFunction<RadioComponentController::rcCalFunctionMax; chanFunction++) {
Don Gagne's avatar
Don Gagne committed
497 498 499 500 501 502 503 504 505
        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
506 507 508 509 510
        const char* paramName = _functionInfo()[chanFunction].parameterName;
        if (paramName) {
            qCDebug(RadioConfigTestLog) << "Validate" << chanFunction << _autopilot->getParameterFact(FactSystem::defaultComponentId, paramName)->rawValue().toInt();
            QCOMPARE(_autopilot->getParameterFact(FactSystem::defaultComponentId, paramName)->rawValue().toInt(), expectedParameterValue);
        }
Don Gagne's avatar
Don Gagne committed
511
    }
Don Gagne's avatar
Don Gagne committed
512 513

    // Validate the channel settings. Note the channels are 1-based in parameter names.
Don Gagne's avatar
Don Gagne committed
514
    for (int chan = 0; chan<_chanMax(); chan++) {
Don Gagne's avatar
Don Gagne committed
515 516 517 518
        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
519 520 521 522
        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
523

Don Gagne's avatar
Don Gagne committed
524
        int rcMinActual = _autopilot->getParameterFact(FactSystem::defaultComponentId, minTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
525
        QCOMPARE(convertOk, true);
Don Gagne's avatar
Don Gagne committed
526
        int rcMaxActual = _autopilot->getParameterFact(FactSystem::defaultComponentId, maxTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
527
        QCOMPARE(convertOk, true);
Don Gagne's avatar
Don Gagne committed
528
        int rcTrimActual = _autopilot->getParameterFact(FactSystem::defaultComponentId, trimTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
529
        QCOMPARE(convertOk, true);
Don Gagne's avatar
Don Gagne committed
530
        float rcReversedFloat = _autopilot->getParameterFact(FactSystem::defaultComponentId, revTpl.arg(oneBasedChannel))->rawValue().toFloat(&convertOk);
Don Gagne's avatar
Don Gagne committed
531 532 533
        QCOMPARE(convertOk, true);
        bool rcReversedActual = (rcReversedFloat == -1.0f);
        
Lorenz Meier's avatar
Lorenz Meier committed
534 535
        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;
536

Don Gagne's avatar
Don Gagne committed
537 538 539 540
        QCOMPARE(rcMinExpected, rcMinActual);
        QCOMPARE(rcMaxExpected, rcMaxActual);
        QCOMPARE(rcTrimExpected, rcTrimActual);
        QCOMPARE(rcReversedExpected, rcReversedActual);
541 542
    }
    
Don Gagne's avatar
Don Gagne committed
543
    // Check mapping for all fuctions
544
    for (int chanFunction=0; chanFunction<RadioComponentController::rcCalFunctionMax; chanFunction++) {
Don Gagne's avatar
Don Gagne committed
545 546 547 548 549
        int expectedValue;
        if (_rgFunctionChannelMap[chanFunction] == -1) {
            expectedValue = 0;  // 0 signals no mapping
        } else {
            expectedValue = _rgFunctionChannelMap[chanFunction] + 1; // 1-based
550
        }
Don Gagne's avatar
Don Gagne committed
551 552 553 554 555
        const char* paramName = _functionInfo()[chanFunction].parameterName;
        if (paramName) {
            // qCDebug(RadioConfigTestLog) << chanFunction << expectedValue << mapParamsSet[paramName].toInt();
            QCOMPARE(_autopilot->getParameterFact(FactSystem::defaultComponentId, paramName)->rawValue().toInt(), expectedValue);
        }
556
    }
Don Gagne's avatar
Don Gagne committed
557
}
Don Gagne's avatar
Don Gagne committed
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582

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