read data from serial port



  • I ask this question before and I could not make the problem clear
    because it's not a good question
    so I delete the last topic and post new one with new details
    I want to read data from USB port of raspberry pi and convert it to string for save it to excel file
    also get the first number in string line and emit it for use it to an other function

    #include "MyThread.h"
    #include <wiringSerial.h>
    #include <sstream>
    #include <fstream>
    #include <iostream>
    #include <string>
    
    void MyThread::run()
    {
    
        qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
    
        int fd ,x;
        
          
        if ((fd = serialOpen ("/dev/ttyACM0",230400)) < 0)
        {
            fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
        }
    
        while (serialDataAvail(fd)>-2)
        {
             //-------value format is int-------
            value=serialGetchar (fd) ; 
         //--------NewValue format is string------
          NewValue.push_back(value);
          qDebug()<<NewValue.c_str();
       //   nm=NewValue.back();
       //   cout<<nm<<endl;
             if (!WriteNewRecord(NewValue)) {
               fstream FileStream;
                  FileStream << NewValue <<endl;
                            }
                      
            msleep(1); 
           emit signalValueUpdated(x);
      
        }
        serialClose(fd);
    
    
    }
    
    
    

    the data that receive is number between -1 to 255,currentDate,currentTime
    like 85,2018/8/3,17:21:3
    9,2018/8/27,1:40:34
    -the length is not fixed!
    -for 1 sec I receive 314 samples so they have same time stamp
    I want to get just number,before first " , "( that between -1,255,not date and time ) with int format to call in emit signalValueUpdated(x); for use in other place;
    with stoi() and .toInt() ,the output is zero
    NewValue.split(", ")[0].toInt(); just get the first byte of NewValue
    How can I do this?


  • Qt Champions 2017

    hi
    In not sure why split and toInt dont work for u ?

    QString input{"85,2018/8/3,17:21:3"};
    QStringList values = input.split(",");
    qDebug() << values[0].toInt();
    

    gives 85.



  • @mrjj I read from serial in while
    and get 314 sps per second ,
    and push_back them in string ,when I use the split it do it from the beginning of string NewValue , it doesn't split just new line that receive
    and .toInt() return zero
    how can do it just for new line data that receive?


  • Qt Champions 2017

    @isan
    You mean data comes like
    85,2018/8/3,17:21:3
    85,2018/8/3,17:21:3
    85,2018/8/3,17:21:3
    85,2018/8/3,17:21:3
    with newline in between ?



  • @mrjj the data that receive is like:
    when print with qDebug<<NewValue.c_str();
    85,2018/8/3,17:21:3
    98,2018/8/3,17:21:3
    102,2018/8/3,17:21:3
    9,2018/8/3,17:21:3
    .......(until 314 samples )
    167,2018/8/3,17:21:4
    34,2018/8/3,17:21:4
    28,2018/8/3,17:21:4
    85,2018/8/3,17:21:4
    .......(until 314 samples )


  • Qt Champions 2017

    so every time value variable is \n
    you have a full line in NewValue and can split and take value.



  • @mrjj with this:

    QStringList values = input.split(",");
    qDebug() << values[0].toInt();
    

    that you said?
    I change my code:

    void MyThread::run()
    {
    
        qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
    
        int fd ,x;
        
          
        if ((fd = serialOpen ("/dev/ttyACM0",230400)) < 0)
        {
            fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
        }
    
        while (serialDataAvail(fd)>-2)
        {
             //-------value format is int-------
            value=serialGetchar (fd) ;
        //--------vs format is QString------
        vs.push_back(value);
         //--------values format is QStringList------
         values = input.split(",");
          x= values[0].toInt();
     msleep(1); 
           emit signalValueUpdated(x);
      
        }
        serialClose(fd); 
    }
    

    the first line that receive is 96,2018/8/3,21:35:40
    the emit signalValueUpdated(x); is 96 for ever


  • Qt Champions 2017

    hi
    well you only ask for first value!
    values = input.split(","); // makes long list (potentially )
    x= values[0].toInt(); // take only first in list

    so it would be more like

    for ( const QString& valline : values ) {
          qDebug() << "val =" << valline.toInt();
        }
    

    and since list also contains other data, it looks like
    96
    2018/8/3
    21:35:40
    80
    2018/8/3
    21:35:40
    90
    2018/8/3
    21:35:40
    so value every 3 index



  • @mrjj I should use this :

    for ( const QString& valline : values ) {
        qDebug() << "val =" << valline.toInt();
      }
    

    instead of this :

    x= values[0].toInt();
    

    am I right?

    qDebug() << "val =" << valline.toInt();
    

    always returns zero to me!


  • Qt Champions 2017

    @isan
    hmm
    maybe input is not as you expect then.
    try qDebug() << values;
    to see what it has



  • @mrjj said in read data from serial port:

    qDebug() << values;

    return :
    \n191", "2018/8/3", "23:28:55 \r\n187", "2018/8/3", "23:28:55 \r\n185", "2018/8/3", "23:28:55 \r\n164", "2018/8/3", "23:28:55 \r\n131", "2018/8/3", "23:28:55 \r\n103", "2018/8/3", "23:28:55 \r\n....................................


  • Qt Champions 2017

    Ok so when we only split at ","
    We get \n\r on some/all of the values.
    Using something Like ReadLine might be easier.
    but you seem to use native serial comm and not Qt version?
    but you can try
    for ( const QString& valline : values ) {
    qDebug() << "val =" << valline.trimmed().toInt();
    }
    Trimmed() should remove the \n\r
    http://doc.qt.io/qt-5/qstring.html#trimmed

    ah. wait.
    it looks like some of the values are in same index as timestamp
    "23:28:55 \r\n187"


  • Qt Champions 2017

    Hi
    Im not really sure what is happening.
    Seems to not to be structured as we think/needs more splitting

    QString input{"85,2018/8/3,17:21:3\\n\\r85,2018/8/3,17:21:3\\n\\r95,2018/8/3,17:21:3"};
      QStringList lines = input.split("\\n\\r");
      for ( const QString& line : lines) {
        QStringList values = line.split(",");
        for ( const QString& valline : values ) {
          qDebug() << "val =" << valline.trimmed().toInt();
        }
      }
    

    val = 85
    val = 0
    val = 0
    val = 85
    val = 0
    val = 0
    val = 95
    val = 0
    val = 0

    when do you start processing the input ?
    After it all have been read or how do u know that input is ready ?



  • @mrjj it's return zero and sometimes 2018

    when do you start processing the input ?
    After it all have been read or how do u know that input is ready ?

    I'm not sure what you mean?
    read from serial port in thread and thread start in other class constructor.
    so it's start when program run!
    data send from arduino that connected to raspberry pi with USB port


  • Qt Champions 2017

    @isan
    Looking at the code, it seems to me you
    send al data and thread will read it all. and then close serial.
    so

    while (serialDataAvail(fd) > -2) {
      //-------value format is int-------
      value = serialGetchar (fd) ;
      //--------vs format is QString------
      vs.push_back(value);  
     }
     serialClose(fd);
     
     // here u should have complete data and can use 
    to get the values if data is complete
    input would be vs
    
      QStringList lines = input.split("\\n\\r");
      for ( const QString& line : lines) {
        QStringList values = line.split(",");
        for ( const QString& valline : values ) {
          qDebug() << "val =" << valline.trimmed().toInt();
        }
      }
    }
    


  • @mrjj
    I have no idea of the implications, but you have pasted code for OP as:

      QStringList lines = input.split("\\n\\r");
    

    If he is supposed to be copying this, shouldn't he be using

      QStringList lines = input.split("\r\n");
    

    Or, from his qDebug(), does it mean that the input literally has the 4-character sequence \r\n in it, and not CR-LF? In which case he would want

    QStringList lines = input.split("\\r\\n");
    
    

  • Qt Champions 2017

    @JonB
    Thank you , yes u are right its \r\n :) (of cause)
    or \r\n when escaped.



  • Now, going back to where @isan wrote:

    return :
     \n191", "2018/8/3", "23:28:55 \r\n187", "2018/8/3", "23:28:55 \r\n185", "2018/8/3", "23:28:55 \r\n164", "2018/8/3", "23:28:55 \r\n131", "2018/8/3", "23:28:55 \r\n103", "2018/8/3", "23:28:55 \r\n....................................
    

    So if that's really right, after first splitting on "\r\n" (not even certain about that if the input really starts as shown with just \n and not \r\n, I'll just assume it's really \r\n), he then needs to split on "\",\"", not just plain ,. Then at the end of that you have 3 clean tokens per line.

    I have to say the input looks a bit oddly tokenized/quoted, but that's what corresponds to the input he shows. If you're not careful and leave " characters in, you'll get toInt() returning 0 where you don't expect.


  • Qt Champions 2017

    @JonB
    Hi
    I think the "s comes from qDebug and is not in the input. (looking at the sending code higher up)
    It seems he reads the entire load in one go and closes port so that means he should be able to
    read complete string and then split it. ( i hope )



  • @mrjj said in read data from serial port:

    @isan
    Looking at the code, it seems to me you
    send al data and thread will read it all. and then close serial.
    so

    while (serialDataAvail(fd) > -2) {
      //-------value format is int-------
      value = serialGetchar (fd) ;
      //--------vs format is QString------
      vs.push_back(value);  
     }
     serialClose(fd);
     
     // here u should have complete data and can use 
    to get the values if data is complete
    input would be vs
    
      QStringList lines = input.split("\\n\\r");
      for ( const QString& line : lines) {
        QStringList values = line.split(",");
        for ( const QString& valline : values ) {
          qDebug() << "val =" << valline.trimmed().toInt();
        }
      }
    }
    

    Data is always sent and It does not go out of while() and I can not wait for complete data
    Upon receive, I must use the data in other classes
    I should not miss any data, if I close the port, the data will be lost


  • Qt Champions 2017

    @isan
    ok so it must be on the fly.

    Then you need to use 2 buffers as not to parse already received data over and over.
    so in pseudo code

    Read char from serial
    tempbuffer += char
    if char is \n then
    split tempbuffer
    emit value
    clear tempbuffer

    //i assume u want to store all ?
    Mainbuffer +=char



  • @mrjj so the code is like:

    void MyThread::run()
    {
    
        qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
    
        int fd ,x;
        
          
        if ((fd = serialOpen ("/dev/ttyACM0",230400)) < 0)
        {
            fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
        }
    
        while (serialDataAvail(fd)>-2)
        {
             //-------value format is int -------//
            value=serialGetchar (fd) ;
         //--------vs format is QString------//
             vs.push_back(value);
        //--------tempbuffer format is QString------//
       tempbuffer .append( vs);
       if (vs=="\n")
      //-------- values format is QStringList------//
         values = tempbuffer.split(",");
          x= values[0].toInt();
     msleep(1); 
           emit signalValueUpdated(x);
           tempbuffer.clear();
      
        }
        serialClose(fd); 
    }
    

    is it true?


  • Qt Champions 2017

    @isan
    Hi
    Almost, you need to clear tempbuffer as soon as you have used it.
    And u need to check last read char (value) being the \n

    void MyThread::run() {
    
      qDebug("Thread id inside run %d", (int)QThread::currentThreadId());
    
      int fd, x=0;
    
    
      if ((fd = serialOpen ("/dev/ttyACM0", 230400)) < 0) {
        fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
      }
    
      while (serialDataAvail(fd) > -2) {
        value = serialGetchar (fd) ;
        vs.push_back(value);
        tempbuffer += value;
        if (value == '\n') {
          values = tempbuffer.split(",");
          x = values[0].toInt();
          tempbuffer.clear();
        }
        msleep(1);
        emit signalValueUpdated(x);
        
    
      }
      serialClose(fd);
    }
    


  • @mrjj , @isan
    This code looks wrong. It doesn't help that we don't see the declarations of vs or tempbuffer. Comment:

    //--------tempbuffer format is QStringList------//

    No, it isn't, because later you go tempbuffer.split(",");. So it's probably a QString.

    Then: you read 1 char, you append it to vs. Then you append vs to tempbuffer. If value is not \n, you pick up the next char, append that to vs (now 2 chars long), append that to tempBuffer (now 3 chars long)...

    Hmm, vs must be a single char, not a QString like the comment says it is? Who knows....

    Separate issue:

    while (serialDataAvail(fd)>-2)
    

    Nope. serialDataAvail(fd) returns -1 on error. The code accepts that as a legal. It also should therefore never exit the while loop. Further, if 0 bytes are available code goes into the value=serialGetchar (fd) call. After 10 seconds of no data that will return -1. At which point accepts that as the legal char received. Finally, if error opening device in the first place, the code writes a message and then continues into the loop, which makes no sense.

    All this code really needs correcting....

    Finally, have a think about the fact that sometimes you are using Qt & C++ functions, sometimes you are doing lowest-level C library calls. Do you really need to mix them?


  • Qt Champions 2017

    +@JonB
    Thx, yes value should be added to tempbuffer.
    Then i can learn not to edit code in forum directly :)
    So something like this + all than @JonB said

    while (serialDataAvail(fd) > -2) { // fix condition! 
        value = serialGetchar (fd) ;// read char
        vs.push_back(value); // store in ful buffer
        tempbuffer += value; // add to tempbuffer
        if (value == '\n') { // if we just read \n
          values = tempbuffer.split(","); // split on , to QStringList
          x = values[0].toInt(); // take first index and convert to int
          tempbuffer.clear(); // clear it for next 
        }
    ......
    


  • I‘ve been following this thread for a while now, and you guy‘s doing a great job :-)

    Just one thing that‘s been buging me from the beginning.

    The call off split on the string. It‘s used for nothing but temporary storage to than turn the first entry into an INT.

    I would highly recommand to at least use splitref.



  • @mrjj Thanks for keep helping to solve my problem
    It's work!


  • Qt Champions 2017

    @isan
    Super :) \O/


  • Qt Champions 2017

    @J.Hilk
    Yes i agree. but in this case we wanted to split very small sample so
    i decided not to introduce new classes. (QVector/QStringRef)
    as to focus on getting it running. But yes, much better to use normally as the speed gain is huge for large dataset. (more than i did imagine)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.