RadioConfigTest.cc 30.9 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 19

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

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

26 27 28 29
// 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) \
{ \
30 31 32 33
    if (_controller->_nextButton->isEnabled() != !!((mask) & nextButtonMask) || \
        _controller->_skipButton->isEnabled() != !!((mask) & skipButtonMask) || \
        _controller->_cancelButton->isEnabled() != !!((mask) & cancelButtonMask) ) { \
        qCDebug(RadioConfigTestLog) << _controller->_statusText->property("text"); \
34
    } \
35 36 37
    QCOMPARE(_controller->_nextButton->isEnabled(), !!((mask) & nextButtonMask)); \
    QCOMPARE(_controller->_skipButton->isEnabled(), !!((mask) & skipButtonMask)); \
    QCOMPARE(_controller->_cancelButton->isEnabled(), !!((mask) & cancelButtonMask)); \
38 39 40 41 42 43
}

// 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
44
    if (mode == testModeStandalone && tryCancel ## cancelNum) { \
45
        QTest::mouseClick(_cancelButton, Qt::LeftButton); \
46
        QCOMPARE(_controller->_rcCalState, RadioComponentController::rcCalStateChannelWait); \
47 48 49 50 51 52 53
        tryCancel ## cancelNum = false; \
        goto StartOver; \
    } else { \
        QTest::mouseClick(_nextButton, Qt::LeftButton); \
    } \
}

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

56 57 58
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
59

Don Gagne's avatar
Don Gagne committed
60
const struct RadioConfigTest::ChannelSettings RadioConfigTest::_rgChannelSettingsPX4[RadioComponentController::_chanMaxPX4] = {
Don Gagne's avatar
Don Gagne committed
61
	// Function										Min                 Max                 #  Reversed
62 63
	
	// Channel 0 : Not mapped to function, Simulate invalid Min/Max
64
	{ RadioComponentController::rcCalFunctionMax,			_testCenterValue,	_testCenterValue,   0, false },
65
	
66
    // Channels 1-4: Mapped to attitude control function
67 68 69 70
    { RadioComponentController::rcCalFunctionRoll,			_testMinValue,      _testMaxValue,      0, true },
    { RadioComponentController::rcCalFunctionPitch,			_testMinValue,      _testMaxValue,      0, false },
    { RadioComponentController::rcCalFunctionYaw,			_testMinValue,      _testMaxValue,      0, true },
    { RadioComponentController::rcCalFunctionThrottle,		_testMinValue,      _testMaxValue,      0,  false },
71
    
72
    // Channels 5-11: Not mapped to function, Simulate invalid Min/Max, since available channel Min/Max is still shown.
73
    // These are here to skip over the flight mode functions
74 75 76 77
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
78 79 80
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,   _testCenterValue,   0,	false },
81 82
	
    // Channel 12 : Not mapped to function, Simulate invalid Min, valid Max
83
    { RadioComponentController::rcCalFunctionMax,			_testCenterValue,	_testMaxValue,      0,  false },
84 85
    
	// Channel 13 : Not mapped to function, Simulate valid Min, invalid Max
86
	{ RadioComponentController::rcCalFunctionMax,           _testMinValue,      _testCenterValue,   0,	false },
87 88
	
    // Channels 14-17: Not mapped to function, Simulate invalid Min/Max, since available channel Min/Max is still shown
89 90 91 92
    { 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
93 94
};

