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


24 25
SerialLink::SerialLink(QString portname, int baudRate, bool hardwareFlowControl, bool parity,
                       int dataBits, int stopBits) :
Bill Bonney's avatar
Bill Bonney committed
26 27
    m_bytesRead(0),
    m_port(NULL),
28
    m_stopp(false),
29
    m_reqReset(false)
pixhawk's avatar
pixhawk committed
30 31
{
    // Setup settings
Bill Bonney's avatar
Bill Bonney committed
32
    m_portName = portname.trimmed();
33

34
    if (m_portName == "" && getCurrentPorts().size() > 0)
35
    {
36
        m_portName = m_ports.first().trimmed();
37 38
    }

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

    m_baud = baudRate;
43

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

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

lm's avatar
lm committed
64
    loadSettings();
Lorenz Meier's avatar
Lorenz Meier committed
65 66 67 68 69

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

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

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

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

89
    QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();
90

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

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

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

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

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

pixhawk's avatar
pixhawk committed
135 136 137 138 139

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

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

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

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

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

        if (m_transmitBuffer.count() > 0) {
185 186
            QMutexLocker writeLocker(&m_writeMutex);
            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
                linkErrorCount = 0;
            }
195
            m_transmitBuffer =  m_transmitBuffer.remove(0, numWritten);
196 197
        }

198 199
        //wait n msecs for data to be ready
        //[TODO][BB] lower to SerialLink::poll_interval?
200
        bool success = m_port->waitForReadyRead(10);
201

202
        if (success) {
203 204 205 206 207 208 209 210
            QByteArray readData = m_port->readAll();
            while (m_port->waitForReadyRead(10))
                readData += m_port->readAll();
            if (readData.length() > 0) {
                emit bytesReceived(this, readData);
//                qDebug() << "rx of length " << QString::number(readData.length());

                m_bytesRead += readData.length();
211
                linkErrorCount = 0;
212
            }
213 214
        }
        else {
215
            linkErrorCount++;
tstellanova's avatar
tstellanova committed
216
            //qDebug() << "Wait read response timeout" << QTime::currentTime().toString();
217
        }
218

219
        if (bytes != m_bytesRead) { // i.e things are good and data is being read.
220
            bytes = m_bytesRead;
221 222
            msecs = QDateTime::currentMSecsSinceEpoch();
        }
223 224
        else {
            if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) {
225 226
                //It's been 10 seconds since the last data came in. Reset and try again
                msecs = QDateTime::currentMSecsSinceEpoch();
227
                if (msecs - initialmsecs > 25000) {
228 229 230 231 232 233 234
                    //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;
                }
235
                if (!triedDTR && triedreset) {
236
                    triedDTR = true;
237
                    emit communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal");
238
                    qDebug() << "No data!!! Attempting reset via DTR.";
239 240 241
                    m_port->setDataTerminalReady(true);
                    msleep(250);
                    m_port->setDataTerminalReady(false);
242
                }
243
                else if (!triedreset) {
244
                    qDebug() << "No data!!! Attempting reset via reboot command.";
245
                    emit communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command");
246
                    m_port->write("reboot\r\n",8);
247 248
                    triedreset = true;
                }
249 250
                else {
                    emit communicationUpdate(getName(),"No data to receive on COM port....");
251 252 253 254
                    qDebug() << "No data!!!";
                }
            }
        }
pixhawk's avatar
pixhawk committed
255
        MG::SLEEP::msleep(SerialLink::poll_interval);
256 257 258 259 260 261 262
    } // 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
263

264 265
        emit disconnected();
        emit connected(false);
266
    }
pixhawk's avatar
pixhawk committed
267 268
}

269 270
void SerialLink::writeBytes(const char* data, qint64 size)
{
Bill Bonney's avatar
Bill Bonney committed
271
    if(m_port && m_port->isOpen()) {
272
//        qDebug() << "writeBytes" << m_portName << "attempting to tx " << size << "bytes.";
pixhawk's avatar
pixhawk committed
273

274
        QByteArray byteArray(data, size);
275 276 277 278
        {
            QMutexLocker writeLocker(&m_writeMutex);
            m_transmitBuffer.append(byteArray);
        }
279

280
        // Extra debug logging
281
//            qDebug() << byteArray->toHex();
282 283 284 285
    } else {
        disconnect();
        // Error occured
        emit communicationError(getName(), tr("Could not send data - link %1 is disconnected!").arg(getName()));
pixhawk's avatar
pixhawk committed
286 287 288 289 290 291 292 293 294
    }
}

/**
 * @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
 **/
