MissionCommandTree.cc 10.3 KB
Newer Older
1 2 3

/****************************************************************************
 *
Gus Grubba's avatar
Gus Grubba committed
4
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/


#include "MissionCommandTree.h"
#include "FactMetaData.h"
#include "Vehicle.h"
#include "FirmwarePluginManager.h"
#include "QGCApplication.h"
#include "MissionCommandUIInfo.h"
#include "MissionCommandList.h"
19
#include "SettingsManager.h"
20 21 22

#include <QQmlEngine>

23 24
MissionCommandTree::MissionCommandTree(QGCApplication* app, QGCToolbox* toolbox, bool unitTest)
    : QGCTool(app, toolbox)
25
    , _allCommandsCategory(tr("All commands"))
26
    , _settingsManager(nullptr)
27 28 29 30 31 32 33 34
    , _unitTest(unitTest)
{
}

void MissionCommandTree::setToolbox(QGCToolbox* toolbox)
{
    QGCTool::setToolbox(toolbox);

35 36
    _settingsManager = toolbox->settingsManager();

37 38 39
#ifdef UNITTEST_BUILD
    if (_unitTest) {
        // Load unit testing tree
40 41 42 43 44 45
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_GENERIC] =           new MissionCommandList(":/unittest/UT-MavCmdInfoCommon.json", true, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_FIXED_WING] =        new MissionCommandList(":/unittest/UT-MavCmdInfoFixedWing.json", false, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_QUADROTOR] =         new MissionCommandList(":/unittest/UT-MavCmdInfoMultiRotor.json", false, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_VTOL_QUADROTOR] =    new MissionCommandList(":/unittest/UT-MavCmdInfoVTOL.json", false, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_SUBMARINE] =         new MissionCommandList(":/unittest/UT-MavCmdInfoSub.json", false, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_GROUND_ROVER] =      new MissionCommandList(":/unittest/UT-MavCmdInfoRover.json", false, this);
46 47 48
    } else {
#endif
        // Load all levels of hierarchy
49
        for (MAV_AUTOPILOT firmwareType: _toolbox->firmwarePluginManager()->supportedFirmwareTypes()) {
50 51 52 53 54
            FirmwarePlugin* plugin = _toolbox->firmwarePluginManager()->firmwarePluginForAutopilot(firmwareType, MAV_TYPE_QUADROTOR);

            QList<MAV_TYPE> vehicleTypes;
            vehicleTypes << MAV_TYPE_GENERIC << MAV_TYPE_FIXED_WING << MAV_TYPE_QUADROTOR << MAV_TYPE_VTOL_QUADROTOR << MAV_TYPE_GROUND_ROVER << MAV_TYPE_SUBMARINE;

55
            for(MAV_TYPE vehicleType: vehicleTypes) {
56 57 58 59 60 61 62 63 64 65 66 67 68
                QString overrideFile = plugin->missionCommandOverrides(vehicleType);
                if (!overrideFile.isEmpty()) {
                    _staticCommandTree[firmwareType][vehicleType] = new MissionCommandList(overrideFile, firmwareType == MAV_AUTOPILOT_GENERIC && vehicleType == MAV_TYPE_GENERIC /* baseCommandList */, this);
                }
            }
        }
#ifdef UNITTEST_BUILD
    }
#endif
}

MAV_AUTOPILOT MissionCommandTree::_baseFirmwareType(MAV_AUTOPILOT firmwareType) const
{
69
    if (qgcApp()->toolbox()->firmwarePluginManager()->supportedFirmwareTypes().contains(firmwareType)) {
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
        return firmwareType;
    } else {
        return MAV_AUTOPILOT_GENERIC;
    }

}

MAV_TYPE MissionCommandTree::_baseVehicleType(MAV_TYPE mavType) const
{
    if (QGCMAVLink::isFixedWing(mavType)) {
        return MAV_TYPE_FIXED_WING;
    } else if (QGCMAVLink::isMultiRotor(mavType)) {
        return MAV_TYPE_QUADROTOR;
    } else if (QGCMAVLink::isVTOL(mavType)) {
        return MAV_TYPE_VTOL_QUADROTOR;
    } else if (QGCMAVLink::isRover(mavType)) {
        return MAV_TYPE_GROUND_ROVER;
    } else if (QGCMAVLink::isSub(mavType)) {
        return MAV_TYPE_SUBMARINE;
    } else {
        return MAV_TYPE_GENERIC;
    }
}

