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 # # OS generated files #
###################### ######################
.DS_Store? .DS_Store?
.DS_Store
ehthumbs.db ehthumbs.db
Icon? Icon?
Thumbs.db Thumbs.db
@@ -69,6 +70,7 @@ build/
xcuserdata xcuserdata
*.moved-aside *.moved-aside
*.xccheckout *.xccheckout
xcshareddata
# IntelliJ Files # # 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. // National Aeronautics and Space Administration. All Rights Reserved.
// //
// DISCLAIMERS // DISCLAIMERS
@@ -70,7 +70,7 @@ int main(void)
tv.tv_usec = 100 * 1000; tv.tv_usec = 100 * 1000;
while (1) while (1)
{ {
float posi[7]; float posi[7]; // FIXME: change this to the 64-bit lat/lon/h
int result = getPOSI(client, posi, aircraftNum); int result = getPOSI(client, posi, aircraftNum);
if (result < 0) // Error in getPOSI if (result < 0) // Error in getPOSI
{ {

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. //National Aeronautics and Space Administration. All Rights Reserved.
// //
//DISCLAIMERS //DISCLAIMERS

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. //National Aeronautics and Space Administration. All Rights Reserved.
// //
//DISCLAIMERS //DISCLAIMERS

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. //National Aeronautics and Space Administration. All Rights Reserved.
// //
//DISCLAIMERS //DISCLAIMERS
@@ -35,7 +35,7 @@ int main(void)
}; };
char path[256] = { 0 }; char path[256] = { 0 };
displayStart("1.2.0.0"); displayStart("1.3-rc.1");
while (1) while (1)
{ {
switch (displayMenu("What would you like to do?", mainOpts, 3)) switch (displayMenu("What would you like to do?", mainOpts, 3))

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. //National Aeronautics and Space Administration. All Rights Reserved.
// //
//DISCLAIMERS //DISCLAIMERS
@@ -89,10 +89,10 @@ void playback(char* path, int interval)
displayMsg("Starting Playback..."); displayMsg("Starting Playback...");
XPCSocket sock = openUDP("127.0.0.1"); XPCSocket sock = openUDP("127.0.0.1");
float posi[7]; double posi[7];
while (!feof(fd) && !ferror(fd)) 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]); &posi[0], &posi[1], &posi[2], &posi[3], &posi[4], &posi[5], &posi[6]);
playbackSleep(interval); playbackSleep(interval);
if (result != 7) if (result != 7)

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. //National Aeronautics and Space Administration. All Rights Reserved.
// //
//DISCLAIMERS //DISCLAIMERS

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. //National Aeronautics and Space Administration. All Rights Reserved.
// //
//DISCLAIMERS //DISCLAIMERS
@@ -273,7 +273,7 @@ int setCONN(XPCSocket* sock, unsigned short port)
int pauseSim(XPCSocket sock, char pause) int pauseSim(XPCSocket sock, char pause)
{ {
// Validte input // 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); printError("pauseSim", "Invalid argument: %i", pause);
return -2; return -2;
@@ -563,13 +563,14 @@ int getPOSI(XPCSocket sock, float values[7], char ac)
printError("getPOSI", "Unexpected response length."); printError("getPOSI", "Unexpected response length.");
return -3; return -3;
} }
// TODO: change this to the 64-bit lat/lon/h
// Copy response into values // Copy response into values
memcpy(values, readBuffer + 6, 7 * sizeof(float)); memcpy(values, readBuffer + 6, 7 * sizeof(float));
return 0; return 0;
} }
int sendPOSI(XPCSocket sock, float values[], int size, char ac) int sendPOSI(XPCSocket sock, double values[], int size, char ac)
{ {
// Validate input // Validate input
if (ac < 0 || ac > 20) if (ac < 0 || ac > 20)
@@ -584,23 +585,32 @@ int sendPOSI(XPCSocket sock, float values[], int size, char ac)
} }
// Setup command // Setup command
// 5 byte header + up to 7 values * 5 bytes each unsigned char buffer[46] = "POSI";
unsigned char buffer[40] = "POSI"; buffer[4] = 0xff; //Placeholder for message length
buffer[5] = ac; buffer[5] = ac;
int i; // iterator 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) if (i < size)
{ {
val = values[i]; 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 // Send Command
if (sendUDP(sock, buffer, 40) < 0) if (sendUDP(sock, buffer, 46) < 0)
{ {
printError("sendPOSI", "Failed to send command"); printError("sendPOSI", "Failed to send command");
return -3; return -3;
@@ -735,7 +745,7 @@ int sendTEXT(XPCSocket sock, char* msg, int x, int y)
size_t len = 14 + msgLen; size_t len = 14 + msgLen;
memcpy(buffer + 5, &x, sizeof(int)); memcpy(buffer + 5, &x, sizeof(int));
memcpy(buffer + 9, &y, sizeof(int)); memcpy(buffer + 9, &y, sizeof(int));
buffer[13] = msgLen; buffer[13] = (unsigned char)msgLen;
strncpy(buffer + 14, msg, msgLen); strncpy(buffer + 14, msg, msgLen);
// Send Command // Send Command

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. //National Aeronautics and Space Administration. All Rights Reserved.
// //
//DISCLAIMERS //DISCLAIMERS
@@ -112,7 +112,7 @@ int setCONN(XPCSocket* sock, unsigned short port);
/// Pause or unpause the simulation. /// Pause or unpause the simulation.
/// ///
/// \param sock The socket to use to send the command. /// \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. /// \returns 0 if successful, otherwise a negative value.
int pauseSim(XPCSocket sock, char pause); int pauseSim(XPCSocket sock, char pause);
@@ -213,7 +213,7 @@ int getPOSI(XPCSocket sock, float values[7], char ac);
/// \param size The number of elements in values. /// \param size The number of elements in values.
/// \param ac The aircraft number to set the position of. 0 for the player aircraft. /// \param ac The aircraft number to set the position of. 0 for the player aircraft.
/// \returns 0 if successful, otherwise a negative value. /// \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 // Controls

View File

@@ -33,7 +33,7 @@ int main()
// Set Location/Orientation (sendPOSI) // Set Location/Orientation (sendPOSI)
// Set Up Position Array // Set Up Position Array
float POSI[9] = { 0.0 }; double POSI[9] = { 0.0 };
POSI[0] = 37.524; // Lat POSI[0] = 37.524; // Lat
POSI[1] = -122.06899; // Lon POSI[1] = -122.06899; // Lon
POSI[2] = 2500; // Alt POSI[2] = 2500; // Alt

15
Java/.idea/misc.xml generated
View File

@@ -1,19 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="11" project-jdk-type="JavaSDK">
<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">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View File

@@ -2,6 +2,7 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <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" /> <module fileurl="file://$PROJECT_DIR$/XPlaneConnect.iml" filepath="$PROJECT_DIR$/XPlaneConnect.iml" />
</modules> </modules>
</component> </component>

View File

@@ -1,7 +1,6 @@
package gov.nasa.xpc.ex; package gov.nasa.xpc.ex;
import gov.nasa.xpc.XPlaneConnect; import gov.nasa.xpc.XPlaneConnect;
import java.io.IOException; import java.io.IOException;
import java.net.SocketException; import java.net.SocketException;
import java.util.Arrays; import java.util.Arrays;
@@ -25,11 +24,11 @@ public class Main
xpc.getDREF("sim/test/test_float"); xpc.getDREF("sim/test/test_float");
System.out.println("Setting player aircraft position"); 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); xpc.sendPOSI(posi);
System.out.println("Setting another aircraft position"); System.out.println("Setting another aircraft position");
posi[0] = 37.52465F; posi[0] = 37.52465;
posi[4] = 20; posi[4] = 20;
xpc.sendPOSI(posi, 1); xpc.sendPOSI(posi, 1);

View File

@@ -20,7 +20,7 @@ public class Main
int aircraft = 0; int aircraft = 0;
while(true) while(true)
{ {
float[] posi = xpc.getPOSI(aircraft); float[] posi = xpc.getPOSI(aircraft); // FIXME: change this to 64-bit double
float[] ctrl = xpc.getCTRL(aircraft); float[] ctrl = xpc.getCTRL(aircraft);
System.out.format("Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n", 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" }; 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("(c) 2013-2015 United States Government as represented by the Administrator");
System.out.println("of the National Aeronautics and Space Administration. All Rights Reserved."); System.out.println("of the National Aeronautics and Space Administration. All Rights Reserved.");
while(true) while(true)
@@ -99,7 +99,7 @@ public class Main
{ {
for (int i = 0; i < count; ++i) 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", 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])); posi[0], posi[1], posi[2], posi[3], posi[4], posi[5], posi[6]));
try try
@@ -125,11 +125,11 @@ public class Main
{ {
while(reader.hasNextLine()) while(reader.hasNextLine())
{ {
float[] posi = new float[7]; double[] posi = new double[7];
for (int i = 0; i < 7; ++i) for (int i = 0; i < 7; ++i)
{ {
String s = reader.next(); String s = reader.next();
posi[i] = Float.parseFloat(s); posi[i] = Double.parseDouble(s);
} }
reader.nextLine(); reader.nextLine();
xpc.sendPOSI(posi); xpc.sendPOSI(posi);

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4"> <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 /> <exclude-output />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="gov.nasa.xpc" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="gov.nasa.xpc" />
@@ -10,6 +10,15 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <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> </component>
</module> </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: //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. // National Aeronautics and Space Administration. All Rights Reserved.
// //
// DISCLAIMERS // DISCLAIMERS

View File

@@ -1,5 +1,5 @@
//NOTICES: //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. // National Aeronautics and Space Administration. All Rights Reserved.
// //
// DISCLAIMERS // DISCLAIMERS

View File

@@ -1,5 +1,5 @@
//NOTICES: //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. // National Aeronautics and Space Administration. All Rights Reserved.
// //
// DISCLAIMERS // DISCLAIMERS
@@ -25,6 +25,8 @@
package gov.nasa.xpc; package gov.nasa.xpc;
import gov.nasa.xpc.discovery.Beacon;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.AutoCloseable; import java.lang.AutoCloseable;
@@ -136,6 +138,19 @@ public class XPlaneConnect implements AutoCloseable
this(xpHost, xpPort, port, 100); 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. * 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 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 // 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}. * @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. * @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 // Send request
ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream();
@@ -570,7 +585,7 @@ public class XPlaneConnect implements AutoCloseable
} }
// Parse response // Parse response
float[] result = new float[7]; double[] result = new double[7];
ByteBuffer bb = ByteBuffer.wrap(data); ByteBuffer bb = ByteBuffer.wrap(data);
bb.order(ByteOrder.LITTLE_ENDIAN); bb.order(ByteOrder.LITTLE_ENDIAN);
for(int i = 0; i < 7; ++i) for(int i = 0; i < 7; ++i)
@@ -600,13 +615,13 @@ public class XPlaneConnect implements AutoCloseable
* </p> * </p>
* @throws IOException If the command can not be sent. * @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); 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> * @param values <p>An array containing position elements as follows:</p>
* <ol> * <ol>
@@ -626,7 +641,7 @@ public class XPlaneConnect implements AutoCloseable
* @param ac The ac to set. 0 for the player ac. * @param ac The ac to set. 0 for the player ac.
* @throws IOException If the command can not be sent. * @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 //Preconditions
if(values == null) if(values == null)
@@ -644,15 +659,22 @@ public class XPlaneConnect implements AutoCloseable
//Pad command values and convert to bytes //Pad command values and convert to bytes
int i; int i;
ByteBuffer bb = ByteBuffer.allocate(28); ByteBuffer bb = ByteBuffer.allocate(40);
bb.order(ByteOrder.LITTLE_ENDIAN); bb.order(ByteOrder.LITTLE_ENDIAN);
for(i = 0; i < values.length; ++i) 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) for(; i < 7; ++i)
{ {
bb.putFloat(i * 4, -998); bb.putFloat(-998);
} }
//Build and send message //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. %pauseSim Pauses or unpauses X-Plane.
% %
%Inputs %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. % socket (optional): The client to use when sending the command.
% %
%Use %Use

View File

@@ -40,7 +40,7 @@ if ~exist('socket', 'var')
end end
%% Validate input %% Validate input
posi = single(posi); posi = double(posi);
if ~exist('ac', 'var') if ~exist('ac', 'var')
ac = 0; ac = 0;
end end

View File

@@ -56,7 +56,7 @@ def printMenu(title, opts):
return int(raw_input("Please select and option: ")) return int(raw_input("Please select and option: "))
def ex(): 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 "(c) 2013-2015 United States Government as represented by the Administrator"
print "of the National Aeronautics and Space Administration. All Rights Reserved." print "of the National Aeronautics and Space Administration. All Rights Reserved."

View File

@@ -98,10 +98,12 @@ class XPlaneConnect(object):
'''Pauses or un-pauses the physics simulation engine in X-Plane. '''Pauses or un-pauses the physics simulation engine in X-Plane.
Args: 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) 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.") raise ValueError("Invalid argument for pause command.")
buffer = struct.pack("<4sxB", "SIMU", pause) buffer = struct.pack("<4sxB", "SIMU", pause)
@@ -189,6 +191,7 @@ class XPlaneConnect(object):
if ac < 0 or ac > 20: if ac < 0 or ac > 20:
raise ValueError("Aircraft number must be between 0 and 20.") raise ValueError("Aircraft number must be between 0 and 20.")
# FIXME update this to the 64-bit double lat/lon/h
# Pack message # Pack message
buffer = struct.pack("<4sxB", "POSI", ac) buffer = struct.pack("<4sxB", "POSI", ac)
for i in range(7): for i in range(7):

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 ### 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. of the National Aeronautics and Space Administration. All Rights Reserved.
No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY 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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef CTRLTESTS_H #ifndef CTRLTESTS_H
#define CTRLTESTS_H #define CTRLTESTS_H

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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef DATATESTS_H #ifndef DATATESTS_H
#define DATATESTS_H #define DATATESTS_H

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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef DREFTESTS_H #ifndef DREFTESTS_H
#define DREFTESTS_H #define DREFTESTS_H

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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef POSITESTS_H #ifndef POSITESTS_H
#define POSITESTS_H #define POSITESTS_H
@@ -6,7 +6,7 @@
#include "Test.h" #include "Test.h"
#include "xplaneConnect.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]; float* data[7];
int sizes[7]; int sizes[7];
@@ -32,15 +32,15 @@ int doPOSITest(char* drefs[7], float values[], int size, int ac, float expected[
} }
// Test values // Test values
float actual[7]; double actual[7];
for (int i = 0; i < 7; ++i) for (int i = 0; i < 7; ++i)
{ {
actual[i] = data[i][0]; 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 // Execute Test
float actual[7]; float actual[7];
@@ -70,8 +70,8 @@ int doGETPTest(float values[7], int ac, float expected[7])
int basicPOSITest(char** drefs, int ac) int basicPOSITest(char** drefs, int ac)
{ {
// Set psoition and initial orientation // Set psoition and initial orientation
float POSI[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 }; double POSI[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 };
float expected[7] = { 37.524F, -122.06899F, 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); int result = doPOSITest(drefs, POSI, 7, ac, expected);
if (result < 0) if (result < 0)
{ {
@@ -79,9 +79,9 @@ int basicPOSITest(char** drefs, int ac)
} }
// Set orientation // Set orientation
POSI[0] = -998.0F; POSI[0] = -998.0;
POSI[1] = -998.0F; POSI[1] = -998.0;
POSI[2] = -998.0F; POSI[2] = -998.0;
POSI[3] = 5.0F; POSI[3] = 5.0F;
POSI[4] = -5.0F; POSI[4] = -5.0F;
POSI[5] = 10.0F; POSI[5] = 10.0F;
@@ -101,10 +101,10 @@ int basicPOSITest(char** drefs, int ac)
expected[0] = loc[0][0]; expected[0] = loc[0][0];
expected[1] = loc[1][0]; expected[1] = loc[1][0];
expected[2] = loc[2][0]; expected[2] = loc[2][0];
expected[3] = 5.0F; expected[3] = 5.0;
expected[4] = -5.0F; expected[4] = -5.0;
expected[5] = 10.0F; expected[5] = 10.0;
expected[6] = 0.0F; expected[6] = 0.0;
result = doPOSITest(drefs, POSI, 7, ac, expected); result = doPOSITest(drefs, POSI, 7, ac, expected);
if (result < 0) if (result < 0)
{ {
@@ -145,13 +145,13 @@ int testPOSI_NonPlayer()
int testGetPOSI_Player() 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); return doGETPTest(POSI, 0, POSI);
} }
int testGetPOSI_NonPlayer() 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); return doGETPTest(POSI, 3, POSI);
} }

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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef SIMUTESTS_H #ifndef SIMUTESTS_H
#define SIMIUTESTS_H #define SIMIUTESTS_H
@@ -16,7 +16,7 @@ int doSIMUTest(int value, float expected)
int result = pauseSim(sock, value); int result = pauseSim(sock, value);
if (result >= 0) if (result >= 0)
{ {
result = getDREF(sock, dref, &actual, &size); result = getDREF(sock, dref, actual, &size);
} }
closeUDP(sock); closeUDP(sock);
if (result < 0) if (result < 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. //National Aeronautics and Space Administration. All Rights Reserved.
#include "Test.h" #include "Test.h"
@@ -57,3 +57,27 @@ int compareArrays(float* expected[], int esizes[], float* actual[], int asizes[]
} }
return 0; 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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef TESTRUNNER_H #ifndef TESTRUNNER_H
#define TESTRUNNER_H #define TESTRUNNER_H
@@ -33,5 +33,7 @@ void runTest(int(*test)(), char* name);
int compareFloat(float expected, float actual); int compareFloat(float expected, float actual);
int compareArray(float expected[], float actual[], int size); int compareArray(float expected[], float actual[], int size);
int compareArrays(float* expected[], int esizes[], float* actual[], int asizes[], int count); 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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef TEXTTESTS_H #ifndef TEXTTESTS_H
#define TEXTTESTS_H #define TEXTTESTS_H

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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef UDPTESTS_H #ifndef UDPTESTS_H
#define UDPTESTS_H #define UDPTESTS_H

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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef VIEWTESTS_H #ifndef VIEWTESTS_H
#define VIEWTESTS_H #define VIEWTESTS_H

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. //National Aeronautics and Space Administration. All Rights Reserved.
#ifndef WYPTTESTS_H #ifndef WYPTTESTS_H
#define WYPTTESTS_H #define WYPTTESTS_H

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. //National Aeronautics and Space Administration. All Rights Reserved.
#include "Test.h" #include "Test.h"
#include "UDPTests.h" #include "UDPTests.h"
@@ -85,4 +85,3 @@ int main(int argc, const char * argv[]) {
return 0; return 0;
} }

View File

@@ -542,15 +542,15 @@ public class XPlaneConnectTest
public void testSendPOSI() throws IOException public void testSendPOSI() throws IOException
{ {
String[] drefs = { String[] drefs = {
"sim/flightmodel/position/latitude", "sim/flightmodel/position/latitude",
"sim/flightmodel/position/longitude", "sim/flightmodel/position/longitude",
"sim/flightmodel/position/y_agl", "sim/flightmodel/position/y_agl",
"sim/flightmodel/position/phi", "sim/flightmodel/position/phi",
"sim/flightmodel/position/theta", "sim/flightmodel/position/theta",
"sim/flightmodel/position/psi", "sim/flightmodel/position/psi",
"sim/cockpit/switches/gear_handle_status" "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()) try(XPlaneConnect xpc = new XPlaneConnect())
{ {
xpc.pauseSim(true); xpc.pauseSim(true);
@@ -585,7 +585,7 @@ public class XPlaneConnectTest
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testSendPOSI_LongCtrl() throws IOException 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()) try(XPlaneConnect xpc = new XPlaneConnect())
{ {
xpc.sendPOSI(posi); xpc.sendPOSI(posi);
@@ -595,7 +595,7 @@ public class XPlaneConnectTest
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testSendPOSI_NegativeAircraftNum() throws IOException 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()) try(XPlaneConnect xpc = new XPlaneConnect())
{ {
xpc.sendPOSI(posi, -1); xpc.sendPOSI(posi, -1);
@@ -605,7 +605,7 @@ public class XPlaneConnectTest
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testSendPOSI_LargeAircraftNum() throws IOException 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()) try(XPlaneConnect xpc = new XPlaneConnect())
{ {
xpc.sendPOSI(posi, 300); xpc.sendPOSI(posi, 300);
@@ -702,12 +702,12 @@ public class XPlaneConnectTest
@Test @Test
public void testGetPOSI() throws IOException 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()) try(XPlaneConnect xpc = new XPlaneConnect())
{ {
xpc.pauseSim(true); xpc.pauseSim(true);
xpc.sendPOSI(values); xpc.sendPOSI(values);
float[] actual = xpc.getPOSI(0); double[] actual = xpc.getPOSI(0);
assertArrayEquals(values, actual, 1e-4F); 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_C_COMPILER gcc)
SET(CMAKE_CXX_COMPILER g++) 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 add_library(xpc64 SHARED XPCPlugin.cpp
DataManager.cpp DataManager.cpp
@@ -17,9 +21,12 @@ add_library(xpc64 SHARED XPCPlugin.cpp
Log.cpp Log.cpp
Message.cpp Message.cpp
MessageHandlers.cpp MessageHandlers.cpp
Timer.cpp
UDPSocket.cpp) UDPSocket.cpp)
set_target_properties(xpc64 PROPERTIES PREFIX "" SUFFIX ".xpl") 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 add_library(xpc32 SHARED XPCPlugin.cpp
DataManager.cpp DataManager.cpp
@@ -27,9 +34,12 @@ add_library(xpc32 SHARED XPCPlugin.cpp
Log.cpp Log.cpp
Message.cpp Message.cpp
MessageHandlers.cpp MessageHandlers.cpp
Timer.cpp
UDPSocket.cpp) UDPSocket.cpp)
set_target_properties(xpc32 PROPERTIES PREFIX "" SUFFIX ".xpl") 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. # Switch install targets when uncommenting the 32 bit line above.
install(TARGETS xpc64 DESTINATION XPlaneConnect/64 RENAME lin.xpl) 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. // National Aeronautics and Space Administration. All Rights Reserved.
// //
// X-Plane API // 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_Latitude, XPLMFindDataRef("sim/flightmodel/position/latitude")));
drefs.insert(make_pair(DREF_Longitude, XPLMFindDataRef("sim/flightmodel/position/longitude"))); 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_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_LocalX, XPLMFindDataRef("sim/flightmodel/position/local_x")));
drefs.insert(make_pair(DREF_LocalY, XPLMFindDataRef("sim/flightmodel/position/local_y"))); 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()); Log::FormatLine(LOG_ERROR, "DMAN", "ERROR: invalid DREF %s", dref.c_str());
return; return;
} }
if (isnan(values[0])) if (std::isnan(values[0]))
{ {
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Value must be a number (NaN received)"); Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Value must be a number (NaN received)");
return; return;
@@ -629,11 +629,12 @@ namespace XPC
if ((gear < -8.5 && gear > -9.5) || IsDefault(gear)) if ((gear < -8.5 && gear > -9.5) || IsDefault(gear))
{ {
Log::WriteLine(LOG_INFO, "DMAN", "Not actually setting gear because of default value");
return; 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; 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", Log::FormatLine(LOG_INFO, "DMAN", "Setting position (%f, %f, %f) for aircraft %i",
pos[0], pos[1], pos[2], aircraft); 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)"); Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Position must be a number (NaN received)");
return; return;
@@ -669,28 +670,28 @@ namespace XPC
if (IsDefault(pos[0])) if (IsDefault(pos[0]))
{ {
pos[0] = (float)GetDouble(DREF_Latitude, aircraft); pos[0] = GetDouble(DREF_Latitude, aircraft);
} }
if (IsDefault(pos[1])) if (IsDefault(pos[1]))
{ {
pos[1] = (float)GetDouble(DREF_Longitude, aircraft); pos[1] = GetDouble(DREF_Longitude, aircraft);
} }
if (IsDefault(pos[2])) 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 // See: http://www.xsquawkbox.net/xpsdk/mediawiki/MovingThePlane
// Need to get the aircraft's current orientation before moving and // Need to get the aircraft's current orientation before moving and
// reset the orientation after moving to update the quaternion // reset the orientation after moving to update the quaternion
float orient[3]; float orient[3];
orient[0] = GetFloat(DREF_Pitch, aircraft); orient[0] = GetFloat(DREF_Pitch, aircraft);
orient[1] = GetFloat(DREF_Roll, aircraft); orient[1] = GetFloat(DREF_Roll, aircraft);
orient[2] = GetFloat(DREF_HeadingTrue, aircraft); orient[2] = GetFloat(DREF_HeadingTrue, aircraft);
// Now set the aircraft's position. Need to set world position for // 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", // "long" moves, but since there isn't an easy way to calculate "long",
// we just set it every time. // we just set it every time.
double local[3]; double local[3];
XPLMWorldToLocal(pos[0], pos[1], pos[2], &local[0], &local[1], &local[2]); 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 // 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_LocalY, local[1], aircraft);
Set(DREF_LocalZ, local[2], aircraft); Set(DREF_LocalZ, local[2], aircraft);
// If the sim is unpaused, this will override the above settings. // If the sim is unpaused, this will override the above settings.
Set(DREF_Latitude, (double)pos[0], aircraft); Set(DREF_Latitude, pos[0], aircraft);
Set(DREF_Longitude, (double)pos[1], aircraft); Set(DREF_Longitude, pos[1], aircraft);
Set(DREF_Elevation, (double)pos[2], aircraft); Set(DREF_Elevation, pos[2], aircraft);
// Now reset orientation to update q // Now reset orientation to update q
SetOrientation(orient, aircraft); SetOrientation(orient, aircraft);
} }
void DataManager::SetOrientation(float orient[3], char aircraft) void DataManager::SetOrientation(float orient[3], char aircraft)
{ {
Log::FormatLine(LOG_INFO, "DMAN", "Setting orientation (%f, %f, %f) for aircraft %i", Log::FormatLine(LOG_INFO, "DMAN", "Setting orientation (%f, %f, %f) for aircraft %i",
orient[0], orient[1], orient[2], aircraft); 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)"); Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Orientation must be a number (NaN received)");
return; return;
@@ -762,7 +763,7 @@ namespace XPC
{ {
Log::FormatLine(LOG_INFO, "DMAN", "Setting flaps (value:%f)", value); 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)"); Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Flap value must be a number (NaN received)");
return; return;
@@ -784,7 +785,7 @@ namespace XPC
return -998.0F; return -998.0F;
} }
bool DataManager::IsDefault(float value) bool DataManager::IsDefault(double value)
{ {
return value < -997.9 && value > -999.1; 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. // National Aeronautics and Space Administration. All Rights Reserved.
#ifndef XPCPLUGIN_DATAMANAGER_H_ #ifndef XPCPLUGIN_DATAMANAGER_H_
#define XPCPLUGIN_DATAMANAGER_H_ #define XPCPLUGIN_DATAMANAGER_H_
@@ -396,7 +396,7 @@ namespace XPC
/// \param pos An array containing latitude, longitude and altitude in /// \param pos An array containing latitude, longitude and altitude in
/// fractional degrees and meters above sea level. /// fractional degrees and meters above sea level.
/// \param aircraft The aircraft to set the position of. /// \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. /// Sets the orientation of the specified aircraft.
/// ///
@@ -417,7 +417,7 @@ namespace XPC
/// ///
/// \param value The value to check. /// \param value The value to check.
/// \returns true if value is a default value; otherwise false. /// \returns true if value is a default value; otherwise false.
static bool IsDefault(float value); static bool IsDefault(double value);
}; };
} }
#endif #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. // National Aeronautics and Space Administration. All Rights Reserved.
// //
// X-Plane API // X-Plane API
@@ -173,7 +173,7 @@ namespace XPC
glBegin(GL_LINE_STRIP); glBegin(GL_LINE_STRIP);
for (size_t i = 0; i < numWaypoints; ++i) 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); glVertex3f((float)l->x, (float)l->y, (float)l->z);
} }
glEnd(); glEnd();
@@ -226,7 +226,7 @@ namespace XPC
// Enable drawing if necessary // Enable drawing if necessary
if (!msgEnabled) if (!msgEnabled)
{ {
XPLMRegisterDrawCallback(MessageDrawCallback, xplm_Phase_Window, 0, NULL); XPLMRegisterDrawCallback(MessageDrawCallback, xplm_Phase_Window, 0, NULL);
msgEnabled = true; 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. // National Aeronautics and Space Administration. All Rights Reserved.
#ifndef XPCPLUGIN_DRAWING_H_ #ifndef XPCPLUGIN_DRAWING_H_
#define 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. // National Aeronautics and Space Administration. All Rights Reserved.
#include "Log.h" #include "Log.h"
@@ -111,7 +111,7 @@ namespace XPC
std::fprintf(fd, "X-Plane Connect [Version %s]\n", version.c_str()); std::fprintf(fd, "X-Plane Connect [Version %s]\n", version.c_str());
std::fprintf(fd, "Compiled %s %s\n", __DATE__, __TIME__); 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, "Administrator of the National Aeronautics and Space Administration.\n");
std::fprintf(fd, "All Rights Reserved.\n\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. // National Aeronautics and Space Administration. All Rights Reserved.
#ifndef XPCPLUGIN_LOG_H_ #ifndef XPCPLUGIN_LOG_H_
#define XPCPLUGIN_LOG_H_ #define XPCPLUGIN_LOG_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. // National Aeronautics and Space Administration. All Rights Reserved.
#include "Message.h" #include "Message.h"
#include "Log.h" #include "Log.h"
@@ -11,7 +11,7 @@
namespace XPC namespace XPC
{ {
Message::Message() {} Message::Message() {}
Message Message::ReadFrom(const UDPSocket& sock) Message Message::ReadFrom(const UDPSocket& sock)
{ {
@@ -110,17 +110,17 @@ namespace XPC
else if (head == "DREF") else if (head == "DREF")
{ {
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
string dref((char*)buffer + 6, buffer[5]); string dref((char*)buffer + 6, buffer[5]);
Log::FormatLine(LOG_DEBUG, "DBUG", " DREF (size %i) = %s", dref.length(), dref.c_str()); Log::FormatLine(LOG_DEBUG, "DBUG", " DREF (size %i) = %s", dref.length(), dref.c_str());
ss.str(""); ss.str("");
int values = buffer[6 + buffer[5]]; int values = buffer[6 + buffer[5]];
ss << " Values(size " << values << ") ="; ss << " Values(size " << values << ") =";
for (int i = 0; i < values; ++i) for (int i = 0; i < values; ++i)
{ {
ss << " " << *((float*)(buffer + values + 1 + sizeof(float) * i)); ss << " " << *((float*)(buffer + values + 1 + sizeof(float) * i));
} }
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
} }
else if (head == "GETC" || head == "GETP") else if (head == "GETC" || head == "GETP")
{ {
ss << " Aircraft:" << (int)buffer[5]; ss << " Aircraft:" << (int)buffer[5];
@@ -129,15 +129,15 @@ namespace XPC
else if (head == "GETD") else if (head == "GETD")
{ {
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
int cur = 6; int cur = 6;
for (int i = 0; i < buffer[5]; ++i) for (int i = 0; i < buffer[5]; ++i)
{ {
string dref((char*)buffer + cur + 1, buffer[cur]); string dref((char*)buffer + cur + 1, buffer[cur]);
Log::FormatLine(LOG_DEBUG, "DBUG", " #%i/%i (size:%i) %s", Log::FormatLine(LOG_DEBUG, "DBUG", " #%i/%i (size:%i) %s",
i + 1, buffer[5], dref.length(), dref.c_str()); i + 1, buffer[5], dref.length(), dref.c_str());
cur += 1 + buffer[cur]; cur += 1 + buffer[cur];
} }
} }
else if (head == "POSI") else if (head == "POSI")
{ {
char aircraft = buffer[5]; char aircraft = buffer[5];
@@ -146,14 +146,14 @@ namespace XPC
float orient[3]; float orient[3];
memcpy(pos, buffer + 6, 12); memcpy(pos, buffer + 6, 12);
memcpy(orient, buffer + 18, 12); memcpy(orient, buffer + 18, 12);
ss << " AC:" << (int)aircraft; ss << " AC:" << (int)aircraft;
ss << " Pos:(" << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ") Orient:("; 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; ss << gear;
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
} }
else if (head == "SIMU") else if (head == "SIMU")
{ {
ss << ' ' << (int)buffer[5]; ss << ' ' << (int)buffer[5];
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
} }
@@ -163,9 +163,9 @@ namespace XPC
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
} }
else else
{ {
ss << " UNKNOWN HEADER "; ss << " UNKNOWN HEADER ";
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); 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. // National Aeronautics and Space Administration. All Rights Reserved.
#ifndef XPCPLUGIN_MESSAGE_H_ #ifndef XPCPLUGIN_MESSAGE_H_
#define 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. // National Aeronautics and Space Administration. All Rights Reserved.
// //
// X-Plane API // X-Plane API
@@ -20,9 +20,16 @@
#include "Log.h" #include "Log.h"
#include "XPLMUtilities.h" #include "XPLMUtilities.h"
#include "XPLMGraphics.h"
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <cstdint>
#define MULTICAST_GROUP "239.255.1.1"
#define MULITCAST_PORT 49710
namespace XPC namespace XPC
{ {
@@ -33,6 +40,8 @@ namespace XPC
MessageHandlers::ConnectionInfo MessageHandlers::connection; MessageHandlers::ConnectionInfo MessageHandlers::connection;
UDPSocket* MessageHandlers::sock; UDPSocket* MessageHandlers::sock;
static sockaddr multicast_address = UDPSocket::GetAddr(MULTICAST_GROUP, MULITCAST_PORT);
void MessageHandlers::SetSocket(UDPSocket* socket) void MessageHandlers::SetSocket(UDPSocket* socket)
{ {
Log::WriteLine(LOG_TRACE, "MSGH", "Setting socket"); Log::WriteLine(LOG_TRACE, "MSGH", "Setting socket");
@@ -128,6 +137,28 @@ namespace XPC
} }
} }
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) void MessageHandlers::HandleConn(const Message& msg)
{ {
const unsigned char* buffer = msg.GetBuffer(); const unsigned char* buffer = msg.GetBuffer();
@@ -342,10 +373,11 @@ namespace XPC
} }
case 20: // Position case 20: // Position
{ {
float pos[3]; // TODO: loss of precision here
pos[0] = values[i][2]; double pos[3];
pos[1] = values[i][3]; pos[0] = (double)values[i][2];
pos[2] = values[i][4]; pos[1] = (double)values[i][3];
pos[2] = (double)values[i][4];
DataManager::SetPosition(pos); DataManager::SetPosition(pos);
break; break;
} }
@@ -524,6 +556,7 @@ namespace XPC
unsigned char response[34] = "POSI"; unsigned char response[34] = "POSI";
response[5] = (char)DataManager::GetInt(DREF_GearHandle, aircraft); 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 + 6)) = (float)DataManager::GetDouble(DREF_Latitude, aircraft);
*((float*)(response + 10)) = (float)DataManager::GetDouble(DREF_Longitude, aircraft); *((float*)(response + 10)) = (float)DataManager::GetDouble(DREF_Longitude, aircraft);
*((float*)(response + 14)) = (float)DataManager::GetDouble(DREF_Elevation, aircraft); *((float*)(response + 14)) = (float)DataManager::GetDouble(DREF_Elevation, aircraft);
@@ -545,18 +578,37 @@ namespace XPC
const unsigned char* buffer = msg.GetBuffer(); const unsigned char* buffer = msg.GetBuffer();
const std::size_t size = msg.GetSize(); 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; return;
} }
char aircraftNumber = buffer[5]; /* convert float to double */
float gear = *((float*)(buffer + 30)); DataManager::SetPosition(posd, aircraftNumber);
float pos[3]; DataManager::SetOrientation(orient, aircraftNumber);
float orient[3]; if (gear >= 0)
memcpy(pos, buffer + 6, 12); {
memcpy(orient, buffer + 18, 12); DataManager::SetGear(gear, true, aircraftNumber);
}
if (aircraftNumber > 0) if (aircraftNumber > 0)
{ {
@@ -569,13 +621,6 @@ namespace XPC
DataManager::Set(DREF_PauseAI, ai, 0, 20); 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) void MessageHandlers::HandleSimu(const Message& msg)
@@ -583,8 +628,8 @@ namespace XPC
// Update log // Update log
Log::FormatLine(LOG_TRACE, "SIMU", "Message Received (Conn %i)", connection.id); Log::FormatLine(LOG_TRACE, "SIMU", "Message Received (Conn %i)", connection.id);
char v = msg.GetBuffer()[5]; unsigned char v = msg.GetBuffer()[5];
if (v < 0 || v > 2) if (v < 0 || (v > 2 && v < 100) || (v > 119 && v < 200) || v > 219)
{ {
Log::FormatLine(LOG_ERROR, "SIMU", "ERROR: Invalid argument: %i", v); Log::FormatLine(LOG_ERROR, "SIMU", "ERROR: Invalid argument: %i", v);
return; return;
@@ -599,6 +644,16 @@ namespace XPC
value[i] = value[i] ? 0 : 1; 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 else
{ {
for (int i = 0; i < 20; ++i) for (int i = 0; i < 20; ++i)
@@ -610,18 +665,27 @@ namespace XPC
// Set DREF // Set DREF
DataManager::Set(DREF_Pause, value, 20); DataManager::Set(DREF_Pause, value, 20);
switch (v) if (v == 0)
{ {
case 0: Log::WriteLine(LOG_INFO, "SIMU", "Simulation resumed for all a/c");
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;
} }
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) void MessageHandlers::HandleText(const Message& msg)
@@ -659,15 +723,105 @@ namespace XPC
// Update Log // Update Log
Log::FormatLine(LOG_TRACE, "VIEW", "Message Received(Conn %i)", connection.id); Log::FormatLine(LOG_TRACE, "VIEW", "Message Received(Conn %i)", connection.id);
int enable_camera_location = 0;
const std::size_t size = msg.GetSize(); 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; return;
} }
const unsigned char* buffer = msg.GetBuffer(); const unsigned char* buffer = msg.GetBuffer();
int type = *((int*)(buffer + 5)); int type = *((int*)(buffer + 5));
XPLMCommandKeyStroke(type); 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) 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. // National Aeronautics and Space Administration. All Rights Reserved.
#ifndef XPCPLUGIN_MESSAGEHANDLERS_H_ #ifndef XPCPLUGIN_MESSAGEHANDLERS_H_
#define XPCPLUGIN_MESSAGEHANDLERS_H_ #define XPCPLUGIN_MESSAGEHANDLERS_H_
@@ -7,6 +7,9 @@
#include <string> #include <string>
#include <map> #include <map>
#include "XPLMCamera.h"
namespace XPC namespace XPC
{ {
/// A function that handles a message. /// A function that handles a message.
@@ -26,16 +29,18 @@ namespace XPC
/// socket. /// socket.
/// ///
/// \details After a message is read, HandleMessage analyzes the sender's network address /// \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 /// 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 /// connection details for an existing client, or creates a new connection record
/// for new clients. Finally, the message handler checks the message type and /// for new clients. Finally, the message handler checks the message type and
/// dispatches the message to the appropriate handler. /// dispatches the message to the appropriate handler.
/// \param msg The message to be processed. /// \param msg The message to be processed.
static void HandleMessage(Message& msg); static void HandleMessage(Message& msg);
/// Sets the socket that message handlers use to send responses. /// Sets the socket that message handlers use to send responses.
static void SetSocket(UDPSocket* socket); static void SetSocket(UDPSocket* socket);
static void SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion);
private: private:
// One handler per message type. Message types are descripbed on the // One handler per message type. Message types are descripbed on the
// wiki at https://github.com/nasa/XPlaneConnect/wiki/Network-Information // wiki at https://github.com/nasa/XPlaneConnect/wiki/Network-Information
@@ -55,6 +60,14 @@ namespace XPC
static void HandleXPlaneData(const Message& msg); static void HandleXPlaneData(const Message& msg);
static void HandleUnknown(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 typedef struct
{ {
unsigned char id; unsigned char id;

View File

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

View File

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

View File

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

View File

@@ -21,7 +21,7 @@ void XPCProcess::StartProcessTime(float inSeconds)
FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast<void *>(this)); FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast<void *>(this));
} }
void XPCProcess::StartProcessCycles(long inCycles) void XPCProcess::StartProcessCycles(int inCycles)
{ {
mCallbackTime = -inCycles; mCallbackTime = -inCycles;
if (!mInCallback) if (!mInCallback)

View File

@@ -10,7 +10,7 @@ public:
virtual ~XPCProcess(); virtual ~XPCProcess();
void StartProcessTime(float inSeconds); void StartProcessTime(float inSeconds);
void StartProcessCycles(long inCycles); void StartProcessCycles(int inCycles);
void StopProcess(void); void StopProcess(void);
virtual void DoProcessing( virtual void DoProcessing(

View File

@@ -22,7 +22,7 @@ XPCWidget::XPCWidget(
inIsRoot ? NULL : inParent, inIsRoot ? NULL : inParent,
inClass); inClass);
XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast<long>(this)); XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast<intptr_t>(this));
XPAddWidgetCallback(mWidget, WidgetCallback); XPAddWidgetCallback(mWidget, WidgetCallback);
} }
@@ -33,7 +33,7 @@ XPCWidget::XPCWidget(
mOwnsChildren(false), mOwnsChildren(false),
mOwnsWidget(inOwnsWidget) mOwnsWidget(inOwnsWidget)
{ {
XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast<long>(this)); XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast<intptr_t>(this));
XPAddWidgetCallback(mWidget, WidgetCallback); XPAddWidgetCallback(mWidget, WidgetCallback);
} }
@@ -95,8 +95,8 @@ void XPCWidget::RemoveAttachment(
int XPCWidget::HandleWidgetMessage( int XPCWidget::HandleWidgetMessage(
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2) intptr_t inParam2)
{ {
return 0; return 0;
} }
@@ -104,8 +104,8 @@ int XPCWidget::HandleWidgetMessage(
int XPCWidget::WidgetCallback( int XPCWidget::WidgetCallback(
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2) intptr_t inParam2)
{ {
XPCWidget * me = reinterpret_cast<XPCWidget *>(XPGetWidgetProperty(inWidget, xpProperty_Object, NULL)); XPCWidget * me = reinterpret_cast<XPCWidget *>(XPGetWidgetProperty(inWidget, xpProperty_Object, NULL));
if (me == NULL) if (me == NULL)

View File

@@ -14,8 +14,8 @@ public:
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2)=0; intptr_t inParam2)=0;
}; };
@@ -56,16 +56,16 @@ public:
virtual int HandleWidgetMessage( virtual int HandleWidgetMessage(
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2); intptr_t inParam2);
private: private:
static int WidgetCallback( static int WidgetCallback(
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2); intptr_t inParam2);
typedef std::pair<XPCWidgetAttachment *, bool> AttachmentInfo; typedef std::pair<XPCWidgetAttachment *, bool> AttachmentInfo;
typedef std::vector<AttachmentInfo> AttachmentVector; typedef std::vector<AttachmentInfo> AttachmentVector;

View File

@@ -22,8 +22,8 @@ int XPCKeyFilterAttachment::HandleWidgetMessage(
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2) intptr_t inParam2)
{ {
if (inMessage == xpMsg_KeyPress) if (inMessage == xpMsg_KeyPress)
{ {
@@ -42,7 +42,7 @@ int XPCKeyFilterAttachment::HandleWidgetMessage(
XPCKeyMessageAttachment::XPCKeyMessageAttachment( XPCKeyMessageAttachment::XPCKeyMessageAttachment(
char inKey, char inKey,
long inMessage, int inMessage,
void * inParam, void * inParam,
bool inConsume, bool inConsume,
bool inVkey, bool inVkey,
@@ -62,8 +62,8 @@ int XPCKeyMessageAttachment::HandleWidgetMessage(
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2) intptr_t inParam2)
{ {
if (inMessage == xpMsg_KeyPress) if (inMessage == xpMsg_KeyPress)
{ {
@@ -81,7 +81,7 @@ int XPCKeyMessageAttachment::HandleWidgetMessage(
XPCPushButtonMessageAttachment::XPCPushButtonMessageAttachment( XPCPushButtonMessageAttachment::XPCPushButtonMessageAttachment(
XPWidgetID inWidget, XPWidgetID inWidget,
long inMessage, int inMessage,
void * inParam, void * inParam,
XPCListener * inListener) : XPCListener * inListener) :
mMsg(inMessage), mParam(inParam), mWidget(inWidget) mMsg(inMessage), mParam(inParam), mWidget(inWidget)
@@ -98,8 +98,8 @@ int XPCPushButtonMessageAttachment::HandleWidgetMessage(
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2) intptr_t inParam2)
{ {
if ((inMessage == xpMsg_PushButtonPressed) && ((XPWidgetID) inParam1 == mWidget)) if ((inMessage == xpMsg_PushButtonPressed) && ((XPWidgetID) inParam1 == mWidget))
{ {
@@ -117,7 +117,7 @@ int XPCPushButtonMessageAttachment::HandleWidgetMessage(
XPCSliderMessageAttachment::XPCSliderMessageAttachment( XPCSliderMessageAttachment::XPCSliderMessageAttachment(
XPWidgetID inWidget, XPWidgetID inWidget,
long inMessage, int inMessage,
void * inParam, void * inParam,
XPCListener * inListener) : XPCListener * inListener) :
mMsg(inMessage), mParam(inParam), mWidget(inWidget) mMsg(inMessage), mParam(inParam), mWidget(inWidget)
@@ -134,8 +134,8 @@ int XPCSliderMessageAttachment::HandleWidgetMessage(
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2) intptr_t inParam2)
{ {
if ((inMessage == xpMsg_ScrollBarSliderPositionChanged) && ((XPWidgetID) inParam1 == mWidget)) if ((inMessage == xpMsg_ScrollBarSliderPositionChanged) && ((XPWidgetID) inParam1 == mWidget))
{ {
@@ -149,7 +149,7 @@ int XPCSliderMessageAttachment::HandleWidgetMessage(
XPCCloseButtonMessageAttachment::XPCCloseButtonMessageAttachment( XPCCloseButtonMessageAttachment::XPCCloseButtonMessageAttachment(
XPWidgetID inWidget, XPWidgetID inWidget,
long inMessage, int inMessage,
void * inParam, void * inParam,
XPCListener * inListener) : XPCListener * inListener) :
mMsg(inMessage), mParam(inParam), mWidget(inWidget) mMsg(inMessage), mParam(inParam), mWidget(inWidget)
@@ -166,8 +166,8 @@ int XPCCloseButtonMessageAttachment::HandleWidgetMessage(
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2) intptr_t inParam2)
{ {
if ((inMessage == xpMessage_CloseButtonPushed) && ((XPWidgetID) inParam1 == mWidget)) if ((inMessage == xpMessage_CloseButtonPushed) && ((XPWidgetID) inParam1 == mWidget))
{ {
@@ -190,8 +190,8 @@ int XPCTabGroupAttachment::HandleWidgetMessage(
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2) intptr_t inParam2)
{ {
if ((inMessage == xpMsg_KeyPress) && (KEY_CHAR(inParam1) == XPLM_KEY_TAB) && if ((inMessage == xpMsg_KeyPress) && (KEY_CHAR(inParam1) == XPLM_KEY_TAB) &&
((KEY_FLAGS(inParam1) & xplm_UpFlag) == 0)) ((KEY_FLAGS(inParam1) & xplm_UpFlag) == 0))
@@ -199,7 +199,7 @@ int XPCTabGroupAttachment::HandleWidgetMessage(
bool backwards = (KEY_FLAGS(inParam1) & xplm_ShiftFlag) != 0; bool backwards = (KEY_FLAGS(inParam1) & xplm_ShiftFlag) != 0;
std::vector<XPWidgetID> widgets; std::vector<XPWidgetID> widgets;
XPCGetOrderedSubWidgets(inWidget, widgets); XPCGetOrderedSubWidgets(inWidget, widgets);
long n, index = 0; int n, index = 0;
XPWidgetID focusWidget = XPGetWidgetWithFocus(); XPWidgetID focusWidget = XPGetWidgetWithFocus();
std::vector<XPWidgetID>::iterator iter = std::find(widgets.begin(), widgets.end(), focusWidget); std::vector<XPWidgetID>::iterator iter = std::find(widgets.begin(), widgets.end(), focusWidget);
if (iter != widgets.end()) if (iter != widgets.end())
@@ -254,8 +254,8 @@ static void XPCGetOrderedSubWidgets(
std::vector<XPWidgetID>& outChildren) std::vector<XPWidgetID>& outChildren)
{ {
outChildren.clear(); outChildren.clear();
long count = XPCountChildWidgets(inWidget); int count = XPCountChildWidgets(inWidget);
for (long n = 0; n < count; ++n) for (int n = 0; n < count; ++n)
{ {
XPWidgetID child = XPGetNthChildWidget(inWidget, n); XPWidgetID child = XPGetNthChildWidget(inWidget, n);
outChildren.push_back(child); outChildren.push_back(child);

View File

@@ -18,8 +18,8 @@ public:
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2); intptr_t inParam2);
private: private:
@@ -34,7 +34,7 @@ public:
XPCKeyMessageAttachment( XPCKeyMessageAttachment(
char inKey, char inKey,
long inMessage, int inMessage,
void * inParam, void * inParam,
bool inConsume, bool inConsume,
bool inVkey, bool inVkey,
@@ -45,14 +45,14 @@ public:
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2); intptr_t inParam2);
private: private:
char mKey; char mKey;
bool mVkey; bool mVkey;
long mMsg; int mMsg;
void * mParam; void * mParam;
bool mConsume; bool mConsume;
@@ -63,7 +63,7 @@ public:
XPCPushButtonMessageAttachment( XPCPushButtonMessageAttachment(
XPWidgetID inWidget, XPWidgetID inWidget,
long inMessage, int inMessage,
void * inParam, void * inParam,
XPCListener * inListener); XPCListener * inListener);
virtual ~XPCPushButtonMessageAttachment(); virtual ~XPCPushButtonMessageAttachment();
@@ -72,12 +72,12 @@ public:
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2); intptr_t inParam2);
private: private:
XPWidgetID mWidget; XPWidgetID mWidget;
long mMsg; int mMsg;
void * mParam; void * mParam;
}; };
@@ -86,7 +86,7 @@ public:
XPCSliderMessageAttachment( XPCSliderMessageAttachment(
XPWidgetID inWidget, XPWidgetID inWidget,
long inMessage, int inMessage,
void * inParam, void * inParam,
XPCListener * inListener); XPCListener * inListener);
virtual ~XPCSliderMessageAttachment(); virtual ~XPCSliderMessageAttachment();
@@ -95,12 +95,12 @@ public:
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2); intptr_t inParam2);
private: private:
XPWidgetID mWidget; XPWidgetID mWidget;
long mMsg; int mMsg;
void * mParam; void * mParam;
}; };
@@ -110,7 +110,7 @@ public:
XPCCloseButtonMessageAttachment( XPCCloseButtonMessageAttachment(
XPWidgetID inWidget, XPWidgetID inWidget,
long inMessage, int inMessage,
void * inParam, void * inParam,
XPCListener * inListener); XPCListener * inListener);
virtual ~XPCCloseButtonMessageAttachment(); virtual ~XPCCloseButtonMessageAttachment();
@@ -119,12 +119,12 @@ public:
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2); intptr_t inParam2);
private: private:
XPWidgetID mWidget; XPWidgetID mWidget;
long mMsg; int mMsg;
void * mParam; void * mParam;
}; };
@@ -138,8 +138,8 @@ public:
XPCWidget * inObject, XPCWidget * inObject,
XPWidgetMessage inMessage, XPWidgetMessage inMessage,
XPWidgetID inWidget, XPWidgetID inWidget,
long inParam1, intptr_t inParam1,
long inParam2); intptr_t inParam2);
}; };

View File

@@ -27,7 +27,7 @@
extern "C" { extern "C" {
#endif #endif
#ifdef _WIN32 #if IBM
#include <windows.h> #include <windows.h>
#else #else
#include <stdint.h> #include <stdint.h>
@@ -49,7 +49,7 @@ extern "C" {
#ifdef __cplusplus #ifdef __cplusplus
#ifdef APL #if APL
#if __GNUC__ >= 4 #if __GNUC__ >= 4
#define PLUGIN_API extern "C" __attribute__((visibility("default"))) #define PLUGIN_API extern "C" __attribute__((visibility("default")))
#elif __MACH__ #elif __MACH__
@@ -57,16 +57,16 @@ extern "C" {
#else #else
#define PLUGIN_API extern "C" __declspec(dllexport) #define PLUGIN_API extern "C" __declspec(dllexport)
#endif #endif
#endif #elif IBM
#ifdef _WIN32
#define PLUGIN_API extern "C" __declspec(dllexport) #define PLUGIN_API extern "C" __declspec(dllexport)
#endif #elif LIN
#ifdef LIN
#if __GNUC__ >= 4 #if __GNUC__ >= 4
#define PLUGIN_API extern "C" __attribute__((visibility("default"))) #define PLUGIN_API extern "C" __attribute__((visibility("default")))
#else #else
#define PLUGIN_API extern "C" #define PLUGIN_API extern "C"
#endif #endif
#else
#error "Platform not defined!"
#endif #endif
#else #else
#if APL #if APL
@@ -90,7 +90,7 @@ extern "C" {
#endif #endif
#endif #endif
#ifdef APL #if APL
#if XPLM #if XPLM
#if __GNUC__ >= 4 #if __GNUC__ >= 4
#define XPLM_API __attribute__((visibility("default"))) #define XPLM_API __attribute__((visibility("default")))
@@ -102,15 +102,13 @@ extern "C" {
#else #else
#define XPLM_API #define XPLM_API
#endif #endif
#endif #elif IBM
#ifdef _WIN32
#if XPLM #if XPLM
#define XPLM_API __declspec(dllexport) #define XPLM_API __declspec(dllexport)
#else #else
#define XPLM_API __declspec(dllimport) #define XPLM_API __declspec(dllimport)
#endif #endif
#endif #elif LIN
#ifdef LIN
#if XPLM #if XPLM
#if __GNUC__ >= 4 #if __GNUC__ >= 4
#define XPLM_API __attribute__((visibility("default"))) #define XPLM_API __attribute__((visibility("default")))
@@ -120,6 +118,8 @@ extern "C" {
#else #else
#define XPLM_API #define XPLM_API
#endif #endif
#else
#error "Platform not defined!"
#endif #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. 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 X-Plane SDK Release 2.1.2 RC2 1/15/13
Removed headers from frameworks, as they don't work; updated README. 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. // National Aeronautics and Space Administration. All Rights Reserved.
#include "Log.h" #include "Log.h"
#include "UDPSocket.h" #include "UDPSocket.h"
@@ -139,6 +139,18 @@ namespace XPC
} }
} }
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) std::string UDPSocket::GetHost(sockaddr* sa)
{ {
char ip[INET6_ADDRSTRLEN + 6] = { 0 }; char ip[INET6_ADDRSTRLEN + 6] = { 0 };

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. // National Aeronautics and Space Administration. All Rights Reserved.
#ifndef XPCPLUGIN_SOCKET_H_ #ifndef XPCPLUGIN_SOCKET_H_
#define XPCPLUGIN_SOCKET_H_ #define XPCPLUGIN_SOCKET_H_
@@ -62,6 +62,8 @@ namespace XPC
/// \param addr The socket address to parse. /// \param addr The socket address to parse.
/// \returns A string representation of the socket address. /// \returns A string representation of the socket address.
static std::string GetHost(sockaddr* addr); static std::string GetHost(sockaddr* addr);
static sockaddr GetAddr(std::string address, unsigned short port);
private: private:
#ifdef _WIN32 #ifdef _WIN32
SOCKET sock; 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. // National Aeronautics and Space Administration. All Rights Reserved.
// //
// DISCLAIMERS // DISCLAIMERS
@@ -60,12 +60,16 @@
#include "Log.h" #include "Log.h"
#include "MessageHandlers.h" #include "MessageHandlers.h"
#include "UDPSocket.h" #include "UDPSocket.h"
#include "Timer.h"
// XPLM Includes // XPLM Includes
#include "XPLMProcessing.h" #include "XPLMProcessing.h"
#include "XPLMUtilities.h"
// System Includes // System Includes
#include <cstdlib>
#include <cstring> #include <cstring>
#include <cmath>
#ifdef __APPLE__ #ifdef __APPLE__
#include <mach/mach_time.h> #include <mach/mach_time.h>
#endif #endif
@@ -73,7 +77,12 @@
#define RECVPORT 49009 // Port that the plugin receives commands on #define RECVPORT 49009 // Port that the plugin receives commands on
#define OPS_PER_CYCLE 20 // Max Number of operations per cycle #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::UDPSocket* sock = NULL;
XPC::Timer* timer = NULL;
double start; double start;
double lap; double lap;
@@ -89,12 +98,12 @@ static float XPCFlightLoopCallback(float inElapsedSinceLastCall, float inElapsed
PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc) 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(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 (__APPLE__)
if ( abs(timeConvert) <= 1e-9 ) // is about 0 if ( timeConvert <= 1e-9 ) // is about 0
{ {
mach_timebase_info_data_t timeBase; mach_timebase_info_data_t timeBase;
(void)mach_timebase_info(&timeBase); (void)mach_timebase_info(&timeBase);
@@ -103,7 +112,7 @@ PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc)
1000000000.0; 1000000000.0;
} }
#endif #endif
XPC::Log::Initialize("1.2.1"); XPC::Log::Initialize(XPC_PLUGIN_VERSION);
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Start"); XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Start");
XPC::DataManager::Initialize(); XPC::DataManager::Initialize();
@@ -131,12 +140,18 @@ PLUGIN_API void XPluginDisable(void)
XPC::Drawing::ClearWaypoints(); XPC::Drawing::ClearWaypoints();
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Disabled, sockets closed"); XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Disabled, sockets closed");
timer->stop();
delete timer;
timer = NULL;
} }
PLUGIN_API int XPluginEnable(void) PLUGIN_API int XPluginEnable(void)
{ {
// Open sockets // Open sockets
sock = new XPC::UDPSocket(RECVPORT); sock = new XPC::UDPSocket(RECVPORT);
timer = new XPC::Timer();
XPC::MessageHandlers::SetSocket(sock); XPC::MessageHandlers::SetSocket(sock);
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Enabled, sockets opened"); XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Enabled, sockets opened");
@@ -150,6 +165,15 @@ PLUGIN_API int XPluginEnable(void)
void* refcon = NULL; // Don't pass anything to the callback directly void* refcon = NULL; // Don't pass anything to the callback directly
XPLMRegisterFlightLoopCallback(XPCFlightLoopCallback, interval, refcon); 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; 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 = { objects = {
/* Begin PBXBuildFile section */ /* 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 */; }; BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */; };
BE8361EF18C5591C00E9C923 /* mac.xpl in CopyFiles */ = {isa = PBXBuildFile; fileRef = D607B19909A556E400699BC3 /* mac.xpl */; }; BE8361EF18C5591C00E9C923 /* mac.xpl in CopyFiles */ = {isa = PBXBuildFile; fileRef = D607B19909A556E400699BC3 /* mac.xpl */; };
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */; }; BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */; };
@@ -36,6 +37,8 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference 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; }; 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>"; }; 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>"; }; BEABAD2C1AE041A3007BA7DA /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataManager.h; sourceTree = "<group>"; };
@@ -76,6 +79,7 @@
AC4E46B809C2E0B3006B7E1B /* src */ = { AC4E46B809C2E0B3006B7E1B /* src */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
3D0F44CD21C6D3E7008A0655 /* Timer.cpp */,
BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */, BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */,
BEDC620218EDF1A7005DB364 /* xplaneConnect.c */, BEDC620218EDF1A7005DB364 /* xplaneConnect.c */,
BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */, BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */,
@@ -91,6 +95,7 @@
BE953E0B1AEB183400CE4A8C /* inc */ = { BE953E0B1AEB183400CE4A8C /* inc */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
3D0F44CC21C6D3E7008A0655 /* Timer.h */,
BEDC620318EDF1A7005DB364 /* xplaneConnect.h */, BEDC620318EDF1A7005DB364 /* xplaneConnect.h */,
BEABAD2C1AE041A3007BA7DA /* DataManager.h */, BEABAD2C1AE041A3007BA7DA /* DataManager.h */,
BEABAD301AE041A3007BA7DA /* Drawing.h */, BEABAD301AE041A3007BA7DA /* Drawing.h */,
@@ -190,6 +195,7 @@
BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */, BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */,
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */, BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */,
BEABAD391AE041A3007BA7DA /* Drawing.cpp in Sources */, BEABAD391AE041A3007BA7DA /* Drawing.cpp in Sources */,
3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */,
BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */, BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */,
BEABAD3F1AE0498D007BA7DA /* UDPSocket.cpp in Sources */, BEABAD3F1AE0498D007BA7DA /* UDPSocket.cpp in Sources */,
); );
@@ -298,11 +304,14 @@
D607B19C09A556E400699BC3 /* Debug */ = { D607B19C09A556E400699BC3 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ARCHS = "$(ARCHS_STANDARD)";
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_LINK_OBJC_RUNTIME = NO; CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
CONFIGURATION_BUILD_DIR = ./XPlaneConnect/;
CURRENT_PROJECT_VERSION = 0.24; CURRENT_PROJECT_VERSION = 0.24;
GCC_ENABLE_OBJC_EXCEPTIONS = NO; GCC_ENABLE_OBJC_EXCEPTIONS = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
@@ -337,11 +346,14 @@
D607B19D09A556E400699BC3 /* Release */ = { D607B19D09A556E400699BC3 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ARCHS = "$(ARCHS_STANDARD)";
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_LINK_OBJC_RUNTIME = NO; CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
CONFIGURATION_BUILD_DIR = ./XPlaneConnect/;
CURRENT_PROJECT_VERSION = 0.24; CURRENT_PROJECT_VERSION = 0.24;
GCC_ENABLE_OBJC_EXCEPTIONS = NO; GCC_ENABLE_OBJC_EXCEPTIONS = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO;
@@ -365,9 +377,7 @@
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/xplaneConnect-asdjuezcjkhojuewbyxhyhabxfwc/Build/Products/Debug", "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/xplaneConnect-asdjuezcjkhojuewbyxhyhabxfwc/Build/Products/Debug",
); );
MACH_O_TYPE = mh_bundle; MACH_O_TYPE = mh_bundle;
ONLY_ACTIVE_ARCH = NO; ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = mac; PRODUCT_NAME = mac;
SDKROOT = macosx; SDKROOT = macosx;
STRIP_INSTALLED_PRODUCT = YES; STRIP_INSTALLED_PRODUCT = YES;

View File

@@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013 # Visual Studio 2015
VisualStudioVersion = 12.0.31101.0 VisualStudioVersion = 15.0.28307.168
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xpcPlugin", "xpcPlugin.vcxproj", "{6AEF5D28-2701-44FF-AE10-1DEF07C5CAEA}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xpcPlugin", "xpcPlugin.vcxproj", "{6AEF5D28-2701-44FF-AE10-1DEF07C5CAEA}"
EndProject EndProject

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?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"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
@@ -28,25 +28,25 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@@ -121,7 +121,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>EnableAllWarnings</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Full</Optimization> <Optimization>Full</Optimization>
<PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DebugInformationFormat>OldStyle</DebugInformationFormat> <DebugInformationFormat>OldStyle</DebugInformationFormat>
@@ -171,7 +171,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>EnableAllWarnings</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Full</Optimization> <Optimization>Full</Optimization>
<PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck> <SDLCheck>
@@ -206,6 +206,7 @@
<ClInclude Include="..\Log.h" /> <ClInclude Include="..\Log.h" />
<ClInclude Include="..\Message.h" /> <ClInclude Include="..\Message.h" />
<ClInclude Include="..\MessageHandlers.h" /> <ClInclude Include="..\MessageHandlers.h" />
<ClCompile Include="..\Timer.h" />
<ClInclude Include="..\UDPSocket.h" /> <ClInclude Include="..\UDPSocket.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -214,6 +215,7 @@
<ClCompile Include="..\Log.cpp" /> <ClCompile Include="..\Log.cpp" />
<ClCompile Include="..\Message.cpp" /> <ClCompile Include="..\Message.cpp" />
<ClCompile Include="..\MessageHandlers.cpp" /> <ClCompile Include="..\MessageHandlers.cpp" />
<ClCompile Include="..\Timer.cpp" />
<ClCompile Include="..\UDPSocket.cpp" /> <ClCompile Include="..\UDPSocket.cpp" />
<ClCompile Include="..\XPCPlugin.cpp" /> <ClCompile Include="..\XPCPlugin.cpp" />
</ItemGroup> </ItemGroup>