SerialLink.cc 22.7 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 66

    // Set the port name
67 68 69 70 71 72 73 74 75
//    if (m_portName == "")
//    {
//        m_name = tr("Serial Link ") + QString::number(getId());
//    }
//    else
//    {
//        m_name = portname.trimmed();
//    }

lm's avatar
lm committed
76
    loadSettings();
pixhawk's avatar
pixhawk committed
77
}
78 79 80 81 82
void SerialLink::requestReset()
{
    QMutexLocker locker(&this->m_stoppMutex);
    m_reqReset = true;
}
pixhawk's avatar
pixhawk committed
83 84 85 86

SerialLink::~SerialLink()
{
    disconnect();
Bill Bonney's avatar
Bill Bonney committed
87 88
    if(m_port) delete m_port;
    m_port = NULL;
89 90
}

91
QList<QString> SerialLink::getCurrentPorts()
92
{
93
    m_ports.clear();
Bill Bonney's avatar
Bill Bonney committed
94
    // Example use QSerialPortInfo
Bill Bonney's avatar
Bill Bonney committed
95
    // [TODO] make this thread safe
96

97
    QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();
98

99 100
    if( portList.count() == 0){
        qDebug() << "No Ports Found" << m_ports;
101 102
    }

103
    foreach (const QSerialPortInfo &info, portList)
104
    {
Bill Bonney's avatar
Bill Bonney committed
105 106 107
//        qDebug() << "PortName    : " << info.portName()
//                 << "Description : " << info.description();
//        qDebug() << "Manufacturer: " << info.manufacturer();
108

109
        m_ports.append(info.portName());
110
    }
Bill Bonney's avatar
Bill Bonney committed
111
    return m_ports;
pixhawk's avatar
pixhawk committed
112 113
}

114 115 116 117 118
void SerialLink::loadSettings()
{
    // Load defaults from settings
    QSettings settings(QGC::COMPANYNAME, QGC::APPNAME);
    settings.sync();
119 120
    if (settings.contains("SERIALLINK_COMM_PORT"))
    {
Bill Bonney's avatar
Bill Bonney committed
121 122 123 124 125 126
        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();
127 128 129 130 131 132 133
    }
}

void SerialLink::writeSettings()
{
    // Store settings
    QSettings settings(QGC::COMPANYNAME, QGC::APPNAME);
134
    settings.setValue("SERIALLINK_COMM_PORT", getPortName());
135 136
    settings.setValue("SERIALLINK_COMM_BAUD", getBaudRateType());
    settings.setValue("SERIALLINK_COMM_PARITY", getParityType());
137 138 139
    settings.setValue("SERIALLINK_COMM_STOPBITS", getStopBits());
    settings.setValue("SERIALLINK_COMM_DATABITS", getDataBits());
    settings.setValue("SERIALLINK_COMM_FLOW_CONTROL", getFlowType());
140 141 142
    settings.sync();
}

pixhawk's avatar
pixhawk committed
143 144 145 146 147

/**
 * @brief Runs the thread
 *
 **/
148 149
void SerialLink::run()
{
pixhawk's avatar
pixhawk committed
150
    // Initialize the connection
151 152 153
    if (!hardwareConnect())
    {
        //Need to error out here.
154
        emit communicationError(getName(),"Error connecting: " + m_port->errorString());
155
        return;
156
    }
pixhawk's avatar
pixhawk committed
157 158

    // Qt way to make clear what a while(1) loop does
159 160
    qint64 msecs = QDateTime::currentMSecsSinceEpoch();
    qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch();
161 162 163
    quint64 bytes = 0;
    bool triedreset = false;
    bool triedDTR = false;
164 165
    qint64 timeout = 5000;

166 167
    forever
    {
168 169
        {
            QMutexLocker locker(&this->m_stoppMutex);
170
            if(m_stopp)
171
            {
172 173 174
                m_stopp = false;
                break; // exit the thread
            }
175

176 177 178 179 180 181 182
            if (m_reqReset)
            {
                m_reqReset = false;
                communicationUpdate(getName(),"Reset requested via DTR signal");
                m_port->setDataTerminalReady(true);
                msleep(250);
                m_port->setDataTerminalReady(false);
183 184
            }
        }
185 186 187 188 189 190 191 192 193 194 195 196

        if (m_transmitBuffer.size() > 0) {
            // send the data
            QMutexLocker lockWrite(&m_writeMutex);
            int num_written = m_port->write(m_transmitBuffer.constData());
            if (num_written > 0){
                m_transmitBuffer = m_transmitBuffer.remove(0,num_written);
            }

        }


197 198 199 200 201 202 203 204 205 206 207 208 209 210
        bool error = m_port->waitForReadyRead(500);

        if(error) { // Waits for 1/2 second [TODO][BB] lower to SerialLink::poll_interval?
            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;
            }
        } else {
211
//            qDebug() << "readyReadTime #"<< __LINE__;
212 213 214

        }
        if (bytes != m_bytesRead) // i.e things are good and data is being read.
215
        {
216
            bytes = m_bytesRead;
217 218 219 220
            msecs = QDateTime::currentMSecsSinceEpoch();
        }
        else
        {
221
            if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout)
222 223 224
            {
                //It's been 10 seconds since the last data came in. Reset and try again
                msecs = QDateTime::currentMSecsSinceEpoch();
225 226 227 228 229 230 231 232 233
                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;
                }
234 235 236
                if (!triedDTR && triedreset)
                {
                    triedDTR = true;
237
                    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 244 245
                }
                else if (!triedreset)
                {
                    qDebug() << "No data!!! Attempting reset via reboot command.";
246
                    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 250 251
                    triedreset = true;
                }
                else
                {
252
                    communicationUpdate(getName(),"No data to receive on COM port....");
253 254 255 256
                    qDebug() << "No data!!!";
                }
            }
        }
pixhawk's avatar
pixhawk committed
257
        MG::SLEEP::msleep(SerialLink::poll_interval);
258 259 260 261 262 263 264
    } // 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
265

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

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

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

282
//        qDebug() << "writeBytes " << m_portName << "tx'd" << b << "bytes:";
pixhawk's avatar
pixhawk committed
283

284 285
        // Increase write counter
        m_bitsSentTotal += size * 8;
286

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

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

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

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


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

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

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

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

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

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

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

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

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

    QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected()));

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

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

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

Bill Bonney's avatar
Bill Bonney committed
436 437 438 439 440 441
    // 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
442

Bill Bonney's avatar
Bill Bonney committed
443 444
    emit connected();
    emit connected(true);
445

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

449 450
    writeSettings();

Bill Bonney's avatar
Bill Bonney committed
451
    return true; // successful connection
pixhawk's avatar
pixhawk committed
452
}
453 454


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

812

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

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

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

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