Don Gagne's avatar
Don Gagne committed
95
// Note the: 1500/*RadioComponentController::_rcCalPWMCenterPoint*/ entries. For some reason I couldn't get the compiler to do the
96
// 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
97
const struct RadioConfigTest::ChannelSettings RadioConfigTest::_rgChannelSettingsValidatePX4[RadioComponentController::_chanMaxPX4] = {
Don Gagne's avatar
Don Gagne committed
98
    // Function										Min Value									Max Value									Trim Value										Reversed
99
	
100
    // Channels 0: not mapped and should be set to defaults
101
	{ RadioComponentController::rcCalFunctionMax,			RadioComponentController::_rcCalPWMDefaultMinValue,	RadioComponentController::_rcCalPWMDefaultMaxValue,	1500/*RadioComponentController::_rcCalPWMCenterPoint*/,         false },
102
	
103
    // Channels 1-4: Mapped to attitude control function
104 105 106 107
	{ RadioComponentController::rcCalFunctionRoll,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               true },
    { RadioComponentController::rcCalFunctionPitch,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               false },
    { RadioComponentController::rcCalFunctionYaw,			_testMinValue,                              _testMaxValue,                              _testCenterValue,                               true },
    { RadioComponentController::rcCalFunctionThrottle,		_testMinValue,                              _testMaxValue,                              _testMinValue,                                  false },
108
    
109 110 111 112
    // 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 },
113 114 115 116
    { 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 },
117
	
Don Gagne's avatar
Don Gagne committed
118
	// Channels 12-17 are not mapped and should be set to defaults
119 120 121 122 123 124
	{ 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
125 126
};

Don Gagne's avatar
Don Gagne committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
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 },
165
    { RadioComponentController::rcCalFunctionPitch,			_testMinValue, _testMaxValue, _testCenterValue, true },
Don Gagne's avatar
Don Gagne committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
    { 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 },
};

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

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

    // 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);
200 201
    
    // This will instatiate the widget with an active uas with ready parameters
202
    _calWidget = new QGCQmlWidgetHolder(QString(), NULL);
203
    _calWidget->resize(600, 600);
204
    Q_CHECK_PTR(_calWidget);
205
    _calWidget->setAutoPilot(_autopilot);
206 207 208 209 210 211 212
    QObject* vehicleComponent;
    if (firmwareType == MAV_AUTOPILOT_PX4) {
        vehicleComponent = dynamic_cast<QObject*>(dynamic_cast<PX4AutoPilotPlugin*>(_autopilot)->radioComponent());
    } else {
        vehicleComponent = dynamic_cast<QObject*>(dynamic_cast<APMAutoPilotPlugin*>(_autopilot)->radioComponent());
    }
    _calWidget->setContextPropertyObject("vehicleComponent", vehicleComponent);
213
    _calWidget->setSource(QUrl::fromUserInput("qrc:/qml/RadioComponent.qml"));
214
    
215 216 217
    // Nasty hack to get to controller
    _controller = RadioComponentController::_unitTestController;
    Q_ASSERT(_controller);
Don Gagne's avatar
Don Gagne committed
218

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

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

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

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

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

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

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

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

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

335
void RadioConfigTest::_switchSelectAutoStep(const char* functionStr, RadioComponentController::rcCalFunctions function)
336
{
Don Gagne's avatar
Don Gagne committed
337
    Q_UNUSED(functionStr);
338
    ////qCDebug(RadioConfigTestLog)() << "_switchSelectAutoStep" << functionStr << "function:" << function;
339
    
Don Gagne's avatar
Don Gagne committed
340
    int buttonMask = cancelButtonMask;
341
    if (function != RadioComponentController::rcCalFunctionModeSwitch) {
Don Gagne's avatar
Don Gagne committed
342
        buttonMask |= skipButtonMask;
Don Gagne's avatar
Don Gagne committed
343 344
    }
    
Don Gagne's avatar
Don Gagne committed
345
    CHK_BUTTONS(buttonMask);
Don Gagne's avatar
Don Gagne committed
346
    
347
    int saveStep = _controller->_currentStep;
348
    
Don Gagne's avatar
Don Gagne committed
349 350
    // Wiggle stick for channel
    int channel = _rgFunctionChannelMap[function];
351 352
    _mockLink->emitRemoteControlChannelRawChanged(channel, _testMinValue);
    _mockLink->emitRemoteControlChannelRawChanged(channel, _testMaxValue);
Don Gagne's avatar
Don Gagne committed
353
    
354
    QCOMPARE(_controller->_currentStep, saveStep + 1);
355 356
}

