SerialLink.cc 23.5 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
void SerialLink::loadSettings()
{
    // Load defaults from settings
121
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
122
    settings.sync();
123 124
    if (settings.contains("SERIALLINK_COMM_PORT"))
    {
Bill Bonney's avatar
Bill Bonney committed
125
        m_portName = settings.value("SERIALLINK_COMM_PORT").toString();
126 127
        checkIfCDC();

Bill Bonney's avatar
Bill Bonney committed
128 129 130 131 132
        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();
133 134 135 136 137 138
    }
}

void SerialLink::writeSettings()
{
    // Store settings
139
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
140
    settings.setValue("SERIALLINK_COMM_PORT", getPortName());
141 142
    settings.setValue("SERIALLINK_COMM_BAUD", getBaudRateType());
    settings.setValue("SERIALLINK_COMM_PARITY", getParityType());
143 144 145
    settings.setValue("SERIALLINK_COMM_STOPBITS", getStopBits());
    settings.setValue("SERIALLINK_COMM_DATABITS", getDataBits());
    settings.setValue("SERIALLINK_COMM_FLOW_CONTROL", getFlowType());
146 147 148
    settings.sync();
}

149
void SerialLink::checkIfCDC()
150
{
151 152 153 154 155 156 157 158 159 160 161 162
    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";
163
        m_is_cdc = false;
164 165 166 167 168
        qDebug() << "Attempting connection to an APM, with description:" << description;
    }
    else if (description.toLower().contains("px4"))
    {
        type = "px4";
169
        m_is_cdc = true;
170 171 172 173 174
        qDebug() << "Attempting connection to a PX4 unit with description:" << description;
    }
    else
    {
        type = "other";
175
        m_is_cdc = false;
176 177
        qDebug() << "Attempting connection to something unknown with description:" << description;
    }
178 179 180 181 182 183 184 185 186 187
}


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

pixhawk's avatar
pixhawk committed
189
    // Initialize the connection
190
    if (!hardwareConnect(type)) {
191
        //Need to error out here.
192 193 194 195 196
        QString err("Could not create port.");
        if (m_port) {
            err = m_port->errorString();
        }
        emit communicationError(getName(),"Error connecting: " + err);
197
        return;
198
    }
pixhawk's avatar
pixhawk committed
199

200 201
    qint64 msecs = QDateTime::currentMSecsSinceEpoch();
    qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch();
202
    quint64 bytes = 0;
203
    qint64 timeout = 5000;
204
    int linkErrorCount = 0;
205

206
    // Qt way to make clear what a while(1) loop does
207
    forever {
208
        {
209
            QMutexLocker locker(&this->m_stoppMutex);
210
            if (m_stopp) {
211 212 213
                m_stopp = false;
                break; // exit the thread
            }
214
        }
215

216
        // If there are too many errors on this link, disconnect.
217 218
        if (isConnected() && (linkErrorCount > 100)) {
            qDebug() << "linkErrorCount too high: re-connecting!";
219
            linkErrorCount = 0;
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
            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;
            }

245 246
        }

247
        // Write all our buffered data out the serial port.
248
        if (m_transmitBuffer.count() > 0) {
249
            m_writeMutex.lock();
250
            int numWritten = m_port->write(m_transmitBuffer);
251
            bool txSuccess = m_port->waitForBytesWritten(5);
252
            if (!txSuccess || (numWritten != m_transmitBuffer.count())) {
253 254
                linkErrorCount++;
                qDebug() << "TX Error! wrote" << numWritten << ", asked for " << m_transmitBuffer.count() << "bytes";
255 256
            }
            else {
257 258

                // Since we were successful, reset out error counter.
259 260
                linkErrorCount = 0;
            }
261 262 263 264 265 266 267

            // 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.
268 269
            QMutexLocker dataRateLocker(&dataRateMutex);
            logDataRateToBuffer(outDataWriteAmounts, outDataWriteTimes, &outDataIndex, numWritten, QDateTime::currentMSecsSinceEpoch());
270 271
        }

