Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. How to receive serial data sent as Struct and convert it to decimal
Forum Updated to NodeBB v4.3 + New Features

How to receive serial data sent as Struct and convert it to decimal

Scheduled Pinned Locked Moved Solved Mobile and Embedded
10 Posts 3 Posters 1.2k Views 2 Watching
  • 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.
  • V Offline
    V Offline
    Vignesh R
    wrote on last edited by
    #1

    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 refrence

    double 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 decimal

    This 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 advancestrikethrough text

    M 1 Reply Last reply
    0
    • V Vignesh R

      @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.

      M Offline
      M Offline
      mpergand
      wrote on last edited by
      #5

      @Vignesh-R
      Assuming your host is little endian,
      In MainWindow::readyData() try:

      data = COMPORT->readAll();
      int16_t val=(data[1]<<8)+(uchar)data[0];

      Note the uchar cast, as @JonB said, the type must be unsigned.

      1 Reply Last reply
      1
      • V Vignesh R

        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 refrence

        double 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 decimal

        This 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 advancestrikethrough text

        M Offline
        M Offline
        mpergand
        wrote on last edited by mpergand
        #2

        @Vignesh-R
        What is the initial format of the value, 16 bits integer ?
        and what endianess ?

        V 1 Reply Last reply
        3
        • M mpergand

          @Vignesh-R
          What is the initial format of the value, 16 bits integer ?
          and what endianess ?

          V Offline
          V Offline
          Vignesh R
          wrote on last edited by
          #3

          @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.

          JonBJ M 2 Replies Last reply
          0
          • V Vignesh R

            @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.

            JonBJ Online
            JonBJ Online
            JonB
            wrote on last edited by JonB
            #4

            @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 does

            x = ((Data.T1 << 8) & 0xFF00) | (Data.T2 & 0xFF)
            

            get you back your original x? I assume your x is of type short/int16_t or similar (if not, say so!). 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.

            Also your Serial.write() relies on Data struct being packed, note sure what it will do without that.

            V 1 Reply Last reply
            0
            • V Vignesh R

              @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.

              M Offline
              M Offline
              mpergand
              wrote on last edited by
              #5

              @Vignesh-R
              Assuming your host is little endian,
              In MainWindow::readyData() try:

              data = COMPORT->readAll();
              int16_t val=(data[1]<<8)+(uchar)data[0];

              Note the uchar cast, as @JonB said, the type must be unsigned.

              1 Reply Last reply
              1
              • JonBJ JonB

                @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 does

                x = ((Data.T1 << 8) & 0xFF00) | (Data.T2 & 0xFF)
                

                get you back your original x? I assume your x is of type short/int16_t or similar (if not, say so!). 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.

                Also your Serial.write() relies on Data struct being packed, note sure what it will do without that.

                V Offline
                V Offline
                Vignesh R
                wrote on last edited by
                #6

                @JonB

                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?

                JonBJ 1 Reply Last reply
                0
                • V Vignesh R

                  @JonB

                  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?

                  JonBJ Online
                  JonBJ Online
                  JonB
                  wrote on last edited by JonB
                  #7

                  @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 your struct, and on it only being 16-bits wide. Neither of these may be the case if you have not told the compiler to pack the struct. How you do that can vary between compilers.

                  V 1 Reply Last reply
                  1
                  • JonBJ JonB

                    @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 your struct, and on it only being 16-bits wide. Neither of these may be the case if you have not told the compiler to pack the struct. How you do that can vary between compilers.

                    V Offline
                    V Offline
                    Vignesh R
                    wrote on last edited by
                    #8

                    @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.

                    Thanks for the help @JonB @mpergand

                    JonBJ 1 Reply Last reply
                    0
                    • aha_1980A aha_1980 has marked this topic as solved on
                    • V Vignesh R

                      @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.

                      Thanks for the help @JonB @mpergand

                      JonBJ Online
                      JonBJ Online
                      JonB
                      wrote on last edited by
                      #9

                      @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 store x in a int16_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"?

                      V 1 Reply Last reply
                      1
                      • JonBJ JonB

                        @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 store x in a int16_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"?

                        V Offline
                        V Offline
                        Vignesh R
                        wrote on last edited by Vignesh R
                        #10
                        This post is deleted!
                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved