SerialLink.cc 22.9 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
    m_stopp(false),
27
    m_reqReset(false)
pixhawk's avatar
pixhawk committed
28
{
29 30
    // Get the name of the current port in use.
    m_portName = portname.trimmed();
31
    if (m_portName == "" && getCurrentPorts().size() > 0)
32
    {
33
        m_portName = m_ports.first().trimmed();
34 35
    }

pixhawk's avatar
pixhawk committed
36
    // Set unique ID and add link to the list of links
Bill Bonney's avatar
Bill Bonney committed
37 38 39
    m_id = getNextLinkId();

    m_baud = baudRate;
40

41 42
    if (hardwareFlowControl)
    {
Bill Bonney's avatar
Bill Bonney committed
43
        m_flowControl = QSerialPort::HardwareControl;
44 45 46
    }
    else
    {
Bill Bonney's avatar
Bill Bonney committed
47
        m_flowControl = QSerialPort::NoFlowControl;
48 49 50
    }
    if (parity)
    {
Bill Bonney's avatar
Bill Bonney committed
51
        m_parity = QSerialPort::EvenParity;
52 53 54
    }
    else
    {
Bill Bonney's avatar
Bill Bonney committed
55
        m_parity = QSerialPort::NoParity;
56
    }
Bill Bonney's avatar
Bill Bonney committed
57 58 59

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

lm's avatar
lm committed
61
    loadSettings();
Lorenz Meier's avatar
Lorenz Meier committed
62 63 64 65 66

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

67
    LinkManager::instance()->add(this);
pixhawk's avatar
pixhawk committed
68
}
69

70 71 72 73 74
void SerialLink::requestReset()
{
    QMutexLocker locker(&this->m_stoppMutex);
    m_reqReset = true;
}
pixhawk's avatar
pixhawk committed
75 76 77 78

SerialLink::~SerialLink()
{
    disconnect();
Bill Bonney's avatar
Bill Bonney committed
79 80
    if(m_port) delete m_port;
    m_port = NULL;
81 82
}

83
QList<QString> SerialLink::getCurrentPorts()
84
{
85
    m_ports.clear();
86

87
    QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();
88

89 90
    if( portList.count() == 0){
        qDebug() << "No Ports Found" << m_ports;
91 92
    }

93
    foreach (const QSerialPortInfo &info, portList)
94
    {
Bill Bonney's avatar
Bill Bonney committed
95 96 97
//        qDebug() << "PortName    : " << info.portName()
//                 << "Description : " << info.description();
//        qDebug() << "Manufacturer: " << info.manufacturer();
98

99
        m_ports.append(info.portName());
100
    }
Bill Bonney's avatar
Bill Bonney committed
101
    return m_ports;
pixhawk's avatar
pixhawk committed
102 103
}

104 105 106
void SerialLink::loadSettings()
{
    // Load defaults from settings
107
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
108
    settings.sync();
109 110
    if (settings.contains("SERIALLINK_COMM_PORT"))
    {
Bill Bonney's avatar
Bill Bonney committed
111 112 113 114 115 116
        m_portName = settings.value("SERIALLINK_COMM_PORT").toString();
        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();
117 118 119 120 121 122
    }
}

void SerialLink::writeSettings()
{
    // Store settings
123
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
124
    settings.setValue("SERIALLINK_COMM_PORT", getPortName());
125 126
    settings.setValue("SERIALLINK_COMM_BAUD", getBaudRateType());
    settings.setValue("SERIALLINK_COMM_PARITY", getParityType());
127 128 129
    settings.setValue("SERIALLINK_COMM_STOPBITS", getStopBits());
    settings.setValue("SERIALLINK_COMM_DATABITS", getDataBits());
    settings.setValue("SERIALLINK_COMM_FLOW_CONTROL", getFlowType());
130 131 132
    settings.sync();
}

pixhawk's avatar
pixhawk committed
133 134 135 136 137

/**
 * @brief Runs the thread
 *
 **/
