SerialLink.cc 24.4 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

SerialLink::~SerialLink()
{
88
    _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;
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;
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
    }
}

/**
 * @brief Disconnect the connection.
 *
 * @return True if connection has been disconnected, false if connection couldn't be disconnected.
 **/
398
bool SerialLink::_disconnect(void)
399
{
Bill Bonney's avatar
Bill Bonney committed
400
    if (isRunning())
401 402
    {
        {
Bill Bonney's avatar
Bill Bonney committed
403 404
            QMutexLocker locker(&m_stoppMutex);
            m_stopp = true;
405
        }
Bill Bonney's avatar
Bill Bonney committed
406
        wait(); // This will terminate the thread and close the serial port
pixhawk's avatar
pixhawk committed
407

408 409
        return true;
    }
pixhawk's avatar
pixhawk committed
410

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

413 414
    qDebug() << "already disconnected";
    return true;
pixhawk's avatar
pixhawk committed
415 416 417 418 419 420 421
}

/**
 * @brief Connect the connection.
 *
 * @return True if connection has been established, false if connection couldn't be established.
 **/
422
bool SerialLink::_connect(void)
423
{   
424
    qDebug() << "CONNECT CALLED";
Bill Bonney's avatar
Bill Bonney committed
425
    if (isRunning())
426
        _disconnect();
427 428
    {
        QMutexLocker locker(&this->m_stoppMutex);
Bill Bonney's avatar
Bill Bonney committed
429
        m_stopp = false;
430
    }
Bill Bonney's avatar
Bill Bonney committed
431

432
    start(HighPriority);
433
    return true;
pixhawk's avatar
pixhawk committed
434 435 436
}

/**
437
 * @brief This function is called indirectly by the _connect() call.
pixhawk's avatar
pixhawk committed
438
 *
439
 * The _connect() function starts the thread and indirectly calls this method.
pixhawk's avatar
pixhawk committed
440 441
 *
 * @return True if the connection could be established, false otherwise
442
 * @see _connect() For the right function to establish the connection.
pixhawk's avatar
pixhawk committed
443
 **/
444
bool SerialLink::hardwareConnect(QString &type)
445
{
446
    if (m_port) {
Bill Bonney's avatar
Bill Bonney committed
447 448
        qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port";
        m_port->close();
449
        QGC::SLEEP::usleep(50000);
Bill Bonney's avatar
Bill Bonney committed
450 451
        delete m_port;
        m_port = NULL;
452
    }
pixhawk's avatar
pixhawk committed
453

454
    qDebug() << "SerialLink: hardwareConnect to " << m_portName;
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476

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

477
    m_port = new QSerialPort(m_portName);
Lorenz Meier's avatar
Lorenz Meier committed
478
    m_port->moveToThread(this);
479 480 481

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

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

488
    checkIfCDC();
pixhawk's avatar
pixhawk committed
489

490 491 492 493 494 495 496 497
    //    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
    }

498 499 500 501 502 503 504 505 506 507 508
    // 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));
    }

509 510
    emit communicationUpdate(getName(),"Opened port!");

Bill Bonney's avatar
Bill Bonney committed
511 512
    emit connected();
    emit connected(true);
513

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

517 518
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
519
    return true; // successful connection
pixhawk's avatar
pixhawk committed
520
}
521

522
void SerialLink::linkError(QSerialPort::SerialPortError error)
523
{
524
    if (error != QSerialPort::NoError) {
525 526 527 528 529
        // 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;
530
    }
531 532
}

533

pixhawk's avatar
pixhawk committed
534 535 536 537 538
/**
 * @brief Check if connection is active.
 *
 * @return True if link is connected, false otherwise.
 **/
539
bool SerialLink::isConnected() const
540
{
Bill Bonney's avatar
Bill Bonney committed
541 542 543

    if (m_port) {
        bool isConnected = m_port->isOpen();
544 545
//        qDebug() << "SerialLink #" << __LINE__ << ":"<<  m_port->portName()
//                 << " isConnected =" << QString::number(isConnected);
Bill Bonney's avatar
Bill Bonney committed
546
        return isConnected;
547
    } else {
548 549
//        qDebug() << "SerialLink #" << __LINE__ << ":" <<  m_portName
//                 << " isConnected = NULL";
lm's avatar
lm committed
550 551
        return false;
    }
pixhawk's avatar
pixhawk committed
552 553
}

