PX4RCCalibrationTest.cc 27.7 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 24
/*=====================================================================
 
 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/>.
 
 ======================================================================*/

#include "PX4RCCalibrationTest.h"
25
#include "RadioComponentController.h"
26
#include "UASManager.h"
27
#include "AutoPilotPluginManager.h"
28 29

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

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

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

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

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

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

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

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

142 143 144
RadioConfigTest::RadioConfigTest(void) :
    _calWidget(NULL),
    _controller(NULL)
145
{
146
    
Don Gagne's avatar
Don Gagne committed
147 148
}

149
void RadioConfigTest::init(void)
150
{
Don Gagne's avatar
Don Gagne committed
151 152
    UnitTest::init();
    
153 154 155 156 157
    _mockLink = new MockLink();
    Q_CHECK_PTR(_mockLink);
    LinkManager::instance()->_addLink(_mockLink);
    LinkManager::instance()->connectLink(_mockLink);
    QTest::qWait(5000); // Give enough time for UI to settle and heartbeats to go through
158
    
159
    _autopilot = AutoPilotPluginManager::instance()->getInstanceForAutoPilotPlugin(UASManager::instance()->getActiveUAS()).data();
160
    Q_ASSERT(_autopilot);
161
    
162 163
    QSignalSpy spyPlugin(_autopilot, SIGNAL(pluginReadyChanged(bool)));
    if (!_autopilot->pluginReady()) {
164
        QCOMPARE(spyPlugin.wait(60000), true);
165 166 167
    }
    Q_ASSERT(_autopilot->pluginReady());
    
168
    // This will instatiate the widget with an active uas with ready parameters
169
    _calWidget = new QGCQmlWidgetHolder();
170
    _calWidget->resize(600, 600);
171
    Q_CHECK_PTR(_calWidget);
172 173
    _calWidget->setAutoPilot(_autopilot);
    _calWidget->setSource(QUrl::fromUserInput("qrc:/qml/RadioComponent.qml"));
174
    
175 176 177
    // Nasty hack to get to controller
    _controller = RadioComponentController::_unitTestController;
    Q_ASSERT(_controller);
Don Gagne's avatar
Don Gagne committed
178

179
    _controller->_setUnitTestMode();
Don Gagne's avatar
Don Gagne committed
180 181 182 183
    
    _rgSignals[0] = SIGNAL(nextButtonMessageBoxDisplayed());
    _multiSpyNextButtonMessageBox = new MultiSignalSpy();
    Q_CHECK_PTR(_multiSpyNextButtonMessageBox);
184
    QCOMPARE(_multiSpyNextButtonMessageBox->init(_controller, _rgSignals, 1), true);
Don Gagne's avatar
Don Gagne committed
185
    
186
    QCOMPARE(_controller->_currentStep, -1);
187 188
}

189
void RadioConfigTest::cleanup(void)
190
{
Don Gagne's avatar
Don Gagne committed
191 192 193
    Q_ASSERT(_calWidget);
    delete _calWidget;
    
194 195
    // Disconnecting the link will prompt for log file save
    setExpectedFileDialog(getSaveFileName, QStringList());
196
    
197
    LinkManager::instance()->disconnectLink(_mockLink);
198
    
Don Gagne's avatar
Don Gagne committed
199
    UnitTest::cleanup();
200 201
}

Don Gagne's avatar
Don Gagne committed
202
/// @brief Test for correct behavior in determining minimum numbers of channels for flight.
203
void RadioConfigTest::_minRCChannels_test(void)
204 205
{
    // Next button won't be enabled until we see the minimum number of channels.
206 207
    for (int chan=0; chan<RadioComponentController::_chanMinimum; chan++) {
        _mockLink->emitRemoteControlChannelRawChanged(chan, (float)RadioComponentController::_rcCalPWMCenterPoint);
Don Gagne's avatar
Don Gagne committed
208 209
        
        // We use _chanCount internally so we should validate it
210
        QCOMPARE(_controller->_chanCount, chan+1);
Don Gagne's avatar
Don Gagne committed
211 212
        
        // Validate Next button state
213
        _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
214
        bool signalFound = _multiSpyNextButtonMessageBox->waitForSignalByIndex(0, 200);
215
        if (chan == RadioComponentController::_chanMinimum - 1) {
Don Gagne's avatar
Don Gagne committed
216 217
            // Last channel should trigger Calibration available
            QCOMPARE(signalFound, false);
218
            QCOMPARE(_controller->_currentStep, 0);
219
        } else {
Don Gagne's avatar
Don Gagne committed
220 221
            // Still less than the minimum channels. Next button should show message box. Calibration should not start.
            QCOMPARE(signalFound, true);
222
            QCOMPARE(_controller->_currentStep, -1);
223
        }
Don Gagne's avatar
Don Gagne committed
224
        _multiSpyNextButtonMessageBox->clearAllSignals();
Don Gagne's avatar
Don Gagne committed
225

226 227 228
        // The following test code no longer works since view update doesn't happens until parameters are received.
        // Leaving code here because RC Cal could be restructured to handle this case at some point.
#if 0
Don Gagne's avatar
Don Gagne committed
229
        // Only available channels should have visible widget. A ui update cycle needs to have passed so we wait a little.
230 231 232
        QTest::qWait(RadioComponentController::_updateInterval * 2);
        for (int chanWidget=0; chanWidget<RadioComponentController::_chanMax; chanWidget++) {
            qCDebug(RadioConfigTestLog) << _rgValueWidget[chanWidget]->objectName() << chanWidget << chan;
Don Gagne's avatar
Don Gagne committed
233
            QCOMPARE(_rgValueWidget[chanWidget]->isVisible(), !!(chanWidget <= chan));
Don Gagne's avatar
Don Gagne committed
234
        }
235
#endif
236 237 238
    }
}

