OpalLink.cc 14.7 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    QGROUNDCONTROL is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Implementation of class OpalLink
 *   @author Bryan Godbolt <godbolt@ualberta.ca>
 */

30 31
#include "OpalLink.h"

32 33 34 35 36
OpalLink::OpalLink() :
        connectState(false),
        heartbeatTimer(new QTimer(this)),
        heartbeatRate(MAVLINK_HEARTBEAT_DEFAULT_RATE),
        m_heartbeatsEnabled(true),
37
        getSignalsTimer(new QTimer(this)),
Bryan Godbolt's avatar
Bryan Godbolt committed
38
        getSignalsPeriod(10),
39 40
        receiveBuffer(new QQueue<QByteArray>()),
        systemID(1),
41
        componentID(1),
42
        params(NULL),
43 44
        opalInstID(101),
        sendRCValues(false)
45
{
46
    start(QThread::LowPriority);
Bryan Godbolt's avatar
Bryan Godbolt committed
47 48 49 50 51

    // Set unique ID and add link to the list of links
    this->id = getNextLinkId();
    this->name = tr("OpalRT link ") + QString::number(getId());
    LinkManager::instance()->add(this);
52 53 54

    // Start heartbeat timer, emitting a heartbeat at the configured rate
    QObject::connect(heartbeatTimer, SIGNAL(timeout()), this, SLOT(heartbeat()));
55 56

    QObject::connect(getSignalsTimer, SIGNAL(timeout()), this, SLOT(getSignals()));
57 58
}

59 60 61 62 63 64 65 66

/*
 *
  Communication
 *
 */

qint64 OpalLink::bytesAvailable()
67
{
68
    return 0;
Bryan Godbolt's avatar
Bryan Godbolt committed
69 70
}

71
void OpalLink::writeBytes(const char *bytes, qint64 length)
Bryan Godbolt's avatar
Bryan Godbolt committed
72
{
73 74 75 76 77 78 79 80 81 82 83 84 85 86
    /* decode the message */
    mavlink_message_t msg;
    mavlink_status_t status;        
    int decodeSuccess = 0;
    for (int i=0; (!(decodeSuccess=mavlink_parse_char(this->getId(), bytes[i], &msg, &status))&& i<length); ++i);    

    /* perform the appropriate action */
    if (decodeSuccess)
    {
        switch(msg.msgid)
        {
        case MAVLINK_MSG_ID_PARAM_REQUEST_LIST:
            {
                qDebug() << "OpalLink::writeBytes(): request params";
87

88
                mavlink_message_t param;
89

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

                OpalRT::ParameterList::const_iterator paramIter;
                for (paramIter = params->begin(); paramIter != params->end(); ++paramIter)
                {
                    mavlink_msg_param_value_pack(systemID,
                                                 (*paramIter).getComponentID(),
                                                 &param,
                                                 (*paramIter).getParamID().toInt8_t(),
                                                 (static_cast<OpalRT::Parameter>(*paramIter)).getValue(),
                                                 params->count(),
                                                 params->indexOf(*paramIter));
                    receiveMessage(param);
                }


105 106 107
            }
        case MAVLINK_MSG_ID_PARAM_SET:
            {
108 109 110

//                qDebug() << "OpalLink::writeBytes(): Attempt to set a parameter";

111 112
                mavlink_param_set_t param;
                mavlink_msg_param_set_decode(&msg, &param);
113 114 115 116 117
                OpalRT::QGCParamID paramName((char*)param.param_id);

//                qDebug() << "OpalLink::writeBytes():paramName: " << paramName;

                if ((*params).contains(param.target_component, paramName))
118
                {
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
                    OpalRT::Parameter p = (*params)(param.target_component, paramName);
//                    qDebug() << __FILE__ << ":" << __LINE__ << ": "  << p;
                    // Set the param value in Opal-RT
                    p.setValue(param.param_value);

                    // Get the param value from Opal-RT to make sure it was set properly
                    mavlink_message_t paramMsg;
                    mavlink_msg_param_value_pack(systemID,
                                                 p.getComponentID(),
                                                 &paramMsg,
                                                 p.getParamID().toInt8_t(),
                                                 p.getValue(),
                                                 params->count(),
                                                 params->indexOf(p));
                    receiveMessage(paramMsg);
134 135 136
                }
            }
            break;
137 138 139 140 141 142 143 144
        case MAVLINK_MSG_ID_REQUEST_RC_CHANNELS:
        {
        	mavlink_request_rc_channels_t rc;
        	mavlink_msg_request_rc_channels_decode(&msg, &rc);
        	//qDebug() << __FILE__ << __LINE__ << ": enabled=" << static_cast<bool>(rc.enabled);
        	this->sendRCValues = static_cast<bool>(rc.enabled);
        }
        break;
145
#ifdef MAVLINK_ENABLED_UALBERTA_MESSAGES
146 147 148 149 150 151
        case MAVLINK_MSG_ID_RADIO_CALIBRATION:
        {
            mavlink_radio_calibration_t radio;
            mavlink_msg_radio_calibration_decode(&msg, &radio);
            qDebug() << "RADIO CALIBRATION RECEIVED";
            qDebug() << "AILERON: " << radio.aileron[0] << " " << radio.aileron[1] << " " << radio.aileron[2];
152 153 154 155 156
            qDebug() << "ELEVATOR: " << radio.elevator[0] << " " << radio.elevator[1] << " " << radio.elevator[2];
            qDebug() << "RUDDER: " << radio.rudder[0] << " " << radio.rudder[1] << " " << radio.rudder[2];
            qDebug() << "GYRO: " << radio.gyro[0] << " " << radio.gyro[1];
            qDebug() << "PITCH: " << radio.pitch[0] << radio.pitch[1] << radio.pitch[2] << radio.pitch[3] << radio.pitch[4];
            qDebug() << "THROTTLE: " << radio.throttle[0] << radio.throttle[1] << radio.throttle[2] << radio.throttle[3] << radio.throttle[4];
157 158 159
        }
        break;
#endif
160 161 162 163 164 165
        default:
            {
                qDebug() << "OpalLink::writeBytes(): Unknown mavlink packet";
            }
        }
    }
Bryan Godbolt's avatar
Bryan Godbolt committed
166 167
}

