/*===================================================================== QGroundControl Open Source Ground Control Station (c) 2009 - 2014 QGROUNDCONTROL PROJECT 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 . ======================================================================*/ #include "PX4RCCalibrationTest.h" #include "UASManager.h" #include "MockQGCUASParamManager.h" /// @file /// @brief QPX4RCCalibration Widget unit test /// /// @author Don Gagne // 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) \ { \ if (_nextButton->isEnabled() != !!((mask) & nextButtonMask) || \ _skipButton->isEnabled() != !!((mask) & skipButtonMask) || \ _cancelButton->isEnabled() != !!((mask) & cancelButtonMask) || \ _tryAgainButton->isEnabled() != !!((mask) & tryAgainButtonMask)) { \ qDebug() << _statusLabel->text(); \ } \ QCOMPARE(_nextButton->isEnabled(), !!((mask) & nextButtonMask)); \ QCOMPARE(_skipButton->isEnabled(), !!((mask) & skipButtonMask)); \ QCOMPARE(_cancelButton->isEnabled(), !!((mask) & cancelButtonMask)); \ QCOMPARE(_tryAgainButton->isEnabled(), !!((mask) & tryAgainButtonMask)); \ } // 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) \ { \ if (mode == testModeStandalone && tryCancel ## cancelNum) { \ QTest::mouseClick(_cancelButton, Qt::LeftButton); \ QCOMPARE(_calWidget->_rcCalState, PX4RCCalibration::rcCalStateChannelWait); \ tryCancel ## cancelNum = false; \ goto StartOver; \ } else { \ QTest::mouseClick(_nextButton, Qt::LeftButton); \ } \ } const int PX4RCCalibrationTest::_testMinValue = PX4RCCalibration::_rcCalPWMDefaultMinValue + 10; const int PX4RCCalibrationTest::_testMaxValue = PX4RCCalibration::_rcCalPWMDefaultMaxValue - 10; const int PX4RCCalibrationTest::_testTrimValue = PX4RCCalibration::_rcCalPWMDefaultTrimValue + 10; const int PX4RCCalibrationTest::_testThrottleTrimValue = PX4RCCalibration::_rcCalPWMDefaultMinValue + 10; const struct PX4RCCalibrationTest::ChannelSettings PX4RCCalibrationTest::_rgChannelSettingsPreValidate[PX4RCCalibrationTest::_availableChannels] = { //Min Value Max Value Trim Value Reversed MinMaxShown MinValid MaxValid // Channel 0 : rcCalFunctionRoll { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibrationTest::_testTrimValue, false, true, true, true }, // Channel 1 : rcCalFunctionPitch { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibrationTest::_testTrimValue, false, true, true, true }, // Channel 2 : rcCalFunctionYaw { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibrationTest::_testTrimValue, false, true, true, true }, // Channel 3 : rcCalFunctionThrottle { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibrationTest::_testThrottleTrimValue, false, true, true, true }, // Channel 4 : rcCalFunctionModeSwitch { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibration::_rcCalPWMCenterPoint, false, true, true, true }, // Channel 5 : Simulate invalid Min, valid Max { PX4RCCalibration::_rcCalPWMCenterPoint, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMCenterPoint, false, true, false, true }, // Channels 6-7: Invalid Min/Max, since available channel Min/Max is still shown { PX4RCCalibration::_rcCalPWMCenterPoint, PX4RCCalibration::_rcCalPWMCenterPoint, PX4RCCalibration::_rcCalPWMCenterPoint, false, true, false, false }, { PX4RCCalibration::_rcCalPWMCenterPoint, PX4RCCalibration::_rcCalPWMCenterPoint, PX4RCCalibration::_rcCalPWMCenterPoint, false, true, false, false }, }; const struct PX4RCCalibrationTest::ChannelSettings PX4RCCalibrationTest::_rgChannelSettingsPostValidate[PX4RCCalibration::_chanMax] = { // Min Value Max Value Trim Value Reversed MinMaxShown MinValid MaxValid // Channel 0 : rcCalFunctionRoll { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibrationTest::_testTrimValue, false, true, true, true }, // Channel 1 : rcCalFunctionPitch { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibrationTest::_testTrimValue, false, true, true, true }, // Channel 2 : rcCalFunctionYaw { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibrationTest::_testTrimValue, false, true, true, true }, // Channel 3 : rcCalFunctionThrottle { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibrationTest::_testThrottleTrimValue, false, true, true, true }, // Channel 4 : rcCalFunctionModeSwitch { PX4RCCalibrationTest::_testMinValue, PX4RCCalibrationTest::_testMaxValue, PX4RCCalibration::_rcCalPWMCenterPoint, false, true, true, true }, // Channel 5 : Simulate invalid Min, valid Max, validation should switch back to defaults { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, true, true, true }, // Channels 6-7: Invalid Min/Max, since available channel Min/Max is still shown, validation will set to defaults { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, true, true, true }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, true, true, true }, // We are simulating an 8-channel radio, all other channel should be defaulted { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, { PX4RCCalibration::_rcCalPWMDefaultMinValue, PX4RCCalibration::_rcCalPWMDefaultMaxValue, PX4RCCalibration::_rcCalPWMDefaultTrimValue, false, false, false, false }, }; PX4RCCalibrationTest::PX4RCCalibrationTest(void) : _mockUASManager(NULL), _calWidget(NULL) { } /// @brief Called one time before any test cases are run. void PX4RCCalibrationTest::initTestCase(void) { // The test case code makes the following assumptions about PX4RCCalibration class internals. // Make sure these don't change out from under us. Q_ASSERT(PX4RCCalibration::rcCalFunctionRoll == 0); Q_ASSERT(PX4RCCalibration::rcCalFunctionPitch == 1); Q_ASSERT(PX4RCCalibration::rcCalFunctionYaw == 2); Q_ASSERT(PX4RCCalibration::rcCalFunctionThrottle == 3); Q_ASSERT(PX4RCCalibration::rcCalFunctionModeSwitch == 4); // We only set min/max for required channels. Make sure the set of required channels doesn't change out from under us. for (int chanFunction=0; chanFunctionsetMockActiveUAS(_mockUAS); // Get pointers to the push buttons _cancelButton = _calWidget->findChild("rcCalCancel"); _nextButton = _calWidget->findChild("rcCalNext"); _skipButton = _calWidget->findChild("rcCalSkip"); _tryAgainButton = _calWidget->findChild("rcCalTryAgain"); Q_ASSERT(_cancelButton); Q_ASSERT(_nextButton); Q_ASSERT(_skipButton); Q_ASSERT(_tryAgainButton); _statusLabel = _calWidget->findChild("rcCalStatus"); Q_ASSERT(_statusLabel); for (size_t i=0; ifindChild(radioWidgetName.arg(i+1)); Q_ASSERT(radioWidget); _rgRadioWidget[i] = radioWidget; } } void PX4RCCalibrationTest::cleanup(void) { Q_ASSERT(_mockUAS); delete _mockUAS; UASManager::setMockUASManager(NULL); Q_ASSERT(_mockUASManager); delete _mockUASManager; Q_ASSERT(_calWidget); delete _calWidget; } /// @brief Tests for correct behavior when active UAS is set into widget. void PX4RCCalibrationTest::_setUAS_test(void) { // Widget is initialized with UAS, so it should be enabled QCOMPARE(_calWidget->isEnabled(), true); // Take away the UAS and widget should disable _mockUASManager->setMockActiveUAS(NULL); QCOMPARE(_calWidget->isEnabled(), false); } /// @brief Test for correct behavior in determining minimum numbers of channels for fligth. void PX4RCCalibrationTest::_minRCChannels_test(void) { // Next button won't be enabled until we see the minimum number of channels. for (int i=0; iemitRemoteControlChannelRawChanged(i, (float)PX4RCCalibration::_rcCalPWMCenterPoint); // We use _chanCount internally so we should validate it QCOMPARE(_calWidget->_chanCount, i+1); // Validate Next button state if (i == PX4RCCalibration::_chanMinimum - 1) { // Last channel should trigger enable CHK_BUTTONS(nextButtonMask); } else { // Still less than the minimum channels CHK_BUTTONS(0); } // Only available channels should have enabled widget. A ui update cycle needs to have passed so we wait a little. QTest::qWait(PX4RCCalibration::_updateInterval * 2); for (int chanWidget=0; chanWidgetisEnabled(), !!(chanWidget <= i)); } } } #if 0 /// @brief Tests that even when not calibrating the channel display is live void PX4RCCalibrationTest::_liveRC_test(void) { for (int i=0; iemitRemoteControlChannelRawChanged(i, (float)PX4RCCalibration::_rcCalPWMValidMaxValue); } for (int i=0; ivalue(), PX4RCCalibration::_rcCalPWMValidMinValue); QCOMPARE(radioWidget->max(), PX4RCCalibration::_rcCalPWMValidMaxValue); } } #endif void PX4RCCalibrationTest::_beginState_worker(enum TestMode mode) { bool tryCancel1 = true; StartOver: if (mode == testModeStandalone || mode == testModePrerequisite) { _centerChannels(); _calWidget->_unitTestForceCalState(PX4RCCalibration::rcCalStateBegin); } // Next button is always enabled in this state CHK_BUTTONS(nextButtonMask | cancelButtonMask); // Click the next button: // We should now be waiting for movement on a channel to identify the first RC function. The Next button will stay // disabled until the sticks are moved enough to identify the channel. For required functions the Skip button is // disabled. NEXT_OR_CANCEL(1); QCOMPARE(_calWidget->_rcCalState, PX4RCCalibration::rcCalStateIdentify); CHK_BUTTONS(cancelButtonMask); } void PX4RCCalibrationTest::_beginState_test(void) { _beginState_worker(testModeStandalone); } void PX4RCCalibrationTest::_identifyState_worker(enum TestMode mode) { bool tryCancel1 = true; StartOver: if (mode == testModeStandalone || mode == testModePrerequisite) { _centerChannels(); _calWidget->_unitTestForceCalState(PX4RCCalibration::rcCalStateIdentify); } // Loop over all function idenitfying required channels for (int i=0; iemitRemoteControlChannelRawChanged(i, (float)PX4RCCalibration::_rcCalPWMCenterPoint + (PX4RCCalibration::_rcCalMoveDelta - 2.0f)); CHK_BUTTONS(cancelButtonMask | skipMask); if (i != 0) { // Try to assign a channel 0 to more than one function. This is not allowed so Next button should not enable. _mockUAS->emitRemoteControlChannelRawChanged(0, (float)PX4RCCalibration::_rcCalPWMValidMinValue); _mockUAS->emitRemoteControlChannelRawChanged(0, (float)PX4RCCalibration::_rcCalPWMValidMaxValue); CHK_BUTTONS(cancelButtonMask | skipMask); } if (tryCancel1) { NEXT_OR_CANCEL(1); } // Move channel larger than delta to identify channel. We should now be sitting in a found state. _mockUAS->emitRemoteControlChannelRawChanged(i, (float)PX4RCCalibration::_rcCalPWMCenterPoint + (PX4RCCalibration::_rcCalMoveDelta + 2.0f)); CHK_BUTTONS(cancelButtonMask | tryAgainButtonMask | nextButtonMask); NEXT_OR_CANCEL(1); } // We should now be waiting for min/max values. QCOMPARE(_calWidget->_rcCalState, PX4RCCalibration::rcCalStateMinMax); CHK_BUTTONS(nextButtonMask | cancelButtonMask); if (mode == testModeStandalone) { _calWidget->_writeCalibration(false /* !trimsOnly */); _validateParameters(validateMappingMask); } } void PX4RCCalibrationTest::_identifyState_test(void) { _identifyState_worker(testModeStandalone); } void PX4RCCalibrationTest::_minMaxState_worker(enum TestMode mode) { bool tryCancel1 = true; StartOver: if (mode == testModeStandalone || mode == testModePrerequisite) { // The Min/Max calibration updates the radio channel ui widgets with the min/max values as you move the sticks. // In order for the roll/pitch/yaw/throttle radio channel ui widgets to be updated correctly those functions // must be alread mapped to a channel. So we have to run the _identifyState_test first to set up the internal // state correctly. _identifyState_worker(testModePrerequisite); _centerChannels(); _calWidget->_unitTestForceCalState(PX4RCCalibration::rcCalStateMinMax); // We should now be waiting for min/max values. CHK_BUTTONS(nextButtonMask | cancelButtonMask); } // Before we start sending rc values the widgets should all have min/max as invalid for (int chan=0; chanisMinValid(), false); QCOMPARE(_rgRadioWidget[chan]->isMaxValid(), false); } // Try setting a min/max value that is below the threshold to make sure min/max doesn't go valid _mockUAS->emitRemoteControlChannelRawChanged(0, (float)(PX4RCCalibration::_rcCalPWMValidMinValue + 1)); _mockUAS->emitRemoteControlChannelRawChanged(0, (float)(PX4RCCalibration::_rcCalPWMValidMaxValue - 1)); QCOMPARE(_rgRadioWidget[0]->isMinValid(), false); QCOMPARE(_rgRadioWidget[0]->isMaxValid(), false); // Send min/max values for (int chan=0; chan<_minMaxChannels; chan++) { // Send Min/Max _mockUAS->emitRemoteControlChannelRawChanged(chan, (float)_rgChannelSettingsPreValidate[chan].rcMin); _mockUAS->emitRemoteControlChannelRawChanged(chan, (float)_rgChannelSettingsPreValidate[chan].rcMax); } _validateWidgets(validateMinMaxMask, _rgChannelSettingsPreValidate); // Make sure throttle is at min _mockUAS->emitRemoteControlChannelRawChanged(PX4RCCalibration::rcCalFunctionThrottle, (float)PX4RCCalibration::_rcCalPWMValidMinValue); // Click the next button: We should now be waiting for center throttle in prep for inversion detection. // Throttle channel is at minimum so Next button should be disabled. NEXT_OR_CANCEL(1); QCOMPARE(_calWidget->_rcCalState, PX4RCCalibration::rcCalStateCenterThrottle); CHK_BUTTONS(cancelButtonMask); if (mode == testModeStandalone) { _calWidget->_writeCalibration(false /* !trimsOnly */); _validateParameters(validateMinMaxMask); } } void PX4RCCalibrationTest::_minMaxState_test(void) { _minMaxState_worker(testModeStandalone); } void PX4RCCalibrationTest::_centerThrottleState_worker(enum TestMode mode) { bool tryCancel1 = true; StartOver: if (mode == testModeStandalone || mode == testModePrerequisite) { // In order to perform the center throttle state test the throttle channel has to have been identified. // So we have to run the _identifyState_test first to set up the internal state correctly. _identifyState_worker(testModePrerequisite); _centerChannels(); _mockUAS->emitRemoteControlChannelRawChanged(PX4RCCalibration::rcCalFunctionThrottle, (float)PX4RCCalibration::_rcCalPWMValidMinValue); _calWidget->_unitTestForceCalState(PX4RCCalibration::rcCalStateCenterThrottle); // We should now be waiting for center throttle in prep for inversion detection. // Throttle channel is at minimum so Next button should be disabled. CHK_BUTTONS(cancelButtonMask); } // Move the throttle to just below rough center. Next should still be disabled _mockUAS->emitRemoteControlChannelRawChanged(PX4RCCalibration::rcCalFunctionThrottle, PX4RCCalibration::_rcCalPWMCenterPoint - PX4RCCalibration::_rcCalRoughCenterDelta - 1); CHK_BUTTONS(cancelButtonMask); // Center the throttle and make sure Next button gets enabled _mockUAS->emitRemoteControlChannelRawChanged(PX4RCCalibration::rcCalFunctionThrottle, PX4RCCalibration::_rcCalPWMCenterPoint); CHK_BUTTONS(cancelButtonMask | nextButtonMask); // Click the next button which should take us to our first channel inversion test. The Next button will stay disabled until // the stick for the specified channel is moved down. NEXT_OR_CANCEL(1); QCOMPARE(_calWidget->_rcCalState, PX4RCCalibration::rcCalStateDetectInversion); CHK_BUTTONS(cancelButtonMask); } void PX4RCCalibrationTest::_centerThrottleState_test(void) { _centerThrottleState_worker(testModeStandalone); } void PX4RCCalibrationTest::_detectInversionState_worker(enum TestMode mode) { bool tryCancel1 = true; bool tryCancel2 = true; StartOver: if (mode == testModeStandalone || mode == testModePrerequisite) { // In order to perform the detect inversion test the roll/pitch/yaw/throttle functions must be mapped to a channel. // So we have to run the _identifyState_test first to set up the internal state correctly. _identifyState_worker(testModePrerequisite); _centerChannels(); _calWidget->_unitTestForceCalState(PX4RCCalibration::rcCalStateDetectInversion); // We should now be at the first channel inversion test. The Next button will stay disabled until the stick for the specified // channel is moved in the appropriate direction. CHK_BUTTONS(cancelButtonMask); } // Loop over Attitude Control Functions (roll/yaw/pitch/throttle) to detect inversion for (int chanFunction=PX4RCCalibration::rcCalFunctionFirstAttitudeFunction; chanFunction<=PX4RCCalibration::rcCalFunctionLastAttitudeFunction; chanFunction++) { if (chanFunction != 0) { // Click next to move to next inversion to identify NEXT_OR_CANCEL(1); CHK_BUTTONS(cancelButtonMask); } // Move all channels except for the one we are trying to detect to min and max value to make sure there is no effect. for (int chan=0; chan<_availableChannels; chan++) { if (chanFunction != chan) { _mockUAS->emitRemoteControlChannelRawChanged(chan, (float)PX4RCCalibration::_rcCalPWMCenterPoint + (PX4RCCalibration::_rcCalMoveDelta + 2.0f)); _mockUAS->emitRemoteControlChannelRawChanged(chan, (float)PX4RCCalibration::_rcCalPWMCenterPoint - (PX4RCCalibration::_rcCalMoveDelta + 2.0f)); CHK_BUTTONS(cancelButtonMask); // Make sure to re-center for next inversion detect _mockUAS->emitRemoteControlChannelRawChanged(chan, (float)PX4RCCalibration::_rcCalPWMCenterPoint); } } // Move the channel we are detecting inversion on to the min value which should indicate no inversion. // This should put us in the found state and enable the Next button. _mockUAS->emitRemoteControlChannelRawChanged(chanFunction, (float)PX4RCCalibration::_rcCalPWMCenterPoint - (PX4RCCalibration::_rcCalMoveDelta + 2.0f)); CHK_BUTTONS(cancelButtonMask | tryAgainButtonMask | nextButtonMask); } // Click the next button: We should now be waiting for low throttle in prep for trim detection. // Throttle channel is at minimum so Next button should be disabled. _centerChannels(); NEXT_OR_CANCEL(2); QCOMPARE(_calWidget->_rcCalState, PX4RCCalibration::rcCalStateTrims); CHK_BUTTONS(cancelButtonMask); if (mode == testModeStandalone) { _calWidget->_writeCalibration(false /* !trimsOnly */); _validateParameters(validateMappingMask | validateReversedMask); } } void PX4RCCalibrationTest::_detectInversionState_test(void) { _detectInversionState_worker(testModeStandalone); } void PX4RCCalibrationTest::_trimsState_worker(enum TestMode mode) { bool tryCancel1 = true; StartOver: if (mode == testModeStandalone || mode == testModePrerequisite) { // In order to perform the trim state test the functions must be mapped and the min/max values must be set. // So we have to run the _minMaxState_test first to set up the internal state correctly. _minMaxState_worker(testModePrerequisite); _centerChannels(); _calWidget->_unitTestForceCalState(PX4RCCalibration::rcCalStateTrims); // We should now be waiting for low throttle. CHK_BUTTONS(cancelButtonMask); } // Send trim values to attitude control function channels for (int chan=0; chan<_attitudeChannels; chan++) { _mockUAS->emitRemoteControlChannelRawChanged(chan, _rgChannelSettingsPreValidate[chan].rcTrim); } _validateWidgets(validateTrimsMask, _rgChannelSettingsPreValidate); // Throttle trim was set, so next should be enabled CHK_BUTTONS(cancelButtonMask | nextButtonMask); // Click the next button which should set Trims and take us the Save step. NEXT_OR_CANCEL(1); QCOMPARE(_calWidget->_rcCalState, PX4RCCalibration::rcCalStateSave); CHK_BUTTONS(cancelButtonMask | nextButtonMask); _validateWidgets(validateTrimsMask, _rgChannelSettingsPostValidate); if (mode == testModeStandalone) { _calWidget->_writeCalibration(false /* !trimsOnly */); _validateParameters(validateTrimsMask); } } void PX4RCCalibrationTest::_trimsState_test(void) { _trimsState_worker(testModeStandalone); } void PX4RCCalibrationTest::_fullCalibration_test(void) { _centerChannels(); QTest::mouseClick(_nextButton, Qt::LeftButton); _beginState_worker(testModeFullSequence); _identifyState_worker(testModeFullSequence); _minMaxState_worker(testModeFullSequence); _centerThrottleState_worker(testModeFullSequence); _detectInversionState_worker(testModeFullSequence); _trimsState_worker(testModeFullSequence); // One more click and the parameters should get saved QTest::mouseClick(_nextButton, Qt::LeftButton); _validateParameters(validateAllMask); _validateWidgets(validateAllMask, _rgChannelSettingsPostValidate); } /// @brief Sends RC center point values on minimum set of channels. void PX4RCCalibrationTest::_centerChannels(void) { // Initialize available channels them to center point. This should also set the channel count above the // minimum such that we can enter the idle state. for (int i=0; i<_availableChannels; i++) { _mockUAS->emitRemoteControlChannelRawChanged(i, (float)PX4RCCalibration::_rcCalPWMCenterPoint); } } void PX4RCCalibrationTest::_validateParameters(int validateMask) { MockQGCUASParamManager* paramMgr = _mockUAS->getMockQGCUASParamManager(); MockQGCUASParamManager::ParamMap_t mapParamsSet = paramMgr->getMockSetParameters(); QString minTpl("RC%1_MIN"); QString maxTpl("RC%1_MAX"); QString trimTpl("RC%1_TRIM"); QString revTpl("RC%1_REV"); // Check mapping for all fuctions for (int chanFunction=0; chanFunction= PX4RCCalibration::rcCalFunctionFirstAttitudeFunction && chan <= PX4RCCalibration::rcCalFunctionLastAttitudeFunction) { if (chan == PX4RCCalibration::rcCalFunctionThrottle) { rcTrimExpected = _testThrottleTrimValue; } else { rcTrimExpected = _testTrimValue; } } else { rcTrimExpected = PX4RCCalibration::_rcCalPWMDefaultTrimValue; } if (validateMask & validateMinMaxMask) { QCOMPARE(mapParamsSet.contains(minTpl.arg(oneBasedChannel)), true); QCOMPARE(mapParamsSet.contains(maxTpl.arg(oneBasedChannel)), true); QCOMPARE(mapParamsSet[minTpl.arg(oneBasedChannel)].toInt(&convertOk), rcMinExpected); QCOMPARE(convertOk, true); QCOMPARE(mapParamsSet[maxTpl.arg(oneBasedChannel)].toInt(&convertOk), rcMaxExpected); QCOMPARE(convertOk, true); } if (validateMask & validateTrimsMask) { QCOMPARE(mapParamsSet.contains(trimTpl.arg(oneBasedChannel)), true); QCOMPARE(mapParamsSet[trimTpl.arg(oneBasedChannel)].toInt(&convertOk), rcTrimExpected); QCOMPARE(convertOk, true); } // No channels are reversed if (validateMask & validateReversedMask) { QCOMPARE(mapParamsSet.contains(revTpl.arg(oneBasedChannel)), true); QCOMPARE(mapParamsSet[revTpl.arg(oneBasedChannel)].toFloat(&convertOk), 1.0f /* not reversed */); QCOMPARE(convertOk, true); } } if (validateMask & validateMappingMask) { // Check mapping for all fuctions for (int chanFunction=0; chanFunctionisMinMaxShown(), rgChannelSettings[chan].isMinMaxShown); QCOMPARE(radioWidget->min(), rgChannelSettings[chan].rcMin); QCOMPARE(radioWidget->max(), rgChannelSettings[chan].rcMax); QCOMPARE(radioWidget->isMinValid(), rgChannelSettings[chan].isMinValid); QCOMPARE(radioWidget->isMaxValid(), rgChannelSettings[chan].isMaxValid); } if (validateMask & validateTrimsMask) { QCOMPARE(radioWidget->trim(), rgChannelSettings[chan].rcTrim); } } for (int chan=_availableChannels; chanisEnabled(), false); } }