SerialLink.cc 24.7 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9 10 11 12
/*=====================================================================
======================================================================*/
/**
 * @file
 *   @brief Cross-platform support for serial ports
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QTimer>
#include <QDebug>
13
#include <QSettings>
pixhawk's avatar
pixhawk committed
14
#include <QMutexLocker>
15 16
#include <QSerialPort>
#include <QSerialPortInfo>
pixhawk's avatar
pixhawk committed
17 18
#include "SerialLink.h"
#include "LinkManager.h"
19
#include "QGC.h"
pixhawk's avatar
pixhawk committed
20 21
#include <MG.h>

22 23
SerialLink::SerialLink(QString portname, int baudRate, bool hardwareFlowControl, bool parity,
                       int dataBits, int stopBits) :
Bill Bonney's avatar
Bill Bonney committed
24
    m_bytesRead(0),
25
    m_port(Q_NULLPTR),
26 27
    type(""),
    m_is_cdc(true),
28
    m_stopp(false),
29
    m_reqReset(false)
pixhawk's avatar
pixhawk committed
30
{
31 32 33 34
    // We're doing it wrong - because the Qt folks got the API wrong:
    // http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
    moveToThread(this);

35 36
    // Get the name of the current port in use.
    m_portName = portname.trimmed();
37 38
    QList<QString> ports = getCurrentPorts();
    if (m_portName == "" && ports.size() > 0)
39
    {
40
        m_portName = ports.first().trimmed();
41 42
    }

43 44
    checkIfCDC();

pixhawk's avatar
pixhawk committed
45
    // Set unique ID and add link to the list of links
Bill Bonney's avatar
Bill Bonney committed
46 47 48
    m_id = getNextLinkId();

    m_baud = baudRate;
49

50 51
    if (hardwareFlowControl)
    {
Bill Bonney's avatar
Bill Bonney committed
52
        m_flowControl = QSerialPort::HardwareControl;
53 54 55
    }
    else
    {
Bill Bonney's avatar
Bill Bonney committed
56
        m_flowControl = QSerialPort::NoFlowControl;
57 58 59
    }
    if (parity)
    {
Bill Bonney's avatar
Bill Bonney committed
60
        m_parity = QSerialPort::EvenParity;
61 62 63
    }
    else
    {
Bill Bonney's avatar
Bill Bonney committed
64
        m_parity = QSerialPort::NoParity;
65
    }
Bill Bonney's avatar
Bill Bonney committed
66 67 68

    m_dataBits = dataBits;
    m_stopBits = stopBits;
pixhawk's avatar
pixhawk committed
69

lm's avatar
lm committed
70
    loadSettings();
Lorenz Meier's avatar
Lorenz Meier committed
71 72 73 74 75

    qDebug() << "create SerialLink " << portname << baudRate << hardwareFlowControl
             << parity << dataBits << stopBits;
    qDebug() << "m_portName " << m_portName;

76
    LinkManager::instance()->add(this);
77
    qDebug() << "link added to link manager";
pixhawk's avatar
pixhawk committed
78
}
79

80 81 82 83 84
void SerialLink::requestReset()
{
    QMutexLocker locker(&this->m_stoppMutex);
    m_reqReset = true;
}
pixhawk's avatar
pixhawk committed
85 86 87 88

SerialLink::~SerialLink()
{
    disconnect();
Bill Bonney's avatar
Bill Bonney committed
89 90
    if(m_port) delete m_port;
    m_port = NULL;
Lorenz Meier's avatar
Lorenz Meier committed
91 92 93 94 95

    // Tell the thread to exit
    quit();
    // Wait for it to exit
    wait();
96 97
}

98
QList<QString> SerialLink::getCurrentPorts()
99
{
100
    QList<QString> ports;
101

102 103
    QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();
    foreach (const QSerialPortInfo &info, portList)
104
    {
105
        ports.append(info.portName());
106
    }
107

108
    return ports;
pixhawk's avatar
pixhawk committed
109 110
}

111 112 113 114 115 116 117 118 119 120
bool SerialLink::isBootloader()
{
    QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();

    if( portList.count() == 0){
        return false;
    }

    foreach (const QSerialPortInfo &info, portList)
    {
121
        // XXX debug statements will be removed once we have 100% stable link reports
122 123 124 125 126 127
//        qDebug() << "PortName    : " << info.portName()
//                 << "Description : " << info.description();
//        qDebug() << "Manufacturer: " << info.manufacturer();

       if (info.portName().trimmed() == this->m_portName.trimmed() &&
               (info.description().toLower().contains("bootloader") ||
128 129 130
                info.description().toLower().contains("px4 bl") ||
                info.description().toLower().contains("px4 fmu v1.6"))) {
//           qDebug() << "BOOTLOADER FOUND";
131 132 133 134 135 136 137 138
           return true;
       }
    }

    // Not found
    return false;
}

139 140 141
void SerialLink::loadSettings()
{
    // Load defaults from settings
142
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
143
    settings.sync();
144 145
    if (settings.contains("SERIALLINK_COMM_PORT"))
    {
Bill Bonney's avatar
Bill Bonney committed
146
        m_portName = settings.value("SERIALLINK_COMM_PORT").toString();
147 148
        checkIfCDC();

Bill Bonney's avatar
Bill Bonney committed
149 150 151 152 153
        m_baud = settings.value("SERIALLINK_COMM_BAUD").toInt();
        m_parity = settings.value("SERIALLINK_COMM_PARITY").toInt();
        m_stopBits = settings.value("SERIALLINK_COMM_STOPBITS").toInt();
        m_dataBits = settings.value("SERIALLINK_COMM_DATABITS").toInt();
        m_flowControl = settings.value("SERIALLINK_COMM_FLOW_CONTROL").toInt();
154 155 156 157 158 159
    }
}

void SerialLink::writeSettings()
{
    // Store settings
160
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
161
    settings.setValue("SERIALLINK_COMM_PORT", getPortName());
162 163
    settings.setValue("SERIALLINK_COMM_BAUD", getBaudRateType());
    settings.setValue("SERIALLINK_COMM_PARITY", getParityType());
164 165 166
    settings.setValue("SERIALLINK_COMM_STOPBITS", getStopBits());
    settings.setValue("SERIALLINK_COMM_DATABITS", getDataBits());
    settings.setValue("SERIALLINK_COMM_FLOW_CONTROL", getFlowType());
167 168 169
    settings.sync();
}

170
void SerialLink::checkIfCDC()
171
{
172 173 174 175 176 177 178 179 180 181 182 183
    QString description = "X";
    foreach (QSerialPortInfo info,QSerialPortInfo::availablePorts())
    {
        if (m_portName == info.portName())
        {
            description = info.description();
            break;
        }
    }
    if (description.toLower().contains("mega") && description.contains("2560"))
    {
        type = "apm";
184
        m_is_cdc = false;
185 186 187 188 189
        qDebug() << "Attempting connection to an APM, with description:" << description;
    }
    else if (description.toLower().contains("px4"))
    {
        type = "px4";
190
        m_is_cdc = true;
191 192 193 194 195
        qDebug() << "Attempting connection to a PX4 unit with description:" << description;
    }
    else
    {
        type = "other";
196
        m_is_cdc = false;
197 198
        qDebug() << "Attempting connection to something unknown with description:" << description;
    }
199 200 201 202 203 204 205 206 207 208
}


/**
 * @brief Runs the thread
 *
 **/
