Raspberry Pi

Raspberry Qt – Part 7

Finding the serial port

There is one chunk of the code we really do need to discuss and that is the snippet of how the application chooses its serial port beginning around line 48 in serialthread.cpp. I even put a comment in the code to explain why it looks the way it does.

    // One cannot be certain about order if more than one serial port is on the system.
    // My HP development machine had only one physical serial port yet Ubuntu identified
    // ttys4 and ttys0. Naturally ttys4 ended up coming out of the list first. I have no idea what
    // device it thought was a serial port.
    //
    // Yes, it is a horrible waste of resources since foreach() makes a copy of the container/collection before
    // it begins working on it.
    QMap <QString, QSerialPortInfo> portMap;
    foreach( const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        portMap.insert( info.portName(), info);
    }

    foreach( QSerialPortInfo info, portMap)
    {
        QSerialPort serial;
        serial.setPort(info);
        QString txt;
        QTextStream strm( &txt);

        strm << "Testing: " << info.portName() << " manufacturer: " << info.manufacturer()
                 << " description: " << info.description() << " serial number: " << info.serialNumber()
                    << " baud: " << serial.baudRate() << " data: " << serial.dataBits() << " parity: " << serial.parity()
                       << " stop: " << serial.stopBits();

        LogikalLogger::Instance().logString( LogikalLogger::LL_INFO, txt);
        if (serial.open(QIODevice::ReadOnly))
        {
            serial.close();
            if (!portFound)
            {
                m_portInfo = info;
                txt = "port " + info.portName() + " chosen as device";
                LogikalLogger::Instance().logString( LogikalLogger::LL_INFO, txt);
                portFound = true;
                // don't crash out of the foreach, won't take long to spin through it.
            }
        }
        else
        {
            LogikalLogger::Instance().logString( LogikalLogger::LL_ERR, "Test failed: " + serial.errorString());
        }
    }

Believe it or not I had been using the code for finding the serial port over a number of years on different projects both personal and professional. Always just took the QList from availablePorts() and walked down it. Never had a problem. The machine I chose to use for this project gave me my first problem. While there is physically only one serial port, Ubuntu thinks there is both a ttys0 and ttys4 and the little caveat found with availablePorts() came back to bite me. I have no idea what this machine believes is ttys4 but, it came back first in the list and it successfully opened. Most frustrating! Software didn’t work and the mini-tester verified we were not connected.

As a result of that experience (remember: experience is what you get when you don’t get what you want) we now have 2 foreach() loops. The first creates a QMap ordered by port name. We are lucky that most operating systems number serial ports but start with a base name so they can be sorted.

Assignment 1:

Get your Linux environment set up to cleanly build and run the application on your desktop. Connect your cable to your Pi, tail out syslog and achieve the same results I have shown you in Part 6.

Assignment 2:

Modify the code in serialthread.cpp to read and use serial port information from a config/ini/whatever file. By information I mean port number, baud rate, data, parity and stop bits. Fall back to finding the first port if and only if you cannot successfully load the information or open the serial port.