138 139
void SerialLink::run()
{
pixhawk's avatar
pixhawk committed
140
    // Initialize the connection
141
    if (!hardwareConnect()) {
142
        //Need to error out here.
143
        emit communicationError(getName(),"Error connecting: " + m_port->errorString());
144
        disconnect(); // This tidies up and sends the necessary signals
145
        emit communicationError(tr("Serial Port %1").arg(getPortName()), tr("Cannot read / write data - check physical USB and cable connections."));
146
        return;
147
    }
pixhawk's avatar
pixhawk committed
148 149

    // Qt way to make clear what a while(1) loop does
150 151
    qint64 msecs = QDateTime::currentMSecsSinceEpoch();
    qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch();
152 153 154
    quint64 bytes = 0;
    bool triedreset = false;
    bool triedDTR = false;
155
    qint64 timeout = 5000;
156
    int linkErrorCount = 0;
157

158
    forever {
159
        {
160
            QMutexLocker locker(&this->m_stoppMutex);
161 162 163 164
            if(m_stopp) {
                m_stopp = false;
                break; // exit the thread
            }
165

166 167 168 169 170 171 172
            if (m_reqReset) {
                m_reqReset = false;
                emit communicationUpdate(getName(),"Reset requested via DTR signal");
                m_port->setDataTerminalReady(true);
                msleep(250);
                m_port->setDataTerminalReady(false);
            }
173
        }
174

175
        // If there are too many errors on this link, disconnect.
Lorenz Meier's avatar
Lorenz Meier committed
176
        if (isConnected() && (linkErrorCount > 1000)) {
177
            qDebug() << "linkErrorCount too high: disconnecting!";
178
            linkErrorCount = 0;
179
            emit communicationUpdate(getName(), tr("Disconnecting on too many link errors"));
180 181 182
            disconnect();
        }

183
        // Write all our buffered data out the serial port.
184
        if (m_transmitBuffer.count() > 0) {
185
            m_writeMutex.lock();
186
            int numWritten = m_port->write(m_transmitBuffer);
187
            bool txSuccess = m_port->waitForBytesWritten(5);
188
            if (!txSuccess || (numWritten != m_transmitBuffer.count())) {
189 190
                linkErrorCount++;
                qDebug() << "TX Error! wrote" << numWritten << ", asked for " << m_transmitBuffer.count() << "bytes";
191 192
            }
            else {
193 194

                // Since we were successful, reset out error counter.
195 196
                linkErrorCount = 0;
            }
197 198 199 200 201 202 203

            // 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.
204 205
            QMutexLocker dataRateLocker(&dataRateMutex);
            logDataRateToBuffer(outDataWriteAmounts, outDataWriteTimes, &outDataIndex, numWritten, QDateTime::currentMSecsSinceEpoch());
206 207
        }

208 209
        //wait n msecs for data to be ready
        //[TODO][BB] lower to SerialLink::poll_interval?
210
        m_dataMutex.lock();
211
        bool success = m_port->waitForReadyRead(10);
212

213
        if (success) {
214 215 216
            QByteArray readData = m_port->readAll();
            while (m_port->waitForReadyRead(10))
                readData += m_port->readAll();
217
            m_dataMutex.unlock();
218 219 220
            if (readData.length() > 0) {
                emit bytesReceived(this, readData);

221
                // Log this data reception for this timestep
222 223
                QMutexLocker dataRateLocker(&dataRateMutex);
                logDataRateToBuffer(inDataWriteAmounts, inDataWriteTimes, &inDataIndex, readData.length(), QDateTime::currentMSecsSinceEpoch());
224 225

                // Track the total amount of data read.
226
                m_bytesRead += readData.length();
227
                linkErrorCount = 0;
228
            }
229 230
        }
        else {
231
            m_dataMutex.unlock();
232
            linkErrorCount++;
233
        }
234

235
        if (bytes != m_bytesRead) { // i.e things are good and data is being read.
236
            bytes = m_bytesRead;
237 238
            msecs = QDateTime::currentMSecsSinceEpoch();
        }
239 240
        else {
            if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) {
241 242
                //It's been 10 seconds since the last data came in. Reset and try again
                msecs = QDateTime::currentMSecsSinceEpoch();
243
                if (msecs - initialmsecs > 25000) {
244 245 246 247 248 249 250
                    //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;
                }
251
                if (!triedDTR && triedreset) {
252
                    triedDTR = true;
253
                    emit communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal");
254
                    qDebug() << "No data!!! Attempting reset via DTR.";
255 256 257
                    m_port->setDataTerminalReady(true);
                    msleep(250);
                    m_port->setDataTerminalReady(false);
258
                }
259
                else if (!triedreset) {
260
                    qDebug() << "No data!!! Attempting reset via reboot command.";
261
                    emit communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command");
262
                    m_port->write("reboot\r\n",8);
263 264
                    triedreset = true;
                }
265 266
                else {
                    emit communicationUpdate(getName(),"No data to receive on COM port....");
267 268 269 270
                    qDebug() << "No data!!!";
                }
            }
        }
pixhawk's avatar
pixhawk committed
271
        MG::SLEEP::msleep(SerialLink::poll_interval);
272 273 274 275 276 277 278
    } // 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
