How to receive serial data sent as Struct and convert it to decimal
-
Hello everyone,
I am currently working on a project where I will send my data in the form of struct through serial communication. The member variables of the struct are such that each value to be transmitted is split into 2 int8 part. Now in my GUI, I want to receive this data, convert it back to its original decimal value.
Currently, my gui can receive the data ( in int8t form), but I am not able to write a code to convert it data back to decimal. I have attached my code for refrencedouble MainWindow::from16(int8_t MSB, int8_t LSB) { QByteArray LSBByte = QByteArray::number(LSB,2); if(LSBByte.size()>=9) LSBByte=LSBByte.remove(0,24); QByteArray MSBByte = QByteArray::number(MSB,2); if(MSBByte.size()>=9) MSBByte=MSBByte.remove(0,24); QByteArray ByteVal = (MSBByte.append(LSBByte)); qDebug()<< ByteVal.size(); double dec=0; int i = ByteVal.length()-1; while(i != 0){ QString tempChar = QString(ByteVal.at(i)); dec+= tempChar.at(0).digitValue()*pow(2,i); i--; } return dec/100; % ignore the /100 part } void MainWindow::readyData() { while(COMPORT->bytesAvailable()) { data = COMPORT->readAll(); memcpy(&temp.T1,data, sizeof(temp)); } SensorData.AccX.append(from16(temp.AccZMSB,temp.AccZLSB)); }
For some context SensorData is a struct with member AccX to which I want to append this converted data to.
from16 () is the function I made to convert 2 8 bit data back to decimalThis code can convert data back to a positive value such as 1000 but it fails if the data represents -900. Can someone tell me how I can convert 2 int8t data back to decimal.
Thanks in advance
strikethrough text -
@mpergand
So for eg say I want to send int x = -12345. This is what is do// RasPi Pico code for sending data // Data is a struct with member variables of type int8_t Data.T1 = (x>>8) & 0xFF; // T1 is of the type int8_t Data.T2 = x & 0xFF; // T2 is of the type int8_t Serial.write((char*)&Data,sizeof(Data)); //send data through serial port
in my GUI I can successfully receive these values and store them in a struct with member variables of the form int8_t.
Now I am not able to figure out a way to get back -12345. If x was 12345 my code works but it fails for -12345.For endianess, i think it is big endian format. I store the Left 8 bits in variable called MSB and the right 8bits in LSB.
I follow the same convention on both the transmitting and receiving end of my code. -
Hello everyone,
I am currently working on a project where I will send my data in the form of struct through serial communication. The member variables of the struct are such that each value to be transmitted is split into 2 int8 part. Now in my GUI, I want to receive this data, convert it back to its original decimal value.
Currently, my gui can receive the data ( in int8t form), but I am not able to write a code to convert it data back to decimal. I have attached my code for refrencedouble MainWindow::from16(int8_t MSB, int8_t LSB) { QByteArray LSBByte = QByteArray::number(LSB,2); if(LSBByte.size()>=9) LSBByte=LSBByte.remove(0,24); QByteArray MSBByte = QByteArray::number(MSB,2); if(MSBByte.size()>=9) MSBByte=MSBByte.remove(0,24); QByteArray ByteVal = (MSBByte.append(LSBByte)); qDebug()<< ByteVal.size(); double dec=0; int i = ByteVal.length()-1; while(i != 0){ QString tempChar = QString(ByteVal.at(i)); dec+= tempChar.at(0).digitValue()*pow(2,i); i--; } return dec/100; % ignore the /100 part } void MainWindow::readyData() { while(COMPORT->bytesAvailable()) { data = COMPORT->readAll(); memcpy(&temp.T1,data, sizeof(temp)); } SensorData.AccX.append(from16(temp.AccZMSB,temp.AccZLSB)); }
For some context SensorData is a struct with member AccX to which I want to append this converted data to.
from16 () is the function I made to convert 2 8 bit data back to decimalThis code can convert data back to a positive value such as 1000 but it fails if the data represents -900. Can someone tell me how I can convert 2 int8t data back to decimal.
Thanks in advance
strikethrough text@Vignesh-R
What is the initial format of the value, 16 bits integer ?
and what endianess ? -
@Vignesh-R
What is the initial format of the value, 16 bits integer ?
and what endianess ?@mpergand
So for eg say I want to send int x = -12345. This is what is do// RasPi Pico code for sending data // Data is a struct with member variables of type int8_t Data.T1 = (x>>8) & 0xFF; // T1 is of the type int8_t Data.T2 = x & 0xFF; // T2 is of the type int8_t Serial.write((char*)&Data,sizeof(Data)); //send data through serial port
in my GUI I can successfully receive these values and store them in a struct with member variables of the form int8_t.
Now I am not able to figure out a way to get back -12345. If x was 12345 my code works but it fails for -12345.For endianess, i think it is big endian format. I store the Left 8 bits in variable called MSB and the right 8bits in LSB.
I follow the same convention on both the transmitting and receiving end of my code. -
@mpergand
So for eg say I want to send int x = -12345. This is what is do// RasPi Pico code for sending data // Data is a struct with member variables of type int8_t Data.T1 = (x>>8) & 0xFF; // T1 is of the type int8_t Data.T2 = x & 0xFF; // T2 is of the type int8_t Serial.write((char*)&Data,sizeof(Data)); //send data through serial port
in my GUI I can successfully receive these values and store them in a struct with member variables of the form int8_t.
Now I am not able to figure out a way to get back -12345. If x was 12345 my code works but it fails for -12345.For endianess, i think it is big endian format. I store the Left 8 bits in variable called MSB and the right 8bits in LSB.
I follow the same convention on both the transmitting and receiving end of my code.@Vignesh-R
Untested, and this is not the right way to do it in C++, but following what you have done at the C/bit level doesx = ((Data.T1 << 8) & 0xFF00) | (Data.T2 & 0xFF)
get you back your original
x
? I assume yourx
is of typeshort
/int16_t
or similar (if not, say so!). Might be nicer if yourT1
/T2
wereuint8_t
instead ofint8_t
, can't imagine they are supposed be signed quantities given how they are used to formx
.Also your
Serial.write()
relies onData
struct being packed, note sure what it will do without that. -
@mpergand
So for eg say I want to send int x = -12345. This is what is do// RasPi Pico code for sending data // Data is a struct with member variables of type int8_t Data.T1 = (x>>8) & 0xFF; // T1 is of the type int8_t Data.T2 = x & 0xFF; // T2 is of the type int8_t Serial.write((char*)&Data,sizeof(Data)); //send data through serial port
in my GUI I can successfully receive these values and store them in a struct with member variables of the form int8_t.
Now I am not able to figure out a way to get back -12345. If x was 12345 my code works but it fails for -12345.For endianess, i think it is big endian format. I store the Left 8 bits in variable called MSB and the right 8bits in LSB.
I follow the same convention on both the transmitting and receiving end of my code. -
@Vignesh-R
Untested, and this is not the right way to do it in C++, but following what you have done at the C/bit level doesx = ((Data.T1 << 8) & 0xFF00) | (Data.T2 & 0xFF)
get you back your original
x
? I assume yourx
is of typeshort
/int16_t
or similar (if not, say so!). Might be nicer if yourT1
/T2
wereuint8_t
instead ofint8_t
, can't imagine they are supposed be signed quantities given how they are used to formx
.Also your
Serial.write()
relies onData
struct being packed, note sure what it will do without that.Thanks for the reply . x is in an int. Currently I have stored its 16 bit representation into 2 int8t variable ( named MSB and LSB).
Might be nicer if your T1/T2 were uint8_t instead of int8_t, can't imagine they are supposed be signed quantities given how they are used to form x
Thanks for this suggestion. Will look into it.
Also your Serial.write() relies on Data struct being packed, note sure what it will do without that
Can you elaborate on this? What do you mean by packed?
-
Thanks for the reply . x is in an int. Currently I have stored its 16 bit representation into 2 int8t variable ( named MSB and LSB).
Might be nicer if your T1/T2 were uint8_t instead of int8_t, can't imagine they are supposed be signed quantities given how they are used to form x
Thanks for this suggestion. Will look into it.
Also your Serial.write() relies on Data struct being packed, note sure what it will do without that
Can you elaborate on this? What do you mean by packed?
@Vignesh-R said in How to receive serial data sent as Struct and convert it to decimal:
x is in an int. Currently I have stored its 16 bit representation into 2 int8t variable
Then you have a problem.
int
is usually 32-bit, occasionally, 64-bit, never 16-bit since last century. Apart from the fact that you are losing data/precision when you break it into 16-bits/2x8-bits, this will also affect how you rebuild it from 16-bits. This may be part of your problem as to why you are failing to rebuild an original-negative 32-bit int from 2x8-bit.If you are only going to send it as 2x8-bit I would start by working from/to an
int16_t
so you known where you are.Can you elaborate on this? What do you mean by packed?
You have
Serial.write((char*)&Data,sizeof(Data));
You are assuming/relying on
T1
&T2
being contiguous in yourstruct
, and on it only being 16-bits wide. Neither of these may be the case if you have not told the compiler to pack thestruct
. How you do that can vary between compilers. -
@Vignesh-R said in How to receive serial data sent as Struct and convert it to decimal:
x is in an int. Currently I have stored its 16 bit representation into 2 int8t variable
Then you have a problem.
int
is usually 32-bit, occasionally, 64-bit, never 16-bit since last century. Apart from the fact that you are losing data/precision when you break it into 16-bits/2x8-bits, this will also affect how you rebuild it from 16-bits. This may be part of your problem as to why you are failing to rebuild an original-negative 32-bit int from 2x8-bit.If you are only going to send it as 2x8-bit I would start by working from/to an
int16_t
so you known where you are.Can you elaborate on this? What do you mean by packed?
You have
Serial.write((char*)&Data,sizeof(Data));
You are assuming/relying on
T1
&T2
being contiguous in yourstruct
, and on it only being 16-bits wide. Neither of these may be the case if you have not told the compiler to pack thestruct
. How you do that can vary between compilers.@JonB
Might sound stupid, but the task was to send sensor data through the microncontroller. Usually, this is given by the sensor in a floating point something like -9.81. So I multiplied it by 100 and then split it into 2 8 bit parts. Each of the 8 bit parts is stored as an int8t. Which is part of struct Data. I send this thorugh serial communication.I receive this serial data and store it in a QByteArray data. (Now taking @mpergand suggestion is changed my code to what he suggested).
int16_t val=(data[1]<<8)+(uchar)data[0];// as per @mpergand suggestion
Now I can retrieve the data back.
I am not sure if I am losing precision when I am doing this. I will have to look into it. But from my current guess looking into the value, I don't think I am losing any precision.
-
A aha_1980 has marked this topic as solved on
-
@JonB
Might sound stupid, but the task was to send sensor data through the microncontroller. Usually, this is given by the sensor in a floating point something like -9.81. So I multiplied it by 100 and then split it into 2 8 bit parts. Each of the 8 bit parts is stored as an int8t. Which is part of struct Data. I send this thorugh serial communication.I receive this serial data and store it in a QByteArray data. (Now taking @mpergand suggestion is changed my code to what he suggested).
int16_t val=(data[1]<<8)+(uchar)data[0];// as per @mpergand suggestion
Now I can retrieve the data back.
I am not sure if I am losing precision when I am doing this. I will have to look into it. But from my current guess looking into the value, I don't think I am losing any precision.
@Vignesh-R said in How to receive serial data sent as Struct and convert it to decimal:
I am not sure if I am losing precision when I am doing this. I will have to look into it. But from my current guess looking into the value, I don't think I am losing any precision.
Just so you know. If your original
int x
value is greater than+32767
or less than-32768
you will not get the right result back after conversion, because the number uses more than 16 (signed) bits in the first place. If you don't have values like that then that is fine, but then you might as well storex
in aint16_t
in the first place so that you will know the allowable range. What is the possible range of "the sensor in a floating point something like -9.81"? -
@Vignesh-R said in How to receive serial data sent as Struct and convert it to decimal:
I am not sure if I am losing precision when I am doing this. I will have to look into it. But from my current guess looking into the value, I don't think I am losing any precision.
Just so you know. If your original
int x
value is greater than+32767
or less than-32768
you will not get the right result back after conversion, because the number uses more than 16 (signed) bits in the first place. If you don't have values like that then that is fine, but then you might as well storex
in aint16_t
in the first place so that you will know the allowable range. What is the possible range of "the sensor in a floating point something like -9.81"?