MissionCommandTree.cc 9.63 KB
Newer Older
1 2
/****************************************************************************
 *
Gus Grubba's avatar
Gus Grubba committed
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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"
17
#include "SettingsManager.h"
18 19 20

#include <QQmlEngine>

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

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

33 34
    _settingsManager = toolbox->settingsManager();

35 36 37
#ifdef UNITTEST_BUILD
    if (_unitTest) {
        // Load unit testing tree
38 39 40 41 42 43
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassGeneric]      = new MissionCommandList(":/unittest/UT-MavCmdInfoCommon.json", true, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassFixedWing]    = new MissionCommandList(":/unittest/UT-MavCmdInfoFixedWing.json", false, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassMultiRotor]   = new MissionCommandList(":/unittest/UT-MavCmdInfoMultiRotor.json", false, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassVTOL]         = new MissionCommandList(":/unittest/UT-MavCmdInfoVTOL.json", false, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassSub]          = new MissionCommandList(":/unittest/UT-MavCmdInfoSub.json", false, this);
        _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassRoverBoat]    = new MissionCommandList(":/unittest/UT-MavCmdInfoRover.json", false, this);
44 45 46
    } else {
#endif
        // Load all levels of hierarchy
47 48
        for (const QGCMAVLink::FirmwareClass_t firmwareClass: _toolbox->firmwarePluginManager()->supportedFirmwareClasses()) {
            FirmwarePlugin* plugin = _toolbox->firmwarePluginManager()->firmwarePluginForAutopilot(QGCMAVLink::firmwareClassToAutopilot(firmwareClass), MAV_TYPE_QUADROTOR);
49

50 51
            for (const QGCMAVLink::VehicleClass_t vehicleClass: QGCMAVLink::allVehicleClasses()) {
                QString overrideFile = plugin->missionCommandOverrides(vehicleClass);
52
                if (!overrideFile.isEmpty()) {
53
                    _staticCommandTree[firmwareClass][vehicleClass] = new MissionCommandList(overrideFile, firmwareClass == QGCMAVLink::FirmwareClassGeneric && vehicleClass == QGCMAVLink::VehicleClassGeneric /* baseCommandList */, this);
54 55 56 57 58 59 60 61 62
                }
            }
        }
#ifdef UNITTEST_BUILD
    }
#endif
}

/// Add the next level of the hierarchy to a collapsed tree.
63 64 65
///     @param cmdList          List of mission commands to collapse into ui info
///     @param collapsedTree    Tree we are collapsing into
void MissionCommandTree::_collapseHierarchy(const MissionCommandList*               cmdList,
66 67
                                            QMap<MAV_CMD, MissionCommandUIInfo*>&   collapsedTree)
{
68 69 70
    if (!cmdList) {
        return;
    }
71

72
    for (MAV_CMD command: cmdList->commandIds()) {
73 74 75 76 77 78 79 80 81 82 83
        MissionCommandUIInfo* uiInfo = cmdList->getUIInfo(command);
        if (uiInfo) {
            if (collapsedTree.contains(command)) {
                collapsedTree[command]->_overrideInfo(uiInfo);
            } else {
                collapsedTree[command] = new MissionCommandUIInfo(*uiInfo);
            }
        }
    }
}

84
void MissionCommandTree::_buildAllCommands(Vehicle* vehicle, QGCMAVLink::VehicleClass_t vtolMode)
85
{
86 87
    QGCMAVLink::FirmwareClass_t firmwareClass;
    QGCMAVLink::VehicleClass_t  vehicleClass;
88

89
    _firmwareAndVehicleClassInfo(vehicle, vtolMode, firmwareClass, vehicleClass);
90

91
    if (_allCommands.contains(firmwareClass) && _allCommands[firmwareClass].contains(vehicleClass)) {
Don Gagne's avatar
Don Gagne committed
92
        // Already built
93 94 95
        return;
    }

96
    QMap<MAV_CMD, MissionCommandUIInfo*>& collapsedTree = _allCommands[firmwareClass][vehicleClass];
97

98 99
    // Base of the tree is all commands
    _collapseHierarchy(_staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassGeneric], collapsedTree);
100

101 102 103
    // Add the overrides for specific vehicle types
    if (vehicleClass != QGCMAVLink::VehicleClassGeneric) {
        _collapseHierarchy(_staticCommandTree[QGCMAVLink::FirmwareClassGeneric][vehicleClass], collapsedTree);
104 105
    }

106 107 108
    // Add the overrides for specific firmware class, all vehicles
    if (firmwareClass != QGCMAVLink::FirmwareClassGeneric) {
        _collapseHierarchy(_staticCommandTree[firmwareClass][QGCMAVLink::VehicleClassGeneric], collapsedTree);
109

110 111 112
        // Add overrides for specific vehicle class
        if (vehicleClass != QGCMAVLink::VehicleClassGeneric) {
            _collapseHierarchy(_staticCommandTree[firmwareClass][vehicleClass], collapsedTree);
113 114 115
        }
    }

Don Gagne's avatar
Don Gagne committed
116
    // Build category list from supported commands
117
    QList<MAV_CMD> supportedCommands = vehicle->firmwarePlugin()->supportedMissionCommands(vehicleClass);
Don Gagne's avatar
Don Gagne committed
118 119 120
    for (MAV_CMD cmd: collapsedTree.keys()) {
        if (supportedCommands.contains(cmd)) {
            QString newCategory = collapsedTree[cmd]->category();
121 122
            if (!_supportedCategories[firmwareClass][vehicleClass].contains(newCategory)) {
                _supportedCategories[firmwareClass][vehicleClass].append(newCategory);
Don Gagne's avatar
Don Gagne committed
123
            }
124 125
        }
    }
