Menu

New canReadLine() and readLine() routines

Anonymous
2016-01-01
2016-01-02
  • Anonymous

    Anonymous - 2016-01-01

    Hi Stefan,
    happy new 2016. I was away for a while because of my work.
    I'm studying your great QT source code and iI'm tryng to adapt some routines to my (Arduino) needs;

    I submit to your attention two simple routines (for reading serial data lines in a not-blocking manner) I've added to my personal version of scriptSerialPort.h:

    // PASERRA NEW SERIAL ROUTINES
        ///This function checks if a data line is ready to be read
        Q_INVOKABLE bool canReadLine(){return m_serialPort.canReadLine();}
    
        ///Returns serial bytes until EOL ('\n') char (not included).
        // the EOL recognition char is '\n' but this version accepts also "\r\n"
        Q_INVOKABLE QString readLine()
        {
            QByteArray data = m_serialPort.readLine();
            int size = data.size();
            int eol2 = (int)data.at(size-2);
    
            data.remove(size-1,1); // remove last char: EOL ('\n' )
    
            if (eol2 == 13) data.remove(size-2,1); //remove '\r' if present (see Arduino's Println())
    
            QString str(data); // send data without EOL char(s)
            return str;
        }
    

    this a short script to show how to use them:

    var str = ""; 
    
    function stopScript() 
    {
        serialPort.close();
        scriptThread.appendTextToConsole("script has been stopped");
    }
    
    scriptThread.appendTextToConsole('script has started');
    
    // serialPort readData routine
    function serialReceive()
    {
    if (serialPort.canReadLine()) {
    str = serialPort.readLine();
    var strArray = str.split(",");
    scriptThread.appendTextToConsole(strArray[1]); // if str is "1,2,3" it prints '2'
    return;
    }
    scriptThread.appendTextToConsole("not receive Line");
    }
    
    // serialPort
    var portName = "\\\\.\\COM3";
    var serialPort = scriptThread.createSerialPort();
    serialPort.readyReadSignal.connect(serialReceive);
    serialPort.setPortName(portName);
    
    serialPort.setDTR(false);
    
    if (serialPort.open())
    {
    serialPort.setBaudRate(115200); //115200
    serialPort.setDataBits(8);
    serialPort.setParity("None");
    serialPort.setStopBits("1");
    serialPort.setFlowControl("None");
    serialPort.setDTR(true);
    serialPort.setRTS(true);
    }
    else
    {
    scriptThread.messageBox("Critical", 'Error', 'Unable to open serial port');
    scriptThread.stopScript();
    }
    

    If you want you can modify/test/add the above code to the next official version of ScriptCommunivcator.
    Greetings,
    Pier Andrea.

     
  • Stefan Zieker

    Stefan Zieker - 2016-01-02

    Hi Pier ,

    nice to hear you again :-) and thx for your new idea. I will add this in the next version of ScriptCommunicator.

    Greetings,
    Stefan

     

    Last edit: Stefan Zieker 2016-01-02
  • Stefan Zieker

    Stefan Zieker - 2016-01-02

    Hi Pier,

    I changed your function to:

     ///This function reads a line (a line ends with a '\n') of ASCII characters.
    ///If removeNewLine is true then the '\n' will not returned (is removed from the received line)
    ///If removeCarriageReturn is true then a '\r' in front of '\n' will also not returned.
    ///Note: If no new data line is ready for reading this functions returns an empty string.
     Q_INVOKABLE QString readLine(bool removeNewLine=true, bool removeCarriageReturn=true)
        {
            QString result;
            if(canReadLine())
            {
                result = m_serialPort.readLine();
                if(removeNewLine && removeCarriageReturn)
                {
                    //Remove '\r\n'
                    result.replace("\r\n", "");
                }
                else if(removeNewLine)
                {
                    //Remove '\n'
                    result.replace("\n", "");
                }
            }
            return result;
        }
    

    Greetings,
    Stefan

     

    Last edit: Stefan Zieker 2016-01-02
  • Stefan Zieker

    Stefan Zieker - 2016-01-02

    Hi Pier,

    I have uploaded a new test version of ScriptCommunicator (Files/Test).

    Best regards,
    Stefan

     
  • Anonymous

    Anonymous - 2016-01-02

    Hi Stefan,
    your code is much more elegant than mine! I've started to program in QT just Yesterday and I have to learn much more things about this specific C++ implementation. I've discovered another thing about the readLine() routine. serialReceive() is called every time you have a serial event while readLine() returns ONLY a line of data. In case you have more lines of data waiting to be read (immagine that the MCU sends a lot of data at very high speed), they stay in the buffer until NEXT data is received (more lines to read). In this way you coud have an accumulation of incoming data in the input buffer. The ideal situation could be to check if there are more lines to read inside the serialReceive() routine before leaving it (i.e. a while cicle that checks if the readLine() return is an empty string.
    Cheers,
    Pier Andrea.

     

    Last edit: Anonymous 2016-01-02
  • Stefan Zieker

    Stefan Zieker - 2016-01-02

    Hi Pier,

    I do not know if I did understand you correctly. But I would write your QtScript function like this:

    // serialPort readData routine
    function serialReceive()
    {
        while (serialPort.canReadLine()) 
        {
            str = serialPort.readLine();
            var strArray = str.split(",");
            scriptThread.appendTextToConsole(strArray[1]); // if str is "1,2,3" it prints '2'
        }
    }
    

    Or do you mean this:

    Q_INVOKABLE QStringList readLines(bool removeNewLine=true, bool removeCarriageReturn=true)
        {
            QStringList result;
            while(canReadLine())
            {
                QString currentLine = m_serialPort.readLine());
                if(removeNewLine && removeCarriageReturn)
                {
                    //Remove '\r\n'
                    currentLine.replace("\r\n", "");
                }
                else if(removeNewLine)
                {
                    //Remove '\n'
                    currentLine.replace("\n", "");
                }
                result.append(currentLine);
            }
            return result;
        }
    

    Best regards,
    Stefan

     

    Last edit: Stefan Zieker 2016-01-02
  • Anonymous

    Anonymous - 2016-01-02

    Thank you Stefan,
    both the routines are useful! The fisrt routine is the classical approach (this in particular I had in my mind). The second routine is great: you can increae the parsing speed and immediately plot ASCII data!
    You are great!
    Pier Andrea.

     
  • Anonymous

    Anonymous - 2016-01-02

    I've found a strange behaviour in your last two routines (when only \n is present in the line they are unable to remove it (no problem with \r\n sequence); the following routines work very well altough no so elegant:

        Q_INVOKABLE QString readLine(bool removeNewLine=true, bool removeCarriageReturn=true)
           {
               QString result = "";
               if(canReadLine())
               {
                   result = m_serialPort.readLine();
                   if(removeNewLine) result.replace("\n", "");
                   if(removeCarriageReturn) result.replace("\r", "");
               }
               return result;
           }
    
        Q_INVOKABLE QStringList readLines(bool removeNewLine=true, bool removeCarriageReturn=true)
            {
                QStringList result;
    
                while(canReadLine())
                {
                    QString currentLine = m_serialPort.readLine();
                        if(removeNewLine) currentLine.replace("\n", "");
                        if(removeCarriageReturn) currentLine.replace("\r", "");
                    result.append(currentLine);
                }
                return result;
            }
    

    ReadLines seems to be the better routine for high performance data exchange:

    // serialPort readData routine
    function serialReceive()
    {
        var strArray = serialPort.readLines();
        if (strArray.length == 0) {
        scriptThread.appendTextToConsole("No Received Lines");
        return;
        }
        scriptThread.appendTextToConsole("Received Lines (N): " + strArray.length);
        for(var i=0; i<strArray.length;i++) scriptThread.appendTextToConsole(i + ") " + strArray[i]);
    }
    

    Cheers,
    Pier Andrea.

     

    Last edit: Anonymous 2016-01-02
  • Stefan Zieker

    Stefan Zieker - 2016-01-02

    Hi Pier,

    my solution has not the best performance. It should be implemented like this:

    Q_INVOKABLE QString readLine(bool removeNewLine=true, bool removeCarriageReturn=true)
        {
            QString result;
            if(m_serialPort.canReadLine())
            {
                QByteArray data = m_serialPort.readLine();
                int size = data.size();
                if(removeCarriageReturn && (size >= 2))
                {
                    if(data.at(size-2) == '\r')
                    {
                        //Remove '\r'.
                        data.remove(size-2, 1);
                        size--;
                    }
                }
                if(removeNewLine)
                {
                    //Remove '\n'.
                    data.remove(size-1 ,1);
                }
                result = data;
            }
            return result;
        }
    

    Cheers,
    Stefan Zieker

     

Anonymous
Anonymous

Add attachments
Cancel





Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.