272 273
        //wait n msecs for data to be ready
        //[TODO][BB] lower to SerialLink::poll_interval?
274
        m_dataMutex.lock();
275
        bool success = m_port->waitForReadyRead(10);
276

277
        if (success) {
278 279 280
            QByteArray readData = m_port->readAll();
            while (m_port->waitForReadyRead(10))
                readData += m_port->readAll();
281
            m_dataMutex.unlock();
282 283 284
            if (readData.length() > 0) {
                emit bytesReceived(this, readData);

285
                // Log this data reception for this timestep
286 287
                QMutexLocker dataRateLocker(&dataRateMutex);
                logDataRateToBuffer(inDataWriteAmounts, inDataWriteTimes, &inDataIndex, readData.length(), QDateTime::currentMSecsSinceEpoch());
288 289

                // Track the total amount of data read.
290
                m_bytesRead += readData.length();
291
                linkErrorCount = 0;
292
            }
293 294
        }
        else {
295
            m_dataMutex.unlock();
296
            linkErrorCount++;
297
        }
298

299
        if (bytes != m_bytesRead) { // i.e things are good and data is being read.
300
            bytes = m_bytesRead;
301 302
            msecs = QDateTime::currentMSecsSinceEpoch();
        }
303 304
        else {
            if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) {
305 306
                //It's been 10 seconds since the last data came in. Reset and try again
                msecs = QDateTime::currentMSecsSinceEpoch();
307
                if (msecs - initialmsecs > 25000) {
308 309 310 311 312 313 314
                    //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;
                }
315 316
            }
        }
317 318
        //MG::SLEEP::msleep(SerialLink::poll_interval);
        QGC::SLEEP::msleep(2);
319 320
    } // end of forever
    
321
    if (m_port) {
322 323 324 325
        qDebug() << "Closing Port #"<< __LINE__ << m_port->portName();
        m_port->close();
        delete m_port;
        m_port = NULL;
pixhawk's avatar
pixhawk committed
326

327 328
        emit disconnected();
        emit connected(false);
329
    }
pixhawk's avatar
pixhawk committed
330 331
}

332 333
void SerialLink::writeBytes(const char* data, qint64 size)
{
Bill Bonney's avatar
Bill Bonney committed
334
    if(m_port && m_port->isOpen()) {
pixhawk's avatar
pixhawk committed
335

336
        QByteArray byteArray(data, size);
337 338 339
        m_writeMutex.lock();
        m_transmitBuffer.append(byteArray);
        m_writeMutex.unlock();
340 341 342
    } else {
        // Error occured
        emit communicationError(getName(), tr("Could not send data - link %1 is disconnected!").arg(getName()));
pixhawk's avatar
pixhawk committed
343 344 345 346 347 348 349 350 351
    }
}

/**
 * @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
 **/
352 353
void SerialLink::readBytes()
{
Bill Bonney's avatar
Bill Bonney committed
354
    if(m_port && m_port->isOpen()) {
355 356
        const qint64 maxLength = 2048;
        char data[maxLength];
357
        m_dataMutex.lock();
Bill Bonney's avatar
Bill Bonney committed
358
        qint64 numBytes = m_port->bytesAvailable();
359

360
        if(numBytes > 0) {
pixhawk's avatar
pixhawk committed
361 362 363
            /* Read as much data in buffer as possible without overflow */
            if(maxLength < numBytes) numBytes = maxLength;

Bill Bonney's avatar
Bill Bonney committed
364
            m_port->read(data, numBytes);
pixhawk's avatar
pixhawk committed
365 366 367
            QByteArray b(data, numBytes);
            emit bytesReceived(this, b);
        }
368
        m_dataMutex.unlock();
pixhawk's avatar
pixhawk committed
369 370 371 372 373 374 375 376 377
    }
}


/**
 * @brief Get the number of bytes to read.
 *
 * @return The number of bytes to read
 **/