126
    _supportedCategories[firmwareClass][vehicleClass].append(_allCommandsCategory);
127 128 129 130
}

QStringList MissionCommandTree::_availableCategoriesForVehicle(Vehicle* vehicle)
{
131 132
    QGCMAVLink::FirmwareClass_t firmwareClass;
    QGCMAVLink::VehicleClass_t  vehicleClass;
133

134 135
    _firmwareAndVehicleClassInfo(vehicle, QGCMAVLink::VehicleClassGeneric, firmwareClass, vehicleClass);
    _buildAllCommands(vehicle, QGCMAVLink::VehicleClassGeneric);
136

137
    return _supportedCategories[firmwareClass][vehicleClass];
138 139 140 141
}

QString MissionCommandTree::friendlyName(MAV_CMD command)
{
142
    MissionCommandList *    commandList =   _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric];
143 144
    MissionCommandUIInfo*   uiInfo =        commandList->getUIInfo(command);

Don Gagne's avatar
Don Gagne committed
145 146 147
    if (uiInfo) {
        return uiInfo->friendlyName();
    } else {
Don Gagne's avatar
Don Gagne committed
148
        return QStringLiteral("MAV_CMD(%1)").arg((int)command);
Don Gagne's avatar
Don Gagne committed
149
    }
150 151 152 153
}

QString MissionCommandTree::rawName(MAV_CMD command)
{
154
    MissionCommandList *    commandList =   _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric];
155 156
    MissionCommandUIInfo*   uiInfo =        commandList->getUIInfo(command);

Don Gagne's avatar
Don Gagne committed
157 158 159
    if (uiInfo) {
        return uiInfo->rawName();
    } else {
Don Gagne's avatar
Don Gagne committed
160
        return QStringLiteral("MAV_CMD(%1)").arg((int)command);
Don Gagne's avatar
Don Gagne committed
161
    }
162 163 164 165
}

const QList<MAV_CMD>& MissionCommandTree::allCommandIds(void) const
{
166
    return _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric]->commandIds();
167 168
}

169
const MissionCommandUIInfo* MissionCommandTree::getUIInfo(Vehicle* vehicle, QGCMAVLink::VehicleClass_t vtolMode,  MAV_CMD command)
170
{
171 172
    QGCMAVLink::FirmwareClass_t firmwareClass;
    QGCMAVLink::VehicleClass_t  vehicleClass;
173

174 175
    _firmwareAndVehicleClassInfo(vehicle, vtolMode, firmwareClass, vehicleClass);
    _buildAllCommands(vehicle, vtolMode);
176

177
    const QMap<MAV_CMD, MissionCommandUIInfo*>& infoMap = _allCommands[firmwareClass][vehicleClass];
178 179 180
    if (infoMap.contains(command)) {
        return infoMap[command];
    } else {
Don Gagne's avatar
Don Gagne committed
181
        return nullptr;
182 183 184
    }
}

185
QVariantList MissionCommandTree::getCommandsForCategory(Vehicle* vehicle, const QString& category, bool showFlyThroughCommands)
186
{
187 188
    QGCMAVLink::FirmwareClass_t firmwareClass;
    QGCMAVLink::VehicleClass_t  vehicleClass;
189

190 191
    _firmwareAndVehicleClassInfo(vehicle, QGCMAVLink::VehicleClassGeneric, firmwareClass, vehicleClass);
    _buildAllCommands(vehicle, QGCMAVLink::VehicleClassGeneric);
192

193
    // vehicle can be null in which case _firmwareAndVehicleClassInfo will tell of the firmware/vehicle type for the offline editing vehicle.
194
    // We then use that to get a firmware plugin so we can get the list of supported commands.
195
    FirmwarePlugin* firmwarePlugin = qgcApp()->toolbox()->firmwarePluginManager()->firmwarePluginForAutopilot(QGCMAVLink::firmwareClassToAutopilot(firmwareClass), QGCMAVLink::vehicleClassToMavType(vehicleClass));
196
    QList<MAV_CMD>  supportedCommands = firmwarePlugin->supportedMissionCommands(vehicleClass);
197

198
    QVariantList list;
199
    QMap<MAV_CMD, MissionCommandUIInfo*> commandMap = _allCommands[firmwareClass][vehicleClass];
200
    for (MAV_CMD command: commandMap.keys()) {
201
        if (supportedCommands.isEmpty() || supportedCommands.contains(command)) {
Don Gagne's avatar
Don Gagne committed
202
            MissionCommandUIInfo* uiInfo = commandMap[command];
203
            if ((uiInfo->category() == category || category == _allCommandsCategory) && (showFlyThroughCommands || !uiInfo->specifiesCoordinate() || uiInfo->isStandaloneCoordinate())) {
Don Gagne's avatar
Don Gagne committed
204 205
                list.append(QVariant::fromValue(uiInfo));
            }
206 207 208 209 210 211
        }
    }

    return list;
}

212
void MissionCommandTree::_firmwareAndVehicleClassInfo(Vehicle* vehicle, QGCMAVLink::VehicleClass_t vtolMode, QGCMAVLink::FirmwareClass_t& firmwareClass, QGCMAVLink::VehicleClass_t& vehicleClass) const
213
{
214 215
    firmwareClass = QGCMAVLink::firmwareClass(vehicle->firmwareType());
    vehicleClass = QGCMAVLink::vehicleClass(vehicle->vehicleType());
216 217 218
    if (vehicleClass == QGCMAVLink::VehicleClassVTOL && vtolMode != QGCMAVLink::VehicleClassGeneric) {
        vehicleClass = vtolMode;
    }
219
}