279

280 281
        emit disconnected();
        emit connected(false);
282
    }
pixhawk's avatar
pixhawk committed
283 284
}

285 286
void SerialLink::writeBytes(const char* data, qint64 size)
{
Bill Bonney's avatar
Bill Bonney committed
287
    if(m_port && m_port->isOpen()) {
pixhawk's avatar
pixhawk committed
288

289
        QByteArray byteArray(data, size);
290 291 292
        m_writeMutex.lock();
        m_transmitBuffer.append(byteArray);
        m_writeMutex.unlock();
293 294 295 296
    } else {
        disconnect();
        // Error occured
        emit communicationError(getName(), tr("Could not send data - link %1 is disconnected!").arg(getName()));
pixhawk's avatar
pixhawk committed
297 298 299 300 301 302 303 304 305
    }
}

/**
 * @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
 **/
306 307
void SerialLink::readBytes()
{
Bill Bonney's avatar
Bill Bonney committed
308
    if(m_port && m_port->isOpen()) {
309 310
        const qint64 maxLength = 2048;
        char data[maxLength];
311
        m_dataMutex.lock();
Bill Bonney's avatar
Bill Bonney committed
312
        qint64 numBytes = m_port->bytesAvailable();
313

314
        if(numBytes > 0) {
pixhawk's avatar
pixhawk committed
315 316 317
            /* Read as much data in buffer as possible without overflow */
            if(maxLength < numBytes) numBytes = maxLength;

Bill Bonney's avatar
Bill Bonney committed
318
            m_port->read(data, numBytes);
pixhawk's avatar
pixhawk committed
319 320 321
            QByteArray b(data, numBytes);
            emit bytesReceived(this, b);
        }
322
        m_dataMutex.unlock();
pixhawk's avatar
pixhawk committed
323 324 325 326 327 328 329 330 331
    }
}


/**
 * @brief Get the number of bytes to read.
 *
 * @return The number of bytes to read
 **/
332 333
qint64 SerialLink::bytesAvailable()
{
Bill Bonney's avatar
Bill Bonney committed
334 335
    if (m_port) {
        return m_port->bytesAvailable();
336
    } else {
337 338
        return 0;
    }
pixhawk's avatar
pixhawk committed
339 340 341 342 343 344 345
}

/**
 * @brief Disconnect the connection.
 *
 * @return True if connection has been disconnected, false if connection couldn't be disconnected.
 **/
346 347
bool SerialLink::disconnect()
{
348 349 350
    qDebug() << "disconnect";
    if (m_port)
        qDebug() << m_port->portName();
Bill Bonney's avatar
Bill Bonney committed
351 352

    if (isRunning())
353
    {
354
        qDebug() << "running so disconnect" << m_port->portName();
355
        {
Bill Bonney's avatar
Bill Bonney committed
356 357
            QMutexLocker locker(&m_stoppMutex);
            m_stopp = true;
358
        }
Bill Bonney's avatar
Bill Bonney committed
359
        wait(); // This will terminate the thread and close the serial port
pixhawk's avatar
pixhawk committed
360

Bill Bonney's avatar
Bill Bonney committed
361
        emit disconnected(); // [TODO] There are signals from QSerialPort we should use
362 363 364
        emit connected(false);
        return true;
    }
pixhawk's avatar
pixhawk committed
365

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

368 369
    qDebug() << "already disconnected";
    return true;
pixhawk's avatar
pixhawk committed
370 371 372 373 374 375 376 377
}

