SerialLink.cc 24.6 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;
90 91
}

92
QList<QString> SerialLink::getCurrentPorts()
93
{
94
    m_ports.clear();
95

96
    QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();
97

98 99
    if( portList.count() == 0){
        qDebug() << "No Ports Found" << m_ports;
100 101
    }

102
    foreach (const QSerialPortInfo &info, portList)
103
    {
Bill Bonney's avatar
Bill Bonney committed
104 105 106
//        qDebug() << "PortName    : " << info.portName()
//                 << "Description : " << info.description();
//        qDebug() << "Manufacturer: " << info.manufacturer();
107

108
        m_ports.append(info.portName());
109
    }
Bill Bonney's avatar
Bill Bonney committed
110
    return m_ports;
pixhawk's avatar
pixhawk committed
111 112
}

113 114 115
void SerialLink::loadSettings()
{
    // Load defaults from settings
116
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
117
    settings.sync();
118 119
    if (settings.contains("SERIALLINK_COMM_PORT"))
    {
Bill Bonney's avatar
Bill Bonney committed
120
        m_portName = settings.value("SERIALLINK_COMM_PORT").toString();
121 122
        checkIfCDC();

Bill Bonney's avatar
Bill Bonney committed
123 124 125 126 127
        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();
128 129 130 131 132 133
    }
}

void SerialLink::writeSettings()
{
    // Store settings
134
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
135
    settings.setValue("SERIALLINK_COMM_PORT", getPortName());
136 137
    settings.setValue("SERIALLINK_COMM_BAUD", getBaudRateType());
    settings.setValue("SERIALLINK_COMM_PARITY", getParityType());
138 139 140
    settings.setValue("SERIALLINK_COMM_STOPBITS", getStopBits());
    settings.setValue("SERIALLINK_COMM_DATABITS", getDataBits());
    settings.setValue("SERIALLINK_COMM_FLOW_CONTROL", getFlowType());
141 142 143
    settings.sync();
}

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


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

pixhawk's avatar
pixhawk committed
184
    // Initialize the connection
185
    if (!hardwareConnect(type)) {
186
        //Need to error out here.
187 188 189 190 191 192
        QString err("Could not create port.");
        if (m_port) {
            err = m_port->errorString();
        }
        emit communicationError(getName(),"Error connecting: " + err);
//        disconnect(); // This tidies up and sends the necessary signals
193
        return;
194
    }
195
    qDebug() << "connected";
pixhawk's avatar
pixhawk committed
196 197

    // Qt way to make clear what a while(1) loop does
198 199
    qint64 msecs = QDateTime::currentMSecsSinceEpoch();
    qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch();
200
    quint64 bytes = 0;
201 202
//    bool triedreset = false;
//    bool triedDTR = false;
203
    qint64 timeout = 5000;
204
    int linkErrorCount = 0;
205

