QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
MockLink.h
Go to the documentation of this file.
1#pragma once
2
4#include "LinkInterface.h"
5#include "MAVLinkEnums.h"
7#include "QGCMAVLinkTypes.h"
8#include "MockConfiguration.h"
11
12#include <QtCore/QElapsedTimer>
13#include <QtCore/QMap>
14#include <QtCore/QMutex>
15#include <QtCore/QSet>
16#include <QtPositioning/QGeoCoordinate>
17
18#include <array>
19#include <atomic>
20
21class MockLinkCamera;
22class MockLinkFTP;
23class MockLinkGimbal;
24class MockLinkWorker;
25class QThread;
26
27class MockLink : public LinkInterface
28{
29 Q_OBJECT
30 friend class MockLinkFTP;
31
32public:
33 explicit MockLink(SharedLinkConfigurationPtr &config, QObject *parent = nullptr);
34 virtual ~MockLink();
35
36 void run1HzTasks();
37 void run10HzTasks();
38 void run500HzTasks();
40
41 bool shouldSendStatusText() const { return _sendStatusText; }
42
43 bool isConnected() const final { return _connected; }
44 void disconnect() final;
45
46 Q_INVOKABLE void setCommLost(bool commLost) { _commLost = commLost; }
47 Q_INVOKABLE void simulateConnectionRemoved();
48
49 int vehicleId() const { return _vehicleSystemId; }
50 MAV_AUTOPILOT getFirmwareType() const { return _firmwareType; }
51
52 double vehicleLatitude() const { return _vehicleLatitude; }
53 double vehicleLongitude() const { return _vehicleLongitude; }
54 double vehicleAltitudeAMSL() const { return _vehicleAltitudeAMSL; }
55
56 bool signingEnabled() const { return _signingEnabled; }
57
60
63 void sendStatusTextMessage(uint8_t severity, const QString &text);
64
66 void setCalibrationPose(MockLinkPX4Calibration::Pose pose) const { _mockLinkPX4Calibration->setPose(pose); }
67
68 MockLinkFTP *mockLinkFTP() const;
69
71 void setArmed(bool armed) { if (armed) _mavBaseMode |= MAV_MODE_FLAG_SAFETY_ARMED; else _mavBaseMode &= ~MAV_MODE_FLAG_SAFETY_ARMED; }
72 bool armed() const { return (_mavBaseMode & MAV_MODE_FLAG_SAFETY_ARMED) != 0; }
73
77 void setMissionItemFailureMode(MockLinkMissionItemHandler::FailureMode_t failureMode, MAV_MISSION_RESULT failureAckResult) const { _missionItemHandler->setFailureMode(failureMode, failureAckResult); }
78
80 void sendUnexpectedMissionAck(MAV_MISSION_RESULT ackType) const { _missionItemHandler->sendUnexpectedMissionAck(ackType); }
81
83 void sendUnexpectedMissionItem() const { _missionItemHandler->sendUnexpectedMissionItem(); }
84
86 void sendUnexpectedMissionRequest() const { _missionItemHandler->sendUnexpectedMissionRequest(); }
87
88 void sendUnexpectedCommandAck(MAV_CMD command, MAV_RESULT ackResult);
89
91 void resetMissionItemHandler() const { _missionItemHandler->reset(); }
92
94 void loadSimpleMultirotorMission() const { _missionItemHandler->loadSimpleMultirotorMission(); }
95
97 QString logDownloadFile() const { return _logDownloadFilename; }
98
99 void clearReceivedMavCommandCounts() { _receivedMavCommandCountMap.clear(); _receivedMavCommandByCompCountMap.clear(); _receivedRequestMessageByCompAndMsgCountMap.clear(); }
100 int receivedMavCommandCount(MAV_CMD command) const { return _receivedMavCommandCountMap.value(command, 0); }
101 int receivedMavCommandCount(MAV_CMD command, int compId) const { return _receivedMavCommandByCompCountMap.value(command).value(compId, 0); }
102 int receivedRequestMessageCount(int compId, int messageId) const { return _receivedRequestMessageByCompAndMsgCountMap.value(compId).value(messageId, 0); }
103 void clearReceivedRequestMessageCounts() { _receivedRequestMessageCountMap.clear(); _receivedRequestMessageByCompAndMsgCountMap.clear(); }
104 int receivedRequestMessageCount(uint32_t messageId) const { return _receivedRequestMessageCountMap.value(messageId, 0); }
105 void clearReceivedMavlinkMessageCounts() { _receivedMavlinkMessageCountMap.clear(); _hashCheckRequestCount = 0; _missionItemHandler->clearRequestListCounts(); }
106 int receivedMavlinkMessageCount(uint32_t messageId) const { return _receivedMavlinkMessageCountMap.value(messageId, 0); }
107 int receivedMissionRequestListCount(MAV_MISSION_TYPE type) const { return _missionItemHandler->requestListCount(type); }
108
115 void setRequestMessageFailureMode(RequestMessageFailureMode_t failureMode) { _requestMessageFailureMode = failureMode; }
116
119 void setRequestMessageNoResponse(uint32_t messageId, bool noResponse = true) {
120 QMutexLocker locker(&_requestMessageNoResponseMutex);
121 if (noResponse) {
122 _requestMessageNoResponseIds.insert(messageId);
123 } else {
124 _requestMessageNoResponseIds.remove(messageId);
125 }
126 }
127
135 _paramSetFailureMode = mode;
136 _paramSetFailureFirstAttemptPending = (mode == FailParamSetFirstAttemptNoAck);
137 }
138
146 _paramRequestReadFailureMode = mode;
147 _paramRequestReadFailureFirstAttemptPending = (mode == FailParamRequestReadFirstAttemptNoResponse);
148 }
149
150 void setHashCheckNoResponse(bool noResponse) { _hashCheckNoResponse = noResponse; }
151
155 void setResetSysAutostartOnParamReset(bool reset) { _resetSysAutostartOnParamReset = reset; }
156
158 int hashCheckRequestCount() const { return _hashCheckRequestCount; }
159
161 void setMockParamValue(int componentId, const QString &paramName, float value);
162
165 void setInt32ParamValue(int componentId, const QString &paramName, int32_t value) { _mapParamName2Value[componentId][paramName] = QVariant::fromValue(value); }
166
169 QVariant paramValue(int componentId, const QString &paramName) const { return _mapParamName2Value.value(componentId).value(paramName); }
170
171 static MockLink *startPX4MockLink(bool sendStatusText, bool enableCamera, bool enableGimbal, MockConfiguration::FailureMode_t failureMode = MockConfiguration::FailNone);
172 static MockLink *startPX4MockLinkWithMission(bool sendStatusText, bool enableCamera, bool enableGimbal, MockConfiguration::FailureMode_t failureMode = MockConfiguration::FailNone);
173 static MockLink *startGenericMockLink(bool sendStatusText, bool enableCamera, bool enableGimbal, MockConfiguration::FailureMode_t failureMode = MockConfiguration::FailNone);
174 static MockLink *startNoInitialConnectMockLink(bool sendStatusText, bool enableCamera, bool enableGimbal, MockConfiguration::FailureMode_t failureMode = MockConfiguration::FailNone);
175 static MockLink *startAPMArduCopterMockLink(bool sendStatusText, bool enableCamera, bool enableGimbal, MockConfiguration::FailureMode_t failureMode = MockConfiguration::FailNone);
176 static MockLink *startAPMArduPlaneMockLink(bool sendStatusText, bool enableCamera, bool enableGimbal, MockConfiguration::FailureMode_t failureMode = MockConfiguration::FailNone);
177 static MockLink *startAPMArduSubMockLink(bool sendStatusText, bool enableCamera, bool enableGimbal, MockConfiguration::FailureMode_t failureMode = MockConfiguration::FailNone);
178 static MockLink *startAPMArduRoverMockLink(bool sendStatusText, bool enableCamera, bool enableGimbal, MockConfiguration::FailureMode_t failureMode = MockConfiguration::FailNone);
179
180 // Special commands for testing Vehicle::sendMavCommandWithHandler
181 static constexpr MAV_CMD MAV_CMD_MOCKLINK_ALWAYS_RESULT_ACCEPTED = MAV_CMD_USER_1;
182 static constexpr MAV_CMD MAV_CMD_MOCKLINK_ALWAYS_RESULT_FAILED = MAV_CMD_USER_2;
183 static constexpr MAV_CMD MAV_CMD_MOCKLINK_SECOND_ATTEMPT_RESULT_ACCEPTED = MAV_CMD_USER_3;
184 static constexpr MAV_CMD MAV_CMD_MOCKLINK_SECOND_ATTEMPT_RESULT_FAILED = MAV_CMD_USER_4;
185 static constexpr MAV_CMD MAV_CMD_MOCKLINK_NO_RESPONSE = MAV_CMD_USER_5;
186 static constexpr MAV_CMD MAV_CMD_MOCKLINK_NO_RESPONSE_NO_RETRY = static_cast<MAV_CMD>(MAV_CMD_USER_5 + 1);
187 static constexpr MAV_CMD MAV_CMD_MOCKLINK_RESULT_IN_PROGRESS_ACCEPTED = static_cast<MAV_CMD>(MAV_CMD_USER_5 + 2);
188 static constexpr MAV_CMD MAV_CMD_MOCKLINK_RESULT_IN_PROGRESS_FAILED = static_cast<MAV_CMD>(MAV_CMD_USER_5 + 3);
189 static constexpr MAV_CMD MAV_CMD_MOCKLINK_RESULT_IN_PROGRESS_NO_ACK = static_cast<MAV_CMD>(MAV_CMD_USER_5 + 4);
190
191signals:
192 void writeBytesQueuedSignal(const QByteArray &bytes);
193 void highLatencyTransmissionEnabledChanged(bool highLatencyTransmissionEnabled);
194
195private slots:
197 void _writeBytes(const QByteArray &bytes) final;
198 void _writeBytesQueued(const QByteArray &bytes);
199
200private:
201 typedef struct {
202 const char *name;
203 uint8_t standard_mode;
204 uint32_t custom_mode;
205 bool canBeSet;
206 bool advanced;
207 } FlightMode_t;
208
209 bool _connect() final;
210 bool _allocateMavlinkChannel() final;
211 void _freeMavlinkChannel() final;
212
213 bool _incomingMavlinkChannelIsSet() const;
214 bool _outgoingMavlinkChannelIsSet() const;
215
216 void _loadParams();
217 void _resetParamsToDefaults();
218
220 float _floatUnionForParam(int componentId, const QString &paramName);
221 uint32_t _computeParamHash(int componentId) const;
222 void _setParamFloatUnionIntoMap(int componentId, const QString &paramName, float paramFloat);
223
225 void _handleIncomingNSHBytes(const char *bytes, int cBytes);
227 void _handleIncomingMavlinkBytes(const uint8_t *bytes, int cBytes);
229 void _updateIncomingMessageCounts(const mavlink_message_t &msg);
230 void _handleIncomingMavlinkMsg(const mavlink_message_t &msg);
231 void _handleHeartBeat(const mavlink_message_t &msg);
232 void _handleSetMode(const mavlink_message_t &msg);
233 void _handleParamRequestList(const mavlink_message_t &msg);
234 void _handleParamSet(const mavlink_message_t &msg);
235 void _handleParamRequestRead(const mavlink_message_t &msg);
236 void _handleFTP(const mavlink_message_t &msg);
237 void _handleCommandLong(const mavlink_message_t &msg);
238 void _handleCommandInt(const mavlink_message_t &msg);
239 void _handleInProgressCommandLong(const mavlink_command_long_t &request);
240 void _handleCommandLongSetMessageInterval(const mavlink_command_long_t &request, bool &acccepted);
241 void _handleManualControl(const mavlink_message_t &msg);
242 void _handleRCChannelsOverride(const mavlink_message_t &msg);
243 void _handlePreFlightCalibration(const mavlink_command_long_t &request);
244 void _handleTakeoff(const mavlink_command_long_t &request);
245 void _handleLogRequestList(const mavlink_message_t &msg);
246 void _handleLogRequestData(const mavlink_message_t &msg);
247 void _handleParamMapRC(const mavlink_message_t &msg);
248 void _handleSetupSigning(const mavlink_message_t &msg);
249 void _sendParamError(int componentId, const char *paramId, int16_t paramIndex, uint8_t errorCode);
250 void _handleRequestMessage(const mavlink_command_long_t &request, bool &accepted, bool &noAck);
251 void _handleRequestMessageAutopilotVersion(const mavlink_command_long_t &request, bool &accepted);
252 void _handleRequestMessageDebug(const mavlink_command_long_t &request, bool &accepted, bool &noAck);
253 void _handleRequestMessageAvailableModes(const mavlink_command_long_t &request, bool &accepted);
254
255 void _sendHeartBeat();
256 void _sendHighLatency2();
257 void _sendHomePosition();
258 void _sendGpsRawInt();
259 void _sendGlobalPositionInt();
260 void _sendExtendedSysState();
261 void _sendVibration();
262 void _sendSysStatus();
263 void _sendBatteryStatus();
264 void _sendNamedValueFloats();
265 void _sendChunkedStatusText(uint16_t chunkId, bool missingChunks);
266 void _sendStatusTextMessages();
267 void _respondWithAutopilotVersion();
268 void _sendRCChannels();
269 void _sendADSBVehicles();
270 void _sendGeneralMetaData();
271 void _sendRemoteIDArmStatus();
272 void _sendEscInfo();
273 void _sendEscStatus();
274 void _sendRadioStatus();
275 void _sendAvailableModesMonitor();
276 void _sendAttitudeQuaternion();
277 void _sendAttitudeTarget();
278 void _sendLocalPositionNed();
279 void _sendPositionTargetLocalNed();
280
281 void _paramRequestListWorker();
282 void _logDownloadWorker();
283 void _availableModesWorker();
284 void _apmCompassCalWorker();
285 void _apmAccelCalWorker();
286 void _sendAvailableMode(uint8_t modeIndexOneBased);
287 int _availableModesCount() const;
288 void _moveADSBVehicle(int vehicleIndex);
289
290 static MockLink *_startMockLinkWorker(const QString &configName, MAV_AUTOPILOT firmwareType, MAV_TYPE vehicleType, bool sendStatusText, bool enableCamera, bool enableGimbal, MockConfiguration::FailureMode_t failureMode, bool preloadMission = false);
291 static MockLink *_startMockLink(MockConfiguration *mockConfig);
292
295 static QString _createRandomFile(uint32_t byteCount);
296
297 QThread *_workerThread = nullptr;
298 MockLinkWorker *_worker = nullptr;
299
300 const MockConfiguration *_mockConfig = nullptr;
301 const MAV_AUTOPILOT _firmwareType = MAV_AUTOPILOT_PX4;
302 const MAV_TYPE _vehicleType = MAV_TYPE_QUADROTOR;
303 const bool _sendStatusText = false;
304 const bool _enableCamera = false;
305 const bool _enableGimbal = false;
306 const MockConfiguration::FailureMode_t _failureMode = MockConfiguration::FailNone;
307 const uint8_t _vehicleSystemId = 0;
308 const double _vehicleLatitude = 0.0;
309 const double _vehicleLongitude = 0.0;
310 // These are just set for reporting the fields in _respondWithAutopilotVersion()
311 // and ensuring that the Vehicle reports the fields in Vehicle::firmwareBoardVendorId etc.
312 // They do not control any mock simulation (and it is up to the Custom build to do that).
313 const uint16_t _boardVendorId = 0;
314 const uint16_t _boardProductId = 0;
315 MockLinkMissionItemHandler *const _missionItemHandler = nullptr;
316 MockLinkCamera *const _mockLinkCamera = nullptr;
317 MockLinkGimbal *const _mockLinkGimbal = nullptr;
318 MockLinkPX4Calibration *const _mockLinkPX4Calibration = nullptr;
319 MockLinkFTP *const _mockLinkFTP = nullptr;
320
321 uint8_t _incomingMavlinkChannel = std::numeric_limits<uint8_t>::max();
322 QMutex _incomingMavlinkMutex;
324 uint8_t _outgoingMavlinkChannel = std::numeric_limits<uint8_t>::max();
325
326 mavlink_signing_t _mockSigning{};
327 mavlink_signing_streams_t _mockSigningStreams{};
328
329 bool _connected = false;
330 bool _inNSH = false;
331
332 uint8_t _mavBaseMode = MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
333 uint32_t _mavCustomMode = PX4CustomMode::MANUAL;
334 uint8_t _mavState = MAV_STATE_STANDBY;
335
336 QElapsedTimer _runningTime;
337 static constexpr int kTestParamRequestListBatch = 25;
338 static constexpr int32_t _batteryMaxTimeRemaining = 15 * 60;
339 int8_t _battery1PctRemaining = 100;
340 int32_t _battery1TimeRemaining = _batteryMaxTimeRemaining;
341 MAV_BATTERY_CHARGE_STATE _battery1ChargeState = MAV_BATTERY_CHARGE_STATE_OK;
342 int8_t _battery2PctRemaining = 100;
343 int32_t _battery2TimeRemaining = _batteryMaxTimeRemaining;
344 MAV_BATTERY_CHARGE_STATE _battery2ChargeState = MAV_BATTERY_CHARGE_STATE_OK;
345
346 double _vehicleAltitudeAMSL = _defaultVehicleHomeAltitude;
347 std::atomic<bool> _commLost = false;
348 bool _signingEnabled = false;
349 bool _highLatencyTransmissionEnabled = true;
350
351 int _sendHomePositionDelayCount = 10;
352 int _sendGPSPositionDelayCount = 100;
353
354 int _currentParamRequestListComponentIndex = -1;
355 int _currentParamRequestListParamIndex = -1;
356 QList<int> _paramRequestListComponentIds;
357 QStringList _paramRequestListParamNames;
361 QMutex _paramRequestListMutex;
362
363 // Mavlink standard modes worker information
364 int _availableModesWorkerNextModeIndex = 0;
368 QMutex _availableModesWorkerMutex;
369 uint8_t _availableModesMonitorSeqNumber = 0;
370
371 QString _logDownloadFilename;
372 uint32_t _logDownloadCurrentOffset = 0;
373 uint32_t _logDownloadBytesRemaining = 0;
377 QMutex _logDownloadMutex;
378
379 RequestMessageFailureMode_t _requestMessageFailureMode = FailRequestMessageNone;
380 mutable QMutex _requestMessageNoResponseMutex;
381 QSet<uint32_t> _requestMessageNoResponseIds;
382 ParamSetFailureMode_t _paramSetFailureMode = FailParamSetNone;
383 bool _paramSetFailureFirstAttemptPending = false;
384 ParamRequestReadFailureMode_t _paramRequestReadFailureMode = FailParamRequestReadNone;
385 bool _paramRequestReadFailureFirstAttemptPending = false;
386 bool _hashCheckNoResponse = false;
387 int _hashCheckRequestCount = 0;
388 bool _paramRequestListHashCheckSent = false;
389 bool _resetSysAutostartOnParamReset = false;
390
391 // APM compass calibration worker state
392 // Protects _apmCompassCalProgress: main thread writes 0 to start/stop,
393 // worker thread reads/increments each 100ms tick.
394 QMutex _apmCompassCalMutex;
395 int _apmCompassCalProgress = -1;
396 int _apmCompassCalTickCount = 0;
397
398 // APM accel calibration worker state
399 // Protects _apmAccelCalPos: main thread writes the starting pos,
400 // worker thread reads and advances through the sequence.
401 QMutex _apmAccelCalMutex;
403 static constexpr ACCELCAL_VEHICLE_POS kAPMAccelCalPosSequence[] = {
404 ACCELCAL_VEHICLE_POS_LEVEL,
405 ACCELCAL_VEHICLE_POS_LEFT,
406 ACCELCAL_VEHICLE_POS_RIGHT,
407 ACCELCAL_VEHICLE_POS_NOSEDOWN,
408 ACCELCAL_VEHICLE_POS_NOSEUP,
409 ACCELCAL_VEHICLE_POS_BACK,
410 };
411 int _apmAccelCalPosIndex = -1;
412 bool _apmAccelCalGotAck = false;
413 int _apmAccelCalTickCount = 0;
414
415 struct RCChannelOverride {
416 enum class State { Ignore, Overridden, Released } state = State::Ignore;
417 uint16_t value = 0;
418 };
419 static constexpr int kRcChannelOverrideChannelCount = 18;
420 std::array<RCChannelOverride, kRcChannelOverrideChannelCount> _rcChannelOverrides;
421
422 QMap<MAV_CMD, int> _receivedMavCommandCountMap;
423 QMap<MAV_CMD, QMap<int, int>> _receivedMavCommandByCompCountMap;
424 QMap<uint32_t, int> _receivedRequestMessageCountMap;
425 QMap<int, QMap<int, int>> _receivedRequestMessageByCompAndMsgCountMap;
426 QMap<uint32_t, int> _receivedMavlinkMessageCountMap;
427 QMap<int, QMap<QString, QVariant>> _mapParamName2Value;
428 QMap<int, QMap<QString, MAV_PARAM_TYPE>> _mapParamName2MavParamType;
429
430 struct ADSBVehicle {
431 QGeoCoordinate coordinate;
432 double angle = 0.0;
433 double altitude = 0.0;
434 };
435 QList<ADSBVehicle> _adsbVehicles;
436 QList<QGeoCoordinate> _adsbVehicleCoordinates;
437 static constexpr int _numberOfVehicles = 5;
438 double _adsbAngles[_numberOfVehicles]{};
439
440 static std::atomic<int> _nextVehicleSystemId;
441
442 // Vehicle position is set close to default Gazebo vehicle location. This allows for multi-vehicle
443 // testing of a gazebo vehicle and a mocklink vehicle
444 static constexpr double _defaultVehicleLatitude = 47.397;
445 static constexpr double _defaultVehicleLongitude = 8.5455;
446 static constexpr double _defaultVehicleHomeAltitude = 488.056;
447
448 static constexpr const char *_failParam = "COM_FLTMODE6";
449
450 static constexpr uint8_t _vehicleComponentId = MAV_COMP_ID_AUTOPILOT1;
451
452 static constexpr uint16_t _logDownloadLogId = 0;
453 static constexpr uint32_t _logDownloadFileSize = 1000;
454
455 static constexpr bool _mavlinkStarted = true;
456
460 inline static const QSet<QString> kAPMCalOffsetParams = {
461 QStringLiteral("COMPASS_OFS_X"), QStringLiteral("COMPASS_OFS_Y"), QStringLiteral("COMPASS_OFS_Z"),
462 QStringLiteral("COMPASS_OFS2_X"), QStringLiteral("COMPASS_OFS2_Y"), QStringLiteral("COMPASS_OFS2_Z"),
463 QStringLiteral("COMPASS_OFS3_X"), QStringLiteral("COMPASS_OFS3_Y"), QStringLiteral("COMPASS_OFS3_Z"),
464 QStringLiteral("INS_ACCOFFS_X"), QStringLiteral("INS_ACCOFFS_Y"), QStringLiteral("INS_ACCOFFS_Z"),
465 };
466
467 static QList<FlightMode_t> _availableFlightModes;
468
469 std::atomic<bool> _disconnectedEmitted{false};
470};
Config config
std::shared_ptr< LinkConfiguration > SharedLinkConfigurationPtr
struct __mavlink_message mavlink_message_t
struct __mavlink_command_long_t mavlink_command_long_t
The link interface defines the interface for all links used to communicate with the ground station ap...
Simulates MAVLink Camera Protocol v2 components for MockLink.
Mock implementation of Mavlink FTP server.
Definition MockLinkFTP.h:16
Simulates MAVLink Gimbal Manager Protocol for MockLink.
int requestListCount(MAV_MISSION_TYPE type) const
void sendUnexpectedMissionAck(MAV_MISSION_RESULT ackType)
Called to send a MISSION_ACK message while the MissionManager is in idle state.
void reset()
Reset the state of the MissionItemHandler to no items, no transactions in progress.
void setFailureMode(FailureMode_t failureMode, MAV_MISSION_RESULT failureAckResult)
void sendUnexpectedMissionRequest()
Called to send a MISSION_REQUEST message while the MissionManager is in idle state.
void sendUnexpectedMissionItem()
Called to send a MISSION_ITEM message while the MissionManager is in idle state.
Simulates the PX4 commander magnetometer and accelerometer calibration protocols for MockLink.
Pose
Vehicle poses. Order matches the PX4 detect_orientation_return enum.
Worker class that runs periodic tasks for MockLink simulation.