/// Add the next level of the hierarchy to a collapsed tree.
///     @param vehicle Collapsed tree is for this vehicle
///     @param cmdList List of mission commands to collapse into ui info
///     @param collapsedTree Tree we are collapsing into
void MissionCommandTree::_collapseHierarchy(Vehicle*                                vehicle,
                                            const MissionCommandList*               cmdList,
                                            QMap<MAV_CMD, MissionCommandUIInfo*>&   collapsedTree)
{
    MAV_AUTOPILOT   baseFirmwareType;
    MAV_TYPE        baseVehicleType;

    _baseVehicleInfo(vehicle, baseFirmwareType, baseVehicleType);

107
    for (MAV_CMD command: cmdList->commandIds()) {
108 109 110 111 112 113 114 115 116 117 118
        MissionCommandUIInfo* uiInfo = cmdList->getUIInfo(command);
        if (uiInfo) {
            if (collapsedTree.contains(command)) {
                collapsedTree[command]->_overrideInfo(uiInfo);
            } else {
                collapsedTree[command] = new MissionCommandUIInfo(*uiInfo);
            }
        }
    }
}

Don Gagne's avatar
Don Gagne committed
119
void MissionCommandTree::_buildAllCommands(Vehicle* vehicle)
120 121 122 123 124 125
{
    MAV_AUTOPILOT   baseFirmwareType;
    MAV_TYPE        baseVehicleType;

    _baseVehicleInfo(vehicle, baseFirmwareType, baseVehicleType);

Don Gagne's avatar
Don Gagne committed
126 127 128
    if (_allCommands.contains(baseFirmwareType) &&
            _allCommands[baseFirmwareType].contains(baseVehicleType)) {
        // Already built
129 130 131
        return;
    }

Don Gagne's avatar
Don Gagne committed
132
    QMap<MAV_CMD, MissionCommandUIInfo*>& collapsedTree = _allCommands[baseFirmwareType][baseVehicleType];
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151

    // Any Firmware, Any Vehicle
    _collapseHierarchy(vehicle, _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_GENERIC], collapsedTree);

    // Any Firmware, Specific Vehicle
    if (baseVehicleType != MAV_TYPE_GENERIC) {
        _collapseHierarchy(vehicle, _staticCommandTree[MAV_AUTOPILOT_GENERIC][baseVehicleType], collapsedTree);
    }

    // Known Firmware, Any Vehicle
    if (baseFirmwareType != MAV_AUTOPILOT_GENERIC) {
        _collapseHierarchy(vehicle, _staticCommandTree[baseFirmwareType][MAV_TYPE_GENERIC], collapsedTree);

        // Known Firmware, Specific Vehicle
        if (baseVehicleType != MAV_TYPE_GENERIC) {
            _collapseHierarchy(vehicle, _staticCommandTree[baseFirmwareType][baseVehicleType], collapsedTree);
        }
    }

Don Gagne's avatar
Don Gagne committed
152 153 154 155 156 157 158 159
    // Build category list from supported commands
    QList<MAV_CMD> supportedCommands = vehicle->firmwarePlugin()->supportedMissionCommands();
    for (MAV_CMD cmd: collapsedTree.keys()) {
        if (supportedCommands.contains(cmd)) {
            QString newCategory = collapsedTree[cmd]->category();
            if (!_supportedCategories[baseFirmwareType][baseVehicleType].contains(newCategory)) {
                _supportedCategories[baseFirmwareType][baseVehicleType].append(newCategory);
            }
160 161
        }
    }
Don Gagne's avatar
Don Gagne committed
162
    _supportedCategories[baseFirmwareType][baseVehicleType].append(_allCommandsCategory);
163 164 165 166 167 168 169 170
}

QStringList MissionCommandTree::_availableCategoriesForVehicle(Vehicle* vehicle)
{
    MAV_AUTOPILOT   baseFirmwareType;
    MAV_TYPE        baseVehicleType;

    _baseVehicleInfo(vehicle, baseFirmwareType, baseVehicleType);
Don Gagne's avatar
Don Gagne committed
171
    _buildAllCommands(vehicle);
172

Don Gagne's avatar
Don Gagne committed
173
    return _supportedCategories[baseFirmwareType][baseVehicleType];
174 175 176 177 178 179 180
}

QString MissionCommandTree::friendlyName(MAV_CMD command)
{
    MissionCommandList *    commandList =   _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_GENERIC];
    MissionCommandUIInfo*   uiInfo =        commandList->getUIInfo(command);