206
    forever {
207
        {
208
            QMutexLocker locker(&this->m_stoppMutex);
209 210 211 212
            if(m_stopp) {
                m_stopp = false;
                break; // exit the thread
            }
213

214 215 216 217 218 219 220
            if (m_reqReset) {
                m_reqReset = false;
                emit communicationUpdate(getName(),"Reset requested via DTR signal");
                m_port->setDataTerminalReady(true);
                msleep(250);
                m_port->setDataTerminalReady(false);
            }
221
        }
222

223
        // If there are too many errors on this link, disconnect.
Lorenz Meier's avatar
Lorenz Meier committed
224
        if (isConnected() && (linkErrorCount > 1000)) {
225
            qDebug() << "linkErrorCount too high: disconnecting!";
226
            linkErrorCount = 0;
227
            emit communicationUpdate(getName(), tr("Disconnecting on too many link errors"));
228 229 230
            disconnect();
        }

231
        // Write all our buffered data out the serial port.
232
        if (m_transmitBuffer.count() > 0) {
233
            m_writeMutex.lock();
234
            int numWritten = m_port->write(m_transmitBuffer);
235
            bool txSuccess = m_port->waitForBytesWritten(5);
236
            if (!txSuccess || (numWritten != m_transmitBuffer.count())) {
237 238
                linkErrorCount++;
                qDebug() << "TX Error! wrote" << numWritten << ", asked for " << m_transmitBuffer.count() << "bytes";
239 240
            }
            else {
241 242

                // Since we were successful, reset out error counter.
243 244
                linkErrorCount = 0;
            }
245 246 247 248 249 250 251

            // 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.
252 253
            QMutexLocker dataRateLocker(&dataRateMutex);
            logDataRateToBuffer(outDataWriteAmounts, outDataWriteTimes, &outDataIndex, numWritten, QDateTime::currentMSecsSinceEpoch());
254 255
        }

256 257
        //wait n msecs for data to be ready
        //[TODO][BB] lower to SerialLink::poll_interval?
258
        m_dataMutex.lock();
259
        bool success = m_port->waitForReadyRead(10);
260

261
        if (success) {
262 263 264
            QByteArray readData = m_port->readAll();
            while (m_port->waitForReadyRead(10))
                readData += m_port->readAll();
265
            m_dataMutex.unlock();
266 267 268
            if (readData.length() > 0) {
                emit bytesReceived(this, readData);

269
                // Log this data reception for this timestep
270 271
                QMutexLocker dataRateLocker(&dataRateMutex);
                logDataRateToBuffer(inDataWriteAmounts, inDataWriteTimes, &inDataIndex, readData.length(), QDateTime::currentMSecsSinceEpoch());
272 273

                // Track the total amount of data read.
274
                m_bytesRead += readData.length();
275
                linkErrorCount = 0;
276
            }
277 278
        }
        else {
279
            m_dataMutex.unlock();
280
            linkErrorCount++;
281
        }
282

283
        if (bytes != m_bytesRead) { // i.e things are good and data is being read.
284
            bytes = m_bytesRead;
285 286
            msecs = QDateTime::currentMSecsSinceEpoch();
        }
287 288
        else {
            if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) {
289 290
                //It's been 10 seconds since the last data came in. Reset and try again
                msecs = QDateTime::currentMSecsSinceEpoch();
291
                if (msecs - initialmsecs > 25000) {
292 293 294 295 296 297 298
                    //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;
                }
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
//                if (!triedDTR && triedreset) {
//                    triedDTR = true;
//                    emit communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal");
//                    qDebug() << "No data!!! Attempting reset via DTR.";
//                    m_port->setDataTerminalReady(true);
//                    msleep(250);
//                    m_port->setDataTerminalReady(false);
//                }
//                else if (!triedreset) {
//                    qDebug() << "No data!!! Attempting reset via reboot command.";
//                    emit communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command");
//                    m_port->write("reboot\r\n",8);
//                    triedreset = true;
//                }
//                else {
//                    emit communicationUpdate(getName(),"No data to receive on COM port....");
//                    qDebug() << "No data!!!";
//                }
317 318
            }
        }
319 320
        //MG::SLEEP::msleep(SerialLink::poll_interval);
        QGC::SLEEP::msleep(2);
321 322 323 324 325 326 327
    } // end of forever
    
    if (m_port) { // [TODO][BB] Not sure we need to close the port here
        qDebug() << "Closing Port #"<< __LINE__ << m_port->portName();
        m_port->close();
        delete m_port;
        m_port = NULL;
pixhawk's avatar
pixhawk committed
328

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

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

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

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

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

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


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

/**
 * @brief Disconnect the connection.
 *
 * @return True if connection has been disconnected, false if connection couldn't be disconnected.
 **/
395 396
bool SerialLink::disconnect()
{
397 398 399
    qDebug() << "disconnect";
    if (m_port)
        qDebug() << m_port->portName();
Bill Bonney's avatar
Bill Bonney committed
400 401

    if (isRunning())
402 403
    {
        {
Bill Bonney's avatar
Bill Bonney committed
404 405
            QMutexLocker locker(&m_stoppMutex);
            m_stopp = true;
406
        }
Bill Bonney's avatar
Bill Bonney committed
407
        wait(); // This will terminate the thread and close the serial port
pixhawk's avatar
pixhawk committed
408

Bill Bonney's avatar
Bill Bonney committed
409
        emit disconnected(); // [TODO] There are signals from QSerialPort we should use
410 411 412
        emit connected(false);
        return true;
    }
pixhawk's avatar
pixhawk committed
413

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

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

/**
 * @brief Connect the connection.
 *
 * @return True if connection has been established, false if connection couldn't be established.
 **/
bool SerialLink::connect()
426
{   
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 457 458 459 460
    qDebug() << "SerialLink: hardwareConnect to " << m_portName;
    m_port = new QSerialPort(m_portName);

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

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

467
    checkIfCDC();
pixhawk's avatar
pixhawk committed
468

469 470 471 472 473 474 475 476
    //    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
    }

477 478 479 480 481 482 483 484 485 486 487
    // 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));
    }

488 489
    emit communicationUpdate(getName(),"Opened port!");

Bill Bonney's avatar
Bill Bonney committed
490 491
    emit connected();
    emit connected(true);
492

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

496 497
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
498
    return true; // successful connection
pixhawk's avatar
pixhawk committed
499
}
500