554
int SerialLink::getId() const
pixhawk's avatar
pixhawk committed
555
{
Bill Bonney's avatar
Bill Bonney committed
556
    return m_id;
pixhawk's avatar
pixhawk committed
557 558
}

559
QString SerialLink::getName() const
pixhawk's avatar
pixhawk committed
560
{
561
    return m_portName;
pixhawk's avatar
pixhawk committed
562 563
}

564 565 566 567
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
568
qint64 SerialLink::getConnectionSpeed() const
569
{
Bill Bonney's avatar
Bill Bonney committed
570
    int baudRate;
571
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
        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
607 608 609 610
    }
    return dataRate;
}

611
QString SerialLink::getPortName() const
612
{
Bill Bonney's avatar
Bill Bonney committed
613
    return m_portName;
pixhawk's avatar
pixhawk committed
614 615
}

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

618
int SerialLink::getBaudRate() const
619
{
620
    return getConnectionSpeed();
pixhawk's avatar
pixhawk committed
621 622
}

623
int SerialLink::getBaudRateType() const
624
{
Bill Bonney's avatar
Bill Bonney committed
625
    int baudRate;
626
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
627 628 629 630 631
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    return baudRate;
pixhawk's avatar
pixhawk committed
632 633
}

634
int SerialLink::getFlowType() const
635
{
636

Bill Bonney's avatar
Bill Bonney committed
637
    int flowControl;
638
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
639 640 641 642 643
        flowControl = m_port->flowControl();
    } else {
        flowControl = m_flowControl;
    }
    return flowControl;
pixhawk's avatar
pixhawk committed
644 645
}

646
int SerialLink::getParityType() const
647
{
648

Bill Bonney's avatar
Bill Bonney committed
649
    int parity;
650
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
651 652 653 654 655
        parity = m_port->parity();
    } else {
        parity = m_parity;
    }
    return parity;
pixhawk's avatar
pixhawk committed
656 657
}

658
int SerialLink::getDataBitsType() const
659
{
660

Bill Bonney's avatar
Bill Bonney committed
661
    int dataBits;
662
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
663 664 665 666 667
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }
    return dataBits;
pixhawk's avatar
pixhawk committed
668 669
}

670
int SerialLink::getStopBitsType() const
671
{
672

Bill Bonney's avatar
Bill Bonney committed
673
    int stopBits;
674
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
675 676 677 678 679
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
    return stopBits;
pixhawk's avatar
pixhawk committed
680 681
}

682
int SerialLink::getDataBits() const
683
{
684

Bill Bonney's avatar
Bill Bonney committed
685 686
    int ret;
    int dataBits;
687
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
688 689 690 691 692 693 694
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }

    switch (dataBits) {
    case QSerialPort::Data5:
695 696
        ret = 5;
        break;
Bill Bonney's avatar
Bill Bonney committed
697
    case QSerialPort::Data6:
698 699
        ret = 6;
        break;
Bill Bonney's avatar
Bill Bonney committed
700
    case QSerialPort::Data7:
701 702
        ret = 7;
        break;
Bill Bonney's avatar
Bill Bonney committed
703
    case QSerialPort::Data8:
704 705 706
        ret = 8;
        break;
    default:
707
        ret = -1;
708 709 710 711 712
        break;
    }
    return ret;
}

713
int SerialLink::getStopBits() const
714
{
715

Bill Bonney's avatar
Bill Bonney committed
716
    int stopBits;
717
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
718 719 720 721
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
722
    int ret = -1;
Bill Bonney's avatar
Bill Bonney committed
723 724
    switch (stopBits) {
    case QSerialPort::OneStop:
725 726
        ret = 1;
        break;
Bill Bonney's avatar
Bill Bonney committed
727
    case QSerialPort::TwoStop:
728 729 730 731 732 733
        ret = 2;
        break;
    default:
        ret = -1;
        break;
    }
734 735 736
    return ret;
}

