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 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;
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 399
bool SerialLink::disconnect()
{
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
        emit connected(false);
        emit disconnected();
410 411
        return true;
    }
pixhawk's avatar
pixhawk committed
412

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

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

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

434
    start(HighPriority);
435
    return true;
pixhawk's avatar
pixhawk committed
436 437 438 439 440 441 442 443 444 445
}

/**
 * @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.
 **/
446
bool SerialLink::hardwareConnect(QString &type)
447
{
448
    if (m_port) {
Bill Bonney's avatar
Bill Bonney committed
449 450
        qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port";
        m_port->close();
451
        QGC::SLEEP::usleep(50000);
Bill Bonney's avatar
Bill Bonney committed
452 453
        delete m_port;
        m_port = NULL;
454
    }
pixhawk's avatar
pixhawk committed
455

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

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

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

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

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

490
    checkIfCDC();
pixhawk's avatar
pixhawk committed
491

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

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

511 512
    emit communicationUpdate(getName(),"Opened port!");

Bill Bonney's avatar
Bill Bonney committed
513 514
    emit connected();
    emit connected(true);
515

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

519 520
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
521
    return true; // successful connection
pixhawk's avatar
pixhawk committed
522
}
523

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

535

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

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

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

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

566 567 568 569
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
570
qint64 SerialLink::getConnectionSpeed() const
571
{
Bill Bonney's avatar
Bill Bonney committed
572
    int baudRate;
573
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
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 607 608
        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
609 610 611 612
    }
    return dataRate;
}

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

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

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

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

636
int SerialLink::getFlowType() const
637
{
638

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

648
int SerialLink::getParityType() const
649
{
650

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

660
int SerialLink::getDataBitsType() const
661
{
662

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

672
int SerialLink::getStopBitsType() const
673
{
674

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

684
int SerialLink::getDataBits() const
685
{
686

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

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

715
int SerialLink::getStopBits() const
716
{
717

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

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

        checkIfCDC();

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

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


bool SerialLink::setBaudRateType(int rateIndex)
{
763

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

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

783
    return result;
pixhawk's avatar
pixhawk committed
784 785
}

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

bool SerialLink::setBaudRate(int rate)
{
796

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

809 810
bool SerialLink::setFlowType(int flow)
{
811

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

823 824
bool SerialLink::setParityType(int parity)
{
825

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

855

856
bool SerialLink::setDataBits(int dataBits)
857
{
858 859

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

871
bool SerialLink::setStopBits(int stopBits)
872
{
873

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

bool SerialLink::setDataBitsType(int dataBits)
{
888

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

bool SerialLink::setStopBitsType(int stopBits)
{
902

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