Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

(udp) convert one QByteArray to multiple structs ?



  • Hi eveyone,

    I'm learning c++ and I try to make my own telemetry application for F1 2018 as the game can send its data via UDP.
    The reception works fine, but I don't know how I can convert the QByteArray that readDatagram() gives me.

    The data is sent using multiple structs, some are inside others, here's the doc : link to CodeMaster's forum thread. For example, the speed of the car is in the CarTelemetryData struct that is in the PacketCarTelemetryData struct, I know I can do PacketCarTelemetryData->CarTelemetryData->m_speed to get it but when I do it, the app crashes with no error. The variables types are all the same both in the .h and .cpp.
    (I just tried to put all the structures in one, and use reinterpret_cast to this new one but still the same problem ...)

    My question is : is there any way I can "cast" (or whatever) my datagram to my multiple structures ?

    Thanks a lot !

    ps: tell me if you don't understand, also my structs file is 260 lines long so I assume it's better to copy to something like pastebin ?



  • Hi,

    First of all, look in the debugger to see how the data are arranged, if it looks correct or messy.

    There are several possible issues in your case.

    • how the data structures are packed, also called Data structure alignment
      You may need to specified it with the structs def in the .h file
      see: http://www.cplusplus.com/forum/general/14659/
    • you may have to care about the endianness and possibly do some conversion regarding the host architecture.

    Looking at the link your provide above, i don't see any information about the data alignment and the endianess, unfortunatly.

    Maybe i'm out of the subject, i don't know ;)


  • Moderators

    Hi @Natalya
    Have you thought about using QDataStream ?
    If you provide >> overloads for QDataStream and your structs, you should be able to „stream“ the data from your QByteArray into your structs.

    What @mpergand said still applies, so keep that in mind.

    Usefull links:
    http://doc.qt.io/qt-5/qdatastream.html
    https://www.qtcentre.org/threads/15168-QDataStream-class-struct-amp-stream-operators



  • Hi @mpergand and @J-Hilk

    I took a look in the debugger, I have 'SIGSEGV Segmentation Fault' error on an empty line after commented lines what ever i do ... I've read that it have something to do with the pointers ?

    And sorry, but I don't understand how to use QDataStream :/

    But thanks to you guys.



  • @Natalya said in (udp) convert one QByteArray to multiple structs ?:

    I have 'SIGSEGV Segmentation Fault' error on an empty line after commented lines what ever i do

    Yes, you and i already know that :)
    The point is why.
    If you put a breakpoint just after the struct pointer affectation, then in the debugger you can look at the struct field values.

    The first value you can check is the m_packetFormat field, it must be 2018 (0x7E2)
    Any other value means something wrong occured.


  • Moderators

    @Natalya said in (udp) convert one QByteArray to multiple structs ?:

    And sorry, but I don't understand how to use QDataStream :/

    here,

    to pratice with:

    //PacketHeader.h
    #ifndef PACKETHEADER_H
    #define PACKETHEADER_H
    
    #include <cstdint>
    #include <QDataStream>
    
    struct PacketHeader
    {
        uint16_t    m_packetFormat;         // 2018
        uint8_t     m_packetVersion;        // Version of this packet type, all start from 1
        uint8_t     m_packetId;             // Identifier for the packet type, see below
        uint64_t    m_sessionUID;           // Unique identifier for the session
        float       m_sessionTime;          // Session timestamp
        uint16_t    m_frameIdentifier;      // Identifier for the frame the data was retrieved on
        uint8_t     m_playerCarIndex;       // Index of player's car in the array
    
    
        friend QDataStream& operator<<(QDataStream &out, const PacketHeader &p);
    
        friend QDataStream& operator>>(QDataStream &in, PacketHeader &p);
    };
    
    #endif // PACKETHEADER_H
    
    
    //PacketHeader.cpp
    #include "packetheader.h"
    
    QDataStream &operator<<(QDataStream &out, const PacketHeader &p)
    {
        out << p.m_packetFormat         // 2018
            << p.m_packetVersion        // Version of this packet type, all start from 1
            << p.m_packetId             // Identifier for the packet type, see below
            << p.m_sessionUID           // Unique identifier for the session
            << p.m_sessionTime          // Session timestamp
            << p.m_frameIdentifier      // Identifier for the frame the data was retrieved on
            << p.m_playerCarIndex;       // Index of player's car in the array
        return out;
    }
    
    QDataStream &operator>>(QDataStream &in, PacketHeader &p)
    {
        in >> p.m_packetFormat         // 2018
            >> p.m_packetVersion        // Version of this packet type, all start from 1
            >> p.m_packetId             // Identifier for the packet type, see below
            >> p.m_sessionUID           // Unique identifier for the session
            >> p.m_sessionTime          // Session timestamp
            >> p.m_frameIdentifier      // Identifier for the frame the data was retrieved on
            >> p.m_playerCarIndex;       // Index of player's car in the array
        return in;
    }
    
    //main
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        PacketHeader p;
        p.m_playerCarIndex = 5;
    
        qDebug() << p.m_playerCarIndex;
    
        QByteArray ba;
    
        QDataStream in(&ba, QIODevice::WriteOnly);
    
        in << p;
        qDebug() << ba;
    
    
        PacketHeader p2;
        QDataStream Out(ba);
        Out >> p2;
    
        qDebug() << p2.m_playerCarIndex;
    
    
        return a.exec();
    }
    //Console output to see that its written and read
    5
    "4m\xC0s\x00\xB5\xFD\xE0\x00\x00\x00\x01""Fx\x07U\xA0\x00\x00\x00]\x04\x05"
    5
    


  • @J-Hilk Thanks, I'll look at that

    @mpergand the error keeps happening, I've made a new struct containing all the others (not the ones like telemetry that is only in PacketTelemetry of course) and I displayed that value, I've got '0xffffffe2' for the entire structure and so for the entire datagram ...
    I think that my part where I receive is wrong, like if it was cutting the data. I have a datagram.resize() to what looks like to be the received datagram's size, and it works on my 2017 version but not here...

    I'm quite lost to be honest



  • looking at the faqs, i see:

    What encoding format is used?
    All values are encoded using Little Endian format.

    Is the data packed?
    Yes, all data is packed.

    Some code trying to simulate the stuation:

    struct PacketHeader
    {
        uint16_t    m_packetFormat;         // 2018
        uint8_t     m_packetVersion;        // Version of this packet type, all start from 1
        uint8_t     m_packetId;             // Identifier for the packet type, see below
        uint64_t    m_sessionUID;           // Unique identifier for the session
        float     m_sessionTime;          // Session timestamp
        uint      m_frameIdentifier;      // Identifier for the frame the data was retrieved on
        uint8_t     m_playerCarIndex;       // Index of player's car in the array
    };
    
    struct Packet
    {
        struct PacketHeader p;
        uint8_t m;
    };
    
    
    int main(int argc, char *argv[])
    {
    
        QByteArray dat;
        dat.append(226);    // 2018 intel format
        dat.append(7);
    
        dat.append(1);      // version
        dat.append(2);      // id
    
        Packet* pa=(Packet*)dat.data();
    
    qDebug()<<dat;
    qDebug()<<pa->p.m_packetFormat;
    

    What i see in the debugger:

    	dat	@0x7fff5fbffb88	QByteArray
    		d	(hex) 0	QByteArray::Data
    			size	4	int
    			alloc	8	int
    	pa	@0x7fff5fbffb70	Packet
    		m	0	uint8_t
    		p	@0x10b804228	PacketHeader
    			m_frameIdentifier	4026531840	uint
    			m_packetFormat	2018	uint16_t
    			m_packetId	2	uint8_t
    			m_packetVersion	1	uint8_t
    			m_playerCarIndex	88	uint8_t
    			m_sessionTime	0.0	float
    			m_sessionUID	4487907200	uint64_t
    

    and with qDebug message:

    qDebug()<<dat;
    qDebug()<<pa->p.m_packetFormat;
    
    results:
    "\xE2\x07\x01\x02"
    2018
    

Log in to reply