378 379
qint64 SerialLink::bytesAvailable()
{
Bill Bonney's avatar
Bill Bonney committed
380 381
    if (m_port) {
        return m_port->bytesAvailable();
382
    } else {
383 384
        return 0;
    }
pixhawk's avatar
pixhawk committed
385 386 387 388 389 390 391
}

/**
 * @brief Disconnect the connection.
 *
 * @return True if connection has been disconnected, false if connection couldn't be disconnected.
 **/
392 393
bool SerialLink::disconnect()
{
Bill Bonney's avatar
Bill Bonney committed
394
    if (isRunning())
395 396
    {
        {
Bill Bonney's avatar
Bill Bonney committed
397 398
            QMutexLocker locker(&m_stoppMutex);
            m_stopp = true;
399
        }
Bill Bonney's avatar
Bill Bonney committed
400
        wait(); // This will terminate the thread and close the serial port
pixhawk's avatar
pixhawk committed
401

402 403
        return true;
    }
pixhawk's avatar
pixhawk committed
404

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

407 408
    qDebug() << "already disconnected";
    return true;
pixhawk's avatar
pixhawk committed
409 410 411 412 413 414 415 416
}

/**
 * @brief Connect the connection.
 *
 * @return True if connection has been established, false if connection couldn't be established.
 **/
bool SerialLink::connect()
417
{   
418
    qDebug() << "CONNECT CALLED";
Bill Bonney's avatar
Bill Bonney committed
419 420
    if (isRunning())
        disconnect();
421 422
    {
        QMutexLocker locker(&this->m_stoppMutex);
Bill Bonney's avatar
Bill Bonney committed
423
        m_stopp = false;
424
    }
Bill Bonney's avatar
Bill Bonney committed
425

426
    start(HighPriority);
427
    return true;
pixhawk's avatar
pixhawk committed
428 429 430 431 432 433 434 435 436 437
}

/**
 * @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.
 **/
438
bool SerialLink::hardwareConnect(QString &type)
439
{
440
    if (m_port) {
Bill Bonney's avatar
Bill Bonney committed
441 442
        qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port";
        m_port->close();
443
        QGC::SLEEP::usleep(50000);
Bill Bonney's avatar
Bill Bonney committed
444 445
        delete m_port;
        m_port = NULL;
446
    }
pixhawk's avatar
pixhawk committed
447

448 449
    qDebug() << "SerialLink: hardwareConnect to " << m_portName;
    m_port = new QSerialPort(m_portName);
Lorenz Meier's avatar
Lorenz Meier committed
450
    m_port->moveToThread(this);
451 452 453

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

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

460
    checkIfCDC();
pixhawk's avatar
pixhawk committed
461

462 463 464 465 466 467 468 469
    //    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
    }

470 471 472 473 474 475 476 477 478 479 480
    // 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));
    }

481 482
    emit communicationUpdate(getName(),"Opened port!");

Bill Bonney's avatar
Bill Bonney committed
483 484
    emit connected();
    emit connected(true);
485

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

489 490
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
491
    return true; // successful connection
pixhawk's avatar
pixhawk committed
492
}
493

494
void SerialLink::linkError(QSerialPort::SerialPortError error)
495
{
496
    if (error != QSerialPort::NoError) {
497 498 499 500 501
        // 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;
502
    }
503 504
}

505

pixhawk's avatar
pixhawk committed
506 507 508 509 510
/**
 * @brief Check if connection is active.
 *
 * @return True if link is connected, false otherwise.
 **/
511
bool SerialLink::isConnected() const
512
{
Bill Bonney's avatar
Bill Bonney committed
513 514 515

    if (m_port) {
        bool isConnected = m_port->isOpen();
516 517
//        qDebug() << "SerialLink #" << __LINE__ << ":"<<  m_port->portName()
//                 << " isConnected =" << QString::number(isConnected);
Bill Bonney's avatar
Bill Bonney committed
518
        return isConnected;
519
    } else {
520 521
//        qDebug() << "SerialLink #" << __LINE__ << ":" <<  m_portName
//                 << " isConnected = NULL";
lm's avatar
lm committed
522 523
        return false;
    }
pixhawk's avatar
pixhawk committed
524 525
}