168

169
void OpalLink::readBytes()
Bryan Godbolt's avatar
Bryan Godbolt committed
170
{
171
    receiveDataMutex.lock();
Bryan Godbolt's avatar
Bryan Godbolt committed
172
    emit bytesReceived(this, receiveBuffer->dequeue());
173 174
    receiveDataMutex.unlock();

Bryan Godbolt's avatar
Bryan Godbolt committed
175 176
}

177
void OpalLink::receiveMessage(mavlink_message_t message)
Bryan Godbolt's avatar
Bryan Godbolt committed
178 179
{

180 181 182 183 184 185 186
    // Create buffer
    char buffer[MAVLINK_MAX_PACKET_LEN];
    // Write message into buffer, prepending start sign
    int len = mavlink_msg_to_send_buffer((uint8_t*)(buffer), &message);
    // If link is connected
    if (isConnected())
    {
Bryan Godbolt's avatar
Bryan Godbolt committed
187
        receiveDataMutex.lock();
188
        receiveBuffer->enqueue(QByteArray(buffer, len));
Bryan Godbolt's avatar
Bryan Godbolt committed
189
        receiveDataMutex.unlock();
190
        readBytes();
191 192
    }

Bryan Godbolt's avatar
Bryan Godbolt committed
193 194
}

195
void OpalLink::heartbeat()
Bryan Godbolt's avatar
Bryan Godbolt committed
196
{
197 198 199 200 201 202 203 204

    if (m_heartbeatsEnabled)
    {
        mavlink_message_t beat;
        mavlink_msg_heartbeat_pack(systemID, componentID,&beat, MAV_HELICOPTER, MAV_AUTOPILOT_GENERIC);
        receiveMessage(beat);
    }

Bryan Godbolt's avatar
Bryan Godbolt committed
205
}
206 207
void OpalLink::setSignals(double *values)
{
Bryan Godbolt's avatar
Bryan Godbolt committed
208
    unsigned short numSignals = 2;
209 210 211 212 213 214 215
    unsigned short logicalId = 1;
    unsigned short signalIndex[] = {0,1};

    int returnValue;
    returnValue =  OpalSetSignals( numSignals, logicalId, signalIndex, values);
    if (returnValue != EOK)
    {
216
        OpalRT::OpalErrorMsg::displayLastErrorMsg();
217 218
    }
}
219
void OpalLink::getSignals()
Bryan Godbolt's avatar
Bryan Godbolt committed
220
{
Bryan Godbolt's avatar
Bryan Godbolt committed
221 222 223 224
    unsigned long  timeout = 0;
    unsigned short acqGroup = 0; //this is actually group 1 in the model
    unsigned short *numSignals = new unsigned short(0);
    double *timestep = new double(0);
225
    double values[OpalRT::NUM_OUTPUT_SIGNALS] = {};
Bryan Godbolt's avatar
Bryan Godbolt committed
226 227 228 229 230
    unsigned short *lastValues = new unsigned short(false);
    unsigned short *decimation = new unsigned short(0);

    while (!(*lastValues))
    {
231
        int returnVal = OpalGetSignals(timeout, acqGroup, OpalRT::NUM_OUTPUT_SIGNALS, numSignals, timestep,
Bryan Godbolt's avatar
Bryan Godbolt committed
232 233 234
                                       values, lastValues, decimation);

        if (returnVal == EOK )
235
        {            
236
            /* Send position info to qgroundcontrol */
Bryan Godbolt's avatar
Bryan Godbolt committed
237 238 239 240 241 242 243 244 245 246
            mavlink_message_t local_position;
            mavlink_msg_local_position_pack(systemID, componentID, &local_position,
                                            (*timestep)*1000000,
                                            values[OpalRT::X_POS],
                                            values[OpalRT::Y_POS],
                                            values[OpalRT::Z_POS],
                                            values[OpalRT::X_VEL],
                                            values[OpalRT::Y_VEL],
                                            values[OpalRT::Z_VEL]);
            receiveMessage(local_position);
247 248 249 250 251 252 253 254

            /* send attitude info to qgroundcontrol */
            mavlink_message_t attitude;
            mavlink_msg_attitude_pack(systemID, componentID, &attitude,
                                      (*timestep)*1000000,
                                      values[OpalRT::ROLL],
                                      values[OpalRT::PITCH],
                                      values[OpalRT::YAW],
255 256 257
                                      values[OpalRT::ROLL_SPEED],
                                      values[OpalRT::PITCH_SPEED],
                                      values[OpalRT::YAW_SPEED]
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
                                      );
            receiveMessage(attitude);

            /* send bias info to qgroundcontrol */
            mavlink_message_t bias;
            mavlink_msg_nav_filter_bias_pack(systemID, componentID, &bias,
                                             (*timestep)*1000000,
                                             values[OpalRT::B_F_0],
                                             values[OpalRT::B_F_1],
                                             values[OpalRT::B_F_2],
                                             values[OpalRT::B_W_0],
                                             values[OpalRT::B_W_1],
                                             values[OpalRT::B_W_2]
                                             );
            receiveMessage(bias);
Bryan Godbolt's avatar
Bryan Godbolt committed
273 274

            /* send radio outputs */
275 276 277 278
            if (sendRCValues)
            {
                mavlink_message_t rc;
                mavlink_msg_rc_channels_pack(systemID, componentID, &rc,
Bryan Godbolt's avatar
Bryan Godbolt committed
279 280 281 282 283 284 285 286
                                             duty2PulseMicros(values[OpalRT::RAW_CHANNEL_1]),
                                             duty2PulseMicros(values[OpalRT::RAW_CHANNEL_2]),
                                             duty2PulseMicros(values[OpalRT::RAW_CHANNEL_3]),
                                             duty2PulseMicros(values[OpalRT::RAW_CHANNEL_4]),
                                             duty2PulseMicros(values[OpalRT::RAW_CHANNEL_5]),
                                             duty2PulseMicros(values[OpalRT::RAW_CHANNEL_6]),
                                             duty2PulseMicros(values[OpalRT::RAW_CHANNEL_7]),
                                             duty2PulseMicros(values[OpalRT::RAW_CHANNEL_8]),
287 288 289 290 291 292 293 294
                                             rescaleNorm(values[OpalRT::NORM_CHANNEL_1]),
                                             rescaleNorm(values[OpalRT::NORM_CHANNEL_2]),
                                             rescaleNorm(values[OpalRT::NORM_CHANNEL_3]),
                                             rescaleNorm(values[OpalRT::NORM_CHANNEL_4]),
                                             rescaleNorm(values[OpalRT::NORM_CHANNEL_5]),
                                             rescaleNorm(values[OpalRT::NORM_CHANNEL_6]),
                                             rescaleNorm(values[OpalRT::NORM_CHANNEL_7]),
                                             rescaleNorm(values[OpalRT::NORM_CHANNEL_8]),
Bryan Godbolt's avatar
Bryan Godbolt committed
295 296
                                             0 //rssi unused
                                             );
297 298
                receiveMessage(rc);
            }
299 300
        }        
        else if (returnVal != EAGAIN) // if returnVal == EAGAIN => data just wasn't ready
Bryan Godbolt's avatar
Bryan Godbolt committed
301 302
        {
            getSignalsTimer->stop();
303
            OpalRT::OpalErrorMsg::displayLastErrorMsg();
Bryan Godbolt's avatar
Bryan Godbolt committed
304 305 306 307 308 309 310 311 312
        }
    }

    /* deallocate used memory */

    delete numSignals;
    delete timestep;
    delete lastValues;
    delete decimation;
313

Bryan Godbolt's avatar
Bryan Godbolt committed
314 315
}

