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>
Bill Bonney's avatar
Bill Bonney committed
15 16
#include <qserialport.h>
#include <qserialportinfo.h>
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 25
    m_bytesRead(0),
    m_port(NULL),
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
    if (m_portName == "" && getCurrentPorts().size() > 0)
38
    {
39
        m_portName = m_ports.first().trimmed();
40 41
    }

42 43
    checkIfCDC();

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

    m_baud = baudRate;
48

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

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

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

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

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

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

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

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

97
QList<QString> SerialLink::getCurrentPorts()
98
{
99
    m_ports.clear();
100

101
    QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();
102

103 104
    if( portList.count() == 0){
        qDebug() << "No Ports Found" << m_ports;
105 106
    }

107
    foreach (const QSerialPortInfo &info, portList)
108
    {
Bill Bonney's avatar
Bill Bonney committed
109 110 111
//        qDebug() << "PortName    : " << info.portName()
//                 << "Description : " << info.description();
//        qDebug() << "Manufacturer: " << info.manufacturer();
112

113
        m_ports.append(info.portName());
114
    }
Bill Bonney's avatar
Bill Bonney committed
115
    return m_ports;
pixhawk's avatar
pixhawk committed
116 117
}

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
bool SerialLink::isBootloader()
{
    QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();

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

    foreach (const QSerialPortInfo &info, portList)
    {
//        qDebug() << "PortName    : " << info.portName()
//                 << "Description : " << info.description();
//        qDebug() << "Manufacturer: " << info.manufacturer();

       if (info.portName().trimmed() == this->m_portName.trimmed() &&
               (info.description().toLower().contains("bootloader") ||
                info.description().toLower().contains("px4 bl"))) {
           qDebug() << "BOOTLOADER FOUND";
           return true;
       }
    }

    // Not found
    return false;
}

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

Bill Bonney's avatar
Bill Bonney committed
154 155 156 157 158
        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();
159 160 161 162 163 164
    }
}

void SerialLink::writeSettings()
{
    // Store settings
165
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
166
    settings.setValue("SERIALLINK_COMM_PORT", getPortName());
167 168
    settings.setValue("SERIALLINK_COMM_BAUD", getBaudRateType());
    settings.setValue("SERIALLINK_COMM_PARITY", getParityType());
169 170 171
    settings.setValue("SERIALLINK_COMM_STOPBITS", getStopBits());
    settings.setValue("SERIALLINK_COMM_DATABITS", getDataBits());
    settings.setValue("SERIALLINK_COMM_FLOW_CONTROL", getFlowType());
172 173 174
    settings.sync();
}

175
void SerialLink::checkIfCDC()
176
{
177 178 179 180 181 182 183 184 185 186 187 188
    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";
189
        m_is_cdc = false;
190 191 192 193 194
        qDebug() << "Attempting connection to an APM, with description:" << description;
    }
    else if (description.toLower().contains("px4"))
    {
        type = "px4";
195
        m_is_cdc = true;
196 197 198 199 200
        qDebug() << "Attempting connection to a PX4 unit with description:" << description;
    }
    else
    {
        type = "other";
201
        m_is_cdc = false;
202 203
        qDebug() << "Attempting connection to something unknown with description:" << description;
    }
204 205 206 207 208 209 210 211 212 213
}


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

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

226 227
    qint64 msecs = QDateTime::currentMSecsSinceEpoch();
    qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch();
228
    quint64 bytes = 0;
229
    qint64 timeout = 5000;
230
    int linkErrorCount = 0;
231

232
    // Qt way to make clear what a while(1) loop does
233
    forever {
234
        {
235
            QMutexLocker locker(&this->m_stoppMutex);
236
            if (m_stopp) {
237 238 239
                m_stopp = false;
                break; // exit the thread
            }
240
        }
241

242
        // If there are too many errors on this link, disconnect.
243 244
        if (isConnected() && (linkErrorCount > 100)) {
            qDebug() << "linkErrorCount too high: re-connecting!";
245
            linkErrorCount = 0;
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
            emit communicationUpdate(getName(), tr("Reconnecting on too many link errors"));

            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;
            }

271 272
        }

