MockLinkMissionItemHandler.cc 15.1 KB
Newer Older
1 2 3 4 5 6 7 8 9
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

10 11

#include "MockLinkMissionItemHandler.h"
Don Gagne's avatar
Don Gagne committed
12
#include "MockLink.h"
13 14 15

#include <QDebug>

Don Gagne's avatar
Don Gagne committed
16
QGC_LOGGING_CATEGORY(MockLinkMissionItemHandlerLog, "MockLinkMissionItemHandlerLog")
17

18
MockLinkMissionItemHandler::MockLinkMissionItemHandler(MockLink* mockLink, MAVLinkProtocol* mavlinkProtocol)
19 20 21
    : _mockLink(mockLink)
    , _missionItemResponseTimer(NULL)
    , _failureMode(FailNone)
Don Gagne's avatar
Don Gagne committed
22
    , _sendHomePositionOnEmptyList(false)
23
    , _mavlinkProtocol(mavlinkProtocol)
24 25 26
    , _failReadRequestListFirstResponse(true)
    , _failReadRequest1FirstResponse(true)
    , _failWriteMissionCountFirstResponse(true)
27
{
Don Gagne's avatar
Don Gagne committed
28
    Q_ASSERT(mockLink);
29 30
}

31 32 33 34 35 36 37 38 39 40 41 42 43 44
MockLinkMissionItemHandler::~MockLinkMissionItemHandler()
{

}

void MockLinkMissionItemHandler::_startMissionItemResponseTimer(void)
{
    if (!_missionItemResponseTimer) {
        _missionItemResponseTimer = new QTimer();
        connect(_missionItemResponseTimer, &QTimer::timeout, this, &MockLinkMissionItemHandler::_missionItemResponseTimeout);
    }
    _missionItemResponseTimer->start(500);
}

Don Gagne's avatar
Don Gagne committed
45
bool MockLinkMissionItemHandler::handleMessage(const mavlink_message_t& msg)
46 47
{
    switch (msg.msgid) {
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    case MAVLINK_MSG_ID_MISSION_REQUEST_LIST:
        _handleMissionRequestList(msg);
        break;

    case MAVLINK_MSG_ID_MISSION_REQUEST:
        _handleMissionRequest(msg);
        break;

    case MAVLINK_MSG_ID_MISSION_ITEM:
        _handleMissionItem(msg);
        break;

    case MAVLINK_MSG_ID_MISSION_COUNT:
        _handleMissionCount(msg);
        break;

    case MAVLINK_MSG_ID_MISSION_ACK:
        // Acks are received back for each MISSION_ITEM message
        break;

    case MAVLINK_MSG_ID_MISSION_SET_CURRENT:
        // Sets the currently active mission item
        break;

    case MAVLINK_MSG_ID_MISSION_CLEAR_ALL:
Don Gagne's avatar
Don Gagne committed
73
        // Delete all plan items
74
        _missionItems.clear();
Don Gagne's avatar
Don Gagne committed
75 76 77
        _fenceItems.clear();
        _rallyItems.clear();
        _sendAck(MAV_MISSION_ACCEPTED);
78 79 80 81
        break;

    default:
        return false;
82
    }
Don Gagne's avatar
Don Gagne committed
83 84
    
    return true;
85 86
}