Don Gagne's avatar
Don Gagne committed
357
void RadioConfigTest::_fullCalibrationWorker(MAV_AUTOPILOT firmwareType)
358
{
Don Gagne's avatar
Don Gagne committed
359 360
    _init(firmwareType);

361
    // IMPORTANT NOTE: We used channels 1-5 for attitude mapping in the test below.
362
    // MockLink.params file cannot have flight mode switches mapped to those channels.
363 364 365 366 367
    // 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.
    
368
    for (int function=0; function<RadioComponentController::rcCalFunctionMax; function++) {
369 370 371
        bool found = false;
        
        // If we are mapping this function during cal set it into _rgFunctionChannelMap
Don Gagne's avatar
Don Gagne committed
372 373
        for (int channel=0; channel<_chanMax(); channel++) {
            if (_channelSettings()[channel].function == function) {
374
                
Don Gagne's avatar
Don Gagne committed
375 376 377 378 379
                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";

380
                    foreach (const QString &switchParam, switchList) {
381
                        Q_ASSERT(_vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, switchParam)->rawValue().toInt() != channel + 1);
Don Gagne's avatar
Don Gagne committed
382
                    }
383 384 385 386 387 388 389 390 391 392 393
                }
                
                _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
394 395
            const char* paramName = _functionInfo()[function].parameterName;
            if (paramName) {
396
                _rgFunctionChannelMap[function] = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, paramName)->rawValue().toInt();
Don Gagne's avatar
Don Gagne committed
397 398 399 400 401 402
                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
                }
403
            } else {
Don Gagne's avatar
Don Gagne committed
404
                _rgFunctionChannelMap[function] = -1;   // -1 signals no mapping
405 406 407
            }
        }
    }
Don Gagne's avatar
Don Gagne committed
408 409
    
    _channelHomePosition();
410
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
411
    _beginCalibration();
412 413 414 415 416 417 418 419 420
    _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
421
    _switchMinMaxStep();
422 423

    // One more click and the parameters should get saved
424
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
425
    _validateParameters();
426 427
}

Don Gagne's avatar
Don Gagne committed
428 429 430 431 432 433 434 435 436 437 438
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
439
/// @brief Sets rc input to Throttle down home position. Centers all other channels.
440
void RadioConfigTest::_channelHomePosition(void)
441
{
Don Gagne's avatar
Don Gagne committed
442
    // Initialize available channels to center point.
Don Gagne's avatar
Don Gagne committed
443
    for (int i=0; i<_chanMax(); i++) {
444
        _mockLink->emitRemoteControlChannelRawChanged(i, (float)RadioComponentController::_rcCalPWMCenterPoint);
445
    }
Don Gagne's avatar
Don Gagne committed
446
    
447 448
    // 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.
449
    _mockLink->emitRemoteControlChannelRawChanged(_rgFunctionChannelMap[RadioComponentController::rcCalFunctionThrottle], _testMinValue - 1);
450 451
}

452
void RadioConfigTest::_validateParameters(void)
453 454 455 456 457 458
{
    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
459
    // Check mapping for all fuctions
460
    for (int chanFunction=0; chanFunction<RadioComponentController::rcCalFunctionMax; chanFunction++) {
Don Gagne's avatar
Don Gagne committed
461 462 463 464 465 466 467 468 469
        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
470 471
        const char* paramName = _functionInfo()[chanFunction].parameterName;
        if (paramName) {
472 473
            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
474
        }
Don Gagne's avatar
Don Gagne committed
475
    }
Don Gagne's avatar
Don Gagne committed
476 477

    // Validate the channel settings. Note the channels are 1-based in parameter names.
Don Gagne's avatar
Don Gagne committed
478
    for (int chan = 0; chan<_chanMax(); chan++) {
Don Gagne's avatar
Don Gagne committed
479 480 481 482
        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
483 484 485 486
        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
487

488
        int rcMinActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, minTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
489
        QCOMPARE(convertOk, true);
490
        int rcMaxActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, maxTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
491
        QCOMPARE(convertOk, true);
492
        int rcTrimActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, trimTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
493
        QCOMPARE(convertOk, true);
494
        float rcReversedFloat = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, revTpl.arg(oneBasedChannel))->rawValue().toFloat(&convertOk);
Don Gagne's avatar
Don Gagne committed
495 496 497
        QCOMPARE(convertOk, true);
        bool rcReversedActual = (rcReversedFloat == -1.0f);
        
Lorenz Meier's avatar
Lorenz Meier committed
498 499
        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;
500

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

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