pixhawk's avatar
pixhawk committed
737 738
bool SerialLink::setPortName(QString portName)
{
Bill Bonney's avatar
Bill Bonney committed
739 740
    qDebug() << "current portName " << m_portName;
    qDebug() << "setPortName to " << portName;
741
    bool accepted = true;
Bill Bonney's avatar
Bill Bonney committed
742 743 744
    if ((portName != m_portName)
            && (portName.trimmed().length() > 0)) {
        m_portName = portName.trimmed();
745 746 747

        checkIfCDC();

Bill Bonney's avatar
Bill Bonney committed
748 749
        if(m_port)
            m_port->setPortName(portName);
750

751
        emit nameChanged(m_portName); // [TODO] maybe we can eliminate this
752
        emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
753
        return accepted;
pixhawk's avatar
pixhawk committed
754
    }
Bill Bonney's avatar
Bill Bonney committed
755
    return false;
pixhawk's avatar
pixhawk committed
756 757 758 759 760
}


bool SerialLink::setBaudRateType(int rateIndex)
{
761

762
  // These minimum and maximum baud rates were based on those enumerated in <QSerialPort>
763
    bool result;
Bill Bonney's avatar
Bill Bonney committed
764 765
    const int minBaud = (int)QSerialPort::Baud1200;
    const int maxBaud = (int)QSerialPort::Baud115200;
766

767
    if ((rateIndex >= minBaud && rateIndex <= maxBaud))
768
    {
769 770 771 772 773 774 775 776 777 778
        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
779 780
    }

781
    return result;
pixhawk's avatar
pixhawk committed
782 783
}

784 785 786 787 788 789 790
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
791 792 793

bool SerialLink::setBaudRate(int rate)
{
794

Bill Bonney's avatar
Bill Bonney committed
795 796 797 798
    bool accepted = false;
    if (rate != m_baud) {
        m_baud = rate;
        accepted = true;
799
        if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
800
            accepted = m_port->setBaudRate(rate);
801
        }
802
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
803
    }
804
    return accepted;
pixhawk's avatar
pixhawk committed
805 806
}

807 808
bool SerialLink::setFlowType(int flow)
{
809

Bill Bonney's avatar
Bill Bonney committed
810 811 812 813
    bool accepted = false;
    if (flow != m_flowControl) {
        m_flowControl = static_cast<QSerialPort::FlowControl>(flow);
        accepted = true;
814
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
815
            accepted = m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(flow));
816
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
817 818 819 820
    }
    return accepted;
}

821 822
bool SerialLink::setParityType(int parity)
{
823

Bill Bonney's avatar
Bill Bonney committed
824 825 826 827
    bool accepted = false;
    if (parity != m_parity) {
        m_parity = static_cast<QSerialPort::Parity>(parity);
        accepted = true;
828
        if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
            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;
                }
847
            emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
848
        }
pixhawk's avatar
pixhawk committed
849 850 851 852
    }
    return accepted;
}

853

854
bool SerialLink::setDataBits(int dataBits)
855
{
856 857

    qDebug("SET DATA BITS");
Bill Bonney's avatar
Bill Bonney committed
858 859 860 861
    bool accepted = false;
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
        accepted = true;
862
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
863
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
864
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
865 866 867 868
    }
    return accepted;
}

869
bool SerialLink::setStopBits(int stopBits)
870
{
871

Bill Bonney's avatar
Bill Bonney committed
872 873 874 875 876
    // Note 3 is OneAndAHalf stopbits.
    bool accepted = false;
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
        accepted = true;
877
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
878
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
879
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
880 881 882
    }
    return accepted;
}
883 884 885

bool SerialLink::setDataBitsType(int dataBits)
{
886

887
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
888 889
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
890
        accepted = true;
891
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
892
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
893
        emit updateLink(this);
894 895 896 897 898 899
    }
    return accepted;
}

bool SerialLink::setStopBitsType(int stopBits)
{
900

901
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
902 903
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
904
        accepted = true;
905
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
906
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
907
        emit updateLink(this);
908 909 910
    }
    return accepted;
}