Don Gagne's avatar
Don Gagne committed
87
void MockLinkMissionItemHandler::_handleMissionRequestList(const mavlink_message_t& msg)
88
{
Don Gagne's avatar
Don Gagne committed
89
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequestList read sequence";
90
    
91 92 93 94 95 96 97 98
    _failReadRequest1FirstResponse = true;

    if (_failureMode == FailReadRequestListNoResponse) {
        qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequestList not responding due to failure mode FailReadRequestListNoResponse";
    } else if (_failureMode == FailReadRequestListFirstResponse && _failReadRequestListFirstResponse) {
        _failReadRequestListFirstResponse = false;
        qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequestList not responding due to failure mode FailReadRequestListFirstResponse";
    } else {
99 100
        mavlink_mission_request_list_t request;
        
101
        _failReadRequestListFirstResponse = true;
102 103 104
        mavlink_msg_mission_request_list_decode(&msg, &request);
        
        Q_ASSERT(request.target_system == _mockLink->vehicleId());
Don Gagne's avatar
Don Gagne committed
105

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
        _requestType = (MAV_MISSION_TYPE)request.mission_type;

        int itemCount;
        switch (_requestType) {
        case MAV_MISSION_TYPE_MISSION:
            itemCount = _missionItems.count();
            if (itemCount == 0 && _sendHomePositionOnEmptyList) {
                itemCount = 1;
            }
            break;
        case MAV_MISSION_TYPE_FENCE:
            itemCount = _fenceItems.count();
            break;
        case MAV_MISSION_TYPE_RALLY:
            itemCount = _rallyItems.count();
            break;
        default:
            Q_ASSERT(false);
Don Gagne's avatar
Don Gagne committed
124
        }
125 126 127
        
        mavlink_message_t   responseMsg;
        
128 129 130
        mavlink_msg_mission_count_pack_chan(_mockLink->vehicleId(),
                                            MAV_COMP_ID_MISSIONPLANNER,
                                            _mockLink->mavlinkChannel(),
Donald Gagne's avatar
Donald Gagne committed
131 132 133 134
                                            &responseMsg,               // Outgoing message
                                            msg.sysid,                  // Target is original sender
                                            msg.compid,                 // Target is original sender
                                            itemCount,                  // Number of mission items
135
                                            _requestType);
136 137
        _mockLink->respondWithMavlinkMessage(responseMsg);
    }
Don Gagne's avatar
Don Gagne committed
138
}
139

Don Gagne's avatar
Don Gagne committed
140
void MockLinkMissionItemHandler::_handleMissionRequest(const mavlink_message_t& msg)
141
{
Don Gagne's avatar
Don Gagne committed
142
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest read sequence";
143
    
Don Gagne's avatar
Don Gagne committed
144
    mavlink_mission_request_t request;
145
    
Don Gagne's avatar
Don Gagne committed
146
    mavlink_msg_mission_request_decode(&msg, &request);
147
    
Don Gagne's avatar
Don Gagne committed
148
    Q_ASSERT(request.target_system == _mockLink->vehicleId());
149

150 151 152 153 154 155 156
    if (_failureMode == FailReadRequest0NoResponse && request.seq == 0) {
        qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest not responding due to failure mode FailReadRequest0NoResponse";
    } else if (_failureMode == FailReadRequest1NoResponse && request.seq == 1) {
        qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest not responding due to failure mode FailReadRequest1NoResponse";
    } else if (_failureMode == FailReadRequest1FirstResponse && request.seq == 1 && _failReadRequest1FirstResponse) {
        _failReadRequest1FirstResponse = false;
        qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest not responding due to failure mode FailReadRequest1FirstResponse";
157 158 159 160 161 162 163 164 165 166 167
    } else {
        // FIXME: Track whether all items are requested, or requested in sequence
        
        if ((_failureMode == FailReadRequest0IncorrectSequence && request.seq == 0) ||
                (_failureMode == FailReadRequest1IncorrectSequence && request.seq == 1)) {
            // Send back the incorrect sequence number
            qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest sending bad sequence number";
            request.seq++;
        }
        
        if ((_failureMode == FailReadRequest0ErrorAck && request.seq == 0) ||
168
                (_failureMode == FailReadRequest1ErrorAck && request.seq == 1)) {
169 170
            _sendAck(MAV_MISSION_ERROR);
        } else {
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
            mavlink_mission_item_t  item;
            mavlink_message_t       responseMsg;

            switch (request.mission_type) {
            case MAV_MISSION_TYPE_MISSION:
                if (_missionItems.count() == 0 && _sendHomePositionOnEmptyList) {
                    item.frame = MAV_FRAME_GLOBAL_RELATIVE_ALT;
                    item.command = MAV_CMD_NAV_WAYPOINT;
                    item.current = false;
                    item.autocontinue = true;
                    item.param1 = item.param2 = item.param3 = item.param4 = item.x = item.y = item.z = 0;
                } else {
                    item = _missionItems[request.seq];
                }
                break;
            case MAV_MISSION_TYPE_FENCE:
                item = _fenceItems[request.seq];
                break;
            case MAV_MISSION_TYPE_RALLY:
                item = _rallyItems[request.seq];
                break;
            default:
                Q_ASSERT(false);
Don Gagne's avatar
Don Gagne committed
194
            }
195
            
196 197 198 199 200 201 202 203 204 205 206 207
            mavlink_msg_mission_item_pack_chan(_mockLink->vehicleId(),
                                               MAV_COMP_ID_MISSIONPLANNER,
                                               _mockLink->mavlinkChannel(),
                                               &responseMsg,            // Outgoing message
                                               msg.sysid,               // Target is original sender
                                               msg.compid,              // Target is original sender
                                               request.seq,             // Index of mission item being sent
                                               item.frame,
                                               item.command,
                                               item.current,
                                               item.autocontinue,
                                               item.param1, item.param2, item.param3, item.param4,
Donald Gagne's avatar
Donald Gagne committed
208
                                               item.x, item.y, item.z,
209
                                               _requestType);
210 211 212
            _mockLink->respondWithMavlinkMessage(responseMsg);
        }
    }
213 214
}

