Version 1.3-rc.1 (#138)
* Minor improvements to the handling of landing gear by the SetGear and HandlePOSI functions * sendPOSI command change (double for lat/lon/h) (#111) * Updated POSI to use doubles for lat/lon/alt, as step size for floats was unacceptably large at high longitudes. * Updated Java library for MATLAB, updated Java project, and updated Windows plugin binaries * Rolled back Java version to 1.7 for MATLAB compatibility * Update MessageHandlers.cpp * Update DataManager.cpp * Added pause functionality for individual a/c Adds new cases such that: 0: Unpauses all a/c 1: Pauses all a/c 2: Switches case for all a/c 100:119: Pauses a/c 0:19 200:219: Unpauses a/c 0:19 Updates log messages. Keeps the 0,1,2 arguments as they previously were. * Finished individual pause functionality * Update DataManager.cpp * Updated flags to allow for individual pause commands * Individual pause command documentation * Updated flags to allow for individual pause commands * Adding individual pause to documentation * Updated flags to allow for individual pause commands * Requested changes, cleaning * Update CMakeLists.txt Include "-fno-stack-protector" for linking and compiling for systems that do not have this have this flag as a default. * Enabling AI after setting position (#118) Previously, the code enabled the AI before setting the position of a/c, which negated its purpose. * Updated XPlane SDK to version 2.1.3 * Resolve function ambiguity for std::abs on mac Fixes #126 * Update copyright notice * Update Windows binaries * Update Linux binaries * Update version numbers * fix osx abs ambiguity (#142) * fix indexing error (#143) * Runway camera location control (#144) * update ignore * basics working * set cam pos remotely * log cam position * keep default behaviour, if short view message is received Compatibility with existing software * all to tabs * rename variable * option to use camera direction fields * Added UDP multicast for plugin discovery (#153) * Added Timer * Added UDPSocket::GetAddr * Added MessageHandlers::SendBeacon() * PoC of starting a timer on PluginEnable * C++11 * Added Timer to xcode project * C++11 in cmake * added Timer to cmake * use function pointer in Timer * moved Timer to namespace + wait for thread to join when stopping the timer * Windows: changed uint to unisgned short * Windows: Added Timer.h/cpp to project * GetAddr static * Send xplane and plugin version with BECN * SendBeacon with params * fixed file copyrights * Include functional to fix Linux compile error * review fixes * Send plugin receive port in BECN * review fixes * Fixed tabs vs spaces indentations (#157) * Java client BECN implementation (#155) * Added MS Azure Dev Ops CI integration (#162) * Do not build for i386 on macOS Use ARCHS_STANDARD to avoid the error “The i386 architecture is deprecated. You should update your ARCHS build setting to remove the i386 architecture.” * Fixed missing include The Visual Studio solution was not compiling * Fixed isnan ambigious refernce Ambigious reference when compiling on travis https://stackoverflow.com/questions/33770374/why-is-isnan-ambiguous-and-how-to-avoid-it * Set MSVC warning level to 3 Too many warnings were generated when building a Release build making Travis job to fail because of too much output * Use default toolset for Visual Studio AppVeyor recommends to set the default toolset * #include <cstdint> * Use MSVC ToolsVersion="14.0" # Conflicts: # xpcPlugin/xpcPlugin/xpcPlugin.vcxproj * Removed binaries from repository # Conflicts: # xpcPlugin/XPlaneConnect/64/win.xpl # xpcPlugin/XPlaneConnect/win.xpl * Added ms azure ci xcode linux linux + macos linux + macos removed branch filter win tests win tests Test all platfroms artifacts tests * output all binaries to ‘XPlaneConnect’ All platforms produce a binary in xpcPlugin/XPlaneConnect/ xpcPlugin/XPlaneConnect/64/ * Added ms azure GH deploy deploy stage GH release test trigger tags * Clean up yml file - Added variables - Added job decriptions * Ignore script to ignore .exp files + fixed output path * Renamed ms azure GH connection * Update service connection for azure pipeline * Added Python3 compatible xpc client. (#156) * Update Azure Pipelines service connection
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -19,6 +19,7 @@
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store?
|
||||
.DS_Store
|
||||
ehthumbs.db
|
||||
Icon?
|
||||
Thumbs.db
|
||||
@@ -69,6 +70,7 @@ build/
|
||||
xcuserdata
|
||||
*.moved-aside
|
||||
*.xccheckout
|
||||
xcshareddata
|
||||
|
||||
# IntelliJ Files #
|
||||
##################
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// DISCLAIMERS
|
||||
@@ -70,7 +70,7 @@ int main(void)
|
||||
tv.tv_usec = 100 * 1000;
|
||||
while (1)
|
||||
{
|
||||
float posi[7];
|
||||
float posi[7]; // FIXME: change this to the 64-bit lat/lon/h
|
||||
int result = getPOSI(client, posi, aircraftNum);
|
||||
if (result < 0) // Error in getPOSI
|
||||
{
|
||||
@@ -98,4 +98,4 @@ int main(void)
|
||||
printf("\n\nPress Any Key to exit...");
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT
|
||||
// THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY
|
||||
@@ -68,4 +68,4 @@ int getInt(char* prompt)
|
||||
int result;
|
||||
scanf("%d", &result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT
|
||||
// THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY
|
||||
@@ -37,4 +37,4 @@ void getString(char* prompt, char buffer[255]);
|
||||
|
||||
int getInt(char* prompt);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT
|
||||
// THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY
|
||||
@@ -35,7 +35,7 @@ int main(void)
|
||||
};
|
||||
char path[256] = { 0 };
|
||||
|
||||
displayStart("1.2.0.0");
|
||||
displayStart("1.3-rc.1");
|
||||
while (1)
|
||||
{
|
||||
switch (displayMenu("What would you like to do?", mainOpts, 3))
|
||||
@@ -67,4 +67,4 @@ int main(void)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT
|
||||
// THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY
|
||||
@@ -89,18 +89,18 @@ void playback(char* path, int interval)
|
||||
displayMsg("Starting Playback...");
|
||||
|
||||
XPCSocket sock = openUDP("127.0.0.1");
|
||||
float posi[7];
|
||||
double posi[7];
|
||||
while (!feof(fd) && !ferror(fd))
|
||||
{
|
||||
int result = fscanf(fd, "%f, %f, %f, %f, %f, %f, %f\n",
|
||||
int result = fscanf(fd, "%lf, %lf, %lf, %lf, %lf, %lf, %lf\n",
|
||||
&posi[0], &posi[1], &posi[2], &posi[3], &posi[4], &posi[5], &posi[6]);
|
||||
playbackSleep(interval);
|
||||
if (result != 7)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
sendPOSI(sock, posi, 7, 0);
|
||||
}
|
||||
closeUDP(sock);
|
||||
displayMsg("Playback Complete");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT
|
||||
// THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY
|
||||
@@ -29,4 +29,4 @@ void record(char* path, int interval, int duration);
|
||||
|
||||
void playback(char* path, int interval);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT
|
||||
// THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY
|
||||
@@ -82,13 +82,13 @@ XPCSocket openUDP(const char *xpIP)
|
||||
XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port)
|
||||
{
|
||||
XPCSocket sock;
|
||||
|
||||
|
||||
// Setup Port
|
||||
struct sockaddr_in recvaddr;
|
||||
recvaddr.sin_family = AF_INET;
|
||||
recvaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
recvaddr.sin_port = htons(port);
|
||||
|
||||
|
||||
// Set X-Plane Port and IP
|
||||
if (strcmp(xpIP, "localhost") == 0)
|
||||
{
|
||||
@@ -96,7 +96,7 @@ XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port)
|
||||
}
|
||||
strncpy(sock.xpIP, xpIP, 16);
|
||||
sock.xpPort = xpPort == 0 ? 49009 : xpPort;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsa;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
|
||||
@@ -105,7 +105,7 @@ XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if ((sock.sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
{
|
||||
printError("OpenUDP", "Socket creation failed");
|
||||
@@ -128,7 +128,7 @@ XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port)
|
||||
if (setsockopt(sock.sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0)
|
||||
{
|
||||
printError("OpenUDP", "Failed to set timeout");
|
||||
}
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ int sendUDP(XPCSocket sock, char buffer[], int len)
|
||||
printError("sendUDP", "Message length must be positive.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Set up destination address
|
||||
struct sockaddr_in dst;
|
||||
dst.sin_family = AF_INET;
|
||||
@@ -273,7 +273,7 @@ int setCONN(XPCSocket* sock, unsigned short port)
|
||||
int pauseSim(XPCSocket sock, char pause)
|
||||
{
|
||||
// Validte input
|
||||
if (pause < 0 || pause > 2)
|
||||
if (pause < 0 || (pause > 2 && pause < 100) || (pause > 119 && pause < 200) || pause > 219)
|
||||
{
|
||||
printError("pauseSim", "Invalid argument: %i", pause);
|
||||
return -2;
|
||||
@@ -311,7 +311,7 @@ int sendDATA(XPCSocket sock, float data[][9], int rows)
|
||||
|
||||
// Setup command
|
||||
// 5 byte header + 134 rows * 9 values * 4 bytes per value => 4829 byte max length.
|
||||
char buffer[4829] = "DATA";
|
||||
char buffer[4829] = "DATA";
|
||||
int len = 5 + rows * 9 * sizeof(float);
|
||||
unsigned short step = 9 * sizeof(float);
|
||||
int i; // iterator
|
||||
@@ -462,7 +462,7 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si
|
||||
{
|
||||
unsigned char buffer[65536];
|
||||
int result = readUDP(sock, buffer, 65536);
|
||||
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -563,13 +563,14 @@ int getPOSI(XPCSocket sock, float values[7], char ac)
|
||||
printError("getPOSI", "Unexpected response length.");
|
||||
return -3;
|
||||
}
|
||||
// TODO: change this to the 64-bit lat/lon/h
|
||||
|
||||
// Copy response into values
|
||||
memcpy(values, readBuffer + 6, 7 * sizeof(float));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendPOSI(XPCSocket sock, float values[], int size, char ac)
|
||||
int sendPOSI(XPCSocket sock, double values[], int size, char ac)
|
||||
{
|
||||
// Validate input
|
||||
if (ac < 0 || ac > 20)
|
||||
@@ -584,23 +585,32 @@ int sendPOSI(XPCSocket sock, float values[], int size, char ac)
|
||||
}
|
||||
|
||||
// Setup command
|
||||
// 5 byte header + up to 7 values * 5 bytes each
|
||||
unsigned char buffer[40] = "POSI";
|
||||
unsigned char buffer[46] = "POSI";
|
||||
buffer[4] = 0xff; //Placeholder for message length
|
||||
buffer[5] = ac;
|
||||
int i; // iterator
|
||||
for (i = 0; i < 7; i++)
|
||||
|
||||
for (i = 0; i < 7; i++) // double for lat/lon/h
|
||||
{
|
||||
float val = -998;
|
||||
double val = -998;
|
||||
|
||||
if (i < size)
|
||||
{
|
||||
val = values[i];
|
||||
}
|
||||
*((float*)(buffer + 6 + i * 4)) = val;
|
||||
if (i < 3) /* lat/lon/h */
|
||||
{
|
||||
memcpy(&buffer[6 + i*8], &val, sizeof(double));
|
||||
}
|
||||
else /* attitude and gear */
|
||||
{
|
||||
float f = (float)val;
|
||||
memcpy(&buffer[18 + i*4], &f, sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
// Send Command
|
||||
if (sendUDP(sock, buffer, 40) < 0)
|
||||
if (sendUDP(sock, buffer, 46) < 0)
|
||||
{
|
||||
printError("sendPOSI", "Failed to send command");
|
||||
return -3;
|
||||
@@ -735,9 +745,9 @@ int sendTEXT(XPCSocket sock, char* msg, int x, int y)
|
||||
size_t len = 14 + msgLen;
|
||||
memcpy(buffer + 5, &x, sizeof(int));
|
||||
memcpy(buffer + 9, &y, sizeof(int));
|
||||
buffer[13] = msgLen;
|
||||
buffer[13] = (unsigned char)msgLen;
|
||||
strncpy(buffer + 14, msg, msgLen);
|
||||
|
||||
|
||||
// Send Command
|
||||
if (sendUDP(sock, buffer, len) < 0)
|
||||
{
|
||||
@@ -807,4 +817,4 @@ int sendVIEW(XPCSocket sock, VIEW_TYPE view)
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/**** End View functions ****/
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT
|
||||
// THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY
|
||||
@@ -78,7 +78,7 @@ typedef enum
|
||||
XPC_VIEW_FULLSCREENWITHHUD,
|
||||
XPC_VIEW_FULLSCREENNOHUD,
|
||||
} VIEW_TYPE;
|
||||
|
||||
|
||||
// Low Level UDP Functions
|
||||
|
||||
/// Opens a new connection to XPC on an OS chosen port.
|
||||
@@ -112,10 +112,10 @@ int setCONN(XPCSocket* sock, unsigned short port);
|
||||
/// Pause or unpause the simulation.
|
||||
///
|
||||
/// \param sock The socket to use to send the command.
|
||||
/// \param pause 0 to unpause the sim; any other value to pause.
|
||||
/// \param pause 0 to unpause the sim; 1 to pause, 100:119 to pause a/c 0:19, 200:219 to unpause a/c 0:19.
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
int pauseSim(XPCSocket sock, char pause);
|
||||
|
||||
|
||||
// X-Plane UDP DATA
|
||||
|
||||
/// Reads X-Plane data from the specified socket.
|
||||
@@ -193,7 +193,7 @@ int getDREF(XPCSocket sock, const char* dref, float values[], int* size);
|
||||
/// to the actual number of elements copied in for that row.
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char count, int sizes[]);
|
||||
|
||||
|
||||
// Position
|
||||
|
||||
/// Gets the position and orientation of the specified aircraft.
|
||||
@@ -213,7 +213,7 @@ int getPOSI(XPCSocket sock, float values[7], char ac);
|
||||
/// \param size The number of elements in values.
|
||||
/// \param ac The aircraft number to set the position of. 0 for the player aircraft.
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
int sendPOSI(XPCSocket sock, float values[], int size, char ac);
|
||||
int sendPOSI(XPCSocket sock, double values[], int size, char ac);
|
||||
|
||||
// Controls
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ int main()
|
||||
|
||||
// Set Location/Orientation (sendPOSI)
|
||||
// Set Up Position Array
|
||||
float POSI[9] = { 0.0 };
|
||||
double POSI[9] = { 0.0 };
|
||||
POSI[0] = 37.524; // Lat
|
||||
POSI[1] = -122.06899; // Lon
|
||||
POSI[2] = 2500; // Alt
|
||||
|
||||
15
Java/.idea/misc.xml
generated
15
Java/.idea/misc.xml
generated
@@ -1,19 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
1
Java/.idea/modules.xml
generated
1
Java/.idea/modules.xml
generated
@@ -2,6 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/Examples/DiscoveryExample/DiscoveryExample.iml" filepath="$PROJECT_DIR$/Examples/DiscoveryExample/DiscoveryExample.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/XPlaneConnect.iml" filepath="$PROJECT_DIR$/XPlaneConnect.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package gov.nasa.xpc.ex;
|
||||
|
||||
import gov.nasa.xpc.XPlaneConnect;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
import java.util.Arrays;
|
||||
@@ -25,11 +24,11 @@ public class Main
|
||||
xpc.getDREF("sim/test/test_float");
|
||||
|
||||
System.out.println("Setting player aircraft position");
|
||||
float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1};
|
||||
double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1};
|
||||
xpc.sendPOSI(posi);
|
||||
|
||||
System.out.println("Setting another aircraft position");
|
||||
posi[0] = 37.52465F;
|
||||
posi[0] = 37.52465;
|
||||
posi[4] = 20;
|
||||
xpc.sendPOSI(posi, 1);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public class Main
|
||||
int aircraft = 0;
|
||||
while(true)
|
||||
{
|
||||
float[] posi = xpc.getPOSI(aircraft);
|
||||
float[] posi = xpc.getPOSI(aircraft); // FIXME: change this to 64-bit double
|
||||
float[] ctrl = xpc.getCTRL(aircraft);
|
||||
|
||||
System.out.format("Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n",
|
||||
|
||||
12
Java/Examples/DiscoveryExample/DiscoveryExample.iml
Normal file
12
Java/Examples/DiscoveryExample/DiscoveryExample.iml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="gov.nasa.xpc.ex" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="XPlaneConnect" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,35 @@
|
||||
package gov.nasa.xpc.ex;
|
||||
|
||||
import gov.nasa.xpc.XPlaneConnect;
|
||||
import gov.nasa.xpc.discovery.XPlaneConnectDiscovery;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
|
||||
|
||||
|
||||
public class DiscoveryConnectionExample {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
XPlaneConnectDiscovery discovery = new XPlaneConnectDiscovery();
|
||||
discovery.start(xpc -> {
|
||||
|
||||
sendDref(xpc);
|
||||
});
|
||||
System.out.println("Example done");
|
||||
}
|
||||
|
||||
static void sendDref(XPlaneConnect xpc) {
|
||||
System.out.println("Sending DREF");
|
||||
try {
|
||||
xpc.getDREF("sim/test/test_float");
|
||||
|
||||
} catch (SocketException e) {
|
||||
System.out.println("Unable to set up the connection. (Error message was '" + e.getMessage() + "'.)");
|
||||
} catch (IOException e) {
|
||||
System.out.println("Something went wrong with one of the commands. (Error message was '" + e.getMessage() + "'.)");
|
||||
}
|
||||
System.out.println("Sending DREF done");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package gov.nasa.xpc.ex;
|
||||
|
||||
import gov.nasa.xpc.discovery.XPlaneConnectDiscovery;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* XPlaneConnect discovery example that prints continuously each BECN packet
|
||||
*/
|
||||
public class SimpleDiscoveryExample {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
XPlaneConnectDiscovery discovery = new XPlaneConnectDiscovery();
|
||||
discovery.onBeaconReceived(beacon -> {
|
||||
System.out.println("Discovered XPlaneConnect plugin:");
|
||||
System.out.println("Plugin version: " + beacon.getPluginVersion());
|
||||
System.out.println("X-Plane version: " + beacon.getXplaneVersion());
|
||||
System.out.println("Address: " + beacon.getXplaneAddress().getHostAddress() + ":" + beacon.getPluginPort());
|
||||
});
|
||||
discovery.start();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class Main
|
||||
{
|
||||
String[] mainOpts = new String[] { "Record X-Plane", "Playback File", "Exit" };
|
||||
|
||||
System.out.println("X-Plane Connect Playback Example [Version 1.2.0.0]");
|
||||
System.out.println("X-Plane Connect Playback Example [Version 1.3-rc.1]");
|
||||
System.out.println("(c) 2013-2015 United States Government as represented by the Administrator");
|
||||
System.out.println("of the National Aeronautics and Space Administration. All Rights Reserved.");
|
||||
while(true)
|
||||
@@ -99,7 +99,7 @@ public class Main
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
float[] posi = xpc.getPOSI(0);
|
||||
float[] posi = xpc.getPOSI(0); // FIXME: change this to 64-bit double
|
||||
writer.write(String.format("%1$f, %2$f, %3$f, %4$f, %5$f, %6$f, %7$f\n",
|
||||
posi[0], posi[1], posi[2], posi[3], posi[4], posi[5], posi[6]));
|
||||
try
|
||||
@@ -125,11 +125,11 @@ public class Main
|
||||
{
|
||||
while(reader.hasNextLine())
|
||||
{
|
||||
float[] posi = new float[7];
|
||||
double[] posi = new double[7];
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
String s = reader.next();
|
||||
posi[i] = Float.parseFloat(s);
|
||||
posi[i] = Double.parseDouble(s);
|
||||
}
|
||||
reader.nextLine();
|
||||
xpc.sendPOSI(posi);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="gov.nasa.xpc" />
|
||||
@@ -10,6 +10,15 @@
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="junit-4.11" level="project" />
|
||||
<orderEntry type="module-library" scope="TEST">
|
||||
<library name="JUnit4">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/junit-4.12.jar!/" />
|
||||
<root url="jar://$MODULE_DIR$/lib/hamcrest-core-1.3.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
</module>
|
||||
BIN
Java/lib/hamcrest-core-1.3.jar
Normal file
BIN
Java/lib/hamcrest-core-1.3.jar
Normal file
Binary file not shown.
BIN
Java/lib/junit-4.12.jar
Normal file
BIN
Java/lib/junit-4.12.jar
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
//NOTICES:
|
||||
// Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// DISCLAIMERS
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//NOTICES:
|
||||
// Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// DISCLAIMERS
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//NOTICES:
|
||||
// Copyright (c) 2013-2016 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// DISCLAIMERS
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
package gov.nasa.xpc;
|
||||
|
||||
import gov.nasa.xpc.discovery.Beacon;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.AutoCloseable;
|
||||
@@ -136,6 +138,19 @@ public class XPlaneConnect implements AutoCloseable
|
||||
this(xpHost, xpPort, port, 100);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@code XPlaneConnect} class from a received discovery Beacon
|
||||
* @param beacon The beacon received from {@code XPlaneConnectDiscovery}
|
||||
* @throws SocketException If this instance is unable to bind to the specified port.
|
||||
*/
|
||||
public XPlaneConnect(Beacon beacon) throws SocketException {
|
||||
this.socket = new DatagramSocket(0);
|
||||
this.xplaneAddr = beacon.getXplaneAddress();
|
||||
this.xplanePort = beacon.getPluginPort();
|
||||
this.socket.setSoTimeout(100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@code XPlaneConnect} class using the specified ports, hostname, and timeout.
|
||||
*
|
||||
@@ -223,9 +238,9 @@ public class XPlaneConnect implements AutoCloseable
|
||||
*/
|
||||
public void pauseSim(int pause) throws IOException
|
||||
{
|
||||
if(pause < 0 || pause > 2)
|
||||
if(pause < 0 || (pause > 2 && pause < 100) || (pause > 119 && pause < 200) || pause > 219)
|
||||
{
|
||||
throw new IllegalArgumentException("pause must be a value in the range [0, 2].");
|
||||
throw new IllegalArgumentException("pause must be a value in the range [0, 2], [100, 119], or [200, 219].");
|
||||
}
|
||||
|
||||
// S I M U LEN VAL
|
||||
@@ -549,7 +564,7 @@ public class XPlaneConnect implements AutoCloseable
|
||||
* @return An array containing control surface data in the same format as {@code sendPOSI}.
|
||||
* @throws IOException If the command cannot be sent or a response cannot be read.
|
||||
*/
|
||||
public float[] getPOSI(int ac) throws IOException
|
||||
public double[] getPOSI(int ac) throws IOException
|
||||
{
|
||||
// Send request
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
@@ -570,7 +585,7 @@ public class XPlaneConnect implements AutoCloseable
|
||||
}
|
||||
|
||||
// Parse response
|
||||
float[] result = new float[7];
|
||||
double[] result = new double[7];
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
for(int i = 0; i < 7; ++i)
|
||||
@@ -600,13 +615,13 @@ public class XPlaneConnect implements AutoCloseable
|
||||
* </p>
|
||||
* @throws IOException If the command can not be sent.
|
||||
*/
|
||||
public void sendPOSI(float[] values) throws IOException
|
||||
public void sendPOSI(double[] values) throws IOException
|
||||
{
|
||||
sendPOSI(values, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the specified ac.
|
||||
* Sets the position of the specified ac with double precision coordinates.
|
||||
*
|
||||
* @param values <p>An array containing position elements as follows:</p>
|
||||
* <ol>
|
||||
@@ -626,7 +641,7 @@ public class XPlaneConnect implements AutoCloseable
|
||||
* @param ac The ac to set. 0 for the player ac.
|
||||
* @throws IOException If the command can not be sent.
|
||||
*/
|
||||
public void sendPOSI(float[] values, int ac) throws IOException
|
||||
public void sendPOSI(double[] values, int ac) throws IOException
|
||||
{
|
||||
//Preconditions
|
||||
if(values == null)
|
||||
@@ -644,15 +659,22 @@ public class XPlaneConnect implements AutoCloseable
|
||||
|
||||
//Pad command values and convert to bytes
|
||||
int i;
|
||||
ByteBuffer bb = ByteBuffer.allocate(28);
|
||||
ByteBuffer bb = ByteBuffer.allocate(40);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
for(i = 0; i < values.length; ++i)
|
||||
{
|
||||
bb.putFloat(i * 4, values[i]);
|
||||
if(i<3) /* lat/lon/height as double */
|
||||
{
|
||||
bb.putDouble(values[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
bb.putFloat((float)values[i]);
|
||||
}
|
||||
}
|
||||
for(; i < 7; ++i)
|
||||
{
|
||||
bb.putFloat(i * 4, -998);
|
||||
bb.putFloat(-998);
|
||||
}
|
||||
|
||||
//Build and send message
|
||||
|
||||
45
Java/src/discovery/Beacon.java
Normal file
45
Java/src/discovery/Beacon.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package gov.nasa.xpc.discovery;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
|
||||
public class Beacon {
|
||||
|
||||
private InetAddress xplaneAddress;
|
||||
private int pluginPort;
|
||||
private String pluginVersion;
|
||||
private int xPlaneVersion;
|
||||
|
||||
|
||||
public Beacon(InetAddress xplaneAddress, int pluginPort, String pluginVersion, int xPlaneVersion) {
|
||||
this.xplaneAddress = xplaneAddress;
|
||||
this.pluginPort = pluginPort;
|
||||
this.pluginVersion = pluginVersion;
|
||||
this.xPlaneVersion = xPlaneVersion;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return xplaneAddress.getHostAddress();
|
||||
}
|
||||
|
||||
public String getPluginVersion() {
|
||||
return pluginVersion;
|
||||
}
|
||||
|
||||
public String getXplaneVersion() {
|
||||
return String.format("%.2f", xPlaneVersion / 100.0);
|
||||
}
|
||||
|
||||
public int getPluginPort() {
|
||||
return pluginPort;
|
||||
}
|
||||
|
||||
public InetAddress getXplaneAddress() {
|
||||
return xplaneAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "host: " + getHost() + ":" + getPluginPort() +" version: " + getPluginVersion() + " X-Plane Version: " + getXplaneVersion();
|
||||
}
|
||||
}
|
||||
54
Java/src/discovery/BeaconParser.java
Normal file
54
Java/src/discovery/BeaconParser.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package gov.nasa.xpc.discovery;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Parser class that parses the UDP discovery BECN packet. The format of the packet is
|
||||
* - 4 bytes: BECN
|
||||
* - 1 byte: 0
|
||||
* - 2 bytes: XPlaneConnect server port e.g. '49009'
|
||||
* - 4 bytes: X-Plane version e.g. '11260'
|
||||
* - null terminated string: XPlaneConnect plugin version e.g. '1.3-rc.1'
|
||||
*/
|
||||
public class BeaconParser {
|
||||
|
||||
private static String BECN = "BECN";
|
||||
|
||||
private static int XPC_PORT_OFFSET = BECN.length() + 1;
|
||||
private static int XPC_PORT_LEN = 2;
|
||||
private static int XPC_VERSION_OFFSET = XPC_PORT_OFFSET + XPC_PORT_LEN;
|
||||
private static int XPC_VERSION_LEN = 4;
|
||||
private static int XPC_PLUGIN_VERSION_OFFSET = XPC_VERSION_OFFSET + XPC_VERSION_LEN;
|
||||
|
||||
|
||||
public Beacon readBCN(DatagramPacket packet) throws IOException {
|
||||
if (packet.getLength() < BECN.length()) {
|
||||
throw new IOException("BECN response too short");
|
||||
}
|
||||
|
||||
byte[] data = packet.getData();
|
||||
|
||||
String command = new String(data, 0, BECN.length());
|
||||
if (!command.equals(BECN)) {
|
||||
throw new IOException("Expected " + BECN + " got '" + command + "'");
|
||||
}
|
||||
|
||||
InetAddress address = packet.getAddress();
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
// 2 bytes: port as short + converted to an int
|
||||
int port = bb.getShort(XPC_PORT_OFFSET) & 0xffff;
|
||||
|
||||
// 4 bytes: x plane version as int
|
||||
int version = bb.getInt(XPC_VERSION_OFFSET);
|
||||
|
||||
// plugin version
|
||||
String pluginVersion = new String(data, XPC_PLUGIN_VERSION_OFFSET, packet.getLength() - XPC_PLUGIN_VERSION_OFFSET);
|
||||
|
||||
return new Beacon(address, port, pluginVersion.trim(), version);
|
||||
}
|
||||
}
|
||||
10
Java/src/discovery/BeaconReceivedListener.java
Normal file
10
Java/src/discovery/BeaconReceivedListener.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package gov.nasa.xpc.discovery;
|
||||
|
||||
public interface BeaconReceivedListener {
|
||||
|
||||
/**
|
||||
* Called every time a BECN packet is received
|
||||
* @param beacon The parsed beacon
|
||||
*/
|
||||
void onBeaconReceived(Beacon beacon);
|
||||
}
|
||||
14
Java/src/discovery/DiscoveryConnectionCallback.java
Normal file
14
Java/src/discovery/DiscoveryConnectionCallback.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package gov.nasa.xpc.discovery;
|
||||
|
||||
import gov.nasa.xpc.XPlaneConnect;
|
||||
|
||||
public interface DiscoveryConnectionCallback {
|
||||
|
||||
/**
|
||||
* Helper callback called when a 1st XPlanePlugin is discovered. When the 1st packet is received, an XPlaneConnect
|
||||
* instance is created and the discovery is stopped.
|
||||
*
|
||||
* @param xpc The XPlaneConnect instance configured with the discovered
|
||||
*/
|
||||
void onConnectionEstablished(XPlaneConnect xpc);
|
||||
}
|
||||
94
Java/src/discovery/XPlaneConnectDiscovery.java
Normal file
94
Java/src/discovery/XPlaneConnectDiscovery.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package gov.nasa.xpc.discovery;
|
||||
|
||||
import gov.nasa.xpc.XPlaneConnect;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MulticastSocket;
|
||||
import java.net.SocketException;
|
||||
|
||||
|
||||
/**
|
||||
* The XPlaneConnectDiscovery joins a UDP multi cast group and listens for BECN packets published by
|
||||
* XPlaneConnect server plugin. It allows to clients to discover XPlane instances and be sure that the XPlanePlugin is
|
||||
* installed.
|
||||
*/
|
||||
public class XPlaneConnectDiscovery implements AutoCloseable {
|
||||
|
||||
private static int DEFAULT_PORT = 49710;
|
||||
private static String DEFAULT_ADDRESS = "239.255.1.1";
|
||||
|
||||
private BeaconReceivedListener mListener;
|
||||
|
||||
private MulticastSocket socket = null;
|
||||
private byte[] buf = new byte[256];
|
||||
|
||||
private int mPort;
|
||||
private String mAddress;
|
||||
private BeaconParser parser = new BeaconParser();
|
||||
|
||||
private XPlaneConnectDiscovery(int port, String address) {
|
||||
mPort = port;
|
||||
mAddress = address;
|
||||
}
|
||||
|
||||
public XPlaneConnectDiscovery() {
|
||||
this(DEFAULT_PORT, DEFAULT_ADDRESS);
|
||||
}
|
||||
|
||||
public void start(DiscoveryConnectionCallback callback) throws IOException {
|
||||
onBeaconReceived(beacon -> {
|
||||
this.close();
|
||||
|
||||
try {
|
||||
XPlaneConnect xpc = new XPlaneConnect(beacon);
|
||||
callback.onConnectionEstablished(xpc);
|
||||
} catch (SocketException e) {
|
||||
System.err.println("Could not connect to a discovered XplaneConnect " +beacon+ ": " + e.getMessage());
|
||||
}
|
||||
});
|
||||
start();
|
||||
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
System.out.println("Starting XPlane Connect discovery");
|
||||
socket = new MulticastSocket(mPort);
|
||||
InetAddress group = InetAddress.getByName(mAddress);
|
||||
socket.joinGroup(group);
|
||||
while (socket != null) {
|
||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||
socket.receive(packet);
|
||||
if (mListener == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
Beacon beacon = parser.readBCN(packet);
|
||||
mListener.onBeaconReceived(beacon);
|
||||
} catch (IOException ex) {
|
||||
System.err.println("Received packet on discovery group but could not parse it: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
close();
|
||||
System.out.println("XPlane Connect discovery ended");
|
||||
}
|
||||
|
||||
|
||||
public void onBeaconReceived(BeaconReceivedListener mListener) {
|
||||
this.mListener = mListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
close();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -2,7 +2,7 @@ function pauseSim( pause, socket )
|
||||
%pauseSim Pauses or unpauses X-Plane.
|
||||
%
|
||||
%Inputs
|
||||
% pause: binary value 0=run, 1=pause
|
||||
% pause: int 0= unpause all, 1= pause all, 2= switch all, 100:119= pause a/c 0:19, 200:219= unpause a/c 0:19
|
||||
% socket (optional): The client to use when sending the command.
|
||||
%
|
||||
%Use
|
||||
@@ -34,4 +34,4 @@ pause = int32(pause);
|
||||
%% Send command
|
||||
socket.pauseSim(pause);
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
function sendPOSI( posi, ac, socket )
|
||||
% sendPOSI Sets the position of the specified aircraft.
|
||||
%
|
||||
%
|
||||
% Inputs
|
||||
% posi: Position array where the elements are as follows:
|
||||
% 1. Latitiude (deg)
|
||||
@@ -12,14 +12,14 @@ function sendPOSI( posi, ac, socket )
|
||||
% 7. Gear (0=up, 1=down)
|
||||
% acft (optional): The aircraft to set. 0 for the player aircraft.
|
||||
% socket (optional): The client to use when sending the command.
|
||||
%
|
||||
%
|
||||
% Use
|
||||
% 1. import XPlaneConnect.*;
|
||||
% 2. sendPOSI([37.5242422, -122.06899, 2500, 0, 0, 0, 1], 1);
|
||||
%
|
||||
%
|
||||
% Note: send the value -998 to not overwrite that parameter. That is, if
|
||||
% -998 is sent, the parameter will stay at the current X-Plane value.
|
||||
%
|
||||
%
|
||||
% Contributors
|
||||
% [CT] Christopher Teubert (SGT, Inc.)
|
||||
% christopher.a.teubert@nasa.gov
|
||||
@@ -33,14 +33,14 @@ global clients;
|
||||
if ~exist('socket', 'var')
|
||||
assert(isequal(length(clients) < 2, 1), '[sendPOSI] ERROR: Multiple clients open. You must specify which client to use.');
|
||||
if isempty(clients)
|
||||
socket = openUDP();
|
||||
socket = openUDP();
|
||||
else
|
||||
socket = clients(1);
|
||||
end
|
||||
end
|
||||
|
||||
%% Validate input
|
||||
posi = single(posi);
|
||||
posi = double(posi);
|
||||
if ~exist('ac', 'var')
|
||||
ac = 0;
|
||||
end
|
||||
@@ -49,4 +49,4 @@ ac = logical(ac);
|
||||
%% Send command
|
||||
socket.sendPOSI(posi, ac);
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,9 +11,9 @@ Socket = openUDP();
|
||||
while 1
|
||||
posi = getPOSI(0, Socket);
|
||||
ctrl = getCTRL(0, Socket);
|
||||
|
||||
|
||||
fprintf('Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n', ...
|
||||
posi(1), posi(2), posi(3), ctrl(2), ctrl(1), ctrl(3));
|
||||
pause(0.1);
|
||||
end
|
||||
closeUDP(Socket);
|
||||
closeUDP(Socket);
|
||||
|
||||
@@ -33,7 +33,7 @@ def playback(path, interval):
|
||||
print "Unable to open file."
|
||||
return
|
||||
|
||||
with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client:
|
||||
with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client:
|
||||
print "Starting Playback..."
|
||||
for line in fd:
|
||||
try:
|
||||
@@ -56,7 +56,7 @@ def printMenu(title, opts):
|
||||
return int(raw_input("Please select and option: "))
|
||||
|
||||
def ex():
|
||||
print "X-Plane Connect Playback Example [Version 1.2.0]"
|
||||
print "X-Plane Connect Playback Example [Version 1.3-rc.1]"
|
||||
print "(c) 2013-2015 United States Government as represented by the Administrator"
|
||||
print "of the National Aeronautics and Space Administration. All Rights Reserved."
|
||||
|
||||
@@ -79,4 +79,4 @@ def ex():
|
||||
print "Unrecognized option."
|
||||
|
||||
if __name__ == "__main__":
|
||||
ex()
|
||||
ex()
|
||||
|
||||
@@ -8,7 +8,7 @@ class XPlaneConnect(object):
|
||||
# Basic Functions
|
||||
def __init__(self, xpHost = 'localhost', xpPort = 49009, port = 0, timeout = 100):
|
||||
'''Sets up a new connection to an X-Plane Connect plugin running in X-Plane.
|
||||
|
||||
|
||||
Args:
|
||||
xpHost: The hostname of the machine running X-Plane.
|
||||
xpPort: The port on which the XPC plugin is listening. Usually 49007.
|
||||
@@ -33,7 +33,7 @@ class XPlaneConnect(object):
|
||||
# Setup XPlane IP and port
|
||||
self.xpDst = (xpIP, xpPort)
|
||||
|
||||
# Create and bind socket
|
||||
# Create and bind socket
|
||||
clientAddr = ("0.0.0.0", port)
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
self.socket.bind(clientAddr)
|
||||
@@ -71,18 +71,18 @@ class XPlaneConnect(object):
|
||||
# Configuration
|
||||
def setCONN(self, port):
|
||||
'''Sets the port on which the client sends and receives data.
|
||||
|
||||
|
||||
Args:
|
||||
port: The new port to use.
|
||||
'''
|
||||
#Validate parameters
|
||||
#Validate parameters
|
||||
if port < 0 or port > 65535:
|
||||
raise ValueError("The specified port is not a valid port number.")
|
||||
|
||||
#Send command
|
||||
buffer = struct.pack("<4sxH", "CONN", port)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
|
||||
#Rebind socket
|
||||
clientAddr = ("0.0.0.0", port)
|
||||
timeout = self.socket.gettimeout();
|
||||
@@ -96,12 +96,14 @@ class XPlaneConnect(object):
|
||||
|
||||
def pauseSim(self, pause):
|
||||
'''Pauses or un-pauses the physics simulation engine in X-Plane.
|
||||
|
||||
|
||||
Args:
|
||||
pause: True to pause the simulation; False to resume.
|
||||
pause: True to pause the simulation for all a/c; False to resume for all a/c.
|
||||
2 to switch the status for all a/c. 100:119 to pause a/c 0:19. 200:219 to
|
||||
resume a/c 0:19
|
||||
'''
|
||||
pause = int(pause)
|
||||
if pause < 0 or pause > 2:
|
||||
if pause < 0 or (pause > 2 and pause < 100) or (pause > 119 and pause < 200) or pause > 219 :
|
||||
raise ValueError("Invalid argument for pause command.")
|
||||
|
||||
buffer = struct.pack("<4sxB", "SIMU", pause)
|
||||
@@ -110,7 +112,7 @@ class XPlaneConnect(object):
|
||||
# X-Plane UDP Data
|
||||
def readDATA(self):
|
||||
'''Reads X-Plane data.
|
||||
|
||||
|
||||
Returns: A 2 dimensional array containing 0 or more rows of data. Each array
|
||||
in the result will have 9 elements, the first of which is the row number which
|
||||
that array represents data for, and the rest of which are the data elements in
|
||||
@@ -127,7 +129,7 @@ class XPlaneConnect(object):
|
||||
|
||||
def sendDATA(self, data):
|
||||
'''Sends X-Plane data over the underlying UDP socket.
|
||||
|
||||
|
||||
Args:
|
||||
data: An array of values representing data rows to be set. Each array in `data`
|
||||
should have 9 elements, the first of which is a row number in the range (0-134),
|
||||
@@ -143,7 +145,7 @@ class XPlaneConnect(object):
|
||||
buffer += struct.pack("<I8f", *row)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Position
|
||||
# Position
|
||||
def getPOSI(self, ac = 0):
|
||||
'''Gets position information for the specified aircraft.
|
||||
|
||||
@@ -189,6 +191,7 @@ class XPlaneConnect(object):
|
||||
if ac < 0 or ac > 20:
|
||||
raise ValueError("Aircraft number must be between 0 and 20.")
|
||||
|
||||
# FIXME update this to the 64-bit double lat/lon/h
|
||||
# Pack message
|
||||
buffer = struct.pack("<4sxB", "POSI", ac)
|
||||
for i in range(7):
|
||||
@@ -264,8 +267,8 @@ class XPlaneConnect(object):
|
||||
|
||||
# Send
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# DREF Manipulation
|
||||
|
||||
# DREF Manipulation
|
||||
def sendDREF(self, dref, values):
|
||||
'''Sets the specified dataref to the specified value.
|
||||
|
||||
@@ -294,7 +297,7 @@ class XPlaneConnect(object):
|
||||
raise ValueError("dref must be a non-empty string less than 256 characters.")
|
||||
if value == None:
|
||||
raise ValueError("value must be a scalar or sequence of floats.")
|
||||
|
||||
|
||||
# Pack message
|
||||
if hasattr(value, "__len__"):
|
||||
if len(value) > 255:
|
||||
@@ -310,7 +313,7 @@ class XPlaneConnect(object):
|
||||
|
||||
def getDREF(self, dref):
|
||||
'''Gets the value of an X-Plane dataref.
|
||||
|
||||
|
||||
Args:
|
||||
dref: The name of the dataref to get.
|
||||
|
||||
|
||||
72
Python3/src/basicExample.py
Normal file
72
Python3/src/basicExample.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from time import sleep
|
||||
import xpc
|
||||
|
||||
def ex():
|
||||
print "X-Plane Connect example script"
|
||||
print "Setting up simulation"
|
||||
with xpc.XPlaneConnect() as client:
|
||||
# Verify connection
|
||||
try:
|
||||
# If X-Plane does not respond to the request, a timeout error
|
||||
# will be raised.
|
||||
client.getDREF("sim/test/test_float")
|
||||
except:
|
||||
print "Error establishing connection to X-Plane."
|
||||
print "Exiting..."
|
||||
return
|
||||
|
||||
# Set position of the player aircraft
|
||||
print "Setting position"
|
||||
# Lat Lon Alt Pitch Roll Yaw Gear
|
||||
posi = [37.524, -122.06899, 2500, 0, 0, 0, 1]
|
||||
client.sendPOSI(posi)
|
||||
|
||||
# Set position of a non-player aircraft
|
||||
print "Setting NPC position"
|
||||
# Lat Lon Alt Pitch Roll Yaw Gear
|
||||
posi = [37.52465, -122.06899, 2500, 0, 20, 0, 1]
|
||||
client.sendPOSI(posi, 1)
|
||||
|
||||
# Set angle of attack, velocity, and orientation using the DATA command
|
||||
print "Setting orientation"
|
||||
data = [\
|
||||
[18, 0, -998, 0, -998, -998, -998, -998, -998],\
|
||||
[ 3, 130, 130, 130, 130, -998, -998, -998, -998],\
|
||||
[16, 0, 0, 0, -998, -998, -998, -998, -998]\
|
||||
]
|
||||
client.sendDATA(data)
|
||||
|
||||
# Set control surfaces and throttle of the player aircraft using sendCTRL
|
||||
print "Setting controls"
|
||||
ctrl = [0.0, 0.0, 0.0, 0.8]
|
||||
client.sendCTRL(ctrl)
|
||||
|
||||
# Pause the sim
|
||||
print "Pausing"
|
||||
client.pauseSim(True)
|
||||
sleep(2)
|
||||
|
||||
# Toggle pause state to resume
|
||||
print "Resuming"
|
||||
client.pauseSim(False)
|
||||
|
||||
# Stow landing gear using a dataref
|
||||
print "Stowing gear"
|
||||
gear_dref = "sim/cockpit/switches/gear_handle_status"
|
||||
client.sendDREF(gear_dref, 0)
|
||||
|
||||
# Let the sim run for a bit.
|
||||
sleep(4)
|
||||
|
||||
# Make sure gear was stowed successfully
|
||||
gear_status = client.getDREF(gear_dref)
|
||||
if gear_status[0] == 0:
|
||||
print "Gear stowed"
|
||||
else:
|
||||
print "Error stowing gear"
|
||||
|
||||
print "End of Python client example"
|
||||
raw_input("Press any key to exit...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
ex()
|
||||
16
Python3/src/monitorExample.py
Normal file
16
Python3/src/monitorExample.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import sys
|
||||
|
||||
import xpc
|
||||
|
||||
def monitor():
|
||||
with xpc.XPlaneConnect() as client:
|
||||
while True:
|
||||
posi = client.getPOSI();
|
||||
ctrl = client.getCTRL();
|
||||
|
||||
print "Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n"\
|
||||
% (posi[0], posi[1], posi[2], ctrl[1], ctrl[0], ctrl[2])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
monitor()
|
||||
82
Python3/src/playbackExample.py
Normal file
82
Python3/src/playbackExample.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from time import sleep
|
||||
import xpc
|
||||
|
||||
def record(path, interval = 0.1, duration = 60):
|
||||
try:
|
||||
fd = open(path, "w")
|
||||
except:
|
||||
print "Unable to open file."
|
||||
return
|
||||
|
||||
count = int(duration / interval)
|
||||
if count < 1:
|
||||
print "duration is less than a single frame."
|
||||
return
|
||||
|
||||
with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client:
|
||||
print "Recording..."
|
||||
for i in range(0, count):
|
||||
try:
|
||||
posi = client.getPOSI()
|
||||
fd.write("{0}, {1}, {2}, {3}, {4}, {5}, {6}\n".format(*posi))
|
||||
except:
|
||||
print "Error reading position"
|
||||
continue
|
||||
sleep(interval);
|
||||
print "Recording Complete"
|
||||
fd.close()
|
||||
|
||||
def playback(path, interval):
|
||||
try:
|
||||
fd = open(path, "r")
|
||||
except:
|
||||
print "Unable to open file."
|
||||
return
|
||||
|
||||
with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client:
|
||||
print "Starting Playback..."
|
||||
for line in fd:
|
||||
try:
|
||||
posi = [ float(x) for x in line.split(',') ]
|
||||
posi = client.sendPOSI(posi)
|
||||
except:
|
||||
print "Error sending position"
|
||||
continue
|
||||
sleep(interval);
|
||||
print "Playback Complete"
|
||||
fd.close()
|
||||
|
||||
def printMenu(title, opts):
|
||||
print "\n+---------------------------------------------- +"
|
||||
print "| {0:42} |\n".format(title)
|
||||
print "+---------------------------------------------- +"
|
||||
for i in range(0,len(opts)):
|
||||
print "| {0:2}. {1:40} |".format(i + 1, opts[i])
|
||||
print "+---------------------------------------------- +"
|
||||
return int(raw_input("Please select and option: "))
|
||||
|
||||
def ex():
|
||||
print "X-Plane Connect Playback Example [Version 1.2.0]"
|
||||
print "(c) 2013-2015 United States Government as represented by the Administrator"
|
||||
print "of the National Aeronautics and Space Administration. All Rights Reserved."
|
||||
|
||||
mainOpts = [ "Record X-Plane", "Playback File", "Exit" ]
|
||||
|
||||
while True:
|
||||
opt = printMenu("What would you like to do?", mainOpts)
|
||||
if opt == 1:
|
||||
path = raw_input("Enter save file path: ")
|
||||
interval = float(raw_input("Enter interval between frames (seconds): "))
|
||||
duration = float(raw_input("Enter duration to record for (seconds): "))
|
||||
record(path, interval, duration)
|
||||
elif opt == 2:
|
||||
path = raw_input("Enter save file path: ")
|
||||
interval = float(raw_input("Enter interval between frames (seconds): "))
|
||||
playback(path, interval)
|
||||
elif opt == 3:
|
||||
return;
|
||||
else:
|
||||
print "Unrecognized option."
|
||||
|
||||
if __name__ == "__main__":
|
||||
ex()
|
||||
437
Python3/src/xpc.py
Normal file
437
Python3/src/xpc.py
Normal file
@@ -0,0 +1,437 @@
|
||||
import socket
|
||||
import struct
|
||||
|
||||
|
||||
class XPlaneConnect(object):
|
||||
"""XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin."""
|
||||
socket = None
|
||||
|
||||
# Basic Functions
|
||||
def __init__(self, xpHost='localhost', xpPort=49009, port=0, timeout=100):
|
||||
"""Sets up a new connection to an X-Plane Connect plugin running in X-Plane.
|
||||
|
||||
Args:
|
||||
xpHost: The hostname of the machine running X-Plane.
|
||||
xpPort: The port on which the XPC plugin is listening. Usually 49007.
|
||||
port: The port which will be used to send and receive data.
|
||||
timeout: The period (in milliseconds) after which read attempts will fail.
|
||||
"""
|
||||
|
||||
# Validate parameters
|
||||
xpIP = None
|
||||
try:
|
||||
xpIP = socket.gethostbyname(xpHost)
|
||||
except:
|
||||
raise ValueError("Unable to resolve xpHost.")
|
||||
|
||||
if xpPort < 0 or xpPort > 65535:
|
||||
raise ValueError("The specified X-Plane port is not a valid port number.")
|
||||
if port < 0 or port > 65535:
|
||||
raise ValueError("The specified port is not a valid port number.")
|
||||
if timeout < 0:
|
||||
raise ValueError("timeout must be non-negative.")
|
||||
|
||||
# Setup XPlane IP and port
|
||||
self.xpDst = (xpIP, xpPort)
|
||||
|
||||
# Create and bind socket
|
||||
clientAddr = ("0.0.0.0", port)
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
self.socket.bind(clientAddr)
|
||||
timeout /= 1000.0
|
||||
self.socket.settimeout(timeout)
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
# Define __enter__ and __exit__ to support the `with` construct.
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
"""Closes the specified connection and releases resources associated with it."""
|
||||
if self.socket is not None:
|
||||
self.socket.close()
|
||||
self.socket = None
|
||||
|
||||
def sendUDP(self, buffer):
|
||||
"""Sends a message over the underlying UDP socket."""
|
||||
# Preconditions
|
||||
if(len(buffer) == 0):
|
||||
raise ValueError("sendUDP: buffer is empty.")
|
||||
|
||||
self.socket.sendto(buffer, 0, self.xpDst)
|
||||
|
||||
def readUDP(self):
|
||||
"""Reads a message from the underlying UDP socket."""
|
||||
return self.socket.recv(16384)
|
||||
|
||||
# Configuration
|
||||
def setCONN(self, port):
|
||||
"""Sets the port on which the client sends and receives data.
|
||||
|
||||
Args:
|
||||
port: The new port to use.
|
||||
"""
|
||||
|
||||
#Validate parameters
|
||||
if port < 0 or port > 65535:
|
||||
raise ValueError("The specified port is not a valid port number.")
|
||||
|
||||
#Send command
|
||||
buffer = struct.pack(b"<4sxH", b"CONN", port)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
#Rebind socket
|
||||
clientAddr = ("0.0.0.0", port)
|
||||
timeout = self.socket.gettimeout()
|
||||
self.socket.close()
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
self.socket.bind(clientAddr)
|
||||
self.socket.settimeout(timeout)
|
||||
|
||||
#Read response
|
||||
buffer = self.socket.recv(1024)
|
||||
|
||||
def pauseSim(self, pause):
|
||||
"""Pauses or un-pauses the physics simulation engine in X-Plane.
|
||||
|
||||
Args:
|
||||
pause: True to pause the simulation; False to resume.
|
||||
"""
|
||||
pause = int(pause)
|
||||
if pause < 0 or pause > 2:
|
||||
raise ValueError("Invalid argument for pause command.")
|
||||
|
||||
buffer = struct.pack(b"<4sxB", b"SIMU", pause)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# X-Plane UDP Data
|
||||
def readDATA(self):
|
||||
"""Reads X-Plane data.
|
||||
|
||||
Returns: A 2 dimensional array containing 0 or more rows of data. Each array
|
||||
in the result will have 9 elements, the first of which is the row number which
|
||||
that array represents data for, and the rest of which are the data elements in
|
||||
that row.
|
||||
"""
|
||||
buffer = self.readUDP()
|
||||
if len(buffer) < 6:
|
||||
return None
|
||||
rows = (len(buffer) - 5) / 36
|
||||
data = []
|
||||
for i in range(rows):
|
||||
data.append(struct.unpack_from(b"9f", buffer, 5 + 36*i))
|
||||
return data
|
||||
|
||||
def sendDATA(self, data):
|
||||
"""Sends X-Plane data over the underlying UDP socket.
|
||||
|
||||
Args:
|
||||
data: An array of values representing data rows to be set. Each array in `data`
|
||||
should have 9 elements, the first of which is a row number in the range (0-134),
|
||||
and the rest of which are the values to set for that data row.
|
||||
"""
|
||||
if len(data) > 134:
|
||||
raise ValueError("Too many rows in data.")
|
||||
|
||||
buffer = struct.pack(b"<4sx", b"DATA")
|
||||
for row in data:
|
||||
if len(row) != 9:
|
||||
raise ValueError("Row does not contain exactly 9 values. <" + str(row) + ">")
|
||||
buffer += struct.pack(b"<I8f", *row)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Position
|
||||
def getPOSI(self, ac=0):
|
||||
"""Gets position information for the specified aircraft.
|
||||
|
||||
Args:
|
||||
ac: The aircraft to get the position of. 0 is the main/player aircraft.
|
||||
"""
|
||||
# Send request
|
||||
buffer = struct.pack(b"<4sxB", b"GETP", ac)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Read response
|
||||
resultBuf = self.readUDP()
|
||||
if len(resultBuf) != 34:
|
||||
raise ValueError("Unexpected response length.")
|
||||
|
||||
result = struct.unpack(b"<4sxBfffffff", resultBuf)
|
||||
if result[0] != b"POSI":
|
||||
raise ValueError("Unexpected header: " + result[0])
|
||||
|
||||
# Drop the header & ac from the return value
|
||||
return result[2:]
|
||||
|
||||
def sendPOSI(self, values, ac=0):
|
||||
"""Sets position information on the specified aircraft.
|
||||
|
||||
Args:
|
||||
values: The position values to set. `values` is a array containing up to
|
||||
7 elements. If less than 7 elements are specified or any elment is set to `-998`,
|
||||
those values will not be changed. The elements in `values` corespond to the
|
||||
following:
|
||||
* Latitude (deg)
|
||||
* Longitude (deg)
|
||||
* Altitude (m above MSL)
|
||||
* Pitch (deg)
|
||||
* Roll (deg)
|
||||
* True Heading (deg)
|
||||
* Gear (0=up, 1=down)
|
||||
ac: The aircraft to set the position of. 0 is the main/player aircraft.
|
||||
"""
|
||||
# Preconditions
|
||||
if len(values) < 1 or len(values) > 7:
|
||||
raise ValueError("Must have between 0 and 7 items in values.")
|
||||
if ac < 0 or ac > 20:
|
||||
raise ValueError("Aircraft number must be between 0 and 20.")
|
||||
|
||||
# Pack message
|
||||
buffer = struct.pack(b"<4sxB", b"POSI", ac)
|
||||
for i in range(7):
|
||||
val = -998
|
||||
if i < len(values):
|
||||
val = values[i]
|
||||
buffer += struct.pack(b"<f", val)
|
||||
|
||||
# Send
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Controls
|
||||
def getCTRL(self, ac=0):
|
||||
"""Gets the control surface information for the specified aircraft.
|
||||
|
||||
Args:
|
||||
ac: The aircraft to get the control surfaces of. 0 is the main/player aircraft.
|
||||
"""
|
||||
# Send request
|
||||
buffer = struct.pack(b"<4sxB", b"GETC", ac)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Read response
|
||||
resultBuf = self.readUDP()
|
||||
if len(resultBuf) != 31:
|
||||
raise ValueError("Unexpected response length.")
|
||||
|
||||
result = struct.unpack(b"<4sxffffbfBf", resultBuf)
|
||||
if result[0] != b"CTRL":
|
||||
raise ValueError("Unexpected header: " + result[0])
|
||||
|
||||
# Drop the header from the return value
|
||||
result =result[1:7] + result[8:]
|
||||
return result
|
||||
|
||||
def sendCTRL(self, values, ac=0):
|
||||
"""Sets control surface information on the specified aircraft.
|
||||
|
||||
Args:
|
||||
values: The control surface values to set. `values` is a array containing up to
|
||||
6 elements. If less than 6 elements are specified or any elment is set to `-998`,
|
||||
those values will not be changed. The elements in `values` corespond to the
|
||||
following:
|
||||
* Latitudinal Stick [-1,1]
|
||||
* Longitudinal Stick [-1,1]
|
||||
* Rudder Pedals [-1, 1]
|
||||
* Throttle [-1, 1]
|
||||
* Gear (0=up, 1=down)
|
||||
* Flaps [0, 1]
|
||||
* Speedbrakes [-0.5, 1.5]
|
||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||
"""
|
||||
# Preconditions
|
||||
if len(values) < 1 or len(values) > 7:
|
||||
raise ValueError("Must have between 0 and 6 items in values.")
|
||||
if ac < 0 or ac > 20:
|
||||
raise ValueError("Aircraft number must be between 0 and 20.")
|
||||
|
||||
# Pack message
|
||||
buffer = struct.pack(b"<4sx", b"CTRL")
|
||||
for i in range(6):
|
||||
val = -998
|
||||
if i < len(values):
|
||||
val = values[i]
|
||||
if i == 4:
|
||||
val = -1 if (abs(val + 998) < 1e-4) else val
|
||||
buffer += struct.pack(b"b", val)
|
||||
else:
|
||||
buffer += struct.pack(b"<f", val)
|
||||
|
||||
buffer += struct.pack(b"B", ac)
|
||||
if len(values) == 7:
|
||||
buffer += struct.pack(b"<f", values[6])
|
||||
|
||||
# Send
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# DREF Manipulation
|
||||
def sendDREF(self, dref, values):
|
||||
"""Sets the specified dataref to the specified value.
|
||||
|
||||
Args:
|
||||
dref: The name of the datarefs to set.
|
||||
values: Either a scalar value or a sequence of values.
|
||||
"""
|
||||
self.sendDREFs([dref], [values])
|
||||
|
||||
def sendDREFs(self, drefs, values):
|
||||
"""Sets the specified datarefs to the specified values.
|
||||
|
||||
Args:
|
||||
drefs: A list of names of the datarefs to set.
|
||||
values: A list of scalar or vector values to set.
|
||||
"""
|
||||
if len(drefs) != len(values):
|
||||
raise ValueError("drefs and values must have the same number of elements.")
|
||||
|
||||
buffer = struct.pack(b"<4sx", b"DREF")
|
||||
for i in range(len(drefs)):
|
||||
dref = drefs[i]
|
||||
value = values[i]
|
||||
|
||||
# Preconditions
|
||||
if len(dref) == 0 or len(dref) > 255:
|
||||
raise ValueError("dref must be a non-empty string less than 256 characters.")
|
||||
|
||||
if value is None:
|
||||
raise ValueError("value must be a scalar or sequence of floats.")
|
||||
|
||||
# Pack message
|
||||
if hasattr(value, "__len__"):
|
||||
if len(value) > 255:
|
||||
raise ValueError("value must have less than 256 items.")
|
||||
fmt = "<B{0:d}sB{1:d}f".format(len(dref), len(value))
|
||||
buffer += struct.pack(fmt.encode(), len(dref), dref.encode(), len(value), value)
|
||||
else:
|
||||
fmt = "<B{0:d}sBf".format(len(dref))
|
||||
buffer += struct.pack(fmt.encode(), len(dref), dref.encode(), 1, value)
|
||||
|
||||
# Send
|
||||
self.sendUDP(buffer)
|
||||
|
||||
def getDREF(self, dref):
|
||||
"""Gets the value of an X-Plane dataref.
|
||||
|
||||
Args:
|
||||
dref: The name of the dataref to get.
|
||||
|
||||
Returns: A sequence of data representing the values of the requested dataref.
|
||||
"""
|
||||
return self.getDREFs([dref])[0]
|
||||
|
||||
def getDREFs(self, drefs):
|
||||
"""Gets the value of one or more X-Plane datarefs.
|
||||
|
||||
Args:
|
||||
drefs: The names of the datarefs to get.
|
||||
|
||||
Returns: A multidimensional sequence of data representing the values of the requested
|
||||
datarefs.
|
||||
"""
|
||||
# Send request
|
||||
buffer = struct.pack(b"<4sxB", b"GETD", len(drefs))
|
||||
for dref in drefs:
|
||||
fmt = "<B{0:d}s".format(len(dref))
|
||||
buffer += struct.pack(fmt.encode(), len(dref), dref.encode())
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Read and parse response
|
||||
buffer = self.readUDP()
|
||||
resultCount = struct.unpack_from(b"B", buffer, 5)[0]
|
||||
offset = 6
|
||||
result = []
|
||||
for i in range(resultCount):
|
||||
rowLen = struct.unpack_from(b"B", buffer, offset)[0]
|
||||
offset += 1
|
||||
fmt = "<{0:d}f".format(rowLen)
|
||||
row = struct.unpack_from(fmt.encode(), buffer, offset)
|
||||
result.append(row)
|
||||
offset += rowLen * 4
|
||||
return result
|
||||
|
||||
# Drawing
|
||||
def sendTEXT(self, msg, x=-1, y=-1):
|
||||
"""Sets a message that X-Plane will display on the screen.
|
||||
|
||||
Args:
|
||||
msg: The string to display on the screen
|
||||
x: The distance in pixels from the left edge of the screen to display the
|
||||
message. A value of -1 indicates that the default horizontal position should
|
||||
be used.
|
||||
y: The distance in pixels from the bottom edge of the screen to display the
|
||||
message. A value of -1 indicates that the default vertical position should be
|
||||
used.
|
||||
"""
|
||||
if y < -1:
|
||||
raise ValueError("y must be greater than or equal to -1.")
|
||||
|
||||
if msg == None:
|
||||
msg = ""
|
||||
|
||||
msgLen = len(msg)
|
||||
|
||||
# TODO: Multiple byte conversions
|
||||
buffer = struct.pack(b"<4sxiiB" + (str(msgLen) + "s").encode(), b"TEXT", x, y, msgLen, msg.encode())
|
||||
self.sendUDP(buffer)
|
||||
|
||||
def sendVIEW(self, view):
|
||||
"""Sets the camera view in X-Plane
|
||||
|
||||
Args:
|
||||
view: The view to use. The ViewType class provides named constants
|
||||
for known views.
|
||||
"""
|
||||
# Preconditions
|
||||
if view < ViewType.Forwards or view > ViewType.FullscreenNoHud:
|
||||
raise ValueError("Unknown view command.")
|
||||
|
||||
# Pack buffer
|
||||
buffer = struct.pack(b"<4sxi", b"VIEW", view)
|
||||
|
||||
# Send message
|
||||
self.sendUDP(buffer)
|
||||
|
||||
def sendWYPT(self, op, points):
|
||||
"""Adds, removes, or clears waypoints. Waypoints are three dimensional points on or
|
||||
above the Earth's surface that are represented visually in the simulator. Each
|
||||
point consists of a latitude and longitude expressed in fractional degrees and
|
||||
an altitude expressed as meters above sea level.
|
||||
|
||||
Args:
|
||||
op: The operation to perform. Pass `1` to add waypoints,
|
||||
`2` to remove waypoints, and `3` to clear all waypoints.
|
||||
points: A sequence of floating point values representing latitude, longitude, and
|
||||
altitude triples. The length of this array should always be divisible by 3.
|
||||
"""
|
||||
if op < 1 or op > 3:
|
||||
raise ValueError("Invalid operation specified.")
|
||||
if len(points) % 3 != 0:
|
||||
raise ValueError("Invalid points. Points should be divisible by 3.")
|
||||
if len(points) / 3 > 255:
|
||||
raise ValueError("Too many points. You can only send 255 points at a time.")
|
||||
|
||||
if op == 3:
|
||||
buffer = struct.pack(b"<4sxBB", b"WYPT", 3, 0)
|
||||
else:
|
||||
buffer = struct.pack(("<4sxBB" + str(len(points)) + "f").encode(), b"WYPT", op, len(points), *points)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
|
||||
class ViewType(object):
|
||||
Forwards = 73
|
||||
Down = 74
|
||||
Left = 75
|
||||
Right = 76
|
||||
Back = 77
|
||||
Tower = 78
|
||||
Runway = 79
|
||||
Chase = 80
|
||||
Follow = 81
|
||||
FollowWithPanel = 82
|
||||
Spot = 83
|
||||
FullscreenWithHud = 84
|
||||
FullscreenNoHud = 85
|
||||
58
Python3/xplaneConnect.pyproj
Normal file
58
Python3/xplaneConnect.pyproj
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>3c7a940d-17c8-4e91-882f-9bc8b1d2f54b</ProjectGuid>
|
||||
<ProjectHome>.</ProjectHome>
|
||||
<StartupFile>src\basicExample.py</StartupFile>
|
||||
<SearchPath>
|
||||
</SearchPath>
|
||||
<WorkingDirectory>.</WorkingDirectory>
|
||||
<OutputPath>.</OutputPath>
|
||||
<Name>XPlaneConnect</Name>
|
||||
<RootNamespace>XPlaneConnect</RootNamespace>
|
||||
<InterpreterId>{9a7a9026-48c1-4688-9d5d-e5699d47d074}</InterpreterId>
|
||||
<InterpreterVersion>2.7</InterpreterVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="src\playbackExample.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="src\monitorExample.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="src\xpc.py" />
|
||||
<Compile Include="src\basicExample.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="src\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<InterpreterReference Include="{9a7a9026-48c1-4688-9d5d-e5699d47d074}\2.7" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<PtvsTargetsFile>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets</PtvsTargetsFile>
|
||||
</PropertyGroup>
|
||||
<Import Condition="Exists($(PtvsTargetsFile))" Project="$(PtvsTargetsFile)" />
|
||||
<Import Condition="!Exists($(PtvsTargetsFile))" Project="$(MSBuildToolsPath)\Microsoft.Common.targets" />
|
||||
<!-- Uncomment the CoreCompile target to enable the Build command in
|
||||
Visual Studio and specify your pre- and post-build commands in
|
||||
the BeforeBuild and AfterBuild targets below. -->
|
||||
<!--<Target Name="CoreCompile" />-->
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
</Project>
|
||||
24
Python3/xplaneConnect.sln
Normal file
24
Python3/xplaneConnect.sln
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "XPlaneConnect", "XPlaneConnect.pyproj", "{3C7A940D-17C8-4E91-882F-9BC8B1D2F54B}"
|
||||
EndProject
|
||||
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "Tests", "..\TestScripts\Python Tests\Tests.pyproj", "{6931EBB2-4E01-4C5A-86B6-668C0E75051B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3C7A940D-17C8-4E91-882F-9BC8B1D2F54B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3C7A940D-17C8-4E91-882F-9BC8B1D2F54B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6931EBB2-4E01-4C5A-86B6-668C0E75051B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6931EBB2-4E01-4C5A-86B6-668C0E75051B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -68,7 +68,7 @@ the next official release.
|
||||
|
||||
|
||||
### Notices
|
||||
Copyright ©2013-2017 United States Government as represented by the Administrator
|
||||
Copyright ©2013-2018 United States Government as represented by the Administrator
|
||||
of the National Aeronautics and Space Administration. All Rights Reserved.
|
||||
|
||||
No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef CTRLTESTS_H
|
||||
#define CTRLTESTS_H
|
||||
@@ -23,7 +23,7 @@ int doCTRLTest(XPCSocket *sock, char* drefs[7], float values[], int size, int ac
|
||||
{
|
||||
result = getDREFs(*sock, drefs, data, 7, sizes);
|
||||
}
|
||||
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
@@ -102,7 +102,7 @@ int basicCTRLTest(char** drefs, int ac)
|
||||
CTRL[4] = -998;
|
||||
CTRL[5] = -998;
|
||||
result = doCTRLTest(&sock, drefs, CTRL, 6, ac, expected);
|
||||
|
||||
|
||||
pauseSim(sock, 0);
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
@@ -200,4 +200,4 @@ int testGETC_NonPlayer()
|
||||
float CTRL[7] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F, -1.5F };
|
||||
return doGETCTest(CTRL, 2, CTRL);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef DATATESTS_H
|
||||
#define DATATESTS_H
|
||||
@@ -59,4 +59,4 @@ int testDATA()
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef DREFTESTS_H
|
||||
#define DREFTESTS_H
|
||||
@@ -244,4 +244,4 @@ int testDREF()
|
||||
return doDREFTest(drefs, values, expected, 6, sizes);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef POSITESTS_H
|
||||
#define POSITESTS_H
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
int doPOSITest(char* drefs[7], float values[], int size, int ac, float expected[7])
|
||||
int doPOSITest(char* drefs[7], double values[], int size, int ac, double expected[7])
|
||||
{
|
||||
float* data[7];
|
||||
int sizes[7];
|
||||
@@ -32,15 +32,15 @@ int doPOSITest(char* drefs[7], float values[], int size, int ac, float expected[
|
||||
}
|
||||
|
||||
// Test values
|
||||
float actual[7];
|
||||
double actual[7];
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
actual[i] = data[i][0];
|
||||
}
|
||||
return compareArray(expected, actual, 7);
|
||||
return compareDoubleArray(expected, actual, 7);
|
||||
}
|
||||
|
||||
int doGETPTest(float values[7], int ac, float expected[7])
|
||||
int doGETPTest(double values[7], int ac, double expected[7])
|
||||
{
|
||||
// Execute Test
|
||||
float actual[7];
|
||||
@@ -70,8 +70,8 @@ int doGETPTest(float values[7], int ac, float expected[7])
|
||||
int basicPOSITest(char** drefs, int ac)
|
||||
{
|
||||
// Set psoition and initial orientation
|
||||
float POSI[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 };
|
||||
float expected[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 };
|
||||
double POSI[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 };
|
||||
double expected[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 };
|
||||
int result = doPOSITest(drefs, POSI, 7, ac, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
@@ -79,9 +79,9 @@ int basicPOSITest(char** drefs, int ac)
|
||||
}
|
||||
|
||||
// Set orientation
|
||||
POSI[0] = -998.0F;
|
||||
POSI[1] = -998.0F;
|
||||
POSI[2] = -998.0F;
|
||||
POSI[0] = -998.0;
|
||||
POSI[1] = -998.0;
|
||||
POSI[2] = -998.0;
|
||||
POSI[3] = 5.0F;
|
||||
POSI[4] = -5.0F;
|
||||
POSI[5] = 10.0F;
|
||||
@@ -101,10 +101,10 @@ int basicPOSITest(char** drefs, int ac)
|
||||
expected[0] = loc[0][0];
|
||||
expected[1] = loc[1][0];
|
||||
expected[2] = loc[2][0];
|
||||
expected[3] = 5.0F;
|
||||
expected[4] = -5.0F;
|
||||
expected[5] = 10.0F;
|
||||
expected[6] = 0.0F;
|
||||
expected[3] = 5.0;
|
||||
expected[4] = -5.0;
|
||||
expected[5] = 10.0;
|
||||
expected[6] = 0.0;
|
||||
result = doPOSITest(drefs, POSI, 7, ac, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
@@ -145,14 +145,14 @@ int testPOSI_NonPlayer()
|
||||
|
||||
int testGetPOSI_Player()
|
||||
{
|
||||
float POSI[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 };
|
||||
double POSI[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 };
|
||||
return doGETPTest(POSI, 0, POSI);
|
||||
}
|
||||
|
||||
int testGetPOSI_NonPlayer()
|
||||
{
|
||||
float POSI[7] = { 37.624F, -122.06899F, 1500, 0, 0, 0, 1 };
|
||||
double POSI[7] = { 37.624, -122.06899, 1500, 0, 0, 0, 1 };
|
||||
return doGETPTest(POSI, 3, POSI);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef SIMUTESTS_H
|
||||
#define SIMIUTESTS_H
|
||||
@@ -16,7 +16,7 @@ int doSIMUTest(int value, float expected)
|
||||
int result = pauseSim(sock, value);
|
||||
if (result >= 0)
|
||||
{
|
||||
result = getDREF(sock, dref, &actual, &size);
|
||||
result = getDREF(sock, dref, actual, &size);
|
||||
}
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
@@ -78,4 +78,4 @@ int testSIMU_Toggle()
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Test.h"
|
||||
|
||||
@@ -56,4 +56,28 @@ int compareArrays(float* expected[], int esizes[], float* actual[], int asizes[]
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int compareDoubleArray(double expected[], double actual[], int size)
|
||||
{
|
||||
return compareDoubleArrays(&expected, &size, &actual, &size, 1);
|
||||
}
|
||||
|
||||
int compareDoubleArrays(double* expected[], int esizes[], double* actual[], int asizes[], int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (esizes[i] != asizes[i])
|
||||
{
|
||||
return -100 - i;
|
||||
}
|
||||
for (int j = 0; j < esizes[i]; ++j)
|
||||
{
|
||||
if (!feq(actual[i][j], expected[i][j]) && !isnan(expected[i][j]))
|
||||
{
|
||||
return -1000 - i * 100 - j;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef TESTRUNNER_H
|
||||
#define TESTRUNNER_H
|
||||
@@ -33,5 +33,7 @@ void runTest(int(*test)(), char* name);
|
||||
int compareFloat(float expected, float actual);
|
||||
int compareArray(float expected[], float actual[], int size);
|
||||
int compareArrays(float* expected[], int esizes[], float* actual[], int asizes[], int count);
|
||||
int compareDoubleArray(double expected[], double actual[], int size);
|
||||
int compareDoubleArrays(double* expected[], int esizes[], double* actual[], int asizes[], int count);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef TEXTTESTS_H
|
||||
#define TEXTTESTS_H
|
||||
@@ -29,4 +29,4 @@ int testTEXT()
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef UDPTESTS_H
|
||||
#define UDPTESTS_H
|
||||
@@ -52,4 +52,4 @@ int testCONN()
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef VIEWTESTS_H
|
||||
#define VIEWTESTS_H
|
||||
@@ -70,4 +70,4 @@ int testView()
|
||||
|
||||
return doViewTest(XPC_VIEW_CHASE, XPC_VDREF_CHASE);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef WYPTTESTS_H
|
||||
#define WYPTTESTS_H
|
||||
@@ -39,4 +39,4 @@ int testWYPT()
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Test.h"
|
||||
#include "UDPTests.h"
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
printf("XPC Tests-c ");
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
printf("(Windows)\n");
|
||||
#elif (__APPLE__)
|
||||
@@ -23,7 +23,7 @@ int main(int argc, const char * argv[]) {
|
||||
#else
|
||||
printf("(Unable to determine operating system) \n")
|
||||
#endif
|
||||
|
||||
|
||||
// Basic Networking
|
||||
runTest(testOpen, "open");
|
||||
crossPlatformUSleep(SLEEP_AMOUNT);
|
||||
@@ -78,11 +78,10 @@ int main(int argc, const char * argv[]) {
|
||||
// setConn
|
||||
crossPlatformUSleep(SLEEP_AMOUNT);
|
||||
runTest(testCONN, "CONN");
|
||||
|
||||
|
||||
printf( "----------------\nTest Summary\n\tFailed: %i\n\tPassed: %i\n", testFailed, testPassed );
|
||||
printf("Press any key to exit.");
|
||||
getchar();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -542,15 +542,15 @@ public class XPlaneConnectTest
|
||||
public void testSendPOSI() throws IOException
|
||||
{
|
||||
String[] drefs = {
|
||||
"sim/flightmodel/position/latitude",
|
||||
"sim/flightmodel/position/longitude",
|
||||
"sim/flightmodel/position/y_agl",
|
||||
"sim/flightmodel/position/phi",
|
||||
"sim/flightmodel/position/theta",
|
||||
"sim/flightmodel/position/psi",
|
||||
"sim/cockpit/switches/gear_handle_status"
|
||||
"sim/flightmodel/position/latitude",
|
||||
"sim/flightmodel/position/longitude",
|
||||
"sim/flightmodel/position/y_agl",
|
||||
"sim/flightmodel/position/phi",
|
||||
"sim/flightmodel/position/theta",
|
||||
"sim/flightmodel/position/psi",
|
||||
"sim/cockpit/switches/gear_handle_status"
|
||||
};
|
||||
float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1};
|
||||
double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1};
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.pauseSim(true);
|
||||
@@ -585,7 +585,7 @@ public class XPlaneConnectTest
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSendPOSI_LongCtrl() throws IOException
|
||||
{
|
||||
float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1, -998};
|
||||
double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1, -998};
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.sendPOSI(posi);
|
||||
@@ -595,7 +595,7 @@ public class XPlaneConnectTest
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSendPOSI_NegativeAircraftNum() throws IOException
|
||||
{
|
||||
float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1, -998};
|
||||
double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1, -998};
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.sendPOSI(posi, -1);
|
||||
@@ -605,7 +605,7 @@ public class XPlaneConnectTest
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSendPOSI_LargeAircraftNum() throws IOException
|
||||
{
|
||||
float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1, -998};
|
||||
double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1, -998};
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.sendPOSI(posi, 300);
|
||||
@@ -702,12 +702,12 @@ public class XPlaneConnectTest
|
||||
@Test
|
||||
public void testGetPOSI() throws IOException
|
||||
{
|
||||
float[] values = { 37.524F, -122.06899F, 2500.0F, 45.0F, -45.0F, 15.0F, 1.0F };
|
||||
double[] values = { 37.524, -122.06899, 2500.0, 45.0, -45.0, 15.0, 1.0 };
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.pauseSim(true);
|
||||
xpc.sendPOSI(values);
|
||||
float[] actual = xpc.getPOSI(0);
|
||||
double[] actual = xpc.getPOSI(0);
|
||||
|
||||
assertArrayEquals(values, actual, 1e-4F);
|
||||
}
|
||||
@@ -725,4 +725,4 @@ public class XPlaneConnectTest
|
||||
assertArrayEquals(values, actual, 1e-4F);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
73
TestScripts/Java Tests/XPlaneDiscoveryTests.java
Normal file
73
TestScripts/Java Tests/XPlaneDiscoveryTests.java
Normal file
@@ -0,0 +1,73 @@
|
||||
package gov.nasa.xpc.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import gov.nasa.xpc.discovery.Beacon;
|
||||
import gov.nasa.xpc.discovery.BeaconParser;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
|
||||
|
||||
public class XPlaneDiscoveryTests {
|
||||
|
||||
private BeaconParser parser;
|
||||
private DatagramPacket packet;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
parser = new BeaconParser();
|
||||
byte[] bytes = HexHelper.decodeHexString("4245434E0071BFFC2B0000312E332D72632E310000000000000000");
|
||||
packet = new DatagramPacket(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readBeaconParsesPort() throws IOException {
|
||||
Beacon beacon = parser.readBCN(packet);
|
||||
assertEquals(beacon.getPluginPort(), 49009);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readBeaconParsesXplaneVersion() throws IOException {
|
||||
Beacon beacon = parser.readBCN(packet);
|
||||
assertEquals(beacon.getXplaneVersion(), "112.60");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readBeaconParsesPluginVersion() throws IOException {
|
||||
Beacon beacon = parser.readBCN(packet);
|
||||
assertEquals(beacon.getPluginVersion(), "1.3-rc.1");
|
||||
}
|
||||
}
|
||||
|
||||
class HexHelper {
|
||||
static byte[] decodeHexString(String hexString) {
|
||||
if (hexString.length() % 2 == 1) {
|
||||
throw new IllegalArgumentException("Invalid hexadecimal String supplied.");
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[hexString.length() / 2];
|
||||
for (int i = 0; i < hexString.length(); i += 2) {
|
||||
bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static byte hexToByte(String hexString) {
|
||||
int firstDigit = toDigit(hexString.charAt(0));
|
||||
int secondDigit = toDigit(hexString.charAt(1));
|
||||
return (byte) ((firstDigit << 4) + secondDigit);
|
||||
}
|
||||
|
||||
private static int toDigit(char hexChar) {
|
||||
int digit = Character.digit(hexChar, 16);
|
||||
if (digit == -1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid Hexadecimal Character: " + hexChar);
|
||||
}
|
||||
return digit;
|
||||
}
|
||||
}
|
||||
165
azure-pipelines.yml
Normal file
165
azure-pipelines.yml
Normal file
@@ -0,0 +1,165 @@
|
||||
# Xcode
|
||||
# Build, test, and archive an Xcode workspace on macOS.
|
||||
# Add steps that install certificates, test, sign, and distribute an app, save build artifacts, and more:
|
||||
# https://docs.microsoft.com/azure/devops/pipelines/languages/xcode
|
||||
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
# Build all branches starting with 'ms-' This is useful when making and testing chanes made to this file
|
||||
- ms-*
|
||||
tags:
|
||||
include:
|
||||
- '*'
|
||||
# pr:
|
||||
# - '*'
|
||||
variables:
|
||||
xpcBuildOutputPath: xpcPlugin/XPlaneConnect/
|
||||
xpcArtifactNameLinux: xpc-linux
|
||||
xpcArtifactNameMac: xpc-macos
|
||||
xpcArtifactNameWindows: xpc-windows
|
||||
xpcPackageName: XPlaneConnect
|
||||
|
||||
# The Github Release tasks requires a GH 'service connection' to be setup in the MS Azure Account
|
||||
# This connection must be setup in with a GH token in the MS Azure Project Settings
|
||||
#
|
||||
# https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/github-release?view=azure-devops
|
||||
# https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#sep-github
|
||||
xpcGitHubConnection: XPC-Azure
|
||||
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
jobs:
|
||||
- job: macOS
|
||||
pool:
|
||||
vmImage: 'macos-latest'
|
||||
|
||||
steps:
|
||||
- task: Xcode@5
|
||||
inputs:
|
||||
actions: 'build'
|
||||
scheme: ''
|
||||
sdk: 'macosx10.14'
|
||||
configuration: 'Release'
|
||||
xcWorkspacePath: 'xpcPlugin/xpcPlugin.xcodeproj'
|
||||
xcodeVersion: 'default' # Options: 8, 9, 10, default, specifyPath
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: '$(xpcArtifactNameMac)'
|
||||
targetPath: '$(xpcBuildOutputPath)'
|
||||
|
||||
- job: Linux
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y g++-5 mesa-common-dev g++-multilib g++-5-multilib
|
||||
displayName: 'apt install'
|
||||
|
||||
- script: |
|
||||
cd xpcPlugin
|
||||
cmake .
|
||||
make
|
||||
displayName: 'make'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'xpc-linux'
|
||||
targetPath: '$(xpcBuildOutputPath)'
|
||||
|
||||
- job: Windows
|
||||
pool:
|
||||
vmImage: 'vs2017-win2016'
|
||||
|
||||
variables:
|
||||
solution: 'xpcPlugin/xpcPlugin/xpcPlugin.sln'
|
||||
buildPlatform: 'Win32|x64'
|
||||
buildConfiguration: 'Release'
|
||||
appxPackageDir: '$(build.artifactStagingDirectory)\AppxPackages\\'
|
||||
|
||||
steps:
|
||||
- task: NuGetToolInstaller@0
|
||||
|
||||
- task: NuGetCommand@2
|
||||
inputs:
|
||||
restoreSolution: '$(solution)'
|
||||
|
||||
- task: VSBuild@1
|
||||
inputs:
|
||||
platform: 'Win32'
|
||||
solution: '$(solution)'
|
||||
configuration: '$(buildConfiguration)'
|
||||
msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload'
|
||||
|
||||
- task: VSBuild@1
|
||||
inputs:
|
||||
platform: 'x64'
|
||||
solution: '$(solution)'
|
||||
configuration: '$(buildConfiguration)'
|
||||
msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload'
|
||||
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
rm $(xpcBuildOutputPath)/win.exp
|
||||
rm $(xpcBuildOutputPath)/win.lib
|
||||
rm $(xpcBuildOutputPath)/64/win.exp
|
||||
rm $(xpcBuildOutputPath)/64/win.lib
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: '$(xpcArtifactNameWindows)'
|
||||
targetPath: '$(xpcBuildOutputPath)'
|
||||
|
||||
- stage: Deploy
|
||||
jobs:
|
||||
- job: Package_Binaries
|
||||
displayName: 'Package Binaries'
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: '$(xpcArtifactNameMac)'
|
||||
targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName)
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: '$(xpcArtifactNameLinux)'
|
||||
targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName)
|
||||
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: '$(xpcArtifactNameWindows)'
|
||||
targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName)
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: '$(xpcPackageName)'
|
||||
targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName)
|
||||
|
||||
# Archive Files
|
||||
- task: ArchiveFiles@2
|
||||
inputs:
|
||||
rootFolderOrFile: '$(System.DefaultWorkingDirectory)/$(xpcPackageName)'
|
||||
includeRootFolder: true
|
||||
archiveType: 'zip'
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip'
|
||||
|
||||
# Uploads the .zip to GitHub and creates a new "Release" with the commit tag
|
||||
# This tasks runs only on pushed tags
|
||||
- task: GitHubRelease@0
|
||||
inputs:
|
||||
gitHubConnection: '$(xpcGitHubConnection)'
|
||||
repositoryName: '$(Build.Repository.Name)'
|
||||
action: 'create'
|
||||
target: '$(Build.SourceVersion)'
|
||||
tagSource: 'auto'
|
||||
tag: $(tagName)
|
||||
assets: '$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip'
|
||||
isPreRelease: true
|
||||
@@ -10,6 +10,10 @@ add_definitions(-DXPLM200 -DLIN=1)
|
||||
|
||||
SET(CMAKE_C_COMPILER gcc)
|
||||
SET(CMAKE_CXX_COMPILER g++)
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
SET(XPC_OUTPUT_DIR "XPlaneConnect")
|
||||
SET(XPC_OUTPUT_NAME "lin")
|
||||
|
||||
add_library(xpc64 SHARED XPCPlugin.cpp
|
||||
DataManager.cpp
|
||||
@@ -17,9 +21,12 @@ add_library(xpc64 SHARED XPCPlugin.cpp
|
||||
Log.cpp
|
||||
Message.cpp
|
||||
MessageHandlers.cpp
|
||||
Timer.cpp
|
||||
UDPSocket.cpp)
|
||||
set_target_properties(xpc64 PROPERTIES PREFIX "" SUFFIX ".xpl")
|
||||
set_target_properties(xpc64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m64")
|
||||
set_target_properties(xpc64 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${XPC_OUTPUT_DIR}/64)
|
||||
set_target_properties(xpc64 PROPERTIES OUTPUT_NAME ${XPC_OUTPUT_NAME})
|
||||
set_target_properties(xpc64 PROPERTIES COMPILE_FLAGS "-m64 -fno-stack-protector" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m64 -fno-stack-protector")
|
||||
|
||||
add_library(xpc32 SHARED XPCPlugin.cpp
|
||||
DataManager.cpp
|
||||
@@ -27,9 +34,12 @@ add_library(xpc32 SHARED XPCPlugin.cpp
|
||||
Log.cpp
|
||||
Message.cpp
|
||||
MessageHandlers.cpp
|
||||
Timer.cpp
|
||||
UDPSocket.cpp)
|
||||
set_target_properties(xpc32 PROPERTIES PREFIX "" SUFFIX ".xpl")
|
||||
set_target_properties(xpc32 PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m32")
|
||||
set_target_properties(xpc32 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${XPC_OUTPUT_DIR})
|
||||
set_target_properties(xpc32 PROPERTIES OUTPUT_NAME ${XPC_OUTPUT_NAME})
|
||||
set_target_properties(xpc32 PROPERTIES COMPILE_FLAGS "-m32 -fno-stack-protector" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m32 -fno-stack-protector")
|
||||
|
||||
# Switch install targets when uncommenting the 32 bit line above.
|
||||
install(TARGETS xpc64 DESTINATION XPlaneConnect/64 RENAME lin.xpl)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// X-Plane API
|
||||
@@ -109,7 +109,7 @@ namespace XPC
|
||||
drefs.insert(make_pair(DREF_Latitude, XPLMFindDataRef("sim/flightmodel/position/latitude")));
|
||||
drefs.insert(make_pair(DREF_Longitude, XPLMFindDataRef("sim/flightmodel/position/longitude")));
|
||||
drefs.insert(make_pair(DREF_AGL, XPLMFindDataRef("sim/flightmodel/position/y_agl")));
|
||||
drefs.insert(make_pair(DREF_Elevation, XPLMFindDataRef("sim/flightmodel/position/elevation")));
|
||||
drefs.insert(make_pair(DREF_Elevation, XPLMFindDataRef("sim/flightmodel/position/elevation")));
|
||||
|
||||
drefs.insert(make_pair(DREF_LocalX, XPLMFindDataRef("sim/flightmodel/position/local_x")));
|
||||
drefs.insert(make_pair(DREF_LocalY, XPLMFindDataRef("sim/flightmodel/position/local_y")));
|
||||
@@ -522,7 +522,7 @@ namespace XPC
|
||||
Log::FormatLine(LOG_ERROR, "DMAN", "ERROR: invalid DREF %s", dref.c_str());
|
||||
return;
|
||||
}
|
||||
if (isnan(values[0]))
|
||||
if (std::isnan(values[0]))
|
||||
{
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Value must be a number (NaN received)");
|
||||
return;
|
||||
@@ -629,11 +629,12 @@ namespace XPC
|
||||
|
||||
if ((gear < -8.5 && gear > -9.5) || IsDefault(gear))
|
||||
{
|
||||
Log::WriteLine(LOG_INFO, "DMAN", "Not actually setting gear because of default value");
|
||||
return;
|
||||
}
|
||||
if (isnan(gear) || gear < 0 || gear > 1)
|
||||
if (std::isnan(gear) || gear < 0 || gear > 1)
|
||||
{
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Gear value must be 0 or 1");
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Gear value must be between 0 and 1");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -657,11 +658,11 @@ namespace XPC
|
||||
}
|
||||
}
|
||||
|
||||
void DataManager::SetPosition(float pos[3], char aircraft)
|
||||
void DataManager::SetPosition(double pos[3], char aircraft)
|
||||
{
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting position (%f, %f, %f) for aircraft %i",
|
||||
pos[0], pos[1], pos[2], aircraft);
|
||||
if (isnan(pos[0] + pos[1] + pos[2]))
|
||||
if (std::isnan(pos[0] + pos[1] + pos[2]))
|
||||
{
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Position must be a number (NaN received)");
|
||||
return;
|
||||
@@ -669,28 +670,28 @@ namespace XPC
|
||||
|
||||
if (IsDefault(pos[0]))
|
||||
{
|
||||
pos[0] = (float)GetDouble(DREF_Latitude, aircraft);
|
||||
pos[0] = GetDouble(DREF_Latitude, aircraft);
|
||||
}
|
||||
if (IsDefault(pos[1]))
|
||||
{
|
||||
pos[1] = (float)GetDouble(DREF_Longitude, aircraft);
|
||||
pos[1] = GetDouble(DREF_Longitude, aircraft);
|
||||
}
|
||||
if (IsDefault(pos[2]))
|
||||
{
|
||||
pos[2] = (float)GetDouble(DREF_Elevation, aircraft);
|
||||
pos[2] = GetDouble(DREF_Elevation, aircraft);
|
||||
}
|
||||
|
||||
// See: http://www.xsquawkbox.net/xpsdk/mediawiki/MovingThePlane
|
||||
// Need to get the aircraft's current orientation before moving and
|
||||
// reset the orientation after moving to update the quaternion
|
||||
float orient[3];
|
||||
orient[0] = GetFloat(DREF_Pitch, aircraft);
|
||||
orient[1] = GetFloat(DREF_Roll, aircraft);
|
||||
orient[2] = GetFloat(DREF_HeadingTrue, aircraft);
|
||||
// See: http://www.xsquawkbox.net/xpsdk/mediawiki/MovingThePlane
|
||||
// Need to get the aircraft's current orientation before moving and
|
||||
// reset the orientation after moving to update the quaternion
|
||||
float orient[3];
|
||||
orient[0] = GetFloat(DREF_Pitch, aircraft);
|
||||
orient[1] = GetFloat(DREF_Roll, aircraft);
|
||||
orient[2] = GetFloat(DREF_HeadingTrue, aircraft);
|
||||
|
||||
// Now set the aircraft's position. Need to set world position for
|
||||
// "long" moves, but since there isn't an easy way to calculate "long",
|
||||
// we just set it every time.
|
||||
// Now set the aircraft's position. Need to set world position for
|
||||
// "long" moves, but since there isn't an easy way to calculate "long",
|
||||
// we just set it every time.
|
||||
double local[3];
|
||||
XPLMWorldToLocal(pos[0], pos[1], pos[2], &local[0], &local[1], &local[2]);
|
||||
// If the sim is paused, setting global position won't update the
|
||||
@@ -699,19 +700,19 @@ namespace XPC
|
||||
Set(DREF_LocalY, local[1], aircraft);
|
||||
Set(DREF_LocalZ, local[2], aircraft);
|
||||
// If the sim is unpaused, this will override the above settings.
|
||||
Set(DREF_Latitude, (double)pos[0], aircraft);
|
||||
Set(DREF_Longitude, (double)pos[1], aircraft);
|
||||
Set(DREF_Elevation, (double)pos[2], aircraft);
|
||||
Set(DREF_Latitude, pos[0], aircraft);
|
||||
Set(DREF_Longitude, pos[1], aircraft);
|
||||
Set(DREF_Elevation, pos[2], aircraft);
|
||||
|
||||
// Now reset orientation to update q
|
||||
SetOrientation(orient, aircraft);
|
||||
// Now reset orientation to update q
|
||||
SetOrientation(orient, aircraft);
|
||||
}
|
||||
|
||||
void DataManager::SetOrientation(float orient[3], char aircraft)
|
||||
{
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting orientation (%f, %f, %f) for aircraft %i",
|
||||
orient[0], orient[1], orient[2], aircraft);
|
||||
if (isnan(orient[0] + orient[1] + orient[2]))
|
||||
if (std::isnan(orient[0] + orient[1] + orient[2]))
|
||||
{
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Orientation must be a number (NaN received)");
|
||||
return;
|
||||
@@ -762,7 +763,7 @@ namespace XPC
|
||||
{
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting flaps (value:%f)", value);
|
||||
|
||||
if (isnan(value))
|
||||
if (std::isnan(value))
|
||||
{
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Flap value must be a number (NaN received)");
|
||||
return;
|
||||
@@ -784,7 +785,7 @@ namespace XPC
|
||||
return -998.0F;
|
||||
}
|
||||
|
||||
bool DataManager::IsDefault(float value)
|
||||
bool DataManager::IsDefault(double value)
|
||||
{
|
||||
return value < -997.9 && value > -999.1;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_DATAMANAGER_H_
|
||||
#define XPCPLUGIN_DATAMANAGER_H_
|
||||
@@ -396,7 +396,7 @@ namespace XPC
|
||||
/// \param pos An array containing latitude, longitude and altitude in
|
||||
/// fractional degrees and meters above sea level.
|
||||
/// \param aircraft The aircraft to set the position of.
|
||||
static void SetPosition(float pos[3], char aircraft = 0);
|
||||
static void SetPosition(double pos[3], char aircraft = 0);
|
||||
|
||||
/// Sets the orientation of the specified aircraft.
|
||||
///
|
||||
@@ -417,7 +417,7 @@ namespace XPC
|
||||
///
|
||||
/// \param value The value to check.
|
||||
/// \returns true if value is a default value; otherwise false.
|
||||
static bool IsDefault(float value);
|
||||
static bool IsDefault(double value);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// X-Plane API
|
||||
@@ -173,7 +173,7 @@ namespace XPC
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for (size_t i = 0; i < numWaypoints; ++i)
|
||||
{
|
||||
LocalPoint* l = &localPoints[i];
|
||||
LocalPoint* l = &localPoints[i];
|
||||
glVertex3f((float)l->x, (float)l->y, (float)l->z);
|
||||
}
|
||||
glEnd();
|
||||
@@ -226,7 +226,7 @@ namespace XPC
|
||||
// Enable drawing if necessary
|
||||
if (!msgEnabled)
|
||||
{
|
||||
XPLMRegisterDrawCallback(MessageDrawCallback, xplm_Phase_Window, 0, NULL);
|
||||
XPLMRegisterDrawCallback(MessageDrawCallback, xplm_Phase_Window, 0, NULL);
|
||||
msgEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_DRAWING_H_
|
||||
#define XPCPLUGIN_DRAWING_H_
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Log.h"
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace XPC
|
||||
|
||||
std::fprintf(fd, "X-Plane Connect [Version %s]\n", version.c_str());
|
||||
std::fprintf(fd, "Compiled %s %s\n", __DATE__, __TIME__);
|
||||
std::fprintf(fd, "Copyright (c) 2013-2017 United States Government as represented by the\n");
|
||||
std::fprintf(fd, "Copyright (c) 2013-2018 United States Government as represented by the\n");
|
||||
std::fprintf(fd, "Administrator of the National Aeronautics and Space Administration.\n");
|
||||
std::fprintf(fd, "All Rights Reserved.\n\n");
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_LOG_H_
|
||||
#define XPCPLUGIN_LOG_H_
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace XPC
|
||||
{
|
||||
/// Handles logging for the plugin.
|
||||
///
|
||||
///
|
||||
/// \details Provides functions to write lines to the XPC log file.
|
||||
/// \author Jason Watkins
|
||||
/// \version 1.1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Message.h"
|
||||
#include "Log.h"
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace XPC
|
||||
{
|
||||
Message::Message() {}
|
||||
Message::Message() {}
|
||||
|
||||
Message Message::ReadFrom(const UDPSocket& sock)
|
||||
{
|
||||
@@ -110,17 +110,17 @@ namespace XPC
|
||||
else if (head == "DREF")
|
||||
{
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
string dref((char*)buffer + 6, buffer[5]);
|
||||
Log::FormatLine(LOG_DEBUG, "DBUG", " DREF (size %i) = %s", dref.length(), dref.c_str());
|
||||
ss.str("");
|
||||
int values = buffer[6 + buffer[5]];
|
||||
ss << " Values(size " << values << ") =";
|
||||
for (int i = 0; i < values; ++i)
|
||||
{
|
||||
ss << " " << *((float*)(buffer + values + 1 + sizeof(float) * i));
|
||||
string dref((char*)buffer + 6, buffer[5]);
|
||||
Log::FormatLine(LOG_DEBUG, "DBUG", " DREF (size %i) = %s", dref.length(), dref.c_str());
|
||||
ss.str("");
|
||||
int values = buffer[6 + buffer[5]];
|
||||
ss << " Values(size " << values << ") =";
|
||||
for (int i = 0; i < values; ++i)
|
||||
{
|
||||
ss << " " << *((float*)(buffer + values + 1 + sizeof(float) * i));
|
||||
}
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
}
|
||||
}
|
||||
else if (head == "GETC" || head == "GETP")
|
||||
{
|
||||
ss << " Aircraft:" << (int)buffer[5];
|
||||
@@ -129,15 +129,15 @@ namespace XPC
|
||||
else if (head == "GETD")
|
||||
{
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
int cur = 6;
|
||||
for (int i = 0; i < buffer[5]; ++i)
|
||||
{
|
||||
string dref((char*)buffer + cur + 1, buffer[cur]);
|
||||
Log::FormatLine(LOG_DEBUG, "DBUG", " #%i/%i (size:%i) %s",
|
||||
int cur = 6;
|
||||
for (int i = 0; i < buffer[5]; ++i)
|
||||
{
|
||||
string dref((char*)buffer + cur + 1, buffer[cur]);
|
||||
Log::FormatLine(LOG_DEBUG, "DBUG", " #%i/%i (size:%i) %s",
|
||||
i + 1, buffer[5], dref.length(), dref.c_str());
|
||||
cur += 1 + buffer[cur];
|
||||
}
|
||||
}
|
||||
cur += 1 + buffer[cur];
|
||||
}
|
||||
}
|
||||
else if (head == "POSI")
|
||||
{
|
||||
char aircraft = buffer[5];
|
||||
@@ -146,14 +146,14 @@ namespace XPC
|
||||
float orient[3];
|
||||
memcpy(pos, buffer + 6, 12);
|
||||
memcpy(orient, buffer + 18, 12);
|
||||
ss << " AC:" << (int)aircraft;
|
||||
ss << " AC:" << (int)aircraft;
|
||||
ss << " Pos:(" << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ") Orient:(";
|
||||
ss << orient[3] << ' ' << orient[4] << ' ' << orient[5] << ") Gear:";
|
||||
ss << orient[0] << ' ' << orient[1] << ' ' << orient[2] << ") Gear:";
|
||||
ss << gear;
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
}
|
||||
}
|
||||
else if (head == "SIMU")
|
||||
{
|
||||
{
|
||||
ss << ' ' << (int)buffer[5];
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
}
|
||||
@@ -163,9 +163,9 @@ namespace XPC
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
ss << " UNKNOWN HEADER ";
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_MESSAGE_H_
|
||||
#define XPCPLUGIN_MESSAGE_H_
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// X-Plane API
|
||||
@@ -20,9 +20,16 @@
|
||||
#include "Log.h"
|
||||
|
||||
#include "XPLMUtilities.h"
|
||||
#include "XPLMGraphics.h"
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
#define MULTICAST_GROUP "239.255.1.1"
|
||||
#define MULITCAST_PORT 49710
|
||||
|
||||
|
||||
namespace XPC
|
||||
{
|
||||
@@ -32,6 +39,8 @@ namespace XPC
|
||||
std::string MessageHandlers::connectionKey;
|
||||
MessageHandlers::ConnectionInfo MessageHandlers::connection;
|
||||
UDPSocket* MessageHandlers::sock;
|
||||
|
||||
static sockaddr multicast_address = UDPSocket::GetAddr(MULTICAST_GROUP, MULITCAST_PORT);
|
||||
|
||||
void MessageHandlers::SetSocket(UDPSocket* socket)
|
||||
{
|
||||
@@ -127,6 +136,28 @@ namespace XPC
|
||||
MessageHandlers::HandleUnknown(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion) {
|
||||
|
||||
unsigned char response[128] = "BECN";
|
||||
|
||||
std::size_t cur = 5;
|
||||
|
||||
// 2 bytes plugin port
|
||||
*((uint16_t *)(response + cur)) = pluginReceivePort;
|
||||
cur += sizeof(uint16_t);
|
||||
|
||||
// 4 bytes xplane version
|
||||
*((uint32_t*)(response + cur)) = xplaneVersion;
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
// plugin version
|
||||
int len = pluginVersion.length();
|
||||
memcpy(response + cur, pluginVersion.c_str(), len);
|
||||
cur += strlen(pluginVersion.c_str()) + len;
|
||||
|
||||
sock->SendTo(response, cur, &multicast_address);
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleConn(const Message& msg)
|
||||
{
|
||||
@@ -342,10 +373,11 @@ namespace XPC
|
||||
}
|
||||
case 20: // Position
|
||||
{
|
||||
float pos[3];
|
||||
pos[0] = values[i][2];
|
||||
pos[1] = values[i][3];
|
||||
pos[2] = values[i][4];
|
||||
// TODO: loss of precision here
|
||||
double pos[3];
|
||||
pos[0] = (double)values[i][2];
|
||||
pos[1] = (double)values[i][3];
|
||||
pos[2] = (double)values[i][4];
|
||||
DataManager::SetPosition(pos);
|
||||
break;
|
||||
}
|
||||
@@ -439,7 +471,7 @@ namespace XPC
|
||||
unsigned char aircraft = buffer[5];
|
||||
// TODO(jason-watkins): Get proper printf specifier for unsigned char
|
||||
Log::FormatLine(LOG_TRACE, "GCTL", "Getting control information for aircraft %u", aircraft);
|
||||
|
||||
|
||||
float throttle[8];
|
||||
unsigned char response[31] = "CTRL";
|
||||
*((float*)(response + 5)) = DataManager::GetFloat(DREF_Elevator, aircraft);
|
||||
@@ -524,13 +556,14 @@ namespace XPC
|
||||
|
||||
unsigned char response[34] = "POSI";
|
||||
response[5] = (char)DataManager::GetInt(DREF_GearHandle, aircraft);
|
||||
// TODO change lat/lon/h to double?
|
||||
*((float*)(response + 6)) = (float)DataManager::GetDouble(DREF_Latitude, aircraft);
|
||||
*((float*)(response + 10)) = (float)DataManager::GetDouble(DREF_Longitude, aircraft);
|
||||
*((float*)(response + 14)) = (float)DataManager::GetDouble(DREF_Elevation, aircraft);
|
||||
*((float*)(response + 18)) = DataManager::GetFloat(DREF_Pitch, aircraft);
|
||||
*((float*)(response + 22)) = DataManager::GetFloat(DREF_Roll, aircraft);
|
||||
*((float*)(response + 26)) = DataManager::GetFloat(DREF_HeadingTrue, aircraft);
|
||||
|
||||
|
||||
float gear[10];
|
||||
DataManager::GetFloatArray(DREF_GearDeploy, gear, 10, aircraft);
|
||||
*((float*)(response + 30)) = gear[0];
|
||||
@@ -545,18 +578,37 @@ namespace XPC
|
||||
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
const std::size_t size = msg.GetSize();
|
||||
if (size < 34)
|
||||
|
||||
char aircraftNumber = buffer[5];
|
||||
float gear = *((float*)(buffer + 42));
|
||||
double posd[3];
|
||||
float orient[3];
|
||||
|
||||
if (size == 34) /* lat/lon/h as 32-bit float */
|
||||
{
|
||||
Log::FormatLine(LOG_ERROR, "POSI", "ERROR: Unexpected size: %i (Expected at least 34)", size);
|
||||
posd[0] = *((float*)&buffer[6]);
|
||||
posd[1] = *((float*)&buffer[10]);
|
||||
posd[2] = *((float*)&buffer[14]);
|
||||
memcpy(orient, buffer + 18, 12);
|
||||
}
|
||||
else if (size == 46) /* lat/lon/h as 64-bit double */
|
||||
{
|
||||
memcpy(posd, buffer + 6, 3*8);
|
||||
memcpy(orient, buffer + 30, 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::FormatLine(LOG_ERROR, "POSI", "ERROR: Unexpected size: %i (Expected 34 or 46)", size);
|
||||
return;
|
||||
}
|
||||
|
||||
char aircraftNumber = buffer[5];
|
||||
float gear = *((float*)(buffer + 30));
|
||||
float pos[3];
|
||||
float orient[3];
|
||||
memcpy(pos, buffer + 6, 12);
|
||||
memcpy(orient, buffer + 18, 12);
|
||||
/* convert float to double */
|
||||
DataManager::SetPosition(posd, aircraftNumber);
|
||||
DataManager::SetOrientation(orient, aircraftNumber);
|
||||
if (gear >= 0)
|
||||
{
|
||||
DataManager::SetGear(gear, true, aircraftNumber);
|
||||
}
|
||||
|
||||
if (aircraftNumber > 0)
|
||||
{
|
||||
@@ -569,13 +621,6 @@ namespace XPC
|
||||
DataManager::Set(DREF_PauseAI, ai, 0, 20);
|
||||
}
|
||||
}
|
||||
|
||||
DataManager::SetPosition(pos, aircraftNumber);
|
||||
DataManager::SetOrientation(orient, aircraftNumber);
|
||||
if (gear != -1)
|
||||
{
|
||||
DataManager::SetGear(gear, true, aircraftNumber);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleSimu(const Message& msg)
|
||||
@@ -583,13 +628,13 @@ namespace XPC
|
||||
// Update log
|
||||
Log::FormatLine(LOG_TRACE, "SIMU", "Message Received (Conn %i)", connection.id);
|
||||
|
||||
char v = msg.GetBuffer()[5];
|
||||
if (v < 0 || v > 2)
|
||||
unsigned char v = msg.GetBuffer()[5];
|
||||
if (v < 0 || (v > 2 && v < 100) || (v > 119 && v < 200) || v > 219)
|
||||
{
|
||||
Log::FormatLine(LOG_ERROR, "SIMU", "ERROR: Invalid argument: %i", v);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int value[20];
|
||||
if (v == 2)
|
||||
{
|
||||
@@ -599,6 +644,16 @@ namespace XPC
|
||||
value[i] = value[i] ? 0 : 1;
|
||||
}
|
||||
}
|
||||
else if ((v >= 100) && (v < 120))
|
||||
{
|
||||
DataManager::GetIntArray(DREF_Pause, value, 20);
|
||||
value[v - 100] = 1;
|
||||
}
|
||||
else if ((v >= 200) && (v < 220))
|
||||
{
|
||||
DataManager::GetIntArray(DREF_Pause, value, 20);
|
||||
value[v - 200] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 20; ++i)
|
||||
@@ -610,18 +665,27 @@ namespace XPC
|
||||
// Set DREF
|
||||
DataManager::Set(DREF_Pause, value, 20);
|
||||
|
||||
switch (v)
|
||||
if (v == 0)
|
||||
{
|
||||
case 0:
|
||||
Log::WriteLine(LOG_INFO, "SIMU", "Simulation resumed");
|
||||
break;
|
||||
case 1:
|
||||
Log::WriteLine(LOG_INFO, "SIMU", "Simulation paused");
|
||||
break;
|
||||
case 2:
|
||||
Log::FormatLine(LOG_INFO, "SIMU", "Simulation switched to %i", value[0]);
|
||||
break;
|
||||
Log::WriteLine(LOG_INFO, "SIMU", "Simulation resumed for all a/c");
|
||||
}
|
||||
else if (v == 1)
|
||||
{
|
||||
Log::WriteLine(LOG_INFO, "SIMU", "Simulation paused for all a/c");
|
||||
}
|
||||
else if (v == 2)
|
||||
{
|
||||
Log::FormatLine(LOG_INFO, "SIMU", "Simulation switched to %i for all a/c", value[0]);
|
||||
}
|
||||
else if ((v >= 100) && (v < 120))
|
||||
{
|
||||
Log::FormatLine(LOG_INFO, "SIMU", "Simulation paused for a/c %i", (v-100));
|
||||
}
|
||||
else if ((v >= 200) && (v < 220))
|
||||
{
|
||||
Log::FormatLine(LOG_INFO, "SIMU", "Simulation resumed for a/c %i", (v-100));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleText(const Message& msg)
|
||||
@@ -653,21 +717,111 @@ namespace XPC
|
||||
Log::WriteLine(LOG_INFO, "TEXT", "[TEXT] Text set");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MessageHandlers::HandleView(const Message& msg)
|
||||
{
|
||||
// Update Log
|
||||
Log::FormatLine(LOG_TRACE, "VIEW", "Message Received(Conn %i)", connection.id);
|
||||
|
||||
int enable_camera_location = 0;
|
||||
|
||||
const std::size_t size = msg.GetSize();
|
||||
if (size != 9)
|
||||
if (size == 9)
|
||||
{
|
||||
Log::FormatLine(LOG_ERROR, "VIEW", "Error: Unexpected length. Message was %d bytes, expected 9.", size);
|
||||
// default view switcher as before
|
||||
}
|
||||
else if (size == 37)
|
||||
{
|
||||
// Allow camera location control
|
||||
enable_camera_location = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::FormatLine(LOG_ERROR, "VIEW", "Error: Unexpected length. Message was %d bytes, expected 9 or 37.", size);
|
||||
return;
|
||||
}
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
int type = *((int*)(buffer + 5));
|
||||
XPLMCommandKeyStroke(type);
|
||||
|
||||
if(type == 79 && enable_camera_location == 1) // runway camera view
|
||||
{
|
||||
static struct CameraProperties campos;
|
||||
|
||||
campos.loc[0] = *(double*)(buffer+9);
|
||||
campos.loc[1] = *(double*)(buffer+17);
|
||||
campos.loc[2] = *(double*)(buffer+25);
|
||||
campos.direction[0] = -998;
|
||||
campos.direction[1] = -998;
|
||||
campos.direction[2] = -998;
|
||||
campos.zoom = *(float*)(buffer+33);
|
||||
|
||||
Log::FormatLine(LOG_TRACE, "VIEW", "Cam pos %f %f %f zoom %f", campos.loc[0], campos.loc[1], campos.loc[2],campos.zoom);
|
||||
|
||||
XPLMControlCamera(xplm_ControlCameraUntilViewChanges, CamFunc, &campos);
|
||||
}
|
||||
}
|
||||
|
||||
int MessageHandlers::CamFunc( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon)
|
||||
{
|
||||
if (outCameraPosition && !inIsLosingControl)
|
||||
{
|
||||
struct CameraProperties* campos = (struct CameraProperties*)inRefcon;
|
||||
|
||||
// camera position
|
||||
double clat = campos->loc[0];
|
||||
double clon = campos->loc[1];
|
||||
double calt = campos->loc[2];
|
||||
|
||||
double cX, cY, cZ;
|
||||
XPLMWorldToLocal(clat, clon, calt, &cX, &cY, &cZ);
|
||||
|
||||
outCameraPosition->x = cX;
|
||||
outCameraPosition->y = cY;
|
||||
outCameraPosition->z = cZ;
|
||||
|
||||
// Log::FormatLine(LOG_TRACE, "CAM", "Cam pos %f %f %f", clat, clon, calt);
|
||||
|
||||
if(campos->direction[0] == -998) // calculate camera direction
|
||||
{
|
||||
// aircraft position
|
||||
double x = XPC::DataManager::GetDouble(XPC::DREF_LocalX, 0);
|
||||
double y = XPC::DataManager::GetDouble(XPC::DREF_LocalY, 0);
|
||||
double z = XPC::DataManager::GetDouble(XPC::DREF_LocalZ, 0);
|
||||
|
||||
// relative position vector cam to plane
|
||||
double dx = x - cX;
|
||||
double dy = y - cY;
|
||||
double dz = z - cZ;
|
||||
|
||||
// Log::FormatLine(LOG_TRACE, "CAM", "Cam vect %f %f %f", dx, dy, dz);
|
||||
|
||||
double pi = 3.141592653589793;
|
||||
|
||||
// horizontal distance
|
||||
double dist = sqrt(dx*dx + dz*dz);
|
||||
|
||||
outCameraPosition->pitch = atan2(dy, dist) * 180.0/pi;
|
||||
|
||||
double angle = atan2(dz, dx) * 180.0/pi; // rel to pos right (pos X)
|
||||
|
||||
outCameraPosition->heading = 90 + angle; // rel to north
|
||||
|
||||
// Log::FormatLine(LOG_TRACE, "CAM", "Cam p %f hdg %f ", outCameraPosition->pitch, outCameraPosition->heading);
|
||||
|
||||
outCameraPosition->roll = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
outCameraPosition->roll = campos->direction[0];
|
||||
outCameraPosition->pitch = campos->direction[1];
|
||||
outCameraPosition->heading = campos->direction[2];
|
||||
}
|
||||
|
||||
outCameraPosition->zoom = campos->zoom;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleWypt(const Message& msg)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_MESSAGEHANDLERS_H_
|
||||
#define XPCPLUGIN_MESSAGEHANDLERS_H_
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "XPLMCamera.h"
|
||||
|
||||
|
||||
namespace XPC
|
||||
{
|
||||
/// A function that handles a message.
|
||||
@@ -26,15 +29,17 @@ namespace XPC
|
||||
/// socket.
|
||||
///
|
||||
/// \details After a message is read, HandleMessage analyzes the sender's network address
|
||||
/// to determine whether the sender is a new client. It then either loads
|
||||
/// connection details for an existing client, or creates a new connection record
|
||||
/// for new clients. Finally, the message handler checks the message type and
|
||||
/// dispatches the message to the appropriate handler.
|
||||
/// to determine whether the sender is a new client. It then either loads
|
||||
/// connection details for an existing client, or creates a new connection record
|
||||
/// for new clients. Finally, the message handler checks the message type and
|
||||
/// dispatches the message to the appropriate handler.
|
||||
/// \param msg The message to be processed.
|
||||
static void HandleMessage(Message& msg);
|
||||
|
||||
/// Sets the socket that message handlers use to send responses.
|
||||
static void SetSocket(UDPSocket* socket);
|
||||
|
||||
static void SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion);
|
||||
|
||||
private:
|
||||
// One handler per message type. Message types are descripbed on the
|
||||
@@ -54,6 +59,14 @@ namespace XPC
|
||||
|
||||
static void HandleXPlaneData(const Message& msg);
|
||||
static void HandleUnknown(const Message& msg);
|
||||
|
||||
static int CamFunc( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon);
|
||||
|
||||
struct CameraProperties{
|
||||
double loc[3];
|
||||
float direction[3];
|
||||
float zoom;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ void XPCBroadcaster::RemoveListener(
|
||||
}
|
||||
|
||||
void XPCBroadcaster::BroadcastMessage(
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam)
|
||||
{
|
||||
ListenerVector::iterator iter;
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
protected:
|
||||
|
||||
void BroadcastMessage(
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam=0);
|
||||
|
||||
private:
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
virtual ~XPCListener();
|
||||
|
||||
virtual void ListenToMessage(
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam)=0;
|
||||
|
||||
private:
|
||||
|
||||
@@ -21,7 +21,7 @@ void XPCProcess::StartProcessTime(float inSeconds)
|
||||
FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast<void *>(this));
|
||||
}
|
||||
|
||||
void XPCProcess::StartProcessCycles(long inCycles)
|
||||
void XPCProcess::StartProcessCycles(int inCycles)
|
||||
{
|
||||
mCallbackTime = -inCycles;
|
||||
if (!mInCallback)
|
||||
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
virtual ~XPCProcess();
|
||||
|
||||
void StartProcessTime(float inSeconds);
|
||||
void StartProcessCycles(long inCycles);
|
||||
void StartProcessCycles(int inCycles);
|
||||
void StopProcess(void);
|
||||
|
||||
virtual void DoProcessing(
|
||||
|
||||
@@ -22,7 +22,7 @@ XPCWidget::XPCWidget(
|
||||
inIsRoot ? NULL : inParent,
|
||||
inClass);
|
||||
|
||||
XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast<long>(this));
|
||||
XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast<intptr_t>(this));
|
||||
XPAddWidgetCallback(mWidget, WidgetCallback);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ XPCWidget::XPCWidget(
|
||||
mOwnsChildren(false),
|
||||
mOwnsWidget(inOwnsWidget)
|
||||
{
|
||||
XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast<long>(this));
|
||||
XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast<intptr_t>(this));
|
||||
XPAddWidgetCallback(mWidget, WidgetCallback);
|
||||
}
|
||||
|
||||
@@ -95,8 +95,8 @@ void XPCWidget::RemoveAttachment(
|
||||
int XPCWidget::HandleWidgetMessage(
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2)
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -104,8 +104,8 @@ int XPCWidget::HandleWidgetMessage(
|
||||
int XPCWidget::WidgetCallback(
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2)
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2)
|
||||
{
|
||||
XPCWidget * me = reinterpret_cast<XPCWidget *>(XPGetWidgetProperty(inWidget, xpProperty_Object, NULL));
|
||||
if (me == NULL)
|
||||
|
||||
@@ -14,8 +14,8 @@ public:
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2)=0;
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2)=0;
|
||||
|
||||
};
|
||||
|
||||
@@ -56,16 +56,16 @@ public:
|
||||
virtual int HandleWidgetMessage(
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2);
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2);
|
||||
|
||||
private:
|
||||
|
||||
static int WidgetCallback(
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2);
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2);
|
||||
|
||||
typedef std::pair<XPCWidgetAttachment *, bool> AttachmentInfo;
|
||||
typedef std::vector<AttachmentInfo> AttachmentVector;
|
||||
|
||||
@@ -22,8 +22,8 @@ int XPCKeyFilterAttachment::HandleWidgetMessage(
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2)
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2)
|
||||
{
|
||||
if (inMessage == xpMsg_KeyPress)
|
||||
{
|
||||
@@ -42,7 +42,7 @@ int XPCKeyFilterAttachment::HandleWidgetMessage(
|
||||
|
||||
XPCKeyMessageAttachment::XPCKeyMessageAttachment(
|
||||
char inKey,
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam,
|
||||
bool inConsume,
|
||||
bool inVkey,
|
||||
@@ -62,8 +62,8 @@ int XPCKeyMessageAttachment::HandleWidgetMessage(
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2)
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2)
|
||||
{
|
||||
if (inMessage == xpMsg_KeyPress)
|
||||
{
|
||||
@@ -81,7 +81,7 @@ int XPCKeyMessageAttachment::HandleWidgetMessage(
|
||||
|
||||
XPCPushButtonMessageAttachment::XPCPushButtonMessageAttachment(
|
||||
XPWidgetID inWidget,
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam,
|
||||
XPCListener * inListener) :
|
||||
mMsg(inMessage), mParam(inParam), mWidget(inWidget)
|
||||
@@ -98,8 +98,8 @@ int XPCPushButtonMessageAttachment::HandleWidgetMessage(
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2)
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2)
|
||||
{
|
||||
if ((inMessage == xpMsg_PushButtonPressed) && ((XPWidgetID) inParam1 == mWidget))
|
||||
{
|
||||
@@ -117,7 +117,7 @@ int XPCPushButtonMessageAttachment::HandleWidgetMessage(
|
||||
|
||||
XPCSliderMessageAttachment::XPCSliderMessageAttachment(
|
||||
XPWidgetID inWidget,
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam,
|
||||
XPCListener * inListener) :
|
||||
mMsg(inMessage), mParam(inParam), mWidget(inWidget)
|
||||
@@ -134,8 +134,8 @@ int XPCSliderMessageAttachment::HandleWidgetMessage(
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2)
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2)
|
||||
{
|
||||
if ((inMessage == xpMsg_ScrollBarSliderPositionChanged) && ((XPWidgetID) inParam1 == mWidget))
|
||||
{
|
||||
@@ -149,7 +149,7 @@ int XPCSliderMessageAttachment::HandleWidgetMessage(
|
||||
|
||||
XPCCloseButtonMessageAttachment::XPCCloseButtonMessageAttachment(
|
||||
XPWidgetID inWidget,
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam,
|
||||
XPCListener * inListener) :
|
||||
mMsg(inMessage), mParam(inParam), mWidget(inWidget)
|
||||
@@ -166,8 +166,8 @@ int XPCCloseButtonMessageAttachment::HandleWidgetMessage(
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2)
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2)
|
||||
{
|
||||
if ((inMessage == xpMessage_CloseButtonPushed) && ((XPWidgetID) inParam1 == mWidget))
|
||||
{
|
||||
@@ -190,8 +190,8 @@ int XPCTabGroupAttachment::HandleWidgetMessage(
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2)
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2)
|
||||
{
|
||||
if ((inMessage == xpMsg_KeyPress) && (KEY_CHAR(inParam1) == XPLM_KEY_TAB) &&
|
||||
((KEY_FLAGS(inParam1) & xplm_UpFlag) == 0))
|
||||
@@ -199,7 +199,7 @@ int XPCTabGroupAttachment::HandleWidgetMessage(
|
||||
bool backwards = (KEY_FLAGS(inParam1) & xplm_ShiftFlag) != 0;
|
||||
std::vector<XPWidgetID> widgets;
|
||||
XPCGetOrderedSubWidgets(inWidget, widgets);
|
||||
long n, index = 0;
|
||||
int n, index = 0;
|
||||
XPWidgetID focusWidget = XPGetWidgetWithFocus();
|
||||
std::vector<XPWidgetID>::iterator iter = std::find(widgets.begin(), widgets.end(), focusWidget);
|
||||
if (iter != widgets.end())
|
||||
@@ -254,8 +254,8 @@ static void XPCGetOrderedSubWidgets(
|
||||
std::vector<XPWidgetID>& outChildren)
|
||||
{
|
||||
outChildren.clear();
|
||||
long count = XPCountChildWidgets(inWidget);
|
||||
for (long n = 0; n < count; ++n)
|
||||
int count = XPCountChildWidgets(inWidget);
|
||||
for (int n = 0; n < count; ++n)
|
||||
{
|
||||
XPWidgetID child = XPGetNthChildWidget(inWidget, n);
|
||||
outChildren.push_back(child);
|
||||
|
||||
@@ -18,8 +18,8 @@ public:
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2);
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2);
|
||||
|
||||
private:
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
|
||||
XPCKeyMessageAttachment(
|
||||
char inKey,
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam,
|
||||
bool inConsume,
|
||||
bool inVkey,
|
||||
@@ -45,14 +45,14 @@ public:
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2);
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2);
|
||||
|
||||
private:
|
||||
|
||||
char mKey;
|
||||
bool mVkey;
|
||||
long mMsg;
|
||||
int mMsg;
|
||||
void * mParam;
|
||||
bool mConsume;
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
|
||||
XPCPushButtonMessageAttachment(
|
||||
XPWidgetID inWidget,
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam,
|
||||
XPCListener * inListener);
|
||||
virtual ~XPCPushButtonMessageAttachment();
|
||||
@@ -72,12 +72,12 @@ public:
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2);
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2);
|
||||
|
||||
private:
|
||||
XPWidgetID mWidget;
|
||||
long mMsg;
|
||||
int mMsg;
|
||||
void * mParam;
|
||||
};
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
|
||||
XPCSliderMessageAttachment(
|
||||
XPWidgetID inWidget,
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam,
|
||||
XPCListener * inListener);
|
||||
virtual ~XPCSliderMessageAttachment();
|
||||
@@ -95,12 +95,12 @@ public:
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2);
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2);
|
||||
|
||||
private:
|
||||
XPWidgetID mWidget;
|
||||
long mMsg;
|
||||
int mMsg;
|
||||
void * mParam;
|
||||
};
|
||||
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
|
||||
XPCCloseButtonMessageAttachment(
|
||||
XPWidgetID inWidget,
|
||||
long inMessage,
|
||||
int inMessage,
|
||||
void * inParam,
|
||||
XPCListener * inListener);
|
||||
virtual ~XPCCloseButtonMessageAttachment();
|
||||
@@ -119,12 +119,12 @@ public:
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2);
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2);
|
||||
|
||||
private:
|
||||
XPWidgetID mWidget;
|
||||
long mMsg;
|
||||
int mMsg;
|
||||
void * mParam;
|
||||
};
|
||||
|
||||
@@ -138,8 +138,8 @@ public:
|
||||
XPCWidget * inObject,
|
||||
XPWidgetMessage inMessage,
|
||||
XPWidgetID inWidget,
|
||||
long inParam1,
|
||||
long inParam2);
|
||||
intptr_t inParam1,
|
||||
intptr_t inParam2);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#if IBM
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
@@ -49,7 +49,7 @@ extern "C" {
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef APL
|
||||
#if APL
|
||||
#if __GNUC__ >= 4
|
||||
#define PLUGIN_API extern "C" __attribute__((visibility("default")))
|
||||
#elif __MACH__
|
||||
@@ -57,16 +57,16 @@ extern "C" {
|
||||
#else
|
||||
#define PLUGIN_API extern "C" __declspec(dllexport)
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#elif IBM
|
||||
#define PLUGIN_API extern "C" __declspec(dllexport)
|
||||
#endif
|
||||
#ifdef LIN
|
||||
#elif LIN
|
||||
#if __GNUC__ >= 4
|
||||
#define PLUGIN_API extern "C" __attribute__((visibility("default")))
|
||||
#else
|
||||
#define PLUGIN_API extern "C"
|
||||
#endif
|
||||
#else
|
||||
#error "Platform not defined!"
|
||||
#endif
|
||||
#else
|
||||
#if APL
|
||||
@@ -90,7 +90,7 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef APL
|
||||
#if APL
|
||||
#if XPLM
|
||||
#if __GNUC__ >= 4
|
||||
#define XPLM_API __attribute__((visibility("default")))
|
||||
@@ -102,15 +102,13 @@ extern "C" {
|
||||
#else
|
||||
#define XPLM_API
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#elif IBM
|
||||
#if XPLM
|
||||
#define XPLM_API __declspec(dllexport)
|
||||
#else
|
||||
#define XPLM_API __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#ifdef LIN
|
||||
#elif LIN
|
||||
#if XPLM
|
||||
#if __GNUC__ >= 4
|
||||
#define XPLM_API __attribute__((visibility("default")))
|
||||
@@ -120,6 +118,8 @@ extern "C" {
|
||||
#else
|
||||
#define XPLM_API
|
||||
#endif
|
||||
#else
|
||||
#error "Platform not defined!"
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
@@ -51,6 +51,11 @@ Mach-O if you want to use 2.0 features.
|
||||
|
||||
This section contains per-release notes for the history of the X-Plane SDK.
|
||||
|
||||
X-Plane SDK Release 2.1.3 11/14/13
|
||||
|
||||
Fixed XPC Wrappers to use int and intptr_t instead of long. This fixes
|
||||
crashes for plugins on 64-bit Windows.
|
||||
|
||||
X-Plane SDK Release 2.1.2 RC2 1/15/13
|
||||
|
||||
Removed headers from frameworks, as they don't work; updated README.
|
||||
|
||||
27
xpcPlugin/Timer.cpp
Normal file
27
xpcPlugin/Timer.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
|
||||
#include "Timer.h"
|
||||
using namespace std;
|
||||
|
||||
namespace XPC {
|
||||
void Timer::start(const chrono::milliseconds interval, const Callback &callback) {
|
||||
{
|
||||
running.test_and_set();
|
||||
th = thread([=]()
|
||||
{
|
||||
while (running.test_and_set()) {
|
||||
this_thread::sleep_for(interval);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::stop() {
|
||||
running.clear();
|
||||
if(th.joinable()) {
|
||||
th.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
30
xpcPlugin/Timer.h
Normal file
30
xpcPlugin/Timer.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
|
||||
#ifndef XPCPLUGIN_TIMER_H_
|
||||
#define XPCPLUGIN_TIMER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
namespace XPC {
|
||||
class Timer
|
||||
{
|
||||
std::atomic_flag running;
|
||||
std::thread th;
|
||||
|
||||
public:
|
||||
|
||||
using Callback = std::function<void(void)>;
|
||||
|
||||
void start(const std::chrono::milliseconds, const Callback &callback);
|
||||
|
||||
void stop();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* Timer_hpp */
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Log.h"
|
||||
#include "UDPSocket.h"
|
||||
@@ -138,6 +138,18 @@ namespace XPC
|
||||
Log::FormatLine(LOG_INFO, tag, "Send succeeded. (remote: %s)", GetHost(remote).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
sockaddr UDPSocket::GetAddr(std::string address, unsigned short port)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr(address.c_str());
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
sockaddr* sa = reinterpret_cast<sockaddr*>(&addr);
|
||||
return *sa;
|
||||
}
|
||||
|
||||
std::string UDPSocket::GetHost(sockaddr* sa)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_SOCKET_H_
|
||||
#define XPCPLUGIN_SOCKET_H_
|
||||
@@ -56,12 +56,14 @@ namespace XPC
|
||||
/// \param len The number of bytes to send.
|
||||
/// \param remote The destination socket.
|
||||
void SendTo(const unsigned char* buffer, std::size_t len, sockaddr* remote) const;
|
||||
|
||||
|
||||
/// Gets a string containing the IP address and port contained in the given sockaddr.
|
||||
///
|
||||
/// \param addr The socket address to parse.
|
||||
/// \returns A string representation of the socket address.
|
||||
static std::string GetHost(sockaddr* addr);
|
||||
|
||||
static sockaddr GetAddr(std::string address, unsigned short port);
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
SOCKET sock;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// DISCLAIMERS
|
||||
@@ -60,12 +60,16 @@
|
||||
#include "Log.h"
|
||||
#include "MessageHandlers.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
|
||||
// XPLM Includes
|
||||
#include "XPLMProcessing.h"
|
||||
#include "XPLMUtilities.h"
|
||||
|
||||
// System Includes
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
@@ -73,7 +77,12 @@
|
||||
#define RECVPORT 49009 // Port that the plugin receives commands on
|
||||
#define OPS_PER_CYCLE 20 // Max Number of operations per cycle
|
||||
|
||||
#define XPC_PLUGIN_VERSION "1.3-rc.1"
|
||||
|
||||
using namespace std;
|
||||
|
||||
XPC::UDPSocket* sock = NULL;
|
||||
XPC::Timer* timer = NULL;
|
||||
|
||||
double start;
|
||||
double lap;
|
||||
@@ -89,12 +98,12 @@ static float XPCFlightLoopCallback(float inElapsedSinceLastCall, float inElapsed
|
||||
|
||||
PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc)
|
||||
{
|
||||
strcpy(outName, "X-Plane Connect [Version 1.2.1]");
|
||||
strcpy(outName, "X-Plane Connect [Version 1.3-rc.1]");
|
||||
strcpy(outSig, "NASA.XPlaneConnect");
|
||||
strcpy(outDesc, "X Plane Communications Toolbox\nCopyright (c) 2013-2017 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved.");
|
||||
strcpy(outDesc, "X Plane Communications Toolbox\nCopyright (c) 2013-2018 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved.");
|
||||
|
||||
#if (__APPLE__)
|
||||
if ( abs(timeConvert) <= 1e-9 ) // is about 0
|
||||
if ( timeConvert <= 1e-9 ) // is about 0
|
||||
{
|
||||
mach_timebase_info_data_t timeBase;
|
||||
(void)mach_timebase_info(&timeBase);
|
||||
@@ -103,7 +112,7 @@ PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc)
|
||||
1000000000.0;
|
||||
}
|
||||
#endif
|
||||
XPC::Log::Initialize("1.2.1");
|
||||
XPC::Log::Initialize(XPC_PLUGIN_VERSION);
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Start");
|
||||
XPC::DataManager::Initialize();
|
||||
|
||||
@@ -131,12 +140,18 @@ PLUGIN_API void XPluginDisable(void)
|
||||
XPC::Drawing::ClearWaypoints();
|
||||
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Disabled, sockets closed");
|
||||
|
||||
timer->stop();
|
||||
delete timer;
|
||||
timer = NULL;
|
||||
}
|
||||
|
||||
PLUGIN_API int XPluginEnable(void)
|
||||
{
|
||||
// Open sockets
|
||||
sock = new XPC::UDPSocket(RECVPORT);
|
||||
timer = new XPC::Timer();
|
||||
|
||||
XPC::MessageHandlers::SetSocket(sock);
|
||||
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Enabled, sockets opened");
|
||||
@@ -145,11 +160,20 @@ PLUGIN_API int XPluginEnable(void)
|
||||
XPC::Log::FormatLine(LOG_INFO, "EXEC", "Benchmarking Enabled (Verbosity: %i)", benchmarkingSwitch);
|
||||
}
|
||||
XPC::Log::FormatLine(LOG_INFO, "EXEC", "Debug Logging Enabled (Verbosity: %i)", LOG_LEVEL);
|
||||
|
||||
|
||||
float interval = -1; // Call every frame
|
||||
void* refcon = NULL; // Don't pass anything to the callback directly
|
||||
XPLMRegisterFlightLoopCallback(XPCFlightLoopCallback, interval, refcon);
|
||||
|
||||
|
||||
int xpVer;
|
||||
XPLMGetVersions(&xpVer, NULL, NULL);
|
||||
|
||||
timer->start(chrono::milliseconds(1000), [=]{
|
||||
XPC::MessageHandlers::SendBeacon(XPC_PLUGIN_VERSION, RECVPORT, xpVer);
|
||||
});
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */; };
|
||||
BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */; };
|
||||
BE8361EF18C5591C00E9C923 /* mac.xpl in CopyFiles */ = {isa = PBXBuildFile; fileRef = D607B19909A556E400699BC3 /* mac.xpl */; };
|
||||
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */; };
|
||||
@@ -36,6 +37,8 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
3D0F44CC21C6D3E7008A0655 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = "<group>"; };
|
||||
3D0F44CD21C6D3E7008A0655 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = "<group>"; };
|
||||
BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XPCPlugin.cpp; sourceTree = SOURCE_ROOT; usesTabs = 1; };
|
||||
BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DataManager.cpp; sourceTree = "<group>"; };
|
||||
BEABAD2C1AE041A3007BA7DA /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataManager.h; sourceTree = "<group>"; };
|
||||
@@ -76,6 +79,7 @@
|
||||
AC4E46B809C2E0B3006B7E1B /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3D0F44CD21C6D3E7008A0655 /* Timer.cpp */,
|
||||
BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */,
|
||||
BEDC620218EDF1A7005DB364 /* xplaneConnect.c */,
|
||||
BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */,
|
||||
@@ -91,6 +95,7 @@
|
||||
BE953E0B1AEB183400CE4A8C /* inc */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3D0F44CC21C6D3E7008A0655 /* Timer.h */,
|
||||
BEDC620318EDF1A7005DB364 /* xplaneConnect.h */,
|
||||
BEABAD2C1AE041A3007BA7DA /* DataManager.h */,
|
||||
BEABAD301AE041A3007BA7DA /* Drawing.h */,
|
||||
@@ -190,6 +195,7 @@
|
||||
BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */,
|
||||
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */,
|
||||
BEABAD391AE041A3007BA7DA /* Drawing.cpp in Sources */,
|
||||
3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */,
|
||||
BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */,
|
||||
BEABAD3F1AE0498D007BA7DA /* UDPSocket.cpp in Sources */,
|
||||
);
|
||||
@@ -298,11 +304,14 @@
|
||||
D607B19C09A556E400699BC3 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_LINK_OBJC_RUNTIME = NO;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
|
||||
CONFIGURATION_BUILD_DIR = ./XPlaneConnect/;
|
||||
CURRENT_PROJECT_VERSION = 0.24;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
|
||||
@@ -337,11 +346,14 @@
|
||||
D607B19D09A556E400699BC3 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD)";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_LINK_OBJC_RUNTIME = NO;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
|
||||
CONFIGURATION_BUILD_DIR = ./XPlaneConnect/;
|
||||
CURRENT_PROJECT_VERSION = 0.24;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
|
||||
@@ -365,9 +377,7 @@
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/xplaneConnect-asdjuezcjkhojuewbyxhyhabxfwc/Build/Products/Debug",
|
||||
);
|
||||
MACH_O_TYPE = mh_bundle;
|
||||
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
|
||||
PRODUCT_NAME = mac;
|
||||
SDKROOT = macosx;
|
||||
STRIP_INSTALLED_PRODUCT = YES;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
# Visual Studio 2015
|
||||
VisualStudioVersion = 15.0.28307.168
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xpcPlugin", "xpcPlugin.vcxproj", "{6AEF5D28-2701-44FF-AE10-1DEF07C5CAEA}"
|
||||
EndProject
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -28,25 +28,25 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
@@ -121,7 +121,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>EnableAllWarnings</WarningLevel>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Full</Optimization>
|
||||
<PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
@@ -171,7 +171,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>EnableAllWarnings</WarningLevel>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Full</Optimization>
|
||||
<PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>
|
||||
@@ -206,6 +206,7 @@
|
||||
<ClInclude Include="..\Log.h" />
|
||||
<ClInclude Include="..\Message.h" />
|
||||
<ClInclude Include="..\MessageHandlers.h" />
|
||||
<ClCompile Include="..\Timer.h" />
|
||||
<ClInclude Include="..\UDPSocket.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -214,6 +215,7 @@
|
||||
<ClCompile Include="..\Log.cpp" />
|
||||
<ClCompile Include="..\Message.cpp" />
|
||||
<ClCompile Include="..\MessageHandlers.cpp" />
|
||||
<ClCompile Include="..\Timer.cpp" />
|
||||
<ClCompile Include="..\UDPSocket.cpp" />
|
||||
<ClCompile Include="..\XPCPlugin.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user