diff --git a/C/monitorExample/main.c b/C/monitorExample/main.c index e6d2e62..e0af291 100644 --- a/C/monitorExample/main.c +++ b/C/monitorExample/main.c @@ -26,6 +26,8 @@ #include #include "stdio.h" +struct timeval tv; + #ifdef WIN32 HANDLE hStdIn = NULL; INPUT_RECORD buffer; @@ -51,7 +53,6 @@ int waitForInput() #else int fdstdin = 0; fd_set fds; -struct timeval tv; int waitForInput() { @@ -67,10 +68,10 @@ int main(void) { XPCSocket client = openUDP("127.0.0.1"); const int aircraftNum = 0; - tv.tv_usec = 100 * 1000; + tv.tv_usec = 100 * 1000; while (1) { - float posi[7]; // FIXME: change this to the 64-bit lat/lon/h + double posi[7]; int result = getPOSI(client, posi, aircraftNum); if (result < 0) // Error in getPOSI { diff --git a/C/playbackExample/src/playback.c b/C/playbackExample/src/playback.c index 4d2e594..dd92e45 100644 --- a/C/playbackExample/src/playback.c +++ b/C/playbackExample/src/playback.c @@ -65,7 +65,7 @@ void record(char* path, int interval, int duration) XPCSocket sock = openUDP("127.0.0.1"); for (int i = 0; i < count; ++i) { - float posi[7]; + double posi[7]; int result = getPOSI(sock, posi, 0); playbackSleep(interval); if (result < 0) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index ed984fb..9425c94 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -387,7 +387,7 @@ int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], { // Setup command // Max size is technically unlimited. - unsigned char buffer[65536] = "DREF"; + char buffer[65536] = "DREF"; int pos = 5; int i; // Iterator for (i = 0; i < count; ++i) @@ -433,7 +433,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) // Setup command // 6 byte header + potentially 255 drefs, each 256 chars long. // Easiest to just round to an even 2^16. - unsigned char buffer[65536] = "GETD"; + char buffer[65536] = "GETD"; buffer[5] = count; int len = 6; int i; // iterator @@ -460,7 +460,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int sizes[]) { - unsigned char buffer[65536]; + char buffer[65536]; int result = readUDP(sock, buffer, 65536); if (result < 0) @@ -537,10 +537,10 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char /*****************************************************************************/ /**** POSI functions ****/ /*****************************************************************************/ -int getPOSI(XPCSocket sock, float values[7], char ac) +int getPOSI(XPCSocket sock, double values[7], char ac) { // Setup send command - unsigned char buffer[6] = "GETP"; + char buffer[6] = "GETP"; buffer[5] = ac; // Send command @@ -551,22 +551,41 @@ int getPOSI(XPCSocket sock, float values[7], char ac) } // Get response - unsigned char readBuffer[34]; - int readResult = readUDP(sock, readBuffer, 34); + char readBuffer[46]; + float f[7]; + int readResult = readUDP(sock, readBuffer, 46); + + // Copy response into values if (readResult < 0) { printError("getPOSI", "Failed to read response."); return -2; } - if (readResult != 34) + else if (readResult == 34) /* lat/lon/h as 32-bit float */ + { + memcpy(f, readBuffer + 6, 7 * sizeof(float)); + values[0] = (double)f[0]; + values[1] = (double)f[1]; + values[2] = (double)f[2]; + values[3] = (double)f[3]; + values[4] = (double)f[4]; + values[5] = (double)f[5]; + values[6] = (double)f[6]; + } + else if (readResult == 46) /* lat/lon/h as 64-bit double */ + { + memcpy(values, readBuffer + 6, 3 * sizeof(double)); + memcpy(f, readBuffer + 30, 4 * sizeof(float)); + values[3] = (double)f[0]; + values[4] = (double)f[1]; + values[5] = (double)f[2]; + values[6] = (double)f[3]; + } + else { 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; } @@ -585,7 +604,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) } // Setup command - unsigned char buffer[46] = "POSI"; + char buffer[46] = "POSI"; buffer[4] = 0xff; //Placeholder for message length buffer[5] = ac; int i; // iterator @@ -627,7 +646,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) int getCTRL(XPCSocket sock, float values[7], char ac) { // Setup send command - unsigned char buffer[6] = "GETC"; + char buffer[6] = "GETC"; buffer[5] = ac; // Send command @@ -638,7 +657,7 @@ int getCTRL(XPCSocket sock, float values[7], char ac) } // Get response - unsigned char readBuffer[31]; + char readBuffer[31]; int readResult = readUDP(sock, readBuffer, 31); if (readResult < 0) { @@ -675,7 +694,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac) // Setup Command // 5 byte header + 5 float values * 4 + 2 byte values - unsigned char buffer[31] = "CTRL"; + char buffer[31] = "CTRL"; int cur = 5; int i; // iterator for (i = 0; i < 6; i++) diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 8cfb06f..4a62b17 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -201,8 +201,9 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char /// \param sock The socket used to send the command and receive the response. /// \param values An array to store the position information returned by the /// plugin. The format of values is [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear] +/// \param ac The aircraft number to get the position of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. -int getPOSI(XPCSocket sock, float values[7], char ac); +int getPOSI(XPCSocket sock, double values[7], char ac); /// Sets the position and orientation of the specified aircraft. /// @@ -211,7 +212,7 @@ int getPOSI(XPCSocket sock, float values[7], char ac); /// [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]. If less than 7 values are specified, /// the unspecified values will be left unchanged. /// \param size The number of elements in values. -/// \param ac The aircraft number to set the position of. 0 for the player aircraft. +/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int sendPOSI(XPCSocket sock, double values[], int size, char ac); @@ -223,7 +224,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac); /// \param values An array to store the position information returned by the /// plugin. The format of values is [Elevator, Aileron, Rudder, /// Throttle, Gear, Flaps, Speed Brakes] -/// \param ac The aircraft to set the control surfaces of. 0 is the main/player aircraft. +/// \param ac The aircraft to set the control surfaces of. 0 is the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int getCTRL(XPCSocket sock, float values[7], char ac); @@ -234,7 +235,7 @@ int getCTRL(XPCSocket sock, float values[7], char ac); /// [Elevator, Aileron, Rudder, Throttle, Gear, Flaps, Speed Brakes]. If less than /// 6 values are specified, the unspecified values will be left unchanged. /// \param size The number of elements in values. -/// \param ac The aircraft number to set the control surfaces of. 0 for the player aircraft. +/// \param ac The aircraft to set the control surfaces of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int sendCTRL(XPCSocket sock, float values[], int size, char ac); @@ -246,7 +247,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac); /// \param msg The message to print of the screen. /// \param x The distance in pixels from the left edge of the screen to print the text. /// \param y The distance in pixels from the bottom edge of the screen to print the top line of text. -/// \returns 0 if successful, otherwise a negative value. +/// \returns 0 if successful, otherwise a negative value. int sendTEXT(XPCSocket sock, char* msg, int x, int y); /// Sets the camera view in X-Plane. diff --git a/Python3/src/basicExample.py b/Python3/src/basicExample.py index f381e5d..b42f2c1 100644 --- a/Python3/src/basicExample.py +++ b/Python3/src/basicExample.py @@ -2,8 +2,8 @@ from time import sleep import xpc def ex(): - print "X-Plane Connect example script" - print "Setting up simulation" + print("X-Plane Connect example script") + print("Setting up simulation") with xpc.XPlaneConnect() as client: # Verify connection try: @@ -11,24 +11,24 @@ def ex(): # will be raised. client.getDREF("sim/test/test_float") except: - print "Error establishing connection to X-Plane." - print "Exiting..." + print("Error establishing connection to X-Plane.") + print("Exiting...") return # Set position of the player aircraft - print "Setting position" + 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" + 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" + print("Setting orientation") data = [\ [18, 0, -998, 0, -998, -998, -998, -998, -998],\ [ 3, 130, 130, 130, 130, -998, -998, -998, -998],\ @@ -37,21 +37,21 @@ def ex(): client.sendDATA(data) # Set control surfaces and throttle of the player aircraft using sendCTRL - print "Setting controls" + print("Setting controls") ctrl = [0.0, 0.0, 0.0, 0.8] client.sendCTRL(ctrl) # Pause the sim - print "Pausing" + print("Pausing") client.pauseSim(True) sleep(2) # Toggle pause state to resume - print "Resuming" + print("Resuming") client.pauseSim(False) # Stow landing gear using a dataref - print "Stowing gear" + print("Stowing gear") gear_dref = "sim/cockpit/switches/gear_handle_status" client.sendDREF(gear_dref, 0) @@ -61,12 +61,12 @@ def ex(): # Make sure gear was stowed successfully gear_status = client.getDREF(gear_dref) if gear_status[0] == 0: - print "Gear stowed" + print("Gear stowed") else: - print "Error stowing gear" + print("Error stowing gear") - print "End of Python client example" - raw_input("Press any key to exit...") + print("End of Python client example") + 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 index c4cdb48..562ac53 100644 --- a/Python3/src/monitorExample.py +++ b/Python3/src/monitorExample.py @@ -8,8 +8,8 @@ def monitor(): 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]) + 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__": diff --git a/Python3/src/playbackExample.py b/Python3/src/playbackExample.py index dfa4f52..17eb2f1 100644 --- a/Python3/src/playbackExample.py +++ b/Python3/src/playbackExample.py @@ -5,78 +5,78 @@ def record(path, interval = 0.1, duration = 60): try: fd = open(path, "w") except: - print "Unable to open file." + print("Unable to open file.") return count = int(duration / interval) if count < 1: - print "duration is less than a single frame." + print("duration is less than a single frame.") return with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client: - print "Recording..." + 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" + print("Error reading position") continue sleep(interval); - print "Recording Complete" + print("Recording Complete") fd.close() def playback(path, interval): try: fd = open(path, "r") except: - print "Unable to open file." + print("Unable to open file.") return with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client: - print "Starting Playback..." + 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" + print("Error sending position") continue sleep(interval); - print "Playback Complete" + print("Playback Complete") fd.close() def printMenu(title, opts): - print "\n+---------------------------------------------- +" - print "| {0:42} |\n".format(title) - print "+---------------------------------------------- +" + 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: ")) + print("| {0:2}. {1:40} |".format(i + 1, opts[i])) + print("+---------------------------------------------- +") + return int(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." + 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): ")) + path = input("Enter save file path: ") + interval = float(input("Enter interval between frames (seconds): ")) + duration = float(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): ")) + path = input("Enter save file path: ") + interval = float(input("Enter interval between frames (seconds): ")) playback(path, interval) elif opt == 3: return; else: - print "Unrecognized option." + 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 index ddf2be9..9c85942 100644 --- a/Python3/src/xpc.py +++ b/Python3/src/xpc.py @@ -1,7 +1,6 @@ import socket import struct - class XPlaneConnect(object): """XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin.""" socket = None @@ -158,10 +157,13 @@ class XPlaneConnect(object): # Read response resultBuf = self.readUDP() - if len(resultBuf) != 34: + if len(resultBuf) == 34: + result = struct.unpack(b"<4sxBfffffff", resultBuf) + elif len(resultBuf) == 46: + result = struct.unpack(b"<4sxBdddffff", resultBuf) + else: raise ValueError("Unexpected response length.") - result = struct.unpack(b"<4sxBfffffff", resultBuf) if result[0] != b"POSI": raise ValueError("Unexpected header: " + result[0]) @@ -197,7 +199,10 @@ class XPlaneConnect(object): val = -998 if i < len(values): val = values[i] - buffer += struct.pack(b"= 0) { result = getDREFs(*sock, drefs, data, 7, sizes); @@ -66,19 +66,19 @@ int doGETCTest(float values[7], int ac, float expected[7]) return 0; } -int basicCTRLTest(char** drefs, int ac) +int basicCTRLTest(const char** drefs, int ac) { // Set control surfaces to known state. float CTRL[6] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F }; float expected[7] = { 0.0F, 0.0F, 0.0F, NAN, NAN, NAN, NAN }; - XPCSocket sock = openUDP(IP); - pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 + XPCSocket sock = openUDP(IP); + pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 int result = doCTRLTest(&sock, drefs, CTRL, 3, ac, expected); if (result < 0) { return -10000 + result; } - crossPlatformUSleep(SLEEP_AMOUNT); + crossPlatformUSleep(SLEEP_AMOUNT); // Test control surfaces and set other values to known state. expected[0] = CTRL[0] = 0.2F; @@ -92,19 +92,19 @@ int basicCTRLTest(char** drefs, int ac) { return -20000 + result; } - crossPlatformUSleep(SLEEP_AMOUNT); + crossPlatformUSleep(SLEEP_AMOUNT); // Test other values and verify control surfaces unchanged. expected[0] = CTRL[0] = 0.15F; expected[1] = CTRL[1] = 0.15F; expected[2] = CTRL[2] = 0.15F; expected[3] = CTRL[3] = 0.9F; - CTRL[4] = -998; + CTRL[4] = -998; CTRL[5] = -998; result = doCTRLTest(&sock, drefs, CTRL, 6, ac, expected); - pauseSim(sock, 0); - closeUDP(sock); + pauseSim(sock, 0); + closeUDP(sock); if (result < 0) { if (result == -1004) { @@ -112,12 +112,12 @@ int basicCTRLTest(char** drefs, int ac) } return -30000 + result; } - return 0; + return 0; } int testCTRL_Player() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit2/controls/yoke_pitch_ratio", "sim/cockpit2/controls/yoke_roll_ratio", @@ -132,7 +132,7 @@ int testCTRL_Player() int testCTRL_NonPlayer() { - char* drefs[] = + const char* drefs[] = { "sim/multiplayer/position/plane1_yolk_pitch", "sim/multiplayer/position/plane1_yolk_roll", @@ -147,7 +147,7 @@ int testCTRL_NonPlayer() int testCTRL_Speedbrakes() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit2/controls/yoke_pitch_ratio", "sim/cockpit2/controls/yoke_roll_ratio", @@ -161,8 +161,8 @@ int testCTRL_Speedbrakes() // Arm float CTRL[7] = { -998, -998, -998, -998, -998, -998, -0.5F }; float expected[7] = { NAN, NAN, NAN, NAN, NAN, NAN, -0.5F }; - XPCSocket sock = openUDP(IP); - pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 + XPCSocket sock = openUDP(IP); + pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 int result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected); if (result < 0) { @@ -180,13 +180,13 @@ int testCTRL_Speedbrakes() // Retract expected[6] = CTRL[6] = 0.0F; result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected); - pauseSim(sock, 0); - closeUDP(sock); + pauseSim(sock, 0); + closeUDP(sock); if (result < 0) { return -30000 + result; } - return 0; + return 0; } int testGETC() diff --git a/TestScripts/C Tests/DataTests.h b/TestScripts/C Tests/DataTests.h index 4fde0ab..233602c 100644 --- a/TestScripts/C Tests/DataTests.h +++ b/TestScripts/C Tests/DataTests.h @@ -10,7 +10,7 @@ int testDATA() { // Initialize int i, j; // Iterator - char* drefs[100] = + const char* drefs[100] = { "sim/aircraft/parts/acf_gear_deploy" }; diff --git a/TestScripts/C Tests/DrefTests.h b/TestScripts/C Tests/DrefTests.h index c64ce6d..586b408 100644 --- a/TestScripts/C Tests/DrefTests.h +++ b/TestScripts/C Tests/DrefTests.h @@ -6,7 +6,7 @@ #include "Test.h" #include "xplaneConnect.h" -int doGETDTest(char* drefs[], float* expected[], int count, int sizes[]) +int doGETDTest(const char* drefs[], float* expected[], int count, int sizes[]) { // Setup memory int* asizes = (int*)malloc(sizeof(int) * count); @@ -37,7 +37,7 @@ int doGETDTest(char* drefs[], float* expected[], int count, int sizes[]) return result; } -int doDREFTest(char* drefs[], float* values[], float* expected[], int count, int sizes[]) +int doDREFTest(const char* drefs[], float* values[], float* expected[], int count, int sizes[]) { // Setup memory int* asizes = (int*)malloc(sizeof(int) * count); @@ -74,7 +74,7 @@ int doDREFTest(char* drefs[], float* values[], float* expected[], int count, int int testGETD_Basic() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/autopilot/altitude", //float @@ -99,20 +99,20 @@ int testGETD_Basic() int testGETD_TestFloat() { - char* dref = "sim/test/test_float"; + const char* dref = "sim/test/test_float"; int size = 1; float* expected[1]; expected[0] = (float*)malloc(sizeof(float)); expected[0][0] = 0.0F; - int result = doGETDTest(&dref, &expected, 1, &size); + int result = doGETDTest(&dref, expected, 1, &size); free(expected[0]); return result; } int testGETD_Types() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/autopilot/altitude", //float @@ -173,7 +173,7 @@ int testGETD_Types() int testDREF() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/autopilot/altitude", //float diff --git a/TestScripts/C Tests/PosiTests.h b/TestScripts/C Tests/PosiTests.h index fc084ec..1b3983a 100644 --- a/TestScripts/C Tests/PosiTests.h +++ b/TestScripts/C Tests/PosiTests.h @@ -6,7 +6,7 @@ #include "Test.h" #include "xplaneConnect.h" -int doPOSITest(char* drefs[7], double values[], int size, int ac, double expected[7]) +int doPOSITest(const char* drefs[7], double values[], int size, int ac, double expected[7]) { float* data[7]; int sizes[7]; @@ -43,7 +43,7 @@ int doPOSITest(char* drefs[7], double values[], int size, int ac, double expecte int doGETPTest(double values[7], int ac, double expected[7]) { // Execute Test - float actual[7]; + double actual[7]; XPCSocket sock = openUDP(IP); int result = sendPOSI(sock, values, 7, ac); if (result >= 0) @@ -67,7 +67,7 @@ int doGETPTest(double values[7], int ac, double expected[7]) return 0; } -int basicPOSITest(char** drefs, int ac) +int basicPOSITest(const char** drefs, int ac) { // Set psoition and initial orientation double POSI[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 }; @@ -110,12 +110,12 @@ int basicPOSITest(char** drefs, int ac) { return -20000 + result; } - return 0; + return 0; } int testPOSI_Player() { - char* drefs[] = + const char* drefs[] = { "sim/flightmodel/position/latitude", "sim/flightmodel/position/longitude", @@ -130,7 +130,7 @@ int testPOSI_Player() int testPOSI_NonPlayer() { - char* drefs[] = + const char* drefs[] = { "sim/multiplayer/position/plane1_lat", "sim/multiplayer/position/plane1_lon", diff --git a/TestScripts/Python3 Tests/Tests.py b/TestScripts/Python3 Tests/Tests.py new file mode 100644 index 0000000..41e2bd4 --- /dev/null +++ b/TestScripts/Python3 Tests/Tests.py @@ -0,0 +1,434 @@ +import random +import unittest +import importlib +import time + +from importlib.machinery import SourceFileLoader +xpc = SourceFileLoader('xpc', '../../Python3/src/xpc.py').load_module() + +class XPCTests(unittest.TestCase): + """Tests the functionality of the XPlaneConnect class.""" + + def test_init(self): + try: + client = xpc.XPlaneConnect() + except: + self.fail("Default constructor failed.") + + try: + client = xpc.XPlaneConnect("I'm not a real host") + self.fail("Failed to catch invalid XP host.") + except ValueError: + pass + + try: + client = xpc.XPlaneConnect("127.0.0.1", 90001) + self.fail("Failed to catch invalid XP port.") + except ValueError: + pass + try: + client = xpc.XPlaneConnect("127.0.0.1", -1) + self.fail("Failed to catch invalid XP port.") + except ValueError: + pass + + try: + client = xpc.XPlaneConnect("127.0.0.1", 49009, 90001) + self.fail("Failed to catch invalid local port.") + except ValueError: + pass + try: + client = xpc.XPlaneConnect("127.0.0.1", 49009, -1) + self.fail("Failed to catch invalid XP port.") + except ValueError: + pass + + try: + client = xpc.XPlaneConnect("127.0.0.1", 49009, 0, -1) + self.fail("Failed to catch invalid timeout.") + except ValueError: + pass + + def test_close(self): + client = xpc.XPlaneConnect("127.0.0.1", 49009, 49063) + client.close() + self.assertIsNone(client.socket) + client = xpc.XPlaneConnect("127.0.0.1", 49009, 49063) + + def test_send_read(self): + # Init + test = "\x00\x01\x02\x03\x05" + + # Setup + sender = xpc.XPlaneConnect("127.0.0.1", 49063, 49064) + receiver = xpc.XPlaneConnect("127.0.0.1", 49009, 49063) + + # Execution + sender.sendUDP(test.encode()) + buf = receiver.readUDP() + + # Cleanup + sender.close() + receiver.close() + + # Tests + for a, b in zip(test, buf.decode()): + self.assertEqual(a, b) + + def test_getDREFs(self): + # Setup + client = xpc.XPlaneConnect() + drefs = ["sim/cockpit/switches/gear_handle_status",\ + "sim/cockpit2/switches/panel_brightness_ratio"] + + # Execution + result = client.getDREFs(drefs) + + # Cleanup + client.close() + + # Tests + self.assertEqual(2, len(result)) + self.assertEqual(1, len(result[0])) + self.assertEqual(4, len(result[1])) + + def test_sendDREF(self): + dref = "sim/cockpit/switches/gear_handle_status" + value = None + def do_test(): + # Setup + client = xpc.XPlaneConnect() + + # Execute + client.sendDREF(dref, value) + result = client.getDREF(dref) + + # Cleanup + client.close() + + # Tests + self.assertEqual(1, len(result)) + self.assertEqual(value, result[0]) + + # Test 1 + value = 1 + do_test() + + # Test 2 + value = 0 + do_test() + + def test_sendDREFs(self): + drefs = [\ + "sim/cockpit/switches/gear_handle_status",\ + "sim/cockpit/autopilot/altitude"] + values = None + def do_test(): + # Setup + client = xpc.XPlaneConnect() + + # Execute + client.sendDREFs(drefs, values) + result = client.getDREFs(drefs) + + # Cleanup + client.close() + + # Tests + self.assertEqual(2, len(result)) + self.assertEqual(1, len(result[0])) + self.assertEqual(values[0], result[0][0]) + self.assertEqual(1, len(result[1])) + self.assertEqual(values[1], result[1][0]) + + # Test 1 + values = [1, 2000] + do_test() + + # Test 2 + values = [0, 4000] + do_test() + + def test_sendDATA(self): + # Setup + dref = "sim/aircraft/parts/acf_gear_deploy" + data = [[ 14, 1, 0, -998, -998, -998, -998, -998, -998 ]] + client = xpc.XPlaneConnect() + + # Execute + client.sendDATA(data) + result = client.getDREF(dref) + + # Cleanup + client.close() + + #Tests + self.assertEqual(result[0], data[0][1]) + + def test_pauseSim(self): + dref = "sim/operation/override/override_planepath" + value = None + expected = None + def do_test(): + # Setup + client = xpc.XPlaneConnect() + + # Execute + client.pauseSim(value) + result = client.getDREF(dref) + + # Cleanup + client.close() + + # Test + self.assertAlmostEqual(expected, result[0]) + + # Test 1 + value = True + expected = 1.0 + do_test() + + # Test 2 + value = False + expected = 0.0 + do_test() + + # Test 3 + value = 1 + expected = 1.0 + do_test() + + # Test 4 + value = 2 + expected = 0.0 + do_test() + + def test_getCTRL(self): + values = None + ac = 0 + expected = None + def do_test(): + with xpc.XPlaneConnect() as client: + # Execute + client.sendCTRL(values, ac) + result = client.getCTRL(ac) + + # Test + self.assertEqual(len(result), len(expected)) + for a, e in zip(result, expected): + self.assertAlmostEqual(a, e, 4) + + values = [0.0, 0.0, 0.0, 0.8, 1.0, 0.5, -1.5] + expected = values + ac = 0 + do_test() + + ac = 3 + do_test() + + + def test_sendCTRL(self): + # Setup + drefs = ["sim/cockpit2/controls/yoke_pitch_ratio",\ + "sim/cockpit2/controls/yoke_roll_ratio",\ + "sim/cockpit2/controls/yoke_heading_ratio",\ + "sim/flightmodel/engine/ENGN_thro",\ + "sim/cockpit/switches/gear_handle_status",\ + "sim/flightmodel/controls/flaprqst"] + ctrl = [] + + def do_test(): + client = xpc.XPlaneConnect() + + # Execute + client.sendCTRL(ctrl) + result = client.getDREFs(drefs) + + # Cleanup + client.close() + + # Tests + self.assertEqual(6, len(result)) + for i in range(6): + self.assertAlmostEqual(ctrl[i], result[i][0], 4) + + # Test 1 + ctrl = [ -1.0, -1.0, -1.0, 0.0, 1.0, 1.0 ] + do_test() + + # Test 2 + ctrl = [ 1.0, 1.0, 1.0, 0.0, 1.0, 0.5 ] + do_test() + + # Test 2 + ctrl = [ 0.0, 0.0, 0.0, 0.8, 1.0, 0.0 ] + do_test() + + def test_sendCTRL_speedbrake(self): + # Setup + dref = "sim/flightmodel/controls/sbrkrqst" + ctrl = [] + + def do_test(): + client = xpc.XPlaneConnect() + + # Execute + client.sendCTRL(ctrl) + result = client.getDREF(dref) + + # Cleanup + client.close() + + # Tests + self.assertAlmostEqual(result[0], ctrl[6]) + + # Test 1 + ctrl = [-998, -998, -998, -998, -998, -998, -0.5] + do_test() + + # Test 2 + ctrl[6] = 1.0 + do_test() + + # Test 2 + ctrl[6] = 0.0 + do_test() + + def test_getPOSI(self): + values = None + ac = 0 + expected = None + def do_test(): + with xpc.XPlaneConnect() as client: + # Execute + client.pauseSim(True) + client.sendPOSI(values, ac) + result = client.getPOSI(ac) + client.pauseSim(False) + + # Test + self.assertEqual(len(result), len(expected)) + for a, e in zip(result, expected): + self.assertAlmostEqual(a, e, 4) + + values = [ 37.524, -122.06899, 2500, 45, -45, 15, 1 ] + expected = values + ac = 0 + do_test() + + ac = 3 + do_test() + + def test_sendPOSI(self): + # Setup + drefs = ["sim/flightmodel/position/latitude",\ + "sim/flightmodel/position/longitude",\ + "sim/flightmodel/position/elevation",\ + "sim/flightmodel/position/theta",\ + "sim/flightmodel/position/phi",\ + "sim/flightmodel/position/psi",\ + "sim/cockpit/switches/gear_handle_status"] + posi = None + def do_test(): + client = xpc.XPlaneConnect() + + # Execute + client.pauseSim(True) + client.sendPOSI(posi) + result = client.getDREFs(drefs) + client.pauseSim(False) + + # Cleanup + client.close() + + # Tests + self.assertEqual(7, len(result)) + for i in range(7): + self.assertAlmostEqual(posi[i], result[i][0], 4) + + # Test 1 + posi = [ 37.524, -122.06899, 2500, 5, 7, 11, 1 ] + do_test() + + # Test 2 + posi = [ 38, -121.0, 2000, -10, 0, 0, 0 ] + do_test() + + def test_sendTEXT(self): + # Setup + client = xpc.XPlaneConnect() + x = 200 + y = 700 + msg = "Python sendTEXT test message." + + # Execution + client.sendTEXT(msg, x, y) + # NOTE: Manually verify that msg appears on the screen in X-Plane + + # Cleanup + client.close() + + def test_sendView(self): + # Setup + dref = "sim/graphics/view/view_type" + fwd = 1000 + chase = 1017 + + #Execution + with xpc.XPlaneConnect() as client: + client.sendVIEW(xpc.ViewType.Forwards) + result = client.getDREF(dref) + self.assertAlmostEqual(fwd, result[0], 1e-4) + client.sendVIEW(xpc.ViewType.Chase) + result = client.getDREF(dref) + self.assertAlmostEqual(chase, result[0], 1e-4) + + + def test_sendWYPT(self): + # Setup + client = xpc.XPlaneConnect() + points = [\ + 37.5245, -122.06899, 2500,\ + 37.455397, -122.050037, 2500,\ + 37.469567, -122.051411, 2500,\ + 37.479376, -122.060509, 2300,\ + 37.482237, -122.076130, 2100,\ + 37.474881, -122.087288, 1900,\ + 37.467660, -122.079391, 1700,\ + 37.466298, -122.090549, 1500,\ + 37.362562, -122.039223, 1000,\ + 37.361448, -122.034416, 1000,\ + 37.361994, -122.026348, 1000,\ + 37.365541, -122.022572, 1000,\ + 37.373727, -122.024803, 1000,\ + 37.403869, -122.041283, 50,\ + 37.418544, -122.049222, 6] + + # Execution + client.sendPOSI([37.5245, -122.06899, 2500]) + client.sendWYPT(3, []) + client.sendWYPT(1, points) + # NOTE: Manually verify that points appear on the screen in X-Plane + + # Cleanup + client.close() + + def test_setCONN(self): + # Setup + dref = "sim/cockpit/switches/gear_handle_status"; + client = xpc.XPlaneConnect() + + # Execute + client.setCONN(49055) + result = client.getDREF(dref) + + # Cleanup + client.close() + + # Test + self.assertEqual(1, len(result)) + + + +if __name__ == '__main__': + unittest.main() diff --git a/TestScripts/Python3 Tests/Tests.pyproj b/TestScripts/Python3 Tests/Tests.pyproj new file mode 100644 index 0000000..c1626b5 --- /dev/null +++ b/TestScripts/Python3 Tests/Tests.pyproj @@ -0,0 +1,45 @@ + + + + Debug + 2.0 + 6931ebb2-4e01-4c5a-86b6-668c0e75051b + . + Tests.py + ..\..\Python\src\ + . + . + Tests + Tests + {9a7a9026-48c1-4688-9d5d-e5699d47d074} + 2.7 + + + true + false + + + true + false + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets + + + + + + + + + + \ No newline at end of file diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 2556fef..5163edc 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -24,7 +24,6 @@ #include "XPLMScenery.h" #include "XPLMGraphics.h" - #include #include #include @@ -32,7 +31,6 @@ #define MULTICAST_GROUP "239.255.1.1" #define MULITCAST_PORT 49710 - namespace XPC { std::map MessageHandlers::connections; @@ -560,21 +558,20 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GPOS", "Getting position information for aircraft %u", aircraft); - unsigned char response[34] = "POSI"; + unsigned char response[46] = "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); + *((double*)(response + 6)) = DataManager::GetDouble(DREF_Latitude, aircraft); + *((double*)(response + 14)) = DataManager::GetDouble(DREF_Longitude, aircraft); + *((double*)(response + 22)) = DataManager::GetDouble(DREF_Elevation, aircraft); + *((float*)(response + 30)) = DataManager::GetFloat(DREF_Pitch, aircraft); + *((float*)(response + 34)) = DataManager::GetFloat(DREF_Roll, aircraft); + *((float*)(response + 38)) = DataManager::GetFloat(DREF_HeadingTrue, aircraft); float gear[10]; DataManager::GetFloatArray(DREF_GearDeploy, gear, 10, aircraft); - *((float*)(response + 30)) = gear[0]; + *((float*)(response + 42)) = gear[0]; - sock->SendTo(response, 34, &connection.addr); + sock->SendTo(response, 46, &connection.addr); } void MessageHandlers::HandlePosi(const Message& msg) @@ -594,6 +591,7 @@ namespace XPC { float posd_32[3]; memcpy(posd_32, buffer + 6, 12); + /* convert float to double */ posd[0] = posd_32[0]; posd[1] = posd_32[1]; posd[2] = posd_32[2]; @@ -612,7 +610,6 @@ namespace XPC return; } - /* convert float to double */ DataManager::SetPosition(posd, aircraftNumber); DataManager::SetOrientation(orient, aircraftNumber); if (gear >= 0) @@ -632,7 +629,7 @@ namespace XPC } } } - + void MessageHandlers::HandleGetT(const Message& msg) { const unsigned char* buffer = msg.GetBuffer();