SerialLink.cc 24.3 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
    // Get the name of the current port in use.
    m_portName = portname.trimmed();
33
    if (m_portName == "" && getCurrentPorts().size() > 0)
34
    {
35
        m_portName = m_ports.first().trimmed();
36 37
    }

38 39
    checkIfCDC();

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

    m_baud = baudRate;
44

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

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

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

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

71
    LinkManager::instance()->add(this);
pixhawk's avatar
pixhawk committed
72
}
73

74 75 76 77 78
void SerialLink::requestReset()
{
    QMutexLocker locker(&this->m_stoppMutex);
    m_reqReset = true;
}
pixhawk's avatar
pixhawk committed
79 80 81 82

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

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

91
    QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();
92

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

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

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

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

Bill Bonney's avatar
Bill Bonney committed
118 119 120 121 122
        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();
123 124 125 126 127 128
    }
}

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

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


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

pixhawk's avatar
pixhawk committed
179
    // Initialize the connection
180
    if (!hardwareConnect(type)) {
181
        //Need to error out here.
182 183 184 185 186 187
        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
188
        return;
189
    }
pixhawk's avatar
pixhawk committed
190 191

    // Qt way to make clear what a while(1) loop does
192 193
    qint64 msecs = QDateTime::currentMSecsSinceEpoch();
    qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch();
194
    quint64 bytes = 0;
195 196
//    bool triedreset = false;
//    bool triedDTR = false;
197
    qint64 timeout = 5000;
198
    int linkErrorCount = 0;
199

200
    forever {
201
        {
202
            QMutexLocker locker(&this->m_stoppMutex);
203 204 205 206
            if(m_stopp) {
                m_stopp = false;
                break; // exit the thread
            }
207

208 209 210 211 212 213 214
            if (m_reqReset) {
                m_reqReset = false;
                emit communicationUpdate(getName(),"Reset requested via DTR signal");
                m_port->setDataTerminalReady(true);
                msleep(250);
                m_port->setDataTerminalReady(false);
            }
215
        }
216

217
        // If there are too many errors on this link, disconnect.
Lorenz Meier's avatar
Lorenz Meier committed
218
        if (isConnected() && (linkErrorCount > 1000)) {
219
            qDebug() << "linkErrorCount too high: disconnecting!";
220
            linkErrorCount = 0;
221
            emit communicationUpdate(getName(), tr("Disconnecting on too many link errors"));
222 223 224
            disconnect();
        }

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

                // Since we were successful, reset out error counter.
237 238
                linkErrorCount = 0;
            }
239 240 241 242 243 244 245

            // 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.
246 247
            QMutexLocker dataRateLocker(&dataRateMutex);
            logDataRateToBuffer(outDataWriteAmounts, outDataWriteTimes, &outDataIndex, numWritten, QDateTime::currentMSecsSinceEpoch());
248 249
        }

250 251
        //wait n msecs for data to be ready
        //[TODO][BB] lower to SerialLink::poll_interval?
252
        m_dataMutex.lock();
253
        bool success = m_port->waitForReadyRead(10);
254

255
        if (success) {
256 257 258
            QByteArray readData = m_port->readAll();
            while (m_port->waitForReadyRead(10))
                readData += m_port->readAll();
259
            m_dataMutex.unlock();
260 261 262
            if (readData.length() > 0) {
                emit bytesReceived(this, readData);

263
                // Log this data reception for this timestep
264 265
                QMutexLocker dataRateLocker(&dataRateMutex);
                logDataRateToBuffer(inDataWriteAmounts, inDataWriteTimes, &inDataIndex, readData.length(), QDateTime::currentMSecsSinceEpoch());
266 267

                // Track the total amount of data read.
268
                m_bytesRead += readData.length();
269
                linkErrorCount = 0;
270
            }
271 272
        }
        else {
273
            m_dataMutex.unlock();
274
            linkErrorCount++;
275
        }
276

277
        if (bytes != m_bytesRead) { // i.e things are good and data is being read.
278
            bytes = m_bytesRead;
279 280
            msecs = QDateTime::currentMSecsSinceEpoch();
        }
281 282
        else {
            if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) {
283 284
                //It's been 10 seconds since the last data came in. Reset and try again
                msecs = QDateTime::currentMSecsSinceEpoch();
285
                if (msecs - initialmsecs > 25000) {
286 287 288 289 290 291 292
                    //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;
                }
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
//                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!!!";
//                }
311 312
            }
        }
pixhawk's avatar
pixhawk committed
313
        MG::SLEEP::msleep(SerialLink::poll_interval);
314 315 316 317 318 319 320
    } // 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
321

322 323
        emit disconnected();
        emit connected(false);
324
    }
pixhawk's avatar
pixhawk committed
325 326
}