501
void SerialLink::linkError(QSerialPort::SerialPortError error)
502
{
503
    if (error != QSerialPort::NoError) {
504 505 506 507 508
        // 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;
509
    }
510 511
}

512

pixhawk's avatar
pixhawk committed
513 514 515 516 517
/**
 * @brief Check if connection is active.
 *
 * @return True if link is connected, false otherwise.
 **/
518
bool SerialLink::isConnected() const
519
{
Bill Bonney's avatar
Bill Bonney committed
520 521 522

    if (m_port) {
        bool isConnected = m_port->isOpen();
523 524
//        qDebug() << "SerialLink #" << __LINE__ << ":"<<  m_port->portName()
//                 << " isConnected =" << QString::number(isConnected);
Bill Bonney's avatar
Bill Bonney committed
525
        return isConnected;
526
    } else {
527 528
//        qDebug() << "SerialLink #" << __LINE__ << ":" <<  m_portName
//                 << " isConnected = NULL";
lm's avatar
lm committed
529 530
        return false;
    }
pixhawk's avatar
pixhawk committed
531 532
}

533
int SerialLink::getId() const
pixhawk's avatar
pixhawk committed
534
{
Bill Bonney's avatar
Bill Bonney committed
535
    return m_id;
pixhawk's avatar
pixhawk committed
536 537
}

538
QString SerialLink::getName() const
pixhawk's avatar
pixhawk committed
539
{
540
    return m_portName;
pixhawk's avatar
pixhawk committed
541 542
}

543 544 545 546
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
547
qint64 SerialLink::getConnectionSpeed() const
548
{
Bill Bonney's avatar
Bill Bonney committed
549
    int baudRate;
550
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
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 580 581 582 583 584 585 586
        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
587 588 589 590
    }
    return dataRate;
}

591
QString SerialLink::getPortName() const
592
{
Bill Bonney's avatar
Bill Bonney committed
593
    return m_portName;
pixhawk's avatar
pixhawk committed
594 595
}

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

598
int SerialLink::getBaudRate() const
599
{
600
    return getConnectionSpeed();
pixhawk's avatar
pixhawk committed
601 602
}

603
int SerialLink::getBaudRateType() const
604
{
Bill Bonney's avatar
Bill Bonney committed
605
    int baudRate;
606
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
607 608 609 610 611
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    return baudRate;
pixhawk's avatar
pixhawk committed
612 613
}

614
int SerialLink::getFlowType() const
615
{
616

Bill Bonney's avatar
Bill Bonney committed
617
    int flowControl;
618
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
619 620 621 622 623
        flowControl = m_port->flowControl();
    } else {
        flowControl = m_flowControl;
    }
    return flowControl;
pixhawk's avatar
pixhawk committed
624 625
}

626
int SerialLink::getParityType() const
627
{
628

Bill Bonney's avatar
Bill Bonney committed
629
    int parity;
630
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
631 632 633 634 635
        parity = m_port->parity();
    } else {
        parity = m_parity;
    }
    return parity;
pixhawk's avatar
pixhawk committed
636 637
}

638
int SerialLink::getDataBitsType() const
639
{
640

Bill Bonney's avatar
Bill Bonney committed
641
    int dataBits;
642
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
643 644 645 646 647
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }
    return dataBits;
pixhawk's avatar
pixhawk committed
648 649
}

650
int SerialLink::getStopBitsType() const
651
{
652

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

662
int SerialLink::getDataBits() const
663
{
664

Bill Bonney's avatar
Bill Bonney committed
665 666
    int ret;
    int dataBits;
667
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
668 669 670 671 672 673 674
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }

    switch (dataBits) {
    case QSerialPort::Data5:
675 676
        ret = 5;
        break;
Bill Bonney's avatar
Bill Bonney committed
677
    case QSerialPort::Data6:
678 679
        ret = 6;
        break;
Bill Bonney's avatar
Bill Bonney committed
680
    case QSerialPort::Data7:
681 682
        ret = 7;
        break;
Bill Bonney's avatar
Bill Bonney committed
683
    case QSerialPort::Data8:
684 685 686
        ret = 8;
        break;
    default:
687
        ret = -1;
688 689 690 691 692
        break;
    }
    return ret;
}

