SerialLink.cc 23.5 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9 10 11 12
/*=====================================================================
======================================================================*/
/**
 * @file
 *   @brief Cross-platform support for serial ports
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QTimer>
#include <QDebug>
13
#include <QSettings>
pixhawk's avatar
pixhawk committed
14
#include <QMutexLocker>
Bill Bonney's avatar
Bill Bonney committed
15 16
#include <qserialport.h>
#include <qserialportinfo.h>
pixhawk's avatar
pixhawk committed
17 18
#include "SerialLink.h"
#include "LinkManager.h"
19
#include "QGC.h"
pixhawk's avatar
pixhawk committed
20 21
#include <MG.h>

22 23


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 32
    qDebug() << "create SerialLink " << portname << baudRate << hardwareFlowControl
             << parity << dataBits << stopBits;
pixhawk's avatar
pixhawk committed
33
    // Setup settings
Bill Bonney's avatar
Bill Bonney committed
34
    m_portName = portname.trimmed();
35

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

41 42
    qDebug() << "m_portName " << m_portName;

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

    m_baud = baudRate;
47

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

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

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

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

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

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

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

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

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

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

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

pixhawk's avatar
pixhawk committed
134 135 136 137 138

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

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

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

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

176
        if (isConnected() && (linkErrorCount > 100)) {
177
            qDebug() << "linkErrorCount too high: disconnecting!";
178
            linkErrorCount = 0;
179
            emit communicationUpdate(getName(), tr("Disconnecting on too many link errors"));
180 181 182 183
            disconnect();
        }

        if (m_transmitBuffer.count() > 0) {
184 185
            QMutexLocker writeLocker(&m_writeMutex);
            int numWritten = m_port->write(m_transmitBuffer);
186
            bool txSuccess = m_port->waitForBytesWritten(1);
187
            if (!txSuccess || (numWritten != m_transmitBuffer.count())) {
188 189
                linkErrorCount++;
                qDebug() << "TX Error! wrote" << numWritten << ", asked for " << m_transmitBuffer.count() << "bytes";
190 191
            }
            else {
192 193
                linkErrorCount = 0;
            }
194
            m_transmitBuffer =  m_transmitBuffer.remove(0, numWritten);
195 196
        }

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

201
        if (success) {
202 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();
                m_bitsReceivedTotal += readData.length() * 8;
211
                linkErrorCount = 0;
212
            }
213 214
        }
        else {
215
            linkErrorCount++;
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 281
        // Increase write counter
        m_bitsSentTotal += size * 8;
282

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

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

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

Bill Bonney's avatar
Bill Bonney committed
311
            m_port->read(data, numBytes);
pixhawk's avatar
pixhawk committed
312 313 314 315 316 317 318 319 320 321 322
            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
323
            m_bitsReceivedTotal += numBytes * 8;
pixhawk's avatar
pixhawk committed
324 325
        }
    }
Bill Bonney's avatar
Bill Bonney committed
326
    m_dataMutex.unlock();
pixhawk's avatar
pixhawk committed
327 328 329 330 331 332 333 334
}


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

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

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

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

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

371 372
    qDebug() << "already disconnected";
    return true;
pixhawk's avatar
pixhawk committed
373 374 375 376 377 378 379 380
}

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

    start(LowPriority);
390
    return true;
pixhawk's avatar
pixhawk committed
391 392 393 394 395 396 397 398 399 400
}

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

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

    QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected()));
418 419
    QObject::connect(m_port, SIGNAL(error(SerialLinkPortError_t)),
                     this, SLOT(linkError(SerialLinkPortError_t)));
Bill Bonney's avatar
Bill Bonney committed
420 421 422 423

//    port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead);
    m_connectionStartTime = MG::TIME::getGroundTimeNow();

424
    if (!m_port->open(QIODevice::ReadWrite)) {
Bill Bonney's avatar
Bill Bonney committed
425 426 427
        emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
        m_port->close();
        return false; // couldn't open serial port
428
    }
429

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

Bill Bonney's avatar
Bill Bonney committed
432 433 434 435 436 437
    // 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
438

Bill Bonney's avatar
Bill Bonney committed
439 440
    emit connected();
    emit connected(true);
441

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

445 446
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
447
    return true; // successful connection
pixhawk's avatar
pixhawk committed
448
}
449

450
void SerialLink::linkError(SerialLinkPortError_t error)
451 452 453 454
{
    qDebug() << error;
}

455

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

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

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

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

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

534 535
qint64 SerialLink::getTotalUpstream()
{
Bill Bonney's avatar
Bill Bonney committed
536 537 538
    m_statisticsMutex.lock();
    return m_bitsSentTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000);
    m_statisticsMutex.unlock();
pixhawk's avatar
pixhawk committed
539 540
}

541 542
qint64 SerialLink::getCurrentUpstream()
{
pixhawk's avatar
pixhawk committed
543 544 545
    return 0; // TODO
}

546 547
qint64 SerialLink::getMaxUpstream()
{
pixhawk's avatar
pixhawk committed
548 549 550
    return 0; // TODO
}

551
qint64 SerialLink::getBitsSent() const
552
{
Bill Bonney's avatar
Bill Bonney committed
553
    return m_bitsSentTotal;
pixhawk's avatar
pixhawk committed
554 555
}

556
qint64 SerialLink::getBitsReceived() const
557
{
Bill Bonney's avatar
Bill Bonney committed
558
    return m_bitsReceivedTotal;
pixhawk's avatar
pixhawk committed
559 560
}

561 562
qint64 SerialLink::getTotalDownstream()
{
Bill Bonney's avatar
Bill Bonney committed
563 564 565
    m_statisticsMutex.lock();
    return m_bitsReceivedTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000);
    m_statisticsMutex.unlock();
pixhawk's avatar
pixhawk committed
566 567
}

568 569
qint64 SerialLink::getCurrentDownstream()
{
pixhawk's avatar
pixhawk committed
570 571 572
    return 0; // TODO
}

573 574
qint64 SerialLink::getMaxDownstream()
{
pixhawk's avatar
pixhawk committed
575 576 577
    return 0; // TODO
}

578
bool SerialLink::isFullDuplex() const
579
{
pixhawk's avatar
pixhawk committed
580 581 582 583
    /* Serial connections are always half duplex */
    return false;
}

