0

I'm trying to send a packet of data via UDP from my Qt GUI application to a Mathworks Simulink model where it is unpacked. I am using a union to save the data to and convert it to a char array of bytes to send. My first 58 bytes write and read as expected, but the last part doesn't.

I've tried multiple datatypes (int, unsigned int, float, int32_t) and none of them seem to be writing to the proper bytes in m_tx_data.myBytes[].

My guesses are either something is slightly wrong in my code, or Matlab and Qt read/write bytes to ints differently and I can't find out how.

My defined union

const int GUI2DEVICE_NUM_DOUBLE = 7;
const int GUI2DEVICE_NUM_BOOL  = 2;
const int GUI2DEVICE_NUM_INT32 = 3;

const int GUI2DEVICE_DATA_SIZE = (GUI2DEVICE_NUM_DOUBLE*sizeof(double)) +
                                 (GUI2DEVICE_NUM_BOOL*sizeof(bool)) +
                                 (GUI2DEVICE_NUM_INT32*sizeof(unsigned int));
union GuiToDeviceDataType
{
    char myBytes[GUI2DEVICE_DATA_SIZE];
    struct
   {
      double        doub[GUI2DEVICE_NUM_DOUBLE];
      bool          boolean[GUI2DEVICE_NUM_BOOL];
      int32_t       int32[GUI2DEVICE_NUM_INT32];
    } part;
};

Assigning values to the union. Every variable matches type to the part of the struct it is going to. m_tx_data.myBytes is initialized to 0.

    m_tx_data.part.doub[iAmplitude]                 = amplitude;
    m_tx_data.part.doub[iStartFrequency]            = startHz;
    m_tx_data.part.doub[iStopFrequency]             = stopHz;
    m_tx_data.part.doub[iFrequencyRampTime]         = FreqRampTime;
    m_tx_data.part.doub[iAmpRampUpTime]             = AmpRampUpTime;
    m_tx_data.part.doub[iAmpRampDownTime]           = AmpRampDownTime;
    m_tx_data.part.doub[iAutoScaleDecrementPercent] = ASDecPercent;
    m_tx_data.part.boolean[0] = 1;
    m_tx_data.part.boolean[1] = 1;
    m_tx_data.part.int32[iSweepSteps]              = SweepSteps;
    m_tx_data.part.int32[iPeriodsToAverage]        = PeriodsToAverage;
    m_tx_data.part.int32[iPeriodsToIgnore]         = PeriodsToSkip;

The values being assigned to m_tx_data.part.int32[] are equal to 1 (assigning them to 2 or 3 return a similar result). I'm expecting m_tx_data.myBytes[58:61] to be (0 0 0 1) or (1 0 0 0) (endianness), but instead it's returning (0 0 1 0), which is being read as 65536 by Matlab (little endian).

However, for my doubles, they are saving and reading as expected. m_tx_data.myBytes[0:7] = (0 0 0 0 0 0 240 63) which is read as 1 when casted to double by Matlab.

When debugging and looking at m_tx_data.myBytes, I can see the value stored in each byte and watch as each variable is written to the structure.

timrau
  • 22,578
  • 4
  • 51
  • 64
OtterCO
  • 13
  • 2
  • I suspect a problem with alignment of the fields. Try if packing the struct helps, see https://stackoverflow.com/questions/21092415/force-c-structure-to-pack-tightly – Eelke Aug 29 '19 at 17:43

1 Answers1

0

Add check static_assert(sizeof(GuiToDeviceDataType::part) == GUI2DEVICE_DATA_SIZE). It should show error in your case because of alignment. Lets check:

size_t sz1 = sizeof(GuiToDeviceDataType::part);
// sz1 == 72 and GUI2DEVICE_DATA_SIZE is 70

Reorder struct to move bool fields to the end of struct, so you'll get more expected results - padding should be only at the end of struct. You can check this by casting addresses of pointers to char* and then showing the difference:

        GuiToDeviceDataType data;
        size_t sz1 = sizeof(GuiToDeviceDataType::part);
        char* p1 = (char*)(void*)&data.part.boolean[0];
        char* p2 = (char*)(void*)&data.part.int32[0];
        size_t diff = p2 - p1;
        std::cout << diff; // shows 4 for your code