MockLinkMissionItemHandler.cc 12.2 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
        
        mavlink_message_t   responseMsg;
        
99 100 101 102 103 104 105
        mavlink_msg_mission_count_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
                                            itemCount);              // Number of mission items
106 107 108 109
        _mockLink->respondWithMavlinkMessage(responseMsg);
    } else {
        qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionRequestList not responding due to failure mode";
    }
Don Gagne's avatar
Don Gagne committed
110
}
111

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

Don Gagne's avatar
Don Gagne committed
171
void MockLinkMissionItemHandler::_handleMissionCount(const mavlink_message_t& msg)
172
{
Don Gagne's avatar
Don Gagne committed
173 174 175 176 177 178 179 180
    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);
    
181
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionCount write sequence _writeSequenceCount:" << _writeSequenceCount;
Don Gagne's avatar
Don Gagne committed
182 183 184 185
    
    _missionItems.clear();
    
    if (_writeSequenceCount == 0) {
186
        _sendAck(MAV_MISSION_ACCEPTED);
187
    } else {
Don Gagne's avatar
Don Gagne committed
188 189
        _writeSequenceIndex = 0;
        _requestNextMissionItem(_writeSequenceIndex);
190 191 192
    }
}

Don Gagne's avatar
Don Gagne committed
193
void MockLinkMissionItemHandler::_requestNextMissionItem(int sequenceNumber)
194
{
195
    qCDebug(MockLinkMissionItemHandlerLog) << "_requestNextMissionItem write sequence sequenceNumber:" << sequenceNumber << "_failureMode:" << _failureMode;
Don Gagne's avatar
Don Gagne committed
196
    
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
    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;
            
219 220
            missionRequest.target_system =      _mavlinkProtocol->getSystemId();
            missionRequest.target_component =   _mavlinkProtocol->getComponentId();
221 222
            missionRequest.seq =                sequenceNumber;
            
223 224 225 226 227
            mavlink_msg_mission_request_encode_chan(_mockLink->vehicleId(),
                                                    MAV_COMP_ID_MISSIONPLANNER,
                                                    _mockLink->mavlinkChannel(),
                                                    &message,
                                                    &missionRequest);
228 229 230 231 232
            _mockLink->respondWithMavlinkMessage(message);

            // If response with Mission Item doesn't come before timer fires it's an error
            _startMissionItemResponseTimer();
        }
233
    }
234 235 236 237 238 239 240 241
}

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
242
    
243 244
    missionAck.target_system =      _mavlinkProtocol->getSystemId();
    missionAck.target_component =   _mavlinkProtocol->getComponentId();
245
    missionAck.type =               ackType;
Don Gagne's avatar
Don Gagne committed
246
    
247 248 249 250 251
    mavlink_msg_mission_ack_encode_chan(_mockLink->vehicleId(),
                                        MAV_COMP_ID_MISSIONPLANNER,
                                        _mockLink->mavlinkChannel(),
                                        &message,
                                        &missionAck);
Don Gagne's avatar
Don Gagne committed
252
    _mockLink->respondWithMavlinkMessage(message);
253 254
}

Don Gagne's avatar
Don Gagne committed
255
void MockLinkMissionItemHandler::_handleMissionItem(const mavlink_message_t& msg)
256
{
Don Gagne's avatar
Don Gagne committed
257 258
    qCDebug(MockLinkMissionItemHandlerLog) << "_handleMissionItem write sequence";
    
259 260
    _missionItemResponseTimer->stop();
    
Don Gagne's avatar
Don Gagne committed
261 262 263 264 265 266 267 268 269 270
    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) {
271 272 273 274 275 276
        if (_failureMode == FailWriteFinalAckMissingRequests && _writeSequenceIndex == 3) {
            // Send MAV_MISSION_ACCPETED ack too early
            _sendAck(MAV_MISSION_ACCEPTED);
        } else {
            _requestNextMissionItem(_writeSequenceIndex);
        }
277
    } else {
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
        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);
}

312
void MockLinkMissionItemHandler::setMissionItemFailureMode(FailureMode_t failureMode)
313 314 315 316 317 318 319 320
{
    _failureMode = failureMode;
}

void MockLinkMissionItemHandler::shutdown(void)
{
    if (_missionItemResponseTimer) {
        delete _missionItemResponseTimer;
321 322
    }
}