void SerialLink::run()
{
    checkIfCDC();
209

pixhawk's avatar
pixhawk committed
210
    // Initialize the connection
211
    if (!hardwareConnect(type)) {
212
        //Need to error out here.
213 214 215 216 217
        QString err("Could not create port.");
        if (m_port) {
            err = m_port->errorString();
        }
        emit communicationError(getName(),"Error connecting: " + err);
218
        return;
219
    }
pixhawk's avatar
pixhawk committed
220

221 222
    qint64 msecs = QDateTime::currentMSecsSinceEpoch();
    qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch();
223
    quint64 bytes = 0;
224
    qint64 timeout = 5000;
225
    int linkErrorCount = 0;
226

227
    // Qt way to make clear what a while(1) loop does
228
    forever {
229
        {
230
            QMutexLocker locker(&this->m_stoppMutex);
231
            if (m_stopp) {
232 233 234
                m_stopp = false;
                break; // exit the thread
            }
235
        }
236

237
        // If there are too many errors on this link, disconnect.
238
        if (isConnected() && (linkErrorCount > 150)) {
239
            qDebug() << "linkErrorCount too high: re-connecting!";
240
            linkErrorCount = 0;
241
            emit communicationUpdate(getName(), tr("Link timeout, not receiving any data, attempting reconnect"));
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265

            if (m_port) {
                m_port->close();
                delete m_port;
                m_port = NULL;

                emit disconnected();
                emit connected(false);
            }

            QGC::SLEEP::msleep(500);

            unsigned tries = 0;
            const unsigned tries_max = 15;
            while (!hardwareConnect(type) && tries < tries_max) {
                tries++;
                QGC::SLEEP::msleep(500);
            }

            // Give up
            if (tries == tries_max) {
                break;
            }

266 267
        }

268
        // Write all our buffered data out the serial port.
269
        if (m_transmitBuffer.count() > 0) {
270
            m_writeMutex.lock();
271
            int numWritten = m_port->write(m_transmitBuffer);
272 273
            bool txSuccess = m_port->flush();
            txSuccess |= m_port->waitForBytesWritten(10);
274
            if (!txSuccess || (numWritten != m_transmitBuffer.count())) {
275
                linkErrorCount++;
276
                qDebug() << "TX Error! written:" << txSuccess << "wrote" << numWritten << ", asked for " << m_transmitBuffer.count() << "bytes";
277 278
            }
            else {
279 280

                // Since we were successful, reset out error counter.
281 282
                linkErrorCount = 0;
            }
283 284 285 286 287 288 289

            // Now that we transmit all of the data in the transmit buffer, flush it.
            m_transmitBuffer = m_transmitBuffer.remove(0, numWritten);
            m_writeMutex.unlock();

            // Log this written data for this timestep. If this value ends up being 0 due to
            // write() failing, that's what we want as well.
290 291
            QMutexLocker dataRateLocker(&dataRateMutex);
            logDataRateToBuffer(outDataWriteAmounts, outDataWriteTimes, &outDataIndex, numWritten, QDateTime::currentMSecsSinceEpoch());
292 293
        }

294 295
        //wait n msecs for data to be ready
        //[TODO][BB] lower to SerialLink::poll_interval?
296
        m_dataMutex.lock();
297
        bool success = m_port->waitForReadyRead(20);
298

299
        if (success) {
300 301 302
            QByteArray readData = m_port->readAll();
            while (m_port->waitForReadyRead(10))
                readData += m_port->readAll();
303
            m_dataMutex.unlock();
304 305 306
            if (readData.length() > 0) {
                emit bytesReceived(this, readData);

307
                // Log this data reception for this timestep
308 309
                QMutexLocker dataRateLocker(&dataRateMutex);
                logDataRateToBuffer(inDataWriteAmounts, inDataWriteTimes, &inDataIndex, readData.length(), QDateTime::currentMSecsSinceEpoch());
310 311

                // Track the total amount of data read.
312
                m_bytesRead += readData.length();
313
                linkErrorCount = 0;
314
            }
315 316
        }
        else {
317
            m_dataMutex.unlock();
318
            linkErrorCount++;
319
        }
320

321
        if (bytes != m_bytesRead) { // i.e things are good and data is being read.
322
            bytes = m_bytesRead;
323 324
            msecs = QDateTime::currentMSecsSinceEpoch();
        }
325 326
        else {
            if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) {
327 328
                //It's been 10 seconds since the last data came in. Reset and try again
                msecs = QDateTime::currentMSecsSinceEpoch();
329
                if (msecs - initialmsecs > 25000) {
330 331 332 333 334 335 336
                    //After initial 25 seconds, timeouts are increased to 30 seconds.
                    //This prevents temporary silences from things like calibration commands
                    //from screwing things up. In all reality, timeouts should be enabled/disabled
                    //for events like that on a case by case basis.
                    //TODO ^^
                    timeout = 30000;
                }
337 338
            }
        }
339
        QGC::SLEEP::msleep(SerialLink::poll_interval);
340 341
    } // end of forever
    