526
int SerialLink::getId() const
pixhawk's avatar
pixhawk committed
527
{
Bill Bonney's avatar
Bill Bonney committed
528
    return m_id;
pixhawk's avatar
pixhawk committed
529 530
}

531
QString SerialLink::getName() const
pixhawk's avatar
pixhawk committed
532
{
533
    return m_portName;
pixhawk's avatar
pixhawk committed
534 535
}

536 537 538 539
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
540
qint64 SerialLink::getConnectionSpeed() const
541
{
Bill Bonney's avatar
Bill Bonney committed
542
    int baudRate;
543
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
        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
580 581 582 583
    }
    return dataRate;
}

584
QString SerialLink::getPortName() const
585
{
Bill Bonney's avatar
Bill Bonney committed
586
    return m_portName;
pixhawk's avatar
pixhawk committed
587 588
}

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

591
int SerialLink::getBaudRate() const
592
{
593
    return getConnectionSpeed();
pixhawk's avatar
pixhawk committed
594 595
}

596
int SerialLink::getBaudRateType() const
597
{
Bill Bonney's avatar
Bill Bonney committed
598
    int baudRate;
599
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
600 601 602 603 604
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    return baudRate;
pixhawk's avatar
pixhawk committed
605 606
}

607
int SerialLink::getFlowType() const
608
{
609

Bill Bonney's avatar
Bill Bonney committed
610
    int flowControl;
611
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
612 613 614 615 616
        flowControl = m_port->flowControl();
    } else {
        flowControl = m_flowControl;
    }
    return flowControl;
pixhawk's avatar
pixhawk committed
617 618
}

619
int SerialLink::getParityType() const
620
{
621

Bill Bonney's avatar
Bill Bonney committed
622
    int parity;
623
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
624 625 626 627 628
        parity = m_port->parity();
    } else {
        parity = m_parity;
    }
    return parity;
pixhawk's avatar
pixhawk committed
629 630
}

631
int SerialLink::getDataBitsType() const
632
{
633

Bill Bonney's avatar
Bill Bonney committed
634
    int dataBits;
635
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
636 637 638 639 640
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }
    return dataBits;
pixhawk's avatar
pixhawk committed
641 642
}

643
int SerialLink::getStopBitsType() const
644
{
645

Bill Bonney's avatar
Bill Bonney committed
646
    int stopBits;
647
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
648 649 650 651 652
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
    return stopBits;
pixhawk's avatar
pixhawk committed
653 654
}

655
int SerialLink::getDataBits() const
656
{
657

Bill Bonney's avatar
Bill Bonney committed
658 659
    int ret;
    int dataBits;
660
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
661 662 663 664 665 666 667
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }

    switch (dataBits) {
    case QSerialPort::Data5:
668 669
        ret = 5;
        break;
Bill Bonney's avatar
Bill Bonney committed
670
    case QSerialPort::Data6:
671 672
        ret = 6;
        break;
Bill Bonney's avatar
Bill Bonney committed
673
    case QSerialPort::Data7:
674 675
        ret = 7;
        break;
Bill Bonney's avatar
Bill Bonney committed
676
    case QSerialPort::Data8:
677 678 679
        ret = 8;
        break;
    default:
680
        ret = -1;
681 682 683 684 685
        break;
    }
    return ret;
}

686
int SerialLink::getStopBits() const
687
{
688

Bill Bonney's avatar
Bill Bonney committed
689
    int stopBits;
690
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
691 692 693 694
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
695
    int ret = -1;
Bill Bonney's avatar
Bill Bonney committed
696 697
    switch (stopBits) {
    case QSerialPort::OneStop:
698 699
        ret = 1;
        break;
Bill Bonney's avatar
Bill Bonney committed
700
    case QSerialPort::TwoStop:
701 702 703 704 705 706
        ret = 2;
        break;
    default:
        ret = -1;
        break;
    }
707 708 709
    return ret;
}

