RadioConfigTest.cc 30.2 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
}

Don Gagne's avatar
Don Gagne committed
335
void RadioConfigTest::_fullCalibrationWorker(MAV_AUTOPILOT firmwareType)
336
{
Don Gagne's avatar
Don Gagne committed
337 338
    _init(firmwareType);

339
    // IMPORTANT NOTE: We used channels 1-5 for attitude mapping in the test below.
340
    // MockLink.params file cannot have flight mode switches mapped to those channels.
341 342 343 344 345
    // 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.
    
346
    for (int function=0; function<RadioComponentController::rcCalFunctionMax; function++) {
347 348 349
        bool found = false;
        
        // If we are mapping this function during cal set it into _rgFunctionChannelMap
Don Gagne's avatar
Don Gagne committed
350 351
        for (int channel=0; channel<_chanMax(); channel++) {
            if (_channelSettings()[channel].function == function) {
352
                
Don Gagne's avatar
Don Gagne committed
353 354 355 356 357
                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";

358
                    foreach (const QString &switchParam, switchList) {
359
                        Q_ASSERT(_vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, switchParam)->rawValue().toInt() != channel + 1);
Don Gagne's avatar
Don Gagne committed
360
                    }
361 362 363 364 365 366 367 368 369 370 371
                }
                
                _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
372 373
            const char* paramName = _functionInfo()[function].parameterName;
            if (paramName) {
374
                _rgFunctionChannelMap[function] = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, paramName)->rawValue().toInt();
Don Gagne's avatar
Don Gagne committed
375 376 377 378 379 380
                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
                }
381
            } else {
Don Gagne's avatar
Don Gagne committed
382
                _rgFunctionChannelMap[function] = -1;   // -1 signals no mapping
383 384 385
            }
        }
    }
Don Gagne's avatar
Don Gagne committed
386 387
    
    _channelHomePosition();
388
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
389
    _beginCalibration();
390 391 392 393 394 395 396 397 398
    _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
399
    _switchMinMaxStep();
400 401

    // One more click and the parameters should get saved
402
    _controller->nextButtonClicked();
Don Gagne's avatar
Don Gagne committed
403
    _validateParameters();
404 405
}

Don Gagne's avatar
Don Gagne committed
406 407 408 409 410 411 412 413 414 415 416
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
417
/// @brief Sets rc input to Throttle down home position. Centers all other channels.
418
void RadioConfigTest::_channelHomePosition(void)
419
{
Don Gagne's avatar
Don Gagne committed
420
    // Initialize available channels to center point.
Don Gagne's avatar
Don Gagne committed
421
    for (int i=0; i<_chanMax(); i++) {
422
        _mockLink->emitRemoteControlChannelRawChanged(i, (float)RadioComponentController::_rcCalPWMCenterPoint);
423
    }
Don Gagne's avatar
Don Gagne committed
424
    
425 426
    // 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.
427
    _mockLink->emitRemoteControlChannelRawChanged(_rgFunctionChannelMap[RadioComponentController::rcCalFunctionThrottle], _testMinValue - 1);
428 429
}

430
void RadioConfigTest::_validateParameters(void)
431 432 433 434 435 436
{
    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
437
    // Check mapping for all fuctions
438
    for (int chanFunction=0; chanFunction<RadioComponentController::rcCalFunctionMax; chanFunction++) {
Don Gagne's avatar
Don Gagne committed
439 440 441 442 443 444 445 446 447
        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
448 449
        const char* paramName = _functionInfo()[chanFunction].parameterName;
        if (paramName) {
450 451
            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
452
        }
Don Gagne's avatar
Don Gagne committed
453
    }
Don Gagne's avatar
Don Gagne committed
454 455

    // Validate the channel settings. Note the channels are 1-based in parameter names.
Don Gagne's avatar
Don Gagne committed
456
    for (int chan = 0; chan<_chanMax(); chan++) {
Don Gagne's avatar
Don Gagne committed
457 458 459 460
        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
461 462 463 464
        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
465

466
        int rcMinActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, minTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
467
        QCOMPARE(convertOk, true);
468
        int rcMaxActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, maxTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
469
        QCOMPARE(convertOk, true);
470
        int rcTrimActual = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, trimTpl.arg(oneBasedChannel))->rawValue().toInt(&convertOk);
Don Gagne's avatar
Don Gagne committed
471
        QCOMPARE(convertOk, true);
472
        float rcReversedFloat = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, revTpl.arg(oneBasedChannel))->rawValue().toFloat(&convertOk);
Don Gagne's avatar
Don Gagne committed
473 474 475
        QCOMPARE(convertOk, true);
        bool rcReversedActual = (rcReversedFloat == -1.0f);
        
Lorenz Meier's avatar
Lorenz Meier committed
476 477
        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;
478

Don Gagne's avatar
Don Gagne committed
479 480 481 482
        QCOMPARE(rcMinExpected, rcMinActual);
        QCOMPARE(rcMaxExpected, rcMaxActual);
        QCOMPARE(rcTrimExpected, rcTrimActual);
        QCOMPARE(rcReversedExpected, rcReversedActual);
483 484
    }
    
Don Gagne's avatar
Don Gagne committed
485
    // Check mapping for all fuctions
486
    for (int chanFunction=0; chanFunction<RadioComponentController::rcCalFunctionMax; chanFunction++) {
Don Gagne's avatar
Don Gagne committed
487 488 489 490 491
        int expectedValue;
        if (_rgFunctionChannelMap[chanFunction] == -1) {
            expectedValue = 0;  // 0 signals no mapping
        } else {
            expectedValue = _rgFunctionChannelMap[chanFunction] + 1; // 1-based
492
        }
Don Gagne's avatar
Don Gagne committed
493 494 495
        const char* paramName = _functionInfo()[chanFunction].parameterName;
        if (paramName) {
            // qCDebug(RadioConfigTestLog) << chanFunction << expectedValue << mapParamsSet[paramName].toInt();
496
            QCOMPARE(_vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, paramName)->rawValue().toInt(), expectedValue);
Don Gagne's avatar
Don Gagne committed
497
        }
498
    }
Don Gagne's avatar
Don Gagne committed
499
}
Don Gagne's avatar
Don Gagne committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524

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