273
        // Write all our buffered data out the serial port.
274
        if (m_transmitBuffer.count() > 0) {
275
            m_writeMutex.lock();
276
            int numWritten = m_port->write(m_transmitBuffer);
277
            bool txSuccess = m_port->waitForBytesWritten(5);
278
            if (!txSuccess || (numWritten != m_transmitBuffer.count())) {
279 280
                linkErrorCount++;
                qDebug() << "TX Error! wrote" << numWritten << ", asked for " << m_transmitBuffer.count() << "bytes";
281 282
            }
            else {
283 284

                // Since we were successful, reset out error counter.
285 286
                linkErrorCount = 0;
            }
287 288 289 290 291 292 293

            // 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.
294 295
            QMutexLocker dataRateLocker(&dataRateMutex);
            logDataRateToBuffer(outDataWriteAmounts, outDataWriteTimes, &outDataIndex, numWritten, QDateTime::currentMSecsSinceEpoch());
296 297
        }

298 299
        //wait n msecs for data to be ready
        //[TODO][BB] lower to SerialLink::poll_interval?
300
        m_dataMutex.lock();
301
        bool success = m_port->waitForReadyRead(10);
302

303
        if (success) {
304 305 306
            QByteArray readData = m_port->readAll();
            while (m_port->waitForReadyRead(10))
                readData += m_port->readAll();
307
            m_dataMutex.unlock();
308 309 310
            if (readData.length() > 0) {
                emit bytesReceived(this, readData);

311
                // Log this data reception for this timestep
312 313
                QMutexLocker dataRateLocker(&dataRateMutex);
                logDataRateToBuffer(inDataWriteAmounts, inDataWriteTimes, &inDataIndex, readData.length(), QDateTime::currentMSecsSinceEpoch());
314 315

                // Track the total amount of data read.
316
                m_bytesRead += readData.length();
317
                linkErrorCount = 0;
318
            }
319 320
        }
        else {
321
            m_dataMutex.unlock();
322
            linkErrorCount++;
323
        }
324

325
        if (bytes != m_bytesRead) { // i.e things are good and data is being read.
326
            bytes = m_bytesRead;
327 328
            msecs = QDateTime::currentMSecsSinceEpoch();
        }
329 330
        else {
            if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) {
331 332
                //It's been 10 seconds since the last data came in. Reset and try again
                msecs = QDateTime::currentMSecsSinceEpoch();
333
                if (msecs - initialmsecs > 25000) {
334 335 336 337 338 339 340
                    //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;
                }
341 342
            }
        }
343
        QGC::SLEEP::msleep(SerialLink::poll_interval);
344 345
    } // end of forever
    
346
    if (m_port) {
347 348 349 350
        qDebug() << "Closing Port #"<< __LINE__ << m_port->portName();
        m_port->close();
        delete m_port;
        m_port = NULL;
pixhawk's avatar
pixhawk committed
351

352 353
        emit disconnected();
        emit connected(false);
354
    }
pixhawk's avatar
pixhawk committed
355 356
}

357 358
void SerialLink::writeBytes(const char* data, qint64 size)
{
Bill Bonney's avatar
Bill Bonney committed
359
    if(m_port && m_port->isOpen()) {
pixhawk's avatar
pixhawk committed
360

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

/**
 * @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
 **/
377 378
void SerialLink::readBytes()
{
Bill Bonney's avatar
Bill Bonney committed
379
    if(m_port && m_port->isOpen()) {
380 381
        const qint64 maxLength = 2048;
        char data[maxLength];
382
        m_dataMutex.lock();
Bill Bonney's avatar
Bill Bonney committed
383
        qint64 numBytes = m_port->bytesAvailable();
384

385
        if(numBytes > 0) {
pixhawk's avatar
pixhawk committed
386 387 388
            /* Read as much data in buffer as possible without overflow */
            if(maxLength < numBytes) numBytes = maxLength;

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


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

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

427 428
        return true;
    }
pixhawk's avatar
pixhawk committed
429

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

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

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

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

/**
 * @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.
 **/
463
bool SerialLink::hardwareConnect(QString &type)
464
{
465
    if (m_port) {
Bill Bonney's avatar
Bill Bonney committed
466 467
        qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port";
        m_port->close();
468
        QGC::SLEEP::usleep(50000);
Bill Bonney's avatar
Bill Bonney committed
469 470
        delete m_port;
        m_port = NULL;
471
    }
pixhawk's avatar
pixhawk committed
472

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

    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;
        }
    }

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

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

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

507
    checkIfCDC();
pixhawk's avatar
pixhawk committed
508

509 510 511 512 513 514 515 516
    //    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
    }

517 518 519 520 521 522 523 524 525 526 527
    // 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));
    }

528 529
    emit communicationUpdate(getName(),"Opened port!");

Bill Bonney's avatar
Bill Bonney committed
530 531
    emit connected();
    emit connected(true);
532

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

536 537
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
538
    return true; // successful connection
pixhawk's avatar
pixhawk committed
539
}
540