pixhawk's avatar
pixhawk committed
710 711
bool SerialLink::setPortName(QString portName)
{
Bill Bonney's avatar
Bill Bonney committed
712 713
    qDebug() << "current portName " << m_portName;
    qDebug() << "setPortName to " << portName;
714
    bool accepted = true;
Bill Bonney's avatar
Bill Bonney committed
715 716 717
    if ((portName != m_portName)
            && (portName.trimmed().length() > 0)) {
        m_portName = portName.trimmed();
718 719 720

        checkIfCDC();

Bill Bonney's avatar
Bill Bonney committed
721 722
        if(m_port)
            m_port->setPortName(portName);
723

724
        emit nameChanged(m_portName); // [TODO] maybe we can eliminate this
725
        emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
726
        return accepted;
pixhawk's avatar
pixhawk committed
727
    }
Bill Bonney's avatar
Bill Bonney committed
728
    return false;
pixhawk's avatar
pixhawk committed
729 730 731 732 733
}


bool SerialLink::setBaudRateType(int rateIndex)
{
734

735
  // These minimum and maximum baud rates were based on those enumerated in qserialport.h
736
    bool result;
Bill Bonney's avatar
Bill Bonney committed
737 738
    const int minBaud = (int)QSerialPort::Baud1200;
    const int maxBaud = (int)QSerialPort::Baud115200;
739

740
    if ((rateIndex >= minBaud && rateIndex <= maxBaud))
741
    {
742 743 744 745 746 747 748 749 750 751
        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
752 753
    }

754
    return result;
pixhawk's avatar
pixhawk committed
755 756
}

757 758 759 760 761 762 763
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
764 765 766

bool SerialLink::setBaudRate(int rate)
{
767

Bill Bonney's avatar
Bill Bonney committed
768 769 770 771
    bool accepted = false;
    if (rate != m_baud) {
        m_baud = rate;
        accepted = true;
772
        if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
773
            accepted = m_port->setBaudRate(rate);
774
        }
775
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
776
    }
777
    return accepted;
pixhawk's avatar
pixhawk committed
778 779
}

780 781
bool SerialLink::setFlowType(int flow)
{
782

Bill Bonney's avatar
Bill Bonney committed
783 784 785 786
    bool accepted = false;
    if (flow != m_flowControl) {
        m_flowControl = static_cast<QSerialPort::FlowControl>(flow);
        accepted = true;
787
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
788
            accepted = m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(flow));
789
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
790 791 792 793
    }
    return accepted;
}

794 795
bool SerialLink::setParityType(int parity)
{
796

Bill Bonney's avatar
Bill Bonney committed
797 798 799 800
    bool accepted = false;
    if (parity != m_parity) {
        m_parity = static_cast<QSerialPort::Parity>(parity);
        accepted = true;
801
        if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
            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;
                }
820
            emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
821
        }
pixhawk's avatar
pixhawk committed
822 823 824 825
    }
    return accepted;
}

826

827
bool SerialLink::setDataBits(int dataBits)
828
{
829 830

    qDebug("SET DATA BITS");
Bill Bonney's avatar
Bill Bonney committed
831 832 833 834
    bool accepted = false;
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
        accepted = true;
835
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
836
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
837
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
838 839 840 841
    }
    return accepted;
}

842
bool SerialLink::setStopBits(int stopBits)
843
{
844

Bill Bonney's avatar
Bill Bonney committed
845 846 847 848 849
    // Note 3 is OneAndAHalf stopbits.
    bool accepted = false;
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
        accepted = true;
850
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
851
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
852
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
853 854 855
    }
    return accepted;
}
856 857 858

bool SerialLink::setDataBitsType(int dataBits)
{
859

860
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
861 862
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
863
        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);
867 868 869 870 871 872
    }
    return accepted;
}

bool SerialLink::setStopBitsType(int stopBits)
{
873

874
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
875 876
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
877
        accepted = true;
878
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
879
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
880
        emit updateLink(this);
881 882 883
    }
    return accepted;
}