Howto:Parsing binary data received via UDP in C
Jump to navigation
Jump to search
This article is a stub. You can help the wiki by expanding it. |
Note The code shown here is currently platform specific (Windows) and still needs to be ported to use the SimGear wrappers to be truly cross-platform (i.e. compile on Linux/Unix and Mac OS). Equally, it would be a good idea to add self-contained snippets of code that actually compile (including the corresponding CMakeLists.txt). In the long term, it would be great to commit this as a demo to the contrib directory in $FG_SRC (see the talk page for pointers). Any help with this would be appreciated! |
Contributed by: OsoMoore (12/2014)
I am parsing binary data sent by FlightGear via UDP. I am receiving the data with a C++ application written in Visual Studio 2013.
Here is my protocol XML (to be put into $FG_ROOT/Protocols), which determines the layout of each packet (see $FG_ROOT/Docs/README.IO for details):
<?xml version="1.0"?>
<PropertyList>
<generic>
<output>
<binary_mode>true</binary_mode>
<!-- note that chunk ordering/typing is critical here and needs to match the C struct below -->
<chunk>
<name>latitude</name>
<type>float</type>
<node>/position/latitude-deg</node>
</chunk>
<chunk>
<name>longitude</name>
<type>float</type>
<node>/position/longitude-deg</node>
</chunk>
<chunk>
<name>altitude</name>
<type>int</type>
<node>/position/altitude-ft</node>
</chunk>
<chunk>
<name>airspeed</name>
<type>int</type>
<node>/velocities/airspeed-kt</node>
</chunk>
<chunk>
<name>roll</name>
<type>float</type>
<node>/orientation/roll-deg</node>
</chunk>
<chunk>
<name>pitch</name>
<type>float</type>
<node>/orientation/pitch-deg</node>
</chunk>
<chunk>
<name>heading</name>
<type>float</type>
<node>/orientation/heading-deg</node>
</chunk>
<!-- any chunks added here, also need to be added to the C struct below -->
</output>
</generic>
</PropertyList>
Here is the struct into which I receive the data. The #pragma should result in the structure being packed tightly in memory.
#if defined(_WIN32) || defined(WIN32)
#pragma pack(push, 1)
typedef struct {
#else
typedef struct __attribute__((__packed__)) {
#endif
// NOTE: ordering/typing needs to match the protocol spec above
float latitude;
float longitude;
int altitude;
int airspeed;
float roll;
float pitch;
float heading;
} flightgear_packet;
#if defined(_WIN32) || defined(WIN32)
#pragma pack(pop)
#endif
Added this endian swapper function:
float float_swap(float value){
int temp = htonl(*(unsigned int*)&value);
return *(float*)&temp;
};
Here is the code which receives the packet and converts it into host byte ordering:
flightgear_packet buff, buff2;
// initialize buffer (fill with 0)
memset(&buff, 0, sizeof(buff));
bytes_read = recvfrom(SOCKET(sock), (char*)(&buff), sizeof(buff), 0, (struct sockaddr *) &si_other, &slen);
if (bytes_read > 0)
{
// populate structture
buff2.airspeed = ntohl(buff.airspeed);
buff2.altitude = ntohl(buff.altitude);
buff2.heading = float_swap(buff.heading);
buff2.latitude = float_swap(buff.latitude);
buff2.longitude = float_swap(buff.longitude);
buff2.pitch = float_swap(buff.pitch);
buff2.roll = float_swap(buff.roll);
// print out data
printf("Airspeed %i, Altitude %i\n", buff2.airspeed, buff2.altitude);
printf("Position %3.2f, %3.2f\n", buff2.latitude, buff2.longitude);
printf("Pitch/Roll/Heading %3.2f, %3.2f, %3.2f\n", buff2.pitch, buff2.roll, buff2.heading);
}
Hopefully this will be useful to someone else down the line.