MockLinkMissionItemHandler.cc 11.6 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
{
Don Gagne's avatar
Don Gagne committed
25
    Q_ASSERT(mockLink);
26 27
}

28 29 30 31 32 33 34 35 36 37 38 39 40 41
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
42
bool MockLinkMissionItemHandler::handleMessage(const mavlink_message_t& msg)
43 44 45
{
    switch (msg.msgid) {
        case MAVLINK_MSG_ID_MISSION_REQUEST_LIST:
Don Gagne's avatar
Don Gagne committed
46
            _handleMissionRequestList(msg);
47
            break;
Don Gagne's avatar
Don Gagne committed
48
            
49
        case MAVLINK_MSG_ID_MISSION_REQUEST:
Don Gagne's avatar
Don Gagne committed
50
            _handleMissionRequest(msg);
51
            break;
Don Gagne's avatar
Don Gagne committed
52 53 54 55 56
            
        case MAVLINK_MSG_ID_MISSION_ITEM:
            _handleMissionItem(msg);
            break;
            
57
        case MAVLINK_MSG_ID_MISSION_COUNT:
Don Gagne's avatar
Don Gagne committed
58
            _handleMissionCount(msg);
59
            break;
Don Gagne's avatar
Don Gagne committed
60 61 62 63 64 65 66
            
        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
67 68 69 70
            break;
    
        case MAVLINK_MSG_ID_MISSION_CLEAR_ALL:
            // Delete all mission items
Don Gagne's avatar
Don Gagne committed
71
            _missionItems.clear();
72
            break;
Don Gagne's avatar
Don Gagne committed
73 74 75
            
        default:
            return false;
76
    }
Don Gagne's avatar
Don Gagne committed
77 78
    
    return true;
79 80
}

Don Gagne's avatar
Don Gagne committed
81
void MockLinkMissionItemHandler::_handleMissionRequestList(const mavlink_message_t& msg)
82
{
Don Gagne's avatar
Don Gagne committed
83
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequestList read sequence";
84
    
85 86 87 88 89 90
    if (_failureMode != FailReadRequestListNoResponse) {
        mavlink_mission_request_list_t request;
        
        mavlink_msg_mission_request_list_decode(&msg, &request);
        
        Q_ASSERT(request.target_system == _mockLink->vehicleId());
Don Gagne's avatar
Don Gagne committed
91 92 93 94 95

        int itemCount = _missionItems.count();
        if (itemCount == 0 && _sendHomePositionOnEmptyList) {
            itemCount = 1;
        }
96 97 98 99 100 101 102 103
        
        mavlink_message_t   responseMsg;
        
        mavlink_msg_mission_count_pack(_mockLink->vehicleId(),
                                       MAV_COMP_ID_MISSIONPLANNER,
                                       &responseMsg,            // Outgoing message
                                       msg.sysid,               // Target is original sender
                                       msg.compid,              // Target is original sender
Don Gagne's avatar
Don Gagne committed
104
                                       itemCount);              // Number of mission items
105 106 107 108
        _mockLink->respondWithMavlinkMessage(responseMsg);
    } else {
        qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequestList not responding due to failure mode";
    }
Don Gagne's avatar
Don Gagne committed
109
}
110

Don Gagne's avatar
Don Gagne committed
111
void MockLinkMissionItemHandler::_handleMissionRequest(const mavlink_message_t& msg)
112
{
Don Gagne's avatar
Don Gagne committed
113
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest read sequence";
114
    
Don Gagne's avatar
Don Gagne committed
115
    mavlink_mission_request_t request;
116
    
Don Gagne's avatar
Don Gagne committed
117
    mavlink_msg_mission_request_decode(&msg, &request);
118
    
Don Gagne's avatar
Don Gagne committed
119 120
    Q_ASSERT(request.target_system == _mockLink->vehicleId());
    Q_ASSERT(request.seq < _missionItems.count());
121
    
122 123
    if ((_failureMode == FailReadRequest0NoResponse && request.seq == 0) ||
        (_failureMode == FailReadRequest1NoResponse && request.seq == 1)) {
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
        qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequest not responding due to failure mode";
    } 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) ||
            (_failureMode == FailReadRequest1ErrorAck && request.seq == 1)) {
            _sendAck(MAV_MISSION_ERROR);
        } else {
            mavlink_message_t   responseMsg;
            
Don Gagne's avatar
Don Gagne committed
141 142 143 144 145 146 147 148 149 150
            mavlink_mission_item_t item;
            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];
            }
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
            
            mavlink_msg_mission_item_pack(_mockLink->vehicleId(),
                                          MAV_COMP_ID_MISSIONPLANNER,
                                          &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,
                                          item.x, item.y, item.z);
            _mockLink->respondWithMavlinkMessage(responseMsg);
        }
    }
167 168
}

