Convert 2 bytes QByteArray read from serial port into a int
-
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
-
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 orderand 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.
-
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
@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. -
@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.@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 -
@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@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 compilershort int
is 16 bits wide per default. ;) -
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? -
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?@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 -
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?@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); -
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?@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 endsI 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.