342
    if (m_port) {
343 344 345 346
        qDebug() << "Closing Port #"<< __LINE__ << m_port->portName();
        m_port->close();
        delete m_port;
        m_port = NULL;
pixhawk's avatar
pixhawk committed
347

348 349
        emit disconnected();
        emit connected(false);
350
    }
pixhawk's avatar
pixhawk committed
351 352
}

353 354
void SerialLink::writeBytes(const char* data, qint64 size)
{
Bill Bonney's avatar
Bill Bonney committed
355
    if(m_port && m_port->isOpen()) {
pixhawk's avatar
pixhawk committed
356

357
        QByteArray byteArray(data, size);
358 359 360
        m_writeMutex.lock();
        m_transmitBuffer.append(byteArray);
        m_writeMutex.unlock();
361 362 363
    } else {
        // Error occured
        emit communicationError(getName(), tr("Could not send data - link %1 is disconnected!").arg(getName()));
pixhawk's avatar
pixhawk committed
364 365 366 367 368 369 370 371 372
    }
}

/**
 * @brief Read a number of bytes from the interface.
 *
 * @param data Pointer to the data byte array to write the bytes to
 * @param maxLength The maximum number of bytes to write
 **/
373 374
void SerialLink::readBytes()
{
Bill Bonney's avatar
Bill Bonney committed
375
    if(m_port && m_port->isOpen()) {
376 377
        const qint64 maxLength = 2048;
        char data[maxLength];
378
        m_dataMutex.lock();
Bill Bonney's avatar
Bill Bonney committed
379
        qint64 numBytes = m_port->bytesAvailable();
380

381
        if(numBytes > 0) {
pixhawk's avatar
pixhawk committed
382 383 384
            /* Read as much data in buffer as possible without overflow */
            if(maxLength < numBytes) numBytes = maxLength;

Bill Bonney's avatar
Bill Bonney committed
385
            m_port->read(data, numBytes);
pixhawk's avatar
pixhawk committed
386 387 388
            QByteArray b(data, numBytes);
            emit bytesReceived(this, b);
        }
389
        m_dataMutex.unlock();
pixhawk's avatar
pixhawk committed
390 391 392 393 394 395 396 397 398
    }
}