Don Gagne's avatar
Don Gagne committed
169
void MockLinkMissionItemHandler::_handleMissionCount(const mavlink_message_t& msg)
170
{
Don Gagne's avatar
Don Gagne committed
171 172 173 174 175 176 177 178
    mavlink_mission_count_t missionCount;
    
    mavlink_msg_mission_count_decode(&msg, &missionCount);
    Q_ASSERT(missionCount.target_system == _mockLink->vehicleId());
    
    _writeSequenceCount = missionCount.count;
    Q_ASSERT(_writeSequenceCount >= 0);
    
179
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionCount write sequence _writeSequenceCount:" << _writeSequenceCount;
Don Gagne's avatar
Don Gagne committed
180 181 182 183
    
    _missionItems.clear();
    
    if (_writeSequenceCount == 0) {
184
        _sendAck(MAV_MISSION_ACCEPTED);
185
    } else {
Don Gagne's avatar
Don Gagne committed
186 187
        _writeSequenceIndex = 0;
        _requestNextMissionItem(_writeSequenceIndex);
188 189 190
    }
}

Don Gagne's avatar
Don Gagne committed
191
void MockLinkMissionItemHandler::_requestNextMissionItem(int sequenceNumber)
192
{
193
    qCDebug(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem write sequence sequenceNumber:" << sequenceNumber << "_failureMode:" << _failureMode;
Don Gagne's avatar
Don Gagne committed
194
    
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    if ((_failureMode == FailWriteRequest0NoResponse && sequenceNumber == 0) ||
        (_failureMode == FailWriteRequest1NoResponse && sequenceNumber == 1)) {
        qCDebug(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem not responding due to failure mode";
    } else {
        if (sequenceNumber >= _writeSequenceCount) {
            qCWarning(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem requested seqeuence number > write count sequenceNumber::_writeSequenceCount" << sequenceNumber << _writeSequenceCount;
            return;
        }
        
        if ((_failureMode == FailWriteRequest0IncorrectSequence && sequenceNumber == 0) ||
            (_failureMode == FailWriteRequest1IncorrectSequence && sequenceNumber == 1)) {
            sequenceNumber ++;
        }
        
        if ((_failureMode == FailWriteRequest0ErrorAck && sequenceNumber == 0) ||
            (_failureMode == FailWriteRequest1ErrorAck && sequenceNumber == 1)) {
            qCDebug(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem sending ack error due to failure mode";
            _sendAck(MAV_MISSION_ERROR);
        } else {
            mavlink_message_t           message;
            mavlink_mission_request_t   missionRequest;
            
217 218
            missionRequest.target_system =      _mavlinkProtocol->getSystemId();
            missionRequest.target_component =   _mavlinkProtocol->getComponentId();
219 220 221 222 223 224 225 226
            missionRequest.seq =                sequenceNumber;
            
            mavlink_msg_mission_request_encode(_mockLink->vehicleId(), MAV_COMP_ID_MISSIONPLANNER, &message, &missionRequest);
            _mockLink->respondWithMavlinkMessage(message);

            // If response with Mission Item doesn't come before timer fires it's an error
            _startMissionItemResponseTimer();
        }
227
    }
228 229 230 231 232 233 234 235
}

void MockLinkMissionItemHandler::_sendAck(MAV_MISSION_RESULT ackType)
{
    qCDebug(MockLinkMissionItemHandlerLog) << "_sendAck write sequence complete ackType:" << ackType;
    
    mavlink_message_t       message;
    mavlink_mission_ack_t   missionAck;
Don Gagne's avatar
Don Gagne committed
236
    
237 238
    missionAck.target_system =      _mavlinkProtocol->getSystemId();
    missionAck.target_component =   _mavlinkProtocol->getComponentId();
239
    missionAck.type =               ackType;
Don Gagne's avatar
Don Gagne committed
240
    
241
    mavlink_msg_mission_ack_encode(_mockLink->vehicleId(), MAV_COMP_ID_MISSIONPLANNER, &message, &missionAck);
Don Gagne's avatar
Don Gagne committed
242
    _mockLink->respondWithMavlinkMessage(message);
243 244
}

Don Gagne's avatar
Don Gagne committed
245
void MockLinkMissionItemHandler::_handleMissionItem(const mavlink_message_t& msg)
246
{
Don Gagne's avatar
Don Gagne committed
247 248
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionItem write sequence";
    
249 250
    _missionItemResponseTimer->stop();
    
Don Gagne's avatar
Don Gagne committed
251 252 253 254 255 256 257 258 259 260
    mavlink_mission_item_t missionItem;
    
    mavlink_msg_mission_item_decode(&msg, &missionItem);
    
    Q_ASSERT(missionItem.target_system == _mockLink->vehicleId());
    
    _missionItems[missionItem.seq] = missionItem;
    
    _writeSequenceIndex++;
    if (_writeSequenceIndex < _writeSequenceCount) {
261 262 263 264 265 266
        if (_failureMode == FailWriteFinalAckMissingRequests && _writeSequenceIndex == 3) {
            // Send MAV_MISSION_ACCPETED ack too early
            _sendAck(MAV_MISSION_ACCEPTED);
        } else {
            _requestNextMissionItem(_writeSequenceIndex);
        }
267
    } else {
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
        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);
}

302
void MockLinkMissionItemHandler::setMissionItemFailureMode(FailureMode_t failureMode)
303 304 305 306 307 308 309 310
{
    _failureMode = failureMode;
}

void MockLinkMissionItemHandler::shutdown(void)
{
    if (_missionItemResponseTimer) {
        delete _missionItemResponseTimer;
311 312
    }
}