QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
MavCommandQueue.cc
Go to the documentation of this file.
1#include "MavCommandQueue.h"
2
3#include <QtCore/QTimer>
4
5#include "FirmwarePlugin.h"
6#include "MAVLinkLib.h"
7#include "MAVLinkProtocol.h"
9#include "AppMessages.h"
10#include "QGCLoggingCategory.h"
11#include "Vehicle.h"
12#include "VehicleLinkManager.h"
13
14#ifdef QT_DEBUG
15#include "MockLink.h"
16#endif
17
18QGC_LOGGING_CATEGORY(MavCommandQueueLog, "Vehicle.MavCommandQueue")
19
21 : QObject(vehicle)
22 , _vehicle(vehicle)
23{
24 _responseCheckTimer.setSingleShot(false);
25 _responseCheckTimer.setInterval(_responseCheckIntervalMSecs());
26 _responseCheckTimer.start();
27 connect(&_responseCheckTimer, &QTimer::timeout, this, &MavCommandQueue::_responseTimeoutCheck);
28}
29
31{
32 _responseCheckTimer.stop();
33 _responseCheckTimer.disconnect();
34}
35
37{
38 qCDebug(MavCommandQueueLog) << "stop - clearing pending commands and halting response timer";
39 _stopped = true;
40 _responseCheckTimer.stop();
41 _responseCheckTimer.disconnect();
42 _list.clear();
43}
44
45void MavCommandQueue::sendCommand(int compId, MAV_CMD command, bool showError, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
46{
47 sendWorker(false, // commandInt
48 showError,
49 nullptr, // no handlers
50 compId,
51 command,
52 MAV_FRAME_GLOBAL,
53 param1, param2, param3, param4, param5, param6, param7);
54}
55
56void MavCommandQueue::sendCommandDelayed(int compId, MAV_CMD command, bool showError, int milliseconds, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
57{
58 QTimer::singleShot(milliseconds, this, [=, this] {
59 sendCommand(compId, command, showError, param1, param2, param3, param4, param5, param6, param7);
60 });
61}
62
63void MavCommandQueue::sendCommandInt(int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
64{
65 sendWorker(true, // commandInt
66 showError,
67 nullptr, // no handlers
68 compId,
69 command,
70 frame,
71 param1, param2, param3, param4, param5, param6, param7);
72}
73
74void MavCommandQueue::sendCommandWithHandler(const MavCmdAckHandlerInfo_t* ackHandlerInfo, int compId, MAV_CMD command, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
75{
76 sendWorker(false, // commandInt
77 false, // showError
78 ackHandlerInfo,
79 compId,
80 command,
81 MAV_FRAME_GLOBAL,
82 param1, param2, param3, param4, param5, param6, param7);
83}
84
85void MavCommandQueue::sendCommandIntWithHandler(const MavCmdAckHandlerInfo_t* ackHandlerInfo, int compId, MAV_CMD command, MAV_FRAME frame, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
86{
87 sendWorker(true, // commandInt
88 false, // showError
89 ackHandlerInfo,
90 compId,
91 command,
92 frame,
93 param1, param2, param3, param4, param5, param6, param7);
94}
95
96namespace {
97
98struct LambdaFallbackHandlerData {
99 Vehicle* vehicle;
100 bool showError;
101 std::function<void()> unsupportedLambda;
102};
103
104void lambdaFallbackResultHandler(void* resultHandlerData, int /*compId*/, const mavlink_command_ack_t& ack, VehicleTypes::MavCmdResultFailureCode_t /*failureCode*/)
105{
106 auto* data = static_cast<LambdaFallbackHandlerData*>(resultHandlerData);
107 auto* instanceData = data->vehicle->firmwarePluginInstanceData();
108
109 switch (ack.result) {
110 case MAV_RESULT_ACCEPTED:
112 break;
113 case MAV_RESULT_UNSUPPORTED:
114 instanceData->setCommandSupported(MAV_CMD(ack.command), FirmwarePluginInstanceData::CommandSupportedResult::UNSUPPORTED);
115 data->unsupportedLambda();
116 break;
117 default:
118 if (data->showError) {
120 }
121 break;
122 }
123
124 delete data;
125}
126
127} // namespace
128
129void MavCommandQueue::sendCommandWithLambdaFallbackWorker(std::function<void()> lambda, bool commandInt, int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
130{
131 auto* instanceData = _vehicle->firmwarePluginInstanceData();
132
133 switch (instanceData->getCommandSupported(command)) {
135 lambda();
136 break;
138 if (commandInt) {
139 sendCommandInt(compId, command, frame, showError, param1, param2, param3, param4, param5, param6, param7);
140 } else {
141 sendCommand(compId, command, showError, param1, param2, param3, param4, param5, param6, param7);
142 }
143 break;
145 auto* data = new LambdaFallbackHandlerData { _vehicle, showError, std::move(lambda) };
146 const MavCmdAckHandlerInfo_t handlerInfo {
147 /* .resultHandler = */ &lambdaFallbackResultHandler,
148 /* .resultHandlerData = */ data,
149 /* .progressHandler = */ nullptr,
150 /* .progressHandlerData = */ nullptr,
151 };
152 if (commandInt) {
153 sendCommandIntWithHandler(&handlerInfo, compId, command, frame, param1, param2, param3, param4, param5, param6, param7);
154 } else {
155 sendCommandWithHandler(&handlerInfo, compId, command, param1, param2, param3, param4, param5, param6, param7);
156 }
157 break;
158 }
159 }
160}
161
162void MavCommandQueue::sendCommandWithLambdaFallback(std::function<void()> lambda, int compId, MAV_CMD command, bool showError, float param1, float param2, float param3, float param4, float param5, float param6, float param7)
163{
164 sendCommandWithLambdaFallbackWorker(std::move(lambda), false /* commandInt */, compId, command, MAV_FRAME_GLOBAL, showError, param1, param2, param3, param4, param5, param6, param7);
165}
166
167void MavCommandQueue::sendCommandIntWithLambdaFallback(std::function<void()> lambda, int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
168{
169 sendCommandWithLambdaFallbackWorker(std::move(lambda), true /* commandInt */, compId, command, frame, showError, param1, param2, param3, param4, param5, param6, param7);
170}
171
172bool MavCommandQueue::isPending(int targetCompId, MAV_CMD command) const
173{
174 return findEntryIndex(targetCompId, command) != -1;
175}
176
177int MavCommandQueue::findEntryIndex(int targetCompId, MAV_CMD command) const
178{
179 for (int i = 0; i < _list.count(); i++) {
180 const MavCommandListEntry_t& entry = _list[i];
181 if (entry.targetCompId == targetCompId && entry.command == command) {
182 return i;
183 }
184 }
185 return -1;
186}
187
188int MavCommandQueue::_responseCheckIntervalMSecs()
189{
190 // Use shorter check interval during unit tests for faster test execution
191 return QGC::runningUnitTests() ? 50 : 500;
192}
193
194int MavCommandQueue::_ackTimeoutMSecs()
195{
196 // Use shorter ack timeout during unit tests for faster test execution
198}
199
200bool MavCommandQueue::_shouldRetry(MAV_CMD command)
201{
202 switch (command) {
203#ifdef QT_DEBUG
204 // These MockLink commands should be retried so we can create unit tests to test retry code
210 return true;
211#endif
212
213 // In general we should not retry any commands. This is for safety reasons. For example you don't want an ARM command
214 // to timeout with no response over a noisy link twice and then suddenly have the third try work 6 seconds later. At that
215 // point the user could have walked up to the vehicle to see what is going wrong.
216 //
217 // We do retry commands which are part of the initial vehicle connect sequence. This makes this process work better over noisy
218 // links where commands could be lost. Also these commands tend to just be requesting status so if they end up being delayed
219 // there are no safety concerns that could occur.
220 case MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES:
221 case MAV_CMD_REQUEST_MESSAGE:
222 case MAV_CMD_PREFLIGHT_STORAGE:
223 case MAV_CMD_RUN_PREARM_CHECKS:
224 return true;
225
226 default:
227 return false;
228 }
229}
230
231bool MavCommandQueue::_canBeDuplicated(MAV_CMD command)
232{
233 // For some commands we don't care about response as much as we care about sending them regularly.
234 // This test avoids commands not being sent due to an ACK not being received yet.
235 // MOTOR_TEST in ardusub is a case where we need a constant stream of commands so it doesn't time out.
236 switch (command) {
237 case MAV_CMD_DO_MOTOR_TEST:
238 case MAV_CMD_SET_MESSAGE_INTERVAL:
239 return true;
240 default:
241 return false;
242 }
243}
244
245QString MavCommandQueue::_formatCommand(MAV_CMD command, float param1)
246{
247 QString rawName = MissionCommandTree::instance()->rawName(command);
248 QString friendlyName = MissionCommandTree::instance()->friendlyName(command);
249 QString commandStr = friendlyName.isEmpty() ? rawName : QStringLiteral("%1 (%2)").arg(friendlyName, rawName);
250
251 if (command == MAV_CMD_REQUEST_MESSAGE) {
252 const mavlink_message_info_t* info = mavlink_get_message_info_by_id(static_cast<int>(param1));
253 if (info) {
254 commandStr += QStringLiteral(" [%1]").arg(info->name);
255 }
256 }
257
258 return commandStr;
259}
260
261void MavCommandQueue::sendWorker(bool commandInt, bool showError,
262 const MavCmdAckHandlerInfo_t* ackHandlerInfo,
263 int targetCompId, MAV_CMD command, MAV_FRAME frame,
264 float param1, float param2, float param3, float param4, double param5, double param6, float param7)
265{
266 if (_stopped) {
267 return;
268 }
269
270 // We can't send commands to compIdAll using this method. The reason being that we would get responses back possibly from multiple components
271 // which this code can't handle.
272 // We also can't send the majority of commands again if we are already waiting for a response from that same command. If we did that we would not be able to discern
273 // which ack was associated with which command.
274 if ((targetCompId == MAV_COMP_ID_ALL) || (isPending(targetCompId, command) && !_canBeDuplicated(command))) {
275 bool compIdAll = targetCompId == MAV_COMP_ID_ALL;
276 QString rawCommandName = MissionCommandTree::instance()->rawName(command);
277
278 qCDebug(MavCommandQueueLog) << QStringLiteral("sendWorker failing %1").arg(compIdAll ? "MAV_COMP_ID_ALL not supported" : "duplicate command") << rawCommandName << param1 << param2 << param3 << param4 << param5 << param6 << param7;
279
281 if (ackHandlerInfo && ackHandlerInfo->resultHandler) {
282 mavlink_command_ack_t ack = {};
283 ack.result = MAV_RESULT_FAILED;
284 (*ackHandlerInfo->resultHandler)(ackHandlerInfo->resultHandlerData, targetCompId, ack, failureCode);
285 } else {
286 emit commandResult(_vehicle->id(), targetCompId, command, MAV_RESULT_FAILED, failureCode);
287 }
288 if (showError) {
289 QGC::showAppMessage(tr("Unable to send command: %1.").arg(compIdAll ? tr("Internal error - MAV_COMP_ID_ALL not supported") : tr("Waiting on previous response to same command.")));
290 }
291 return;
292 }
293
294 SharedLinkInterfacePtr sharedLink = _vehicle->vehicleLinkManager()->primaryLink().lock();
295 if (!sharedLink) {
296 qCDebug(MavCommandQueueLog) << "sendWorker: primary link gone!";
297
299 if (ackHandlerInfo && ackHandlerInfo->resultHandler) {
300 mavlink_command_ack_t ack = {};
301 ack.command = command;
302 ack.result = MAV_RESULT_FAILED;
303 (*ackHandlerInfo->resultHandler)(ackHandlerInfo->resultHandlerData, targetCompId, ack, failureCode);
304 } else {
305 emit commandResult(_vehicle->id(), targetCompId, command, MAV_RESULT_FAILED, failureCode);
306 }
307
308 if (showError) {
309 QGC::showAppMessage(tr("Unable to send command: Vehicle is not connected."));
310 }
311 return;
312 }
313
314 MavCommandListEntry_t entry;
315 entry.useCommandInt = commandInt;
316 entry.targetCompId = targetCompId;
317 entry.command = command;
318 entry.frame = frame;
319 entry.showError = showError;
320 entry.ackHandlerInfo = {};
321 if (ackHandlerInfo) {
322 entry.ackHandlerInfo = *ackHandlerInfo;
323 }
324 entry.rgParam1 = param1;
325 entry.rgParam2 = param2;
326 entry.rgParam3 = param3;
327 entry.rgParam4 = param4;
328 entry.rgParam5 = param5;
329 entry.rgParam6 = param6;
330 entry.rgParam7 = param7;
331 entry.maxTries = _shouldRetry(command) ? kMaxRetryCount : 1;
332 entry.ackTimeoutMSecs = sharedLink->linkConfiguration()->isHighLatency() ? _ackTimeoutMSecsHighLatency : _ackTimeoutMSecs();
333 entry.elapsedTimer.start();
334
335 qCDebug(MavCommandQueueLog) << "Sending" << _formatCommand(command, param1) << "param1-7:" << command << param1 << param2 << param3 << param4 << param5 << param6 << param7;
336
337 _list.append(entry);
338 _sendFromList(_list.count() - 1);
339}
340
341void MavCommandQueue::_sendFromList(int index)
342{
343 MavCommandListEntry_t commandEntry = _list[index];
344
345 QString rawCommandName = MissionCommandTree::instance()->rawName(commandEntry.command);
346 QString friendlyName = MissionCommandTree::instance()->friendlyName(commandEntry.command);
347
348 if (++_list[index].tryCount > commandEntry.maxTries) {
349 QString logMsg = QStringLiteral("Giving up sending command after max retries: %1").arg(rawCommandName);
350
351 // For REQUEST_MESSAGE commands, also log which message was being requested
352 if (commandEntry.command == MAV_CMD_REQUEST_MESSAGE) {
353 int requestedMsgId = static_cast<int>(commandEntry.rgParam1);
354 const mavlink_message_info_t *info = mavlink_get_message_info_by_id(requestedMsgId);
355 logMsg += QStringLiteral(" requesting: %1").arg(info ? info->name : QString::number(requestedMsgId));
356 }
357
358 qCWarning(MavCommandQueueLog) << logMsg;
359
360 _list.removeAt(index);
361 if (commandEntry.ackHandlerInfo.resultHandler) {
362 mavlink_command_ack_t ack = {};
363 ack.result = MAV_RESULT_FAILED;
364 (*commandEntry.ackHandlerInfo.resultHandler)(commandEntry.ackHandlerInfo.resultHandlerData, commandEntry.targetCompId, ack, MavCmdResultFailureNoResponseToCommand);
365 } else {
366 emit commandResult(_vehicle->id(), commandEntry.targetCompId, commandEntry.command, MAV_RESULT_FAILED, MavCmdResultFailureNoResponseToCommand);
367 }
368 if (commandEntry.showError) {
369 QGC::showAppMessage(tr("Vehicle did not respond to command: %1").arg(friendlyName));
370 }
371 return;
372 }
373
374 if (commandEntry.tryCount > 1 && !_vehicle->px4Firmware() && commandEntry.command == MAV_CMD_START_RX_PAIR) {
375 // The implementation of this command comes from the IO layer and is shared across stacks. So for other firmwares
376 // we aren't really sure whether they are correct or not.
377 return;
378 }
379
380 qCDebug(MavCommandQueueLog) << "Sending" << _formatCommand(commandEntry.command, commandEntry.rgParam1)
381 << "tryCount:param1-7" << commandEntry.tryCount << commandEntry.rgParam1 << commandEntry.rgParam2 << commandEntry.rgParam3 << commandEntry.rgParam4 << commandEntry.rgParam5 << commandEntry.rgParam6 << commandEntry.rgParam7;
382
383 SharedLinkInterfacePtr sharedLink = _vehicle->vehicleLinkManager()->primaryLink().lock();
384 if (!sharedLink) {
385 qCDebug(MavCommandQueueLog) << "_sendFromList: primary link gone!";
386 return;
387 }
388
390
391 if (commandEntry.useCommandInt) {
392 mavlink_command_int_t cmd;
393 memset(&cmd, 0, sizeof(cmd));
394 cmd.target_system = _vehicle->id();
395 cmd.target_component = commandEntry.targetCompId;
396 cmd.command = commandEntry.command;
397 cmd.frame = commandEntry.frame;
398 cmd.param1 = commandEntry.rgParam1;
399 cmd.param2 = commandEntry.rgParam2;
400 cmd.param3 = commandEntry.rgParam3;
401 cmd.param4 = commandEntry.rgParam4;
402 cmd.x = commandEntry.frame == MAV_FRAME_MISSION ? commandEntry.rgParam5 : commandEntry.rgParam5 * 1e7;
403 cmd.y = commandEntry.frame == MAV_FRAME_MISSION ? commandEntry.rgParam6 : commandEntry.rgParam6 * 1e7;
404 cmd.z = commandEntry.rgParam7;
405 mavlink_msg_command_int_encode_chan(MAVLinkProtocol::instance()->getSystemId(),
407 sharedLink->mavlinkChannel(),
408 &msg,
409 &cmd);
410 } else {
412 memset(&cmd, 0, sizeof(cmd));
413 cmd.target_system = _vehicle->id();
414 cmd.target_component = commandEntry.targetCompId;
415 cmd.command = commandEntry.command;
416 // MAVLink spec: confirmation increments on each resend.
417 cmd.confirmation = static_cast<uint8_t>(qMin(commandEntry.tryCount - 1, 255));
418 cmd.param1 = commandEntry.rgParam1;
419 cmd.param2 = commandEntry.rgParam2;
420 cmd.param3 = commandEntry.rgParam3;
421 cmd.param4 = commandEntry.rgParam4;
422 cmd.param5 = static_cast<float>(commandEntry.rgParam5);
423 cmd.param6 = static_cast<float>(commandEntry.rgParam6);
424 cmd.param7 = commandEntry.rgParam7;
425 mavlink_msg_command_long_encode_chan(MAVLinkProtocol::instance()->getSystemId(),
427 sharedLink->mavlinkChannel(),
428 &msg,
429 &cmd);
430 }
431
432 _vehicle->sendMessageOnLinkThreadSafe(sharedLink.get(), msg);
433}
434
435void MavCommandQueue::_responseTimeoutCheck()
436{
437 if (_list.isEmpty()) {
438 return;
439 }
440
441 // Walk the list backwards since _sendFromList can remove entries. Give-up result
442 // handlers invoked from _sendFromList can also re-enter the queue and remove or
443 // clear entries (e.g. closing the vehicle from within the callback), so re-validate
444 // the stop flag and index on every iteration.
445 for (int i = _list.count() - 1; i >= 0; i--) {
446 if (_stopped) {
447 return;
448 }
449 if (i >= _list.count()) {
450 i = _list.count(); // Handler removed entries below us, clamp (loop decrement follows)
451 continue;
452 }
453 MavCommandListEntry_t& commandEntry = _list[i];
454 if (commandEntry.elapsedTimer.elapsed() > commandEntry.ackTimeoutMSecs) {
455 // Try sending command again
456 _sendFromList(i);
457 }
458 }
459}
460
462{
463 QString rawName = MissionCommandTree::instance()->rawName(static_cast<MAV_CMD>(ack.command));
464 QString friendlyName = MissionCommandTree::instance()->friendlyName(static_cast<MAV_CMD>(ack.command));
465 QString commandStr = friendlyName.isEmpty() ? rawName : QStringLiteral("%1 (%2)").arg(friendlyName, rawName);
466
467 switch (ack.result) {
468 case MAV_RESULT_TEMPORARILY_REJECTED:
469 QGC::showAppMessage(tr("%1 command temporarily rejected").arg(commandStr));
470 break;
471 case MAV_RESULT_DENIED:
472 QGC::showAppMessage(tr("%1 command denied").arg(commandStr));
473 break;
474 case MAV_RESULT_UNSUPPORTED:
475 QGC::showAppMessage(tr("%1 command not supported").arg(commandStr));
476 break;
477 case MAV_RESULT_FAILED:
478 QGC::showAppMessage(tr("%1 command failed").arg(commandStr));
479 break;
480 default:
481 // Do nothing
482 break;
483 }
484}
485
487{
488 int entryIndex = findEntryIndex(message.compid, static_cast<MAV_CMD>(ack.command));
489 if (entryIndex == -1) {
490 QString rawCommandName = MissionCommandTree::instance()->rawName(static_cast<MAV_CMD>(ack.command));
491 qCDebug(MavCommandQueueLog) << "handleCommandAck Ack not in list" << rawCommandName;
492 return;
493 }
494
495 if (ack.result == MAV_RESULT_IN_PROGRESS) {
496 MavCommandListEntry_t commandEntry;
497 if (_vehicle->px4Firmware() && ack.command == MAV_CMD_DO_AUTOTUNE_ENABLE) {
498 // Hack to support PX4 autotune which does not send final result ack and just sends in progress
499 commandEntry = _list.takeAt(entryIndex);
500 } else {
501 // Command has not completed yet, don't remove
502 MavCommandListEntry_t& commandEntryRef = _list[entryIndex];
503 commandEntryRef.maxTries = 1; // Vehicle responded to command so don't retry
504 commandEntryRef.elapsedTimer.start(); // We've heard from vehicle, restart elapsed timer for no ack received timeout
505 commandEntry = commandEntryRef;
506 }
507
508 if (commandEntry.ackHandlerInfo.progressHandler) {
509 (*commandEntry.ackHandlerInfo.progressHandler)(commandEntry.ackHandlerInfo.progressHandlerData, message.compid, ack);
510 }
511 return;
512 }
513
514 MavCommandListEntry_t commandEntry = _list.takeAt(entryIndex);
515 if (commandEntry.ackHandlerInfo.resultHandler) {
516 (*commandEntry.ackHandlerInfo.resultHandler)(commandEntry.ackHandlerInfo.resultHandlerData, message.compid, ack, MavCmdResultCommandResultOnly);
517 } else {
518 if (commandEntry.showError) {
520 }
521 emit commandResult(_vehicle->id(), message.compid, ack.command, ack.result, MavCmdResultCommandResultOnly);
522 }
523}
524
526{
527 switch (failureCode) {
529 return QStringLiteral("Command Result Only");
531 return QStringLiteral("No Response To Command");
533 return QStringLiteral("Duplicate Command");
534 default:
535 return QStringLiteral("Unknown (%1)").arg(failureCode);
536 }
537}
std::shared_ptr< LinkInterface > SharedLinkInterfacePtr
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
struct __mavlink_command_ack_t mavlink_command_ack_t
struct __mavlink_command_long_t mavlink_command_long_t
void setCommandSupported(MAV_CMD cmd, CommandSupportedResult status)
static int getComponentId()
static MAVLinkProtocol * instance()
Owns the COMMAND_LONG / COMMAND_INT send/retry/ack pipeline for a single Vehicle.
void sendCommandInt(int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
static QString failureCodeToString(MavCmdResultFailureCode_t failureCode)
static constexpr int kTestAckTimeoutMs
void commandResult(int vehicleId, int targetComponent, int command, int ackResult, int failureCode)
Emitted for every terminal ack that has no user-provided resultHandler.
void sendCommandIntWithHandler(const MavCmdAckHandlerInfo_t *ackHandlerInfo, int compId, MAV_CMD command, MAV_FRAME frame, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, double param5=0.0, double param6=0.0, float param7=0.0f)
void sendCommandWithHandler(const MavCmdAckHandlerInfo_t *ackHandlerInfo, int compId, MAV_CMD command, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f, float param6=0.0f, float param7=0.0f)
static constexpr int kMaxRetryCount
void sendWorker(bool commandInt, bool showError, const MavCmdAckHandlerInfo_t *ackHandlerInfo, int compId, MAV_CMD command, MAV_FRAME frame, float param1, float param2, float param3, float param4, double param5, double param6, float param7)
void handleCommandAck(const mavlink_message_t &message, const mavlink_command_ack_t &ack)
Process a COMMAND_ACK — match it to a pending entry and fire callbacks.
void sendCommandDelayed(int compId, MAV_CMD command, bool showError, int milliseconds, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f, float param6=0.0f, float param7=0.0f)
bool isPending(int targetCompId, MAV_CMD command) const
True if a matching (targetCompId, command) is already queued or awaiting ack.
static void showCommandAckError(const mavlink_command_ack_t &ack)
void sendCommand(int compId, MAV_CMD command, bool showError, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f, float param6=0.0f, float param7=0.0f)
int findEntryIndex(int targetCompId, MAV_CMD command) const
Index of a matching entry in the pending queue, or -1. Exposed for test use.
void sendCommandIntWithLambdaFallback(std::function< void()> lambda, int compId, MAV_CMD command, MAV_FRAME frame, bool showError, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, double param5=0.0, double param6=0.0, float param7=0.0f)
void sendCommandWithLambdaFallback(std::function< void()> lambda, int compId, MAV_CMD command, bool showError, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f, float param6=0.0f, float param7=0.0f)
static MissionCommandTree * instance()
QString rawName(MAV_CMD command) const
Returns the raw name for the specified command.
QString friendlyName(MAV_CMD command) const
Returns the friendly name for the specified command.
WeakLinkInterfacePtr primaryLink() const
bool px4Firmware() const
Definition Vehicle.h:498
VehicleLinkManager * vehicleLinkManager()
Definition Vehicle.h:579
int id() const
Definition Vehicle.h:429
bool sendMessageOnLinkThreadSafe(LinkInterface *link, mavlink_message_t message)
Definition Vehicle.cc:1386
class FirmwarePluginInstanceData * firmwarePluginInstanceData()
Definition Vehicle.h:697
bool runningUnitTests()
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.
Definition AppMessages.cc:9
Callback info bundle for sendMavCommandWithHandler.
MavCmdResultHandler resultHandler
nullptr for no handler
struct VehicleTypes::MavCmdAckHandlerInfo_s MavCmdAckHandlerInfo_t
Callback info bundle for sendMavCommandWithHandler.
@ MavCmdResultFailureDuplicateCommand
Unable to send command since duplicate is already being waited on for response.
@ MavCmdResultCommandResultOnly
commandResult specifies full success/fail info
@ MavCmdResultFailureNoResponseToCommand
No response from vehicle to command.