316

317 318 319 320 321 322
/*
 *
  Administrative
 *
 */
void OpalLink::run()
Bryan Godbolt's avatar
Bryan Godbolt committed
323
{
Bryan Godbolt's avatar
Bryan Godbolt committed
324
//    qDebug() << "OpalLink::run():: Starting the thread";
325 326
}

327 328 329
int OpalLink::getId()
{
    return id;
Bryan Godbolt's avatar
Bryan Godbolt committed
330 331
}

332
QString OpalLink::getName()
Bryan Godbolt's avatar
Bryan Godbolt committed
333
{
334
    return name;
Bryan Godbolt's avatar
Bryan Godbolt committed
335 336
}

337
void OpalLink::setName(QString name)
Bryan Godbolt's avatar
Bryan Godbolt committed
338
{
339 340
    this->name = name;
    emit nameChanged(this->name);
Bryan Godbolt's avatar
Bryan Godbolt committed
341 342
}

343
bool OpalLink::isConnected() {    
344
    return connectState;
Bryan Godbolt's avatar
Bryan Godbolt committed
345 346
}

Bryan Godbolt's avatar
Bryan Godbolt committed
347 348 349 350 351 352
uint16_t OpalLink::duty2PulseMicros(double duty)
{
    /* duty cycle assumed to be of a signal at 70 Hz */
    return static_cast<uint16_t>(duty/70*1000000);
}

