QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
MissionCommandTree.cc
Go to the documentation of this file.
2#include "FirmwarePlugin.h"
7#include "Vehicle.h"
8
9#include <QtCore/QApplicationStatic>
10
11QGC_LOGGING_CATEGORY(MissionCommandTreeLog, "Plan.MissionCommandTree");
12
13Q_APPLICATION_STATIC(MissionCommandTree, _missionCommandTreeInstance);
14
15MissionCommandTree::MissionCommandTree(bool unitTest, QObject *parent)
16 : QObject(parent)
17{
18 qCDebug(MissionCommandTreeLog) << this;
19
20 if (unitTest) {
21 // Load unit testing tree
22 _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassGeneric] = new MissionCommandList(":/unittest/UT-MavCmdInfoCommon.json", true, this);
23 _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassFixedWing] = new MissionCommandList(":/unittest/UT-MavCmdInfoFixedWing.json", false, this);
24 _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassMultiRotor] = new MissionCommandList(":/unittest/UT-MavCmdInfoMultiRotor.json", false, this);
25 _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassVTOL] = new MissionCommandList(":/unittest/UT-MavCmdInfoVTOL.json", false, this);
26 _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassSub] = new MissionCommandList(":/unittest/UT-MavCmdInfoSub.json", false, this);
27 _staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassRoverBoat] = new MissionCommandList(":/unittest/UT-MavCmdInfoRover.json", false, this);
28 } else {
29 // Load all levels of hierarchy
33 const QString overrideFile = plugin->missionCommandOverrides(vehicleClass);
34 if (!overrideFile.isEmpty()) {
35 const bool baseCommandList = ((firmwareClass == QGCMAVLink::FirmwareClassGeneric) && (vehicleClass == QGCMAVLink::VehicleClassGeneric));
36 _staticCommandTree[firmwareClass][vehicleClass] = new MissionCommandList(overrideFile, baseCommandList, this);
37 }
38 }
39 }
40 }
41}
42
44{
45 for (const auto &vehicleMap : std::as_const(_allCommands)) {
46 for (const auto &commandMap : vehicleMap) {
47 for (MissionCommandUIInfo *const uiInfo : commandMap) {
48 delete uiInfo;
49 }
50 }
51 }
52 _allCommands.clear();
53
54 qCDebug(MissionCommandTreeLog) << this;
55}
56
58{
59 return _missionCommandTreeInstance();
60}
61
62void MissionCommandTree::_collapseHierarchy(const MissionCommandList* cmdList,
63 QMap<MAV_CMD, MissionCommandUIInfo*>& collapsedTree, bool baseList) const
64{
65 if (!cmdList) {
66 return;
67 }
68
69 for (const MAV_CMD command: cmdList->commandIds()) {
70 MissionCommandUIInfo *const uiInfo = cmdList->getUIInfo(command);
71 if (uiInfo) {
72 if (collapsedTree.contains(command)) {
73 collapsedTree[command]->_overrideInfo(uiInfo);
74 } else if (baseList) {
75 collapsedTree[command] = new MissionCommandUIInfo(*uiInfo);
76 } else {
77 // Override entries are partial; without the base entry they would produce a broken command
78 qCWarning(MissionCommandTreeLog) << "Skipping override with no base command info" << command;
79 }
80 }
81 }
82}
83
84void MissionCommandTree::_buildAllCommands(Vehicle *vehicle, QGCMAVLink::VehicleClass_t vtolMode)
85{
86 QGCMAVLink::FirmwareClass_t firmwareClass;
87 QGCMAVLink::VehicleClass_t vehicleClass;
88
89 _firmwareAndVehicleClassInfo(vehicle, vtolMode, firmwareClass, vehicleClass);
90
91 if (_allCommands.contains(firmwareClass) && _allCommands[firmwareClass].contains(vehicleClass)) {
92 // Already built
93 return;
94 }
95
96 QMap<MAV_CMD, MissionCommandUIInfo*> &collapsedTree = _allCommands[firmwareClass][vehicleClass];
97
98 // Base of the tree is all commands
99 _collapseHierarchy(_staticCommandTree[MAV_AUTOPILOT_GENERIC][QGCMAVLink::VehicleClassGeneric], collapsedTree,
100 true /* baseList */);
101
102 // Add the overrides for specific vehicle types
103 if (vehicleClass != QGCMAVLink::VehicleClassGeneric) {
104 _collapseHierarchy(_staticCommandTree[QGCMAVLink::FirmwareClassGeneric][vehicleClass], collapsedTree);
105 }
106
107 // Add the overrides for specific firmware class, all vehicles
108 if (firmwareClass != QGCMAVLink::FirmwareClassGeneric) {
109 _collapseHierarchy(_staticCommandTree[firmwareClass][QGCMAVLink::VehicleClassGeneric], collapsedTree);
110
111 // Add overrides for specific vehicle class
112 if (vehicleClass != QGCMAVLink::VehicleClassGeneric) {
113 _collapseHierarchy(_staticCommandTree[firmwareClass][vehicleClass], collapsedTree);
114 }
115 }
116
117 // Build category list from supported commands
118 QList<MAV_CMD> supportedCommands = vehicle->firmwarePlugin()->supportedMissionCommands(vehicleClass);
119 for (const MAV_CMD cmd: collapsedTree.keys()) {
120 if (supportedCommands.contains(cmd)) {
121 const QString newCategory = collapsedTree[cmd]->category();
122 if (!_supportedCategories[firmwareClass][vehicleClass].contains(newCategory)) {
123 _supportedCategories[firmwareClass][vehicleClass].append(newCategory);
124 }
125 }
126 }
127
128 _supportedCategories[firmwareClass][vehicleClass].append(_allCommandsCategory);
129}
130
131QStringList MissionCommandTree::_availableCategoriesForVehicle(Vehicle *vehicle)
132{
133 QGCMAVLink::FirmwareClass_t firmwareClass;
134 QGCMAVLink::VehicleClass_t vehicleClass;
135
136 _firmwareAndVehicleClassInfo(vehicle, QGCMAVLink::VehicleClassGeneric, firmwareClass, vehicleClass);
137 _buildAllCommands(vehicle, QGCMAVLink::VehicleClassGeneric);
138
139 return _supportedCategories[firmwareClass][vehicleClass];
140}
141
142QString MissionCommandTree::friendlyName(MAV_CMD command) const
143{
144 const MissionCommandList *const commandList = _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric];
145 const MissionCommandUIInfo *const uiInfo = commandList->getUIInfo(command);
146
147 return uiInfo ? uiInfo->friendlyName() : QStringLiteral("MAV_CMD(%1)").arg(static_cast<int>(command));
148}
149
150QString MissionCommandTree::rawName(MAV_CMD command) const
151{
152 const MissionCommandList *const commandList = _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric];
153 const MissionCommandUIInfo *const uiInfo = commandList->getUIInfo(command);
154
155 return uiInfo ? uiInfo->rawName() : QStringLiteral("MAV_CMD(%1)").arg(static_cast<int>(command));
156}
157
158bool MissionCommandTree::isLandCommand(MAV_CMD command) const
159{
160 const MissionCommandList *const commandList = _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric];
161 const MissionCommandUIInfo *const uiInfo = commandList->getUIInfo(command);
162
163 return (uiInfo && uiInfo->isLandCommand());
164}
165
166bool MissionCommandTree::isTakeoffCommand(MAV_CMD command) const
167{
168 const MissionCommandList *const commandList = _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric];
169 const MissionCommandUIInfo *const uiInfo = commandList->getUIInfo(command);
170
171 return (uiInfo && uiInfo->isTakeoffCommand());
172}
173
174const QList<MAV_CMD> &MissionCommandTree::allCommandIds() const
175{
176 return _staticCommandTree[QGCMAVLink::FirmwareClassGeneric][QGCMAVLink::VehicleClassGeneric]->commandIds();
177}
178
180{
181 QGCMAVLink::FirmwareClass_t firmwareClass;
182 QGCMAVLink::VehicleClass_t vehicleClass;
183
184 _firmwareAndVehicleClassInfo(vehicle, vtolMode, firmwareClass, vehicleClass);
185 _buildAllCommands(vehicle, vtolMode);
186
187 MissionCommandUIInfo *result = nullptr;
188
189 const QMap<MAV_CMD, MissionCommandUIInfo*> &infoMap = _allCommands[firmwareClass][vehicleClass];
190 if (infoMap.contains(command)) {
191 result = infoMap[command];
192 }
193
194 return result;
195}
196
198{
199 return _availableCategoriesForVehicle(vehicle);
200}
201
202QVariantList MissionCommandTree::getCommandsForCategory(Vehicle *vehicle, const QString &category, bool showFlyThroughCommands)
203{
204 QGCMAVLink::FirmwareClass_t firmwareClass;
205 QGCMAVLink::VehicleClass_t vehicleClass;
206
207 _firmwareAndVehicleClassInfo(vehicle, QGCMAVLink::VehicleClassGeneric, firmwareClass, vehicleClass);
208 _buildAllCommands(vehicle, QGCMAVLink::VehicleClassGeneric);
209
210 // vehicle can be null in which case _firmwareAndVehicleClassInfo will tell of the firmware/vehicle type for the offline editing vehicle.
211 // We then use that to get a firmware plugin so we can get the list of supported commands.
213 const QList<MAV_CMD> supportedCommands = firmwarePlugin->supportedMissionCommands(vehicleClass);
214
215 const QMap<MAV_CMD, MissionCommandUIInfo*> commandMap = _allCommands[firmwareClass][vehicleClass];
216 QVariantList list;
217 for (const MAV_CMD command: commandMap.keys()) {
218 if (supportedCommands.isEmpty() || supportedCommands.contains(command)) {
219 MissionCommandUIInfo* uiInfo = commandMap[command];
220 if ((uiInfo->category() == category || category == _allCommandsCategory) && (showFlyThroughCommands || !uiInfo->specifiesCoordinate() || uiInfo->isStandaloneCoordinate())) {
221 list.append(QVariant::fromValue(uiInfo));
222 }
223 }
224 }
225
226 return list;
227}
228
229void MissionCommandTree::_firmwareAndVehicleClassInfo(Vehicle *vehicle, QGCMAVLink::VehicleClass_t vtolMode, QGCMAVLink::FirmwareClass_t &firmwareClass, QGCMAVLink::VehicleClass_t &vehicleClass) const
230{
231 firmwareClass = QGCMAVLink::firmwareClass(vehicle->firmwareType());
232 vehicleClass = QGCMAVLink::vehicleClass(vehicle->vehicleType());
233 if ((vehicleClass == QGCMAVLink::VehicleClassVTOL) && (vtolMode != QGCMAVLink::VehicleClassGeneric)) {
234 vehicleClass = vtolMode;
235 }
236}
Q_APPLICATION_STATIC(MissionCommandTree, _missionCommandTreeInstance)
#define QGC_LOGGING_CATEGORY(name, categoryStr)
std::array< MsgOutKey, 4 > keys
Definition UBXPlan.cc:13
FirmwarePlugin * firmwarePluginForAutopilot(MAV_AUTOPILOT firmwareType, MAV_TYPE vehicleType)
QList< QGCMAVLink::FirmwareClass_t > supportedFirmwareClasses()
Returns list of firmwares which are supported by the system.
static FirmwarePluginManager * instance()
The FirmwarePlugin class represents the methods and objects which are specific to a certain Firmware ...
virtual QString missionCommandOverrides(QGCMAVLinkTypes::VehicleClass_t vehicleClass) const
virtual QList< MAV_CMD > supportedMissionCommands(QGCMAVLinkTypes::VehicleClass_t) const
List of supported mission commands. Empty list for all commands supported.
Maintains a list of MissionCommandUIInfo objects loaded from a json file.
MissionCommandUIInfo * getUIInfo(MAV_CMD command) const
Returns the ui info for specified command, NULL if command not found.
Manages a hierarchy of MissionCommandUIInfo.
bool isTakeoffCommand(MAV_CMD command) const
MissionCommandTree(bool unitTest=false, QObject *parent=nullptr)
bool isLandCommand(MAV_CMD command) const
~MissionCommandTree()
Destructor for the MissionCommandTree class.
const QList< MAV_CMD > & allCommandIds() const
static MissionCommandTree * instance()
QString rawName(MAV_CMD command) const
Returns the raw name for the specified command.
Q_INVOKABLE QVariantList getCommandsForCategory(Vehicle *vehicle, const QString &category, bool showFlyThroughCommands)
QString friendlyName(MAV_CMD command) const
Returns the friendly name for the specified command.
Q_INVOKABLE QStringList categoriesForVehicle(Vehicle *vehicle)
const MissionCommandUIInfo * getUIInfo(Vehicle *vehicle, QGCMAVLink::VehicleClass_t vtolMode, MAV_CMD command)
UI Information associated with a mission command (MAV_CMD)
QString category(void) const
bool isTakeoffCommand(void) const
QString friendlyName(void) const
bool specifiesCoordinate(void) const
bool isStandaloneCoordinate(void) const
QString rawName(void) const
MAV_TYPE vehicleType() const
Definition Vehicle.h:446
FirmwarePlugin * firmwarePlugin()
Provides access to the Firmware Plugin for this Vehicle.
Definition Vehicle.h:462
MAV_AUTOPILOT firmwareType() const
Definition Vehicle.h:445
GPSCommandSequence::Command command(QByteArrayView body, GPSTextMatcher reply, std::chrono::milliseconds timeout)
body labelled by its text, framed as a sentence, and completed by reply within timeout.
static constexpr VehicleClass_t VehicleClassGeneric