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
{
    // Setup settings
Bill Bonney's avatar
Bill Bonney committed
32
    m_portName = portname.trimmed();
33

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

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

    m_baud = baudRate;
43

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

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

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

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

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

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

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

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

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

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

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

106 107 108
void SerialLink::loadSettings()
{
    // Load defaults from settings
109
    QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
110
    settings.sync();
111 112
    if (settings.contains("SERIALLINK_COMM_PORT"))
    {
Bill Bonney's avatar
Bill Bonney committed
113 114 115 116 117 118
        m_portName = settings.value("SERIALLINK_COMM_PORT").toString();
        m_baud = settings.value("SERIALLINK_COMM_BAUD").toInt();
        m_parity = settings.value("SERIALLINK_COMM_PARITY").toInt();
        m_stopBits = settings.value("SERIALLINK_COMM_STOPBITS").toInt();
        m_dataBits = settings.value("SERIALLINK_COMM_DATABITS").toInt();
        m_flowControl = settings.value("SERIALLINK_COMM_FLOW_CONTROL").toInt();
119 120 121 122 123 124
    }
}

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

pixhawk's avatar
pixhawk committed
135 136 137 138 139

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

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

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

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

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

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

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

202
        if (success) {
203 204 205 206 207 208 209 210 211
            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;
212
                linkErrorCount = 0;
213
            }
214 215
        }
        else {
216
            linkErrorCount++;
tstellanova's avatar
tstellanova committed
217
            //qDebug() << "Wait read response timeout" << QTime::currentTime().toString();
218
        }
219

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

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

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

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

281 282
        // Increase write counter
        m_bitsSentTotal += size * 8;
283

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

446 447
    writeSettings();

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

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

456

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

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

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

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

487 488 489 490
/**
  * This function maps baud rate constants to numerical equivalents.
  * It relies on the mapping given in qportsettings.h from the QSerialPort library.
  */
491
qint64 SerialLink::getNominalDataRate() const
492
{
Bill Bonney's avatar
Bill Bonney committed
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    int baudRate;
    if (m_port) {
        baudRate = m_port->baudRate();
    } else {
        baudRate = m_baud;
    }
    qint64 dataRate;
    switch (baudRate)
    {
        case QSerialPort::Baud1200:
            dataRate = 1200;
            break;
        case QSerialPort::Baud2400:
            dataRate = 2400;
            break;
        case QSerialPort::Baud4800:
            dataRate = 4800;
            break;
        case QSerialPort::Baud9600:
            dataRate = 9600;
            break;
        case QSerialPort::Baud19200:
            dataRate = 19200;
            break;
        case QSerialPort::Baud38400:
            dataRate = 38400;
            break;
        case QSerialPort::Baud57600:
            dataRate = 57600;
            break;
        case QSerialPort::Baud115200:
            dataRate = 115200;
            break;
            // Otherwise do nothing.
        case QSerialPort::UnknownBaud:
        default:
            dataRate = -1;
            break;
pixhawk's avatar
pixhawk committed
531 532 533 534
    }
    return dataRate;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pixhawk's avatar
pixhawk committed
711 712
bool SerialLink::setPortName(QString portName)
{
Bill Bonney's avatar
Bill Bonney committed
713 714 715 716 717 718
    qDebug() << "current portName " << m_portName;
    qDebug() << "setPortName to " << portName;
    bool accepted = false;
    if ((portName != m_portName)
            && (portName.trimmed().length() > 0)) {
        m_portName = portName.trimmed();
719
//        m_name = tr("serial port ") + portName.trimmed(); // [TODO] Do we need this?
Bill Bonney's avatar
Bill Bonney committed
720 721
        if(m_port)
            m_port->setPortName(portName);
722

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


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

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

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

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

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

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

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

814

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

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

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

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