Skip to content
Snippets Groups Projects
SerialLink.cc 24.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • pixhawk's avatar
    pixhawk committed
    /*=====================================================================
    ======================================================================*/
    /**
     * @file
     *   @brief Cross-platform support for serial ports
     *
     *   @author Lorenz Meier <mavteam@student.ethz.ch>
     *
     */
    
    #include <QTimer>
    #include <QDebug>
    
    #include <QSettings>
    
    pixhawk's avatar
    pixhawk committed
    #include <QMutexLocker>
    
    Bill Bonney's avatar
    Bill Bonney committed
    #include <qserialport.h>
    #include <qserialportinfo.h>
    
    pixhawk's avatar
    pixhawk committed
    #include "SerialLink.h"
    #include "LinkManager.h"
    
    #include "QGC.h"
    
    pixhawk's avatar
    pixhawk committed
    #include <MG.h>
    
    
    SerialLink::SerialLink(QString portname, int baudRate, bool hardwareFlowControl, bool parity,
                           int dataBits, int stopBits) :
    
    Bill Bonney's avatar
    Bill Bonney committed
        m_bytesRead(0),
        m_port(NULL),
    
    pixhawk's avatar
    pixhawk committed
    {
    
        // We're doing it wrong - because the Qt folks got the API wrong:
        // http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
        moveToThread(this);
    
    
        // Get the name of the current port in use.
        m_portName = portname.trimmed();
    
        if (m_portName == "" && getCurrentPorts().size() > 0)
    
            m_portName = m_ports.first().trimmed();
    
    pixhawk's avatar
    pixhawk committed
        // Set unique ID and add link to the list of links
    
    Bill Bonney's avatar
    Bill Bonney committed
        m_id = getNextLinkId();
    
        m_baud = baudRate;
    
        if (hardwareFlowControl)
        {
    
    Bill Bonney's avatar
    Bill Bonney committed
            m_flowControl = QSerialPort::HardwareControl;
    
    Bill Bonney's avatar
    Bill Bonney committed
            m_flowControl = QSerialPort::NoFlowControl;
    
    Bill Bonney's avatar
    Bill Bonney committed
            m_parity = QSerialPort::EvenParity;
    
    Bill Bonney's avatar
    Bill Bonney committed
            m_parity = QSerialPort::NoParity;
    
    Bill Bonney's avatar
    Bill Bonney committed
    
        m_dataBits = dataBits;
        m_stopBits = stopBits;
    
    pixhawk's avatar
    pixhawk committed
    
    
    lm's avatar
    lm committed
        loadSettings();
    
    Lorenz Meier's avatar
    Lorenz Meier committed
    
        qDebug() << "create SerialLink " << portname << baudRate << hardwareFlowControl
                 << parity << dataBits << stopBits;
        qDebug() << "m_portName " << m_portName;
    
    
        LinkManager::instance()->add(this);
    
    pixhawk's avatar
    pixhawk committed
    }
    
    void SerialLink::requestReset()
    {
        QMutexLocker locker(&this->m_stoppMutex);
        m_reqReset = true;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    SerialLink::~SerialLink()
    {
        disconnect();
    
    Bill Bonney's avatar
    Bill Bonney committed
        if(m_port) delete m_port;
        m_port = NULL;
    
    QList<QString> SerialLink::getCurrentPorts()
    
        QList<QSerialPortInfo> portList =  QSerialPortInfo::availablePorts();
    
        if( portList.count() == 0){
            qDebug() << "No Ports Found" << m_ports;
    
        foreach (const QSerialPortInfo &info, portList)
    
    Bill Bonney's avatar
    Bill Bonney committed
    //        qDebug() << "PortName    : " << info.portName()
    //                 << "Description : " << info.description();
    //        qDebug() << "Manufacturer: " << info.manufacturer();
    
            m_ports.append(info.portName());
    
    Bill Bonney's avatar
    Bill Bonney committed
        return m_ports;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    void SerialLink::loadSettings()
    {
        // Load defaults from settings
    
        QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
    
        if (settings.contains("SERIALLINK_COMM_PORT"))
        {
    
    Bill Bonney's avatar
    Bill Bonney committed
            m_portName = settings.value("SERIALLINK_COMM_PORT").toString();
    
    Bill Bonney's avatar
    Bill Bonney committed
            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();
    
        }
    }
    
    void SerialLink::writeSettings()
    {
        // Store settings
    
        QSettings settings(QGC::ORG_NAME, QGC::APPNAME);
    
        settings.setValue("SERIALLINK_COMM_PORT", getPortName());
    
        settings.setValue("SERIALLINK_COMM_BAUD", getBaudRateType());
        settings.setValue("SERIALLINK_COMM_PARITY", getParityType());
    
        settings.setValue("SERIALLINK_COMM_STOPBITS", getStopBits());
        settings.setValue("SERIALLINK_COMM_DATABITS", getDataBits());
        settings.setValue("SERIALLINK_COMM_FLOW_CONTROL", getFlowType());
    
        QString description = "X";
        foreach (QSerialPortInfo info,QSerialPortInfo::availablePorts())
        {
            if (m_portName == info.portName())
            {
                description = info.description();
                break;
            }
        }
        if (description.toLower().contains("mega") && description.contains("2560"))
        {
            type = "apm";
    
            qDebug() << "Attempting connection to an APM, with description:" << description;
        }
        else if (description.toLower().contains("px4"))
        {
            type = "px4";
    
            qDebug() << "Attempting connection to a PX4 unit with description:" << description;
        }
        else
        {
            type = "other";
    
            qDebug() << "Attempting connection to something unknown with description:" << description;
        }
    
    pixhawk's avatar
    pixhawk committed
        // Initialize the connection
    
            QString err("Could not create port.");
            if (m_port) {
                err = m_port->errorString();
            }
            emit communicationError(getName(),"Error connecting: " + err);
    //        disconnect(); // This tidies up and sends the necessary signals
    
    pixhawk's avatar
    pixhawk committed
    
        // Qt way to make clear what a while(1) loop does
    
        qint64 msecs = QDateTime::currentMSecsSinceEpoch();
        qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch();
    
    //    bool triedreset = false;
    //    bool triedDTR = false;
    
        qint64 timeout = 5000;
    
        int linkErrorCount = 0;
    
        forever {
    
                QMutexLocker locker(&this->m_stoppMutex);
    
                if(m_stopp) {
                    m_stopp = false;
                    break; // exit the thread
                }
    
                if (m_reqReset) {
                    m_reqReset = false;
                    emit communicationUpdate(getName(),"Reset requested via DTR signal");
                    m_port->setDataTerminalReady(true);
                    msleep(250);
                    m_port->setDataTerminalReady(false);
                }
    
            // If there are too many errors on this link, disconnect.
    
    Lorenz Meier's avatar
    Lorenz Meier committed
            if (isConnected() && (linkErrorCount > 1000)) {
    
                qDebug() << "linkErrorCount too high: disconnecting!";
    
                linkErrorCount = 0;
    
                emit communicationUpdate(getName(), tr("Disconnecting on too many link errors"));
    
            // Write all our buffered data out the serial port.
    
            if (m_transmitBuffer.count() > 0) {
    
                int numWritten = m_port->write(m_transmitBuffer);
    
                bool txSuccess = m_port->waitForBytesWritten(5);
    
                if (!txSuccess || (numWritten != m_transmitBuffer.count())) {
    
                    linkErrorCount++;
                    qDebug() << "TX Error! wrote" << numWritten << ", asked for " << m_transmitBuffer.count() << "bytes";
    
    
                    // Since we were successful, reset out error counter.
    
                    linkErrorCount = 0;
                }
    
    
                // Now that we transmit all of the data in the transmit buffer, flush it.
                m_transmitBuffer = m_transmitBuffer.remove(0, numWritten);
                m_writeMutex.unlock();
    
                // Log this written data for this timestep. If this value ends up being 0 due to
                // write() failing, that's what we want as well.
    
                QMutexLocker dataRateLocker(&dataRateMutex);
                logDataRateToBuffer(outDataWriteAmounts, outDataWriteTimes, &outDataIndex, numWritten, QDateTime::currentMSecsSinceEpoch());
    
            //wait n msecs for data to be ready
            //[TODO][BB] lower to SerialLink::poll_interval?
    
            bool success = m_port->waitForReadyRead(10);
    
                QByteArray readData = m_port->readAll();
                while (m_port->waitForReadyRead(10))
                    readData += m_port->readAll();
    
                if (readData.length() > 0) {
                    emit bytesReceived(this, readData);
    
    
                    // Log this data reception for this timestep
    
                    QMutexLocker dataRateLocker(&dataRateMutex);
                    logDataRateToBuffer(inDataWriteAmounts, inDataWriteTimes, &inDataIndex, readData.length(), QDateTime::currentMSecsSinceEpoch());
    
    
                    // Track the total amount of data read.
    
                    m_bytesRead += readData.length();
    
                    linkErrorCount = 0;
    
                linkErrorCount++;
    
            if (bytes != m_bytesRead) { // i.e things are good and data is being read.
    
                bytes = m_bytesRead;
    
            else {
                if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) {
    
                    //It's been 10 seconds since the last data came in. Reset and try again
                    msecs = QDateTime::currentMSecsSinceEpoch();
    
                    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;
                    }
    
    //                if (!triedDTR && triedreset) {
    //                    triedDTR = true;
    //                    emit communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal");
    //                    qDebug() << "No data!!! Attempting reset via DTR.";
    //                    m_port->setDataTerminalReady(true);
    //                    msleep(250);
    //                    m_port->setDataTerminalReady(false);
    //                }
    //                else if (!triedreset) {
    //                    qDebug() << "No data!!! Attempting reset via reboot command.";
    //                    emit communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command");
    //                    m_port->write("reboot\r\n",8);
    //                    triedreset = true;
    //                }
    //                else {
    //                    emit communicationUpdate(getName(),"No data to receive on COM port....");
    //                    qDebug() << "No data!!!";
    //                }
    
    pixhawk's avatar
    pixhawk committed
            MG::SLEEP::msleep(SerialLink::poll_interval);
    
        } // 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
    
    
            emit disconnected();
            emit connected(false);
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    void SerialLink::writeBytes(const char* data, qint64 size)
    {
    
    Bill Bonney's avatar
    Bill Bonney committed
        if(m_port && m_port->isOpen()) {
    
    pixhawk's avatar
    pixhawk committed
    
    
            QByteArray byteArray(data, size);
    
            m_writeMutex.lock();
            m_transmitBuffer.append(byteArray);
            m_writeMutex.unlock();
    
        } else {
            disconnect();
            // Error occured
            emit communicationError(getName(), tr("Could not send data - link %1 is disconnected!").arg(getName()));
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    /**
     * @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
     **/
    
    Bill Bonney's avatar
    Bill Bonney committed
        if(m_port && m_port->isOpen()) {
    
            const qint64 maxLength = 2048;
            char data[maxLength];
    
    Bill Bonney's avatar
    Bill Bonney committed
            qint64 numBytes = m_port->bytesAvailable();
    
            if(numBytes > 0) {
    
    pixhawk's avatar
    pixhawk committed
                /* Read as much data in buffer as possible without overflow */
                if(maxLength < numBytes) numBytes = maxLength;
    
    
    Bill Bonney's avatar
    Bill Bonney committed
                m_port->read(data, numBytes);
    
    pixhawk's avatar
    pixhawk committed
                QByteArray b(data, numBytes);
                emit bytesReceived(this, b);
            }
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    
    /**
     * @brief Get the number of bytes to read.
     *
     * @return The number of bytes to read
     **/
    
    Bill Bonney's avatar
    Bill Bonney committed
        if (m_port) {
            return m_port->bytesAvailable();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /**
     * @brief Disconnect the connection.
     *
     * @return True if connection has been disconnected, false if connection couldn't be disconnected.
     **/
    
        qDebug() << "disconnect";
        if (m_port)
            qDebug() << m_port->portName();
    
    Bill Bonney's avatar
    Bill Bonney committed
    
        if (isRunning())
    
    Bill Bonney's avatar
    Bill Bonney committed
                QMutexLocker locker(&m_stoppMutex);
                m_stopp = true;
    
    Bill Bonney's avatar
    Bill Bonney committed
            wait(); // This will terminate the thread and close the serial port
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bill Bonney's avatar
    Bill Bonney committed
            emit disconnected(); // [TODO] There are signals from QSerialPort we should use
    
    pixhawk's avatar
    pixhawk committed
    
    
        m_transmitBuffer.clear(); //clear the output buffer to avoid sending garbage at next connect
    
    
        qDebug() << "already disconnected";
        return true;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /**
     * @brief Connect the connection.
     *
     * @return True if connection has been established, false if connection couldn't be established.
     **/
    bool SerialLink::connect()
    
    Bill Bonney's avatar
    Bill Bonney committed
        if (isRunning())
            disconnect();
    
        {
            QMutexLocker locker(&this->m_stoppMutex);
    
    Bill Bonney's avatar
    Bill Bonney committed
            m_stopp = false;
    
    Bill Bonney's avatar
    Bill Bonney committed
    
        start(LowPriority);
    
        return true;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /**
     * @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.
     **/
    
    bool SerialLink::hardwareConnect(QString &type)
    
    Bill Bonney's avatar
    Bill Bonney committed
            qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port";
            m_port->close();
    
    Bill Bonney's avatar
    Bill Bonney committed
            delete m_port;
            m_port = NULL;
    
    pixhawk's avatar
    pixhawk committed
    
    
        qDebug() << "SerialLink: hardwareConnect to " << m_portName;
        m_port = new QSerialPort(m_portName);
    
        if (!m_port) {
            emit communicationUpdate(getName(),"Error opening port: " + m_portName);
    
    Bill Bonney's avatar
    Bill Bonney committed
            return false; // couldn't create serial port.
    
    Bill Bonney's avatar
    Bill Bonney committed
    
        QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected()));
    
        QObject::connect(m_port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(linkError(QSerialPort::SerialPortError)));
    
    Bill Bonney's avatar
    Bill Bonney committed
    
    
    pixhawk's avatar
    pixhawk committed
    
    
        //    port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead);
    
        if (!m_port->open(QIODevice::ReadWrite)) {
            emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
            m_port->close();
            return false; // couldn't open serial port
        }
    
    
        // Need to configure the port
        // NOTE: THE PORT NEEDS TO BE OPEN!
        if (!m_is_cdc) {
            qDebug() << "Configuring port";
            m_port->setBaudRate(m_baud);
            m_port->setDataBits(static_cast<QSerialPort::DataBits>(m_dataBits));
            m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(m_flowControl));
            m_port->setStopBits(static_cast<QSerialPort::StopBits>(m_stopBits));
            m_port->setParity(static_cast<QSerialPort::Parity>(m_parity));
        }
    
    
        emit communicationUpdate(getName(),"Opened port!");
    
    
    Bill Bonney's avatar
    Bill Bonney committed
        emit connected();
        emit connected(true);
    
        qDebug() << "CONNECTING LINK: " << __FILE__ << __LINE__ << "type:" << type << "with settings" << m_port->portName()
    
    Bill Bonney's avatar
    Bill Bonney committed
                 << getBaudRate() << getDataBits() << getParityType() << getStopBits();
    
    Bill Bonney's avatar
    Bill Bonney committed
        return true; // successful connection
    
    pixhawk's avatar
    pixhawk committed
    }
    
    void SerialLink::linkError(QSerialPort::SerialPortError error)
    
        if (error != QSerialPort::NoError) {
    
            // You can use the following qDebug output as needed during development. Make sure to comment it back out
            // when you are done. The reason for this is that this signal is very noisy. For example if you try to
            // connect to a PixHawk before it is ready to accept the connection it will output a continuous stream
            // of errors until the Pixhawk responds.
            //qDebug() << "SerialLink::linkError" << error;
    
    pixhawk's avatar
    pixhawk committed
    /**
     * @brief Check if connection is active.
     *
     * @return True if link is connected, false otherwise.
     **/
    
    bool SerialLink::isConnected() const
    
    Bill Bonney's avatar
    Bill Bonney committed
    
        if (m_port) {
            bool isConnected = m_port->isOpen();
    
    //        qDebug() << "SerialLink #" << __LINE__ << ":"<<  m_port->portName()
    //                 << " isConnected =" << QString::number(isConnected);
    
    Bill Bonney's avatar
    Bill Bonney committed
            return isConnected;
    
    //        qDebug() << "SerialLink #" << __LINE__ << ":" <<  m_portName
    //                 << " isConnected = NULL";
    
    lm's avatar
    lm committed
            return false;
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bill Bonney's avatar
    Bill Bonney committed
        return m_id;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    QString SerialLink::getName() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    /**
      * This function maps baud rate constants to numerical equivalents.
      * It relies on the mapping given in qportsettings.h from the QSerialPort library.
      */
    
    qint64 SerialLink::getConnectionSpeed() const
    
    Bill Bonney's avatar
    Bill Bonney committed
        int baudRate;
    
    Bill Bonney's avatar
    Bill Bonney committed
            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
        }
        return dataRate;
    }
    
    
    QString SerialLink::getPortName() const
    
    Bill Bonney's avatar
    Bill Bonney committed
        return m_portName;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bill Bonney's avatar
    Bill Bonney committed
    // We should replace the accessors below with one to get the QSerialPort
    
    
    int SerialLink::getBaudRate() const
    
        return getConnectionSpeed();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    int SerialLink::getBaudRateType() const
    
    Bill Bonney's avatar
    Bill Bonney committed
        int baudRate;
    
    Bill Bonney's avatar
    Bill Bonney committed
            baudRate = m_port->baudRate();
        } else {
            baudRate = m_baud;
        }
        return baudRate;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    int SerialLink::getFlowType() const
    
    Bill Bonney's avatar
    Bill Bonney committed
        int flowControl;
    
    Bill Bonney's avatar
    Bill Bonney committed
            flowControl = m_port->flowControl();
        } else {
            flowControl = m_flowControl;
        }
        return flowControl;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    int SerialLink::getParityType() const
    
    Bill Bonney's avatar
    Bill Bonney committed
        int parity;
    
    Bill Bonney's avatar
    Bill Bonney committed
            parity = m_port->parity();
        } else {
            parity = m_parity;
        }
        return parity;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    int SerialLink::getDataBitsType() const
    
    Bill Bonney's avatar
    Bill Bonney committed
        int dataBits;
    
    Bill Bonney's avatar
    Bill Bonney committed
            dataBits = m_port->dataBits();
        } else {
            dataBits = m_dataBits;
        }
        return dataBits;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    int SerialLink::getStopBitsType() const
    
    Bill Bonney's avatar
    Bill Bonney committed
        int stopBits;
    
    Bill Bonney's avatar
    Bill Bonney committed
            stopBits = m_port->stopBits();
        } else {
            stopBits = m_stopBits;
        }
        return stopBits;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    int SerialLink::getDataBits() const
    
    Bill Bonney's avatar
    Bill Bonney committed
        int ret;
        int dataBits;
    
    Bill Bonney's avatar
    Bill Bonney committed
            dataBits = m_port->dataBits();
        } else {
            dataBits = m_dataBits;
        }
    
        switch (dataBits) {
        case QSerialPort::Data5:
    
    Bill Bonney's avatar
    Bill Bonney committed
        case QSerialPort::Data6:
    
    Bill Bonney's avatar
    Bill Bonney committed
        case QSerialPort::Data7:
    
    Bill Bonney's avatar
    Bill Bonney committed
        case QSerialPort::Data8:
    
    int SerialLink::getStopBits() const
    
    Bill Bonney's avatar
    Bill Bonney committed
        int stopBits;
    
    Bill Bonney's avatar
    Bill Bonney committed
            stopBits = m_port->stopBits();
        } else {
            stopBits = m_stopBits;
        }
    
    Bill Bonney's avatar
    Bill Bonney committed
        switch (stopBits) {
        case QSerialPort::OneStop:
    
    Bill Bonney's avatar
    Bill Bonney committed
        case QSerialPort::TwoStop:
    
            ret = 2;
            break;
        default:
            ret = -1;
            break;
        }
    
    pixhawk's avatar
    pixhawk committed
    bool SerialLink::setPortName(QString portName)
    {
    
    Bill Bonney's avatar
    Bill Bonney committed
        qDebug() << "current portName " << m_portName;
        qDebug() << "setPortName to " << portName;
    
    Bill Bonney's avatar
    Bill Bonney committed
        if ((portName != m_portName)
                && (portName.trimmed().length() > 0)) {
            m_portName = portName.trimmed();
    
    Bill Bonney's avatar
    Bill Bonney committed
            if(m_port)
                m_port->setPortName(portName);
    
            emit nameChanged(m_portName); // [TODO] maybe we can eliminate this
    
            emit updateLink(this);
    
    Bill Bonney's avatar
    Bill Bonney committed
            return accepted;
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bill Bonney's avatar
    Bill Bonney committed
        return false;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    bool SerialLink::setBaudRateType(int rateIndex)
    {
    
      // These minimum and maximum baud rates were based on those enumerated in qserialport.h
    
    Bill Bonney's avatar
    Bill Bonney committed
        const int minBaud = (int)QSerialPort::Baud1200;
        const int maxBaud = (int)QSerialPort::Baud115200;
    
        if ((rateIndex >= minBaud && rateIndex <= maxBaud))
    
            if (!m_is_cdc && m_port)
            {
                result = m_port->setBaudRate(static_cast<QSerialPort::BaudRate>(rateIndex));
                emit updateLink(this);
            } else {
                m_baud = (int)rateIndex;
                result = true;
            }
        } else {
            result = false;
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    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
    
    bool SerialLink::setBaudRate(int rate)
    {
    
    Bill Bonney's avatar
    Bill Bonney committed
        bool accepted = false;
        if (rate != m_baud) {
            m_baud = rate;
            accepted = true;
    
    Bill Bonney's avatar
    Bill Bonney committed
                accepted = m_port->setBaudRate(rate);
    
            emit updateLink(this);
    
    pixhawk's avatar
    pixhawk committed
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    bool SerialLink::setFlowType(int flow)
    {
    
    Bill Bonney's avatar
    Bill Bonney committed
        bool accepted = false;
        if (flow != m_flowControl) {
            m_flowControl = static_cast<QSerialPort::FlowControl>(flow);
            accepted = true;
    
    Bill Bonney's avatar
    Bill Bonney committed
                accepted = m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(flow));
    
            emit updateLink(this);
    
    pixhawk's avatar
    pixhawk committed
        }
        return accepted;
    }
    
    
    bool SerialLink::setParityType(int parity)
    {
    
    Bill Bonney's avatar
    Bill Bonney committed
        bool accepted = false;
        if (parity != m_parity) {
            m_parity = static_cast<QSerialPort::Parity>(parity);
            accepted = true;
    
    Bill Bonney's avatar
    Bill Bonney committed
                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;
                    }
    
                emit updateLink(this);
    
    Bill Bonney's avatar
    Bill Bonney committed
            }
    
    pixhawk's avatar
    pixhawk committed
        }
        return accepted;
    }
    
    
    bool SerialLink::setDataBits(int dataBits)
    
    Bill Bonney's avatar
    Bill Bonney committed
        bool accepted = false;
        if (dataBits != m_dataBits) {
            m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
            accepted = true;
    
    Bill Bonney's avatar
    Bill Bonney committed
                accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
    
            emit updateLink(this);
    
    pixhawk's avatar
    pixhawk committed
        }
        return accepted;
    }
    
    
    bool SerialLink::setStopBits(int stopBits)
    
    Bill Bonney's avatar
    Bill Bonney committed
        // Note 3 is OneAndAHalf stopbits.
        bool accepted = false;
        if (stopBits != m_stopBits) {
            m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
            accepted = true;
    
    Bill Bonney's avatar
    Bill Bonney committed
                accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
    
            emit updateLink(this);
    
    pixhawk's avatar
    pixhawk committed
        }
        return accepted;
    }
    
    
    bool SerialLink::setDataBitsType(int dataBits)
    {
    
    Bill Bonney's avatar
    Bill Bonney committed
        if (dataBits != m_dataBits) {
            m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
    
    Bill Bonney's avatar
    Bill Bonney committed
                accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
    
            emit updateLink(this);
    
        }
        return accepted;
    }
    
    bool SerialLink::setStopBitsType(int stopBits)
    {
    
    Bill Bonney's avatar
    Bill Bonney committed
        if (stopBits != m_stopBits) {
            m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
    
    Bill Bonney's avatar
    Bill Bonney committed
                accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
    
            emit updateLink(this);