Don Gagne's avatar
Don Gagne committed
181 182 183
    if (uiInfo) {
        return uiInfo->friendlyName();
    } else {
Don Gagne's avatar
Don Gagne committed
184
        return QStringLiteral("MAV_CMD(%1)").arg((int)command);
Don Gagne's avatar
Don Gagne committed
185
    }
186 187 188 189 190 191 192
}

QString MissionCommandTree::rawName(MAV_CMD command)
{
    MissionCommandList *    commandList =   _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_GENERIC];
    MissionCommandUIInfo*   uiInfo =        commandList->getUIInfo(command);

Don Gagne's avatar
Don Gagne committed
193 194 195
    if (uiInfo) {
        return uiInfo->rawName();
    } else {
Don Gagne's avatar
Don Gagne committed
196
        return QStringLiteral("MAV_CMD(%1)").arg((int)command);
Don Gagne's avatar
Don Gagne committed
197
    }
198 199 200 201 202 203 204 205 206 207 208 209 210
}

const QList<MAV_CMD>& MissionCommandTree::allCommandIds(void) const
{
    return _staticCommandTree[MAV_AUTOPILOT_GENERIC][MAV_TYPE_GENERIC]->commandIds();
}

const MissionCommandUIInfo* MissionCommandTree::getUIInfo(Vehicle* vehicle, MAV_CMD command)
{
    MAV_AUTOPILOT   baseFirmwareType;
    MAV_TYPE        baseVehicleType;

    _baseVehicleInfo(vehicle, baseFirmwareType, baseVehicleType);
Don Gagne's avatar
Don Gagne committed
211
    _buildAllCommands(vehicle);
212

Don Gagne's avatar
Don Gagne committed
213
    const QMap<MAV_CMD, MissionCommandUIInfo*>& infoMap = _allCommands[baseFirmwareType][baseVehicleType];
214 215 216
    if (infoMap.contains(command)) {
        return infoMap[command];
    } else {
Don Gagne's avatar
Don Gagne committed
217
        return nullptr;
218 219 220
    }
}

221
QVariantList MissionCommandTree::getCommandsForCategory(Vehicle* vehicle, const QString& category, bool showFlyThroughCommands)
222 223 224 225 226
{
    MAV_AUTOPILOT   baseFirmwareType;
    MAV_TYPE        baseVehicleType;

    _baseVehicleInfo(vehicle, baseFirmwareType, baseVehicleType);
Don Gagne's avatar
Don Gagne committed
227
    _buildAllCommands(vehicle);
228

229 230 231 232 233
    // vehicle can be null in which case _baseVehicleInfo will tell of the firmware/vehicle type for the offline editing vehicle.
    // We then use that to get a firmware plugin so we can get the list of supported commands.
    FirmwarePlugin* firmwarePlugin = qgcApp()->toolbox()->firmwarePluginManager()->firmwarePluginForAutopilot(baseFirmwareType, baseVehicleType);
    QList<MAV_CMD>  supportedCommands = firmwarePlugin->supportedMissionCommands();

234
    QVariantList list;
Don Gagne's avatar
Don Gagne committed
235
    QMap<MAV_CMD, MissionCommandUIInfo*> commandMap = _allCommands[baseFirmwareType][baseVehicleType];
236
    for (MAV_CMD command: commandMap.keys()) {
Don Gagne's avatar
Don Gagne committed
237 238
        if (supportedCommands.contains(command)) {
            MissionCommandUIInfo* uiInfo = commandMap[command];
239 240
            if ((uiInfo->category() == category || category == _allCommandsCategory) &&
                    (showFlyThroughCommands || !uiInfo->specifiesCoordinate() || uiInfo->isStandaloneCoordinate())) {
Don Gagne's avatar
Don Gagne committed
241 242
                list.append(QVariant::fromValue(uiInfo));
            }
243 244 245 246 247 248 249 250 251 252 253 254 255
        }
    }

    return list;
}

void MissionCommandTree::_baseVehicleInfo(Vehicle* vehicle, MAV_AUTOPILOT& baseFirmwareType, MAV_TYPE& baseVehicleType) const
{
    if (vehicle) {
        baseFirmwareType = _baseFirmwareType(vehicle->firmwareType());
        baseVehicleType = _baseVehicleType(vehicle->vehicleType());
    } else {
        // No Vehicle means offline editing
256 257
        baseFirmwareType = _baseFirmwareType((MAV_AUTOPILOT)_settingsManager->appSettings()->offlineEditingFirmwareType()->rawValue().toInt());
        baseVehicleType = _baseVehicleType((MAV_TYPE)_settingsManager->appSettings()->offlineEditingVehicleType()->rawValue().toInt());
258 259
    }
}