diff --git a/.gitignore b/.gitignore index 2575f4c..d77d831 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ # OS generated files # ###################### .DS_Store? +.DS_Store ehthumbs.db Icon? Thumbs.db @@ -69,6 +70,7 @@ build/ xcuserdata *.moved-aside *.xccheckout +xcshareddata # IntelliJ Files # ################## diff --git a/C/monitorExample/main.c b/C/monitorExample/main.c index e78f0cf..e6d2e62 100644 --- a/C/monitorExample/main.c +++ b/C/monitorExample/main.c @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. // // DISCLAIMERS @@ -70,7 +70,7 @@ int main(void) tv.tv_usec = 100 * 1000; while (1) { - float posi[7]; + float posi[7]; // FIXME: change this to the 64-bit lat/lon/h int result = getPOSI(client, posi, aircraftNum); if (result < 0) // Error in getPOSI { @@ -98,4 +98,4 @@ int main(void) printf("\n\nPress Any Key to exit..."); getchar(); return 0; -} \ No newline at end of file +} diff --git a/C/playbackExample/src/chrome.c b/C/playbackExample/src/chrome.c index f1850dd..b4a95b9 100644 --- a/C/playbackExample/src/chrome.c +++ b/C/playbackExample/src/chrome.c @@ -1,8 +1,8 @@ -//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. // //DISCLAIMERS -// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, +// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, // EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY @@ -68,4 +68,4 @@ int getInt(char* prompt) int result; scanf("%d", &result); return result; -} \ No newline at end of file +} diff --git a/C/playbackExample/src/chrome.h b/C/playbackExample/src/chrome.h index fd240e6..33bc0c6 100644 --- a/C/playbackExample/src/chrome.h +++ b/C/playbackExample/src/chrome.h @@ -1,8 +1,8 @@ -//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. // //DISCLAIMERS -// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, +// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, // EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY @@ -37,4 +37,4 @@ void getString(char* prompt, char buffer[255]); int getInt(char* prompt); -#endif \ No newline at end of file +#endif diff --git a/C/playbackExample/src/main.c b/C/playbackExample/src/main.c index abdeb33..785582d 100644 --- a/C/playbackExample/src/main.c +++ b/C/playbackExample/src/main.c @@ -1,8 +1,8 @@ -//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. // //DISCLAIMERS -// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, +// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, // EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY @@ -35,7 +35,7 @@ int main(void) }; char path[256] = { 0 }; - displayStart("1.2.0.0"); + displayStart("1.3-rc.1"); while (1) { switch (displayMenu("What would you like to do?", mainOpts, 3)) @@ -67,4 +67,4 @@ int main(void) } return 0; -} \ No newline at end of file +} diff --git a/C/playbackExample/src/playback.c b/C/playbackExample/src/playback.c index 3226c5a..4d2e594 100644 --- a/C/playbackExample/src/playback.c +++ b/C/playbackExample/src/playback.c @@ -1,8 +1,8 @@ -//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. // //DISCLAIMERS -// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, +// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, // EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY @@ -89,18 +89,18 @@ void playback(char* path, int interval) displayMsg("Starting Playback..."); XPCSocket sock = openUDP("127.0.0.1"); - float posi[7]; + double posi[7]; while (!feof(fd) && !ferror(fd)) { - int result = fscanf(fd, "%f, %f, %f, %f, %f, %f, %f\n", + int result = fscanf(fd, "%lf, %lf, %lf, %lf, %lf, %lf, %lf\n", &posi[0], &posi[1], &posi[2], &posi[3], &posi[4], &posi[5], &posi[6]); playbackSleep(interval); if (result != 7) { continue; - } + } sendPOSI(sock, posi, 7, 0); } closeUDP(sock); displayMsg("Playback Complete"); -} \ No newline at end of file +} diff --git a/C/playbackExample/src/playback.h b/C/playbackExample/src/playback.h index 98fa54b..d76623d 100644 --- a/C/playbackExample/src/playback.h +++ b/C/playbackExample/src/playback.h @@ -1,8 +1,8 @@ -//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. // //DISCLAIMERS -// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, +// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, // EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY @@ -29,4 +29,4 @@ void record(char* path, int interval, int duration); void playback(char* path, int interval); -#endif \ No newline at end of file +#endif diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index e201a75..ed984fb 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -1,8 +1,8 @@ -//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. // //DISCLAIMERS -// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, +// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, // EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY @@ -82,13 +82,13 @@ XPCSocket openUDP(const char *xpIP) XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port) { XPCSocket sock; - + // Setup Port struct sockaddr_in recvaddr; recvaddr.sin_family = AF_INET; recvaddr.sin_addr.s_addr = INADDR_ANY; recvaddr.sin_port = htons(port); - + // Set X-Plane Port and IP if (strcmp(xpIP, "localhost") == 0) { @@ -96,7 +96,7 @@ XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port) } strncpy(sock.xpIP, xpIP, 16); sock.xpPort = xpPort == 0 ? 49009 : xpPort; - + #ifdef _WIN32 WSADATA wsa; if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) @@ -105,7 +105,7 @@ XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port) exit(EXIT_FAILURE); } #endif - + if ((sock.sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { printError("OpenUDP", "Socket creation failed"); @@ -128,7 +128,7 @@ XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port) if (setsockopt(sock.sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { printError("OpenUDP", "Failed to set timeout"); - } + } return sock; } @@ -160,7 +160,7 @@ int sendUDP(XPCSocket sock, char buffer[], int len) printError("sendUDP", "Message length must be positive."); return -1; } - + // Set up destination address struct sockaddr_in dst; dst.sin_family = AF_INET; @@ -273,7 +273,7 @@ int setCONN(XPCSocket* sock, unsigned short port) int pauseSim(XPCSocket sock, char pause) { // Validte input - if (pause < 0 || pause > 2) + if (pause < 0 || (pause > 2 && pause < 100) || (pause > 119 && pause < 200) || pause > 219) { printError("pauseSim", "Invalid argument: %i", pause); return -2; @@ -311,7 +311,7 @@ int sendDATA(XPCSocket sock, float data[][9], int rows) // Setup command // 5 byte header + 134 rows * 9 values * 4 bytes per value => 4829 byte max length. - char buffer[4829] = "DATA"; + char buffer[4829] = "DATA"; int len = 5 + rows * 9 * sizeof(float); unsigned short step = 9 * sizeof(float); int i; // iterator @@ -462,7 +462,7 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si { unsigned char buffer[65536]; int result = readUDP(sock, buffer, 65536); - + if (result < 0) { #ifdef _WIN32 @@ -563,13 +563,14 @@ int getPOSI(XPCSocket sock, float values[7], char ac) printError("getPOSI", "Unexpected response length."); return -3; } + // TODO: change this to the 64-bit lat/lon/h // Copy response into values memcpy(values, readBuffer + 6, 7 * sizeof(float)); return 0; } -int sendPOSI(XPCSocket sock, float values[], int size, char ac) +int sendPOSI(XPCSocket sock, double values[], int size, char ac) { // Validate input if (ac < 0 || ac > 20) @@ -584,23 +585,32 @@ int sendPOSI(XPCSocket sock, float values[], int size, char ac) } // Setup command - // 5 byte header + up to 7 values * 5 bytes each - unsigned char buffer[40] = "POSI"; + unsigned char buffer[46] = "POSI"; + buffer[4] = 0xff; //Placeholder for message length buffer[5] = ac; int i; // iterator - for (i = 0; i < 7; i++) + + for (i = 0; i < 7; i++) // double for lat/lon/h { - float val = -998; + double val = -998; if (i < size) { val = values[i]; } - *((float*)(buffer + 6 + i * 4)) = val; + if (i < 3) /* lat/lon/h */ + { + memcpy(&buffer[6 + i*8], &val, sizeof(double)); + } + else /* attitude and gear */ + { + float f = (float)val; + memcpy(&buffer[18 + i*4], &f, sizeof(float)); + } } // Send Command - if (sendUDP(sock, buffer, 40) < 0) + if (sendUDP(sock, buffer, 46) < 0) { printError("sendPOSI", "Failed to send command"); return -3; @@ -735,9 +745,9 @@ int sendTEXT(XPCSocket sock, char* msg, int x, int y) size_t len = 14 + msgLen; memcpy(buffer + 5, &x, sizeof(int)); memcpy(buffer + 9, &y, sizeof(int)); - buffer[13] = msgLen; + buffer[13] = (unsigned char)msgLen; strncpy(buffer + 14, msg, msgLen); - + // Send Command if (sendUDP(sock, buffer, len) < 0) { @@ -807,4 +817,4 @@ int sendVIEW(XPCSocket sock, VIEW_TYPE view) } /*****************************************************************************/ /**** End View functions ****/ -/*****************************************************************************/ \ No newline at end of file +/*****************************************************************************/ diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index b701c88..8cfb06f 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -1,8 +1,8 @@ -//Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. // //DISCLAIMERS -// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, +// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, // EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY @@ -78,7 +78,7 @@ typedef enum XPC_VIEW_FULLSCREENWITHHUD, XPC_VIEW_FULLSCREENNOHUD, } VIEW_TYPE; - + // Low Level UDP Functions /// Opens a new connection to XPC on an OS chosen port. @@ -112,10 +112,10 @@ int setCONN(XPCSocket* sock, unsigned short port); /// Pause or unpause the simulation. /// /// \param sock The socket to use to send the command. -/// \param pause 0 to unpause the sim; any other value to pause. +/// \param pause 0 to unpause the sim; 1 to pause, 100:119 to pause a/c 0:19, 200:219 to unpause a/c 0:19. /// \returns 0 if successful, otherwise a negative value. int pauseSim(XPCSocket sock, char pause); - + // X-Plane UDP DATA /// Reads X-Plane data from the specified socket. @@ -193,7 +193,7 @@ int getDREF(XPCSocket sock, const char* dref, float values[], int* size); /// to the actual number of elements copied in for that row. /// \returns 0 if successful, otherwise a negative value. int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char count, int sizes[]); - + // Position /// Gets the position and orientation of the specified aircraft. @@ -213,7 +213,7 @@ int getPOSI(XPCSocket sock, float values[7], char ac); /// \param size The number of elements in values. /// \param ac The aircraft number to set the position of. 0 for the player aircraft. /// \returns 0 if successful, otherwise a negative value. -int sendPOSI(XPCSocket sock, float values[], int size, char ac); +int sendPOSI(XPCSocket sock, double values[], int size, char ac); // Controls diff --git a/C/xpcExample/xpcExample/src/main.cpp b/C/xpcExample/xpcExample/src/main.cpp index e9e645a..ba06f01 100644 --- a/C/xpcExample/xpcExample/src/main.cpp +++ b/C/xpcExample/xpcExample/src/main.cpp @@ -33,7 +33,7 @@ int main() // Set Location/Orientation (sendPOSI) // Set Up Position Array - float POSI[9] = { 0.0 }; + double POSI[9] = { 0.0 }; POSI[0] = 37.524; // Lat POSI[1] = -122.06899; // Lon POSI[2] = 2500; // Alt diff --git a/Java/.idea/misc.xml b/Java/.idea/misc.xml index a61f7bc..b7148e8 100644 --- a/Java/.idea/misc.xml +++ b/Java/.idea/misc.xml @@ -1,19 +1,6 @@ - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/Java/.idea/modules.xml b/Java/.idea/modules.xml index 3132258..bc73bac 100644 --- a/Java/.idea/modules.xml +++ b/Java/.idea/modules.xml @@ -2,6 +2,7 @@ + diff --git a/Java/Examples/BasicOperation/src/Main.java b/Java/Examples/BasicOperation/src/Main.java index dc82c9f..99c28c9 100644 --- a/Java/Examples/BasicOperation/src/Main.java +++ b/Java/Examples/BasicOperation/src/Main.java @@ -1,7 +1,6 @@ package gov.nasa.xpc.ex; import gov.nasa.xpc.XPlaneConnect; - import java.io.IOException; import java.net.SocketException; import java.util.Arrays; @@ -25,11 +24,11 @@ public class Main xpc.getDREF("sim/test/test_float"); System.out.println("Setting player aircraft position"); - float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1}; + double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1}; xpc.sendPOSI(posi); System.out.println("Setting another aircraft position"); - posi[0] = 37.52465F; + posi[0] = 37.52465; posi[4] = 20; xpc.sendPOSI(posi, 1); diff --git a/Java/Examples/ContinuousOperation/src/Main.java b/Java/Examples/ContinuousOperation/src/Main.java index 61a14eb..801a369 100644 --- a/Java/Examples/ContinuousOperation/src/Main.java +++ b/Java/Examples/ContinuousOperation/src/Main.java @@ -20,7 +20,7 @@ public class Main int aircraft = 0; while(true) { - float[] posi = xpc.getPOSI(aircraft); + float[] posi = xpc.getPOSI(aircraft); // FIXME: change this to 64-bit double float[] ctrl = xpc.getCTRL(aircraft); System.out.format("Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n", diff --git a/Java/Examples/DiscoveryExample/DiscoveryExample.iml b/Java/Examples/DiscoveryExample/DiscoveryExample.iml new file mode 100644 index 0000000..eeb2a2f --- /dev/null +++ b/Java/Examples/DiscoveryExample/DiscoveryExample.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Java/Examples/DiscoveryExample/src/DiscoveryConnectionExample.java b/Java/Examples/DiscoveryExample/src/DiscoveryConnectionExample.java new file mode 100644 index 0000000..454dd6d --- /dev/null +++ b/Java/Examples/DiscoveryExample/src/DiscoveryConnectionExample.java @@ -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"); + } +} diff --git a/Java/Examples/DiscoveryExample/src/SimpleDiscoveryExample.java b/Java/Examples/DiscoveryExample/src/SimpleDiscoveryExample.java new file mode 100644 index 0000000..cfab704 --- /dev/null +++ b/Java/Examples/DiscoveryExample/src/SimpleDiscoveryExample.java @@ -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(); + } +} diff --git a/Java/Examples/Playback/src/gov/nasa/xpc/Main.java b/Java/Examples/Playback/src/gov/nasa/xpc/Main.java index 0e0b376..3b5925b 100644 --- a/Java/Examples/Playback/src/gov/nasa/xpc/Main.java +++ b/Java/Examples/Playback/src/gov/nasa/xpc/Main.java @@ -12,7 +12,7 @@ public class Main { String[] mainOpts = new String[] { "Record X-Plane", "Playback File", "Exit" }; - System.out.println("X-Plane Connect Playback Example [Version 1.2.0.0]"); + System.out.println("X-Plane Connect Playback Example [Version 1.3-rc.1]"); System.out.println("(c) 2013-2015 United States Government as represented by the Administrator"); System.out.println("of the National Aeronautics and Space Administration. All Rights Reserved."); while(true) @@ -99,7 +99,7 @@ public class Main { for (int i = 0; i < count; ++i) { - float[] posi = xpc.getPOSI(0); + float[] posi = xpc.getPOSI(0); // FIXME: change this to 64-bit double writer.write(String.format("%1$f, %2$f, %3$f, %4$f, %5$f, %6$f, %7$f\n", posi[0], posi[1], posi[2], posi[3], posi[4], posi[5], posi[6])); try @@ -125,11 +125,11 @@ public class Main { while(reader.hasNextLine()) { - float[] posi = new float[7]; + double[] posi = new double[7]; for (int i = 0; i < 7; ++i) { String s = reader.next(); - posi[i] = Float.parseFloat(s); + posi[i] = Double.parseDouble(s); } reader.nextLine(); xpc.sendPOSI(posi); diff --git a/Java/XPlaneConnect.iml b/Java/XPlaneConnect.iml index 70873b5..8acc69f 100644 --- a/Java/XPlaneConnect.iml +++ b/Java/XPlaneConnect.iml @@ -1,6 +1,6 @@ - + @@ -10,6 +10,15 @@ - + + + + + + + + + + \ No newline at end of file diff --git a/Java/lib/hamcrest-core-1.3.jar b/Java/lib/hamcrest-core-1.3.jar new file mode 100644 index 0000000..9d5fe16 Binary files /dev/null and b/Java/lib/hamcrest-core-1.3.jar differ diff --git a/Java/lib/junit-4.12.jar b/Java/lib/junit-4.12.jar new file mode 100644 index 0000000..3a7fc26 Binary files /dev/null and b/Java/lib/junit-4.12.jar differ diff --git a/Java/src/ViewType.java b/Java/src/ViewType.java index 0457050..3cff8c4 100644 --- a/Java/src/ViewType.java +++ b/Java/src/ViewType.java @@ -1,5 +1,5 @@ //NOTICES: -// Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. // // DISCLAIMERS diff --git a/Java/src/WaypointOp.java b/Java/src/WaypointOp.java index 116d848..30cf4fc 100644 --- a/Java/src/WaypointOp.java +++ b/Java/src/WaypointOp.java @@ -1,5 +1,5 @@ //NOTICES: -// Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. // // DISCLAIMERS diff --git a/Java/src/XPlaneConnect.java b/Java/src/XPlaneConnect.java index 8b1f228..675da9b 100644 --- a/Java/src/XPlaneConnect.java +++ b/Java/src/XPlaneConnect.java @@ -1,5 +1,5 @@ //NOTICES: -// Copyright (c) 2013-2016 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. // // DISCLAIMERS @@ -25,6 +25,8 @@ package gov.nasa.xpc; +import gov.nasa.xpc.discovery.Beacon; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.AutoCloseable; @@ -136,6 +138,19 @@ public class XPlaneConnect implements AutoCloseable this(xpHost, xpPort, port, 100); } + + /** + * Initializes a new instance of the {@code XPlaneConnect} class from a received discovery Beacon + * @param beacon The beacon received from {@code XPlaneConnectDiscovery} + * @throws SocketException If this instance is unable to bind to the specified port. + */ + public XPlaneConnect(Beacon beacon) throws SocketException { + this.socket = new DatagramSocket(0); + this.xplaneAddr = beacon.getXplaneAddress(); + this.xplanePort = beacon.getPluginPort(); + this.socket.setSoTimeout(100); + } + /** * Initializes a new instance of the {@code XPlaneConnect} class using the specified ports, hostname, and timeout. * @@ -223,9 +238,9 @@ public class XPlaneConnect implements AutoCloseable */ public void pauseSim(int pause) throws IOException { - if(pause < 0 || pause > 2) + if(pause < 0 || (pause > 2 && pause < 100) || (pause > 119 && pause < 200) || pause > 219) { - throw new IllegalArgumentException("pause must be a value in the range [0, 2]."); + throw new IllegalArgumentException("pause must be a value in the range [0, 2], [100, 119], or [200, 219]."); } // S I M U LEN VAL @@ -549,7 +564,7 @@ public class XPlaneConnect implements AutoCloseable * @return An array containing control surface data in the same format as {@code sendPOSI}. * @throws IOException If the command cannot be sent or a response cannot be read. */ - public float[] getPOSI(int ac) throws IOException + public double[] getPOSI(int ac) throws IOException { // Send request ByteArrayOutputStream os = new ByteArrayOutputStream(); @@ -570,7 +585,7 @@ public class XPlaneConnect implements AutoCloseable } // Parse response - float[] result = new float[7]; + double[] result = new double[7]; ByteBuffer bb = ByteBuffer.wrap(data); bb.order(ByteOrder.LITTLE_ENDIAN); for(int i = 0; i < 7; ++i) @@ -600,13 +615,13 @@ public class XPlaneConnect implements AutoCloseable *