239
void RadioConfigTest::_beginCalibration(void)
240 241 242
{
    CHK_BUTTONS(nextButtonMask | cancelButtonMask);

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

250
void RadioConfigTest::_stickMoveWaitForSettle(int channel, int value)
251
{
252
    qCDebug(RadioConfigTestLog) << "_stickMoveWaitForSettle channel:value" << channel << value;
Don Gagne's avatar
Don Gagne committed
253 254

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

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

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

329 330 331
    int saveStep = _controller->_currentStep;
    _controller->nextButtonClicked();
    QCOMPARE(_controller->_currentStep, saveStep + 1);
332 333
}

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

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

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

383
void RadioConfigTest::_fullCalibration_test(void)
384
{
385
    // IMPORTANT NOTE: We used channels 1-5 for attitude mapping in the test below.
386
    // MockLink.params file cannot have flight mode switches mapped to those channels.
387 388 389 390 391
    // 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.
    
392
    for (int function=0; function<RadioComponentController::rcCalFunctionMax; function++) {
393 394 395
        bool found = false;
        
        // If we are mapping this function during cal set it into _rgFunctionChannelMap
396
        for (int channel=0; channel<RadioConfigTest::_availableChannels; channel++) {
397 398 399 400 401
            if (_rgChannelSettings[channel].function == function) {
                
                // First make sure this function isn't being use for a switch
                
                QStringList switchList;
402
                switchList << "RC_MAP_MODE_SW" << "RC_MAP_LOITER_SW" << "RC_MAP_RETURN_SW" << "RC_MAP_POSCTL_SW" << "RC_MAP_ACRO_SW";
403 404
                
                foreach (QString switchParam, switchList) {
Don Gagne's avatar
Don Gagne committed
405
                    Q_ASSERT(_autopilot->getParameterFact(FactSystem::defaultComponentId, switchParam)->value().toInt() != channel + 1);
406 407 408 409 410 411 412 413 414 415 416
                }
                
                _rgFunctionChannelMap[function] = channel;
                found = true;
                
                break;
            }
        }
        
        // If we aren't mapping this function during calibration, set it to the previous setting
        if (!found) {
417 418
            _rgFunctionChannelMap[function] = _autopilot->getParameterFact(FactSystem::defaultComponentId, RadioComponentController::_rgFunctionInfo[function].parameterName)->value().toInt();
            qCDebug(RadioConfigTestLog) << "Assigning switch" << function << _rgFunctionChannelMap[function];
419 420 421 422 423 424 425
            if (_rgFunctionChannelMap[function] == 0) {
                _rgFunctionChannelMap[function] = -1;   // -1 signals no mapping
            } else {
                _rgFunctionChannelMap[function]--;   // parameter is 1-based, _rgFunctionChannelMap is not
            }
        }
    }
Don Gagne's avatar
Don Gagne committed
426 427
    
    _channelHomePosition();
428
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
429
    _beginCalibration();
430 431 432 433 434 435 436 437 438
    _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
439 440
    _switchMinMaxStep();
    _flapsDetectStep();
441 442 443
    _stickMoveAutoStep("Flaps", RadioComponentController::rcCalFunctionFlaps, moveToMin, false /* not identify step */);
    _switchSelectAutoStep("Aux1", RadioComponentController::rcCalFunctionAux1);
    _switchSelectAutoStep("Aux2", RadioComponentController::rcCalFunctionAux2);
444 445

    // One more click and the parameters should get saved
446
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
447
    _validateParameters();
448 449
}

Don Gagne's avatar
Don Gagne committed
450
/// @brief Sets rc input to Throttle down home position. Centers all other channels.
451
void RadioConfigTest::_channelHomePosition(void)
452
{
Don Gagne's avatar
Don Gagne committed
453
    // Initialize available channels to center point.
Don Gagne's avatar
Don Gagne committed
454
    for (int i=0; i<_availableChannels; i++) {
455
        _mockLink->emitRemoteControlChannelRawChanged(i, (float)RadioComponentController::_rcCalPWMCenterPoint);
456
    }
Don Gagne's avatar
Don Gagne committed
457
    
458 459
    // 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.
460
    _mockLink->emitRemoteControlChannelRawChanged(_rgFunctionChannelMap[RadioComponentController::rcCalFunctionThrottle], _testMinValue - 1);
461 462
}

463
void RadioConfigTest::_validateParameters(void)
464 465 466 467 468 469
{
    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
470
    // Check mapping for all fuctions
471
    for (int chanFunction=0; chanFunction<RadioComponentController::rcCalFunctionMax; chanFunction++) {
Don Gagne's avatar
Don Gagne committed
472 473 474 475 476 477 478 479 480
        int chanIndex = _rgFunctionChannelMap[chanFunction];
        
        int expectedParameterValue;
        if (chanIndex == -1) {
            expectedParameterValue = 0;  // 0 signals no mapping
        } else {
            expectedParameterValue = chanIndex + 1; // 1-based parameter value
        }
        
481 482
        qCDebug(RadioConfigTestLog) << "Validate" << chanFunction << _autopilot->getParameterFact(FactSystem::defaultComponentId, RadioComponentController::_rgFunctionInfo[chanFunction].parameterName)->value().toInt();
        QCOMPARE(_autopilot->getParameterFact(FactSystem::defaultComponentId, RadioComponentController::_rgFunctionInfo[chanFunction].parameterName)->value().toInt(), expectedParameterValue);
Don Gagne's avatar
Don Gagne committed
483
    }
Don Gagne's avatar
Don Gagne committed
484 485

    // Validate the channel settings. Note the channels are 1-based in parameter names.
486
    for (int chan = 0; chan<RadioComponentController::_chanMax; chan++) {
Don Gagne's avatar
Don Gagne committed
487 488 489 490
        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
491 492 493 494 495
		int rcMinExpected = _rgChannelSettingsValidate[chan].rcMin;
		int rcMaxExpected = _rgChannelSettingsValidate[chan].rcMax;
		int rcTrimExpected = _rgChannelSettingsValidate[chan].rcTrim;
        bool rcReversedExpected = _rgChannelSettingsValidate[chan].reversed;

Don Gagne's avatar
Don Gagne committed
496
        int rcMinActual = _autopilot->getParameterFact(FactSystem::defaultComponentId, minTpl.arg(oneBasedChannel))->value().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
497
        QCOMPARE(convertOk, true);
Don Gagne's avatar
Don Gagne committed
498
        int rcMaxActual = _autopilot->getParameterFact(FactSystem::defaultComponentId, maxTpl.arg(oneBasedChannel))->value().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
499
        QCOMPARE(convertOk, true);
Don Gagne's avatar
Don Gagne committed
500
        int rcTrimActual = _autopilot->getParameterFact(FactSystem::defaultComponentId, trimTpl.arg(oneBasedChannel))->value().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
501
        QCOMPARE(convertOk, true);
Don Gagne's avatar
Don Gagne committed
502
        float rcReversedFloat = _autopilot->getParameterFact(FactSystem::defaultComponentId, revTpl.arg(oneBasedChannel))->value().toFloat(&convertOk);
Don Gagne's avatar
Don Gagne committed
503 504 505
        QCOMPARE(convertOk, true);
        bool rcReversedActual = (rcReversedFloat == -1.0f);
        
506 507
        qCDebug(RadioConfigTestLog) << "_validateParemeters expected channel:min:max:trim:rev" << chan << rcMinExpected << rcMaxExpected << rcTrimExpected << rcReversedExpected;
        qCDebug(RadioConfigTestLog) << "_validateParemeters actual channel:min:max:trim:rev" << chan << rcMinActual << rcMaxActual << rcTrimActual << rcReversedActual;
508

Don Gagne's avatar
Don Gagne committed
509 510 511 512
        QCOMPARE(rcMinExpected, rcMinActual);
        QCOMPARE(rcMaxExpected, rcMaxActual);
        QCOMPARE(rcTrimExpected, rcTrimActual);
        QCOMPARE(rcReversedExpected, rcReversedActual);
513 514
    }
    
Don Gagne's avatar
Don Gagne committed
515
    // Check mapping for all fuctions
516
    for (int chanFunction=0; chanFunction<RadioComponentController::rcCalFunctionMax; chanFunction++) {
Don Gagne's avatar
Don Gagne committed
517 518 519 520 521
        int expectedValue;
        if (_rgFunctionChannelMap[chanFunction] == -1) {
            expectedValue = 0;  // 0 signals no mapping
        } else {
            expectedValue = _rgFunctionChannelMap[chanFunction] + 1; // 1-based
522
        }
523 524
        // qCDebug(RadioConfigTestLog) << chanFunction << expectedValue << mapParamsSet[RadioComponentController::_rgFunctionInfo[chanFunction].parameterName].toInt();
        QCOMPARE(_autopilot->getParameterFact(FactSystem::defaultComponentId, RadioComponentController::_rgFunctionInfo[chanFunction].parameterName)->value().toInt(), expectedValue);
525
    }
Don Gagne's avatar
Don Gagne committed
526
}