353 354 355 356
uint8_t OpalLink::rescaleNorm(double norm)
{
    return static_cast<uint8_t>((norm+1)/2*255);
}
Bryan Godbolt's avatar
Bryan Godbolt committed
357

358 359 360

bool OpalLink::connect()
{
Bryan Godbolt's avatar
Bryan Godbolt committed
361
    short modelState;
362

363
    if ((OpalConnect(opalInstID, false, &modelState) == EOK)
364 365
        && (OpalGetSignalControl(0, true) == EOK)
        && (OpalGetParameterControl(true) == EOK))
Bryan Godbolt's avatar
Bryan Godbolt committed
366
    {
367
        connectState = true;
368 369
        if (params)
            delete params;
370
        params = new OpalRT::ParameterList();
371 372 373
        emit connected();
        heartbeatTimer->start(1000/heartbeatRate);
        getSignalsTimer->start(getSignalsPeriod);
Bryan Godbolt's avatar
Bryan Godbolt committed
374 375 376 377
    }
    else
    {
        connectState = false;
378
        OpalRT::OpalErrorMsg::displayLastErrorMsg();
Bryan Godbolt's avatar
Bryan Godbolt committed
379
    }
380 381 382

    emit connected(connectState);
    return connectState;
383 384 385 386
}

bool OpalLink::disconnect()
{
387 388 389 390
    // OpalDisconnect returns void so its success or failure cannot be tested
    OpalDisconnect();
    heartbeatTimer->stop();
    getSignalsTimer->stop();
391 392
    connectState = false;
    emit connected(connectState);
393
    return true;
394 395
}

396

397

398 399 400 401 402 403 404 405

/*
 *
  Statisctics
 *
 */

qint64 OpalLink::getNominalDataRate()
406
{
407
    return 0; //unknown
408
}
Bryan Godbolt's avatar
Bryan Godbolt committed
409

410
int OpalLink::getLinkQuality()
Bryan Godbolt's avatar
Bryan Godbolt committed
411
{
412
    return -1; //not supported
Bryan Godbolt's avatar
Bryan Godbolt committed
413 414
}

415
qint64 OpalLink::getTotalUpstream()
Bryan Godbolt's avatar
Bryan Godbolt committed
416
{
417 418 419 420 421
    statisticsMutex.lock();
    qint64 totalUpstream =  bitsSentTotal / ((MG::TIME::getGroundTimeNow() - connectionStartTime) / 1000);
    statisticsMutex.unlock();
    return totalUpstream;
}
Bryan Godbolt's avatar
Bryan Godbolt committed
422

423 424 425 426 427
qint64 OpalLink::getTotalDownstream() {
    statisticsMutex.lock();
    qint64 totalDownstream = bitsReceivedTotal / ((MG::TIME::getGroundTimeNow() - connectionStartTime) / 1000);
    statisticsMutex.unlock();
    return totalDownstream;
428 429
}

430
qint64 OpalLink::getCurrentUpstream()
431
{
432 433
    return 0; //unknown
}
434

435 436 437 438
qint64 OpalLink::getMaxUpstream()
{
    return 0; //unknown
}
439

440 441
qint64 OpalLink::getBitsSent() {
    return bitsSentTotal;
442 443
}

444 445 446
qint64 OpalLink::getBitsReceived() {
    return bitsReceivedTotal;
}
447 448


449 450 451
bool OpalLink::isFullDuplex()
{
    return false;
Bryan Godbolt's avatar
Bryan Godbolt committed
452
}