* @throws IOException If the command can not be sent. */ - public void sendPOSI(float[] values) throws IOException + public void sendPOSI(double[] values) throws IOException { sendPOSI(values, 0); } /** - * Sets the position of the specified ac. + * Sets the position of the specified ac with double precision coordinates. * * @param values

An array containing position elements as follows:

*
    @@ -626,7 +641,7 @@ public class XPlaneConnect implements AutoCloseable * @param ac The ac to set. 0 for the player ac. * @throws IOException If the command can not be sent. */ - public void sendPOSI(float[] values, int ac) throws IOException + public void sendPOSI(double[] values, int ac) throws IOException { //Preconditions if(values == null) @@ -644,15 +659,22 @@ public class XPlaneConnect implements AutoCloseable //Pad command values and convert to bytes int i; - ByteBuffer bb = ByteBuffer.allocate(28); + ByteBuffer bb = ByteBuffer.allocate(40); bb.order(ByteOrder.LITTLE_ENDIAN); for(i = 0; i < values.length; ++i) { - bb.putFloat(i * 4, values[i]); + if(i<3) /* lat/lon/height as double */ + { + bb.putDouble(values[i]); + } + else + { + bb.putFloat((float)values[i]); + } } for(; i < 7; ++i) { - bb.putFloat(i * 4, -998); + bb.putFloat(-998); } //Build and send message diff --git a/Java/src/discovery/Beacon.java b/Java/src/discovery/Beacon.java new file mode 100644 index 0000000..c5a33c1 --- /dev/null +++ b/Java/src/discovery/Beacon.java @@ -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(); + } +} diff --git a/Java/src/discovery/BeaconParser.java b/Java/src/discovery/BeaconParser.java new file mode 100644 index 0000000..1f7805f --- /dev/null +++ b/Java/src/discovery/BeaconParser.java @@ -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); + } +} \ No newline at end of file diff --git a/Java/src/discovery/BeaconReceivedListener.java b/Java/src/discovery/BeaconReceivedListener.java new file mode 100644 index 0000000..cd2e0d8 --- /dev/null +++ b/Java/src/discovery/BeaconReceivedListener.java @@ -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); +} diff --git a/Java/src/discovery/DiscoveryConnectionCallback.java b/Java/src/discovery/DiscoveryConnectionCallback.java new file mode 100644 index 0000000..1292826 --- /dev/null +++ b/Java/src/discovery/DiscoveryConnectionCallback.java @@ -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); +} diff --git a/Java/src/discovery/XPlaneConnectDiscovery.java b/Java/src/discovery/XPlaneConnectDiscovery.java new file mode 100644 index 0000000..0a92dce --- /dev/null +++ b/Java/src/discovery/XPlaneConnectDiscovery.java @@ -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(); + } +} diff --git a/MATLAB/+XPlaneConnect/XPlaneConnect.jar b/MATLAB/+XPlaneConnect/XPlaneConnect.jar index f9d9e0b..a182eb3 100644 Binary files a/MATLAB/+XPlaneConnect/XPlaneConnect.jar and b/MATLAB/+XPlaneConnect/XPlaneConnect.jar differ diff --git a/MATLAB/+XPlaneConnect/pauseSim.m b/MATLAB/+XPlaneConnect/pauseSim.m index da44b71..c33dcf0 100644 --- a/MATLAB/+XPlaneConnect/pauseSim.m +++ b/MATLAB/+XPlaneConnect/pauseSim.m @@ -2,7 +2,7 @@ function pauseSim( pause, socket ) %pauseSim Pauses or unpauses X-Plane. % %Inputs -% pause: binary value 0=run, 1=pause +% pause: int 0= unpause all, 1= pause all, 2= switch all, 100:119= pause a/c 0:19, 200:219= unpause a/c 0:19 % socket (optional): The client to use when sending the command. % %Use @@ -34,4 +34,4 @@ pause = int32(pause); %% Send command socket.pauseSim(pause); -end \ No newline at end of file +end diff --git a/MATLAB/+XPlaneConnect/sendPOSI.m b/MATLAB/+XPlaneConnect/sendPOSI.m index bff56fb..a8c84a0 100644 --- a/MATLAB/+XPlaneConnect/sendPOSI.m +++ b/MATLAB/+XPlaneConnect/sendPOSI.m @@ -1,6 +1,6 @@ function sendPOSI( posi, ac, socket ) % sendPOSI Sets the position of the specified aircraft. -% +% % Inputs % posi: Position array where the elements are as follows: % 1. Latitiude (deg) @@ -12,14 +12,14 @@ function sendPOSI( posi, ac, socket ) % 7. Gear (0=up, 1=down) % acft (optional): The aircraft to set. 0 for the player aircraft. % socket (optional): The client to use when sending the command. -% +% % Use % 1. import XPlaneConnect.*; % 2. sendPOSI([37.5242422, -122.06899, 2500, 0, 0, 0, 1], 1); -% +% % Note: send the value -998 to not overwrite that parameter. That is, if % -998 is sent, the parameter will stay at the current X-Plane value. -% +% % Contributors % [CT] Christopher Teubert (SGT, Inc.) % christopher.a.teubert@nasa.gov @@ -33,14 +33,14 @@ global clients; if ~exist('socket', 'var') assert(isequal(length(clients) < 2, 1), '[sendPOSI] ERROR: Multiple clients open. You must specify which client to use.'); if isempty(clients) - socket = openUDP(); + socket = openUDP(); else socket = clients(1); end end %% Validate input -posi = single(posi); +posi = double(posi); if ~exist('ac', 'var') ac = 0; end @@ -49,4 +49,4 @@ ac = logical(ac); %% Send command socket.sendPOSI(posi, ac); -end \ No newline at end of file +end diff --git a/MATLAB/MonitorExample/MonitorExample.m b/MATLAB/MonitorExample/MonitorExample.m index ffbdc14..63e8cd4 100644 --- a/MATLAB/MonitorExample/MonitorExample.m +++ b/MATLAB/MonitorExample/MonitorExample.m @@ -11,9 +11,9 @@ Socket = openUDP(); while 1 posi = getPOSI(0, Socket); ctrl = getCTRL(0, Socket); - + fprintf('Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n', ... posi(1), posi(2), posi(3), ctrl(2), ctrl(1), ctrl(3)); pause(0.1); end -closeUDP(Socket); \ No newline at end of file +closeUDP(Socket); diff --git a/Python/src/playbackExample.py b/Python/src/playbackExample.py index dfa4f52..21730b8 100644 --- a/Python/src/playbackExample.py +++ b/Python/src/playbackExample.py @@ -33,7 +33,7 @@ def playback(path, interval): print "Unable to open file." return - with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client: + with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client: print "Starting Playback..." for line in fd: try: @@ -56,7 +56,7 @@ def printMenu(title, opts): return int(raw_input("Please select and option: ")) def ex(): - print "X-Plane Connect Playback Example [Version 1.2.0]" + print "X-Plane Connect Playback Example [Version 1.3-rc.1]" print "(c) 2013-2015 United States Government as represented by the Administrator" print "of the National Aeronautics and Space Administration. All Rights Reserved." @@ -79,4 +79,4 @@ def ex(): print "Unrecognized option." if __name__ == "__main__": - ex() \ No newline at end of file + ex() diff --git a/Python/src/xpc.py b/Python/src/xpc.py index e2b5c5e..71b7eb2 100644 --- a/Python/src/xpc.py +++ b/Python/src/xpc.py @@ -8,7 +8,7 @@ class XPlaneConnect(object): # Basic Functions def __init__(self, xpHost = 'localhost', xpPort = 49009, port = 0, timeout = 100): '''Sets up a new connection to an X-Plane Connect plugin running in X-Plane. - + Args: xpHost: The hostname of the machine running X-Plane. xpPort: The port on which the XPC plugin is listening. Usually 49007. @@ -33,7 +33,7 @@ class XPlaneConnect(object): # Setup XPlane IP and port self.xpDst = (xpIP, xpPort) - # Create and bind socket + # Create and bind socket clientAddr = ("0.0.0.0", port) self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) self.socket.bind(clientAddr) @@ -71,18 +71,18 @@ class XPlaneConnect(object): # Configuration def setCONN(self, port): '''Sets the port on which the client sends and receives data. - + Args: port: The new port to use. ''' - #Validate parameters + #Validate parameters if port < 0 or port > 65535: raise ValueError("The specified port is not a valid port number.") #Send command buffer = struct.pack("<4sxH", "CONN", port) self.sendUDP(buffer) - + #Rebind socket clientAddr = ("0.0.0.0", port) timeout = self.socket.gettimeout(); @@ -96,12 +96,14 @@ class XPlaneConnect(object): def pauseSim(self, pause): '''Pauses or un-pauses the physics simulation engine in X-Plane. - + Args: - pause: True to pause the simulation; False to resume. + pause: True to pause the simulation for all a/c; False to resume for all a/c. + 2 to switch the status for all a/c. 100:119 to pause a/c 0:19. 200:219 to + resume a/c 0:19 ''' pause = int(pause) - if pause < 0 or pause > 2: + if pause < 0 or (pause > 2 and pause < 100) or (pause > 119 and pause < 200) or pause > 219 : raise ValueError("Invalid argument for pause command.") buffer = struct.pack("<4sxB", "SIMU", pause) @@ -110,7 +112,7 @@ class XPlaneConnect(object): # X-Plane UDP Data def readDATA(self): '''Reads X-Plane data. - + Returns: A 2 dimensional array containing 0 or more rows of data. Each array in the result will have 9 elements, the first of which is the row number which that array represents data for, and the rest of which are the data elements in @@ -127,7 +129,7 @@ class XPlaneConnect(object): def sendDATA(self, data): '''Sends X-Plane data over the underlying UDP socket. - + Args: data: An array of values representing data rows to be set. Each array in `data` should have 9 elements, the first of which is a row number in the range (0-134), @@ -143,7 +145,7 @@ class XPlaneConnect(object): buffer += struct.pack(" 20: raise ValueError("Aircraft number must be between 0 and 20.") + # FIXME update this to the 64-bit double lat/lon/h # Pack message buffer = struct.pack("<4sxB", "POSI", ac) for i in range(7): @@ -264,8 +267,8 @@ class XPlaneConnect(object): # Send self.sendUDP(buffer) - - # DREF Manipulation + + # DREF Manipulation def sendDREF(self, dref, values): '''Sets the specified dataref to the specified value. @@ -294,7 +297,7 @@ class XPlaneConnect(object): raise ValueError("dref must be a non-empty string less than 256 characters.") if value == None: raise ValueError("value must be a scalar or sequence of floats.") - + # Pack message if hasattr(value, "__len__"): if len(value) > 255: @@ -310,7 +313,7 @@ class XPlaneConnect(object): def getDREF(self, dref): '''Gets the value of an X-Plane dataref. - + Args: dref: The name of the dataref to get. diff --git a/Python3/src/basicExample.py b/Python3/src/basicExample.py new file mode 100644 index 0000000..f381e5d --- /dev/null +++ b/Python3/src/basicExample.py @@ -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() \ No newline at end of file diff --git a/Python3/src/monitorExample.py b/Python3/src/monitorExample.py new file mode 100644 index 0000000..c4cdb48 --- /dev/null +++ b/Python3/src/monitorExample.py @@ -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() \ No newline at end of file diff --git a/Python3/src/playbackExample.py b/Python3/src/playbackExample.py new file mode 100644 index 0000000..dfa4f52 --- /dev/null +++ b/Python3/src/playbackExample.py @@ -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() \ No newline at end of file diff --git a/Python3/src/xpc.py b/Python3/src/xpc.py new file mode 100644 index 0000000..ddf2be9 --- /dev/null +++ b/Python3/src/xpc.py @@ -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" 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" 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" 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 = " 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 diff --git a/Python3/xplaneConnect.pyproj b/Python3/xplaneConnect.pyproj new file mode 100644 index 0000000..446a9ff --- /dev/null +++ b/Python3/xplaneConnect.pyproj @@ -0,0 +1,58 @@ + + + + Debug + 2.0 + 3c7a940d-17c8-4e91-882f-9bc8b1d2f54b + . + src\basicExample.py + + + . + . + XPlaneConnect + XPlaneConnect + {9a7a9026-48c1-4688-9d5d-e5699d47d074} + 2.7 + + + true + false + + + true + false + + + + Code + + + Code + + + + Code + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets + + + + + + + + + + \ No newline at end of file diff --git a/Python3/xplaneConnect.sln b/Python3/xplaneConnect.sln new file mode 100644 index 0000000..862da8d --- /dev/null +++ b/Python3/xplaneConnect.sln @@ -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 diff --git a/README.md b/README.md index 8240a07..af98065 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ the next official release. ### Notices -Copyright ©2013-2017 United States Government as represented by the Administrator +Copyright ©2013-2018 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved. No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY diff --git a/TestScripts/C Tests/CtrlTests.h b/TestScripts/C Tests/CtrlTests.h index 572ea07..83e7d36 100644 --- a/TestScripts/C Tests/CtrlTests.h +++ b/TestScripts/C Tests/CtrlTests.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef CTRLTESTS_H #define CTRLTESTS_H @@ -23,7 +23,7 @@ int doCTRLTest(XPCSocket *sock, char* drefs[7], float values[], int size, int ac { result = getDREFs(*sock, drefs, data, 7, sizes); } - + if (result < 0) { return -1; @@ -102,7 +102,7 @@ int basicCTRLTest(char** drefs, int ac) CTRL[4] = -998; CTRL[5] = -998; result = doCTRLTest(&sock, drefs, CTRL, 6, ac, expected); - + pauseSim(sock, 0); closeUDP(sock); if (result < 0) @@ -200,4 +200,4 @@ int testGETC_NonPlayer() float CTRL[7] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F, -1.5F }; return doGETCTest(CTRL, 2, CTRL); } -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/DataTests.h b/TestScripts/C Tests/DataTests.h index 2bf1564..4fde0ab 100644 --- a/TestScripts/C Tests/DataTests.h +++ b/TestScripts/C Tests/DataTests.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef DATATESTS_H #define DATATESTS_H @@ -59,4 +59,4 @@ int testDATA() return 0; } -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/DrefTests.h b/TestScripts/C Tests/DrefTests.h index 50338a7..c64ce6d 100644 --- a/TestScripts/C Tests/DrefTests.h +++ b/TestScripts/C Tests/DrefTests.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef DREFTESTS_H #define DREFTESTS_H @@ -244,4 +244,4 @@ int testDREF() return doDREFTest(drefs, values, expected, 6, sizes); } -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/PosiTests.h b/TestScripts/C Tests/PosiTests.h index 104e517..fc084ec 100644 --- a/TestScripts/C Tests/PosiTests.h +++ b/TestScripts/C Tests/PosiTests.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef POSITESTS_H #define POSITESTS_H @@ -6,7 +6,7 @@ #include "Test.h" #include "xplaneConnect.h" -int doPOSITest(char* drefs[7], float values[], int size, int ac, float expected[7]) +int doPOSITest(char* drefs[7], double values[], int size, int ac, double expected[7]) { float* data[7]; int sizes[7]; @@ -32,15 +32,15 @@ int doPOSITest(char* drefs[7], float values[], int size, int ac, float expected[ } // Test values - float actual[7]; + double actual[7]; for (int i = 0; i < 7; ++i) { actual[i] = data[i][0]; } - return compareArray(expected, actual, 7); + return compareDoubleArray(expected, actual, 7); } -int doGETPTest(float values[7], int ac, float expected[7]) +int doGETPTest(double values[7], int ac, double expected[7]) { // Execute Test float actual[7]; @@ -70,8 +70,8 @@ int doGETPTest(float values[7], int ac, float expected[7]) int basicPOSITest(char** drefs, int ac) { // Set psoition and initial orientation - float POSI[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 }; - float expected[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 }; + double POSI[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 }; + double expected[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 }; int result = doPOSITest(drefs, POSI, 7, ac, expected); if (result < 0) { @@ -79,9 +79,9 @@ int basicPOSITest(char** drefs, int ac) } // Set orientation - POSI[0] = -998.0F; - POSI[1] = -998.0F; - POSI[2] = -998.0F; + POSI[0] = -998.0; + POSI[1] = -998.0; + POSI[2] = -998.0; POSI[3] = 5.0F; POSI[4] = -5.0F; POSI[5] = 10.0F; @@ -101,10 +101,10 @@ int basicPOSITest(char** drefs, int ac) expected[0] = loc[0][0]; expected[1] = loc[1][0]; expected[2] = loc[2][0]; - expected[3] = 5.0F; - expected[4] = -5.0F; - expected[5] = 10.0F; - expected[6] = 0.0F; + expected[3] = 5.0; + expected[4] = -5.0; + expected[5] = 10.0; + expected[6] = 0.0; result = doPOSITest(drefs, POSI, 7, ac, expected); if (result < 0) { @@ -145,14 +145,14 @@ int testPOSI_NonPlayer() int testGetPOSI_Player() { - float POSI[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 }; + double POSI[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 }; return doGETPTest(POSI, 0, POSI); } int testGetPOSI_NonPlayer() { - float POSI[7] = { 37.624F, -122.06899F, 1500, 0, 0, 0, 1 }; + double POSI[7] = { 37.624, -122.06899, 1500, 0, 0, 0, 1 }; return doGETPTest(POSI, 3, POSI); } -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/SimuTests.h b/TestScripts/C Tests/SimuTests.h index 0d12012..f4e81e4 100644 --- a/TestScripts/C Tests/SimuTests.h +++ b/TestScripts/C Tests/SimuTests.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef SIMUTESTS_H #define SIMIUTESTS_H @@ -16,7 +16,7 @@ int doSIMUTest(int value, float expected) int result = pauseSim(sock, value); if (result >= 0) { - result = getDREF(sock, dref, &actual, &size); + result = getDREF(sock, dref, actual, &size); } closeUDP(sock); if (result < 0) @@ -78,4 +78,4 @@ int testSIMU_Toggle() return 0; } -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/Test.c b/TestScripts/C Tests/Test.c index 11ddc48..bff0c19 100644 --- a/TestScripts/C Tests/Test.c +++ b/TestScripts/C Tests/Test.c @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #include "Test.h" @@ -56,4 +56,28 @@ int compareArrays(float* expected[], int esizes[], float* actual[], int asizes[] } } return 0; -} \ No newline at end of file +} + +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; +} diff --git a/TestScripts/C Tests/Test.h b/TestScripts/C Tests/Test.h index 5c40d40..26b709f 100644 --- a/TestScripts/C Tests/Test.h +++ b/TestScripts/C Tests/Test.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef TESTRUNNER_H #define TESTRUNNER_H @@ -33,5 +33,7 @@ void runTest(int(*test)(), char* name); int compareFloat(float expected, float actual); int compareArray(float expected[], float actual[], int size); int compareArrays(float* expected[], int esizes[], float* actual[], int asizes[], int count); +int compareDoubleArray(double expected[], double actual[], int size); +int compareDoubleArrays(double* expected[], int esizes[], double* actual[], int asizes[], int count); -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/TextTests.h b/TestScripts/C Tests/TextTests.h index badf16e..987fc15 100644 --- a/TestScripts/C Tests/TextTests.h +++ b/TestScripts/C Tests/TextTests.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef TEXTTESTS_H #define TEXTTESTS_H @@ -29,4 +29,4 @@ int testTEXT() return 0; } -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/UDPTests.h b/TestScripts/C Tests/UDPTests.h index 3c3d3fa..1a4e3b6 100644 --- a/TestScripts/C Tests/UDPTests.h +++ b/TestScripts/C Tests/UDPTests.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef UDPTESTS_H #define UDPTESTS_H @@ -52,4 +52,4 @@ int testCONN() return 0; } -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/ViewTests.h b/TestScripts/C Tests/ViewTests.h index a25c14f..58013c9 100644 --- a/TestScripts/C Tests/ViewTests.h +++ b/TestScripts/C Tests/ViewTests.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef VIEWTESTS_H #define VIEWTESTS_H @@ -70,4 +70,4 @@ int testView() return doViewTest(XPC_VIEW_CHASE, XPC_VDREF_CHASE); } -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/WyptTests.h b/TestScripts/C Tests/WyptTests.h index fce3c2c..c04ecc9 100644 --- a/TestScripts/C Tests/WyptTests.h +++ b/TestScripts/C Tests/WyptTests.h @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #ifndef WYPTTESTS_H #define WYPTTESTS_H @@ -39,4 +39,4 @@ int testWYPT() return 0; } -#endif \ No newline at end of file +#endif diff --git a/TestScripts/C Tests/main.c b/TestScripts/C Tests/main.c index ec2b752..172ac09 100644 --- a/TestScripts/C Tests/main.c +++ b/TestScripts/C Tests/main.c @@ -1,4 +1,4 @@ -//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the +//Copyright (c) 2013-2018 United States Government as represented by the Administrator of the //National Aeronautics and Space Administration. All Rights Reserved. #include "Test.h" #include "UDPTests.h" @@ -13,7 +13,7 @@ int main(int argc, const char * argv[]) { printf("XPC Tests-c "); - + #ifdef _WIN32 printf("(Windows)\n"); #elif (__APPLE__) @@ -23,7 +23,7 @@ int main(int argc, const char * argv[]) { #else printf("(Unable to determine operating system) \n") #endif - + // Basic Networking runTest(testOpen, "open"); crossPlatformUSleep(SLEEP_AMOUNT); @@ -78,11 +78,10 @@ int main(int argc, const char * argv[]) { // setConn crossPlatformUSleep(SLEEP_AMOUNT); runTest(testCONN, "CONN"); - + printf( "----------------\nTest Summary\n\tFailed: %i\n\tPassed: %i\n", testFailed, testPassed ); printf("Press any key to exit."); getchar(); - + return 0; } - diff --git a/TestScripts/Java Tests/XPlaneConnectTest.java b/TestScripts/Java Tests/XPlaneConnectTest.java index 2e94bb5..c58fd04 100644 --- a/TestScripts/Java Tests/XPlaneConnectTest.java +++ b/TestScripts/Java Tests/XPlaneConnectTest.java @@ -542,15 +542,15 @@ public class XPlaneConnectTest public void testSendPOSI() throws IOException { String[] drefs = { - "sim/flightmodel/position/latitude", - "sim/flightmodel/position/longitude", - "sim/flightmodel/position/y_agl", - "sim/flightmodel/position/phi", - "sim/flightmodel/position/theta", - "sim/flightmodel/position/psi", - "sim/cockpit/switches/gear_handle_status" + "sim/flightmodel/position/latitude", + "sim/flightmodel/position/longitude", + "sim/flightmodel/position/y_agl", + "sim/flightmodel/position/phi", + "sim/flightmodel/position/theta", + "sim/flightmodel/position/psi", + "sim/cockpit/switches/gear_handle_status" }; - float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1}; + double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1}; try(XPlaneConnect xpc = new XPlaneConnect()) { xpc.pauseSim(true); @@ -585,7 +585,7 @@ public class XPlaneConnectTest @Test(expected = IllegalArgumentException.class) public void testSendPOSI_LongCtrl() throws IOException { - float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1, -998}; + double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1, -998}; try(XPlaneConnect xpc = new XPlaneConnect()) { xpc.sendPOSI(posi); @@ -595,7 +595,7 @@ public class XPlaneConnectTest @Test(expected = IllegalArgumentException.class) public void testSendPOSI_NegativeAircraftNum() throws IOException { - float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1, -998}; + double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1, -998}; try(XPlaneConnect xpc = new XPlaneConnect()) { xpc.sendPOSI(posi, -1); @@ -605,7 +605,7 @@ public class XPlaneConnectTest @Test(expected = IllegalArgumentException.class) public void testSendPOSI_LargeAircraftNum() throws IOException { - float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1, -998}; + double[] posi = new double[] {37.524, -122.06899, 2500, 0, 0, 0, 1, -998}; try(XPlaneConnect xpc = new XPlaneConnect()) { xpc.sendPOSI(posi, 300); @@ -702,12 +702,12 @@ public class XPlaneConnectTest @Test public void testGetPOSI() throws IOException { - float[] values = { 37.524F, -122.06899F, 2500.0F, 45.0F, -45.0F, 15.0F, 1.0F }; + double[] values = { 37.524, -122.06899, 2500.0, 45.0, -45.0, 15.0, 1.0 }; try(XPlaneConnect xpc = new XPlaneConnect()) { xpc.pauseSim(true); xpc.sendPOSI(values); - float[] actual = xpc.getPOSI(0); + double[] actual = xpc.getPOSI(0); assertArrayEquals(values, actual, 1e-4F); } @@ -725,4 +725,4 @@ public class XPlaneConnectTest assertArrayEquals(values, actual, 1e-4F); } } -} \ No newline at end of file +} diff --git a/TestScripts/Java Tests/XPlaneDiscoveryTests.java b/TestScripts/Java Tests/XPlaneDiscoveryTests.java new file mode 100644 index 0000000..bb954f2 --- /dev/null +++ b/TestScripts/Java Tests/XPlaneDiscoveryTests.java @@ -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; + } +} diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..d04d24a --- /dev/null +++ b/azure-pipelines.yml @@ -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 diff --git a/xpcPlugin/CMakeLists.txt b/xpcPlugin/CMakeLists.txt index d07ae27..a82a220 100644 --- a/xpcPlugin/CMakeLists.txt +++ b/xpcPlugin/CMakeLists.txt @@ -10,6 +10,10 @@ add_definitions(-DXPLM200 -DLIN=1) SET(CMAKE_C_COMPILER gcc) SET(CMAKE_CXX_COMPILER g++) +SET(CMAKE_CXX_STANDARD 11) + +SET(XPC_OUTPUT_DIR "XPlaneConnect") +SET(XPC_OUTPUT_NAME "lin") add_library(xpc64 SHARED XPCPlugin.cpp DataManager.cpp @@ -17,9 +21,12 @@ add_library(xpc64 SHARED XPCPlugin.cpp Log.cpp Message.cpp MessageHandlers.cpp + Timer.cpp UDPSocket.cpp) set_target_properties(xpc64 PROPERTIES PREFIX "" SUFFIX ".xpl") -set_target_properties(xpc64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m64") +set_target_properties(xpc64 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${XPC_OUTPUT_DIR}/64) +set_target_properties(xpc64 PROPERTIES OUTPUT_NAME ${XPC_OUTPUT_NAME}) +set_target_properties(xpc64 PROPERTIES COMPILE_FLAGS "-m64 -fno-stack-protector" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m64 -fno-stack-protector") add_library(xpc32 SHARED XPCPlugin.cpp DataManager.cpp @@ -27,9 +34,12 @@ add_library(xpc32 SHARED XPCPlugin.cpp Log.cpp Message.cpp MessageHandlers.cpp + Timer.cpp UDPSocket.cpp) set_target_properties(xpc32 PROPERTIES PREFIX "" SUFFIX ".xpl") -set_target_properties(xpc32 PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m32") +set_target_properties(xpc32 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${XPC_OUTPUT_DIR}) +set_target_properties(xpc32 PROPERTIES OUTPUT_NAME ${XPC_OUTPUT_NAME}) +set_target_properties(xpc32 PROPERTIES COMPILE_FLAGS "-m32 -fno-stack-protector" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m32 -fno-stack-protector") # Switch install targets when uncommenting the 32 bit line above. install(TARGETS xpc64 DESTINATION XPlaneConnect/64 RENAME lin.xpl) diff --git a/xpcPlugin/DataManager.cpp b/xpcPlugin/DataManager.cpp index 83fca41..6e66abb 100644 --- a/xpcPlugin/DataManager.cpp +++ b/xpcPlugin/DataManager.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. // // X-Plane API @@ -109,7 +109,7 @@ namespace XPC drefs.insert(make_pair(DREF_Latitude, XPLMFindDataRef("sim/flightmodel/position/latitude"))); drefs.insert(make_pair(DREF_Longitude, XPLMFindDataRef("sim/flightmodel/position/longitude"))); drefs.insert(make_pair(DREF_AGL, XPLMFindDataRef("sim/flightmodel/position/y_agl"))); - drefs.insert(make_pair(DREF_Elevation, XPLMFindDataRef("sim/flightmodel/position/elevation"))); + drefs.insert(make_pair(DREF_Elevation, XPLMFindDataRef("sim/flightmodel/position/elevation"))); drefs.insert(make_pair(DREF_LocalX, XPLMFindDataRef("sim/flightmodel/position/local_x"))); drefs.insert(make_pair(DREF_LocalY, XPLMFindDataRef("sim/flightmodel/position/local_y"))); @@ -522,7 +522,7 @@ namespace XPC Log::FormatLine(LOG_ERROR, "DMAN", "ERROR: invalid DREF %s", dref.c_str()); return; } - if (isnan(values[0])) + if (std::isnan(values[0])) { Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Value must be a number (NaN received)"); return; @@ -629,11 +629,12 @@ namespace XPC if ((gear < -8.5 && gear > -9.5) || IsDefault(gear)) { + Log::WriteLine(LOG_INFO, "DMAN", "Not actually setting gear because of default value"); return; } - if (isnan(gear) || gear < 0 || gear > 1) + if (std::isnan(gear) || gear < 0 || gear > 1) { - Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Gear value must be 0 or 1"); + Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Gear value must be between 0 and 1"); return; } @@ -657,11 +658,11 @@ namespace XPC } } - void DataManager::SetPosition(float pos[3], char aircraft) + void DataManager::SetPosition(double pos[3], char aircraft) { Log::FormatLine(LOG_INFO, "DMAN", "Setting position (%f, %f, %f) for aircraft %i", pos[0], pos[1], pos[2], aircraft); - if (isnan(pos[0] + pos[1] + pos[2])) + if (std::isnan(pos[0] + pos[1] + pos[2])) { Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Position must be a number (NaN received)"); return; @@ -669,28 +670,28 @@ namespace XPC if (IsDefault(pos[0])) { - pos[0] = (float)GetDouble(DREF_Latitude, aircraft); + pos[0] = GetDouble(DREF_Latitude, aircraft); } if (IsDefault(pos[1])) { - pos[1] = (float)GetDouble(DREF_Longitude, aircraft); + pos[1] = GetDouble(DREF_Longitude, aircraft); } if (IsDefault(pos[2])) { - pos[2] = (float)GetDouble(DREF_Elevation, aircraft); + pos[2] = GetDouble(DREF_Elevation, aircraft); } - // See: http://www.xsquawkbox.net/xpsdk/mediawiki/MovingThePlane - // Need to get the aircraft's current orientation before moving and - // reset the orientation after moving to update the quaternion - float orient[3]; - orient[0] = GetFloat(DREF_Pitch, aircraft); - orient[1] = GetFloat(DREF_Roll, aircraft); - orient[2] = GetFloat(DREF_HeadingTrue, aircraft); + // See: http://www.xsquawkbox.net/xpsdk/mediawiki/MovingThePlane + // Need to get the aircraft's current orientation before moving and + // reset the orientation after moving to update the quaternion + float orient[3]; + orient[0] = GetFloat(DREF_Pitch, aircraft); + orient[1] = GetFloat(DREF_Roll, aircraft); + orient[2] = GetFloat(DREF_HeadingTrue, aircraft); - // Now set the aircraft's position. Need to set world position for - // "long" moves, but since there isn't an easy way to calculate "long", - // we just set it every time. + // Now set the aircraft's position. Need to set world position for + // "long" moves, but since there isn't an easy way to calculate "long", + // we just set it every time. double local[3]; XPLMWorldToLocal(pos[0], pos[1], pos[2], &local[0], &local[1], &local[2]); // If the sim is paused, setting global position won't update the @@ -699,19 +700,19 @@ namespace XPC Set(DREF_LocalY, local[1], aircraft); Set(DREF_LocalZ, local[2], aircraft); // If the sim is unpaused, this will override the above settings. - Set(DREF_Latitude, (double)pos[0], aircraft); - Set(DREF_Longitude, (double)pos[1], aircraft); - Set(DREF_Elevation, (double)pos[2], aircraft); + Set(DREF_Latitude, pos[0], aircraft); + Set(DREF_Longitude, pos[1], aircraft); + Set(DREF_Elevation, pos[2], aircraft); - // Now reset orientation to update q - SetOrientation(orient, aircraft); + // Now reset orientation to update q + SetOrientation(orient, aircraft); } void DataManager::SetOrientation(float orient[3], char aircraft) { Log::FormatLine(LOG_INFO, "DMAN", "Setting orientation (%f, %f, %f) for aircraft %i", orient[0], orient[1], orient[2], aircraft); - if (isnan(orient[0] + orient[1] + orient[2])) + if (std::isnan(orient[0] + orient[1] + orient[2])) { Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Orientation must be a number (NaN received)"); return; @@ -762,7 +763,7 @@ namespace XPC { Log::FormatLine(LOG_INFO, "DMAN", "Setting flaps (value:%f)", value); - if (isnan(value)) + if (std::isnan(value)) { Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Flap value must be a number (NaN received)"); return; @@ -784,7 +785,7 @@ namespace XPC return -998.0F; } - bool DataManager::IsDefault(float value) + bool DataManager::IsDefault(double value) { return value < -997.9 && value > -999.1; } diff --git a/xpcPlugin/DataManager.h b/xpcPlugin/DataManager.h index c0e80c2..15f1218 100644 --- a/xpcPlugin/DataManager.h +++ b/xpcPlugin/DataManager.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. #ifndef XPCPLUGIN_DATAMANAGER_H_ #define XPCPLUGIN_DATAMANAGER_H_ @@ -396,7 +396,7 @@ namespace XPC /// \param pos An array containing latitude, longitude and altitude in /// fractional degrees and meters above sea level. /// \param aircraft The aircraft to set the position of. - static void SetPosition(float pos[3], char aircraft = 0); + static void SetPosition(double pos[3], char aircraft = 0); /// Sets the orientation of the specified aircraft. /// @@ -417,7 +417,7 @@ namespace XPC /// /// \param value The value to check. /// \returns true if value is a default value; otherwise false. - static bool IsDefault(float value); + static bool IsDefault(double value); }; } #endif diff --git a/xpcPlugin/Drawing.cpp b/xpcPlugin/Drawing.cpp index d737e36..40599c7 100644 --- a/xpcPlugin/Drawing.cpp +++ b/xpcPlugin/Drawing.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. // // X-Plane API @@ -173,7 +173,7 @@ namespace XPC glBegin(GL_LINE_STRIP); for (size_t i = 0; i < numWaypoints; ++i) { - LocalPoint* l = &localPoints[i]; + LocalPoint* l = &localPoints[i]; glVertex3f((float)l->x, (float)l->y, (float)l->z); } glEnd(); @@ -226,7 +226,7 @@ namespace XPC // Enable drawing if necessary if (!msgEnabled) { - XPLMRegisterDrawCallback(MessageDrawCallback, xplm_Phase_Window, 0, NULL); + XPLMRegisterDrawCallback(MessageDrawCallback, xplm_Phase_Window, 0, NULL); msgEnabled = true; } } diff --git a/xpcPlugin/Drawing.h b/xpcPlugin/Drawing.h index 51c39de..c6815e1 100644 --- a/xpcPlugin/Drawing.h +++ b/xpcPlugin/Drawing.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. #ifndef XPCPLUGIN_DRAWING_H_ #define XPCPLUGIN_DRAWING_H_ diff --git a/xpcPlugin/Log.cpp b/xpcPlugin/Log.cpp index a059ebb..581ad7e 100644 --- a/xpcPlugin/Log.cpp +++ b/xpcPlugin/Log.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. #include "Log.h" @@ -111,7 +111,7 @@ namespace XPC std::fprintf(fd, "X-Plane Connect [Version %s]\n", version.c_str()); std::fprintf(fd, "Compiled %s %s\n", __DATE__, __TIME__); - std::fprintf(fd, "Copyright (c) 2013-2017 United States Government as represented by the\n"); + std::fprintf(fd, "Copyright (c) 2013-2018 United States Government as represented by the\n"); std::fprintf(fd, "Administrator of the National Aeronautics and Space Administration.\n"); std::fprintf(fd, "All Rights Reserved.\n\n"); diff --git a/xpcPlugin/Log.h b/xpcPlugin/Log.h index cd6b6ba..5323678 100644 --- a/xpcPlugin/Log.h +++ b/xpcPlugin/Log.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. #ifndef XPCPLUGIN_LOG_H_ #define XPCPLUGIN_LOG_H_ @@ -27,7 +27,7 @@ namespace XPC { /// Handles logging for the plugin. - /// + /// /// \details Provides functions to write lines to the XPC log file. /// \author Jason Watkins /// \version 1.1 diff --git a/xpcPlugin/Message.cpp b/xpcPlugin/Message.cpp index 81c5c9c..f3401f0 100644 --- a/xpcPlugin/Message.cpp +++ b/xpcPlugin/Message.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. #include "Message.h" #include "Log.h" @@ -11,7 +11,7 @@ namespace XPC { - Message::Message() {} + Message::Message() {} Message Message::ReadFrom(const UDPSocket& sock) { @@ -110,17 +110,17 @@ namespace XPC else if (head == "DREF") { Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); - string dref((char*)buffer + 6, buffer[5]); - Log::FormatLine(LOG_DEBUG, "DBUG", " DREF (size %i) = %s", dref.length(), dref.c_str()); - ss.str(""); - int values = buffer[6 + buffer[5]]; - ss << " Values(size " << values << ") ="; - for (int i = 0; i < values; ++i) - { - ss << " " << *((float*)(buffer + values + 1 + sizeof(float) * i)); + string dref((char*)buffer + 6, buffer[5]); + Log::FormatLine(LOG_DEBUG, "DBUG", " DREF (size %i) = %s", dref.length(), dref.c_str()); + ss.str(""); + int values = buffer[6 + buffer[5]]; + ss << " Values(size " << values << ") ="; + for (int i = 0; i < values; ++i) + { + ss << " " << *((float*)(buffer + values + 1 + sizeof(float) * i)); } Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); - } + } else if (head == "GETC" || head == "GETP") { ss << " Aircraft:" << (int)buffer[5]; @@ -129,15 +129,15 @@ namespace XPC else if (head == "GETD") { Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); - int cur = 6; - for (int i = 0; i < buffer[5]; ++i) - { - string dref((char*)buffer + cur + 1, buffer[cur]); - Log::FormatLine(LOG_DEBUG, "DBUG", " #%i/%i (size:%i) %s", + int cur = 6; + for (int i = 0; i < buffer[5]; ++i) + { + string dref((char*)buffer + cur + 1, buffer[cur]); + Log::FormatLine(LOG_DEBUG, "DBUG", " #%i/%i (size:%i) %s", i + 1, buffer[5], dref.length(), dref.c_str()); - cur += 1 + buffer[cur]; - } - } + cur += 1 + buffer[cur]; + } + } else if (head == "POSI") { char aircraft = buffer[5]; @@ -146,14 +146,14 @@ namespace XPC float orient[3]; memcpy(pos, buffer + 6, 12); memcpy(orient, buffer + 18, 12); - ss << " AC:" << (int)aircraft; + ss << " AC:" << (int)aircraft; ss << " Pos:(" << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ") Orient:("; - ss << orient[3] << ' ' << orient[4] << ' ' << orient[5] << ") Gear:"; + ss << orient[0] << ' ' << orient[1] << ' ' << orient[2] << ") Gear:"; ss << gear; Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); - } + } else if (head == "SIMU") - { + { ss << ' ' << (int)buffer[5]; Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); } @@ -163,9 +163,9 @@ namespace XPC Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); } else - { + { ss << " UNKNOWN HEADER "; Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); - } + } } } diff --git a/xpcPlugin/Message.h b/xpcPlugin/Message.h index 34071cb..7fd6046 100644 --- a/xpcPlugin/Message.h +++ b/xpcPlugin/Message.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. #ifndef XPCPLUGIN_MESSAGE_H_ #define XPCPLUGIN_MESSAGE_H_ diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 89d6852..cc4ee18 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. // // X-Plane API @@ -20,9 +20,16 @@ #include "Log.h" #include "XPLMUtilities.h" +#include "XPLMGraphics.h" + #include #include +#include + +#define MULTICAST_GROUP "239.255.1.1" +#define MULITCAST_PORT 49710 + namespace XPC { @@ -32,6 +39,8 @@ namespace XPC std::string MessageHandlers::connectionKey; MessageHandlers::ConnectionInfo MessageHandlers::connection; UDPSocket* MessageHandlers::sock; + + static sockaddr multicast_address = UDPSocket::GetAddr(MULTICAST_GROUP, MULITCAST_PORT); void MessageHandlers::SetSocket(UDPSocket* socket) { @@ -127,6 +136,28 @@ namespace XPC MessageHandlers::HandleUnknown(msg); } } + + void MessageHandlers::SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion) { + + unsigned char response[128] = "BECN"; + + std::size_t cur = 5; + + // 2 bytes plugin port + *((uint16_t *)(response + cur)) = pluginReceivePort; + cur += sizeof(uint16_t); + + // 4 bytes xplane version + *((uint32_t*)(response + cur)) = xplaneVersion; + cur += sizeof(uint32_t); + + // plugin version + int len = pluginVersion.length(); + memcpy(response + cur, pluginVersion.c_str(), len); + cur += strlen(pluginVersion.c_str()) + len; + + sock->SendTo(response, cur, &multicast_address); + } void MessageHandlers::HandleConn(const Message& msg) { @@ -342,10 +373,11 @@ namespace XPC } case 20: // Position { - float pos[3]; - pos[0] = values[i][2]; - pos[1] = values[i][3]; - pos[2] = values[i][4]; + // TODO: loss of precision here + double pos[3]; + pos[0] = (double)values[i][2]; + pos[1] = (double)values[i][3]; + pos[2] = (double)values[i][4]; DataManager::SetPosition(pos); break; } @@ -439,7 +471,7 @@ namespace XPC unsigned char aircraft = buffer[5]; // TODO(jason-watkins): Get proper printf specifier for unsigned char Log::FormatLine(LOG_TRACE, "GCTL", "Getting control information for aircraft %u", aircraft); - + float throttle[8]; unsigned char response[31] = "CTRL"; *((float*)(response + 5)) = DataManager::GetFloat(DREF_Elevator, aircraft); @@ -524,13 +556,14 @@ namespace XPC unsigned char response[34] = "POSI"; response[5] = (char)DataManager::GetInt(DREF_GearHandle, aircraft); + // TODO change lat/lon/h to double? *((float*)(response + 6)) = (float)DataManager::GetDouble(DREF_Latitude, aircraft); *((float*)(response + 10)) = (float)DataManager::GetDouble(DREF_Longitude, aircraft); *((float*)(response + 14)) = (float)DataManager::GetDouble(DREF_Elevation, aircraft); *((float*)(response + 18)) = DataManager::GetFloat(DREF_Pitch, aircraft); *((float*)(response + 22)) = DataManager::GetFloat(DREF_Roll, aircraft); *((float*)(response + 26)) = DataManager::GetFloat(DREF_HeadingTrue, aircraft); - + float gear[10]; DataManager::GetFloatArray(DREF_GearDeploy, gear, 10, aircraft); *((float*)(response + 30)) = gear[0]; @@ -545,18 +578,37 @@ namespace XPC const unsigned char* buffer = msg.GetBuffer(); const std::size_t size = msg.GetSize(); - if (size < 34) + + char aircraftNumber = buffer[5]; + float gear = *((float*)(buffer + 42)); + double posd[3]; + float orient[3]; + + if (size == 34) /* lat/lon/h as 32-bit float */ { - Log::FormatLine(LOG_ERROR, "POSI", "ERROR: Unexpected size: %i (Expected at least 34)", size); + posd[0] = *((float*)&buffer[6]); + posd[1] = *((float*)&buffer[10]); + posd[2] = *((float*)&buffer[14]); + memcpy(orient, buffer + 18, 12); + } + else if (size == 46) /* lat/lon/h as 64-bit double */ + { + memcpy(posd, buffer + 6, 3*8); + memcpy(orient, buffer + 30, 12); + } + else + { + Log::FormatLine(LOG_ERROR, "POSI", "ERROR: Unexpected size: %i (Expected 34 or 46)", size); return; } - char aircraftNumber = buffer[5]; - float gear = *((float*)(buffer + 30)); - float pos[3]; - float orient[3]; - memcpy(pos, buffer + 6, 12); - memcpy(orient, buffer + 18, 12); + /* convert float to double */ + DataManager::SetPosition(posd, aircraftNumber); + DataManager::SetOrientation(orient, aircraftNumber); + if (gear >= 0) + { + DataManager::SetGear(gear, true, aircraftNumber); + } if (aircraftNumber > 0) { @@ -569,13 +621,6 @@ namespace XPC DataManager::Set(DREF_PauseAI, ai, 0, 20); } } - - DataManager::SetPosition(pos, aircraftNumber); - DataManager::SetOrientation(orient, aircraftNumber); - if (gear != -1) - { - DataManager::SetGear(gear, true, aircraftNumber); - } } void MessageHandlers::HandleSimu(const Message& msg) @@ -583,13 +628,13 @@ namespace XPC // Update log Log::FormatLine(LOG_TRACE, "SIMU", "Message Received (Conn %i)", connection.id); - char v = msg.GetBuffer()[5]; - if (v < 0 || v > 2) + unsigned char v = msg.GetBuffer()[5]; + if (v < 0 || (v > 2 && v < 100) || (v > 119 && v < 200) || v > 219) { Log::FormatLine(LOG_ERROR, "SIMU", "ERROR: Invalid argument: %i", v); return; } - + int value[20]; if (v == 2) { @@ -599,6 +644,16 @@ namespace XPC value[i] = value[i] ? 0 : 1; } } + else if ((v >= 100) && (v < 120)) + { + DataManager::GetIntArray(DREF_Pause, value, 20); + value[v - 100] = 1; + } + else if ((v >= 200) && (v < 220)) + { + DataManager::GetIntArray(DREF_Pause, value, 20); + value[v - 200] = 0; + } else { for (int i = 0; i < 20; ++i) @@ -610,18 +665,27 @@ namespace XPC // Set DREF DataManager::Set(DREF_Pause, value, 20); - switch (v) + if (v == 0) { - case 0: - Log::WriteLine(LOG_INFO, "SIMU", "Simulation resumed"); - break; - case 1: - Log::WriteLine(LOG_INFO, "SIMU", "Simulation paused"); - break; - case 2: - Log::FormatLine(LOG_INFO, "SIMU", "Simulation switched to %i", value[0]); - break; + Log::WriteLine(LOG_INFO, "SIMU", "Simulation resumed for all a/c"); } + else if (v == 1) + { + Log::WriteLine(LOG_INFO, "SIMU", "Simulation paused for all a/c"); + } + else if (v == 2) + { + Log::FormatLine(LOG_INFO, "SIMU", "Simulation switched to %i for all a/c", value[0]); + } + else if ((v >= 100) && (v < 120)) + { + Log::FormatLine(LOG_INFO, "SIMU", "Simulation paused for a/c %i", (v-100)); + } + else if ((v >= 200) && (v < 220)) + { + Log::FormatLine(LOG_INFO, "SIMU", "Simulation resumed for a/c %i", (v-100)); + } + } void MessageHandlers::HandleText(const Message& msg) @@ -653,21 +717,111 @@ namespace XPC Log::WriteLine(LOG_INFO, "TEXT", "[TEXT] Text set"); } } - + void MessageHandlers::HandleView(const Message& msg) { // Update Log Log::FormatLine(LOG_TRACE, "VIEW", "Message Received(Conn %i)", connection.id); + int enable_camera_location = 0; + const std::size_t size = msg.GetSize(); - if (size != 9) + if (size == 9) { - Log::FormatLine(LOG_ERROR, "VIEW", "Error: Unexpected length. Message was %d bytes, expected 9.", size); + // default view switcher as before + } + else if (size == 37) + { + // Allow camera location control + enable_camera_location = 1; + } + else + { + Log::FormatLine(LOG_ERROR, "VIEW", "Error: Unexpected length. Message was %d bytes, expected 9 or 37.", size); return; } const unsigned char* buffer = msg.GetBuffer(); int type = *((int*)(buffer + 5)); XPLMCommandKeyStroke(type); + + if(type == 79 && enable_camera_location == 1) // runway camera view + { + static struct CameraProperties campos; + + campos.loc[0] = *(double*)(buffer+9); + campos.loc[1] = *(double*)(buffer+17); + campos.loc[2] = *(double*)(buffer+25); + campos.direction[0] = -998; + campos.direction[1] = -998; + campos.direction[2] = -998; + campos.zoom = *(float*)(buffer+33); + + Log::FormatLine(LOG_TRACE, "VIEW", "Cam pos %f %f %f zoom %f", campos.loc[0], campos.loc[1], campos.loc[2],campos.zoom); + + XPLMControlCamera(xplm_ControlCameraUntilViewChanges, CamFunc, &campos); + } + } + + int MessageHandlers::CamFunc( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon) + { + if (outCameraPosition && !inIsLosingControl) + { + struct CameraProperties* campos = (struct CameraProperties*)inRefcon; + + // camera position + double clat = campos->loc[0]; + double clon = campos->loc[1]; + double calt = campos->loc[2]; + + double cX, cY, cZ; + XPLMWorldToLocal(clat, clon, calt, &cX, &cY, &cZ); + + outCameraPosition->x = cX; + outCameraPosition->y = cY; + outCameraPosition->z = cZ; + +// Log::FormatLine(LOG_TRACE, "CAM", "Cam pos %f %f %f", clat, clon, calt); + + if(campos->direction[0] == -998) // calculate camera direction + { + // aircraft position + double x = XPC::DataManager::GetDouble(XPC::DREF_LocalX, 0); + double y = XPC::DataManager::GetDouble(XPC::DREF_LocalY, 0); + double z = XPC::DataManager::GetDouble(XPC::DREF_LocalZ, 0); + + // relative position vector cam to plane + double dx = x - cX; + double dy = y - cY; + double dz = z - cZ; + +// Log::FormatLine(LOG_TRACE, "CAM", "Cam vect %f %f %f", dx, dy, dz); + + double pi = 3.141592653589793; + + // horizontal distance + double dist = sqrt(dx*dx + dz*dz); + + outCameraPosition->pitch = atan2(dy, dist) * 180.0/pi; + + double angle = atan2(dz, dx) * 180.0/pi; // rel to pos right (pos X) + + outCameraPosition->heading = 90 + angle; // rel to north + +// Log::FormatLine(LOG_TRACE, "CAM", "Cam p %f hdg %f ", outCameraPosition->pitch, outCameraPosition->heading); + + outCameraPosition->roll = 0; + } + else + { + outCameraPosition->roll = campos->direction[0]; + outCameraPosition->pitch = campos->direction[1]; + outCameraPosition->heading = campos->direction[2]; + } + + outCameraPosition->zoom = campos->zoom; + } + + return 1; } void MessageHandlers::HandleWypt(const Message& msg) diff --git a/xpcPlugin/MessageHandlers.h b/xpcPlugin/MessageHandlers.h index 3a48007..a065c96 100644 --- a/xpcPlugin/MessageHandlers.h +++ b/xpcPlugin/MessageHandlers.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. #ifndef XPCPLUGIN_MESSAGEHANDLERS_H_ #define XPCPLUGIN_MESSAGEHANDLERS_H_ @@ -7,6 +7,9 @@ #include #include +#include "XPLMCamera.h" + + namespace XPC { /// A function that handles a message. @@ -26,15 +29,17 @@ namespace XPC /// socket. /// /// \details After a message is read, HandleMessage analyzes the sender's network address - /// to determine whether the sender is a new client. It then either loads - /// connection details for an existing client, or creates a new connection record - /// for new clients. Finally, the message handler checks the message type and - /// dispatches the message to the appropriate handler. + /// to determine whether the sender is a new client. It then either loads + /// connection details for an existing client, or creates a new connection record + /// for new clients. Finally, the message handler checks the message type and + /// dispatches the message to the appropriate handler. /// \param msg The message to be processed. static void HandleMessage(Message& msg); /// Sets the socket that message handlers use to send responses. static void SetSocket(UDPSocket* socket); + + static void SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion); private: // One handler per message type. Message types are descripbed on the @@ -54,6 +59,14 @@ namespace XPC static void HandleXPlaneData(const Message& msg); static void HandleUnknown(const Message& msg); + + static int CamFunc( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon); + + struct CameraProperties{ + double loc[3]; + float direction[3]; + float zoom; + }; typedef struct { diff --git a/xpcPlugin/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp b/xpcPlugin/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp index c2b9c1d..5fe6218 100755 --- a/xpcPlugin/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp +++ b/xpcPlugin/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp @@ -42,7 +42,7 @@ void XPCBroadcaster::RemoveListener( } void XPCBroadcaster::BroadcastMessage( - long inMessage, + int inMessage, void * inParam) { ListenerVector::iterator iter; diff --git a/xpcPlugin/SDK/CHeaders/Wrappers/XPCBroadcaster.h b/xpcPlugin/SDK/CHeaders/Wrappers/XPCBroadcaster.h index 382c3f9..8f34a05 100755 --- a/xpcPlugin/SDK/CHeaders/Wrappers/XPCBroadcaster.h +++ b/xpcPlugin/SDK/CHeaders/Wrappers/XPCBroadcaster.h @@ -20,7 +20,7 @@ public: protected: void BroadcastMessage( - long inMessage, + int inMessage, void * inParam=0); private: diff --git a/xpcPlugin/SDK/CHeaders/Wrappers/XPCListener.h b/xpcPlugin/SDK/CHeaders/Wrappers/XPCListener.h index 02d5bea..dbdd2a0 100755 --- a/xpcPlugin/SDK/CHeaders/Wrappers/XPCListener.h +++ b/xpcPlugin/SDK/CHeaders/Wrappers/XPCListener.h @@ -14,7 +14,7 @@ public: virtual ~XPCListener(); virtual void ListenToMessage( - long inMessage, + int inMessage, void * inParam)=0; private: diff --git a/xpcPlugin/SDK/CHeaders/Wrappers/XPCProcessing.cpp b/xpcPlugin/SDK/CHeaders/Wrappers/XPCProcessing.cpp index bb8ebc3..352c05f 100755 --- a/xpcPlugin/SDK/CHeaders/Wrappers/XPCProcessing.cpp +++ b/xpcPlugin/SDK/CHeaders/Wrappers/XPCProcessing.cpp @@ -21,7 +21,7 @@ void XPCProcess::StartProcessTime(float inSeconds) FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); } -void XPCProcess::StartProcessCycles(long inCycles) +void XPCProcess::StartProcessCycles(int inCycles) { mCallbackTime = -inCycles; if (!mInCallback) diff --git a/xpcPlugin/SDK/CHeaders/Wrappers/XPCProcessing.h b/xpcPlugin/SDK/CHeaders/Wrappers/XPCProcessing.h index 7d21c4f..cd735e5 100755 --- a/xpcPlugin/SDK/CHeaders/Wrappers/XPCProcessing.h +++ b/xpcPlugin/SDK/CHeaders/Wrappers/XPCProcessing.h @@ -10,7 +10,7 @@ public: virtual ~XPCProcess(); void StartProcessTime(float inSeconds); - void StartProcessCycles(long inCycles); + void StartProcessCycles(int inCycles); void StopProcess(void); virtual void DoProcessing( diff --git a/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidget.cpp b/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidget.cpp index dcb7793..8ef8aa3 100755 --- a/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidget.cpp +++ b/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidget.cpp @@ -22,7 +22,7 @@ XPCWidget::XPCWidget( inIsRoot ? NULL : inParent, inClass); - XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); + XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); XPAddWidgetCallback(mWidget, WidgetCallback); } @@ -33,7 +33,7 @@ XPCWidget::XPCWidget( mOwnsChildren(false), mOwnsWidget(inOwnsWidget) { - XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); + XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); XPAddWidgetCallback(mWidget, WidgetCallback); } @@ -95,8 +95,8 @@ void XPCWidget::RemoveAttachment( int XPCWidget::HandleWidgetMessage( XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2) + intptr_t inParam1, + intptr_t inParam2) { return 0; } @@ -104,8 +104,8 @@ int XPCWidget::HandleWidgetMessage( int XPCWidget::WidgetCallback( XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2) + intptr_t inParam1, + intptr_t inParam2) { XPCWidget * me = reinterpret_cast(XPGetWidgetProperty(inWidget, xpProperty_Object, NULL)); if (me == NULL) diff --git a/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidget.h b/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidget.h index 6ce6a22..788b56a 100755 --- a/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidget.h +++ b/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidget.h @@ -14,8 +14,8 @@ public: XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2)=0; + intptr_t inParam1, + intptr_t inParam2)=0; }; @@ -56,16 +56,16 @@ public: virtual int HandleWidgetMessage( XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2); + intptr_t inParam1, + intptr_t inParam2); private: static int WidgetCallback( XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2); + intptr_t inParam1, + intptr_t inParam2); typedef std::pair AttachmentInfo; typedef std::vector AttachmentVector; diff --git a/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp b/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp index 3e13775..d87f105 100755 --- a/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp +++ b/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp @@ -22,8 +22,8 @@ int XPCKeyFilterAttachment::HandleWidgetMessage( XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2) + intptr_t inParam1, + intptr_t inParam2) { if (inMessage == xpMsg_KeyPress) { @@ -42,7 +42,7 @@ int XPCKeyFilterAttachment::HandleWidgetMessage( XPCKeyMessageAttachment::XPCKeyMessageAttachment( char inKey, - long inMessage, + int inMessage, void * inParam, bool inConsume, bool inVkey, @@ -62,8 +62,8 @@ int XPCKeyMessageAttachment::HandleWidgetMessage( XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2) + intptr_t inParam1, + intptr_t inParam2) { if (inMessage == xpMsg_KeyPress) { @@ -81,7 +81,7 @@ int XPCKeyMessageAttachment::HandleWidgetMessage( XPCPushButtonMessageAttachment::XPCPushButtonMessageAttachment( XPWidgetID inWidget, - long inMessage, + int inMessage, void * inParam, XPCListener * inListener) : mMsg(inMessage), mParam(inParam), mWidget(inWidget) @@ -98,8 +98,8 @@ int XPCPushButtonMessageAttachment::HandleWidgetMessage( XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2) + intptr_t inParam1, + intptr_t inParam2) { if ((inMessage == xpMsg_PushButtonPressed) && ((XPWidgetID) inParam1 == mWidget)) { @@ -117,7 +117,7 @@ int XPCPushButtonMessageAttachment::HandleWidgetMessage( XPCSliderMessageAttachment::XPCSliderMessageAttachment( XPWidgetID inWidget, - long inMessage, + int inMessage, void * inParam, XPCListener * inListener) : mMsg(inMessage), mParam(inParam), mWidget(inWidget) @@ -134,8 +134,8 @@ int XPCSliderMessageAttachment::HandleWidgetMessage( XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2) + intptr_t inParam1, + intptr_t inParam2) { if ((inMessage == xpMsg_ScrollBarSliderPositionChanged) && ((XPWidgetID) inParam1 == mWidget)) { @@ -149,7 +149,7 @@ int XPCSliderMessageAttachment::HandleWidgetMessage( XPCCloseButtonMessageAttachment::XPCCloseButtonMessageAttachment( XPWidgetID inWidget, - long inMessage, + int inMessage, void * inParam, XPCListener * inListener) : mMsg(inMessage), mParam(inParam), mWidget(inWidget) @@ -166,8 +166,8 @@ int XPCCloseButtonMessageAttachment::HandleWidgetMessage( XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2) + intptr_t inParam1, + intptr_t inParam2) { if ((inMessage == xpMessage_CloseButtonPushed) && ((XPWidgetID) inParam1 == mWidget)) { @@ -190,8 +190,8 @@ int XPCTabGroupAttachment::HandleWidgetMessage( XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2) + intptr_t inParam1, + intptr_t inParam2) { if ((inMessage == xpMsg_KeyPress) && (KEY_CHAR(inParam1) == XPLM_KEY_TAB) && ((KEY_FLAGS(inParam1) & xplm_UpFlag) == 0)) @@ -199,7 +199,7 @@ int XPCTabGroupAttachment::HandleWidgetMessage( bool backwards = (KEY_FLAGS(inParam1) & xplm_ShiftFlag) != 0; std::vector widgets; XPCGetOrderedSubWidgets(inWidget, widgets); - long n, index = 0; + int n, index = 0; XPWidgetID focusWidget = XPGetWidgetWithFocus(); std::vector::iterator iter = std::find(widgets.begin(), widgets.end(), focusWidget); if (iter != widgets.end()) @@ -254,8 +254,8 @@ static void XPCGetOrderedSubWidgets( std::vector& outChildren) { outChildren.clear(); - long count = XPCountChildWidgets(inWidget); - for (long n = 0; n < count; ++n) + int count = XPCountChildWidgets(inWidget); + for (int n = 0; n < count; ++n) { XPWidgetID child = XPGetNthChildWidget(inWidget, n); outChildren.push_back(child); diff --git a/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h b/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h index a0a82d9..91fb587 100755 --- a/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h +++ b/xpcPlugin/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h @@ -18,8 +18,8 @@ public: XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2); + intptr_t inParam1, + intptr_t inParam2); private: @@ -34,7 +34,7 @@ public: XPCKeyMessageAttachment( char inKey, - long inMessage, + int inMessage, void * inParam, bool inConsume, bool inVkey, @@ -45,14 +45,14 @@ public: XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2); + intptr_t inParam1, + intptr_t inParam2); private: char mKey; bool mVkey; - long mMsg; + int mMsg; void * mParam; bool mConsume; @@ -63,7 +63,7 @@ public: XPCPushButtonMessageAttachment( XPWidgetID inWidget, - long inMessage, + int inMessage, void * inParam, XPCListener * inListener); virtual ~XPCPushButtonMessageAttachment(); @@ -72,12 +72,12 @@ public: XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2); + intptr_t inParam1, + intptr_t inParam2); private: XPWidgetID mWidget; - long mMsg; + int mMsg; void * mParam; }; @@ -86,7 +86,7 @@ public: XPCSliderMessageAttachment( XPWidgetID inWidget, - long inMessage, + int inMessage, void * inParam, XPCListener * inListener); virtual ~XPCSliderMessageAttachment(); @@ -95,12 +95,12 @@ public: XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2); + intptr_t inParam1, + intptr_t inParam2); private: XPWidgetID mWidget; - long mMsg; + int mMsg; void * mParam; }; @@ -110,7 +110,7 @@ public: XPCCloseButtonMessageAttachment( XPWidgetID inWidget, - long inMessage, + int inMessage, void * inParam, XPCListener * inListener); virtual ~XPCCloseButtonMessageAttachment(); @@ -119,12 +119,12 @@ public: XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2); + intptr_t inParam1, + intptr_t inParam2); private: XPWidgetID mWidget; - long mMsg; + int mMsg; void * mParam; }; @@ -138,8 +138,8 @@ public: XPCWidget * inObject, XPWidgetMessage inMessage, XPWidgetID inWidget, - long inParam1, - long inParam2); + intptr_t inParam1, + intptr_t inParam2); }; diff --git a/xpcPlugin/SDK/CHeaders/XPLM/XPLMDefs.h b/xpcPlugin/SDK/CHeaders/XPLM/XPLMDefs.h index acd5f2c..e1909c4 100755 --- a/xpcPlugin/SDK/CHeaders/XPLM/XPLMDefs.h +++ b/xpcPlugin/SDK/CHeaders/XPLM/XPLMDefs.h @@ -27,7 +27,7 @@ extern "C" { #endif -#ifdef _WIN32 +#if IBM #include #else #include @@ -49,7 +49,7 @@ extern "C" { #ifdef __cplusplus - #ifdef APL + #if APL #if __GNUC__ >= 4 #define PLUGIN_API extern "C" __attribute__((visibility("default"))) #elif __MACH__ @@ -57,16 +57,16 @@ extern "C" { #else #define PLUGIN_API extern "C" __declspec(dllexport) #endif - #endif - #ifdef _WIN32 + #elif IBM #define PLUGIN_API extern "C" __declspec(dllexport) - #endif - #ifdef LIN + #elif LIN #if __GNUC__ >= 4 #define PLUGIN_API extern "C" __attribute__((visibility("default"))) #else #define PLUGIN_API extern "C" #endif + #else + #error "Platform not defined!" #endif #else #if APL @@ -90,7 +90,7 @@ extern "C" { #endif #endif -#ifdef APL +#if APL #if XPLM #if __GNUC__ >= 4 #define XPLM_API __attribute__((visibility("default"))) @@ -102,15 +102,13 @@ extern "C" { #else #define XPLM_API #endif -#endif -#ifdef _WIN32 +#elif IBM #if XPLM #define XPLM_API __declspec(dllexport) #else #define XPLM_API __declspec(dllimport) #endif -#endif -#ifdef LIN +#elif LIN #if XPLM #if __GNUC__ >= 4 #define XPLM_API __attribute__((visibility("default"))) @@ -120,6 +118,8 @@ extern "C" { #else #define XPLM_API #endif +#else + #error "Platform not defined!" #endif /*************************************************************************** diff --git a/xpcPlugin/SDK/README.txt b/xpcPlugin/SDK/README.txt index 2773a35..2316eb5 100755 --- a/xpcPlugin/SDK/README.txt +++ b/xpcPlugin/SDK/README.txt @@ -51,6 +51,11 @@ Mach-O if you want to use 2.0 features. This section contains per-release notes for the history of the X-Plane SDK. +X-Plane SDK Release 2.1.3 11/14/13 + +Fixed XPC Wrappers to use int and intptr_t instead of long. This fixes +crashes for plugins on 64-bit Windows. + X-Plane SDK Release 2.1.2 RC2 1/15/13 Removed headers from frameworks, as they don't work; updated README. diff --git a/xpcPlugin/Timer.cpp b/xpcPlugin/Timer.cpp new file mode 100644 index 0000000..db90545 --- /dev/null +++ b/xpcPlugin/Timer.cpp @@ -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(); + } + } +} diff --git a/xpcPlugin/Timer.h b/xpcPlugin/Timer.h new file mode 100644 index 0000000..b2269d4 --- /dev/null +++ b/xpcPlugin/Timer.h @@ -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 +#include +#include +#include +#include +#include + +namespace XPC { + class Timer + { + std::atomic_flag running; + std::thread th; + + public: + + using Callback = std::function; + + void start(const std::chrono::milliseconds, const Callback &callback); + + void stop(); + }; +} + +#endif /* Timer_hpp */ diff --git a/xpcPlugin/UDPSocket.cpp b/xpcPlugin/UDPSocket.cpp index 8f4577f..6eaf3e1 100644 --- a/xpcPlugin/UDPSocket.cpp +++ b/xpcPlugin/UDPSocket.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. #include "Log.h" #include "UDPSocket.h" @@ -138,6 +138,18 @@ namespace XPC Log::FormatLine(LOG_INFO, tag, "Send succeeded. (remote: %s)", GetHost(remote).c_str()); } } + + sockaddr UDPSocket::GetAddr(std::string address, unsigned short port) + { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(address.c_str()); + addr.sin_port = htons(port); + + sockaddr* sa = reinterpret_cast(&addr); + return *sa; + } std::string UDPSocket::GetHost(sockaddr* sa) { diff --git a/xpcPlugin/UDPSocket.h b/xpcPlugin/UDPSocket.h index 6a4b785..a1ee920 100644 --- a/xpcPlugin/UDPSocket.h +++ b/xpcPlugin/UDPSocket.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. #ifndef XPCPLUGIN_SOCKET_H_ #define XPCPLUGIN_SOCKET_H_ @@ -56,12 +56,14 @@ namespace XPC /// \param len The number of bytes to send. /// \param remote The destination socket. void SendTo(const unsigned char* buffer, std::size_t len, sockaddr* remote) const; - + /// Gets a string containing the IP address and port contained in the given sockaddr. /// /// \param addr The socket address to parse. /// \returns A string representation of the socket address. static std::string GetHost(sockaddr* addr); + + static sockaddr GetAddr(std::string address, unsigned short port); private: #ifdef _WIN32 SOCKET sock; diff --git a/xpcPlugin/XPCPlugin.cpp b/xpcPlugin/XPCPlugin.cpp index e02f1d2..b679f86 100755 --- a/xpcPlugin/XPCPlugin.cpp +++ b/xpcPlugin/XPCPlugin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2017 United States Government as represented by the Administrator of the +// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the // National Aeronautics and Space Administration. All Rights Reserved. // // DISCLAIMERS @@ -60,12 +60,16 @@ #include "Log.h" #include "MessageHandlers.h" #include "UDPSocket.h" +#include "Timer.h" // XPLM Includes #include "XPLMProcessing.h" +#include "XPLMUtilities.h" // System Includes +#include #include +#include #ifdef __APPLE__ #include #endif @@ -73,7 +77,12 @@ #define RECVPORT 49009 // Port that the plugin receives commands on #define OPS_PER_CYCLE 20 // Max Number of operations per cycle +#define XPC_PLUGIN_VERSION "1.3-rc.1" + +using namespace std; + XPC::UDPSocket* sock = NULL; +XPC::Timer* timer = NULL; double start; double lap; @@ -89,12 +98,12 @@ static float XPCFlightLoopCallback(float inElapsedSinceLastCall, float inElapsed PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc) { - strcpy(outName, "X-Plane Connect [Version 1.2.1]"); + strcpy(outName, "X-Plane Connect [Version 1.3-rc.1]"); strcpy(outSig, "NASA.XPlaneConnect"); - strcpy(outDesc, "X Plane Communications Toolbox\nCopyright (c) 2013-2017 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved."); + strcpy(outDesc, "X Plane Communications Toolbox\nCopyright (c) 2013-2018 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved."); #if (__APPLE__) - if ( abs(timeConvert) <= 1e-9 ) // is about 0 + if ( timeConvert <= 1e-9 ) // is about 0 { mach_timebase_info_data_t timeBase; (void)mach_timebase_info(&timeBase); @@ -103,7 +112,7 @@ PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc) 1000000000.0; } #endif - XPC::Log::Initialize("1.2.1"); + XPC::Log::Initialize(XPC_PLUGIN_VERSION); XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Start"); XPC::DataManager::Initialize(); @@ -131,12 +140,18 @@ PLUGIN_API void XPluginDisable(void) XPC::Drawing::ClearWaypoints(); XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Disabled, sockets closed"); + + timer->stop(); + delete timer; + timer = NULL; } PLUGIN_API int XPluginEnable(void) { // Open sockets sock = new XPC::UDPSocket(RECVPORT); + timer = new XPC::Timer(); + XPC::MessageHandlers::SetSocket(sock); XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Enabled, sockets opened"); @@ -145,11 +160,20 @@ PLUGIN_API int XPluginEnable(void) XPC::Log::FormatLine(LOG_INFO, "EXEC", "Benchmarking Enabled (Verbosity: %i)", benchmarkingSwitch); } XPC::Log::FormatLine(LOG_INFO, "EXEC", "Debug Logging Enabled (Verbosity: %i)", LOG_LEVEL); - + float interval = -1; // Call every frame void* refcon = NULL; // Don't pass anything to the callback directly XPLMRegisterFlightLoopCallback(XPCFlightLoopCallback, interval, refcon); + + int xpVer; + XPLMGetVersions(&xpVer, NULL, NULL); + + timer->start(chrono::milliseconds(1000), [=]{ + XPC::MessageHandlers::SendBeacon(XPC_PLUGIN_VERSION, RECVPORT, xpVer); + }); + + return 1; } diff --git a/xpcPlugin/XPlaneConnect/64/lin.xpl b/xpcPlugin/XPlaneConnect/64/lin.xpl deleted file mode 100755 index b827500..0000000 Binary files a/xpcPlugin/XPlaneConnect/64/lin.xpl and /dev/null differ diff --git a/xpcPlugin/XPlaneConnect/64/win.xpl b/xpcPlugin/XPlaneConnect/64/win.xpl deleted file mode 100644 index d706dc7..0000000 Binary files a/xpcPlugin/XPlaneConnect/64/win.xpl and /dev/null differ diff --git a/xpcPlugin/XPlaneConnect/lin.xpl b/xpcPlugin/XPlaneConnect/lin.xpl deleted file mode 100755 index eeb2255..0000000 Binary files a/xpcPlugin/XPlaneConnect/lin.xpl and /dev/null differ diff --git a/xpcPlugin/XPlaneConnect/mac.xpl b/xpcPlugin/XPlaneConnect/mac.xpl deleted file mode 100755 index 398019a..0000000 Binary files a/xpcPlugin/XPlaneConnect/mac.xpl and /dev/null differ diff --git a/xpcPlugin/XPlaneConnect/win.xpl b/xpcPlugin/XPlaneConnect/win.xpl deleted file mode 100644 index 20d6094..0000000 Binary files a/xpcPlugin/XPlaneConnect/win.xpl and /dev/null differ diff --git a/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj b/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj index a7ed423..4a4fe23 100755 --- a/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj +++ b/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */; }; BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */; }; BE8361EF18C5591C00E9C923 /* mac.xpl in CopyFiles */ = {isa = PBXBuildFile; fileRef = D607B19909A556E400699BC3 /* mac.xpl */; }; BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */; }; @@ -36,6 +37,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 3D0F44CC21C6D3E7008A0655 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = ""; }; + 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = ""; }; 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 = ""; }; BEABAD2C1AE041A3007BA7DA /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataManager.h; sourceTree = ""; }; @@ -76,6 +79,7 @@ AC4E46B809C2E0B3006B7E1B /* src */ = { isa = PBXGroup; children = ( + 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */, BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */, BEDC620218EDF1A7005DB364 /* xplaneConnect.c */, BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */, @@ -91,6 +95,7 @@ BE953E0B1AEB183400CE4A8C /* inc */ = { isa = PBXGroup; children = ( + 3D0F44CC21C6D3E7008A0655 /* Timer.h */, BEDC620318EDF1A7005DB364 /* xplaneConnect.h */, BEABAD2C1AE041A3007BA7DA /* DataManager.h */, BEABAD301AE041A3007BA7DA /* Drawing.h */, @@ -190,6 +195,7 @@ BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */, BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */, BEABAD391AE041A3007BA7DA /* Drawing.cpp in Sources */, + 3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */, BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */, BEABAD3F1AE0498D007BA7DA /* UDPSocket.cpp in Sources */, ); @@ -298,11 +304,14 @@ D607B19C09A556E400699BC3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ARCHS = "$(ARCHS_STANDARD)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_ENABLE_MODULES = YES; CLANG_LINK_OBJC_RUNTIME = NO; CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; + CONFIGURATION_BUILD_DIR = ./XPlaneConnect/; CURRENT_PROJECT_VERSION = 0.24; GCC_ENABLE_OBJC_EXCEPTIONS = NO; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO; @@ -337,11 +346,14 @@ D607B19D09A556E400699BC3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ARCHS = "$(ARCHS_STANDARD)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_ENABLE_MODULES = YES; CLANG_LINK_OBJC_RUNTIME = NO; CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; + CONFIGURATION_BUILD_DIR = ./XPlaneConnect/; CURRENT_PROJECT_VERSION = 0.24; GCC_ENABLE_OBJC_EXCEPTIONS = NO; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = NO; @@ -365,9 +377,7 @@ "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/xplaneConnect-asdjuezcjkhojuewbyxhyhabxfwc/Build/Products/Debug", ); MACH_O_TYPE = mh_bundle; - ONLY_ACTIVE_ARCH = NO; - PRODUCT_NAME = mac; SDKROOT = macosx; STRIP_INSTALLED_PRODUCT = YES; diff --git a/xpcPlugin/xpcPlugin/xpcPlugin.sln b/xpcPlugin/xpcPlugin/xpcPlugin.sln index e34eb3d..c734f1b 100644 --- a/xpcPlugin/xpcPlugin/xpcPlugin.sln +++ b/xpcPlugin/xpcPlugin/xpcPlugin.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 2015 +VisualStudioVersion = 15.0.28307.168 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xpcPlugin", "xpcPlugin.vcxproj", "{6AEF5D28-2701-44FF-AE10-1DEF07C5CAEA}" EndProject diff --git a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj index 2f48de6..d46ed92 100644 --- a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj +++ b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -28,25 +28,25 @@ DynamicLibrary true - v140 + $(DefaultPlatformToolset) MultiByte DynamicLibrary true - v140 + $(DefaultPlatformToolset) MultiByte DynamicLibrary true - v140 + $(DefaultPlatformToolset) MultiByte DynamicLibrary true - v140 + $(DefaultPlatformToolset) MultiByte @@ -121,7 +121,7 @@ NotUsing - EnableAllWarnings + Level3 Full IBM=1;XPLM200;%(PreprocessorDefinitions) OldStyle @@ -171,7 +171,7 @@ NotUsing - EnableAllWarnings + Level3 Full IBM=1;XPLM200;%(PreprocessorDefinitions) @@ -206,6 +206,7 @@ + @@ -214,6 +215,7 @@ +