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

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

22 23
SerialLink::SerialLink(QString portname, int baudRate, bool hardwareFlowControl, bool parity,
                       int dataBits, int stopBits) :
Bill Bonney's avatar
Bill Bonney committed
24 25
    m_bytesRead(0),
    m_port(NULL),
26
    m_stopp(false),
27
    m_reqReset(false)
pixhawk's avatar
pixhawk committed
28
{
29 30
    qDebug() << "create SerialLink " << portname << baudRate << hardwareFlowControl
             << parity << dataBits << stopBits;
pixhawk's avatar
pixhawk committed
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
    }

39 40
    qDebug() << "m_portName " << m_portName;

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

    m_baud = baudRate;
45

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

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

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

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

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

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

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

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

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

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

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

pixhawk's avatar
pixhawk committed
132 133 134 135 136

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

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

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

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

178
        if (isConnected() && (linkErrorCount > 100)) {
179
            qDebug() << "linkErrorCount too high: disconnecting!";
180
            linkErrorCount = 0;
181
            communicationError("SerialLink", tr("Disconnecting on too many link errors"));
182 183 184 185
            disconnect();
        }

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

199
        bool success = m_port->waitForReadyRead(10);
200

201
        if (success) { // Waits for 1/2 second [TODO][BB] lower to SerialLink::poll_interval?
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
            }
        } else {
214
            linkErrorCount++;
215
            //qDebug() << "Wait read response timeout" << QTime::currentTime().toString();
216
        }
217

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

270 271
        emit disconnected();
        emit connected(false);
272
    }
pixhawk's avatar
pixhawk committed
273 274
}

275 276
void SerialLink::writeBytes(const char* data, qint64 size)
{
Bill Bonney's avatar
Bill Bonney committed
277
    if(m_port && m_port->isOpen()) {
278
//        qDebug() << "writeBytes" << m_portName << "attempting to tx " << size << "bytes.";
pixhawk's avatar
pixhawk committed
279

280
        QByteArray byteArray(data, size);
281 282 283 284
        {
            QMutexLocker writeLocker(&m_writeMutex);
            m_transmitBuffer.append(byteArray);
        }
285

286 287
        // Increase write counter
        m_bitsSentTotal += size * 8;
288

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

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

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

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


/**
 * @brief Get the number of bytes to read.
 *
 * @return The number of bytes to read
 **/
341 342
qint64 SerialLink::bytesAvailable()
{
Bill Bonney's avatar
Bill Bonney committed
343 344
    if (m_port) {
        return m_port->bytesAvailable();
345
    } else {
346 347
        return 0;
    }
pixhawk's avatar
pixhawk committed
348 349 350 351 352 353 354
}

/**
 * @brief Disconnect the connection.
 *
 * @return True if connection has been disconnected, false if connection couldn't be disconnected.
 **/
355 356
bool SerialLink::disconnect()
{
357 358 359
    qDebug() << "disconnect";
    if (m_port)
        qDebug() << m_port->portName();
Bill Bonney's avatar
Bill Bonney committed
360 361

    if (isRunning())
362
    {
363
        qDebug() << "running so disconnect" << m_port->portName();
364
        {
Bill Bonney's avatar
Bill Bonney committed
365 366
            QMutexLocker locker(&m_stoppMutex);
            m_stopp = true;
367
        }
Bill Bonney's avatar
Bill Bonney committed
368
        wait(); // This will terminate the thread and close the serial port
pixhawk's avatar
pixhawk committed
369

Bill Bonney's avatar
Bill Bonney committed
370
        emit disconnected(); // [TODO] There are signals from QSerialPort we should use
371 372 373
        emit connected(false);
        return true;
    }
pixhawk's avatar
pixhawk committed
374

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

377 378
    qDebug() << "already disconnected";
    return true;
pixhawk's avatar
pixhawk committed
379 380 381 382 383 384 385 386
}

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

    start(LowPriority);
396
    return true;
pixhawk's avatar
pixhawk committed
397 398 399 400 401 402 403 404 405 406
}

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

Bill Bonney's avatar
Bill Bonney committed
419
    if (m_port == NULL)
420
    {
Bill Bonney's avatar
Bill Bonney committed
421 422
        emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
        return false; // couldn't create serial port.
423
    }
Bill Bonney's avatar
Bill Bonney committed
424 425

    QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected()));
426 427
    QObject::connect(m_port, SIGNAL(error(QSerialPort::SerialPortError)),
                     this, SLOT(linkError(QSerialPort::SerialPortError)));
Bill Bonney's avatar
Bill Bonney committed
428 429 430 431 432

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

    if (!m_port->open(QIODevice::ReadWrite))
433
    {
Bill Bonney's avatar
Bill Bonney committed
434 435 436
        emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
        m_port->close();
        return false; // couldn't open serial port
437
    }
438

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