/**
 * @brief Get the number of bytes to read.
 *
 * @return The number of bytes to read
 **/
399 400
qint64 SerialLink::bytesAvailable()
{
Bill Bonney's avatar
Bill Bonney committed
401 402
    if (m_port) {
        return m_port->bytesAvailable();
403
    } else {
404 405
        return 0;
    }
pixhawk's avatar
pixhawk committed
406 407 408 409 410 411 412
}

/**
 * @brief Disconnect the connection.
 *
 * @return True if connection has been disconnected, false if connection couldn't be disconnected.
 **/
413 414
bool SerialLink::disconnect()
{
Bill Bonney's avatar
Bill Bonney committed
415
    if (isRunning())
416 417
    {
        {
Bill Bonney's avatar
Bill Bonney committed
418 419
            QMutexLocker locker(&m_stoppMutex);
            m_stopp = true;
420
        }
Bill Bonney's avatar
Bill Bonney committed
421
        wait(); // This will terminate the thread and close the serial port
pixhawk's avatar
pixhawk committed
422

423 424
        emit connected(false);
        emit disconnected();
425 426
        return true;
    }
pixhawk's avatar
pixhawk committed
427

428 429
    m_transmitBuffer.clear(); //clear the output buffer to avoid sending garbage at next connect

430 431
    qDebug() << "already disconnected";
    return true;
pixhawk's avatar
pixhawk committed
432 433 434 435 436 437 438 439
}