/**
 * @brief Connect the connection.
 *
 * @return True if connection has been established, false if connection couldn't be established.
 **/
bool SerialLink::connect()
378
{   
Bill Bonney's avatar
Bill Bonney committed
379 380
    if (isRunning())
        disconnect();
381 382
    {
        QMutexLocker locker(&this->m_stoppMutex);
Bill Bonney's avatar
Bill Bonney committed
383
        m_stopp = false;
384
    }
Bill Bonney's avatar
Bill Bonney committed
385 386

    start(LowPriority);
387
    return true;
pixhawk's avatar
pixhawk committed
388 389 390 391 392 393 394 395 396 397
}

/**
 * @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.
 **/
398 399
bool SerialLink::hardwareConnect()
{
400
    if(m_port) {
Bill Bonney's avatar
Bill Bonney committed
401 402 403 404
        qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port";
        m_port->close();
        delete m_port;
        m_port = NULL;
405
    }
Bill Bonney's avatar
Bill Bonney committed
406 407
    qDebug() << "SerialLink: hardwareConnect to " << m_portName;
    m_port = new QSerialPort(m_portName);
pixhawk's avatar
pixhawk committed
408

409
    if (m_port == NULL) {
Bill Bonney's avatar
Bill Bonney committed
410 411
        emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
        return false; // couldn't create serial port.
412
    }
Bill Bonney's avatar
Bill Bonney committed
413 414

    QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected()));
415
    QObject::connect(m_port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(linkError(QSerialPort::SerialPortError)));
Bill Bonney's avatar
Bill Bonney committed
416 417 418

//    port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead);

419
    if (!m_port->open(QIODevice::ReadWrite)) {
Bill Bonney's avatar
Bill Bonney committed
420 421 422
        emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
        m_port->close();
        return false; // couldn't open serial port
423
    }
424

Bill Bonney's avatar
Bill Bonney committed
425
    emit communicationUpdate(getName(),"Opened port!");
pixhawk's avatar
pixhawk committed
426

Bill Bonney's avatar
Bill Bonney committed
427 428 429 430 431 432
    // Need to configure the 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));
pixhawk's avatar
pixhawk committed
433

Bill Bonney's avatar
Bill Bonney committed
434 435
    emit connected();
    emit connected(true);
436

Bill Bonney's avatar
Bill Bonney committed
437 438
    qDebug() << "CONNECTING LINK: " << __FILE__ << __LINE__ << "with settings" << m_port->portName()
             << getBaudRate() << getDataBits() << getParityType() << getStopBits();
439

440 441
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
442
    return true; // successful connection
pixhawk's avatar
pixhawk committed
443
}
444

445
void SerialLink::linkError(QSerialPort::SerialPortError error)
446
{
447
    if (error != QSerialPort::NoError) {
448 449 450 451 452
        // 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;
453
    }
454 455
}

456

pixhawk's avatar
pixhawk committed
457 458 459 460 461
/**
 * @brief Check if connection is active.
 *
 * @return True if link is connected, false otherwise.
 **/
462
bool SerialLink::isConnected() const
463
{
Bill Bonney's avatar
Bill Bonney committed
464 465 466

    if (m_port) {
        bool isConnected = m_port->isOpen();
467 468
//        qDebug() << "SerialLink #" << __LINE__ << ":"<<  m_port->portName()
//                 << " isConnected =" << QString::number(isConnected);
Bill Bonney's avatar
Bill Bonney committed
469
        return isConnected;
470
    } else {
471 472
//        qDebug() << "SerialLink #" << __LINE__ << ":" <<  m_portName
//                 << " isConnected = NULL";
lm's avatar
lm committed
473 474
        return false;
    }
pixhawk's avatar
pixhawk committed
475 476
}

477
int SerialLink::getId() const
pixhawk's avatar
pixhawk committed
478
{
Bill Bonney's avatar
Bill Bonney committed
479
    return m_id;
pixhawk's avatar
pixhawk committed
480 481
}