584
int SerialLink::getLinkQuality() const
585
{
pixhawk's avatar
pixhawk committed
586 587 588 589
    /* This feature is not supported with this interface */
    return -1;
}

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

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

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

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

613
int SerialLink::getFlowType() const
614
{
Bill Bonney's avatar
Bill Bonney committed
615 616 617 618 619 620 621
    int flowControl;
    if (m_port) {
        flowControl = m_port->flowControl();
    } else {
        flowControl = m_flowControl;
    }
    return flowControl;
pixhawk's avatar
pixhawk committed
622 623
}

624
int SerialLink::getParityType() const
625
{
Bill Bonney's avatar
Bill Bonney committed
626 627 628 629 630 631 632
    int parity;
    if (m_port) {
        parity = m_port->parity();
    } else {
        parity = m_parity;
    }
    return parity;
pixhawk's avatar
pixhawk committed
633 634
}

635
int SerialLink::getDataBitsType() const
636
{
Bill Bonney's avatar
Bill Bonney committed
637 638 639 640 641 642 643
    int dataBits;
    if (m_port) {
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }
    return dataBits;
pixhawk's avatar
pixhawk committed
644 645
}

646
int SerialLink::getStopBitsType() const
647
{
Bill Bonney's avatar
Bill Bonney committed
648 649 650 651 652 653 654
    int stopBits;
    if (m_port) {
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
    return stopBits;
pixhawk's avatar
pixhawk committed
655 656
}

657
int SerialLink::getDataBits() const
658
{
Bill Bonney's avatar
Bill Bonney committed
659 660 661 662 663 664 665 666 667 668
    int ret;
    int dataBits;
    if (m_port) {
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }

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

687
int SerialLink::getStopBits() const
688
{
Bill Bonney's avatar
Bill Bonney committed
689 690 691 692 693 694
    int stopBits;
    if (m_port) {
        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 714 715 716 717
    qDebug() << "current portName " << m_portName;
    qDebug() << "setPortName to " << portName;
    bool accepted = false;
    if ((portName != m_portName)
            && (portName.trimmed().length() > 0)) {
        m_portName = portName.trimmed();
718
//        m_name = tr("serial port ") + portName.trimmed(); // [TODO] Do we need this?
Bill Bonney's avatar
Bill Bonney committed
719 720
        if(m_port)
            m_port->setPortName(portName);
721

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


bool SerialLink::setBaudRateType(int rateIndex)
{
Bill Bonney's avatar
Bill Bonney committed
732 733
    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
734
    bool result;
Bill Bonney's avatar
Bill Bonney committed
735 736
    const int minBaud = (int)QSerialPort::Baud1200;
    const int maxBaud = (int)QSerialPort::Baud115200;
737

Bill Bonney's avatar
Bill Bonney committed
738
    if (m_port && (rateIndex >= minBaud && rateIndex <= maxBaud))
739
    {
740 741 742
        result = m_port->setBaudRate(static_cast<QSerialPort::BaudRate>(rateIndex));
        emit updateLink(this);
        return result;
pixhawk's avatar
pixhawk committed
743 744
    }

Bill Bonney's avatar
Bill Bonney committed
745
    return false;
pixhawk's avatar
pixhawk committed
746 747
}

748 749 750 751 752 753 754
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
755 756 757

bool SerialLink::setBaudRate(int rate)
{
Bill Bonney's avatar
Bill Bonney committed
758 759 760 761 762 763
    bool accepted = false;
    if (rate != m_baud) {
        m_baud = rate;
        accepted = true;
        if (m_port)
            accepted = m_port->setBaudRate(rate);
764
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
765
    }
766
    return accepted;
pixhawk's avatar
pixhawk committed
767 768
}

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

782 783
bool SerialLink::setParityType(int parity)
{
Bill Bonney's avatar
Bill Bonney committed
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
    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;
                }
807
            emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
808
        }
pixhawk's avatar
pixhawk committed
809 810 811 812
    }
    return accepted;
}

813

814
bool SerialLink::setDataBits(int dataBits)
815
{
Bill Bonney's avatar
Bill Bonney committed
816 817 818 819 820 821
    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));
822
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
823 824 825 826
    }
    return accepted;
}

827
bool SerialLink::setStopBits(int stopBits)
828
{
Bill Bonney's avatar
Bill Bonney committed
829 830 831 832 833 834 835
    // 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));
836
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
837 838 839
    }
    return accepted;
}
840 841 842 843

bool SerialLink::setDataBitsType(int dataBits)
{
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
844 845
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
846
        accepted = true;
Bill Bonney's avatar
Bill Bonney committed
847 848
        if (m_port)
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
849
        emit updateLink(this);
850 851 852 853 854 855 856
    }
    return accepted;
}

bool SerialLink::setStopBitsType(int stopBits)
{
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
857 858
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
859
        accepted = true;
Bill Bonney's avatar
Bill Bonney committed
860 861
        if (m_port)
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
862
        emit updateLink(this);
863 864 865
    }
    return accepted;
}