Bill Bonney's avatar
Bill Bonney committed
441 442 443 444 445 446
    // 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
447

Bill Bonney's avatar
Bill Bonney committed
448 449
    emit connected();
    emit connected(true);
450

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

454 455
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
456
    return true; // successful connection
pixhawk's avatar
pixhawk committed
457
}
458

459 460 461 462 463
void SerialLink::linkError(QSerialPort::SerialPortError error)
{
    qDebug() << error;
}

464

pixhawk's avatar
pixhawk committed
465 466 467 468 469
/**
 * @brief Check if connection is active.
 *
 * @return True if link is connected, false otherwise.
 **/
470
bool SerialLink::isConnected() const
471
{
Bill Bonney's avatar
Bill Bonney committed
472 473 474

    if (m_port) {
        bool isConnected = m_port->isOpen();
475 476
//        qDebug() << "SerialLink #" << __LINE__ << ":"<<  m_port->portName()
//                 << " isConnected =" << QString::number(isConnected);
Bill Bonney's avatar
Bill Bonney committed
477
        return isConnected;
478
    } else {
479 480
//        qDebug() << "SerialLink #" << __LINE__ << ":" <<  m_portName
//                 << " isConnected = NULL";
lm's avatar
lm committed
481 482
        return false;
    }
pixhawk's avatar
pixhawk committed
483 484
}

485
int SerialLink::getId() const
pixhawk's avatar
pixhawk committed
486
{
Bill Bonney's avatar
Bill Bonney committed
487
    return m_id;
pixhawk's avatar
pixhawk committed
488 489
}

490
QString SerialLink::getName() const
pixhawk's avatar
pixhawk committed
491
{
492
    return m_portName;
pixhawk's avatar
pixhawk committed
493 494
}

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

543 544
qint64 SerialLink::getTotalUpstream()
{
Bill Bonney's avatar
Bill Bonney committed
545 546 547
    m_statisticsMutex.lock();
    return m_bitsSentTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000);
    m_statisticsMutex.unlock();
pixhawk's avatar
pixhawk committed
548 549
}

550 551
qint64 SerialLink::getCurrentUpstream()
{
pixhawk's avatar
pixhawk committed
552 553 554
    return 0; // TODO
}

555 556
qint64 SerialLink::getMaxUpstream()
{
pixhawk's avatar
pixhawk committed
557 558 559
    return 0; // TODO
}

560
qint64 SerialLink::getBitsSent() const
561
{
Bill Bonney's avatar
Bill Bonney committed
562
    return m_bitsSentTotal;
pixhawk's avatar
pixhawk committed
563 564
}

565
qint64 SerialLink::getBitsReceived() const
566
{
Bill Bonney's avatar
Bill Bonney committed
567
    return m_bitsReceivedTotal;
pixhawk's avatar
pixhawk committed
568 569
}

570 571
qint64 SerialLink::getTotalDownstream()
{
Bill Bonney's avatar
Bill Bonney committed
572 573 574
    m_statisticsMutex.lock();
    return m_bitsReceivedTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000);
    m_statisticsMutex.unlock();
pixhawk's avatar
pixhawk committed
575 576
}

577 578
qint64 SerialLink::getCurrentDownstream()
{
pixhawk's avatar
pixhawk committed
579 580 581
    return 0; // TODO
}

582 583
qint64 SerialLink::getMaxDownstream()
{
pixhawk's avatar
pixhawk committed
584 585 586
    return 0; // TODO
}

587
bool SerialLink::isFullDuplex() const
588
{
pixhawk's avatar
pixhawk committed
589 590 591 592
    /* Serial connections are always half duplex */
    return false;
}

593
int SerialLink::getLinkQuality() const
594
{
pixhawk's avatar
pixhawk committed
595 596 597 598
    /* This feature is not supported with this interface */
    return -1;
}

599
QString SerialLink::getPortName() const
600
{
Bill Bonney's avatar
Bill Bonney committed
601
    return m_portName;
pixhawk's avatar
pixhawk committed
602 603
}

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

606
int SerialLink::getBaudRate() const
607
{
pixhawk's avatar
pixhawk committed
608 609 610
    return getNominalDataRate();
}