Don Gagne's avatar
Don Gagne committed
215
void MockLinkMissionItemHandler::_handleMissionCount(const mavlink_message_t& msg)
216
{
Don Gagne's avatar
Don Gagne committed
217 218 219 220 221
    mavlink_mission_count_t missionCount;
    
    mavlink_msg_mission_count_decode(&msg, &missionCount);
    Q_ASSERT(missionCount.target_system == _mockLink->vehicleId());
    
222
    _requestType = (MAV_MISSION_TYPE)missionCount.mission_type;
Don Gagne's avatar
Don Gagne committed
223 224 225
    _writeSequenceCount = missionCount.count;
    Q_ASSERT(_writeSequenceCount >= 0);
    
226
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionCount write sequence _writeSequenceCount:" << _writeSequenceCount;
Don Gagne's avatar
Don Gagne committed
227
    
228 229 230 231 232 233 234 235 236 237 238
    switch (missionCount.mission_type) {
    case MAV_MISSION_TYPE_MISSION:
        _missionItems.clear();
        break;
    case MAV_MISSION_TYPE_FENCE:
        _fenceItems.clear();
        break;
    case MAV_MISSION_TYPE_RALLY:
        _rallyItems.clear();
        break;
    }
Don Gagne's avatar
Don Gagne committed
239 240
    
    if (_writeSequenceCount == 0) {
241
        _sendAck(MAV_MISSION_ACCEPTED);
242
    } else {
243 244 245 246 247 248 249 250 251 252
        if (_failureMode == FailWriteMissionCountNoResponse) {
            qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionCount not responding due to failure mode FailWriteMissionCountNoResponse";
            return;
        }
        if (_failureMode == FailWriteMissionCountFirstResponse && _failWriteMissionCountFirstResponse) {
            _failWriteMissionCountFirstResponse = false;
            qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionCount not responding due to failure mode FailWriteMissionCountNoResponse";
            return;
        }
        _failWriteMissionCountFirstResponse = true;
Don Gagne's avatar
Don Gagne committed
253 254
        _writeSequenceIndex = 0;
        _requestNextMissionItem(_writeSequenceIndex);
255 256 257
    }
}