295 296
void SerialLink::readBytes()
{
Bill Bonney's avatar
Bill Bonney committed
297 298
    m_dataMutex.lock();
    if(m_port && m_port->isOpen()) {
299 300
        const qint64 maxLength = 2048;
        char data[maxLength];
Bill Bonney's avatar
Bill Bonney committed
301
        qint64 numBytes = m_port->bytesAvailable();
James Goppert's avatar
James Goppert committed
302
        //qDebug() << "numBytes: " << numBytes;
303

304
        if(numBytes > 0) {
pixhawk's avatar
pixhawk committed
305 306 307
            /* Read as much data in buffer as possible without overflow */
            if(maxLength < numBytes) numBytes = maxLength;

Bill Bonney's avatar
Bill Bonney committed
308
            m_port->read(data, numBytes);
pixhawk's avatar
pixhawk committed
309 310 311 312 313 314 315 316 317 318 319 320 321
            QByteArray b(data, numBytes);
            emit bytesReceived(this, b);

            //qDebug() << "SerialLink::readBytes()" << std::hex << data;
            //            int i;
            //            for (i=0; i<numBytes; i++){
            //                unsigned int v=data[i];
            //
            //                fprintf(stderr,"%02x ", v);
            //            }
            //            fprintf(stderr,"\n");
        }
    }
Bill Bonney's avatar
Bill Bonney committed
322
    m_dataMutex.unlock();
pixhawk's avatar
pixhawk committed
323 324 325 326 327 328 329 330
}


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

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

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

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

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

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

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

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

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

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

    QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected()));
414 415
    QObject::connect(m_port, SIGNAL(error(SerialLinkPortError_t)),
                     this, SLOT(linkError(SerialLinkPortError_t)));
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(SerialLinkPortError_t error)
446 447 448 449
{
    qDebug() << error;
}

450

pixhawk's avatar
pixhawk committed
451 452 453 454 455
/**
 * @brief Check if connection is active.
 *
 * @return True if link is connected, false otherwise.
 **/
456
bool SerialLink::isConnected() const
457
{
Bill Bonney's avatar
Bill Bonney committed
458 459 460

    if (m_port) {
        bool isConnected = m_port->isOpen();
461 462
//        qDebug() << "SerialLink #" << __LINE__ << ":"<<  m_port->portName()
//                 << " isConnected =" << QString::number(isConnected);
Bill Bonney's avatar
Bill Bonney committed
463
        return isConnected;
464
    } else {
465 466
//        qDebug() << "SerialLink #" << __LINE__ << ":" <<  m_portName
//                 << " isConnected = NULL";
lm's avatar
lm committed
467 468
        return false;
    }
pixhawk's avatar
pixhawk committed
469 470
}

471
int SerialLink::getId() const
pixhawk's avatar
pixhawk committed
472
{
Bill Bonney's avatar
Bill Bonney committed
473
    return m_id;
pixhawk's avatar
pixhawk committed
474 475
}

476
QString SerialLink::getName() const
pixhawk's avatar
pixhawk committed
477
{
478
    return m_portName;
pixhawk's avatar
pixhawk committed
479 480
}

481 482 483 484
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
485
qint64 SerialLink::getNominalDataRate() const
486
{
Bill Bonney's avatar
Bill Bonney committed
487 488 489 490 491 492 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
    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
525 526 527 528
    }
    return dataRate;
}

529
QString SerialLink::getPortName() const
530
{
Bill Bonney's avatar
Bill Bonney committed
531
    return m_portName;
pixhawk's avatar
pixhawk committed
532 533
}

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

536
int SerialLink::getBaudRate() const
537
{
pixhawk's avatar
pixhawk committed
538 539 540
    return getNominalDataRate();
}