482
QString SerialLink::getName() const
pixhawk's avatar
pixhawk committed
483
{
484
    return m_portName;
pixhawk's avatar
pixhawk committed
485 486
}

487 488 489 490
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
491
qint64 SerialLink::getConnectionSpeed() const
492
{
Bill Bonney's avatar
Bill Bonney committed
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    int baudRate;
    if (m_port) {
        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
531 532 533 534
    }
    return dataRate;
}

535
QString SerialLink::getPortName() const
536
{
Bill Bonney's avatar
Bill Bonney committed
537
    return m_portName;
pixhawk's avatar
pixhawk committed
538 539
}

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

542
int SerialLink::getBaudRate() const
543
{
544
    return getConnectionSpeed();
pixhawk's avatar
pixhawk committed
545 546
}

547
int SerialLink::getBaudRateType() const
548
{
Bill Bonney's avatar
Bill Bonney committed
549 550 551 552 553 554 555
    int baudRate;
    if (m_port) {
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    return baudRate;
pixhawk's avatar
pixhawk committed
556 557
}

558
int SerialLink::getFlowType() const
559
{
Bill Bonney's avatar
Bill Bonney committed
560 561 562 563 564 565 566
    int flowControl;
    if (m_port) {
        flowControl = m_port->flowControl();
    } else {
        flowControl = m_flowControl;
    }
    return flowControl;
pixhawk's avatar
pixhawk committed
567 568
}

569
int SerialLink::getParityType() const
570
{
Bill Bonney's avatar
Bill Bonney committed
571 572 573 574 575 576 577
    int parity;
    if (m_port) {
        parity = m_port->parity();
    } else {
        parity = m_parity;
    }
    return parity;
pixhawk's avatar
pixhawk committed
578 579
}

580
int SerialLink::getDataBitsType() const
581
{
Bill Bonney's avatar
Bill Bonney committed
582 583 584 585 586 587 588
    int dataBits;
    if (m_port) {
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }
    return dataBits;
pixhawk's avatar
pixhawk committed
589 590
}

591
int SerialLink::getStopBitsType() const
592
{
Bill Bonney's avatar
Bill Bonney committed
593 594 595 596 597 598 599
    int stopBits;
    if (m_port) {
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
    return stopBits;
pixhawk's avatar
pixhawk committed
600 601
}

602
int SerialLink::getDataBits() const
603
{
Bill Bonney's avatar
Bill Bonney committed
604 605 606 607 608 609 610 611 612 613
    int ret;
    int dataBits;
    if (m_port) {
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }

    switch (dataBits) {
    case QSerialPort::Data5:
614 615
        ret = 5;
        break;
Bill Bonney's avatar
Bill Bonney committed
616
    case QSerialPort::Data6:
617 618
        ret = 6;
        break;
Bill Bonney's avatar
Bill Bonney committed
619
    case QSerialPort::Data7:
620 621
        ret = 7;
        break;
Bill Bonney's avatar
Bill Bonney committed
622
    case QSerialPort::Data8:
623 624 625
        ret = 8;
        break;
    default:
626
        ret = -1;
627 628 629 630 631
        break;
    }
    return ret;
}

632
int SerialLink::getStopBits() const
633
{
Bill Bonney's avatar
Bill Bonney committed
634 635 636 637 638 639
    int stopBits;
    if (m_port) {
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
640
    int ret = -1;
Bill Bonney's avatar
Bill Bonney committed
641 642
    switch (stopBits) {
    case QSerialPort::OneStop:
643 644
        ret = 1;
        break;
Bill Bonney's avatar
Bill Bonney committed
645
    case QSerialPort::TwoStop:
646 647 648 649 650 651
        ret = 2;
        break;
    default:
        ret = -1;
        break;
    }
652 653 654
    return ret;
}

pixhawk's avatar
pixhawk committed
655 656
bool SerialLink::setPortName(QString portName)
{
Bill Bonney's avatar
Bill Bonney committed
657 658 659 660 661 662 663 664
    qDebug() << "current portName " << m_portName;
    qDebug() << "setPortName to " << portName;
    bool accepted = false;
    if ((portName != m_portName)
            && (portName.trimmed().length() > 0)) {
        m_portName = portName.trimmed();
        if(m_port)
            m_port->setPortName(portName);
665

666
        emit nameChanged(m_portName); // [TODO] maybe we can eliminate this
667
        emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
668
        return accepted;
pixhawk's avatar
pixhawk committed
669
    }
Bill Bonney's avatar
Bill Bonney committed
670
    return false;
pixhawk's avatar
pixhawk committed
671 672 673 674 675
}


bool SerialLink::setBaudRateType(int rateIndex)
{
Bill Bonney's avatar
Bill Bonney committed
676 677
    Q_ASSERT_X(m_port != NULL, "setBaudRateType", "m_port is NULL");
    // These minimum and maximum baud rates were based on those enumerated in qserialport.h
678
    bool result;
Bill Bonney's avatar
Bill Bonney committed
679 680
    const int minBaud = (int)QSerialPort::Baud1200;
    const int maxBaud = (int)QSerialPort::Baud115200;
681

Bill Bonney's avatar
Bill Bonney committed
682
    if (m_port && (rateIndex >= minBaud && rateIndex <= maxBaud))
683
    {
684 685 686
        result = m_port->setBaudRate(static_cast<QSerialPort::BaudRate>(rateIndex));
        emit updateLink(this);
        return result;
pixhawk's avatar
pixhawk committed
687 688
    }

Bill Bonney's avatar
Bill Bonney committed
689
    return false;
pixhawk's avatar
pixhawk committed
690 691
}

692 693 694 695 696 697 698
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
699 700 701

bool SerialLink::setBaudRate(int rate)
{
Bill Bonney's avatar
Bill Bonney committed
702 703 704 705 706 707
    bool accepted = false;
    if (rate != m_baud) {
        m_baud = rate;
        accepted = true;
        if (m_port)
            accepted = m_port->setBaudRate(rate);
708
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
709
    }
710
    return accepted;
pixhawk's avatar
pixhawk committed
711 712
}

713 714
bool SerialLink::setFlowType(int flow)
{
Bill Bonney's avatar
Bill Bonney committed
715 716 717 718 719 720
    bool accepted = false;
    if (flow != m_flowControl) {
        m_flowControl = static_cast<QSerialPort::FlowControl>(flow);
        accepted = true;
        if (m_port)
            accepted = m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(flow));
721
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
722 723 724 725
    }
    return accepted;
}

726 727
bool SerialLink::setParityType(int parity)
{
Bill Bonney's avatar
Bill Bonney committed
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
    bool accepted = false;
    if (parity != m_parity) {
        m_parity = static_cast<QSerialPort::Parity>(parity);
        accepted = true;
        if (m_port) {
            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;
                }
751
            emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
752
        }
pixhawk's avatar
pixhawk committed
753 754 755 756
    }
    return accepted;
}

757

758
bool SerialLink::setDataBits(int dataBits)
759
{
Bill Bonney's avatar
Bill Bonney committed
760 761 762 763 764 765
    bool accepted = false;
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
        accepted = true;
        if (m_port)
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
766
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
767 768 769 770
    }
    return accepted;
}

771
bool SerialLink::setStopBits(int stopBits)
772
{
Bill Bonney's avatar
Bill Bonney committed
773 774 775 776 777 778 779
    // Note 3 is OneAndAHalf stopbits.
    bool accepted = false;
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
        accepted = true;
        if (m_port)
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
780
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
781 782 783
    }
    return accepted;
}
784 785 786 787

bool SerialLink::setDataBitsType(int dataBits)
{
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
788 789
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
790
        accepted = true;
Bill Bonney's avatar
Bill Bonney committed
791 792
        if (m_port)
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
793
        emit updateLink(this);
794 795 796 797 798 799 800
    }
    return accepted;
}

bool SerialLink::setStopBitsType(int stopBits)
{
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
801 802
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
803
        accepted = true;
Bill Bonney's avatar
Bill Bonney committed
804 805
        if (m_port)
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
806
        emit updateLink(this);
807 808 809
    }
    return accepted;
}