611
int SerialLink::getBaudRateType() const
612
{
Bill Bonney's avatar
Bill Bonney committed
613 614 615 616 617 618 619
    int baudRate;
    if (m_port) {
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    return baudRate;
pixhawk's avatar
pixhawk committed
620 621
}

622
int SerialLink::getFlowType() const
623
{
Bill Bonney's avatar
Bill Bonney committed
624 625 626 627 628 629 630
    int flowControl;
    if (m_port) {
        flowControl = m_port->flowControl();
    } else {
        flowControl = m_flowControl;
    }
    return flowControl;
pixhawk's avatar
pixhawk committed
631 632
}

633
int SerialLink::getParityType() const
634
{
Bill Bonney's avatar
Bill Bonney committed
635 636 637 638 639 640 641
    int parity;
    if (m_port) {
        parity = m_port->parity();
    } else {
        parity = m_parity;
    }
    return parity;
pixhawk's avatar
pixhawk committed
642 643
}

644
int SerialLink::getDataBitsType() const
645
{
Bill Bonney's avatar
Bill Bonney committed
646 647 648 649 650 651 652
    int dataBits;
    if (m_port) {
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }
    return dataBits;
pixhawk's avatar
pixhawk committed
653 654
}

655
int SerialLink::getStopBitsType() const
656
{
Bill Bonney's avatar
Bill Bonney committed
657 658 659 660 661 662 663
    int stopBits;
    if (m_port) {
        stopBits = m_port->stopBits();
    } else {
        stopBits = m_stopBits;
    }
    return stopBits;
pixhawk's avatar
pixhawk committed
664 665
}

666
int SerialLink::getDataBits() const
667
{
Bill Bonney's avatar
Bill Bonney committed
668 669 670 671 672 673 674 675 676 677
    int ret;
    int dataBits;
    if (m_port) {
        dataBits = m_port->dataBits();
    } else {
        dataBits = m_dataBits;
    }

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

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

pixhawk's avatar
pixhawk committed
719 720
bool SerialLink::setPortName(QString portName)
{
Bill Bonney's avatar
Bill Bonney committed
721 722 723 724 725 726
    qDebug() << "current portName " << m_portName;
    qDebug() << "setPortName to " << portName;
    bool accepted = false;
    if ((portName != m_portName)
            && (portName.trimmed().length() > 0)) {
        m_portName = portName.trimmed();
727
//        m_name = tr("serial port ") + portName.trimmed(); // [TODO] Do we need this?
Bill Bonney's avatar
Bill Bonney committed
728 729
        if(m_port)
            m_port->setPortName(portName);
730

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


bool SerialLink::setBaudRateType(int rateIndex)
{
Bill Bonney's avatar
Bill Bonney committed
741 742
    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
743
    bool result;
Bill Bonney's avatar
Bill Bonney committed
744 745
    const int minBaud = (int)QSerialPort::Baud1200;
    const int maxBaud = (int)QSerialPort::Baud115200;
746

Bill Bonney's avatar
Bill Bonney committed
747
    if (m_port && (rateIndex >= minBaud && rateIndex <= maxBaud))
748
    {
749 750 751
        result = m_port->setBaudRate(static_cast<QSerialPort::BaudRate>(rateIndex));
        emit updateLink(this);
        return result;
pixhawk's avatar
pixhawk committed
752 753
    }

Bill Bonney's avatar
Bill Bonney committed
754
    return false;
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)
{
Bill Bonney's avatar
Bill Bonney committed
767 768 769 770 771 772
    bool accepted = false;
    if (rate != m_baud) {
        m_baud = rate;
        accepted = true;
        if (m_port)
            accepted = m_port->setBaudRate(rate);
773
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
774
    }
775
    return accepted;
pixhawk's avatar
pixhawk committed
776 777
}

778 779
bool SerialLink::setFlowType(int flow)
{
Bill Bonney's avatar
Bill Bonney committed
780 781 782 783 784 785
    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));
786
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
787 788 789 790
    }
    return accepted;
}

791 792
bool SerialLink::setParityType(int parity)
{
Bill Bonney's avatar
Bill Bonney committed
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
    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;
                }
816
            emit updateLink(this);
Bill Bonney's avatar
Bill Bonney committed
817
        }
pixhawk's avatar
pixhawk committed
818 819 820 821
    }
    return accepted;
}

822

823
bool SerialLink::setDataBits(int dataBits)
824
{
Bill Bonney's avatar
Bill Bonney committed
825 826 827 828 829 830
    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));
831
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
832 833 834 835
    }
    return accepted;
}

836
bool SerialLink::setStopBits(int stopBits)
837
{
Bill Bonney's avatar
Bill Bonney committed
838 839 840 841 842 843 844
    // 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));
845
        emit updateLink(this);
pixhawk's avatar
pixhawk committed
846 847 848
    }
    return accepted;
}
849 850 851 852

bool SerialLink::setDataBitsType(int dataBits)
{
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
853 854
    if (dataBits != m_dataBits) {
        m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
855
        accepted = true;
Bill Bonney's avatar
Bill Bonney committed
856 857
        if (m_port)
            accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
858
        emit updateLink(this);
859 860 861 862 863 864 865
    }
    return accepted;
}

bool SerialLink::setStopBitsType(int stopBits)
{
    bool accepted = false;
Bill Bonney's avatar
Bill Bonney committed
866 867
    if (stopBits != m_stopBits) {
        m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
868
        accepted = true;
Bill Bonney's avatar
Bill Bonney committed
869 870
        if (m_port)
            accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
871
        emit updateLink(this);
872 873 874
    }
    return accepted;
}