0

I am working on a project in which I am receiving data from a serial port. The data is being generated and sent from an Arduino Mega ADK. The arduino data starts with the characters 'S', 'N', 'P' to identify the beginning of the packet. It is followed by 18 bytes of data that is to be stored into 9 quint16 variables. Following that are 3 bytes to be stored in quint8 values, followed by 20 bytes to be stored in 4 int32 values.

I had this working when sending the data as strings, but I cant seem to find a way to get it working when sending the data as individual bytes, and reconstructing them to their values.

From my reading, Arduino is little endian, so I construct the values on the receiving end in the following manner:

The function that parses the data is here:

void MainWindow::NoseAviByte()
{
//Get data from nose cone avi bay
readNoseConeAvi();

//Look for SNP packet header
int curCount = 0;
int maxCount = dataBytes.size();


//Loop through array of bytes
while(curCount < maxCount)
{

    //If packet header is found, parse data vals
    if(((dataBytes.at(curCount) == 'S') && (dataBytes.at(curCount + 1) == 'N') && (dataBytes.at(curCount + 2) == 'P')) && (curCount + 62) < maxCount)
    {
        //All incoming values should be in little endian order
        curCount += 3;
        /***Start Low-g MEMS MPU-9250***/
        quint16 accX = 0;
        quint16 accY = 0;
        quint16 accZ = 0;
        quint16 gyroX = 0;
        quint16 gyroY = 0;
        quint16 gyroZ = 0;
        quint16 magX = 0;
        quint16 magY = 0;
        quint16 magZ = 0;
        /***End Low-g MEMS MPU-9250***/

        /***Start High-g ACC***/
        quint8 accHX = 0;
        quint8 accHY = 0;
        quint8 accHZ = 0;
        /***End High-g ACC***/

        /***Start Hgh precision Alt***/
        quint32 highPresAlt = 0;
        /***End Hgh precision Alt***/

         /***Start GPS***/
        quint32 gpsLat = 0;
        quint32 gpsLong = 0;
        quint32 gpsAlt = 0;
        quint32 gpsTime = 0;

        accX = (dataBytes.at(curCount) + (dataBytes.at(curCount + 1) << 8));
        curCount += 2;
        accY = (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8));
        curCount += 2;
        accZ = (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8));
        curCount += 2;
        gyroX = (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8));
        curCount += 2;
        gyroY = (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8));
        curCount += 2;
        gyroZ = (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8));
        curCount += 2;
        magX = (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8));
        curCount += 2;
        magY = (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8));
        curCount += 2;
        magZ = (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8));
        curCount += 2;

        accHX = dataBytes.at(curCount);
        curCount += 1;
        accHY = dataBytes.at(curCount);
        curCount += 1;
        accHZ = dataBytes.at(curCount);
        curCount += 1;

        highPresAlt = (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8) | (dataBytes.at(curCount + 2) << 16 ) | (dataBytes.at(curCount + 3) << 24));
        curCount += 4;

        gpsLat =  (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8) | (dataBytes.at(curCount + 2) << 16 ) | (dataBytes.at(curCount + 3) << 24));
        curCount += 4;
        gpsLong =  (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8) | (dataBytes.at(curCount + 2) << 16 ) | (dataBytes.at(curCount + 3) << 24));
        curCount += 4;
        gpsAlt =  (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8) | (dataBytes.at(curCount + 2) << 16 ) | (dataBytes.at(curCount + 3) << 24));
        curCount += 4;
        gpsTime =  (dataBytes.at(curCount) | (dataBytes.at(curCount + 1) << 8) | (dataBytes.at(curCount + 2) << 16 ) | (dataBytes.at(curCount + 3) << 24));
        curCount += 4;
    }
    else
    {
        curCount++;
    }
}

}

The function that fills the QByteArray is:

void MainWindow::readNoseConeAvi()
{
QByteArray noseData = serial->readAll();
QDataStream stream(noseData);
dataBytes = noseData;
inDataStream = &stream;

qDebug() << "Reading data bytes from telemetry source: ";
}

I was starting to make a spreadsheet to track any bad values, and found problems right away. It appears I am doing something wrong in reassembling the 32-bit values but cannot figure out why. Here is the output:

var type and expected output with actual output after two runs.

CavemanAGz
  • 43
  • 1
  • 9
  • http://stackoverflow.com/questions/11815894/how-to-read-write-arbitrary-bits-in-c-c/27592777#27592777 – dtech Apr 09 '17 at 15:54

1 Answers1

1

The issue is that QByteArray::at() is returning a char which can go negative. Convert the char to a quint8 first before adding them together.

quint32 myValue = quint8(dataBytes.at(curCount)) | quint8(dataBytes.at(curCount+1)) << 8 | quint8(dataBytes.at(curCount+2)) << 16 | quint8(dataBytes.at(curCount+3)) << 24;

This means that all of your conversions could go wrong, not just quint32. Make sure you specify the type quint8 on your other conversions too.

I suggest you create conversion functions so you don't have to write it out over and over.

mrg95
  • 2,371
  • 11
  • 46
  • 89
  • Thank you so much. This appears to have fixed my issue. Is it the default behavior of QByteArray to return a char when using at()? I guess I need to re-read the documentation on QByteArray – CavemanAGz Apr 09 '17 at 16:35
  • @caveman.agz yes that is the default. Can be annoying sometimes, but I have a class containing dozens of byte conversions that I use in all my projects. Makes it much easier to work with QByteArrays. – mrg95 Apr 10 '17 at 03:13