541
int SerialLink::getBaudRateType() const
542
{
Bill Bonney's avatar
Bill Bonney committed
543 544 545 546 547 548 549
    int baudRate;
    if (m_port) {
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    return baudRate;
pixhawk's avatar
pixhawk committed
550 551
}

552
int SerialLink::getFlowType() const
553
{
Bill Bonney's avatar
Bill Bonney committed
554 555 556 557 558 559 560
    int flowControl;
    if (m_port) {
        flowControl = m_port->flowControl();
    } else {
        flowControl = m_flowControl;
    }
    return flowControl;
pixhawk's avatar
pixhawk committed
561 562
}

563
int SerialLink::getParityType() const
564
{
Bill Bonney's avatar
Bill Bonney committed
565 566 567 568 569 570 571
    int parity;
    if (m_port) {
        parity = m_port->parity();
    } else {
        parity = m_parity;
    }
    return parity;
pixhawk's avatar
pixhawk committed
572 573
}

574
int SerialLink::getDataBitsType() const
575
{
Bill Bonney's avatar
Bill Bonney committed
576 577 578 579 580 581 582
    int dataBits;
    if (m_port) {
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }
    return dataBits;
pixhawk's avatar
pixhawk committed
583 584
}

585
int SerialLink::getStopBitsType() const
586
{
Bill Bonney's avatar
Bill Bonney committed
587 588 589 590 591 592 593
    int stopBits;
    if (m_port) {
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
    return stopBits;
pixhawk's avatar
pixhawk committed
594 595
}

596
int SerialLink::getDataBits() const
597
{
Bill Bonney's avatar
Bill Bonney committed
598 599 600 601 602 603 604 605 606 607
    int ret;
    int dataBits;
    if (m_port) {
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }

    switch (dataBits) {
    case QSerialPort::Data5:
608 609
        ret = 5;
        break;
Bill Bonney's avatar
Bill Bonney committed
610
    case QSerialPort::Data6:
611 612
        ret = 6;
        break;
Bill Bonney's avatar
Bill Bonney committed
613
    case QSerialPort::Data7:
614 615
        ret = 7;
        break;
Bill Bonney's avatar
Bill Bonney committed
616
    case QSerialPort::Data8:
617 618 619
        ret = 8;
        break;
    default:
620
        ret = -1;
621 622 623 624 625
        break;
    }
    return ret;
}

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

pixhawk's avatar
pixhawk committed
649 650
bool SerialLink::setPortName(QString portName)
{
Bill Bonney's avatar
Bill Bonney committed
651 652 653 654 655 656
    qDebug() << "current portName " << m_portName;
    qDebug() << "setPortName to " << portName;
    bool accepted = false;
    if ((portName != m_portName)
            && (portName.trimmed().length() > 0)) {
        m_portName = portName.trimmed();
657
//        m_name = tr("serial port ") + portName.trimmed(); // [TODO] Do we need this?
Bill Bonney's avatar
Bill Bonney committed
658 659
        if(m_port)
            m_port->setPortName(portName);
660

661
        emit nameChanged(m_portName); // [TODO] maybe we can eliminate this
662
        emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
663
        return accepted;
pixhawk's avatar
pixhawk committed
664
    }
Bill Bonney's avatar
Bill Bonney committed
665
    return false;
pixhawk's avatar
pixhawk committed
666 667 668 669 670
}


bool SerialLink::setBaudRateType(int rateIndex)
{
Bill Bonney's avatar
Bill Bonney committed
671 672
    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
673
    bool result;
Bill Bonney's avatar
Bill Bonney committed
674 675
    const int minBaud = (int)QSerialPort::Baud1200;
    const int maxBaud = (int)QSerialPort::Baud115200;
676

Bill Bonney's avatar
Bill Bonney committed
677
    if (m_port && (rateIndex >= minBaud && rateIndex <= maxBaud))
678
    {
679 680 681
        result = m_port->setBaudRate(static_cast<QSerialPort::BaudRate>(rateIndex));
        emit updateLink(this);
        return result;
pixhawk's avatar
pixhawk committed
682 683
    }

Bill Bonney's avatar
Bill Bonney committed
684
    return false;
pixhawk's avatar
pixhawk committed
685 686
}

687 688 689 690 691 692 693
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
694 695 696

bool SerialLink::setBaudRate(int rate)
{
Bill Bonney's avatar
Bill Bonney committed
697 698 699 700 701 702
    bool accepted = false;
    if (rate != m_baud) {
        m_baud = rate;
        accepted = true;
        if (m_port)
            accepted = m_port->setBaudRate(rate);
703
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
704
    }
705
    return accepted;
pixhawk's avatar
pixhawk committed
706 707
}

708 709
bool SerialLink::setFlowType(int flow)
{
Bill Bonney's avatar
Bill Bonney committed
710 711 712 713 714 715
    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));
716
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
717 718 719 720
    }
    return accepted;
}

721 722
bool SerialLink::setParityType(int parity)
{
Bill Bonney's avatar
Bill Bonney committed
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
    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;
                }
746
            emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
747
        }
pixhawk's avatar
pixhawk committed
748 749 750 751
    }
    return accepted;
}

752

753
bool SerialLink::setDataBits(int dataBits)
754
{
Bill Bonney's avatar
Bill Bonney committed
755 756 757 758 759 760
    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));
761
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
762 763 764 765
    }
    return accepted;
}

766
bool SerialLink::setStopBits(int stopBits)
767
{
Bill Bonney's avatar
Bill Bonney committed
768 769 770 771 772 773 774
    // 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));
775
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
776 777 778
    }
    return accepted;
}
779 780 781 782

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

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