/**
 * @brief Connect the connection.
 *
 * @return True if connection has been established, false if connection couldn't be established.
 **/
bool SerialLink::connect()
440
{   
441
    qDebug() << "CONNECT CALLED";
Bill Bonney's avatar
Bill Bonney committed
442 443
    if (isRunning())
        disconnect();
444 445
    {
        QMutexLocker locker(&this->m_stoppMutex);
Bill Bonney's avatar
Bill Bonney committed
446
        m_stopp = false;
447
    }
Bill Bonney's avatar
Bill Bonney committed
448

449
    start(HighPriority);
450
    return true;
pixhawk's avatar
pixhawk committed
451 452 453 454 455 456 457 458 459 460
}

/**
 * @brief This function is called indirectly by the connect() call.
 *
 * The connect() function starts the thread and indirectly calls this method.
 *
 * @return True if the connection could be established, false otherwise
 * @see connect() For the right function to establish the connection.
 **/
461
bool SerialLink::hardwareConnect(QString &type)
462
{
463
    if (m_port) {
Bill Bonney's avatar
Bill Bonney committed
464 465
        qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port";
        m_port->close();
466
        QGC::SLEEP::usleep(50000);
Bill Bonney's avatar
Bill Bonney committed
467 468
        delete m_port;
        m_port = NULL;
469
    }
pixhawk's avatar
pixhawk committed
470

471
    qDebug() << "SerialLink: hardwareConnect to " << m_portName;
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493

    if (isBootloader()) {
        qDebug() << "Not connecting to a bootloader, waiting for 2nd chance";

        const unsigned retry_limit = 12;
        unsigned retries;

        for (retries = 0; retries < retry_limit; retries++) {
            if (!isBootloader()) {
                break;
            }
            QGC::SLEEP::msleep(500);
        }

        // Check limit
        if (retries == retry_limit) {

            // bail out
            return false;
        }
    }

494
    m_port = new QSerialPort(m_portName);
Lorenz Meier's avatar
Lorenz Meier committed
495
    m_port->moveToThread(this);
496 497 498

    if (!m_port) {
        emit communicationUpdate(getName(),"Error opening port: " + m_portName);
Bill Bonney's avatar
Bill Bonney committed
499
        return false; // couldn't create serial port.
500
    }
Bill Bonney's avatar
Bill Bonney committed
501 502

    QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected()));
503
    QObject::connect(m_port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(linkError(QSerialPort::SerialPortError)));
Bill Bonney's avatar
Bill Bonney committed
504

505
    checkIfCDC();
pixhawk's avatar
pixhawk committed
506

507 508 509 510 511 512 513 514
    //    port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead);

    if (!m_port->open(QIODevice::ReadWrite)) {
        emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
        m_port->close();
        return false; // couldn't open serial port
    }

515 516 517 518 519 520 521 522 523 524 525
    // Need to configure the port
    // NOTE: THE PORT NEEDS TO BE OPEN!
    if (!m_is_cdc) {
        qDebug() << "Configuring port";
        m_port->setBaudRate(m_baud);
        m_port->setDataBits(static_cast<QSerialPort::DataBits>(m_dataBits));
        m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(m_flowControl));
        m_port->setStopBits(static_cast<QSerialPort::StopBits>(m_stopBits));
        m_port->setParity(static_cast<QSerialPort::Parity>(m_parity));
    }

526 527
    emit communicationUpdate(getName(),"Opened port!");

Bill Bonney's avatar
Bill Bonney committed
528 529
    emit connected();
    emit connected(true);
530