327 328
void SerialLink::writeBytes(const char* data, qint64 size)
{
Bill Bonney's avatar
Bill Bonney committed
329
    if(m_port && m_port->isOpen()) {
pixhawk's avatar
pixhawk committed
330

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

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

356
        if(numBytes > 0) {
pixhawk's avatar
pixhawk committed
357 358 359
            /* Read as much data in buffer as possible without overflow */
            if(maxLength < numBytes) numBytes = maxLength;

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


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

/**
 * @brief Disconnect the connection.
 *
 * @return True if connection has been disconnected, false if connection couldn't be disconnected.
 **/
388 389
bool SerialLink::disconnect()
{
390 391 392
    qDebug() << "disconnect";
    if (m_port)
        qDebug() << m_port->portName();
Bill Bonney's avatar
Bill Bonney committed
393 394

    if (isRunning())
395 396
    {
        {
Bill Bonney's avatar
Bill Bonney committed
397 398
            QMutexLocker locker(&m_stoppMutex);
            m_stopp = true;
399
        }
Bill Bonney's avatar
Bill Bonney committed
400
        wait(); // This will terminate the thread and close the serial port
pixhawk's avatar
pixhawk committed
401

Bill Bonney's avatar
Bill Bonney committed
402
        emit disconnected(); // [TODO] There are signals from QSerialPort we should use
403 404 405
        emit connected(false);
        return true;
    }
pixhawk's avatar
pixhawk committed
406

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

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

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

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

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

449 450 451 452 453
    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
454
        return false; // couldn't create serial port.
455
    }
Bill Bonney's avatar
Bill Bonney committed
456 457

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

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

462 463 464 465 466 467 468 469
    //    port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead);

    if (!m_port->open(QIODevice::ReadWrite)) {
        emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
        m_port->close();
        return false; // couldn't open serial port
    }

470 471 472 473 474 475 476 477 478 479 480
    // Need to configure the port
    // NOTE: THE PORT NEEDS TO BE OPEN!
    if (!m_is_cdc) {
        qDebug() << "Configuring port";
        m_port->setBaudRate(m_baud);
        m_port->setDataBits(static_cast<QSerialPort::DataBits>(m_dataBits));
        m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(m_flowControl));
        m_port->setStopBits(static_cast<QSerialPort::StopBits>(m_stopBits));
        m_port->setParity(static_cast<QSerialPort::Parity>(m_parity));
    }

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

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

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

489 490
    writeSettings();

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

494
void SerialLink::linkError(QSerialPort::SerialPortError error)
495
{
496
    if (error != QSerialPort::NoError) {
497 498 499 500 501
        // You can use the following qDebug output as needed during development. Make sure to comment it back out
        // when you are done. The reason for this is that this signal is very noisy. For example if you try to
        // connect to a PixHawk before it is ready to accept the connection it will output a continuous stream
        // of errors until the Pixhawk responds.
        //qDebug() << "SerialLink::linkError" << error;
502
    }
503 504
}

505

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

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

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

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

536 537 538 539
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
540
qint64 SerialLink::getConnectionSpeed() const
541
{
Bill Bonney's avatar
Bill Bonney committed
542
    int baudRate;
543
    if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    qint64 dataRate;
    switch (baudRate)
    {
        case QSerialPort::Baud1200:
            dataRate = 1200;
            break;
        case QSerialPort::Baud2400:
            dataRate = 2400;
            break;
        case QSerialPort::Baud4800:
            dataRate = 4800;
            break;
        case QSerialPort::Baud9600:
            dataRate = 9600;
            break;
        case QSerialPort::Baud19200:
            dataRate = 19200;
            break;
        case QSerialPort::Baud38400:
            dataRate = 38400;
            break;
        case QSerialPort::Baud57600:
            dataRate = 57600;
            break;
        case QSerialPort::Baud115200:
            dataRate = 115200;
            break;
            // Otherwise do nothing.
        case QSerialPort::UnknownBaud:
        default:
            dataRate = -1;
            break;
pixhawk's avatar
pixhawk committed
580 581 582 583
    }
    return dataRate;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        checkIfCDC();

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

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


bool SerialLink::setBaudRateType(int rateIndex)
{
734

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

740
    if ((rateIndex >= minBaud && rateIndex <= maxBaud))
741
    {
742 743 744 745 746 747 748 749 750 751
        if (!m_is_cdc && m_port)
        {
            result = m_port->setBaudRate(static_cast<QSerialPort::BaudRate>(rateIndex));
            emit updateLink(this);
        } else {
            m_baud = (int)rateIndex;
            result = true;
        }
    } else {
        result = false;
pixhawk's avatar
pixhawk committed
752 753
    }

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

757 758 759 760 761 762 763
bool SerialLink::setBaudRateString(const QString& rate)
{
    bool ok;
    int intrate = rate.toInt(&ok);
    if (!ok) return false;
    return setBaudRate(intrate);
}
pixhawk's avatar
pixhawk committed
764 765 766

bool SerialLink::setBaudRate(int rate)
{
767

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

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

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

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

Bill Bonney's avatar
Bill Bonney committed
797 798 799 800
    bool accepted = false;
    if (parity != m_parity) {
        m_parity = static_cast<QSerialPort::Parity>(parity);
        accepted = true;
801
        if (m_port && !m_is_cdc) {
Bill Bonney's avatar
Bill Bonney committed
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
            switch (parity) {
                case QSerialPort::NoParity:
                accepted = m_port->setParity(QSerialPort::NoParity);
                break;
                case 1: // Odd Parity setting for backwards compatibilty
                    accepted = m_port->setParity(QSerialPort::OddParity);
                    break;
                case QSerialPort::EvenParity:
                    accepted = m_port->setParity(QSerialPort::EvenParity);
                    break;
                case QSerialPort::OddParity:
                    accepted = m_port->setParity(QSerialPort::OddParity);
                    break;
                default:
                    // If none of the above cases matches, there must be an error
                    accepted = false;
                    break;
                }
820
            emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
821
        }
pixhawk's avatar
pixhawk committed
822 823 824 825
    }
    return accepted;
}

826

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

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

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

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

bool SerialLink::setDataBitsType(int dataBits)
{
859

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

bool SerialLink::setStopBitsType(int stopBits)
{
873

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