541
void SerialLink::linkError(QSerialPort::SerialPortError error)
542
{
543
    if (error != QSerialPort::NoError) {
544 545 546 547 548
        // 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;
549
    }
550 551
}

552

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

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

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

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

583 584 585 586
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
587
qint64 SerialLink::getConnectionSpeed() const
588
{
Bill Bonney's avatar
Bill Bonney committed
589
    int baudRate;
590
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
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 624 625 626
        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.
        case QSerialPort::UnknownBaud:
        default:
            dataRate = -1;
            break;
pixhawk's avatar
pixhawk committed
627 628 629 630
    }
    return dataRate;
}

631
QString SerialLink::getPortName() const
632
{
Bill Bonney's avatar
Bill Bonney committed
633
    return m_portName;
pixhawk's avatar
pixhawk committed
634 635
}

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

638
int SerialLink::getBaudRate() const
639
{
640
    return getConnectionSpeed();
pixhawk's avatar
pixhawk committed
641 642
}

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

654
int SerialLink::getFlowType() const
655
{
656

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

666
int SerialLink::getParityType() const
667
{
668

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

678
int SerialLink::getDataBitsType() const
679
{
680

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

690
int SerialLink::getStopBitsType() const
691
{
692

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

702
int SerialLink::getDataBits() const
703
{
704

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

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

733
int SerialLink::getStopBits() const
734
{
735

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

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

        checkIfCDC();

Bill Bonney's avatar
Bill Bonney committed
768 769
        if(m_port)
            m_port->setPortName(portName);
770

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


bool SerialLink::setBaudRateType(int rateIndex)
{
781

782
  // These minimum and maximum baud rates were based on those enumerated in qserialport.h
783
    bool result;
Bill Bonney's avatar
Bill Bonney committed
784 785
    const int minBaud = (int)QSerialPort::Baud1200;
    const int maxBaud = (int)QSerialPort::Baud115200;
786

787
    if ((rateIndex >= minBaud && rateIndex <= maxBaud))
788
    {
789 790 791 792 793 794 795 796 797 798
        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
799 800
    }

801
    return result;
pixhawk's avatar
pixhawk committed
802 803
}

804 805 806 807 808 809 810
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
811 812 813

bool SerialLink::setBaudRate(int rate)
{
814

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

827 828
bool SerialLink::setFlowType(int flow)
{
829

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

841 842
bool SerialLink::setParityType(int parity)
{
843

Bill Bonney's avatar
Bill Bonney committed
844 845 846 847
    bool accepted = false;
    if (parity != m_parity) {
        m_parity = static_cast<QSerialPort::Parity>(parity);
        accepted = true;
848
        if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
            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;
                }
867
            emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
868
        }
pixhawk's avatar
pixhawk committed
869 870 871 872
    }
    return accepted;
}

873

874
bool SerialLink::setDataBits(int dataBits)
875
{
876 877

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

889
bool SerialLink::setStopBits(int stopBits)
890
{
891

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

bool SerialLink::setDataBitsType(int dataBits)
{
906

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

bool SerialLink::setStopBitsType(int stopBits)
{
920

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