531
    qDebug() << "CONNECTING LINK: " << __FILE__ << __LINE__ << "type:" << type << "with settings" << m_port->portName()
Bill Bonney's avatar
Bill Bonney committed
532
             << getBaudRate() << getDataBits() << getParityType() << getStopBits();
533

534 535
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
536
    return true; // successful connection
pixhawk's avatar
pixhawk committed
537
}
538

539
void SerialLink::linkError(QSerialPort::SerialPortError error)
540
{
541
    if (error != QSerialPort::NoError) {
542 543 544 545 546
        // You can use the following qDebug output as needed during development. Make sure to comment it back out
        // when you are done. The reason for this is that this signal is very noisy. For example if you try to
        // connect to a PixHawk before it is ready to accept the connection it will output a continuous stream
        // of errors until the Pixhawk responds.
        //qDebug() << "SerialLink::linkError" << error;
547
    }
548 549
}

550

pixhawk's avatar
pixhawk committed
551 552 553 554 555
/**
 * @brief Check if connection is active.
 *
 * @return True if link is connected, false otherwise.
 **/
556
bool SerialLink::isConnected() const
557
{
Bill Bonney's avatar
Bill Bonney committed
558 559 560

    if (m_port) {
        bool isConnected = m_port->isOpen();
561 562
//        qDebug() << "SerialLink #" << __LINE__ << ":"<<  m_port->portName()
//                 << " isConnected =" << QString::number(isConnected);
Bill Bonney's avatar
Bill Bonney committed
563
        return isConnected;
564
    } else {
565 566
//        qDebug() << "SerialLink #" << __LINE__ << ":" <<  m_portName
//                 << " isConnected = NULL";
lm's avatar
lm committed
567 568
        return false;
    }
pixhawk's avatar
pixhawk committed
569 570
}

571
int SerialLink::getId() const
pixhawk's avatar
pixhawk committed
572
{
Bill Bonney's avatar
Bill Bonney committed
573
    return m_id;
pixhawk's avatar
pixhawk committed
574 575
}

576
QString SerialLink::getName() const
pixhawk's avatar
pixhawk committed
577
{
578
    return m_portName;
pixhawk's avatar
pixhawk committed
579 580
}

581 582 583 584
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
585
qint64 SerialLink::getConnectionSpeed() const
586
{
Bill Bonney's avatar
Bill Bonney committed
587
    int baudRate;
588
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    qint64 dataRate;
    switch (baudRate)
    {
        case QSerialPort::Baud1200:
            dataRate = 1200;
            break;
        case QSerialPort::Baud2400:
            dataRate = 2400;
            break;
        case QSerialPort::Baud4800:
            dataRate = 4800;
            break;
        case QSerialPort::Baud9600:
            dataRate = 9600;
            break;
        case QSerialPort::Baud19200:
            dataRate = 19200;
            break;
        case QSerialPort::Baud38400:
            dataRate = 38400;
            break;
        case QSerialPort::Baud57600:
            dataRate = 57600;
            break;
        case QSerialPort::Baud115200:
            dataRate = 115200;
            break;
            // Otherwise do nothing.
        default:
            dataRate = -1;
            break;
pixhawk's avatar
pixhawk committed
624 625 626 627
    }
    return dataRate;
}

628
QString SerialLink::getPortName() const
629
{
Bill Bonney's avatar
Bill Bonney committed
630
    return m_portName;
pixhawk's avatar
pixhawk committed
631 632
}

Bill Bonney's avatar
Bill Bonney committed
633 634
// We should replace the accessors below with one to get the QSerialPort

635
int SerialLink::getBaudRate() const
636
{
637
    return getConnectionSpeed();
pixhawk's avatar
pixhawk committed
638 639
}

640
int SerialLink::getBaudRateType() const
641
{
Bill Bonney's avatar
Bill Bonney committed
642
    int baudRate;
643
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
644 645 646 647 648
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    return baudRate;
pixhawk's avatar
pixhawk committed
649 650
}