Don Gagne's avatar
Don Gagne committed
258
void MockLinkMissionItemHandler::_requestNextMissionItem(int sequenceNumber)
259
{
260
    qCDebug(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem write sequence sequenceNumber:" << sequenceNumber << "_failureMode:" << _failureMode;
Don Gagne's avatar
Don Gagne committed
261
    
262 263
    if (_failureMode == FailWriteRequest1NoResponse && sequenceNumber == 1) {
        qCDebug(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem not responding due to failure mode FailWriteRequest1NoResponse";
264 265 266 267 268 269 270
    } else {
        if (sequenceNumber >= _writeSequenceCount) {
            qCWarning(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem requested seqeuence number > write count sequenceNumber::_writeSequenceCount" << sequenceNumber << _writeSequenceCount;
            return;
        }
        
        if ((_failureMode == FailWriteRequest0IncorrectSequence && sequenceNumber == 0) ||
271
                (_failureMode == FailWriteRequest1IncorrectSequence && sequenceNumber == 1)) {
272 273 274 275
            sequenceNumber ++;
        }
        
        if ((_failureMode == FailWriteRequest0ErrorAck && sequenceNumber == 0) ||
276
                (_failureMode == FailWriteRequest1ErrorAck && sequenceNumber == 1)) {
277 278 279
            qCDebug(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem sending ack error due to failure mode";
            _sendAck(MAV_MISSION_ERROR);
        } else {
280 281 282 283 284 285 286 287 288 289
            mavlink_message_t message;

            mavlink_msg_mission_request_pack_chan(_mockLink->vehicleId(),
                                                  MAV_COMP_ID_MISSIONPLANNER,
                                                  _mockLink->mavlinkChannel(),
                                                  &message,
                                                  _mavlinkProtocol->getSystemId(),
                                                  _mavlinkProtocol->getComponentId(),
                                                  sequenceNumber,
                                                  _requestType);
290 291 292 293 294
            _mockLink->respondWithMavlinkMessage(message);

            // If response with Mission Item doesn't come before timer fires it's an error
            _startMissionItemResponseTimer();
        }
295
    }
296 297 298 299 300 301
}

void MockLinkMissionItemHandler::_sendAck(MAV_MISSION_RESULT ackType)
{
    qCDebug(MockLinkMissionItemHandlerLog) << "_sendAck write sequence complete ackType:" << ackType;
    
302
    mavlink_message_t message;
Don Gagne's avatar
Don Gagne committed
303
    
304 305 306 307 308 309 310 311
    mavlink_msg_mission_ack_pack_chan(_mockLink->vehicleId(),
                                      MAV_COMP_ID_MISSIONPLANNER,
                                      _mockLink->mavlinkChannel(),
                                      &message,
                                      _mavlinkProtocol->getSystemId(),
                                      _mavlinkProtocol->getComponentId(),
                                      ackType,
                                      _requestType);
Don Gagne's avatar
Don Gagne committed
312
    _mockLink->respondWithMavlinkMessage(message);
313 314
}

Don Gagne's avatar
Don Gagne committed
315
void MockLinkMissionItemHandler::_handleMissionItem(const mavlink_message_t& msg)
316
{
Don Gagne's avatar
Don Gagne committed
317 318
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionItem write sequence";
    
319 320
    _missionItemResponseTimer->stop();
    
Don Gagne's avatar
Don Gagne committed
321 322 323 324 325 326
    mavlink_mission_item_t missionItem;
    
    mavlink_msg_mission_item_decode(&msg, &missionItem);
    
    Q_ASSERT(missionItem.target_system == _mockLink->vehicleId());
    
327 328 329 330 331 332 333 334 335 336 337 338
    switch (missionItem.mission_type) {
    case MAV_MISSION_TYPE_MISSION:
        _missionItems[missionItem.seq] = missionItem;
        break;
    case MAV_MISSION_TYPE_FENCE:
        _fenceItems[missionItem.seq] = missionItem;
        break;
    case MAV_MISSION_TYPE_RALLY:
        _rallyItems[missionItem.seq] = missionItem;
        break;
    }

Don Gagne's avatar
Don Gagne committed
339 340
    _writeSequenceIndex++;
    if (_writeSequenceIndex < _writeSequenceCount) {
341 342 343 344 345 346
        if (_failureMode == FailWriteFinalAckMissingRequests && _writeSequenceIndex == 3) {
            // Send MAV_MISSION_ACCPETED ack too early
            _sendAck(MAV_MISSION_ACCEPTED);
        } else {
            _requestNextMissionItem(_writeSequenceIndex);
        }
347
    } else {
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
        if (_failureMode != FailWriteFinalAckNoResponse) {
            MAV_MISSION_RESULT ack = MAV_MISSION_ACCEPTED;
            
            if (_failureMode ==  FailWriteFinalAckErrorAck) {
                ack = MAV_MISSION_ERROR;
            }
            _sendAck(ack);
        }
    }
}

void MockLinkMissionItemHandler::_missionItemResponseTimeout(void)
{
    qWarning() << "Timeout waiting for next MISSION_ITEM";
    Q_ASSERT(false);
}

void MockLinkMissionItemHandler::sendUnexpectedMissionAck(MAV_MISSION_RESULT ackType)
{
    _sendAck(ackType);
}

void MockLinkMissionItemHandler::sendUnexpectedMissionItem(void)
{
    // FIXME: NYI
    Q_ASSERT(false);
}

void MockLinkMissionItemHandler::sendUnexpectedMissionRequest(void)
{
    // FIXME: NYI
    Q_ASSERT(false);
}

382
void MockLinkMissionItemHandler::setMissionItemFailureMode(FailureMode_t failureMode)
383 384 385 386 387 388 389 390
{
    _failureMode = failureMode;
}

void MockLinkMissionItemHandler::shutdown(void)
{
    if (_missionItemResponseTimer) {
        delete _missionItemResponseTimer;
391 392
    }
}