693
int SerialLink::getStopBits() const
694
{
695

Bill Bonney's avatar
Bill Bonney committed
696
    int stopBits;
697
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
698 699 700 701
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
702
    int ret = -1;
Bill Bonney's avatar
Bill Bonney committed
703 704
    switch (stopBits) {
    case QSerialPort::OneStop:
705 706
        ret = 1;
        break;
Bill Bonney's avatar
Bill Bonney committed
707
    case QSerialPort::TwoStop:
708 709 710 711 712 713
        ret = 2;
        break;
    default:
        ret = -1;
        break;
    }
714 715 716
    return ret;
}

pixhawk's avatar
pixhawk committed
717 718
bool SerialLink::setPortName(QString portName)
{
Bill Bonney's avatar
Bill Bonney committed
719 720
    qDebug() << "current portName " << m_portName;
    qDebug() << "setPortName to " << portName;
721
    bool accepted = true;
Bill Bonney's avatar
Bill Bonney committed
722 723 724
    if ((portName != m_portName)
            && (portName.trimmed().length() > 0)) {
        m_portName = portName.trimmed();
725 726 727

        checkIfCDC();

Bill Bonney's avatar
Bill Bonney committed
728 729
        if(m_port)
            m_port->setPortName(portName);
730

731
        emit nameChanged(m_portName); // [TODO] maybe we can eliminate this
732
        emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
733
        return accepted;
pixhawk's avatar
pixhawk committed
734
    }
Bill Bonney's avatar
Bill Bonney committed
735
    return false;
pixhawk's avatar
pixhawk committed
736 737 738 739 740
}


bool SerialLink::setBaudRateType(int rateIndex)
{
741

742
  // These minimum and maximum baud rates were based on those enumerated in qserialport.h
743
    bool result;
Bill Bonney's avatar
Bill Bonney committed
744 745
    const int minBaud = (int)QSerialPort::Baud1200;
    const int maxBaud = (int)QSerialPort::Baud115200;
746

747
    if ((rateIndex >= minBaud && rateIndex <= maxBaud))
748
    {
749 750 751 752 753 754 755 756 757 758
        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
759 760
    }

761
    return result;
pixhawk's avatar
pixhawk committed
762 763
}

764 765 766 767 768 769 770
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
771 772 773

bool SerialLink::setBaudRate(int rate)
{
774

Bill Bonney's avatar
Bill Bonney committed
775 776 777 778
    bool accepted = false;
    if (rate != m_baud) {
        m_baud = rate;
        accepted = true;
779
        if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
780
            accepted = m_port->setBaudRate(rate);
781
        }
782
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
783
    }
784
    return accepted;
pixhawk's avatar
pixhawk committed
785 786
}

787 788
bool SerialLink::setFlowType(int flow)
{
789

Bill Bonney's avatar
Bill Bonney committed
790 791 792 793
    bool accepted = false;
    if (flow != m_flowControl) {
        m_flowControl = static_cast<QSerialPort::FlowControl>(flow);
        accepted = true;
794
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
795
            accepted = m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(flow));
796
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
797 798 799 800
    }
    return accepted;
}

801 802
bool SerialLink::setParityType(int parity)
{
803

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

833

834
bool SerialLink::setDataBits(int dataBits)
835
{
836 837

    qDebug("SET DATA BITS");
Bill Bonney's avatar
Bill Bonney committed
838 839 840 841
    bool accepted = false;
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
        accepted = true;
842
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
843
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
844
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
845 846 847 848
    }
    return accepted;
}

849
bool SerialLink::setStopBits(int stopBits)
850
{
851

Bill Bonney's avatar
Bill Bonney committed
852 853 854 855 856
    // Note 3 is OneAndAHalf stopbits.
    bool accepted = false;
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
        accepted = true;
857
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
858
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
859
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
860 861 862
    }
    return accepted;
}
863 864 865

bool SerialLink::setDataBitsType(int dataBits)
{
866

867
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
868 869
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
870
        accepted = true;
871
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
872
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
873
        emit updateLink(this);
874 875 876 877 878 879
    }
    return accepted;
}

bool SerialLink::setStopBitsType(int stopBits)
{
880

881
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
882 883
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
884
        accepted = true;
885
        if (m_port && !m_is_cdc)
Bill Bonney's avatar
Bill Bonney committed
886
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
887
        emit updateLink(this);
888 889 890
    }
    return accepted;
}