651
int SerialLink::getFlowType() const
652
{
653

Bill Bonney's avatar
Bill Bonney committed
654
    int flowControl;
655
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
656 657 658 659 660
        flowControl = m_port->flowControl();
    } else {
        flowControl = m_flowControl;
    }
    return flowControl;
pixhawk's avatar
pixhawk committed
661 662
}

663
int SerialLink::getParityType() const
664
{
665

Bill Bonney's avatar
Bill Bonney committed
666
    int parity;
667
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
668 669 670 671 672
        parity = m_port->parity();
    } else {
        parity = m_parity;
    }
    return parity;
pixhawk's avatar
pixhawk committed
673 674
}

675
int SerialLink::getDataBitsType() const
676
{
677

Bill Bonney's avatar
Bill Bonney committed
678
    int dataBits;
679
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
680 681 682 683 684
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }
    return dataBits;
pixhawk's avatar
pixhawk committed
685 686
}

687
int SerialLink::getStopBitsType() const
688
{
689

Bill Bonney's avatar
Bill Bonney committed
690
    int stopBits;
691
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
692 693 694 695 696
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
    return stopBits;
pixhawk's avatar
pixhawk committed
697 698
}

699
int SerialLink::getDataBits() const
700
{
701

Bill Bonney's avatar
Bill Bonney committed
702 703
    int ret;
    int dataBits;
704
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
705 706 707 708 709 710 711
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }

    switch (dataBits) {
    case QSerialPort::Data5:
712 713
        ret = 5;
        break;
Bill Bonney's avatar
Bill Bonney committed
714
    case QSerialPort::Data6:
715 716
        ret = 6;
        break;
Bill Bonney's avatar
Bill Bonney committed
717
    case QSerialPort::Data7:
718 719
        ret = 7;
        break;
Bill Bonney's avatar
Bill Bonney committed
720
    case QSerialPort::Data8:
721 722 723
        ret = 8;
        break;
    default:
724
        ret = -1;
725 726 727 728 729
        break;
    }
    return ret;
}

730
int SerialLink::getStopBits() const
731
{
732

Bill Bonney's avatar
Bill Bonney committed
733
    int stopBits;
734
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
735 736 737 738
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
739
    int ret = -1;
Bill Bonney's avatar
Bill Bonney committed
740 741
    switch (stopBits) {
    case QSerialPort::OneStop:
742 743
        ret = 1;
        break;
Bill Bonney's avatar
Bill Bonney committed
744
    case QSerialPort::TwoStop:
745 746 747 748 749 750
        ret = 2;
        break;
    default:
        ret = -1;
        break;
    }
751 752 753
    return ret;
}

pixhawk's avatar
pixhawk committed
754 755
bool SerialLink::setPortName(QString portName)
{
Bill Bonney's avatar
Bill Bonney committed
756 757
    qDebug() << "current portName " << m_portName;
    qDebug() << "setPortName to " << portName;
758
    bool accepted = true;
Bill Bonney's avatar
Bill Bonney committed
759 760 761
    if ((portName != m_portName)
            && (portName.trimmed().length() > 0)) {
        m_portName = portName.trimmed();
762 763 764

        checkIfCDC();

Bill Bonney's avatar
Bill Bonney committed
765 766
        if(m_port)
            m_port->setPortName(portName);
767

768
        emit nameChanged(m_portName); // [TODO] maybe we can eliminate this
769
        emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
770
        return accepted;
pixhawk's avatar
pixhawk committed
771
    }
Bill Bonney's avatar
Bill Bonney committed
772
    return false;
pixhawk's avatar
pixhawk committed
773 774 775 776 777
}


