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:
Jason Watkins
2019-07-20 08:43:51 -07:00
committed by GitHub
parent 3ed3f8b014
commit a3be4cb1b6
92 changed files with 1937 additions and 375 deletions

2
.gitignore vendored
View File

@@ -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 #
##################

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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");
}
}

View File

@@ -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

View File

@@ -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 ****/
/*****************************************************************************/
/*****************************************************************************/

View File

@@ -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

View File

@@ -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
View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -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",

View 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>

View File

@@ -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");
}
}

View File

@@ -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();
}
}

View File

@@ -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);

View File

@@ -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>

Binary file not shown.

BIN
Java/lib/junit-4.12.jar Normal file

Binary file not shown.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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();
}
}

View 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);
}
}

View 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);
}

View 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);
}

View 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();
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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()

View File

@@ -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.

View 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()

View 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()

View 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
View 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

View 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
View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}
}
}
}

View 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
View 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

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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_

View File

@@ -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");

View File

@@ -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

View File

@@ -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());
}
}
}
}

View File

@@ -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_

View File

@@ -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)

View File

@@ -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
{

View File

@@ -42,7 +42,7 @@ void XPCBroadcaster::RemoveListener(
}
void XPCBroadcaster::BroadcastMessage(
long inMessage,
int inMessage,
void * inParam)
{
ListenerVector::iterator iter;

View File

@@ -20,7 +20,7 @@ public:
protected:
void BroadcastMessage(
long inMessage,
int inMessage,
void * inParam=0);
private:

View File

@@ -14,7 +14,7 @@ public:
virtual ~XPCListener();
virtual void ListenToMessage(
long inMessage,
int inMessage,
void * inParam)=0;
private:

View File

@@ -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)

View File

@@ -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(

View File

@@ -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)

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -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
/***************************************************************************

View File

@@ -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
View 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
View 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 */

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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.

View File

@@ -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;

View File

@@ -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

View File

@@ -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>