QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
MockLinkMissionItemHandler.cc
Go to the documentation of this file.
2
3#include "MAVLinkProtocol.h"
4#include "MockLink.h"
6
7QGC_LOGGING_CATEGORY(MockLinkMissionItemHandlerLog, "Comms.MockLink.MockLinkMissionItemHandler")
8
10 : QObject(mockLink)
11 , _mockLink(mockLink)
12{
13 // qCDebug(MockLinkMissionItemHandlerLog) << Q_FUNC_INFO << this;
14
15 Q_ASSERT(mockLink);
16
17 (void) connect(&_missionItemResponseTimer, &QTimer::timeout, this, &MockLinkMissionItemHandler::_missionItemResponseTimeout);
18}
19
21{
22 // qCDebug(MockLinkMissionItemHandlerLog) << Q_FUNC_INFO << this;
23}
24
25void MockLinkMissionItemHandler::_startMissionItemResponseTimer()
26{
27 _missionItemResponseTimer.start(500);
28}
29
31{
32 _missionItems.clear();
33
34 constexpr double homeLatitude = 47.397;
35 constexpr double homeLongitude = 8.5455;
36 constexpr float relativeAltitude = 50.0f;
37
38 const auto makeItem = [](uint16_t seq, uint16_t command, bool current, double latitude, double longitude, float altitude) {
39 mavlink_mission_item_int_t item{};
40 item.seq = seq;
41 item.frame = MAV_FRAME_GLOBAL_RELATIVE_ALT;
42 item.command = command;
43 item.current = current ? 1 : 0;
44 item.autocontinue = 1;
45 item.x = static_cast<int32_t>(latitude * 1e7);
46 item.y = static_cast<int32_t>(longitude * 1e7);
47 item.z = altitude;
48 item.mission_type = MAV_MISSION_TYPE_MISSION;
49 return item;
50 };
51
52 // Seq 0: Takeoff
53 _missionItems[0] = makeItem(0, MAV_CMD_NAV_TAKEOFF, true, homeLatitude, homeLongitude, relativeAltitude);
54 // Seq 1: Waypoint
55 _missionItems[1] = makeItem(1, MAV_CMD_NAV_WAYPOINT, false, homeLatitude + 0.001, homeLongitude + 0.001, relativeAltitude);
56 // Seq 2: Return to launch
57 _missionItems[2] = makeItem(2, MAV_CMD_NAV_RETURN_TO_LAUNCH, false, 0.0, 0.0, 0.0);
58
59 qCDebug(MockLinkMissionItemHandlerLog) << "loadSimpleMultirotorMission seeded" << _missionItems.count() << "items";
60}
61
63{
64 switch (msg.msgid) {
65 case MAVLINK_MSG_ID_MISSION_REQUEST_LIST:
66 _handleMissionRequestList(msg);
67 break;
68 case MAVLINK_MSG_ID_MISSION_REQUEST_INT:
69 _handleMissionRequest(msg);
70 break;
71 case MAVLINK_MSG_ID_MISSION_ITEM_INT:
72 _handleMissionItem(msg);
73 break;
74 case MAVLINK_MSG_ID_MISSION_COUNT:
75 _handleMissionCount(msg);
76 break;
77 case MAVLINK_MSG_ID_MISSION_ACK:
78 // Acks are received back for each MISSION_ITEM message
79 break;
80 case MAVLINK_MSG_ID_MISSION_SET_CURRENT:
81 // Sets the currently active mission item
82 break;
83 case MAVLINK_MSG_ID_MISSION_CLEAR_ALL:
84 _handleMissionClearAll(msg);
85 break;
86 default:
87 return false;
88 }
89
90 return true;
91}
92
93void MockLinkMissionItemHandler::_handleMissionClearAll(const mavlink_message_t &msg)
94{
95 mavlink_mission_clear_all_t clearAll{};
96 mavlink_msg_mission_clear_all_decode(&msg, &clearAll);
97
98 Q_ASSERT(clearAll.target_system == _mockLink->vehicleId());
99
100 _requestType = static_cast<MAV_MISSION_TYPE>(clearAll.mission_type);
101 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionClearAll" << _requestType;
102
103 switch (_requestType) {
104 case MAV_MISSION_TYPE_MISSION:
105 _missionItems.clear();
106 break;
107 case MAV_MISSION_TYPE_FENCE:
108 _fenceItems.clear();
109 break;
110 case MAV_MISSION_TYPE_RALLY:
111 _rallyItems.clear();
112 break;
113 case MAV_MISSION_TYPE_ALL:
114 _missionItems.clear();
115 _fenceItems.clear();
116 _rallyItems.clear();
117 break;
118 default:
119 Q_ASSERT(false);
120 }
121
122 _sendAck(MAV_MISSION_ACCEPTED);
123}
124
125void MockLinkMissionItemHandler::_handleMissionRequestList(const mavlink_message_t &msg)
126{
127 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequestList read sequence";
128
129 _failReadRequest1FirstResponse = true;
130
131 mavlink_mission_request_list_t request{};
132 mavlink_msg_mission_request_list_decode(&msg, &request);
133
134 if (_failureMode == FailReadRequestListNoResponse) {
135 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequestList not responding due to failure mode FailReadRequestListNoResponse";
136 return;
137 }
138
139 if ((_failureMode == FailReadRequestListFirstResponse) && _failReadRequestListFirstResponse) {
140 _failReadRequestListFirstResponse = false;
141 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequestList not responding due to failure mode FailReadRequestListFirstResponse";
142 return;
143 }
144
145 _failReadRequestListFirstResponse = true;
146
147 Q_ASSERT(request.target_system == _mockLink->vehicleId());
148 _requestListCounts[static_cast<MAV_MISSION_TYPE>(request.mission_type)]++;
149
150 _requestType = static_cast<MAV_MISSION_TYPE>(request.mission_type);
151
152 int itemCount;
153 switch (_requestType) {
154 case MAV_MISSION_TYPE_MISSION:
155 itemCount = _missionItems.count();
156 if (itemCount == 0 && _sendHomePositionOnEmptyList) {
157 itemCount = 1;
158 }
159 break;
160 case MAV_MISSION_TYPE_FENCE:
161 itemCount = _fenceItems.count();
162 break;
163 case MAV_MISSION_TYPE_RALLY:
164 itemCount = _rallyItems.count();
165 break;
166 default:
167 Q_ASSERT(false);
168 }
169
170 mavlink_message_t responseMsg{};
171 (void) mavlink_msg_mission_count_pack_chan(
172 _mockLink->vehicleId(),
173 MAV_COMP_ID_AUTOPILOT1,
174 _mockLink->mavlinkChannel(),
175 &responseMsg, // Outgoing message
176 msg.sysid, // Target is original sender
177 msg.compid, // Target is original sender
178 itemCount, // Number of mission items
179 _requestType,
180 0
181 );
182
183 _mockLink->respondWithMavlinkMessage(responseMsg);
184}
185
186void MockLinkMissionItemHandler::_handleMissionRequest(const mavlink_message_t &msg)
187{
188 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest read sequence";
189
190 mavlink_mission_request_int_t request{};
191 mavlink_msg_mission_request_int_decode(&msg, &request);
192
193 Q_ASSERT(request.target_system == _mockLink->vehicleId());
194
195 if ((_failureMode == FailReadRequest0NoResponse) && (request.seq == 0)) {
196 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest not responding due to failure mode FailReadRequest0NoResponse";
197 return;
198 }
199
200 if ((_failureMode == FailReadRequest1NoResponse) && (request.seq == 1)) {
201 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest not responding due to failure mode FailReadRequest1NoResponse";
202 return;
203 }
204
205 if ((_failureMode == FailReadRequest1FirstResponse) && (request.seq == 1) && _failReadRequest1FirstResponse) {
206 _failReadRequest1FirstResponse = false;
207 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest not responding due to failure mode FailReadRequest1FirstResponse";
208 return;
209 }
210
211 // FIXME: Track whether all items are requested, or requested in sequence
212
213 if (((_failureMode == FailReadRequest0IncorrectSequence) && (request.seq == 0)) ||
214 ((_failureMode == FailReadRequest1IncorrectSequence) && (request.seq == 1))) {
215 // Send back the incorrect sequence number
216 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest sending bad sequence number";
217 request.seq++;
218 }
219
220 if (((_failureMode == FailReadRequest0ErrorAck) && (request.seq == 0)) ||
221 ((_failureMode == FailReadRequest1ErrorAck) && (request.seq == 1))) {
222 _sendAck(_failureAckResult);
223 return;
224 }
225
226 mavlink_mission_item_int_t missionItemInt{};
227
228 switch (request.mission_type) {
229 case MAV_MISSION_TYPE_MISSION:
230 if (_missionItems.isEmpty() && _sendHomePositionOnEmptyList) {
231 (void) memset(&missionItemInt, 0, sizeof(missionItemInt));
232 missionItemInt.frame = MAV_FRAME_GLOBAL_RELATIVE_ALT;
233 missionItemInt.command = MAV_CMD_NAV_WAYPOINT;
234 missionItemInt.autocontinue = true;
235 } else {
236 missionItemInt = _missionItems[request.seq];
237 }
238 break;
239 case MAV_MISSION_TYPE_FENCE:
240 missionItemInt = _fenceItems[request.seq];
241 break;
242 case MAV_MISSION_TYPE_RALLY:
243 missionItemInt = _rallyItems[request.seq];
244 break;
245 default:
246 Q_ASSERT(false);
247 }
248
249 mavlink_message_t responseMsg{};
250 (void) mavlink_msg_mission_item_int_pack_chan(
251 _mockLink->vehicleId(),
252 MAV_COMP_ID_AUTOPILOT1,
253 _mockLink->mavlinkChannel(),
254 &responseMsg, // Outgoing message
255 msg.sysid, // Target is original sender
256 msg.compid, // Target is original sender
257 request.seq, // Index of mission item being sent
258 missionItemInt.frame,
259 missionItemInt.command,
260 missionItemInt.current,
261 missionItemInt.autocontinue,
262 missionItemInt.param1, missionItemInt.param2, missionItemInt.param3, missionItemInt.param4,
263 missionItemInt.x, missionItemInt.y, missionItemInt.z,
264 _requestType
265 );
266
267 _mockLink->respondWithMavlinkMessage(responseMsg);
268}
269
270void MockLinkMissionItemHandler::_handleMissionCount(const mavlink_message_t &msg)
271{
272 mavlink_mission_count_t missionCount{};
273 mavlink_msg_mission_count_decode(&msg, &missionCount);
274 Q_ASSERT(missionCount.target_system == _mockLink->vehicleId());
275
276 _requestType = (MAV_MISSION_TYPE)missionCount.mission_type;
277 _writeSequenceCount = missionCount.count;
278 Q_ASSERT(_writeSequenceCount >= 0);
279
280 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionCount write sequence _writeSequenceCount:" << _writeSequenceCount;
281
282 switch (missionCount.mission_type) {
283 case MAV_MISSION_TYPE_MISSION:
284 _missionItems.clear();
285 break;
286 case MAV_MISSION_TYPE_FENCE:
287 _fenceItems.clear();
288 break;
289 case MAV_MISSION_TYPE_RALLY:
290 _rallyItems.clear();
291 break;
292 }
293
294 if (_writeSequenceCount == 0) {
295 _sendAck(MAV_MISSION_ACCEPTED);
296 return;
297 }
298
299 if (_failureMode == FailWriteMissionCountNoResponse) {
300 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionCount not responding due to failure mode FailWriteMissionCountNoResponse";
301 return;
302 }
303
304 if (_failureMode == FailWriteMissionCountFirstResponse && _failWriteMissionCountFirstResponse) {
305 _failWriteMissionCountFirstResponse = false;
306 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionCount not responding due to failure mode FailWriteMissionCountNoResponse";
307 return;
308 }
309
310 _failWriteMissionCountFirstResponse = true;
311 _writeSequenceIndex = 0;
312 _requestNextMissionItem(_writeSequenceIndex);
313}
314
315void MockLinkMissionItemHandler::_requestNextMissionItem(int sequenceNumber)
316{
317 qCDebug(MockLinkMissionItemHandlerLog) << "write sequence sequenceNumber:" << sequenceNumber << "_failureMode:" << _failureMode;
318
319 if ((_failureMode == FailWriteRequest1NoResponse) && (sequenceNumber == 1)) {
320 qCDebug(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem not responding due to failure mode FailWriteRequest1NoResponse";
321 return;
322 }
323
324 if (sequenceNumber >= _writeSequenceCount) {
325 qCWarning(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem requested seqeuence number > write count sequenceNumber::_writeSequenceCount" << sequenceNumber << _writeSequenceCount;
326 return;
327 }
328
329 if (((_failureMode == FailWriteRequest0IncorrectSequence) && (sequenceNumber == 0)) ||
330 ((_failureMode == FailWriteRequest1IncorrectSequence) && (sequenceNumber == 1))) {
331 sequenceNumber++;
332 }
333
334 if (((_failureMode == FailWriteRequest0ErrorAck) && (sequenceNumber == 0)) ||
335 ((_failureMode == FailWriteRequest1ErrorAck) && (sequenceNumber == 1))) {
336 qCDebug(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem sending ack error due to failure mode";
337 _sendAck(_failureAckResult);
338 return;
339 }
340
341 mavlink_message_t message{};
342 (void) mavlink_msg_mission_request_int_pack_chan(
343 _mockLink->vehicleId(),
344 MAV_COMP_ID_AUTOPILOT1,
345 _mockLink->mavlinkChannel(),
346 &message,
349 sequenceNumber,
350 _requestType
351 );
352 _mockLink->respondWithMavlinkMessage(message);
353
354 // If response with Mission Item doesn't come before timer fires it's an error
355 _startMissionItemResponseTimer();
356}
357
358void MockLinkMissionItemHandler::_sendAck(MAV_MISSION_RESULT ackType) const
359{
360 qCDebug(MockLinkMissionItemHandlerLog) << "_sendAck write sequence complete ackType:" << ackType;
361
362 mavlink_message_t message{};
363 (void) mavlink_msg_mission_ack_pack_chan(
364 _mockLink->vehicleId(),
365 MAV_COMP_ID_AUTOPILOT1,
366 _mockLink->mavlinkChannel(),
367 &message,
370 ackType,
371 _requestType,
372 0
373 );
374
375 _mockLink->respondWithMavlinkMessage(message);
376}
377
378void MockLinkMissionItemHandler::_handleMissionItem(const mavlink_message_t &msg)
379{
380 qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionItem write sequence";
381
382 _missionItemResponseTimer.stop();
383
384 mavlink_mission_item_int_t missionItemInt{};
385 mavlink_msg_mission_item_int_decode(&msg, &missionItemInt);
386
387 const MAV_MISSION_TYPE missionType = static_cast<MAV_MISSION_TYPE>(missionItemInt.mission_type);
388 const uint16_t seq = missionItemInt.seq;
389
390 switch (missionType) {
391 case MAV_MISSION_TYPE_MISSION:
392 _missionItems[seq] = missionItemInt;
393 break;
394 case MAV_MISSION_TYPE_FENCE:
395 _fenceItems[seq] = missionItemInt;
396 break;
397 case MAV_MISSION_TYPE_RALLY:
398 _rallyItems[seq] = missionItemInt;
399 break;
400 case MAV_MISSION_TYPE_ENUM_END:
401 case MAV_MISSION_TYPE_ALL:
402 qCWarning(MockLinkMissionItemHandlerLog) << "Internal error";
403 break;
404 }
405
406 _writeSequenceIndex++;
407 if (_writeSequenceIndex < _writeSequenceCount) {
408 if ((_failureMode == FailWriteFinalAckMissingRequests) && (_writeSequenceIndex == 3)) {
409 // Send MAV_MISSION_ACCEPTED ack too early
410 _sendAck(MAV_MISSION_ACCEPTED);
411 } else {
412 _requestNextMissionItem(_writeSequenceIndex);
413 }
414
415 return;
416 }
417
418 if (_failureMode != FailWriteFinalAckNoResponse) {
419 MAV_MISSION_RESULT ack = MAV_MISSION_ACCEPTED;
420
421 if (_failureMode == FailWriteFinalAckErrorAck) {
422 ack = MAV_MISSION_ERROR;
423 }
424
425 _sendAck(ack);
426 }
427}
428
429void MockLinkMissionItemHandler::_missionItemResponseTimeout()
430{
431 qCWarning(MockLinkMissionItemHandlerLog) << "Timeout waiting for next MISSION_ITEM_INT";
432 Q_ASSERT(false);
433}
434
436{
437 _sendAck(ackType);
438}
439
441{
442 // FIXME: NYI
443 Q_ASSERT(false);
444}
445
447{
448 // FIXME: NYI
449 Q_ASSERT(false);
450}
451
452void MockLinkMissionItemHandler::setFailureMode(FailureMode_t failureMode, MAV_MISSION_RESULT failureAckResult)
453{
454 _failureMode = failureMode;
455 _failureAckResult = failureAckResult;
456}
457
459{
460 _missionItemResponseTimer.stop();
461}
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
uint8_t mavlinkChannel() const
static int getComponentId()
static MAVLinkProtocol * instance()
int getSystemId() const
void sendUnexpectedMissionAck(MAV_MISSION_RESULT ackType)
Called to send a MISSION_ACK message while the MissionManager is in idle state.
bool handleMavlinkMessage(const mavlink_message_t &msg)
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.