bool SerialLink::setBaudRateType(int rateIndex)
{
778

779
  // These minimum and maximum baud rates were based on those enumerated in <QSerialPort>
780
    bool result;
Bill Bonney's avatar
Bill Bonney committed
781 782
    const int minBaud = (int)QSerialPort::Baud1200;
    const int maxBaud = (int)QSerialPort::Baud115200;
783

784
    if ((rateIndex >= minBaud && rateIndex <= maxBaud))
785
    {
786 787 788 789 790 791 792 793 794 795
        if (!m_is_cdc && m_port)
        {
            result = m_port->setBaudRate(static_cast<QSerialPort::BaudRate>(rateIndex));
            emit updateLink(this);
        } else {
            m_baud = (int)rateIndex;
            result = true;
        }
    } else {
        result = false;
pixhawk's avatar
pixhawk committed
796 797
    }

798
    return result;
pixhawk's avatar
pixhawk committed
799 800
}

801 802 803 804 805 806 807
bool SerialLink::setBaudRateString(const QString& rate)
{
    bool ok;
    int intrate = rate.toInt(&ok);
    if (!ok) return false;
    return setBaudRate(intrate);
}
pixhawk's avatar
pixhawk committed
808 809 810

bool SerialLink::setBaudRate(int rate)
{
811

Bill Bonney's avatar
Bill Bonney committed
812 813 814 815
    bool accepted = false;
    if (rate != m_baud) {
        m_baud = rate;
        accepted = true;
816
        if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
817
            accepted = m_port->setBaudRate(rate);
818
        }
819
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
820
    }
821
    return accepted;
pixhawk's avatar
pixhawk committed
822 823
}

824 825
bool SerialLink::setFlowType(int flow)
{
826

Bill Bonney's avatar
Bill Bonney committed
827 828 829 830
    bool accepted = false;
    if (flow != m_flowControl) {
        m_flowControl = static_cast<QSerialPort::FlowControl>(flow);
        accepted = true;
831
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
832
            accepted = m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(flow));
833
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
834 835 836 837
    }
    return accepted;
}

838 839
bool SerialLink::setParityType(int parity)
{
840

Bill Bonney's avatar
Bill Bonney committed
841 842 843 844
    bool accepted = false;
    if (parity != m_parity) {
        m_parity = static_cast<QSerialPort::Parity>(parity);
        accepted = true;
845
        if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
            switch (parity) {
                case QSerialPort::NoParity:
                accepted = m_port->setParity(QSerialPort::NoParity);
                break;
                case 1: // Odd Parity setting for backwards compatibilty
                    accepted = m_port->setParity(QSerialPort::OddParity);
                    break;
                case QSerialPort::EvenParity:
                    accepted = m_port->setParity(QSerialPort::EvenParity);
                    break;
                case QSerialPort::OddParity:
                    accepted = m_port->setParity(QSerialPort::OddParity);
                    break;
                default:
                    // If none of the above cases matches, there must be an error
                    accepted = false;
                    break;
                }
864
            emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
865
        }
pixhawk's avatar
pixhawk committed
866 867 868 869
    }
    return accepted;
}

870

871
bool SerialLink::setDataBits(int dataBits)
872
{
873 874

    qDebug("SET DATA BITS");
Bill Bonney's avatar
Bill Bonney committed
875 876 877 878
    bool accepted = false;
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
        accepted = true;
879
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
880
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
881
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
882 883 884 885
    }
    return accepted;
}

886
bool SerialLink::setStopBits(int stopBits)
887
{
888

Bill Bonney's avatar
Bill Bonney committed
889 890 891 892 893
    // Note 3 is OneAndAHalf stopbits.
    bool accepted = false;
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
        accepted = true;
894
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
895
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
896
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
897 898 899
    }
    return accepted;
}
900 901 902

bool SerialLink::setDataBitsType(int dataBits)
{
903

904
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
905 906
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
907
        accepted = true;
908
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
909
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
910
        emit updateLink(this);
911 912 913 914 915 916
    }
    return accepted;
}

bool SerialLink::setStopBitsType(int stopBits)
{
917

918
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
919 920
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
921
        accepted = true;
922
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
923
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
924
        emit updateLink(this);
925 926 927
    }
    return accepted;
}