Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    Unsolved Convert 2 bytes QByteArray read from serial port into a int

    General and Desktop
    5
    9
    590
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J
      JorisC last edited by

      Dear all,

      I have read a lot about how to convert a QByteArray into a int but without success in my case... That's why I post on this topic

      First, I have an arduino (MEGA) code which send and int with seria.write() function. For that, I realize an "union"

      union INT{
        int value;
        byte stream[2];
      };
      
      INT my_int
      

      And I stream it ( my_int.value= 125) over serial port:

      void setup(){
      serial.begin(9600);
      my_int.value = 125;   //my_int.stream =[7D, 00]
      
      void loop(){
      
      for (int i = 0; i<2; i++){
       Serial.write(my_int.stream[i]);
      }
      
      }
      

      On Qt side, located in my computer, I receive correctly the byte stream thanks to QSerialPort and readAll() function. Then I store it in a QByteArray as mentionned in QIODevice Class.

      I have a serialport class (serialport.h & serialport.cpp). I have a slot called onReadData() which is triggered by &QSerialPort::readyRead() signal. This is the nominal way to do as explained in many tutorials about how to receive datas from serial port on QT.

      This slot looks like:

      void SerialPort::onReadData()
      {
      
          if(arduino->bytesAvailable()>0){        
      
              QByteArray incomingdata = arduino->readAll();           
             qDebug()<<"incomingdata  = " << incomingdata ;
             qDebug()<<"incomingdata in HEX format  = " << incomingdata.toHex();
      

      This is working well !

      1-qDebug() shows:  incomingdata = "}\x00" 
      2-qDebug() shows:  incomingdata in HEX format = "7d00" 
      

      My problems start NOW !
      From my QByteArray incomingdata, how can I get back my_int = 125 ?

      I believed a union function was possible but it's not the case with QObject
      I tried with QDatastream but without success. I have tried both BigEndian and LittleEndian Byteorder.

              QByteArray ba("7d00");
              QDataStream ds(ba);
              ds.setByteOrder(QDataStream::BigEndian);  //same fail with LittleEndian
              qint16 x
                      ds>>x;
              qDebug() << "x = "<< x;
      

      I also tried with memcpy method and i doesn't work ... In fact, I get a value but this is not 125...

              QByteArray ba("7d00");
              qint16  outIntVar;
              memcpy(&outIntVar, ba.data(), sizeof(qint16));
      

      So I hope someone can tell me how to do to reach my goal and also what I am doing wrong ...
      After succeeding in this step I will have a larger byte stream coming from my arduino with a bytes frame containing int and float.

      Thanks in advance for your help.

      Jo

      KroMignon 1 Reply Last reply Reply Quote 0
      • Kent-Dorfman
        Kent-Dorfman last edited by Kent-Dorfman

        stuff to read up on...not just ask somoene to tell you how to do...

        data endian format
        native CPU word size
        sizeof(int) on each platform in question
        host byte order and network byte order

        and making the assumption that you will always be able to read exactly two bytes from the serial port is a bad idea. Data can arrive at any time, and in any quantity.

        1 Reply Last reply Reply Quote 4
        • KroMignon
          KroMignon @JorisC last edited by

          @JorisC said in Convert 2 bytes QByteArray read from serial port into a int:

          I believed a union function was possible but it's not the case with QObject

          First, you should know that int size depend on processor architecture.
          This means that for 16 bits processors, as on the Arduino board, int has 16 bits, but on you PC it will have 32bits!
          So this has nothing to do with Qt/QObject, this is processor/compiler specific.

          if you want it to work with any compiler, use short int, which will ever been 16 bits:

          union INT{
            short int value;
            byte stream[2];
          };
          

          Second: byte order may vary according to CPU architecture ==> cf. https://en.wikipedia.org/wiki/Endianness

          Third, a serial port is an asynchronous stream. When QSerialPort fires an event, it only means that it have received data, but this does not mean all data sent by Arduino have been received, maybe they will come with some delay.
          Up to you to handle this on the right way, there are many example available around internet.

          It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

          jeremy_k 1 Reply Last reply Reply Quote 3
          • jeremy_k
            jeremy_k @KroMignon last edited by

            @KroMignon said in Convert 2 bytes QByteArray read from serial port into a int:

            @JorisC said in Convert 2 bytes QByteArray read from serial port into a int:

            I believed a union function was possible but it's not the case with QObject

            What is a union function?

            First, you should know that int size depend on processor architecture.
            This means that for 16 bits processors, as on the Arduino board, int has 16 bits, but on you PC it will have 32bits!
            So this has nothing to do with Qt/QObject, this is processor/compiler specific.

            if you want it to work with any compiler, use short int, which will ever been 16 bits:

            A short int is at least 16 bits wide. It could be larger with a standard compliant compiler. In general, the integer types that don't explicitly specify a size have minimum but not maximum allowed widths.
            If the goal is exactly 16 bits, use int16_t or uint16_t (if available...)

            https://en.cppreference.com/w/cpp/language/types
            https://en.cppreference.com/w/cpp/types/integer

            Asking a question about code? http://eel.is/iso-c++/testcase/

            KroMignon 1 Reply Last reply Reply Quote 0
            • KroMignon
              KroMignon @jeremy_k last edited by

              @jeremy_k said in Convert 2 bytes QByteArray read from serial port into a int:

              A short int is at least 16 bits wide. It could be larger with a standard compliant compiler. In general, the integer types that don't explicitly specify a size have minimum but not maximum allowed widths.
              If the goal is exactly 16 bits, use int16_t or uint16_t (if available...)

              Yes, your are right, short int size may change but this implies that you setup your compiler to do it so.
              As you can see on the first link you give, for all compiler short int is 16 bits wide per default. ;)

              It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

              1 Reply Last reply Reply Quote 0
              • J
                JorisC last edited by

                Thanks to all for your time,

                I fully agree with what you told about int size and endianess problematic. I will set my int as uint16.
                I also can manage the serial reception in order to get the entire bytes stream.

                The question, if I refrase, is:
                What is the best way and best practice in Qt to convert the entire 2 byte stream representing my int (125) into this qint16 value.. Qdatastream? Memcpy?

                Christian Ehrlicher KroMignon Kent-Dorfman 3 Replies Last reply Reply Quote 0
                • Christian Ehrlicher
                  Christian Ehrlicher Lifetime Qt Champion @JorisC last edited by

                  @JorisC This depends on the endianess of the data and your os.
                  I would use boost::endian::big_to_native / little_to_native: https://www.boost.org/doc/libs/1_72_0/libs/endian/doc/html/endian.html#conversion_byte_reversal_functions

                  Qt has to stay free or it will die.

                  1 Reply Last reply Reply Quote 1
                  • KroMignon
                    KroMignon @JorisC last edited by

                    @JorisC said in Convert 2 bytes QByteArray read from serial port into a int:

                    What is the best way and best practice in Qt to convert the entire 2 byte stream representing my int (125) into this qint16 value.. Qdatastream? Memcpy?

                    "Best way" is always a little bit relative, in terms of performances, less lines of code or easy to understand...

                    As you will get the data in to QByteArray on Qt side, I think is to use qFromBigEndian<>() (cf. https://doc.qt.io/qt-5/qtendian.html#qFromBigEndian-1)
                    For example: ` value = qFromBigEndian<quint16>(ba);

                    It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                    1 Reply Last reply Reply Quote 1
                    • Kent-Dorfman
                      Kent-Dorfman @JorisC last edited by Kent-Dorfman

                      @JorisC said in Convert 2 bytes QByteArray read from serial port into a int:

                      The question, if I refrase, is:
                      What is the best way and best practice in Qt to convert the entire 2 byte stream representing my int (125) into this qint16 value.. Qdatastream? Memcpy?

                      assuming the following restriction:
                      specified and enforced little endian short int of 16 bits on both ends

                      I prefer
                      int v = 0;
                      memcpy(&v, &buffer[0], sizeof(short int));

                      or
                      v = buffer[0] | (buffer[1] << 8);
                      and it would be safer to explicitly cast the types of buffer[n] to avoid problems with upcasting and bit operations...but my example is lazy.

                      frame checking needs to be done on serial stream, either through inserting STX,ETX characters around the values, and/or, building in fixed and detectable idle periods between sending of values.

                      1 Reply Last reply Reply Quote 0
                      • First post
                        Last post